19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
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 |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 import jdk.internal.module.ModuleInfoWriter; |
|
25 import jdk.test.lib.JDKToolFinder; |
|
26 import jdk.test.lib.process.ProcessTools; |
|
27 import jdk.test.lib.util.JarUtils; |
|
28 import sun.tools.common.ProcessHelper; |
|
29 |
|
30 import java.io.File; |
24 import java.io.File; |
31 import java.io.IOException; |
25 import java.io.IOException; |
32 import java.io.OutputStream; |
26 import java.io.OutputStream; |
|
27 import java.lang.invoke.MethodHandle; |
|
28 import java.lang.invoke.MethodHandles; |
33 import java.lang.module.ModuleDescriptor; |
29 import java.lang.module.ModuleDescriptor; |
|
30 import java.lang.reflect.Method; |
34 import java.nio.file.FileSystems; |
31 import java.nio.file.FileSystems; |
35 import java.nio.file.Files; |
32 import java.nio.file.Files; |
36 import java.nio.file.Path; |
33 import java.nio.file.Path; |
37 import java.util.ArrayList; |
34 import java.util.ArrayList; |
38 import java.util.LinkedList; |
35 import java.util.LinkedList; |
42 import java.util.jar.JarOutputStream; |
39 import java.util.jar.JarOutputStream; |
43 import java.util.jar.Manifest; |
40 import java.util.jar.Manifest; |
44 import java.util.stream.Collectors; |
41 import java.util.stream.Collectors; |
45 import java.util.stream.Stream; |
42 import java.util.stream.Stream; |
46 |
43 |
|
44 import jdk.internal.module.ModuleInfoWriter; |
|
45 import jdk.test.lib.JDKToolFinder; |
|
46 import jdk.test.lib.process.ProcessTools; |
|
47 import jdk.test.lib.util.JarUtils; |
|
48 |
47 /* |
49 /* |
48 * @test |
50 * @test |
49 * @bug 8205654 |
51 * @bug 8205654 |
50 * @summary Unit test for sun.tools.ProcessHelper class. The test launches Java processes with different Java options |
52 * @summary Unit test for sun.tools.ProcessHelper class. The test launches Java processes with different Java options |
51 * and checks that sun.tools.ProcessHelper.getMainClass(pid) method returns a correct main class. return a . |
53 * and checks that sun.tools.ProcessHelper.getMainClass(pid) method returns a correct main class. return a . |
52 * |
54 * |
53 * @requires os.family == "linux" |
55 * @requires os.family == "linux" |
54 * @library /test/lib |
56 * @library /test/lib |
55 * @modules jdk.jcmd/sun.tools.common |
57 * @modules jdk.jcmd/sun.tools.common:+open |
56 * java.base/jdk.internal.module |
58 * java.base/jdk.internal.module |
57 * @build test.TestProcess |
59 * @build test.TestProcess |
58 * @run main/othervm TestProcessHelper |
60 * @run main/othervm TestProcessHelper |
59 */ |
61 */ |
60 public class TestProcessHelper { |
62 public class TestProcessHelper { |
61 |
|
62 private ProcessHelper PROCESS_HELPER = ProcessHelper.platformProcessHelper(); |
|
63 |
63 |
64 private static final String TEST_PROCESS_MAIN_CLASS_NAME = "TestProcess"; |
64 private static final String TEST_PROCESS_MAIN_CLASS_NAME = "TestProcess"; |
65 private static final String TEST_PROCESS_MAIN_CLASS_PACKAGE = "test"; |
65 private static final String TEST_PROCESS_MAIN_CLASS_PACKAGE = "test"; |
66 private static final String TEST_PROCESS_MAIN_CLASS = TEST_PROCESS_MAIN_CLASS_PACKAGE + "." |
66 private static final String TEST_PROCESS_MAIN_CLASS = TEST_PROCESS_MAIN_CLASS_PACKAGE + "." |
67 + TEST_PROCESS_MAIN_CLASS_NAME; |
67 + TEST_PROCESS_MAIN_CLASS_NAME; |
71 private static final String JAVA_PATH = JDKToolFinder.getJDKTool("java"); |
71 private static final String JAVA_PATH = JDKToolFinder.getJDKTool("java"); |
72 private static final Path TEST_CLASS = TEST_CLASSES.resolve(TEST_PROCESS_MAIN_CLASS_PACKAGE) |
72 private static final Path TEST_CLASS = TEST_CLASSES.resolve(TEST_PROCESS_MAIN_CLASS_PACKAGE) |
73 .resolve(TEST_PROCESS_MAIN_CLASS_NAME + ".class"); |
73 .resolve(TEST_PROCESS_MAIN_CLASS_NAME + ".class"); |
74 |
74 |
75 private static final String[] CP_OPTIONS = {"-cp", "-classpath", "--class-path"}; |
75 private static final String[] CP_OPTIONS = {"-cp", "-classpath", "--class-path"}; |
76 private static final String[][] VM_ARGS = {{}, {"-Dtest1=aaa"}, {"-Dtest1=aaa", "-Dtest2=bbb"}}; |
76 private static final String[][] VM_ARGS = {{}, {"-Dtest1=aaa"}, {"-Dtest1=aaa", "-Dtest2=bbb ccc"}}; |
77 private static final String[][] ARGS = {{}, {"param1"}, {"param1", "param2"}}; |
77 private static final String[][] ARGS = {{}, {"param1"}, {"param1", "param2"}}; |
78 private static final String[] MP_OPTIONS = {"-p", "--module-path"}; |
78 private static final String[] MP_OPTIONS = {"-p", "--module-path"}; |
79 private static final String[] MODULE_OPTIONS = {"-m", "--module"}; |
79 private static final String[] MODULE_OPTIONS = {"-m", "--module", "--module="}; |
80 private static final String JAR_OPTION = "-jar"; |
80 private static final String JAR_OPTION = "-jar"; |
81 private static final String MODULE_NAME = "module1"; |
81 private static final String MODULE_NAME = "module1"; |
82 |
82 private static final String[][] EXTRA_MODULAR_OPTIONS = {null, |
|
83 {"--add-opens", "java.base/java.net=ALL-UNNAMED"}, |
|
84 {"--add-exports", "java.base/java.net=ALL-UNNAMED"}, |
|
85 {"--add-reads", "java.base/java.net=ALL-UNNAMED"}, |
|
86 {"--add-modules", "java.management"}, |
|
87 {"--limit-modules", "java.management"}, |
|
88 {"--upgrade-module-path", "test"}}; |
|
89 |
|
90 private static final String[] PATCH_MODULE_OPTIONS = {"--patch-module", null}; |
|
91 |
|
92 private static final MethodHandle MH_GET_MAIN_CLASS = resolveMainClassMH(); |
|
93 |
|
94 private static MethodHandle resolveMainClassMH() { |
|
95 try { |
|
96 Method getMainClassMethod = Class |
|
97 .forName("sun.tools.common.ProcessHelper") |
|
98 .getDeclaredMethod("getMainClass", String.class); |
|
99 getMainClassMethod.setAccessible(true); |
|
100 return MethodHandles.lookup().unreflect(getMainClassMethod); |
|
101 } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) { |
|
102 throw new RuntimeException(e); |
|
103 } |
|
104 } |
|
105 |
|
106 private static String callGetMainClass(Process p) { |
|
107 try { |
|
108 return (String)MH_GET_MAIN_CLASS.invoke(Long.toString(p.pid())); |
|
109 } catch (Throwable e) { |
|
110 throw new RuntimeException(e); |
|
111 } |
|
112 |
|
113 } |
83 |
114 |
84 public static void main(String[] args) throws Exception { |
115 public static void main(String[] args) throws Exception { |
85 new TestProcessHelper().runTests(); |
116 new TestProcessHelper().runTests(); |
86 } |
117 } |
87 |
118 |
95 // and with different combinations of VM and program args. |
126 // and with different combinations of VM and program args. |
96 private void testClassPath() throws Exception { |
127 private void testClassPath() throws Exception { |
97 for (String cp : CP_OPTIONS) { |
128 for (String cp : CP_OPTIONS) { |
98 for (String[] vma : VM_ARGS) { |
129 for (String[] vma : VM_ARGS) { |
99 for (String[] arg : ARGS) { |
130 for (String[] arg : ARGS) { |
100 List<String> cmd = new LinkedList<>(); |
131 for (String[] modularOptions : EXTRA_MODULAR_OPTIONS) { |
101 cmd.add(JAVA_PATH); |
132 List<String> cmd = new LinkedList<>(); |
102 cmd.add(cp); |
133 cmd.add(JAVA_PATH); |
103 cmd.add(TEST_CLASSES.toAbsolutePath().toString()); |
134 cmd.add(cp); |
104 for (String v : vma) { |
135 cmd.add(TEST_CLASSES.toAbsolutePath().toString()); |
105 cmd.add(v); |
136 for (String v : vma) { |
|
137 cmd.add(v); |
|
138 } |
|
139 if (modularOptions != null) { |
|
140 cmd.add(modularOptions[0]); |
|
141 cmd.add(modularOptions[1]); |
|
142 } |
|
143 cmd.add(TEST_PROCESS_MAIN_CLASS); |
|
144 for (String a : arg) { |
|
145 cmd.add(a); |
|
146 } |
|
147 testProcessHelper(cmd, TEST_PROCESS_MAIN_CLASS); |
106 } |
148 } |
107 cmd.add(TEST_PROCESS_MAIN_CLASS); |
|
108 for (String a : arg) { |
|
109 cmd.add(a); |
|
110 } |
|
111 testProcessHelper(cmd, TEST_PROCESS_MAIN_CLASS); |
|
112 } |
149 } |
113 } |
150 } |
114 } |
151 } |
115 } |
152 } |
116 |
153 |
142 prepareModule(); |
179 prepareModule(); |
143 for (String mp : MP_OPTIONS) { |
180 for (String mp : MP_OPTIONS) { |
144 for (String m : MODULE_OPTIONS) { |
181 for (String m : MODULE_OPTIONS) { |
145 for (String[] vma : VM_ARGS) { |
182 for (String[] vma : VM_ARGS) { |
146 for (String[] arg : ARGS) { |
183 for (String[] arg : ARGS) { |
147 List<String> cmd = new LinkedList<>(); |
184 for(String patchModuleOption : PATCH_MODULE_OPTIONS) { |
148 cmd.add(JAVA_PATH); |
185 List<String> cmd = new LinkedList<>(); |
149 cmd.add(mp); |
186 cmd.add(JAVA_PATH); |
150 cmd.add(TEST_MODULES.toAbsolutePath().toString()); |
187 cmd.add(mp); |
151 for (String v : vma) { |
188 cmd.add(TEST_MODULES.toAbsolutePath().toString()); |
152 cmd.add(v); |
189 if (patchModuleOption != null) { |
|
190 cmd.add(patchModuleOption); |
|
191 cmd.add(MODULE_NAME + "=" + TEST_MODULES.toAbsolutePath().toString()); |
|
192 } |
|
193 for (String v : vma) { |
|
194 cmd.add(v); |
|
195 } |
|
196 if (m.endsWith("=")) { |
|
197 cmd.add(m + MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS); |
|
198 } else { |
|
199 cmd.add(m); |
|
200 cmd.add(MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS); |
|
201 } |
|
202 for (String a : arg) { |
|
203 cmd.add(a); |
|
204 } |
|
205 testProcessHelper(cmd, MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS); |
153 } |
206 } |
154 cmd.add(m); |
|
155 cmd.add(MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS); |
|
156 for (String a : arg) { |
|
157 cmd.add(a); |
|
158 } |
|
159 testProcessHelper(cmd, MODULE_NAME + "/" + TEST_PROCESS_MAIN_CLASS); |
|
160 } |
207 } |
161 } |
208 } |
162 } |
209 } |
163 } |
210 } |
164 } |
211 } |
165 |
212 |
166 private void checkMainClass(Process p, String expectedMainClass) { |
213 private void checkMainClass(Process p, String expectedMainClass) { |
167 String mainClass = PROCESS_HELPER.getMainClass(Long.toString(p.pid())); |
214 String mainClass = callGetMainClass(p); |
|
215 // getMainClass() may return null, e.g. due to timing issues. |
|
216 // Attempt some limited retries. |
|
217 if (mainClass == null) { |
|
218 System.err.println("Main class returned by ProcessHelper was null."); |
|
219 // sleep time doubles each round, altogether, wait no longer than 1 sec |
|
220 final int MAX_RETRIES = 10; |
|
221 int retrycount = 0; |
|
222 long sleepms = 1; |
|
223 while (retrycount < MAX_RETRIES && mainClass == null) { |
|
224 System.err.println("Retry " + retrycount + ", sleeping for " + sleepms + "ms."); |
|
225 try { |
|
226 Thread.sleep(sleepms); |
|
227 } catch (InterruptedException e) { |
|
228 // ignore |
|
229 } |
|
230 mainClass = callGetMainClass(p); |
|
231 retrycount++; |
|
232 sleepms *= 2; |
|
233 } |
|
234 } |
168 p.destroyForcibly(); |
235 p.destroyForcibly(); |
169 if (!expectedMainClass.equals(mainClass)) { |
236 if (!expectedMainClass.equals(mainClass)) { |
170 throw new RuntimeException("Main class is wrong: " + mainClass); |
237 throw new RuntimeException("Main class is wrong: " + mainClass); |
171 } |
238 } |
172 } |
239 } |