The server test task runs all ~638 tests in a single JVM (no forkEvery/maxParallelForks in server/build.gradle), and FileReceiverTest.setUpBeforeClass() injects a mock ControllerFactory into global static state via Guice requestStaticInjection. That static state and the JVM are shared across every test class, so execution order and timing can change results.
FileReceiverTest.testPoll1 (an exact file-count assertion) failed once in CI on #405, passed on re-run, and does not reproduce locally on macOS or on a native-Linux Docker run of the same commit. So it's a non-deterministic flake surfaced by ordering/timing, not a product bug.
Directions, by appetite:
- Set
forkEvery on the server test task so one class's static state can't leak into another (costs some wall-time).
- Or reset the global
ControllerFactory in an @AfterClass and stop using requestStaticInjection for shared state.
- Or make the assertion order-independent (filter the fixture dir to the expected files instead of asserting an exact count).
Context: found while diagnosing a CI failure on #405.
The server test task runs all ~638 tests in a single JVM (no
forkEvery/maxParallelForksinserver/build.gradle), andFileReceiverTest.setUpBeforeClass()injects a mockControllerFactoryinto global static state via GuicerequestStaticInjection. That static state and the JVM are shared across every test class, so execution order and timing can change results.FileReceiverTest.testPoll1(an exact file-count assertion) failed once in CI on #405, passed on re-run, and does not reproduce locally on macOS or on a native-Linux Docker run of the same commit. So it's a non-deterministic flake surfaced by ordering/timing, not a product bug.Directions, by appetite:
forkEveryon the server test task so one class's static state can't leak into another (costs some wall-time).ControllerFactoryin an@AfterClassand stop usingrequestStaticInjectionfor shared state.Context: found while diagnosing a CI failure on #405.