1 /*
  2  * Copyright (c) 2023, 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  * @summary Basic test for Enable-Native-Access attribute in the
 27  *          manifest of a main application JAR
 28  * @library /test/lib
 29  * @requires !vm.musl
 30  *
 31  * @build TestEnableNativeAccessJarManifest
 32  *        panama_module/*
 33  *        org.openjdk.foreigntest.unnamed.PanamaMainUnnamedModule
 34  * @run testng/othervm TestEnableNativeAccessJarManifest
 35  */
 36 
 37 import java.nio.file.Files;
 38 import java.nio.file.Path;
 39 import java.nio.file.Paths;
 40 import java.util.List;
 41 import java.util.ArrayList;
 42 import java.util.jar.Attributes;
 43 import java.util.jar.Manifest;
 44 
 45 import jdk.test.lib.process.OutputAnalyzer;
 46 import jdk.test.lib.process.ProcessTools;
 47 import jdk.test.lib.util.JarUtils;
 48 
 49 import org.testng.annotations.Test;
 50 import org.testng.annotations.DataProvider;
 51 
 52 public class TestEnableNativeAccessJarManifest extends TestEnableNativeAccessBase {
 53 
 54     private static final String REINVOKER = "TestEnableNativeAccessJarManifest$Reinvoker";
 55 
 56     static record Attribute(String name, String value) {}
 57 
 58     @Test(dataProvider = "cases")
 59     public void testEnableNativeAccessInJarManifest(String action, String cls, Result expectedResult,
 60                                                     List<Attribute> attributes, List<String> vmArgs, List<String> programArgs) throws Exception {
 61         Manifest man = new Manifest();
 62         Attributes attrs = man.getMainAttributes();
 63         attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
 64         attrs.put(Attributes.Name.MAIN_CLASS, cls);
 65 
 66         for (Attribute attrib : attributes) {
 67             attrs.put(new Attributes.Name(attrib.name()), attrib.value());
 68         }
 69 
 70         // create the JAR file with Test1 and Test2
 71         Path jarfile = Paths.get(action + ".jar");
 72         Files.deleteIfExists(jarfile);
 73 
 74         Path classes = Paths.get(System.getProperty("test.classes", ""));
 75         JarUtils.createJarFile(jarfile, man, classes, Paths.get(cls.replace('.', '/') + ".class"));
 76 
 77         // java -jar test.jar
 78         List<String> command = new ArrayList<>(List.of(
 79             "-Djava.library.path=" + System.getProperty("java.library.path")
 80         ));
 81         command.addAll(vmArgs);
 82         command.add("-jar");
 83         command.add(jarfile.toString());
 84         command.addAll(programArgs);
 85         OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(command.toArray(String[]::new))
 86                 .outputTo(System.out)
 87                 .errorTo(System.out);
 88         checkResult(expectedResult, outputAnalyzer);
 89     }
 90 
 91     @DataProvider
 92     public Object[][] cases() {
 93         return new Object[][] {
 94             // simple cases where a jar contains a single main class with no dependencies
 95             { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"),
 96                     List.of(), List.of(), List.of() },
 97             { "panama_unnamed_module_native_access", UNNAMED, successNoWarning(),
 98                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")), List.of(), List.of() },
 99             { "panama_unnamed_module_native_access_invalid", UNNAMED, failWithError("Only ALL-UNNAMED allowed as value for Enable-Native-Access"),
100                     List.of(new Attribute("Enable-Native-Access", "asdf")), List.of(), List.of() },
101 
102             // more complex cases where a jar invokes a module on the module path that does native access
103             { "panama_enable_native_access_false", REINVOKER, successWithWarning("panama_module"),
104                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
105                     List.of("-p", MODULE_PATH, "--add-modules=panama_module"),
106                     List.of(PANAMA_MAIN_CLS) },
107             { "panama_enable_native_access_reflection_false", REINVOKER, successWithWarning("panama_module"),
108                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
109                     List.of("-p", MODULE_PATH, "--add-modules=panama_module"),
110                     List.of(PANAMA_REFLECTION_CLS) },
111             { "panama_enable_native_access_invoke_false", REINVOKER, successWithWarning("panama_module"),
112                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
113                     List.of("-p", MODULE_PATH, "--add-modules=panama_module"),
114                     List.of(PANAMA_INVOKE_CLS) },
115 
116             { "panama_enable_native_access_true", REINVOKER, successNoWarning(),
117                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
118                     List.of("-p", MODULE_PATH, "--add-modules=panama_module", "--enable-native-access=panama_module"),
119                     List.of(PANAMA_MAIN_CLS) },
120             { "panama_enable_native_access_reflection_true", REINVOKER, successNoWarning(),
121                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
122                     List.of("-p", MODULE_PATH, "--add-modules=panama_module", "--enable-native-access=panama_module"),
123                     List.of(PANAMA_REFLECTION_CLS) },
124             { "panama_enable_native_access_invoke_true", REINVOKER, successNoWarning(),
125                     List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
126                     List.of("-p", MODULE_PATH, "--add-modules=panama_module", "--enable-native-access=panama_module"),
127                     List.of(PANAMA_INVOKE_CLS) }
128         };
129     }
130 
131     public class Reinvoker {
132         public static void main(String[] args) throws Throwable {
133             Class<?> realMainClass = Class.forName(args[0]);
134             realMainClass.getMethod("main", String[].class).invoke(null, (Object) new String[0]);
135         }
136     }
137 }