1 /* 2 * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @enablePreview 27 * @requires jdk.foreign.linker != "UNSUPPORTED" 28 * @requires !vm.musl 29 * 30 * @library /test/lib 31 * @build TestEnableNativeAccess 32 * panama_module/* 33 * org.openjdk.foreigntest.PanamaMainUnnamedModule 34 * @run testng/othervm/timeout=180 TestEnableNativeAccess 35 * @summary Basic test for java --enable-native-access 36 */ 37 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.stream.Stream; 41 42 import jdk.test.lib.process.ProcessTools; 43 import jdk.test.lib.process.OutputAnalyzer; 44 45 import org.testng.annotations.DataProvider; 46 import org.testng.annotations.Test; 47 import static org.testng.Assert.*; 48 49 /** 50 * Basic test of --enable-native-access with expected behaviour: 51 * 52 * if flag present: - permit access to modules that are specified 53 * - deny access to modules that are not specified 54 * (throw IllegalCallerException) 55 * if flag not present: - permit access to all modules and omit a warning 56 * (on first access per module only) 57 */ 58 59 @Test 60 public class TestEnableNativeAccess { 61 62 static final String MODULE_PATH = System.getProperty("jdk.module.path"); 63 64 static final String PANAMA_MAIN = "panama_module/org.openjdk.foreigntest.PanamaMainDirect"; 65 static final String PANAMA_REFLECTION = "panama_module/org.openjdk.foreigntest.PanamaMainReflection"; 66 static final String PANAMA_INVOKE = "panama_module/org.openjdk.foreigntest.PanamaMainInvoke"; 67 static final String PANAMA_JNI = "panama_module/org.openjdk.foreigntest.PanamaMainJNI"; 68 static final String UNNAMED = "org.openjdk.foreigntest.PanamaMainUnnamedModule"; 69 70 /** 71 * Represents the expected result of a test. 72 */ 73 static final class Result { 74 private final boolean success; 75 private final List<String> expectedOutput = new ArrayList<>(); 76 private final List<String> notExpectedOutput = new ArrayList<>(); 77 78 Result(boolean success) { 79 this.success = success; 80 } 81 82 Result expect(String msg) { 83 expectedOutput.add(msg); 84 return this; 85 } 86 87 Result doNotExpect(String msg) { 88 notExpectedOutput.add(msg); 89 return this; 90 } 91 92 boolean shouldSucceed() { 93 return success; 94 } 95 96 Stream<String> expectedOutput() { 97 return expectedOutput.stream(); 98 } 99 100 Stream<String> notExpectedOutput() { 101 return notExpectedOutput.stream(); 102 } 103 104 @Override 105 public String toString() { 106 String s = (success) ? "success" : "failure"; 107 for (String msg : expectedOutput) { 108 s += "/" + msg; 109 } 110 return s; 111 } 112 } 113 114 static Result success() { 115 return new Result(true); 116 } 117 118 static Result successNoWarning() { 119 return success().doNotExpect("WARNING"); 120 } 121 122 static Result successWithWarning(String moduleName) { 123 return success().expect("WARNING").expect("--enable-native-access=" + moduleName); 124 } 125 126 static Result failWithWarning(String expectedOutput) { 127 return new Result(false).expect(expectedOutput).expect("WARNING"); 128 } 129 130 @DataProvider(name = "succeedCases") 131 public Object[][] succeedCases() { 132 return new Object[][] { 133 { "panama_enable_native_access", PANAMA_MAIN, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, 134 { "panama_enable_native_access_reflection", PANAMA_REFLECTION, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, 135 { "panama_enable_native_access_invoke", PANAMA_INVOKE, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, 136 { "panama_enable_native_access_jni", PANAMA_JNI, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, 137 138 { "panama_comma_separated_enable", PANAMA_MAIN, successNoWarning(), new String[]{"--enable-native-access=java.base,panama_module"} }, 139 { "panama_comma_separated_enable_reflection", PANAMA_REFLECTION, successNoWarning(), new String[]{"--enable-native-access=java.base,panama_module"} }, 140 { "panama_comma_separated_enable_invoke", PANAMA_INVOKE, successNoWarning(), new String[]{"--enable-native-access=java.base,panama_module"} }, 141 { "panama_comma_separated_enable_jni", PANAMA_JNI, successNoWarning(), new String[]{"--enable-native-access=java.base,ALL-UNNAMED"} }, 142 143 { "panama_enable_native_access_warn", PANAMA_MAIN, successWithWarning("panama"), new String[]{} }, 144 { "panama_enable_native_access_warn_reflection", PANAMA_REFLECTION, successWithWarning("panama"), new String[]{} }, 145 { "panama_enable_native_access_warn_invoke", PANAMA_INVOKE, successWithWarning("panama"), new String[]{} }, 146 { "panama_enable_native_access_warn_jni", PANAMA_JNI, successWithWarning("ALL-UNNAMED"), new String[]{} }, 147 148 { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"), new String[]{} }, 149 { "panama_all_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, 150 }; 151 } 152 153 /** 154 * Checks an expected result with the output captured by the given 155 * OutputAnalyzer. 156 */ 157 void checkResult(Result expectedResult, OutputAnalyzer outputAnalyzer) { 158 expectedResult.expectedOutput().forEach(outputAnalyzer::shouldContain); 159 expectedResult.notExpectedOutput().forEach(outputAnalyzer::shouldNotContain); 160 int exitValue = outputAnalyzer.getExitValue(); 161 if (expectedResult.shouldSucceed()) { 162 assertTrue(exitValue == 0); 163 } else { 164 assertTrue(exitValue != 0); 165 } 166 } 167 168 /** 169 * Runs the test to execute the given test action. The VM is run with the 170 * given VM options and the output checked to see that it matches the 171 * expected result. 172 */ 173 OutputAnalyzer run(String action, String cls, Result expectedResult, String... vmopts) 174 throws Exception 175 { 176 Stream<String> s1 = Stream.concat( 177 Stream.of(vmopts), 178 Stream.of("-Djava.library.path=" + System.getProperty("java.library.path"))); 179 Stream<String> s2 = cls.equals(UNNAMED) ? Stream.of("--enable-preview", "-p", MODULE_PATH, cls, action) 180 : Stream.of("--enable-preview", "-p", MODULE_PATH, "-m", cls, action); 181 String[] opts = Stream.concat(s1, s2).toArray(String[]::new); 182 OutputAnalyzer outputAnalyzer = ProcessTools 183 .executeTestJava(opts) 184 .outputTo(System.out) 185 .errorTo(System.out); 186 checkResult(expectedResult, outputAnalyzer); 187 return outputAnalyzer; 188 } 189 190 @Test(dataProvider = "succeedCases") 191 public void testSucceed(String action, String cls, Result expectedResult, String... vmopts) throws Exception { 192 run(action, cls, expectedResult, vmopts); 193 } 194 195 /** 196 * Tests that without --enable-native-access, a multi-line warning is printed 197 * on first access of a module. 198 */ 199 public void testWarnFirstAccess() throws Exception { 200 List<String> output1 = run("panama_enable_native_access_first", PANAMA_MAIN, 201 successWithWarning("panama")).asLines(); 202 assertTrue(count(output1, "WARNING") == 3); // 3 on first access, none on subsequent access 203 } 204 205 /** 206 * Specifies --enable-native-access more than once, each list of module names 207 * is appended. 208 */ 209 public void testRepeatedOption() throws Exception { 210 run("panama_enable_native_access_last_one_wins", PANAMA_MAIN, 211 success(), "--enable-native-access=java.base", "--enable-native-access=panama_module"); 212 run("panama_enable_native_access_last_one_wins", PANAMA_MAIN, 213 success(), "--enable-native-access=panama_module", "--enable-native-access=java.base"); 214 } 215 216 /** 217 * Specifies bad value to --enable-native-access. 218 */ 219 public void testBadValue() throws Exception { 220 run("panama_enable_native_access_warn_unknown_module", PANAMA_MAIN, 221 failWithWarning("WARNING: Unknown module: BAD specified to --enable-native-access"), 222 "--enable-native-access=BAD"); 223 run("panama_no_all_module_path_blanket_native_access", PANAMA_MAIN, 224 failWithWarning("WARNING: Unknown module: ALL-MODULE-PATH specified to --enable-native-access"), 225 "--enable-native-access=ALL-MODULE-PATH" ); 226 } 227 228 private int count(Iterable<String> lines, CharSequence cs) { 229 int count = 0; 230 for (String line : lines) { 231 if (line.contains(cs)) count++; 232 } 233 return count; 234 } 235 }