--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/tools/jstatd/JstatdTest.java Wed Oct 30 13:44:40 2013 +0100
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Arrays;
+
+import static jdk.testlibrary.Asserts.*;
+import jdk.testlibrary.JDKToolLauncher;
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessThread;
+import jdk.testlibrary.TestThread;
+import jdk.testlibrary.Utils;
+
+/**
+ * The base class for tests of jstatd.
+ *
+ * The test sequence for TestJstatdDefaults for example is:
+ * <pre>
+ * {@code
+ * // start jstatd process
+ * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy
+ *
+ * // run jps and verify its output
+ * jps -J-XX:+UsePerfData hostname
+ *
+ * // run jstat and verify its output
+ * jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname 250 5
+ *
+ * // stop jstatd process and verify that no unexpected exceptions have been thrown
+ * }
+ * </pre>
+ */
+public final class JstatdTest {
+
+ /**
+ * jstat gcutil option: takes JSTAT_GCUTIL_SAMPLES samples at
+ * JSTAT_GCUTIL_INTERVAL_MS millisecond intervals
+ */
+ private static final int JSTAT_GCUTIL_SAMPLES = 5;
+ private static final int JSTAT_GCUTIL_INTERVAL_MS = 250;
+ private static final String JPS_OUTPUT_REGEX = "^\\d+\\s*.*";
+
+ private boolean useDefaultPort = true;
+ private String port;
+ private String serverName;
+ private String jstatdPid;
+ private boolean withExternalRegistry = false;
+
+ public void setServerName(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public void setUseDefaultPort(boolean useDefaultPort) {
+ this.useDefaultPort = useDefaultPort;
+ }
+
+ public void setWithExternalRegistry(boolean withExternalRegistry) {
+ this.withExternalRegistry = withExternalRegistry;
+ }
+
+ /**
+ * Parse pid from jps output
+ */
+ private String parsePid(String tool, OutputAnalyzer output) throws Exception {
+ String[] lines = output.getOutput().split(Utils.NEW_LINE);
+ String pid = null;
+ int count = 0;
+ String processName = tool;
+ if (tool == "rmiregistry") {
+ processName = "registryimpl";
+ }
+ for (String line : lines) {
+ if (line.toLowerCase().matches("^\\d+\\s{1}" + processName + "$")) {
+ pid = line.split(" ")[0];
+ count++;
+ }
+ }
+ if (count > 1) {
+ throw new Exception("Expected one " + tool
+ + " process, got " + count + ". Test will be canceled.");
+ }
+
+ return pid;
+ }
+
+ private String getToolPid(String tool)
+ throws Exception {
+ OutputAnalyzer output = runJps();
+ return parsePid(tool, output);
+ }
+
+ private String waitOnTool(String tool, TestThread thread) throws Throwable {
+ while (true) {
+ String pid = getToolPid(tool);
+
+ if (pid != null) {
+ System.out.println(tool + " pid: " + pid);
+ return pid;
+ }
+
+ Throwable t = thread.getUncaught();
+ if (t != null) {
+ if (t.getMessage().contains(
+ "java.rmi.server.ExportException: Port already in use")) {
+ System.out.println("Port already in use. Trying to restart with a new one...");
+ Thread.sleep(100);
+ return null;
+ } else {
+ // Something unexpected has happened
+ throw new Throwable(t);
+ }
+ }
+
+ System.out.println("Waiting until " + tool + " is running...");
+ Thread.sleep(100);
+ }
+ }
+
+ private void log(String caption, String... cmd) {
+ System.out.println(Utils.NEW_LINE + caption + ":");
+ System.out.println(Arrays.toString(cmd).replace(",", ""));
+ }
+
+ private String getDestination() throws UnknownHostException {
+ String option = Utils.getHostname();
+ if (port != null) {
+ option += ":" + port;
+ }
+ if (serverName != null) {
+ option += "/" + serverName;
+ }
+ return option;
+ }
+
+ /**
+ * Depending on test settings command line can look like:
+ *
+ * jps -J-XX:+UsePerfData hostname
+ * jps -J-XX:+UsePerfData hostname:port
+ * jps -J-XX:+UsePerfData hostname/serverName
+ * jps -J-XX:+UsePerfData hostname:port/serverName
+ */
+ private OutputAnalyzer runJps() throws Exception {
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps");
+ launcher.addVMArg("-XX:+UsePerfData");
+ launcher.addToolArg(getDestination());
+
+ String[] cmd = launcher.getCommand();
+ log("Start jps", cmd);
+
+ ProcessBuilder processBuilder = new ProcessBuilder(cmd);
+ OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
+ System.out.println(output.getOutput());
+
+ return output;
+ }
+
+ /**
+ * Verifies output form jps contains pids and programs' name information.
+ * The function will discard any lines that come before the first line with pid.
+ * This can happen if the JVM outputs a warning message for some reason
+ * before running jps.
+ *
+ * The output can look like:
+ * 35536 Jstatd
+ * 35417 Main
+ * 31103 org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
+ */
+ private void verifyJpsOutput(OutputAnalyzer output) throws Exception {
+ output.shouldHaveExitValue(0);
+ assertFalse(output.getOutput().isEmpty(), "Output should not be empty");
+
+ boolean foundFirstLineWithPid = false;
+ String[] lines = output.getOutput().split(Utils.NEW_LINE);
+ for (String line : lines) {
+ if (!foundFirstLineWithPid) {
+ foundFirstLineWithPid = line.matches(JPS_OUTPUT_REGEX);
+ continue;
+ }
+ assertTrue(line.matches(JPS_OUTPUT_REGEX),
+ "Output does not match the pattern" + Utils.NEW_LINE + line);
+ }
+ assertTrue(foundFirstLineWithPid, "Invalid output");
+ }
+
+ /**
+ * Depending on test settings command line can look like:
+ *
+ * jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname 250 5
+ * jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname:port 250 5
+ * jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname/serverName 250 5
+ * jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname:port/serverName 250 5
+ */
+ private OutputAnalyzer runJstat() throws Exception {
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstat");
+ launcher.addVMArg("-XX:+UsePerfData");
+ launcher.addVMArg("-Duser.language=en");
+ launcher.addToolArg("-gcutil");
+ launcher.addToolArg(jstatdPid + "@" + getDestination());
+ launcher.addToolArg(Integer.toString(JSTAT_GCUTIL_INTERVAL_MS));
+ launcher.addToolArg(Integer.toString(JSTAT_GCUTIL_SAMPLES));
+
+ String[] cmd = launcher.getCommand();
+ log("Start jstat", cmd);
+
+ ProcessBuilder processBuilder = new ProcessBuilder(cmd);
+ OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
+ System.out.println(output.getOutput());
+
+ return output;
+ }
+
+ private void verifyJstatOutput(OutputAnalyzer output)
+ throws Exception {
+ output.shouldHaveExitValue(0);
+ assertFalse(output.getOutput().isEmpty(), "Output should not be empty");
+
+ JstatGCUtilParser gcUtilParser = new JstatGCUtilParser(
+ output.getOutput());
+ gcUtilParser.parse(JSTAT_GCUTIL_SAMPLES);
+ }
+
+ private void runToolsAndVerify() throws Exception {
+ OutputAnalyzer output = runJps();
+ verifyJpsOutput(output);
+
+ output = runJstat();
+ verifyJstatOutput(output);
+ }
+
+ private Registry startRegistry()
+ throws InterruptedException, RemoteException {
+ Registry registry = null;
+ try {
+ System.out.println("Start rmiregistry on port " + port);
+ registry = LocateRegistry
+ .createRegistry(Integer.parseInt(port));
+ } catch (RemoteException e) {
+ if (e.getMessage().contains("Port already in use")) {
+ System.out.println("Port already in use. Trying to restart with a new one...");
+ Thread.sleep(100);
+ return null;
+ } else {
+ throw e;
+ }
+ }
+ return registry;
+ }
+
+ private void cleanUpThread(ProcessThread thread) throws Throwable {
+ if (thread != null) {
+ thread.stopProcess();
+ thread.joinAndThrow();
+ }
+ }
+
+ /**
+ * Depending on test settings command line can look like:
+ *
+ * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy
+ * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port
+ * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -n serverName
+ * jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -n serverName
+ */
+ private String[] getJstatdCmd() throws UnknownHostException {
+ JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstatd");
+ launcher.addVMArg("-XX:+UsePerfData");
+ String testSrc = System.getProperty("test.src");
+ File policy = new File(testSrc, "all.policy");
+ launcher.addVMArg("-Djava.security.policy=" + policy.getAbsolutePath());
+ if (port != null) {
+ launcher.addToolArg("-p");
+ launcher.addToolArg(port);
+ }
+ if (serverName != null) {
+ launcher.addToolArg("-n");
+ launcher.addToolArg(serverName);
+ }
+
+ String[] cmd = launcher.getCommand();
+ log("Start jstatd", cmd);
+ return cmd;
+ }
+
+ private ProcessThread tryToSetupJstatdProcess() throws Throwable {
+ ProcessThread jstatdThread = new ProcessThread("Jstatd-Thread",
+ getJstatdCmd());
+ try {
+ jstatdThread.start();
+ // Make sure jstatd is up and running
+ jstatdPid = waitOnTool("jstatd", jstatdThread);
+ if (jstatdPid == null) {
+ // The port is already in use. Cancel and try with new one.
+ jstatdThread.stopProcess();
+ jstatdThread.join();
+ return null;
+ }
+ } catch (Throwable t) {
+ // Something went wrong in the product - clean up!
+ cleanUpThread(jstatdThread);
+ throw t;
+ }
+
+ return jstatdThread;
+ }
+
+ public void doTest() throws Throwable {
+ ProcessThread jstatdThread = null;
+ try {
+ while (jstatdThread == null) {
+ if (!useDefaultPort || withExternalRegistry) {
+ port = Integer.toString(Utils.getFreePort());
+ }
+
+ if (withExternalRegistry) {
+ Registry registry = startRegistry();
+ if (registry == null) {
+ // The port is already in use. Cancel and try with new one.
+ continue;
+ }
+ }
+
+ jstatdThread = tryToSetupJstatdProcess();
+ }
+
+ runToolsAndVerify();
+ } finally {
+ cleanUpThread(jstatdThread);
+ }
+ }
+
+}