title: Why does running a test in a forked process make Java fail to load a native library?
body: <p>I work on an application that uses a Java library that interfaces with a native library. We're discovering recently that unit tests (using the spring runner) of this code are consistently failing under specific circumstances, but successful in other circumstances.</p>
  <p>We use Java 8 and SpringBoot 2.3.12.</p>
  <p>I'm currently running these tests on Windows 10.
  When I run the tests from &quot;mvn package&quot; without any special qualifications, the tests run successfully.</p>
  <p>When I run any of the tests in Eclipse (2022-03), I get <code>UnsatisfiedLinkError</code>, and it refers to the first method in a particular class which is defined as &quot;native&quot;.  I don't think there's anything special about the class or method, it's likely just the first one that it tries to load.</p>
  <p>I also get the exact same error when I add the following properties to my Surefire configuration:</p>
  <pre><code>                &lt;reuseForks&gt;false&lt;/reuseForks&gt;
                  &lt;forkCount&gt;1&lt;/forkCount&gt;
  </code></pre>
  <p>These force each test to run in a separate and new jvm instance.</p>
  <p>I also augmented the code that gets run to print out all of the environment variables and system properties.  I stored the results for both the &quot;good&quot; test and the &quot;bad&quot; test into separate files, and I compared them.  There were no significant differences.  Both the java.class.path and java.library.path system property values were identical, along with the PATH environment variable.  The &quot;good&quot; test had a couple of environment variables that indicated the process id.</p>
  <p>I tried running SysInternals ProcMon, and I had it filter on the name of the DLL with the native code.  I did this while running both the &quot;good&quot; and &quot;bad&quot; tests.  Both of them appeared to open the correct dll.</p>
  <p>I could use some ideas of what else to try here.</p>
  <p>If it helps, here is an elided &quot;tail&quot; of the stacktrace (the last &quot;Caused by&quot;). The elided sections are names in our application, which aren't relevant:</p>
  <pre><code>Caused by: java.lang.UnsatisfiedLinkError: com....DIGEST_MD5()I
      at .....DIGEST_MD5(Native Method)
      at .....LibraryContextNative.&lt;clinit&gt;(LibraryContextNative.java:17)
      at .....LibraryContext.getVersion(LibraryContext.java:730)
      at .....getLibraryContext(VoltageHelper.java:142)
      at .....&lt;init&gt;(VoltageHelper.java:99)
      at .....&lt;init&gt;(EncryptorVoltageHelper.java:56)
      at ....getInstance(EncryptorVoltageHelper.java:97)
      at .....getInstance(EncryptorVoltageHelper.java:136)
      at ....&lt;init&gt;(VoltageEncryptFilter.java:72)
      at ...
      at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
      at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
      at ...
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
      at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652)
      at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:485)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1341)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
      at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
      at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)
      at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
      at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
      at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:127)
      at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
      at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:275)
      at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:243)
      at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
      at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
      at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
      at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
      at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
      at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
      at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
      at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
      at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
      at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
      at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
      at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
      at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
      at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
  </code></pre>