Skip to content

Commit 70e3c22

Browse files
Ensure @before and @test run on the same thread in AndroidJUnit4ClassRunner.
Currently, AndroidJUnit4ClassRunner inherits standard JUnit 4 behavior where timeouts are applied only to the test method itself. If a test timeout is set (e.g., passed by TradeFed or runner arguments), FailOnTimeout executes the test method in a separate thread. Since setup (@before) and teardown (@after) are applied outside this timeout, they run on the caller thread, causing a thread mismatch. This prevents ThreadLocal variables initialized in setup from being accessible in the test. This CL modifies AndroidJUnit4ClassRunner to apply the timeout to the combined statement of setup, test, and teardown. This is achieved by: 1. Overriding withAfters to wrap the combined statement in FailOnTimeout. 2. Overriding withPotentialTimeout to be a no-op, preventing double timeout application. This ensures all lifecycle methods run on the same thread spawned by the timeout. NOTE: Because the timeout now wraps setup and teardown, any time spent in @before or @after will now count towards the test timeout. PiperOrigin-RevId: 895547043
1 parent 56d05cb commit 70e3c22

2 files changed

Lines changed: 19 additions & 17 deletions

File tree

runner/android_junit_runner/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
* Add logs at the start and end of RunBefore and RunAfters sections to help bug understanding. (b/445754263)
1414

15+
* Ensure @Before and @Test run on the same thread in AndroidJUnit4ClassRunner.
16+
1517
**Breaking Changes**
1618

1719
**API Changes**

runner/android_junit_runner/java/androidx/test/internal/runner/junit4/AndroidJUnit4ClassRunner.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,31 +73,31 @@ protected Statement withBefores(FrameworkMethod method, Object target, Statement
7373
@Override
7474
protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
7575
List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods(After.class);
76-
return afters.isEmpty() ? statement : new RunAfters(method, statement, afters, target);
77-
}
76+
Statement combined =
77+
afters.isEmpty() ? statement : new RunAfters(method, statement, afters, target);
7878

79-
/**
80-
* Default to {@link org.junit.Test#timeout()} level timeout if set. Otherwise, set the timeout
81-
* that was passed to the instrumentation via argument.
82-
*/
83-
@Override
84-
protected Statement withPotentialTimeout(FrameworkMethod method, Object test, Statement next) {
85-
// test level timeout i.e @Test(timeout = 123)
8679
long timeout = getTimeout(method.getAnnotation(Test.class));
87-
88-
// use runner arg timeout if test level timeout is not present
8980
if (timeout <= 0 && perTestTimeout > 0) {
9081
timeout = perTestTimeout;
9182
}
9283

93-
if (timeout <= 0) {
94-
// no timeout was set
95-
return next;
84+
if (timeout > 0) {
85+
// Cannot switch to use builder as that is not supported in JUnit 4.10 which is what is
86+
// available in AOSP.
87+
@SuppressWarnings("deprecation")
88+
var failOnTimeout = new FailOnTimeout(combined, timeout);
89+
return failOnTimeout;
9690
}
91+
return combined;
92+
}
9793

98-
// Cannot switch to use builder as that is not supported in JUnit 4.10 which is what is
99-
// available in AOSP.
100-
return new FailOnTimeout(next, timeout);
94+
/**
95+
* Default to {@link org.junit.Test#timeout()} level timeout if set. Otherwise, set the timeout
96+
* that was passed to the instrumentation via argument.
97+
*/
98+
@Override
99+
protected Statement withPotentialTimeout(FrameworkMethod method, Object test, Statement next) {
100+
return next;
101101
}
102102

103103
private long getTimeout(Test annotation) {

0 commit comments

Comments
 (0)