Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interrupted test cases cause random failures with thread reuse #1365

Closed
terorontti opened this issue Sep 28, 2016 · 14 comments
Closed

Interrupted test cases cause random failures with thread reuse #1365

terorontti opened this issue Sep 28, 2016 · 14 comments
Labels
Milestone

Comments

@terorontti
Copy link

Whenever a test case is interrupted (Thread.interrupt()), the test runner thread seems to stay in interrupted state. This causes random failures later when the thread is reused for other test cases.

Expected behaviour: When the thread is reused, interrupted flag for the thread is cleaned before starting a new test case. This can be done by calling Thread.interrupted(), which returns the interrupted state, and clears the interrupted flag.

The following code should reproduce the problem, given that test1 is run before test2

import org.junit.Test;

public class ThreadTest {
  @Test
  public void test1() {
    Thread.currentThread().interrupt();
  }

  @Test
  public void test2() throws InterruptedException {
    Thread.sleep(1000);
  }
}

The problem I encountered is similar to the one described in https://www.thoughtwire.com/junit-interupt/

@kcooney
Copy link
Member

kcooney commented Sep 28, 2016

Thanks for the bug report.

I wonder if JUnit should cause an otherwise passing test to fail if the interrupted bit was set during the test run. I am guessing no, because so many otherwise passing tests would start failing, and the fix would be to sprinkle interrupted() calls everywhere.

There is also the question of whether ExpectesException assertThrows() or expectThrows() should ever clear the interrupted bit. I am guessing they should.

@junit-team/junit-committers thoughts?

@ArneDeutsch
Copy link

I would support the idea to call Thread.interrupted() on each thread that is reused for more than one test case just before executing a new test case. But especially if one thread is used for more then one test class. The interrupted flag is state that leaks from one test case to others, making test cases flaky. Especially the test cases that deal with multiple threads that are notoriously hard to get right anyway.

@npathai
Copy link
Contributor

npathai commented Oct 25, 2018

@kcooney I can start working on this.

@kcooney
Copy link
Member

kcooney commented Oct 25, 2018

@npathai fantastic!

There is still an open question of whether ExpectedException or assertThrows() should ever clear the interrupted bit. @junit-team/junit-committers thoughts?

@stefanbirkner
Copy link
Contributor

IMHO we should clear the interrupted flag after each test. We should not clear it in ExpectedException and assertThrows() because it will cleared after the test.

@kcooney can you please explain why you think that ExpectedException and assertThrows() should clear the flag.

@kcooney
Copy link
Member

kcooney commented Oct 26, 2018

@stefanbirkner the general guidance I've read is any time you catch InterruptedException and don't rethrow it you should call interrupt (see https://www.ibm.com/developerworks/library/j-jtp05236/index.html and search for "Don't swallow interrupts"). Since ExpectedException and assertThrows() "swallow" unexpected exceptions, I wanted to see what people thought we should do.

@kcooney
Copy link
Member

kcooney commented Oct 26, 2018

FWIW, I did a quick search in GitHub for calls to interrupted() in JUnit 5 and I didn't find any calls.

@npathai
Copy link
Contributor

npathai commented Oct 26, 2018

@kcooney @stefanbirkner I was wondering how IDE's integrate with JUnit framework. If I have long running test case something like

@Test
  public void test1() throws InterruptedException {
    Thread.sleep(100000);
  }

@Test
  public void test2() throws InterruptedException {
    Thread.sleep(100000);
  }

and I stop the test case forcefully using IDE. Will the IDE interrupt the Thread running JUnit tests or something else?
I checked the behavior in IntelliJ, it seems that they run different process and interrupt the process when test cases are stopped forcefully from IDE. I see Process finished with exit code 130 (interrupted by signal 2: SIGINT) in the console.
I went through eclipse JDT source and found that they use some sort of remote connection for execution of test cases.

My doubt is in a way we are violating Thread.interrupted() convention by not honoring the interruption and swallowing it. So I thought if IDE integration actually used junitThread.interrupt() to stop further execution of JUnit tests then it will not honor that request. So in this case when test1 is executing and I click stop button from IDE, it should allow current method to execute and not run further test cases. Will this behavior get affected by resetting interrupt status flag.

I apologize if the question is dumb, I don't have experience with how IDE's integrate. It will be great if you can shed some light for me.

npathai added a commit to npathai/junit that referenced this issue Oct 26, 2018
npathai added a commit to npathai/junit that referenced this issue Oct 27, 2018
…in separate method. Refactored the way thread interrupted status is checked in Unit test
@kcooney
Copy link
Member

kcooney commented Nov 9, 2018

@ npathai I think IDEs call RunNotifier.pleaseStop()

@kcooney
Copy link
Member

kcooney commented Nov 9, 2018

So it sounds like the concerns is this: what happens if the IDE calls pleaseStop() then Thread.interrupt() on the thread running the tests?

If that thread is not in a blocking method and doesn't call a blocking method, the the test run will abort after the current test complets (due to pleaseStop()).

If that thread is in a blocking method or calls a blocking method, it will throw InterruptedException. If the test doesn't catch that exception it will fail, then the test run will abort.

If the test swallows the exception things get tricky.

@Tibor17
Copy link
Contributor

Tibor17 commented Nov 9, 2018 via email

npathai added a commit to npathai/junit that referenced this issue Dec 3, 2018
…hread interrupted call from ParentRunner to BlockJUnit4ClassRunner methodBlock()
npathai added a commit to npathai/junit that referenced this issue Dec 3, 2018
npathai added a commit to npathai/junit that referenced this issue Dec 4, 2018
…s well, so that interrupt status is cleared if it is set from @afterclass or ClassRule
npathai added a commit to npathai/junit that referenced this issue Dec 5, 2018
npathai added a commit to npathai/junit that referenced this issue Dec 10, 2018
…classBlock() and methodBlock(). The flag is cleared after each test case

completes and after AfterClass/ClassRule are executed
npathai added a commit to npathai/junit that referenced this issue Dec 11, 2018
…classBlock() and methodBlock(). The flag is cleared after each test case

completes and after AfterClass/ClassRule are executed
@marcphilipp marcphilipp added this to the 4.13-beta-2 milestone Dec 16, 2018
marcphilipp pushed a commit that referenced this issue Jan 12, 2019
The thread interrupt status flag is now cleared from `classBlock()` and
`methodBlock()`. The flag is cleared after each test case completes and
after `AfterClass` methods and `ClassRules` have been executed.

Fixes #1365.
marcphilipp pushed a commit that referenced this issue Jan 19, 2019
The thread interrupt status flag is now cleared from `classBlock()` and
`methodBlock()`. The flag is cleared after each test case completes and
after `AfterClass` methods and `ClassRules` have been executed.

Fixes #1365.
marcphilipp pushed a commit that referenced this issue Jan 20, 2019
The thread interrupt status flag is now cleared from `classBlock()` and
`methodBlock()`. The flag is cleared after each test case completes and
after `AfterClass` methods and `ClassRules` have been executed.

Fixes #1365.
marcphilipp pushed a commit that referenced this issue Jan 20, 2019
The thread interrupt status flag is now cleared from `classBlock()` and
`methodBlock()`. The flag is cleared after each test case completes and
after `AfterClass` methods and `ClassRules` have been executed.

Fixes #1365.
@joaodias14
Copy link

Shouldn't this be cherry-picked to JUnit 5? I'm having the same issue with 5.3.2.

@marcphilipp
Copy link
Member

marcphilipp commented May 18, 2019

@joaodias14 Please upgrade to the latest version, it was fixed in 5.4.0 (see junit-team/junit5#1688).

@joaodias14
Copy link

Many thanks @marcphilipp!

aristotle0x01 pushed a commit to aristotle0x01/junit4 that referenced this issue Jun 27, 2022
The thread interrupt status flag is now cleared from `classBlock()` and
`methodBlock()`. The flag is cleared after each test case completes and
after `AfterClass` methods and `ClassRules` have been executed.

Fixes junit-team#1365.
nymanjens added a commit to google/TestParameterInjector that referenced this issue Oct 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants