Skip to content

blackbox-global-scope-teardown: repro for global test scope corruption by mock-scoped test classes - #1054

Draft
stevenschlansker wants to merge 2 commits into
avaje:masterfrom
stevenschlansker:blackbox-global-scope-teardown
Draft

blackbox-global-scope-teardown: repro for global test scope corruption by mock-scoped test classes#1054
stevenschlansker wants to merge 2 commits into
avaje:masterfrom
stevenschlansker:blackbox-global-scope-teardown

Conversation

@stevenschlansker

@stevenschlansker stevenschlansker commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

A test class with mocks/profiles/scopePerTest rebuilds the entire application parented only on the TestScope beans, beside the still-live global scope. This version reproduces the corruption with real JVM-global state: ServerStatus registers itself on the platform MBeanServer in @PostConstruct and unregisters in @PreDestroy, the standard JMX pattern.

With alphabetical class order in one fork: T1 (plain) passes. T2 mocks one unrelated interface and never references ServerStatus; wiring its per-test scope constructs ServerStatus a second time and fails with InstanceAlreadyExistsException, and closing that failed scope unregisters (by ObjectName) the MBean the live global scope owns. T3 (identical to T1) then fails with InstanceNotFoundException. T1 and T3 pass in isolation; T2 fails even alone.

Reproduces on 12.6 and 12.7-RC2.

@stevenschlansker stevenschlansker changed the title blackbox-global-scope-teardown: repro for global test scope corruptio… blackbox-global-scope-teardown: repro for global test scope corruption by mock-scoped test classes Aug 14, 2026
…n by mock-scoped test classes

A test class with mocks/profiles/scopePerTest rebuilds the entire
application parented only on the TestScope beans. The rebuilt beans run
their lifecycle beside the still-live global scope, and closing them at
afterEach tears down JVM-global state (static registries, drivers,
MBeans) the global scope's beans still depend on. With alphabetical
class order in one fork: T1 (global) passes, T2 (one @mock) passes,
T3 (global again) fails. Each class passes in isolation.

Reproduces on 12.6 and 12.7-RC2.
@stevenschlansker
stevenschlansker force-pushed the blackbox-global-scope-teardown branch from d20de65 to 95e31d4 Compare August 14, 2026 20:26
Responds to review feedback asking for a real-world case instead of a
synthetic one. ServerStatus registers itself on the JVM-wide platform
MBeanServer in @PostConstruct and unregisters in @PreDestroy, the
standard JMX pattern (HikariCP, Kafka clients, Jetty).

T1 (plain @injecttest) passes. T2 mocks one unrelated interface and
never references ServerStatus; wiring its scope rebuilds the whole
application beside the live global scope and fails with the JDK's
InstanceAlreadyExistsException. Closing that failed scope runs the
duplicate's @PreDestroy, which unregisters the MBean by ObjectName out
from under the live global instance, so T3 (identical to T1) fails
with InstanceNotFoundException. T1 and T3 pass in isolation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant