Skip to content

Introduce feature flag for auto-closing AutoCloseable in Jupiter's ExtensionContext.Store #4452

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

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5cf0a08
Deprecate `CloseableResource`
YongGoose Apr 6, 2025
a524c83
Introduce configuration parameter
YongGoose Apr 6, 2025
5c7b99e
Log warning for CloseableResource without AutoCloseable
YongGoose Apr 6, 2025
44dfb8a
Add tests
YongGoose Apr 6, 2025
0e22d7b
Update jupiter-tests/src/test/java/org/junit/jupiter/engine/descripto…
YongGoose Apr 9, 2025
f52d0e0
Merge branch 'main' into feature/4434
YongGoose Apr 9, 2025
35f25db
Apply comments
YongGoose Apr 9, 2025
8c6dbb3
Merge branch 'main' into feature/4434
YongGoose Apr 9, 2025
708af7d
Add documents
YongGoose Apr 9, 2025
849492d
Replace warning-suppressed code with AutoCloseable usage
YongGoose Apr 9, 2025
f0af9bb
Merge branch 'main' into feature/4434
YongGoose Apr 11, 2025
a2746b3
Merge branch 'main' into feature/4434
YongGoose Apr 11, 2025
c555910
Merge branch 'main' into feature/4434
YongGoose Apr 12, 2025
c82c098
Apply comment
YongGoose Apr 12, 2025
8a5b7fe
Test warning logs for `CloseableResource` without `AutoCloseable`
YongGoose Apr 12, 2025
e8cb1d3
Merge branch 'main' into feature/4434
YongGoose Apr 13, 2025
46a8df0
Merge branch 'main' into feature/4434
YongGoose Apr 15, 2025
7fab7eb
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/de…
YongGoose Apr 15, 2025
8057fe9
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/de…
YongGoose Apr 15, 2025
ed2df61
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/de…
YongGoose Apr 15, 2025
a255a23
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/de…
YongGoose Apr 15, 2025
46a606d
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/de…
YongGoose Apr 15, 2025
d7a985e
Apply comment
YongGoose Apr 15, 2025
c05235e
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/co…
YongGoose Apr 15, 2025
49cb3f5
Update junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/co…
YongGoose Apr 15, 2025
d498200
Update javadoc
YongGoose Apr 15, 2025
056d060
polishing
YongGoose Apr 15, 2025
d25f1b0
Update document
YongGoose Apr 16, 2025
30a4b01
Merge branch 'main' into feature/4434
YongGoose Apr 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ to start reporting discovery issues.
`static`)
- Cyclic dependencies between `@Suite` classes

* Introduce feature flag for auto-closing `AutoCloseable` in Jupiter's ExtensionContext.Store


[[release-notes-5.13.0-M3-junit-jupiter]]
=== JUnit Jupiter
Expand Down
39 changes: 32 additions & 7 deletions documentation/src/docs/asciidoc/user-guide/extensions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -863,17 +863,20 @@ surrounding `ExtensionContext`. Since `ExtensionContexts` may be nested, the sco
inner contexts may also be limited. Consult the corresponding Javadoc for details on the
methods available for storing and retrieving values via the `{ExtensionContext_Store}`.

.`ExtensionContext.Store.CloseableResource`
.`AutoCloseable`
NOTE: An extension context store is bound to its extension context lifecycle. When an
extension context lifecycle ends it closes its associated store. All stored values
that are instances of `CloseableResource` are notified by an invocation of their `close()`
method in the inverse order they were added in.

An example implementation of `CloseableResource` is shown below, using an `HttpServer`
extension context lifecycle ends it closes its associated store. As of JUnit 5.13,
all stored values that are instances of `AutoCloseable` are notified by an invocation of
their `close()` method in the inverse order they were added in. (unless the
`junit.jupiter.extensions.store.close.autocloseable.enabled` configuration parameter
is set to false). Older versions supported `CloseableResource`, which is still
available for backward compatibility but is no longer recommended.

An example implementation of `AutoCloseable` is shown below, using an `HttpServer`
resource.

[source,java,indent=0]
.`HttpServer` resource implementing `CloseableResource`
.`HttpServer` resource implementing `AutoCloseable`
----
include::{testDir}/example/extensions/HttpServerResource.java[tags=user_guide]
----
Expand All @@ -896,6 +899,28 @@ include::{testDir}/example/extensions/HttpServerExtension.java[tags=user_guide]
include::{testDir}/example/HttpServerDemo.java[tags=user_guide]
----

[[extensions-keeping-state-migration]]
==== Migration Note for Resource Cleanup

Starting with JUnit Jupiter 5.13, the framework automatically closes resources stored in the
`ExtensionContext.Store` that implement `AutoCloseable` when auto-close is enabled (which is the default behavior).
Prior to 5.13, only resources implementing `Store.CloseableResource` were automatically closed.

If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and earlier versions,
and your extension stores resources that need to be cleaned up, you should implement both interfaces:

[source,java,indent=0]
----
public class MyResource implements Store.CloseableResource, AutoCloseable {
@Override
public void close() throws Exception {
// Resource cleanup code
}
}
----

This ensures that your resource will be properly closed regardless of which JUnit Jupiter version is being used.

[[extensions-supported-utilities]]
=== Supported Utilities in Extensions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@

import com.sun.net.httpserver.HttpServer;

import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;

/**
* Demonstrates an implementation of {@link CloseableResource} using an {@link HttpServer}.
* Demonstrates an implementation of {@link AutoCloseable} using an {@link HttpServer}.
*/
// tag::user_guide[]
class HttpServerResource implements CloseableResource {
class HttpServerResource implements AutoCloseable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to update the Asciidoc title for this snippet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, Since HttpServerResource is used as an example to explain CloseableResource, I think it would be better to revert it back to CloseableResource instead of AutoCloseable.

.`ExtensionContext.Store.CloseableResource`
NOTE: An extension context store is bound to its extension context lifecycle. When an
extension context lifecycle ends it closes its associated store. All stored values
that are instances of `CloseableResource` are notified by an invocation of their `close()`
method in the inverse order they were added in.

An example implementation of `CloseableResource` is shown below, using an `HttpServer`
resource.

[source,java,indent=0]
.`HttpServer` resource implementing `CloseableResource`

Using an example with AutoCloseable while explaining Closeable might confuse the reader.
@marcphilipp WDYT? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be used to explain AutoCloseable instead and we should revamp that section to mention that older releases used CloseableResource instead which is still supported but no longer recommended etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be used to explain AutoCloseable instead and we should revamp that section to mention that older releases used CloseableResource instead which is still supported but no longer recommended etc.

Done in 3a96c24 !


private final HttpServer httpServer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,9 @@ interface Store {
* inverse order they were added in.
*
* @since 5.1
* @deprecated Please extend {@code AutoCloseable} directly.
*/
@Deprecated
@API(status = STABLE, since = "5.1")
interface CloseableResource {

Expand Down Expand Up @@ -595,9 +597,11 @@ default <V> V getOrDefault(Object key, Class<V> requiredType, V defaultValue) {
* <p>See {@link #getOrComputeIfAbsent(Object, Function, Class)} for
* further details.
*
* <p>If {@code type} implements {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
* <p>If {@code type} implements {@link CloseableResource} or
* {@link AutoCloseable} (unless the
* {@code junit.jupiter.extensions.store.close.autocloseable.enabled}
* configuration parameter is set to {@code false}), then the {@code close()}
* method will be invoked on the stored object when the store is closed.
*
* @param type the type of object to retrieve; never {@code null}
* @param <V> the key and value type
Expand All @@ -606,6 +610,7 @@ default <V> V getOrDefault(Object key, Class<V> requiredType, V defaultValue) {
* @see #getOrComputeIfAbsent(Object, Function)
* @see #getOrComputeIfAbsent(Object, Function, Class)
* @see CloseableResource
* @see AutoCloseable
*/
@API(status = STABLE, since = "5.1")
default <V> V getOrComputeIfAbsent(Class<V> type) {
Expand All @@ -625,9 +630,11 @@ default <V> V getOrComputeIfAbsent(Class<V> type) {
* <p>For greater type safety, consider using
* {@link #getOrComputeIfAbsent(Object, Function, Class)} instead.
*
* <p>If the created value is an instance of {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
* <p>If the created value is an instance of {@link CloseableResource} or
* {@link AutoCloseable} (unless the
* {@code junit.jupiter.extensions.store.close.autocloseable.enabled}
* configuration parameter is set to {@code false}), then the {@code close()}
* method will be invoked on the stored object when the store is closed.
*
* @param key the key; never {@code null}
* @param defaultCreator the function called with the supplied {@code key}
Expand All @@ -638,6 +645,7 @@ default <V> V getOrComputeIfAbsent(Class<V> type) {
* @see #getOrComputeIfAbsent(Class)
* @see #getOrComputeIfAbsent(Object, Function, Class)
* @see CloseableResource
* @see AutoCloseable
*/
<K, V> Object getOrComputeIfAbsent(K key, Function<K, V> defaultCreator);

Expand All @@ -652,9 +660,11 @@ default <V> V getOrComputeIfAbsent(Class<V> type) {
* a new value will be computed by the {@code defaultCreator} (given
* the {@code key} as input), stored, and returned.
*
* <p>If {@code requiredType} implements {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
* <p>If {@code requiredType} implements {@link CloseableResource} or
* {@link AutoCloseable} (unless the
* {@code junit.jupiter.extensions.store.close.autocloseable.enabled}
* configuration parameter is set to {@code false}), then the {@code close()}
* method will be invoked on the stored object when the store is closed.
*
* @param key the key; never {@code null}
* @param defaultCreator the function called with the supplied {@code key}
Expand All @@ -666,6 +676,7 @@ default <V> V getOrComputeIfAbsent(Class<V> type) {
* @see #getOrComputeIfAbsent(Class)
* @see #getOrComputeIfAbsent(Object, Function)
* @see CloseableResource
* @see AutoCloseable
*/
<K, V> V getOrComputeIfAbsent(K key, Function<K, V> defaultCreator, Class<V> requiredType);

Expand All @@ -676,23 +687,26 @@ default <V> V getOrComputeIfAbsent(Class<V> type) {
* ExtensionContexts} for the store's {@code Namespace} unless they
* overwrite it.
*
* <p>If the {@code value} is an instance of {@link ExtensionContext.Store.CloseableResource}
* the {@code close()} method will be invoked on the stored object when
* the store is closed.
* <p>If the {@code value} is an instance of {@link CloseableResource} or
* {@link AutoCloseable} (unless the
* {@code junit.jupiter.extensions.store.close.autocloseable.enabled}
* configuration parameter is set to {@code false}), then the {@code close()}
* method will be invoked on the stored object when the store is closed.
*
* @param key the key under which the value should be stored; never
* {@code null}
* @param value the value to store; may be {@code null}
* @see CloseableResource
* @see AutoCloseable
*/
void put(Object key, Object value);

/**
* Remove the value that was previously stored under the supplied {@code key}.
*
* <p>The value will only be removed in the current {@link ExtensionContext},
* not in ancestors. In addition, the {@link CloseableResource} API will not
* be honored for values that are manually removed via this method.
* not in ancestors. In addition, the {@link CloseableResource} and {@link AutoCloseable}
* API will not be honored for values that are manually removed via this method.
*
* <p>For greater type safety, consider using {@link #remove(Object, Class)}
* instead.
Expand All @@ -709,8 +723,8 @@ default <V> V getOrComputeIfAbsent(Class<V> type) {
* under the supplied {@code key}.
*
* <p>The value will only be removed in the current {@link ExtensionContext},
* not in ancestors. In addition, the {@link CloseableResource} API will not
* be honored for values that are manually removed via this method.
* not in ancestors. In addition, the {@link CloseableResource} and {@link AutoCloseable}
* API will not be honored for values that are manually removed via this method.
*
* @param key the key; never {@code null}
* @param requiredType the required type of the value; never {@code null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import org.apiguardian.api.API;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;

/**
* Interface for {@link Extension Extensions} that are aware and can influence
Expand Down Expand Up @@ -65,9 +64,11 @@ public interface TestInstantiationAwareExtension extends Extension {
* <li>{@link ExtensionContext#getTestMethod() getTestMethod()} is no longer
* empty, unless the {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS}
* lifecycle is used.</li>
* <li>If the callback adds a new {@link CloseableResource} to the
* {@link Store Store}, the resource is closed just after the instance is
* destroyed.</li>
* <li>If the callback adds a new {@link Store.CloseableResource} or
* {@link AutoCloseable} to the {@link Store Store} (unless the
* {@code junit.jupiter.extensions.store.close.autocloseable.enabled}
* configuration parameter is set to {@code false}), then
* the resource is closed just after the instance is destroyed.</li>
* <li>The callbacks can now access data previously stored by
* {@link TestTemplateInvocationContext}, unless the
* {@link TestInstance.Lifecycle#PER_CLASS PER_CLASS} lifecycle is used.</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,16 @@ public final class Constants {
@API(status = STABLE, since = "5.10")
public static final String PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME = JupiterConfiguration.PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME;

/**
* Property name used to enable auto-closing of {@link AutoCloseable} instances
*
* <p>By default, auto-closing is enabled.
*
* @since 5.13
*/
@API(status = EXPERIMENTAL, since = "5.13")
public static final String CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME = JupiterConfiguration.CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME;

/**
* Property name used to set the default test execution mode: {@value}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ public boolean isParallelExecutionEnabled() {
__ -> delegate.isParallelExecutionEnabled());
}

@Override
public boolean isClosingStoredAutoCloseablesEnabled() {
return (boolean) cache.computeIfAbsent(CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME,
__ -> delegate.isClosingStoredAutoCloseablesEnabled());
}

@Override
public boolean isExtensionAutoDetectionEnabled() {
return (boolean) cache.computeIfAbsent(EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ public boolean isParallelExecutionEnabled() {
return configurationParameters.getBoolean(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME).orElse(false);
}

@Override
public boolean isClosingStoredAutoCloseablesEnabled() {
return configurationParameters.getBoolean(CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME).orElse(true);
}

@Override
public boolean isExtensionAutoDetectionEnabled() {
return configurationParameters.getBoolean(EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME).orElse(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ public interface JupiterConfiguration {
String EXTENSIONS_AUTODETECTION_EXCLUDE_PROPERTY_NAME = "junit.jupiter.extensions.autodetection.exclude";
String DEACTIVATE_CONDITIONS_PATTERN_PROPERTY_NAME = "junit.jupiter.conditions.deactivate";
String PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME = "junit.jupiter.execution.parallel.enabled";
String CLOSING_STORED_AUTO_CLOSEABLE_ENABLED_PROPERTY_NAME = "junit.jupiter.extensions.store.close.autocloseable.enabled";
String DEFAULT_EXECUTION_MODE_PROPERTY_NAME = Execution.DEFAULT_EXECUTION_MODE_PROPERTY_NAME;
String DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME = Execution.DEFAULT_CLASSES_EXECUTION_MODE_PROPERTY_NAME;
String EXTENSIONS_AUTODETECTION_ENABLED_PROPERTY_NAME = "junit.jupiter.extensions.autodetection.enabled";
String EXTENSIONS_TIMEOUT_THREAD_DUMP_ENABLED_PROPERTY_NAME = PreInterruptCallback.THREAD_DUMP_ENABLED_PROPERTY_NAME;
String DEFAULT_TEST_INSTANCE_LIFECYCLE_PROPERTY_NAME = TestInstance.Lifecycle.DEFAULT_LIFECYCLE_PROPERTY_NAME;
String DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME = DisplayNameGenerator.DEFAULT_GENERATOR_PROPERTY_NAME;
String DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME = MethodOrderer.DEFAULT_ORDER_PROPERTY_NAME;
String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME;;
String DEFAULT_TEST_CLASS_ORDER_PROPERTY_NAME = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME;
String DEFAULT_TEST_INSTANTIATION_EXTENSION_CONTEXT_SCOPE_PROPERTY_NAME = ExtensionContextScope.DEFAULT_SCOPE_PROPERTY_NAME;

Predicate<Class<? extends Extension>> getFilterForAutoDetectedExtensions();
Expand All @@ -60,6 +61,8 @@ public interface JupiterConfiguration {

boolean isParallelExecutionEnabled();

boolean isClosingStoredAutoCloseablesEnabled();

boolean isExtensionAutoDetectionEnabled();

boolean isThreadDumpOnTimeoutEnabled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.junit.jupiter.api.extension.ExecutableInvoker;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;
import org.junit.jupiter.api.extension.MediaType;
import org.junit.jupiter.api.function.ThrowingConsumer;
import org.junit.jupiter.api.parallel.ExecutionMode;
Expand All @@ -36,6 +35,8 @@
import org.junit.jupiter.engine.extension.ExtensionContextInternal;
import org.junit.jupiter.engine.extension.ExtensionRegistry;
import org.junit.platform.commons.JUnitException;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.commons.util.UnrecoverableExceptions;
import org.junit.platform.engine.EngineExecutionListener;
Expand All @@ -51,22 +52,17 @@
*/
abstract class AbstractExtensionContext<T extends TestDescriptor> implements ExtensionContextInternal, AutoCloseable {

private static final NamespacedHierarchicalStore.CloseAction<org.junit.platform.engine.support.store.Namespace> CLOSE_RESOURCES = (
__, ___, value) -> {
if (value instanceof CloseableResource) {
((CloseableResource) value).close();
}
};
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractExtensionContext.class);

private final ExtensionContext parent;
private final EngineExecutionListener engineExecutionListener;
private final T testDescriptor;
private final Set<String> tags;
private final JupiterConfiguration configuration;
private final NamespacedHierarchicalStore<org.junit.platform.engine.support.store.Namespace> valuesStore;
private final ExecutableInvoker executableInvoker;
private final ExtensionRegistry extensionRegistry;
private final LauncherStoreFacade launcherStoreFacade;
private final NamespacedHierarchicalStore<org.junit.platform.engine.support.store.Namespace> valuesStore;

AbstractExtensionContext(ExtensionContext parent, EngineExecutionListener engineExecutionListener, T testDescriptor,
JupiterConfiguration configuration, ExtensionRegistry extensionRegistry,
Expand All @@ -80,7 +76,6 @@ abstract class AbstractExtensionContext<T extends TestDescriptor> implements Ext
this.engineExecutionListener = engineExecutionListener;
this.testDescriptor = testDescriptor;
this.configuration = configuration;
this.valuesStore = createStore(parent, launcherStoreFacade);
this.extensionRegistry = extensionRegistry;
this.launcherStoreFacade = launcherStoreFacade;

Expand All @@ -89,18 +84,41 @@ abstract class AbstractExtensionContext<T extends TestDescriptor> implements Ext
.map(TestTag::getName)
.collect(collectingAndThen(toCollection(LinkedHashSet::new), Collections::unmodifiableSet));
// @formatter:on

this.valuesStore = createStore(parent, launcherStoreFacade, createCloseAction());
}

@SuppressWarnings("deprecation")
private NamespacedHierarchicalStore.CloseAction<org.junit.platform.engine.support.store.Namespace> createCloseAction() {
return (__, ___, value) -> {
boolean isAutoCloseEnabled = this.configuration.isClosingStoredAutoCloseablesEnabled();

if (value instanceof AutoCloseable && isAutoCloseEnabled) {
((AutoCloseable) value).close();
return;
}

if (value instanceof Store.CloseableResource) {
if (isAutoCloseEnabled) {
LOGGER.warn(
() -> "Type implements CloseableResource but not AutoCloseable: " + value.getClass().getName());
}
((Store.CloseableResource) value).close();
}
};
}

private static NamespacedHierarchicalStore<org.junit.platform.engine.support.store.Namespace> createStore(
ExtensionContext parent, LauncherStoreFacade launcherStoreFacade) {
ExtensionContext parent, LauncherStoreFacade launcherStoreFacade,
NamespacedHierarchicalStore.CloseAction<org.junit.platform.engine.support.store.Namespace> closeAction) {
NamespacedHierarchicalStore<org.junit.platform.engine.support.store.Namespace> parentStore;
if (parent == null) {
parentStore = launcherStoreFacade.getRequestLevelStore();
}
else {
parentStore = ((AbstractExtensionContext<?>) parent).valuesStore;
}
return new NamespacedHierarchicalStore<>(parentStore, CLOSE_RESOURCES);
return new NamespacedHierarchicalStore<>(parentStore, closeAction);
}

@Override
Expand Down
Loading