Skip to content
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

Using terminally deprecated method System::setSecurityManager #10

Closed
relnah opened this issue Oct 11, 2021 · 8 comments
Closed

Using terminally deprecated method System::setSecurityManager #10

relnah opened this issue Oct 11, 2021 · 8 comments
Assignees
Labels
enhancement New feature or request release 2.0.0

Comments

@relnah
Copy link

relnah commented Oct 11, 2021

Hi!
Running your excellent extension with Java 17 and this caught my eye.

WARNING: System::setSecurityManager has been called by com.ginsberg.junit.exit.SystemExitExtension (file:/C:/Users/xxxxxxxx/.gradle/caches/modules-2/files-2.1/com.ginsberg/junit5-system-exit/1.1.1/528be8c6bbebb85f68264d8b18314f33b00c4768/junit5-system-exit-1.1.1.jar)
WARNING: Please consider reporting this to the maintainers of com.ginsberg.junit.exit.SystemExitExtension
WARNING: System::setSecurityManager will be removed in a future release```
@tginsberg
Copy link
Owner

tginsberg commented Oct 14, 2021

Hi @relnah, thanks for letting me know about this, and for your kind words!

People might get this warning when using junit5-system-exit on Java 17 or higher because Java's Security Manager has been deprecated for removal in JEP-411. Under the covers, this extension uses the Security Manager in order to detect when the JVM is attempting to exit, and prevent it from doing so. I wrote a blog post on how this extension works, if you are interested in the details.

Unfortunately, the deprecation warning does not come with instructions on what we're supposed to do instead. Indeed, JEP-411 mentions that this is a use case they need to consider covering:

Evaluate whether new APIs or mechanisms are needed to address specific narrow use cases for which the Security Manager has been employed, such as blocking System::exit

So for now, there's nothing we can do except wait. I know this extension isn't the only library using the Java Security Manager to do this kind of work. I'm sorry your logs will be polluted with the warning until there's a new way to detect and prevent System.exit()

I'm going to leave this issue open in case other people come here looking for a solution. I've been following JEP-411 as closely as I can, and I will attempt to upgrade this plugin (or provide another) to whatever mechanism comes out that meets our needs.

@tginsberg tginsberg self-assigned this Oct 14, 2021
@tginsberg tginsberg added blocked Progress cannot be made on this issue for now, due to reasons outside this issue. enhancement New feature or request labels Oct 14, 2021
@don-vip
Copy link

don-vip commented Nov 11, 2021

The default behaviour changed in Java 18b21 to throw an UnsupportedOperationException when calling the security manager if -Djava.security.manager=allow is not set, see:
https://bugs.openjdk.java.net/browse/JDK-8271301
https://bugs.openjdk.java.net/browse/JDK-8270380

This is the result when running a test with Java 18:

java.lang.UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release
	at java.base/java.lang.System.setSecurityManager(System.java:411)
	at com.ginsberg.junit.exit.SystemExitExtension.beforeEach(SystemExitExtension.java:86)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachCallbacks$1(TestMethodTestDescriptor.java:159)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeMethodsOrCallbacksUntilExceptionOccurs$5(TestMethodTestDescriptor.java:195)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:195)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachCallbacks(TestMethodTestDescriptor.java:158)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:125)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:185)
	at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:129)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:185)
	at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService.invokeAll(ForkJoinPoolHierarchicalTestExecutorService.java:129)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.ForkJoinPoolHierarchicalTestExecutorService$ExclusiveTask.compute(ForkJoinPoolHierarchicalTestExecutorService.java:185)
	at java.base/java.util.concurrent.RecursiveAction.exec(RecursiveAction.java:194)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
	Suppressed: org.opentest4j.AssertionFailedError: Expected System.exit(0) to be called, but it was not. ==> expected: <0> but was: <null>
		at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
		at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
		at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
		at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:569)
		at com.ginsberg.junit.exit.SystemExitExtension.afterEach(SystemExitExtension.java:66)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAfterEachCallbacks$11(TestMethodTestDescriptor.java:253)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$12(TestMethodTestDescriptor.java:269)
		at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:269)
		at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:268)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:252)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
		... 36 more

@tginsberg
Copy link
Owner

Thanks @don-vip I appreciate the example and links. I'll try to add something to the README about this. I wish there was an approved way to do this, but I'm still waiting for that.

@tginsberg
Copy link
Owner

Update: Not much to say but I am still following developments in regards to a replacement for SecurityManager::checkExit, which this library uses to perform its core function.

The JDK issue for this work has received some comments recently, which hopefully will get some attention or clarification soon.

@tginsberg
Copy link
Owner

Just an update that I'm still keeping my eye on a solution for this. The JDK issue raised for it has not seen any movement in nearly a year, but I'll keep checking.

@hardboiledphil
Copy link

For anyone still hitting this issue while migrating to Java 21. I had code that was using checkExit to ensure a failing service was being stopped with required value returned. This testing was being done through junit test run by gradle. I found that adding the following allowed me to get past the deprecation issue. I believe that null for this value won't allow a security manager to be created (the one to do the exit mocking) and an exception is thrown but setting to allow will allow the mock to be created.

        withType<Test> {
            useJUnitPlatform()

            // To allow monitoring System.Exit() we need to allow security manager so it can be overridden with mock
            // Also note this is a jvm setting so if you have a daemon running you might need to kill it to force
            // a new gradle daemon to pick up this setting when starting the jvm
            systemProperty("java.security.manager", "allow")

I didn't have this issue with java 17, well it might have issued a deprecation warning but didn't throw an exception. I did look at other libraries but was getting the same issue - presumably as they all go through this system file and hit the same code.

@tginsberg
Copy link
Owner

Thanks for the note @hardboiledphil, I've updated the README to account for this.

Still no word on what the future is like for preventing System.exit() calls, but I'll keep you posted when something gets announced.

@tginsberg tginsberg added release 2.0.0 and removed blocked Progress cannot be made on this issue for now, due to reasons outside this issue. labels Aug 30, 2024
@tginsberg
Copy link
Owner

tginsberg commented Sep 7, 2024

I have just released v2.0.0, which should address issues with the terminally deprecated SecurityManager approach. The 2.0.0 version uses a Java Agent to rewrite the Java bytecode as the JVM loads it, replacing System.exit() calls with code that prevents the JVM from exiting if a test is currently being run. Please see the README for details on how to install it. While the API is the same, I also shipped an AssertJ-style fluid assertion as well, if you don't want to use the annotation-based approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request release 2.0.0
Projects
None yet
Development

No branches or pull requests

4 participants