1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
|
/*
* Copyright (c) 2013, 2015, 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.Utils;
import jdk.testlibrary.ProcessTools;
/**
* 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 Long 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;
}
private Long waitOnTool(ProcessThread thread) throws Throwable {
long pid = thread.getPid();
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(thread.getName() + " pid: " + pid);
return pid;
}
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 = ProcessTools.executeProcess(processBuilder);
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 = ProcessTools.executeProcess(processBuilder);
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 Exception {
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jstatd");
launcher.addVMArg("-XX:+UsePerfData");
String testSrc = System.getProperty("test.src");
File policy = new File(testSrc, "all.policy");
assertTrue(policy.exists() && policy.isFile(),
"Security policy " + policy.getAbsolutePath() + " does not exist or not a file");
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);
}
if (withExternalRegistry) {
launcher.addToolArg("-nr");
}
String[] cmd = launcher.getCommand();
log("Start jstatd", cmd);
return cmd;
}
private ProcessThread tryToSetupJstatdProcess() throws Throwable {
ProcessThread jstatdThread = new ProcessThread("Jstatd-Thread",
JstatdTest::isJstadReady, getJstatdCmd());
try {
jstatdThread.start();
// Make sure jstatd is up and running
jstatdPid = waitOnTool(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;
}
private static boolean isJstadReady(String line) {
return line.startsWith("jstatd started (bound to ");
}
public void doTest() throws Throwable {
if (useDefaultPort) {
verifyNoRmiRegistryOnDefaultPort();
}
ProcessThread jstatdThread = null;
try {
while (jstatdThread == null) {
if (!useDefaultPort) {
port = String.valueOf(Utils.getFreePort());
}
if (withExternalRegistry) {
Registry registry = startRegistry();
if (registry == null) {
// The port is already in use. Cancel and try with a new one.
continue;
}
}
jstatdThread = tryToSetupJstatdProcess();
}
runToolsAndVerify();
} finally {
cleanUpThread(jstatdThread);
}
// Verify output from jstatd
OutputAnalyzer output = jstatdThread.getOutput();
assertTrue(output.getOutput().isEmpty(),
"jstatd should get an empty output, got: "
+ Utils.NEW_LINE + output.getOutput());
assertNotEquals(output.getExitValue(), 0,
"jstatd process exited with unexpected exit code");
}
private void verifyNoRmiRegistryOnDefaultPort() throws Exception {
try {
Registry registry = LocateRegistry.getRegistry();
registry.list();
throw new Exception("There is already RMI registry on the default port: " + registry);
} catch (RemoteException e) {
// No RMI registry on default port is detected
}
}
}
|