Path: blob/master/test/jdk/sun/tools/jcmd/TestProcessHelper.java
41149 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.File;24import java.io.IOException;25import java.io.OutputStream;26import java.lang.invoke.MethodHandle;27import java.lang.invoke.MethodHandles;28import java.lang.module.ModuleDescriptor;29import java.lang.reflect.Method;30import java.nio.file.FileSystems;31import java.nio.file.Files;32import java.nio.file.Path;33import java.util.ArrayList;34import java.util.LinkedList;35import java.util.List;36import java.util.jar.Attributes;37import java.util.jar.JarEntry;38import java.util.jar.JarOutputStream;39import java.util.jar.Manifest;40import java.util.stream.Collectors;41import java.util.stream.Stream;4243import jdk.internal.module.ModuleInfoWriter;44import jdk.test.lib.JDKToolFinder;45import jdk.test.lib.process.ProcessTools;46import jdk.test.lib.util.JarUtils;4748/*49* @test50* @bug 820565451* @summary Unit test for sun.tools.ProcessHelper class. The test launches Java processes with different Java options52* and checks that sun.tools.ProcessHelper.getMainClass(pid) method returns a correct main class. return a .53*54* @requires os.family == "linux"55* @library /test/lib56* @modules jdk.jcmd/sun.tools.common:+open57* java.base/jdk.internal.module58* @build test.TestProcess59* @run main/othervm TestProcessHelper60*/61public class TestProcessHelper {6263private static final String TEST_PROCESS_MAIN_CLASS_NAME = "TestProcess";64private static final String TEST_PROCESS_MAIN_CLASS_PACKAGE = "test";65private static final String TEST_PROCESS_MAIN_CLASS = TEST_PROCESS_MAIN_CLASS_PACKAGE + "."66+ TEST_PROCESS_MAIN_CLASS_NAME;67private static final Path TEST_CLASSES = FileSystems.getDefault().getPath(System.getProperty("test.classes"));68private static final Path USER_DIR = FileSystems.getDefault().getPath(System.getProperty("user.dir", "."));69private static final Path TEST_MODULES = USER_DIR.resolve("testmodules");70private static final String JAVA_PATH = JDKToolFinder.getJDKTool("java");71private static final Path TEST_CLASS = TEST_CLASSES.resolve(TEST_PROCESS_MAIN_CLASS_PACKAGE)72.resolve(TEST_PROCESS_MAIN_CLASS_NAME + ".class");7374private static final String[] CP_OPTIONS = {"-cp", "-classpath", "--class-path"};75private static final String[][] VM_ARGS = {{}, {"-Dtest1=aaa"}, {"-Dtest1=aaa", "-Dtest2=bbb ccc"}};76private static final String[][] ARGS = {{}, {"param1"}, {"param1", "param2"}};77private static final String[] MP_OPTIONS = {"-p", "--module-path"};78private static final String[] MODULE_OPTIONS = {"-m", "--module", "--module="};79private static final String JAR_OPTION = "-jar";80private static final String MODULE_NAME = "module1";81private static final String[][] EXTRA_MODULAR_OPTIONS = {null,82{"--add-opens", "java.base/java.net=ALL-UNNAMED"},83{"--add-exports", "java.base/java.net=ALL-UNNAMED"},84{"--add-reads", "java.base/java.net=ALL-UNNAMED"},85{"--add-modules", "java.management"},86{"--limit-modules", "java.management"},87{"--upgrade-module-path", "test"}};8889private static final String[] PATCH_MODULE_OPTIONS = {"--patch-module", null};9091private static final MethodHandle MH_GET_MAIN_CLASS = resolveMainClassMH();9293private static MethodHandle resolveMainClassMH() {94try {95Method getMainClassMethod = Class96.forName("sun.tools.common.ProcessHelper")97.getDeclaredMethod("getMainClass", String.class);98getMainClassMethod.setAccessible(true);99return MethodHandles.lookup().unreflect(getMainClassMethod);100} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) {101throw new RuntimeException(e);102}103}104105private static String callGetMainClass(Process p) {106try {107return (String)MH_GET_MAIN_CLASS.invoke(Long.toString(p.pid()));108} catch (Throwable e) {109throw new RuntimeException(e);110}111112}113114public static void main(String[] args) throws Exception {115new TestProcessHelper().runTests();116}117118public void runTests() throws Exception {119testClassPath();120testJar();121testModule();122}123124// Test Java processes that are started with -classpath, -cp, or --class-path options125// and with different combinations of VM and program args.126private void testClassPath() throws Exception {127for (String cp : CP_OPTIONS) {128for (String[] vma : VM_ARGS) {129for (String[] arg : ARGS) {130for (String[] modularOptions : EXTRA_MODULAR_OPTIONS) {131List<String> cmd = new LinkedList<>();132cmd.add(JAVA_PATH);133cmd.add(cp);134cmd.add(TEST_CLASSES.toAbsolutePath().toString());135for (String v : vma) {136cmd.add(v);137}138if (modularOptions != null) {139cmd.add(modularOptions[0]);140cmd.add(modularOptions[1]);141}142cmd.add(TEST_PROCESS_MAIN_CLASS);143for (String a : arg) {144cmd.add(a);145}146testProcessHelper(cmd, TEST_PROCESS_MAIN_CLASS);147}148}149}150}151}152153// Test Java processes that are started with -jar option154// and with different combinations of VM and program args.155private void testJar() throws Exception {156File jarFile = prepareJar();157for (String[] vma : VM_ARGS) {158for (String[] arg : ARGS) {159List<String> cmd = new LinkedList<>();160cmd.add(JAVA_PATH);161for (String v : vma) {162cmd.add(v);163}164cmd.add(JAR_OPTION);165cmd.add(jarFile.getAbsolutePath());166for (String a : arg) {167cmd.add(a);168}169testProcessHelper(cmd, jarFile.getAbsolutePath());170}171}172173}174175// Test Java processes that are started with -m or --module options176// and with different combination of VM and program args.177private void testModule() throws Exception {178prepareModule();179for (String mp : MP_OPTIONS) {180for (String m : MODULE_OPTIONS) {181for (String[] vma : VM_ARGS) {182for (String[] arg : ARGS) {183for(String patchModuleOption : PATCH_MODULE_OPTIONS) {184List<String> cmd = new LinkedList<>();185cmd.add(JAVA_PATH);186cmd.add(mp);187cmd.add(TEST_MODULES.toAbsolutePath().toString());188if (patchModuleOption != null) {189cmd.add(patchModuleOption);190cmd.add(MODULE_NAME + "=" + TEST_MODULES.toAbsolutePath().toString());191}192for (String v : vma) {193cmd.add(v);194}195if (m.endsWith("=")) {196cmd.add(m + MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS);197} else {198cmd.add(m);199cmd.add(MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS);200}201for (String a : arg) {202cmd.add(a);203}204testProcessHelper(cmd, MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS);205}206}207}208}209}210}211212private void checkMainClass(Process p, String expectedMainClass) {213String mainClass = callGetMainClass(p);214// getMainClass() may return null, e.g. due to timing issues.215// Attempt some limited retries.216if (mainClass == null) {217System.err.println("Main class returned by ProcessHelper was null.");218// sleep time doubles each round, altogether, wait no longer than 1 sec219final int MAX_RETRIES = 10;220int retrycount = 0;221long sleepms = 1;222while (retrycount < MAX_RETRIES && mainClass == null) {223System.err.println("Retry " + retrycount + ", sleeping for " + sleepms + "ms.");224try {225Thread.sleep(sleepms);226} catch (InterruptedException e) {227// ignore228}229mainClass = callGetMainClass(p);230retrycount++;231sleepms *= 2;232}233}234p.destroyForcibly();235if (!expectedMainClass.equals(mainClass)) {236throw new RuntimeException("Main class is wrong: " + mainClass);237}238}239240private void testProcessHelper(List<String> args, String expectedValue) throws Exception {241ProcessBuilder pb = new ProcessBuilder(args);242String cmd = pb.command().stream().collect(Collectors.joining(" "));243System.out.println("Starting the process:" + cmd);244Process p = ProcessTools.startProcess("test", pb);245if (!p.isAlive()) {246throw new RuntimeException("Cannot start the process: " + cmd);247}248checkMainClass(p, expectedValue);249}250251private File prepareJar() throws Exception {252Path jarFile = USER_DIR.resolve("testprocess.jar");253Manifest manifest = createManifest();254JarUtils.createJarFile(jarFile, manifest, TEST_CLASSES, TEST_CLASS);255return jarFile.toFile();256}257258private void prepareModule() throws Exception {259TEST_MODULES.toFile().mkdirs();260Path moduleJar = TEST_MODULES.resolve("mod1.jar");261ModuleDescriptor md = createModuleDescriptor();262createModuleJarFile(moduleJar, md, TEST_CLASSES, TEST_CLASS);263}264265private Manifest createManifest() {266Manifest manifest = new Manifest();267manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");268manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, TEST_PROCESS_MAIN_CLASS);269return manifest;270}271272private ModuleDescriptor createModuleDescriptor() {273ModuleDescriptor.Builder builder274= ModuleDescriptor.newModule(MODULE_NAME).requires("java.base");275return builder.build();276}277278private static void createModuleJarFile(Path jarfile, ModuleDescriptor md, Path dir, Path... files)279throws IOException {280281Path parent = jarfile.getParent();282if (parent != null) {283Files.createDirectories(parent);284}285286List<Path> entries = findAllRegularFiles(dir, files);287288try (OutputStream out = Files.newOutputStream(jarfile);289JarOutputStream jos = new JarOutputStream(out)) {290if (md != null) {291JarEntry je = new JarEntry("module-info.class");292jos.putNextEntry(je);293ModuleInfoWriter.write(md, jos);294jos.closeEntry();295}296297for (Path entry : entries) {298String name = toJarEntryName(entry);299jos.putNextEntry(new JarEntry(name));300Files.copy(dir.resolve(entry), jos);301jos.closeEntry();302}303}304}305306private static String toJarEntryName(Path file) {307Path normalized = file.normalize();308return normalized.subpath(0, normalized.getNameCount())309.toString()310.replace(File.separatorChar, '/');311}312313private static List<Path> findAllRegularFiles(Path dir, Path[] files) throws IOException {314List<Path> entries = new ArrayList<>();315for (Path file : files) {316try (Stream<Path> stream = Files.find(dir.resolve(file), Integer.MAX_VALUE,317(p, attrs) -> attrs.isRegularFile())) {318stream.map(dir::relativize)319.forEach(entries::add);320}321}322return entries;323}324325}326327328