44package net .openhft .affinity ;
55
66import org .junit .jupiter .api .Test ;
7+ import org .junit .jupiter .api .condition .EnabledForJreRange ;
78import org .junit .jupiter .api .condition .EnabledOnOs ;
9+ import org .junit .jupiter .api .condition .JRE ;
810import org .junit .jupiter .api .condition .OS ;
911
1012import java .io .File ;
13+ import java .io .InputStream ;
1114import java .net .URL ;
1215import java .net .URLClassLoader ;
16+ import java .nio .file .Files ;
17+ import java .util .Arrays ;
18+ import java .util .jar .JarEntry ;
19+ import java .util .jar .JarFile ;
1320
1421import static org .junit .jupiter .api .Assertions .*;
1522
@@ -34,13 +41,46 @@ void fallsBackWhenJnaNativeLoadingFails() throws Exception {
3441 }
3542
3643 @ Test
37- void propagatesVmAndAssertionFailures () throws Exception {
44+ void fallsBackWhenJnaNativeVersionIsIncompatible () throws Exception {
45+ // The newer fixture's native ABI is incompatible with the BOM's JNA 5.5 Java classes.
46+ try (JarFile jar = new JarFile (jnaModuleJar ())) {
47+ String resource = "com/sun/jna/" + com .sun .jna .Platform .RESOURCE_PREFIX + "/libjnidispatch.so" ;
48+ JarEntry entry = jar .getJarEntry (resource );
49+ assertNotNull (entry , resource );
50+ try (InputStream input = jar .getInputStream (entry )) {
51+ Files .copy (input , directory .resolve ("libjnidispatch.so" ));
52+ }
53+ }
54+ String log = runProbe (AffinityInitializationTest .class , "native-failure" , true ,
55+ "-Djna.boot.library.path=" + directory .toAbsolutePath (),
56+ "-Djna.nosys=true" , "-Djna.noclasspath=true" );
57+ assertTrue (log .contains ("java.lang.Error:" ), log );
58+ assertTrue (log .contains ("incompatible JNA native library" ), log );
59+ }
60+
61+ @ Test
62+ @ EnabledForJreRange (min = JRE .JAVA_9 )
63+ void selectsJnaFromExportedButUnopenedModule () throws Exception {
64+ runProbe (AffinityInitializationTest .class , "module" , false ,
65+ "--module-path=" + jnaModuleJar (), "--add-modules=com.sun.jna" );
66+ }
67+
68+ private static String jnaModuleJar () {
69+ return Arrays .stream (testClasspath ().split (File .pathSeparator ))
70+ .filter (entry -> new File (entry ).getName ().startsWith ("jna-jpms-" ))
71+ .findFirst ().orElseThrow (() -> new AssertionError ("Missing JNA module test fixture" ));
72+ }
73+
74+ @ Test
75+ @ SuppressWarnings ("removal" ) // ThreadDeath remains relevant to supported older JDKs.
76+ void propagatesVmThreadTerminationAndAssertionFailures () throws Exception {
3877 String [] entries = testClasspath ().split (File .pathSeparator );
3978 URL [] urls = new URL [entries .length ];
4079 for (int i = 0 ; i < entries .length ; i ++) {
4180 urls [i ] = new File (entries [i ]).toURI ().toURL ();
4281 }
43- for (Error failure : new Error []{new OutOfMemoryError ("test loading failure" ), new AssertionError ("test loading failure" )}) {
82+ for (Error failure : new Error []{new OutOfMemoryError ("test loading failure" ), new ThreadDeath (),
83+ new AssertionError ("test loading failure" )}) {
4484 try (URLClassLoader loader = new URLClassLoader (urls , null ) {
4585 @ Override
4686 protected Class <?> loadClass (String name , boolean resolve ) throws ClassNotFoundException {
@@ -66,10 +106,17 @@ public static void main(String[] args) throws Exception {
66106 } else {
67107 assertNotNull (Class .forName ("com.sun.jna.Native" , false , loader ));
68108 }
69- if (scenario .equals ("normal" )) {
109+ if (scenario .equals ("normal" ) || scenario . equals ( "module" ) ) {
70110 assertTrue (Affinity .isJNAAvailable ());
71111 assertEquals ("net.openhft.affinity.impl.LinuxJNAAffinity" , Affinity .getAffinityImpl ().getClass ().getName ());
72112 assertFalse (Affinity .getAffinity ().isEmpty ());
113+ if (scenario .equals ("module" )) {
114+ // Reflection here keeps these tests compilable on Java 8; the module run requires Java 9+.
115+ Object module = Class .class .getMethod ("getModule" ).invoke (Class .forName ("com.sun.jna.Native" ));
116+ assertEquals (Boolean .TRUE , module .getClass ().getMethod ("isNamed" ).invoke (module ));
117+ assertEquals (Boolean .TRUE , module .getClass ().getMethod ("isExported" , String .class ).invoke (module , "com.sun.jna" ));
118+ assertEquals (Boolean .FALSE , module .getClass ().getMethod ("isOpen" , String .class ).invoke (module , "com.sun.jna" ));
119+ }
73120 } else {
74121 assertFalse (Affinity .isJNAAvailable ());
75122 assertEquals ("net.openhft.affinity.impl.NullAffinity" , Affinity .getAffinityImpl ().getClass ().getName ());
0 commit comments