8004926: sun/management/jmxremote/bootstrap/CustomLauncherTest.sh oftenly times out
Summary: Improve reliability by converting the test to Java
Reviewed-by: dsamersoff, dholmes
--- a/jdk/test/TEST.groups Fri Oct 25 11:01:29 2013 +0100
+++ b/jdk/test/TEST.groups Fri Oct 25 13:01:11 2013 +0200
@@ -325,7 +325,8 @@
jdk/lambda/separate/Compiler.java \
sun/management/jdp/JdpTest.sh \
sun/management/jmxremote/bootstrap/JvmstatCountersTest.java \
- sun/management/jmxremote/bootstrap/LocalManagementTest.sh \
+ sun/management/jmxremote/bootstrap/LocalManagementTest.java \
+ sun/management/jmxremote/bootstrap/CustomLauncherTest.java \
sun/misc/JarIndex/metaInfFilenames/Basic.java \
sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java \
sun/reflect/CallerSensitive/CallerSensitiveFinder.java \
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Fri Oct 25 11:01:29 2013 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java Fri Oct 25 13:01:11 2013 +0200
@@ -25,24 +25,127 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Predicate;
import sun.management.VMManagement;
public final class ProcessTools {
+ private static final class LineForwarder extends StreamPumper.LinePump {
+ private final PrintStream ps;
+ private final String prefix;
+ LineForwarder(String prefix, PrintStream os) {
+ this.ps = os;
+ this.prefix = prefix;
+ }
+ @Override
+ protected void processLine(String line) {
+ ps.println("[" + prefix + "] " + line);
+ }
+ }
private ProcessTools() {
}
/**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * @param name The process name
+ * @param processBuilder The process builder
+ * @return Returns the initialized process
+ * @throws IOException
+ */
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder)
+ throws IOException {
+ Process p = null;
+ try {
+ p = startProcess(name, processBuilder, null, -1, TimeUnit.NANOSECONDS);
+ } catch (InterruptedException | TimeoutException e) {
+ // can't ever happen
+ }
+ return p;
+ }
+
+ /**
+ * <p>Starts a process from its builder.</p>
+ * <span>The default redirects of STDOUT and STDERR are started</span>
+ * <p>
+ * It is possible to wait for the process to get to a warmed-up state
+ * via {@linkplain Predicate} condition on the STDOUT
+ * </p>
+ * @param name The process name
+ * @param processBuilder The process builder
+ * @param linePredicate The {@linkplain Predicate} to use on the STDOUT
+ * Used to determine the moment the target app is
+ * properly warmed-up.
+ * It can be null - in that case the warmup is skipped.
+ * @param timeout The timeout for the warmup waiting
+ * @param unit The timeout {@linkplain TimeUnit}
+ * @return Returns the initialized {@linkplain Process}
+ * @throws IOException
+ * @throws InterruptedException
+ * @throws TimeoutException
+ */
+ public static Process startProcess(String name,
+ ProcessBuilder processBuilder,
+ final Predicate<String> linePredicate,
+ long timeout,
+ TimeUnit unit)
+ throws IOException, InterruptedException, TimeoutException {
+ Process p = processBuilder.start();
+ StreamPumper stdout = new StreamPumper(p.getInputStream());
+ StreamPumper stderr = new StreamPumper(p.getErrorStream());
+
+ stdout.addPump(new LineForwarder(name, System.out));
+ stderr.addPump(new LineForwarder(name, System.err));
+ final Phaser phs = new Phaser(1);
+ if (linePredicate != null) {
+ stdout.addPump(new StreamPumper.LinePump() {
+ @Override
+ protected void processLine(String line) {
+ if (linePredicate.test(line)) {
+ if (phs.getRegisteredParties() > 0) {
+ phs.arriveAndDeregister();
+ }
+ }
+ }
+ });
+ }
+ Future<Void> stdoutTask = stdout.process();
+ Future<Void> stderrTask = stderr.process();
+
+ try {
+ if (timeout > -1) {
+ phs.awaitAdvanceInterruptibly(0, timeout, unit);
+ }
+ } catch (TimeoutException | InterruptedException e) {
+ stdoutTask.cancel(true);
+ stderrTask.cancel(true);
+ throw e;
+ }
+
+ return p;
+ }
+
+ /**
* Pumps stdout and stderr from running the process into a String.
*
- * @param processHandler
+ * @param processBuilder
* ProcessHandler to run.
* @return Output from process.
* @throws IOException
@@ -69,22 +172,19 @@
stdoutBuffer);
StreamPumper errPumper = new StreamPumper(process.getErrorStream(),
stderrBuffer);
- Thread outPumperThread = new Thread(outPumper);
- Thread errPumperThread = new Thread(errPumper);
- outPumperThread.setDaemon(true);
- errPumperThread.setDaemon(true);
-
- outPumperThread.start();
- errPumperThread.start();
+ Future<Void> outTask = outPumper.process();
+ Future<Void> errTask = errPumper.process();
try {
process.waitFor();
- outPumperThread.join();
- errPumperThread.join();
+ outTask.get();
+ errTask.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
+ } catch (ExecutionException e) {
+ throw new IOException(e);
}
return new OutputBuffer(stdoutBuffer.toString(),
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java Fri Oct 25 11:01:29 2013 +0100
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java Fri Oct 25 13:01:11 2013 +0200
@@ -23,16 +23,65 @@
package jdk.testlibrary;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicBoolean;
public final class StreamPumper implements Runnable {
private static final int BUF_SIZE = 256;
- private final OutputStream out;
+ /**
+ * Pump will be called by the StreamPumper to process the incoming data
+ */
+ abstract public static class Pump {
+ abstract void register(StreamPumper d);
+ }
+
+ /**
+ * OutputStream -> Pump adapter
+ */
+ final public static class StreamPump extends Pump {
+ private final OutputStream out;
+ public StreamPump(OutputStream out) {
+ this.out = out;
+ }
+
+ @Override
+ void register(StreamPumper sp) {
+ sp.addOutputStream(out);
+ }
+ }
+
+ /**
+ * Used to process the incoming data line-by-line
+ */
+ abstract public static class LinePump extends Pump {
+ @Override
+ final void register(StreamPumper sp) {
+ sp.addLineProcessor(this);
+ }
+
+ abstract protected void processLine(String line);
+ }
+
private final InputStream in;
+ private final Set<OutputStream> outStreams = new HashSet<>();
+ private final Set<LinePump> linePumps = new HashSet<>();
+
+ private final AtomicBoolean processing = new AtomicBoolean(false);
+ private final FutureTask<Void> processingTask = new FutureTask(this, null);
+
+ public StreamPumper(InputStream in) {
+ this.in = in;
+ }
/**
* Create a StreamPumper that reads from in and writes to out.
@@ -43,8 +92,8 @@
* The stream to write to.
*/
public StreamPumper(InputStream in, OutputStream out) {
- this.in = in;
- this.out = out;
+ this(in);
+ this.addOutputStream(out);
}
/**
@@ -54,25 +103,97 @@
*/
@Override
public void run() {
- int length;
- InputStream localIn = in;
- OutputStream localOut = out;
- byte[] buffer = new byte[BUF_SIZE];
+ try (BufferedInputStream is = new BufferedInputStream(in)) {
+ ByteArrayOutputStream lineBos = new ByteArrayOutputStream();
+ byte[] buf = new byte[BUF_SIZE];
+ int len = 0;
+ int linelen = 0;
+
+ while ((len = is.read(buf)) > 0 && !Thread.interrupted()) {
+ for(OutputStream out : outStreams) {
+ out.write(buf, 0, len);
+ }
+ if (!linePumps.isEmpty()) {
+ int i = 0;
+ int lastcrlf = -1;
+ while (i < len) {
+ if (buf[i] == '\n' || buf[i] == '\r') {
+ int bufLinelen = i - lastcrlf - 1;
+ if (bufLinelen > 0) {
+ lineBos.write(buf, lastcrlf + 1, bufLinelen);
+ }
+ linelen += bufLinelen;
- try {
- while ((length = localIn.read(buffer)) > 0 && !Thread.interrupted()) {
- localOut.write(buffer, 0, length);
+ if (linelen > 0) {
+ lineBos.flush();
+ final String line = lineBos.toString();
+ linePumps.stream().forEach((lp) -> {
+ lp.processLine(line);
+ });
+ lineBos.reset();
+ linelen = 0;
+ }
+ lastcrlf = i;
+ }
+
+ i++;
+ }
+ if (lastcrlf == -1) {
+ lineBos.write(buf, 0, len);
+ linelen += len;
+ } else if (lastcrlf < len - 1) {
+ lineBos.write(buf, lastcrlf + 1, len - lastcrlf - 1);
+ linelen += len - lastcrlf - 1;
+ }
+ }
}
+
} catch (IOException e) {
- // Just abort if something like this happens.
e.printStackTrace();
} finally {
+ for(OutputStream out : outStreams) {
+ try {
+ out.flush();
+ } catch (IOException e) {}
+ }
try {
- localOut.flush();
in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ } catch (IOException e) {}
}
}
+
+ final void addOutputStream(OutputStream out) {
+ outStreams.add(out);
+ }
+
+ final void addLineProcessor(LinePump lp) {
+ linePumps.add(lp);
+ }
+
+ final public StreamPumper addPump(Pump ... pump) {
+ if (processing.get()) {
+ throw new IllegalStateException("Can not modify pumper while " +
+ "processing is in progress");
+ }
+ for(Pump p : pump) {
+ p.register(this);
+ }
+ return this;
+ }
+
+ final public Future<Void> process() {
+ if (!processing.compareAndSet(false, true)) {
+ throw new IllegalStateException("Can not re-run the processing");
+ }
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ processingTask.run();
+ }
+ });
+ t.setDaemon(true);
+ t.start();
+
+ return processingTask;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java Fri Oct 25 13:01:11 2013 +0200
@@ -0,0 +1,221 @@
+/*
+ * 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.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import jdk.testlibrary.JdkFinder;
+import jdk.testlibrary.ProcessTools;
+
+/**
+ * @test
+ * @bug 6434402 8004926
+ * @library ../../../../lib/testlibrary
+ * @build TestManager TestApplication CustomLauncherTest
+ * @run main CustomLauncherTest
+ * @author Jaroslav Bachorik
+ */
+public class CustomLauncherTest {
+ private static final String TEST_CLASSES = System.getProperty("test.classes");
+ private static final String TEST_JDK = System.getProperty("test.jdk");
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+ private static final String OSNAME = System.getProperty("os.name");
+ private static final String ARCH;
+ private static final String LIBARCH;
+
+ static {
+ // magic with os.arch
+ String osarch = System.getProperty("os.arch");
+ switch (osarch) {
+ case "i386":
+ case "i486":
+ case "i586":
+ case "i686":
+ case "i786":
+ case "i886":
+ case "i986": {
+ ARCH = "i586";
+ break;
+ }
+ case "x86_64":
+ case "amd64": {
+ ARCH = "amd64";
+ break;
+ }
+ default: {
+ ARCH = osarch;
+ }
+ }
+ LIBARCH = ARCH.equals("i586") ? "i386" : ARCH;
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (TEST_CLASSES == null || TEST_CLASSES.isEmpty()) {
+ System.out.println("Test is designed to be run from jtreg only");
+ return;
+ }
+
+ String PLATFORM = "";
+ switch (OSNAME.toLowerCase()) {
+ case "linux": {
+ PLATFORM = "linux";
+ break;
+ }
+ case "sunos": {
+ PLATFORM = "solaris";
+ break;
+ }
+ default: {
+ System.out.println("Test not designed to run on this operating " +
+ "system (" + OSNAME + "), skipping...");
+ return;
+ }
+ }
+
+ String LAUNCHER = TEST_SRC + File.separator + PLATFORM + "-" + ARCH +
+ File.separator + "launcher";
+
+ final FileSystem FS = FileSystems.getDefault();
+ final boolean hasLauncher = Files.isExecutable(FS.getPath(LAUNCHER));
+ if (!hasLauncher) {
+ System.out.println("Launcher [" + LAUNCHER + "] does not exist. Skipping the test.");
+ return;
+ }
+
+ Path libjvmPath = findLibjvm(FS);
+ if (libjvmPath == null) {
+ throw new Error("Unable to locate 'libjvm.so' in " + TEST_JDK);
+ }
+
+ Process serverPrc = null, clientPrc = null;
+
+ try {
+ System.out.println("Starting custom launcher:");
+ System.out.println("=========================");
+ System.out.println(" launcher : " + LAUNCHER);
+ System.out.println(" libjvm : " + libjvmPath.toString());
+ System.out.println(" classpath : " + TEST_CLASSES);
+ ProcessBuilder server = new ProcessBuilder(LAUNCHER, libjvmPath.toString(), TEST_CLASSES, "TestApplication");
+
+ final AtomicReference<String> port = new AtomicReference<>();
+ final AtomicReference<String> pid = new AtomicReference<>();
+
+ serverPrc = ProcessTools.startProcess(
+ "Launcher",
+ server,
+ (String line) -> {
+ if (line.startsWith("port:")) {
+ port.set(line.split("\\:")[1]);
+ } else if (line.startsWith("pid:")) {
+ pid.set(line.split("\\:")[1]);
+ } else if (line.startsWith("waiting")) {
+ return true;
+ }
+ return false;
+ },
+ 5,
+ TimeUnit.SECONDS
+ );
+
+ System.out.println("Attaching test manager:");
+ System.out.println("=========================");
+ System.out.println(" PID : " + pid.get());
+ System.out.println(" shutdown port : " + port.get());
+
+ ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
+ "-cp",
+ TEST_CLASSES +
+ File.pathSeparator +
+ TEST_JDK +
+ File.separator +
+ "lib" +
+ File.separator +
+ "tools.jar",
+ "TestManager",
+ pid.get(),
+ port.get(),
+ "true"
+ );
+
+ clientPrc = ProcessTools.startProcess(
+ "TestManager",
+ client,
+ (String line) -> line.startsWith("Starting TestManager for PID"),
+ 10,
+ TimeUnit.SECONDS
+ );
+
+ int clientExitCode = clientPrc.waitFor();
+ int serverExitCode = serverPrc.waitFor();
+
+ if (clientExitCode != 0 || serverExitCode != 0) {
+ throw new Error("Test failed");
+ }
+ } finally {
+ if (clientPrc != null) {
+ clientPrc.destroy();
+ clientPrc.waitFor();
+ }
+ if (serverPrc != null) {
+ serverPrc.destroy();
+ serverPrc.waitFor();
+ }
+ }
+ }
+
+ private static Path findLibjvm(FileSystem FS) {
+ Path libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "jre", "lib", LIBARCH));
+ if (libjvmPath == null) {
+ libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "lib", LIBARCH));
+ }
+ return libjvmPath;
+ }
+
+ private static Path findLibjvm(Path libPath) {
+ // ARCH/libjvm.so -> ARCH/server/libjvm.so -> ARCH/client/libjvm.so
+ Path libjvmPath = libPath.resolve("libjvm.so");
+ if (isFileOk(libjvmPath)) {
+ return libjvmPath;
+ }
+ libjvmPath = libPath.resolve("server/libjvm.so");
+ if (isFileOk(libjvmPath)) {
+ return libjvmPath;
+ }
+ libjvmPath = libPath.resolve("client/libjvm.so");
+ if (isFileOk(libPath)) {
+ return libjvmPath;
+ }
+
+ return null;
+ }
+
+ private static boolean isFileOk(Path path) {
+ return Files.isRegularFile(path) && Files.isReadable(path);
+ }
+}
--- a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.sh Fri Oct 25 11:01:29 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2006, 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.
-#
-
-
-# @test
-# @bug 6434402
-# @summary Start an application using a custom launcher and check that
-# a management tool can connect.
-#
-# @build TestManager TestApplication
-# @run shell CustomLauncherTest.sh
-
-#
-# Check we are run from jtreg
-#
-if [ -z "${TESTCLASSES}" ]; then
- echo "Test is designed to be run from jtreg only"
- exit 0
-fi
-
-#
-# For now this test passes silently on Windows - this means the test only
-# has to locate libjvm.so. Also $! is not reliable on some releases of MKS.
-#{
-OS=`uname -s`
-if [ "$OS" != "Linux" -a "$OS" != "SunOS" ]; then
- echo "Test not designed to run on this operating system, skipping..."
- exit 0
-fi
-
-#
-# Locate the custom launcher for this platform
-#
-PLATFORM=unknown
-ARCH=unknown
-if [ "$OS" = "SunOS" ]; then
- PLATFORM=solaris
- case "`uname -p`" in
- i[3-9]86)
- ARCH=i586
- ;;
- sparc)
- ARCH=sparc
- ;;
- esac
-else
- PLATFORM=linux
- case "`uname -m`" in
- i[3-6]86)
- ARCH=i586
- ;;
- x86_64)
- ARCH=amd64
- ;;
- esac
-fi
-
-
-#
-# On x86 the native libraries are in lib/i386 for
-# compatability reasons
-#
-if [ "$ARCH" = "i586" ]; then
- LIBARCH="i386"
-else
- LIBARCH=$ARCH
-fi
-
-
-#
-# Check that a custom launcher exists for this platform
-#
-LAUNCHER="${TESTSRC}/${PLATFORM}-${ARCH}/launcher"
-if [ ! -x "${LAUNCHER}" ]; then
- echo "${LAUNCHER} not found"
- exit 0
-fi
-
-#
-# Locate the libjvm.so library
-#
-JVMLIB="${TESTJAVA}/jre/lib/${LIBARCH}/client/libjvm.so"
-if [ ! -f "${JVMLIB}" ]; then
- JVMLIB="${TESTJAVA}/jre/lib/${LIBARCH}/server/libjvm.so"
- if [ ! -f "${JVMLIB}" ]; then
- JVMLIB="${TESTJAVA}/lib/${LIBARCH}/client/libjvm.so"
- if [ ! -f "${JVMLIB}" ]; then
- JVMLIB="${TESTJAVA}/lib/${LIBARCH}/serevr/libjvm.so"
- if [ ! -f "${JVMLIB}" ]; then
- echo "Unable to locate libjvm.so in ${TESTJAVA}"
- exit 1
- fi
- fi
- fi
-fi
-
-#
-# Start the VM
-#
-outputfile=${TESTCLASSES}/Test.out
-rm -f ${outputfile}
-
-echo ''
-echo "Starting custom launcher..."
-echo " launcher: ${LAUNCHER}"
-echo " libjvm: ${JVMLIB}"
-echo "classpath: ${TESTCLASSES}"
-
-
-${LAUNCHER} ${JVMLIB} ${TESTCLASSES} TestApplication > ${outputfile} &
-pid=$!
-
-# Wait for managed VM to startup (although this looks like a potentially
-# infinate loop, the framework will eventually kill it)
-echo "Waiting for TestAppication to test..."
-attempts=0
-while true; do
- sleep 1
- port=`tail -1 ${outputfile}`
- if [ ! -z "$port" ]; then
- # In case of errors wait time for output to be flushed
- sleep 1
- cat ${outputfile}
- break
- fi
- attempts=`expr $attempts + 1`
- echo "Waiting $attempts second(s) ..."
-done
-
-# Start the manager - this should connect to VM
-${TESTJAVA}/bin/java ${TESTVMOPTS} -classpath ${TESTCLASSES}:${TESTJAVA}/lib/tools.jar \
- TestManager $pid $port true
-if [ $? != 0 ]; then
- echo "Test failed"
- exit 1
-fi
-exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java Fri Oct 25 13:01:11 2013 +0200
@@ -0,0 +1,237 @@
+/*
+ * 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.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @test
+ * @library ../../../../lib/testlibrary
+ * @bug 5016507 6173612 6319776 6342019 6484550 8004926
+ * @summary Start a managed VM and test that a management tool can connect
+ * without connection or username/password details.
+ * TestManager will attempt a connection to the address obtained from
+ * both agent properties and jvmstat buffer.
+ * @build TestManager TestApplication
+ * @run main/timeout=300 LocalManagementTest
+ */
+
+import jdk.testlibrary.ProcessTools;
+
+public class LocalManagementTest {
+ private static final String TEST_CLASSES = System.getProperty("test.classes");
+ private static final String TEST_JDK = System.getProperty("test.jdk");
+
+ public static void main(String[] args) throws Exception {
+ int failures = 0;
+ for(Method m : LocalManagementTest.class.getDeclaredMethods()) {
+ if (Modifier.isStatic(m.getModifiers()) &&
+ m.getName().startsWith("test")) {
+ m.setAccessible(true);
+ try {
+ System.out.println(m.getName());
+ System.out.println("==========");
+ Boolean rslt = (Boolean)m.invoke(null);
+ if (!rslt) {
+ System.err.println(m.getName() + " failed");
+ failures++;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ failures++;
+ }
+ }
+ }
+ if (failures > 0) {
+ throw new Error("Test failed");
+ }
+ }
+
+ private static boolean test1() throws Exception {
+ return doTest("-Dcom.sun.management.jmxremote");
+ }
+
+ private static boolean test2() throws Exception {
+ Path agentPath = findAgent();
+ if (agentPath != null) {
+ String agent = agentPath.toString();
+ return doTest("-javaagent:" + agent);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * no args (blank) - manager should attach and start agent
+ */
+ private static boolean test3() throws Exception {
+ return doTest(null);
+ }
+
+ /**
+ * sanity check arguments to management-agent.jar
+ */
+ private static boolean test4() throws Exception {
+ Path agentPath = findAgent();
+ if (agentPath != null) {
+ ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(
+ "-javaagent:" + agentPath.toString() +
+ "=com.sun.management.jmxremote.port=7775," +
+ "com.sun.management.jmxremote.authenticate=false," +
+ "com.sun.management.jmxremote.ssl=false",
+ "TestApplication",
+ "-exit"
+ );
+
+ Process prc = null;
+ try {
+ prc = ProcessTools.startProcess(
+ "TestApplication",
+ builder
+ );
+ int exitCode = prc.waitFor();
+ return exitCode == 0;
+ } finally {
+ if (prc != null) {
+ prc.destroy();
+ prc.waitFor();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * use DNS-only name service
+ */
+ private static boolean test5() throws Exception {
+ return doTest("-Dsun.net.spi.namservice.provider.1=\"dns,sun\"");
+ }
+
+ private static Path findAgent() {
+ FileSystem FS = FileSystems.getDefault();
+ Path agentPath = FS.getPath(
+ TEST_JDK, "jre", "lib", "management-agent.jar"
+ );
+ if (!isFileOk(agentPath)) {
+ agentPath = FS.getPath(
+ TEST_JDK, "lib", "management-agent.jar"
+ );
+ }
+ if (!isFileOk(agentPath)) {
+ System.err.println("Can not locate management-agent.jar");
+ return null;
+ }
+ return agentPath;
+ }
+
+ private static boolean isFileOk(Path path) {
+ return Files.isRegularFile(path) && Files.isReadable(path);
+ }
+
+ private static boolean doTest(String arg) throws Exception {
+ List<String> args = new ArrayList<>();
+ if (arg != null) {
+ args.add(arg);
+ }
+ args.add("TestApplication");
+ ProcessBuilder server = ProcessTools.createJavaProcessBuilder(
+ args.toArray(new String[args.size()])
+ );
+
+ Process serverPrc = null, clientPrc = null;
+ try {
+ final AtomicReference<String> port = new AtomicReference<>();
+ final AtomicReference<String> pid = new AtomicReference<>();
+
+ serverPrc = ProcessTools.startProcess(
+ "TestApplication",
+ server,
+ (String line) -> {
+ if (line.startsWith("port:")) {
+ port.set(line.split("\\:")[1]);
+ } else if (line.startsWith("pid:")) {
+ pid.set(line.split("\\:")[1]);
+ } else if (line.startsWith("waiting")) {
+ return true;
+ }
+ return false;
+ },
+ 5,
+ TimeUnit.SECONDS
+ );
+
+ System.out.println("Attaching test manager:");
+ System.out.println("=========================");
+ System.out.println(" PID : " + pid.get());
+ System.out.println(" shutdown port : " + port.get());
+
+ ProcessBuilder client = ProcessTools.createJavaProcessBuilder(
+ "-cp",
+ TEST_CLASSES +
+ File.pathSeparator +
+ TEST_JDK +
+ File.separator +
+ "lib" +
+ File.separator +
+ "tools.jar",
+ "TestManager",
+ pid.get(),
+ port.get(),
+ "true"
+ );
+
+ clientPrc = ProcessTools.startProcess(
+ "TestManager",
+ client,
+ (String line) -> line.startsWith("Starting TestManager for PID"),
+ 10,
+ TimeUnit.SECONDS
+ );
+
+ int clientExitCode = clientPrc.waitFor();
+ int serverExitCode = serverPrc.waitFor();
+ return clientExitCode == 0 && serverExitCode == 0;
+ } finally {
+ if (clientPrc != null) {
+ System.out.println("Stopping process " + clientPrc);
+ clientPrc.destroy();
+ clientPrc.waitFor();
+ }
+ if (serverPrc != null) {
+ System.out.println("Stopping process " + serverPrc);
+ serverPrc.destroy();
+ serverPrc.waitFor();
+ }
+ }
+ }
+}
\ No newline at end of file
--- a/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.sh Fri Oct 25 11:01:29 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2004, 2006, 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.
-#
-
-
-# @test
-# @bug 5016507 6173612 6319776 6342019 6484550
-# @summary Start a managed VM and test that a management tool can connect
-# without connection or username/password details.
-# TestManager will attempt a connection to the address obtained from
-# both agent properties and jvmstat buffer.
-#
-# @build TestManager TestApplication
-# @run shell/timeout=300 LocalManagementTest.sh
-
-
-doTest()
-{
- echo ''
-
- outputfile=${TESTCLASSES}/Test.out
- rm -f ${outputfile}
-
- # Start VM with given options
- echo "+ $JAVA ${TESTVMOPTS} $1 Test"
- $JAVA ${TESTVMOPTS} $1 TestApplication > ${outputfile}&
- pid=$!
-
- # Wait for managed VM to startup
- echo "Waiting for VM to startup..."
- attempts=0
- while true; do
- sleep 1
- port=`tail -1 ${outputfile}`
- if [ ! -z "$port" ]; then
- # In case of errors wait time for output to be flushed
- sleep 1
- cat ${outputfile}
- break
- fi
- attempts=`expr $attempts + 1`
- echo "Waiting $attempts second(s) ..."
- done
-
- # Start the manager - this should connect to VM
- sh -xc "$JAVA ${TESTVMOPTS} -classpath ${TESTCLASSES}:${TESTJAVA}/lib/tools.jar \
- TestManager $pid $port" 2>&1
- if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
-}
-
-
-# Check we are run from jtreg
-if [ -z "${TESTCLASSES}" ]; then
- echo "Test is designed to be run from jtreg only"
- exit 0
-fi
-
-# For now this test passes silently on Windows - there are 2 reasons
-# to skip it :-
-#
-# 1. No jstat instrumentation buffers if FAT32 so need
-# -XX:+PerfBypassFileSystemCheck
-# 2. $! is used to get the pid of the created process but it's not
-# reliable on older versions of MKS. Also negative pids are returned
-# on Windows 98.
-
-os=`uname -s`
-if [ "$os" != "Linux" -a "$os" != "SunOS" ]; then
- echo "Test not designed to run on this operating system, skipping..."
- exit 0
-fi
-
-JAVA=${TESTJAVA}/bin/java
-CLASSPATH=${TESTCLASSES}
-export CLASSPATH
-
-failures=0
-
-# Test 1
-doTest "-Dcom.sun.management.jmxremote"
-
-# Test 2
-AGENT="${TESTJAVA}/jre/lib/management-agent.jar"
-if [ ! -f ${AGENT} ]; then
- AGENT="${TESTJAVA}/lib/management-agent.jar"
-fi
-doTest "-javaagent:${AGENT}"
-
-# Test 3 - no args (blank) - manager should attach and start agent
-doTest " "
-
-# Test 4 - sanity check arguments to management-agent.jar
-echo ' '
-sh -xc "${JAVA} ${TESTVMOPTS} -javaagent:${AGENT}=com.sun.management.jmxremote.port=7775,\
-com.sun.management.jmxremote.authenticate=false,com.sun.management.jmxremote.ssl=false \
- TestApplication -exit" 2>&1
-if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
-
-# Test 5 - use DNS-only name service
-doTest "-Dsun.net.spi.namservice.provider.1=\"dns,sun\""
-
-#
-# Results
-#
-echo ''
-if [ $failures -gt 0 ];
- then echo "$failures test(s) failed";
- else echo "All test(s) passed"; fi
-exit $failures
-
--- a/jdk/test/sun/management/jmxremote/bootstrap/TestApplication.java Fri Oct 25 11:01:29 2013 +0100
+++ b/jdk/test/sun/management/jmxremote/bootstrap/TestApplication.java Fri Oct 25 13:01:11 2013 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -24,14 +24,18 @@
/*
*
*
- * A test "application" used by unit test LocalManagementTest.sh. This
- * application binds to some random port, prints the port number to
- * standard output, waits for somebody to connect, and then shuts down.
+ * A test "application" used by unit tests -
+ * LocalManagementTest.java, CustomLauncherTest.java.
+ * This application binds to some random port, prints its pid and
+ * the port number to standard output, waits for somebody to connect,
+ * and then shuts down.
*/
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
+import jdk.testlibrary.ProcessTools;
+
public class TestApplication {
public static void main(String[] args) throws IOException {
// Some tests require the application to exit immediately
@@ -43,8 +47,17 @@
ServerSocket ss = new ServerSocket(0);
int port = ss.getLocalPort();
- // signal test that we are started - do not remove this line!!
- System.out.println(port);
+ int pid = -1;
+ try {
+ pid = ProcessTools.getProcessId();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // signal test that we are started - do not remove these lines!!
+ System.out.println("port:" + port);
+ System.out.println("pid:" + pid);
+ System.out.println("waiting for the manager ...");
System.out.flush();
// wait for manager to connect
--- a/jdk/test/sun/management/jmxremote/bootstrap/TestManager.java Fri Oct 25 11:01:29 2013 +0100
+++ b/jdk/test/sun/management/jmxremote/bootstrap/TestManager.java Fri Oct 25 13:01:11 2013 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -24,7 +24,8 @@
/*
*
*
- * A test "management tool" used by unit test LocalManagementTest.sh.
+ * A test "management tool" used by unit tests -
+ * LocalManagementTest.java, CustomLauncherTest.java
*
* Usage: java TestManager <pid> <port>
*
@@ -32,8 +33,6 @@
* TCP port is used to shutdown the application.
*/
import javax.management.MBeanServerConnection;
-import javax.management.MBeanServerInvocationHandler;
-import javax.management.ObjectName;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnector;
@@ -43,7 +42,6 @@
import java.net.InetSocketAddress;
import java.io.File;
import java.io.IOException;
-import java.util.Properties;
// Sun specific
import com.sun.tools.attach.VirtualMachine;
@@ -111,6 +109,8 @@
"com.sun.management.jmxremote.localConnectorAddress";
public static void main(String[] args) throws Exception {
String pid = args[0]; // pid as a string
+ System.out.println("Starting TestManager for PID = " + pid);
+ System.out.flush();
VirtualMachine vm = VirtualMachine.attach(pid);
String agentPropLocalConnectorAddress = (String)
@@ -140,7 +140,6 @@
System.out.println("Testing the connector address from jvmstat buffer");
connect(pid, jvmstatLocalConnectorAddress);
-
// Shutdown application
int port = Integer.parseInt(args[1]);
System.out.println("Shutdown process via TCP port: " + port);
Binary file jdk/test/sun/management/jmxremote/bootstrap/linux-amd64/launcher has changed