1/*
2 * Copyright (c) 2015, 2017, 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 jhsdb launcher
27 * @library /test/lib
28 * @library /lib/testlibrary
29 * @build jdk.testlibrary.*
30 * @build jdk.test.lib.apps.*
31 * @run main BasicLauncherTest
32 */
33
34import java.io.BufferedReader;
35import java.io.IOException;
36import java.io.OutputStream;
37import java.io.InputStreamReader;
38import java.util.ArrayList;
39import java.util.List;
40import java.util.Arrays;
41import java.util.Optional;
42import jdk.testlibrary.JDKToolLauncher;
43import jdk.testlibrary.Utils;
44import jdk.testlibrary.OutputAnalyzer;
45import jdk.testlibrary.ProcessTools;
46import jdk.test.lib.apps.LingeredApp;
47import jdk.test.lib.Platform;
48
49public class BasicLauncherTest {
50
51    private static LingeredApp theApp = null;
52    private static boolean useJavaLauncher = false;
53
54    private static JDKToolLauncher createSALauncher() {
55        JDKToolLauncher launcher = null;
56        if (useJavaLauncher) {
57            // Use java launcher if we need to pass additional parameters to VM
58            // for debugging purpose
59            // e.g. -Xlog:class+load=info:file=/tmp/BasicLauncherTest.log
60            launcher = JDKToolLauncher.createUsingTestJDK("java");
61            launcher.addToolArg("sun.jvm.hotspot.SALauncher");
62        }
63        else {
64            launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
65        }
66
67        return launcher;
68    }
69
70    public static void launchCLHSDB()
71        throws IOException {
72
73        System.out.println("Starting LingeredApp");
74        try {
75            theApp = LingeredApp.startApp();
76
77            System.out.println("Starting clhsdb against " + theApp.getPid());
78            JDKToolLauncher launcher = createSALauncher();
79            launcher.addToolArg("clhsdb");
80            launcher.addToolArg("--pid=" + Long.toString(theApp.getPid()));
81
82            ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
83            processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
84            Process toolProcess = processBuilder.start();
85
86            try (OutputStream out = toolProcess.getOutputStream()) {
87                out.write("universe\n".getBytes());
88                out.write("quit\n".getBytes());
89            }
90
91            // By default child process output stream redirected to pipe, so we are reading it in foreground.
92            Exception unexpected = null;
93            try (BufferedReader reader =
94                 new BufferedReader(new InputStreamReader(toolProcess.getInputStream()))) {
95                String line;
96
97                while ((line = reader.readLine()) != null) {
98                    line = line.trim();
99                    System.out.println(line);
100
101                    if (line.contains("unknown subtype of CollectedHeap")) {
102                        unexpected = new RuntimeException("CollectedHeap type should be known.");
103                        break;
104                    }
105                }
106            }
107
108            toolProcess.waitFor();
109
110            if (toolProcess.exitValue() != 0) {
111                throw new RuntimeException("FAILED CLHSDB terminated with non-zero exit code " + toolProcess.exitValue());
112            }
113
114            if (unexpected != null) {
115                throw unexpected;
116            }
117
118        } catch (Exception ex) {
119            throw new RuntimeException("Test ERROR " + ex, ex);
120        } finally {
121            LingeredApp.stopApp(theApp);
122        }
123    }
124
125    public static void launchJStack() throws IOException {
126
127        if (Platform.isOSX()) {
128            // Coredump stackwalking is not implemented for Darwin
129            System.out.println("This test is not expected to work on OS X. Skipping");
130            return;
131        }
132
133        System.out.println("Starting LingeredApp");
134        try {
135            theApp = LingeredApp.startApp(Arrays.asList("-Xmx256m"));
136
137            System.out.println("Starting jstack against " + theApp.getPid());
138            JDKToolLauncher launcher = createSALauncher();
139
140            launcher.addToolArg("jstack");
141            launcher.addToolArg("--pid=" + Long.toString(theApp.getPid()));
142
143            ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
144            OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);;
145            output.shouldContain("No deadlocks found");
146            output.shouldNotContain("illegal bci");
147            output.shouldNotContain("AssertionFailure");
148            output.shouldHaveExitValue(0);
149
150        } catch (Exception ex) {
151            throw new RuntimeException("Test ERROR " + ex, ex);
152        } finally {
153            LingeredApp.stopApp(theApp);
154        }
155    }
156
157    /**
158     *
159     * @param vmArgs  - vm and java arguments to launch test app
160     * @return exit code of tool
161     */
162    public static void launch(String expectedMessage,
163                 Optional<String> unexpectedMessage, List<String> toolArgs)
164        throws IOException {
165
166        System.out.println("Starting LingeredApp");
167        try {
168            theApp = LingeredApp.startApp(Arrays.asList("-Xmx256m"));
169
170            System.out.println("Starting " + toolArgs.get(0) + " against " + theApp.getPid());
171            JDKToolLauncher launcher = createSALauncher();
172
173            for (String cmd : toolArgs) {
174                launcher.addToolArg(cmd);
175            }
176
177            launcher.addToolArg("--pid=" + Long.toString(theApp.getPid()));
178
179            ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
180            processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
181            OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);;
182            output.shouldContain(expectedMessage);
183            unexpectedMessage.ifPresent(output::shouldNotContain);
184            output.shouldHaveExitValue(0);
185
186        } catch (Exception ex) {
187            throw new RuntimeException("Test ERROR " + ex, ex);
188        } finally {
189            LingeredApp.stopApp(theApp);
190        }
191    }
192
193    public static void launch(String expectedMessage,
194                              String unexpectedMessage, String... toolArgs)
195        throws IOException {
196
197        launch(expectedMessage, Optional.ofNullable(unexpectedMessage),
198                                                       Arrays.asList(toolArgs));
199    }
200
201    public static void main(String[] args) throws Exception {
202
203        if (!Platform.shouldSAAttach()) {
204            // Silently skip the test if we don't have enough permissions to attach
205            System.err.println("Error! Insufficient permissions to attach.");
206            return;
207        }
208
209        launchCLHSDB();
210
211        launch("compiler detected", null, "jmap", "--clstats");
212        launchJStack();
213        launch("compiler detected", null, "jmap");
214        launch("Java System Properties",
215               "System Properties info not available", "jinfo");
216        launch("java.threads", null, "jsnap");
217
218        // The test throws RuntimeException on error.
219        // IOException is thrown if LingeredApp can't start because of some bad
220        // environment condition
221        System.out.println("Test PASSED");
222    }
223}
224