Path: blob/master/test/jdk/sun/tools/jstatd/JstatdTest.java
41149 views
/*1* Copyright (c) 2013, 2020, 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.net.UnknownHostException;25import java.rmi.RemoteException;26import java.rmi.registry.LocateRegistry;27import java.rmi.registry.Registry;28import java.util.Arrays;29import java.util.List;3031import static jdk.test.lib.Asserts.*;32import jdk.test.lib.Utils;33import jdk.test.lib.JDKToolLauncher;34import jdk.test.lib.process.OutputAnalyzer;35import jdk.test.lib.process.ProcessTools;36import jdk.test.lib.thread.ProcessThread;3738/**39* The base class for tests of jstatd.40*41* The test sequence for TestJstatdDefaults for example is:42* <pre>43* {@code44* // start jstatd process45* jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy46*47* // run jps and verify its output48* jps -J-XX:+UsePerfData hostname49*50* // run jstat and verify its output51* jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname 250 552*53* // stop jstatd process and verify that no unexpected exceptions have been thrown54* }55* </pre>56*/57public final class JstatdTest {5859/**60* jstat gcutil option: takes JSTAT_GCUTIL_SAMPLES samples at61* JSTAT_GCUTIL_INTERVAL_MS millisecond intervals62*/63private static final int JSTAT_GCUTIL_SAMPLES = 5;64private static final int JSTAT_GCUTIL_INTERVAL_MS = 250;65private static final String JPS_OUTPUT_REGEX = "^\\d+\\s*.*";6667private boolean useDefaultPort = true;68private boolean useDefaultRmiPort = true;69private String port;70private String rmiPort;71private String serverName;72private Long jstatdPid;73private boolean withExternalRegistry = false;74private boolean useShortCommandSyntax = false;7576private volatile static boolean portInUse;7778public void setServerName(String serverName) {79this.serverName = serverName;80}8182public void setUseDefaultPort(boolean useDefaultPort) {83this.useDefaultPort = useDefaultPort;84}8586public void setUseDefaultRmiPort(boolean useDefaultRmiPort) {87this.useDefaultRmiPort = useDefaultRmiPort;88}8990public void setWithExternalRegistry(boolean withExternalRegistry) {91this.withExternalRegistry = withExternalRegistry;92}9394private Long waitOnTool(ProcessThread thread) throws Throwable {95long pid = thread.getPid();96if (portInUse) {97System.out.println("Port already in use. Trying to restart with a new one...");98return null;99}100System.out.println(thread.getName() + " pid: " + pid);101return pid;102}103104private void log(String caption, String... cmd) {105System.out.println(Utils.NEW_LINE + caption + ":");106System.out.println(Arrays.toString(cmd).replace(",", ""));107}108109private String getDestination() throws UnknownHostException {110String option = Utils.getHostname();111if (port != null) {112option += ":" + port;113}114if (serverName != null) {115option += "/" + serverName;116}117return option;118}119120/**121* Depending on test settings command line can look like:122*123* jps -J-XX:+UsePerfData hostname124* jps -J-XX:+UsePerfData hostname:port125* jps -J-XX:+UsePerfData hostname/serverName126* jps -J-XX:+UsePerfData hostname:port/serverName127*/128private OutputAnalyzer runJps() throws Exception {129JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps");130launcher.addVMArgs(Utils.getFilteredTestJavaOpts("-XX:+UsePerfData"));131launcher.addVMArg("-XX:+UsePerfData");132launcher.addToolArg(getDestination());133134String[] cmd = launcher.getCommand();135log("Start jps", cmd);136137ProcessBuilder processBuilder = new ProcessBuilder(cmd);138OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);139System.out.println(output.getOutput());140141return output;142}143144/**145* Verifies output form jps contains pids and programs' name information.146* The function will discard any lines that come before the first line with pid.147* This can happen if the JVM outputs a warning message for some reason148* before running jps.149*150* The output can look like:151* 35536 Jstatd152* 35417 Main153* 31103 org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar154*/155private void verifyJpsOutput(OutputAnalyzer output) throws Exception {156output.shouldHaveExitValue(0);157assertFalse(output.getOutput().isEmpty(), "Output should not be empty");158159boolean foundFirstLineWithPid = false;160List<String> lines = output.asLinesWithoutVMWarnings();161for (String line : lines) {162if (!foundFirstLineWithPid) {163foundFirstLineWithPid = line.matches(JPS_OUTPUT_REGEX);164continue;165}166assertTrue(line.matches(JPS_OUTPUT_REGEX),167"Output does not match the pattern" + Utils.NEW_LINE + line);168}169assertTrue(foundFirstLineWithPid, "Invalid output");170}171172/**173* Depending on test settings command line can look like:174*175* jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname 250 5176* jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname:port 250 5177* jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname/serverName 250 5178* jstat -J-XX:+UsePerfData -J-Duser.language=en -gcutil pid@hostname:port/serverName 250 5179*/180private OutputAnalyzer runJstat() throws Exception {181JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstat");182launcher.addVMArg("-XX:+UsePerfData");183launcher.addVMArg("-Duser.language=en");184launcher.addToolArg("-gcutil");185launcher.addToolArg(jstatdPid + "@" + getDestination());186launcher.addToolArg(Integer.toString(JSTAT_GCUTIL_INTERVAL_MS));187launcher.addToolArg(Integer.toString(JSTAT_GCUTIL_SAMPLES));188189String[] cmd = launcher.getCommand();190log("Start jstat", cmd);191192ProcessBuilder processBuilder = new ProcessBuilder(cmd);193OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);194System.out.println(output.getOutput());195196return output;197}198199private void verifyJstatOutput(OutputAnalyzer output)200throws Exception {201output.shouldHaveExitValue(0);202assertFalse(output.getOutput().isEmpty(), "Output should not be empty");203204JstatGCUtilParser gcUtilParser = new JstatGCUtilParser(205output.getOutput());206gcUtilParser.parse(JSTAT_GCUTIL_SAMPLES);207}208209private void runToolsAndVerify() throws Exception {210OutputAnalyzer output = runJps();211verifyJpsOutput(output);212213output = runJstat();214verifyJstatOutput(output);215}216217private Registry startRegistry()218throws InterruptedException, RemoteException {219Registry registry = null;220try {221System.out.println("Start rmiregistry on port " + port);222registry = LocateRegistry223.createRegistry(Integer.parseInt(port));224} catch (RemoteException e) {225if (e.getMessage().contains("Port already in use")) {226System.out.println("Port already in use. Trying to restart with a new one...");227Thread.sleep(100);228return null;229} else {230throw e;231}232}233return registry;234}235236private void cleanUpThread(ProcessThread thread) throws Throwable {237if (thread != null) {238thread.stopProcess();239thread.joinAndThrow();240}241}242243/**244* Depending on test settings command line can look like:245*246* jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy247* jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port248* jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -r rmiport249* jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -n serverName250* jstatd -J-XX:+UsePerfData -J-Djava.security.policy=all.policy -p port -n serverName251*/252private String[] getJstatdCmd() throws Exception {253JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstatd");254launcher.addVMArg("-XX:+UsePerfData");255launcher.addVMArg("-Djava.security.manager=allow");256String testSrc = System.getProperty("test.src");257File policy = new File(testSrc, "all.policy");258assertTrue(policy.exists() && policy.isFile(),259"Security policy " + policy.getAbsolutePath() + " does not exist or not a file");260launcher.addVMArg("-Djava.security.policy=" + policy.getAbsolutePath());261if (port != null) {262addToolArg(launcher,"-p", port);263}264if (rmiPort != null) {265addToolArg(launcher,"-r", rmiPort);266}267if (serverName != null) {268addToolArg(launcher,"-n", serverName);269}270if (withExternalRegistry) {271launcher.addToolArg("-nr");272}273String[] cmd = launcher.getCommand();274log("Start jstatd", cmd);275return cmd;276}277278private void addToolArg(JDKToolLauncher launcher, String name, String value) {279if (useShortCommandSyntax) {280launcher.addToolArg(name + value);281} else {282launcher.addToolArg(name);283launcher.addToolArg(value);284}285}286287private ProcessThread tryToSetupJstatdProcess() throws Throwable {288portInUse = false;289ProcessThread jstatdThread = new ProcessThread("Jstatd-Thread",290JstatdTest::isJstadReady, getJstatdCmd());291try {292jstatdThread.start();293// Make sure jstatd is up and running294jstatdPid = waitOnTool(jstatdThread);295if (jstatdPid == null) {296// The port is already in use. Cancel and try with new one.297jstatdThread.stopProcess();298jstatdThread.join();299return null;300}301} catch (Throwable t) {302// Something went wrong in the product - clean up!303cleanUpThread(jstatdThread);304throw t;305}306307return jstatdThread;308}309310private static boolean isJstadReady(String line) {311if (line.contains("Port already in use")) {312portInUse = true;313return true;314}315return line.startsWith("jstatd started (bound to ");316}317318public void doTest() throws Throwable {319runTest(false);320runTest(true);321}322323private void runTest(boolean useShortSyntax) throws Throwable {324useShortCommandSyntax = useShortSyntax;325if (useDefaultPort) {326verifyNoRmiRegistryOnDefaultPort();327}328329ProcessThread jstatdThread = null;330try {331while (jstatdThread == null) {332if (!useDefaultPort) {333port = String.valueOf(Utils.getFreePort());334}335336if (!useDefaultRmiPort) {337rmiPort = String.valueOf(Utils.getFreePort());338}339340if (withExternalRegistry) {341Registry registry = startRegistry();342if (registry == null) {343// The port is already in use. Cancel and try with a new one.344continue;345}346}347348jstatdThread = tryToSetupJstatdProcess();349}350351runToolsAndVerify();352} finally {353cleanUpThread(jstatdThread);354}355356// Verify output from jstatd357OutputAnalyzer output = jstatdThread.getOutput();358output.shouldBeEmptyIgnoreVMWarnings();359assertNotEquals(output.getExitValue(), 0,360"jstatd process exited with unexpected exit code");361}362363private void verifyNoRmiRegistryOnDefaultPort() throws Exception {364try {365Registry registry = LocateRegistry.getRegistry();366registry.list();367throw new Exception("There is already RMI registry on the default port: " + registry);368} catch (RemoteException e) {369// No RMI registry on default port is detected370}371}372373}374375376