# HG changeset patch # User ykantser # Date 1389868669 -3600 # Node ID 5c1a07e4573db01b72b0749402eb0e6f3d405b02 # Parent 6c67737a5ac06b43a3a3daa32ee614283e1d687e 7185591: jcmd-big-script.sh ERROR: could not find app's Java pid. Reviewed-by: egahlin, sla, jbachorik diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Thu Jan 16 10:27:57 2014 +0100 +++ b/jdk/test/ProblemList.txt Thu Jan 16 11:37:49 2014 +0100 @@ -277,3 +277,10 @@ # jdk_util ############################################################################ + +# svc_tools + +# 8031482 +sun/tools/jcmd/TestJcmdSanity.java windows-all + +############################################################################ diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java --- a/jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java Thu Jan 16 10:27:57 2014 +0100 +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java Thu Jan 16 11:37:49 2014 +0100 @@ -26,34 +26,91 @@ import java.util.Arrays; /** - * Super class for tests which need to attach jcmd to the current process. + * Helper class for starting jcmd process. + *
+ * - jcmd will send diagnostic requests to the current java process:
+ *      jcmd pid_to_current_process PerfCounter.print
+ * - jcmd will be run without sending request to any JVM
+ *      jcmd -h
+ * 
*/ -public class JcmdBase { +public final class JcmdBase { private static ProcessBuilder processBuilder = new ProcessBuilder(); + private JcmdBase() { + // Private constructor to prevent class instantiation + } + /** - * Attach jcmd to the current process + * Sends the diagnostic command request to the current process + * + * @see #jcmd(boolean, String[], String[]) + */ + public final static OutputAnalyzer jcmd(String... jcmdArgs) + throws Exception { + return jcmd(true, null, jcmdArgs); + } + + /** + * Sends the diagnostic command request to the current process. + * jcmd will be run with specified {@code vmArgs}. * - * @param toolArgs - * jcmd command line parameters, e.g. VM.flags - * @return jcmd output + * @see #jcmd(boolean, String[], String[]) + */ + public final static OutputAnalyzer jcmd(String[] vmArgs, + String[] jcmdArgs) throws Exception { + return jcmd(true, vmArgs, jcmdArgs); + } + + /** + * Runs jcmd without sending request to any JVM + * + * @see #jcmd(boolean, String[], String[]) + */ + public final static OutputAnalyzer jcmdNoPid(String[] vmArgs, + String[] jcmdArgs) throws Exception { + return jcmd(false, vmArgs, jcmdArgs); + } + + /** + * If {@code requestToCurrentProcess} is {@code true} + * sends a diagnostic command request to the current process. + * If {@code requestToCurrentProcess} is {@code false} + * runs jcmd without sending request to any JVM. + * + * @param requestToCurrentProcess + * Defines if jcmd will send request to the current process + * @param vmArgs + * jcmd will be run with VM arguments specified, + * e.g. -XX:+UsePerfData + * @param jcmdArgs + * jcmd will be run with option or command and its arguments + * specified, e.g. VM.flags + * @return The output from {@link OutputAnalyzer} object * @throws Exception */ - public final static OutputAnalyzer jcmd(String... toolArgs) - throws Exception { + private static final OutputAnalyzer jcmd(boolean requestToCurrentProcess, + String[] vmArgs, String[] jcmdArgs) throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jcmd"); - launcher.addToolArg(Integer.toString(ProcessTools.getProcessId())); - for (String toolArg : toolArgs) { - launcher.addToolArg(toolArg); + if (vmArgs != null) { + for (String vmArg : vmArgs) { + launcher.addVMArg(vmArg); + } + } + if (requestToCurrentProcess) { + launcher.addToolArg(Integer.toString(ProcessTools.getProcessId())); + } + if (jcmdArgs != null) { + for (String toolArg : jcmdArgs) { + launcher.addToolArg(toolArg); + } } processBuilder.command(launcher.getCommand()); System.out.println(Arrays.toString(processBuilder.command().toArray()).replace(",", "")); OutputAnalyzer output = new OutputAnalyzer(processBuilder.start()); System.out.println(output.getOutput()); - output.shouldHaveExitValue(0); - return output; } diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java --- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Thu Jan 16 10:27:57 2014 +0100 +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java Thu Jan 16 11:37:49 2014 +0100 @@ -23,7 +23,11 @@ package jdk.testlibrary; +import static jdk.testlibrary.Asserts.*; + import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -394,4 +398,99 @@ public int getExitValue() { return exitValue; } + + /** + * Get the contents of the output buffer (stdout and stderr) as list of strings. + * Output will be split by system property 'line.separator'. + * + * @return Contents of the output buffer as list of strings + */ + public List asLines() { + List l = new ArrayList<>(); + String[] a = getOutput().split(Utils.NEW_LINE); + for (String string : a) { + l.add(string); + } + return l; + } + + /** + * Check if there is a line matching {@code pattern} and return its index + * + * @param pattern Matching pattern + * @return Index of first matching line + */ + private int indexOf(List lines, String pattern) { + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).matches(pattern)) { + return i; + } + } + return -1; + } + + /** + * @see #shouldMatchByLine(String, String, String) + */ + public int shouldMatchByLine(String pattern) { + return shouldMatchByLine(null, null, pattern); + } + + /** + * @see #shouldMatchByLine(String, String, String) + */ + public int shouldMatchByLineFrom(String from, String pattern) { + return shouldMatchByLine(from, null, pattern); + } + + /** + * @see #shouldMatchByLine(String, String, String) + */ + public int shouldMatchByLineTo(String to, String pattern) { + return shouldMatchByLine(null, to, pattern); + } + + /** + * Verify that the stdout and stderr contents of output buffer match the + * {@code pattern} line by line. The whole output could be matched or + * just a subset of it. + * + * @param from + * The line from where output will be matched. + * Set {@code from} to null for matching from the first line. + * @param to + * The line until where output will be matched. + * Set {@code to} to null for matching until the last line. + * @param pattern + * Matching pattern + * @return Count of lines which match the {@code pattern} + */ + public int shouldMatchByLine(String from, String to, String pattern) { + List lines = asLines(); + + int fromIndex = 0; + if (from != null) { + fromIndex = indexOf(lines, from); + assertGreaterThan(fromIndex, -1, + "The line/pattern '" + from + "' from where the output should match can not be found"); + } + + int toIndex = lines.size(); + if (to != null) { + toIndex = indexOf(lines, to); + assertGreaterThan(toIndex, -1, + "The line/pattern '" + to + "' until where the output should match can not be found"); + } + + List subList = lines.subList(fromIndex, toIndex); + int matchedCount = 0; + for (String line : subList) { + assertTrue(line.matches(pattern), + "The line '" + line + "' does not match pattern '" + pattern + "'"); + matchedCount++; + } + + return matchedCount; + } + } diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java Thu Jan 16 10:27:57 2014 +0100 +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java Thu Jan 16 11:37:49 2014 +0100 @@ -25,6 +25,9 @@ import static jdk.testlibrary.Asserts.assertTrue; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; @@ -56,7 +59,6 @@ */ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); - private Utils() { // Private constructor to prevent class instantiation } @@ -203,7 +205,6 @@ * @throws Exception If multiple matching jvms are found. */ public static int tryFindJvmPid(String key) throws Throwable { - ProcessBuilder pb = null; OutputAnalyzer output = null; try { JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); @@ -229,4 +230,24 @@ throw t; } } + + /** + * Returns file content as a list of strings + * + * @param file File to operate on + * @return List of strings + * @throws IOException + */ + public static List fileAsList(File file) throws IOException { + assertTrue(file.exists() && file.isFile(), + file.getAbsolutePath() + " does not exist or not a file"); + List output = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) { + while (reader.ready()) { + output.add(reader.readLine().replace(NEW_LINE, "")); + } + } + return output; + } + } diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/sun/tools/jcmd/TestJcmdDefaults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/tools/jcmd/TestJcmdDefaults.java Thu Jan 16 11:37:49 2014 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, 2014, 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 static jdk.testlibrary.Asserts.*; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import jdk.testlibrary.JcmdBase; +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.Utils; + +/** + * Unit test for jcmd utility. Tests jcmd options which do not send + * requests to a specific JVM process. + */ +/* + * @test + * @bug 7104647 + * @library /lib/testlibrary + * @run main TestJcmdDefaults + */ +public class TestJcmdDefaults { + + private static final String TEST_SRC = System.getProperty("test.src").trim(); + private static final String[] VM_ARGS = new String[] { "-XX:+UsePerfData" }; + private static final String JCMD_LIST_REGEX = "^\\d+\\s*.*"; + + public static void main(String[] args) throws Exception { + testJcmdUsage("-h"); + testJcmdUsage("-help"); + testJcmdDefaults(); + testJcmdDefaults("-l"); + } + + /** + * jcmd -J-XX:+UsePerfData -h + * jcmd -J-XX:+UsePerfData -help + */ + private static void testJcmdUsage(String... jcmdArgs) throws Exception { + OutputAnalyzer output = JcmdBase.jcmdNoPid(VM_ARGS, jcmdArgs); + + assertNotEquals(output.getExitValue(), 0); + verifyOutputAgainstFile(output); + } + + /** + * jcmd -J-XX:+UsePerfData + * jcmd -J-XX:+UsePerfData -l + */ + private static void testJcmdDefaults(String... jcmdArgs) throws Exception { + OutputAnalyzer output = JcmdBase.jcmdNoPid(VM_ARGS, jcmdArgs); + + output.shouldHaveExitValue(0); + output.shouldContain("sun.tools.jcmd.JCmd"); + matchListedProcesses(output); + } + + /** + * Verifies the listed processes match a certain pattern. + * + * The output should look like: + * 12246 sun.tools.jcmd.JCmd + * 24428 com.sun.javatest.regtest.MainWrapper /tmp/jtreg/jtreg-workdir/classes/sun/tools/jcmd/TestJcmdDefaults.jta + * + * @param output The generated output from the jcmd. + * @throws Exception + */ + private static void matchListedProcesses(OutputAnalyzer output) throws Exception { + int matchedCount = output.shouldMatchByLine(JCMD_LIST_REGEX); + assertGreaterThan(matchedCount , 0, + "Found no lines matching pattern: " + JCMD_LIST_REGEX); + } + + private static void verifyOutputAgainstFile(OutputAnalyzer output) throws IOException { + File file = new File(TEST_SRC, "usage.out"); + List fileOutput = Utils.fileAsList(file); + List outputAsLines = output.asLines(); + assertTrue(outputAsLines.containsAll(fileOutput), + "The ouput should contain all content of " + file.getAbsolutePath()); + } + +} diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/sun/tools/jcmd/TestJcmdSanity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/tools/jcmd/TestJcmdSanity.java Thu Jan 16 11:37:49 2014 +0100 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2011, 2014, 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 static jdk.testlibrary.Asserts.*; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import jdk.testlibrary.JcmdBase; +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.Utils; + +/** + * Unit test for jcmd utility. The test will send different diagnostic command + * requests to the current java process. + */ +/* + * @test + * @bug 7104647 7154822 + * @library /lib/testlibrary + * @run main TestJcmdSanity + */ +public class TestJcmdSanity { + + private static final String TEST_SRC = System.getProperty("test.src").trim(); + private static final String[] VM_ARGS = new String[] { "-XX:+UsePerfData" }; + private static final String JCMD_COMMAND_REGEX = "(\\w|\\.)*"; + private static final String PERF_COUNTER_REGEX = "(\\w|\\.)*\\=.*"; + + public static void main(String[] args) throws Exception { + testJcmdPidHelp(); + testJcmdPidHelpHelp(); + testJcmdPid_f(); + testJcmdPidPerfCounterPrint(); + testJcmdPidBigScript(); + } + + /** + * jcmd -J-XX:+UsePerfData pid help + */ + private static void testJcmdPidHelp() throws Exception { + OutputAnalyzer output = JcmdBase.jcmd(VM_ARGS, + new String[] {"help"}); + + output.shouldHaveExitValue(0); + output.shouldNotContain("Exception"); + output.shouldContain(Integer.toString(ProcessTools.getProcessId()) + ":"); + matchJcmdCommands(output); + output.shouldContain("For more information about a specific command use 'help '."); + } + + /** + * jcmd -J-XX:+UsePerfData pid help help + */ + private static void testJcmdPidHelpHelp() throws Exception { + OutputAnalyzer output = JcmdBase.jcmd(VM_ARGS, + new String[] {"help", "help"}); + + output.shouldHaveExitValue(0); + verifyOutputAgainstFile(output); + } + + /** + * jcmd -J-XX:+UsePerfData pid PerfCounter.print + */ + private static void testJcmdPidPerfCounterPrint() throws Exception { + OutputAnalyzer output = JcmdBase.jcmd(VM_ARGS, + new String[] {"PerfCounter.print"}); + + output.shouldHaveExitValue(0); + matchPerfCounters(output); + } + + /** + * jcmd -J-XX:+UsePerfData pid -f dcmd-script.txt + */ + private static void testJcmdPid_f() throws Exception { + File scrpitFile = new File(TEST_SRC, "dcmd-script.txt"); + OutputAnalyzer output = JcmdBase.jcmd(VM_ARGS, + new String[] {"-f", scrpitFile.getAbsolutePath()}); + + output.shouldHaveExitValue(0); + verifyOutputAgainstFile(output); + } + + /** + * Tests that it possible send a file over 1024 bytes large via jcmd -f. + * + * jcmd -J-XX:+UsePerfData pid -f dcmd-big-script.txt + */ + private static void testJcmdPidBigScript() throws Exception { + File scrpitFile = new File(TEST_SRC, "dcmd-big-script.txt"); + OutputAnalyzer output = JcmdBase.jcmd(VM_ARGS, + new String[] {"-f", scrpitFile.getAbsolutePath()}); + + output.shouldHaveExitValue(0); + output.shouldNotContain("Exception"); + output.shouldContain(System.getProperty("java.vm.name").trim()); + } + + /** + * Verifies the listed jcmd commands match a certain pattern. + * + * The output of the jcmd commands should look like: + * VM.uptime + * VM.flags + * VM.system_properties + * + * @param output The generated output from the jcmd. + * @throws Exception + */ + private static void matchJcmdCommands(OutputAnalyzer output) throws Exception { + int matchedCount = output.shouldMatchByLine(JCMD_COMMAND_REGEX, + "help", + JCMD_COMMAND_REGEX); + assertGreaterThan(matchedCount , 0, + "Found no lines matching pattern: " + JCMD_COMMAND_REGEX); + } + + /** + * Verifies the generated output from the PerfCounter.print command + * matches a certain pattern. + * + * The output of perf counters should look like: + * java.property.java.vm.name="Java HotSpot(TM) 64-Bit Server VM" + * java.threads.daemon=7 + * sun.rt.javaCommand="com.sun.javatest.regtest.MainWrapper /tmp/jtreg/jtreg-workdir/classes/sun/tools/jcmd/TestJcmdSanity.jta" + * + * @param output The generated output from the PerfCounter.print command. + * @throws Exception + */ + private static void matchPerfCounters(OutputAnalyzer output) throws Exception { + int matchedCount = output.shouldMatchByLineFrom(PERF_COUNTER_REGEX, + PERF_COUNTER_REGEX); + assertGreaterThan(matchedCount , 0, + "Found no lines matching pattern: " + PERF_COUNTER_REGEX); + } + + private static void verifyOutputAgainstFile(OutputAnalyzer output) throws IOException { + File file = new File(TEST_SRC, "help_help.out"); + List fileOutput = Utils.fileAsList(file); + List outputAsLines = output.asLines(); + assertTrue(outputAsLines.containsAll(fileOutput), + "The ouput should contain all content of " + file.getAbsolutePath()); + } + +} diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/sun/tools/jcmd/help_help.out --- a/jdk/test/sun/tools/jcmd/help_help.out Thu Jan 16 10:27:57 2014 +0100 +++ b/jdk/test/sun/tools/jcmd/help_help.out Thu Jan 16 11:37:49 2014 +0100 @@ -1,7 +1,7 @@ help For more information about a specific command use 'help '. With no argument this will show a list of available commands. 'help all' will show help for all commands. -Impact: Low +Impact: Low Syntax : help [options] [] diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/sun/tools/jcmd/jcmd-Defaults.sh --- a/jdk/test/sun/tools/jcmd/jcmd-Defaults.sh Thu Jan 16 10:27:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -# -# Copyright (c) 2011, 2012, 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 7104647 -# @run shell jcmd-Defaults.sh -# @summary Test that output of 'jcmd' and 'jcmd -l' match a specific pattern - -JCMD="${TESTJAVA}/bin/jcmd" - -${JCMD} -J-XX:+UsePerfData 2>&1 | awk -f ${TESTSRC}/jcmd_Output1.awk - -${JCMD} -J-XX:+UsePerfData -l 2>&1 | awk -f ${TESTSRC}/jcmd_Output1.awk diff -r 6c67737a5ac0 -r 5c1a07e4573d jdk/test/sun/tools/jcmd/jcmd-big-script.sh --- a/jdk/test/sun/tools/jcmd/jcmd-big-script.sh Thu Jan 16 10:27:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2012, 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 7154822 -# @summary test if we can send a file over 1024 bytes large via jcmd -f -# @author David Buck -# -# @library ../common -# @build SimpleApplication ShutdownSimpleApplication -# @run shell jcmd-big-script.sh - -. ${TESTSRC}/../common/CommonSetup.sh -. ${TESTSRC}/../common/ApplicationSetup.sh - -# Start application and use PORTFILE for coordination -PORTFILE="${TESTCLASSES}"/shutdown.port -startApplication SimpleApplication "${PORTFILE}" - -failed=0; - -# -f