micronaut-test
micronaut-test copied to clipboard
Be able to share contexts between test classes
Feature description
JUnit's parallel test execution is a great boon for iteration time and lets you maximally use your machine's resources, but it's tough with Micronaut because a lot of libraries are notionally thread safe, but in reality not fully thread safe for initialization/teardown. Thus when JUnit runs each test class in parallel and Micronaut constructs a context in parallel, such libraries are initialized in multiple threads at once and often die or flake as a consequence.
It's frequently wasteful to set up a new context for every test class. It'd be better to re-use a context across multiple tests.
I'd like Micronaut Test to be able to cache test contexts for me. I tried to implement this myself using the ApplicationContextBuilder, but it didn't work for reasons that are hard to understand ... some beans just weren't found in the shared context even though they're clearly there.
It's frequently wasteful to set up a new context for every test class. It'd be better to re-use a context across multiple tests.
this will be a breaking change.
because a lot of libraries are notionally thread safe, but in reality not fully thread safe for initialization/teardown.
Which ones? We already do parallel test execution semi-regularly with separate contexts
@yawkat Not as aggressively as we do I guess. Two recent examples we hit:
Logback init isn't thread safe. We occasionally see flakes here:
java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 0
at java.base/java.util.ArrayList.add(ArrayList.java:484)
at java.base/java.util.ArrayList.add(ArrayList.java:496)
at ch.qos.logback.classic.LoggerContext.addListener(LoggerContext.java:292)
at io.micrometer.core.instrument.binder.logging.LogbackMetrics.<init>(LogbackMetrics.java:76)
Another is Oracle UCP which binds pools to global state. I've reported it to them and they're fixing that by making setup/teardown thread safe, but this is a general problem that I think will keep coming up. It's pretty normal for libraries to be thread safe but not for global init. And it's just wasteful to init and deinit everything all the time, especially expensive things like thread pools.
@sdelamo I'd be happy to opt-in! Or even just have a workaround bit of code we can copy/paste into our codebase for now. Parallel test execution is a big win both for dev productivity and also just stress testing the thread safety of our own code, but the frequency of library flakes caused by this problem is becoming a deal killer.
In theory it could be done using the application context builder, but every time I tried to use it for this I failed with complex problems inside Micronaut that I couldn't figure out.
BTW, another problem we hit yesterday is running out of DB connections/processes. Same cause; too many tests run in parallel and whilst it should work, the one-pool-per-test-class design means the DB falls over.
Ideally we'd be able to control the default scoping of contexts.