1 /*
   2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import static jdk.testlibrary.Asserts.assertGreaterThan;
  25 import static jdk.testlibrary.Asserts.assertTrue;
  26 
  27 import java.io.BufferedWriter;
  28 import java.io.File;
  29 import java.io.FileWriter;
  30 import java.io.IOException;
  31 import java.nio.file.Files;
  32 import java.nio.file.Path;
  33 import java.nio.file.Paths;
  34 import java.util.ArrayList;
  35 import java.util.Arrays;
  36 import java.util.List;
  37 
  38 import jdk.testlibrary.Asserts;
  39 import jdk.testlibrary.JDKToolLauncher;
  40 import jdk.testlibrary.OutputAnalyzer;
  41 import jdk.testlibrary.Utils;
  42 import jdk.testlibrary.ProcessTools;
  43 
  44 /**
  45  * The helper class for running jps utility and verifying output from it
  46  */
  47 public final class JpsHelper {
  48 
  49     /**
  50      * Helper class for handling jps arguments
  51      */
  52     public enum JpsArg {
  53         q,
  54         l,
  55         m,
  56         v,
  57         V;
  58 
  59         /**
  60          * Generate all possible combinations of {@link JpsArg}
  61          * (31 argument combinations and no arguments case)
  62          */
  63         public static List<List<JpsArg>> generateCombinations() {
  64             final int argCount = JpsArg.values().length;
  65             // If there are more than 30 args this algorithm will overflow.
  66             Asserts.assertLessThan(argCount, 31, "Too many args");
  67 
  68             List<List<JpsArg>> combinations = new ArrayList<>();
  69             int combinationCount = (int) Math.pow(2, argCount);
  70             for (int currCombo = 0; currCombo < combinationCount; ++currCombo) {
  71                 List<JpsArg> combination = new ArrayList<>();
  72                 for (int position = 0; position < argCount; ++position) {
  73                     int bit = 1 << position;
  74                     if ((bit & currCombo) != 0) {
  75                         combination.add(JpsArg.values()[position]);
  76                     }
  77                 }
  78                 combinations.add(combination);
  79             }
  80             return combinations;
  81         }
  82 
  83         /**
  84          *  Return combination of {@link JpsArg} as a String array
  85          */
  86         public static String[] asCmdArray(List<JpsArg> jpsArgs) {
  87             List<String> list = new ArrayList<>();
  88             for (JpsArg jpsArg : jpsArgs) {
  89                 list.add("-" + jpsArg.toString());
  90             }
  91             return list.toArray(new String[list.size()]);
  92         }
  93 
  94     }
  95 
  96     /**
  97      * VM arguments to start test application with.
  98      * -XX:+UsePerfData is required for running the tests on embedded platforms.
  99      */
 100     public static final String[] VM_ARGS = {
 101         "-XX:+UsePerfData", "-Xmx512m", "-Xlog:gc*=debug",
 102         "-Dmultiline.prop=value1\nvalue2\r\nvalue3"
 103     };
 104     /**
 105      * VM flag to start test application with
 106      */
 107     public static final String VM_FLAG = "+DisableExplicitGC";
 108 
 109     private static File vmFlagsFile = null;
 110     private static List<String> testVmArgs = null;
 111     private static File manifestFile = null;
 112 
 113     /**
 114      * Create a file containing VM_FLAG in the working directory
 115      */
 116     public static File getVmFlagsFile() throws IOException {
 117         if (vmFlagsFile == null) {
 118             vmFlagsFile = new File("vmflags");
 119             try (BufferedWriter output = new BufferedWriter(new FileWriter(vmFlagsFile))) {
 120                 output.write(VM_FLAG);
 121             }
 122             vmFlagsFile.deleteOnExit();
 123         }
 124         return vmFlagsFile;
 125     }
 126 
 127     /**
 128      * Return a list of VM arguments
 129      */
 130     public static List<String> getVmArgs() throws IOException {
 131         if (testVmArgs == null) {
 132             testVmArgs = new ArrayList<>();
 133             testVmArgs.addAll(Arrays.asList(VM_ARGS));
 134             testVmArgs.add("-XX:Flags=" + getVmFlagsFile().getAbsolutePath());
 135         }
 136         return testVmArgs;
 137     }
 138 
 139     /**
 140      * Start jps utility without any arguments
 141      */
 142     public static OutputAnalyzer jps() throws Exception {
 143         return jps(null, null);
 144     }
 145 
 146     /**
 147      * Start jps utility with tool arguments
 148      */
 149     public static OutputAnalyzer jps(String... toolArgs) throws Exception {
 150         return jps(null, Arrays.asList(toolArgs));
 151     }
 152 
 153     /**
 154      * Start jps utility with VM args and tool arguments
 155      */
 156     public static OutputAnalyzer jps(List<String> vmArgs, List<String> toolArgs) throws Exception {
 157         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps");
 158         launcher.addVMArg("-XX:+UsePerfData");
 159         if (vmArgs != null) {
 160             for (String vmArg : vmArgs) {
 161                 launcher.addVMArg(vmArg);
 162             }
 163         }
 164         if (toolArgs != null) {
 165             for (String toolArg : toolArgs) {
 166                 launcher.addToolArg(toolArg);
 167             }
 168         }
 169 
 170         ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
 171         System.out.println(Arrays.toString(processBuilder.command().toArray()).replace(",", ""));
 172         OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
 173         System.out.println(output.getOutput());
 174 
 175         return output;
 176     }
 177 
 178     /**
 179      * Verify jps stdout contains only pids and programs' name information.
 180      * jps stderr may contain VM warning messages which will be ignored.
 181      *
 182      * The output can look like:
 183      * 35536 Jps
 184      * 35417 Main
 185      * 31103 org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
 186      */
 187     public static void verifyJpsOutput(OutputAnalyzer output, String regex) throws Exception {
 188         output.shouldHaveExitValue(0);
 189         int matchedCount = output.stdoutShouldMatchByLine(regex);
 190         assertGreaterThan(matchedCount , 0, "Found no lines matching pattern: " + regex);
 191         output.stderrShouldNotMatch("[E|e]xception");
 192         output.stderrShouldNotMatch("[E|e]rror");
 193     }
 194 
 195     /**
 196      * Compare jps output with a content in a file line by line
 197      */
 198     public static void verifyOutputAgainstFile(OutputAnalyzer output) throws IOException {
 199         String testSrc = System.getProperty("test.src", "?");
 200         Path path = Paths.get(testSrc, "usage.out");
 201         List<String> fileOutput = Files.readAllLines(path);
 202         List<String> outputAsLines = output.asLines();
 203         assertTrue(outputAsLines.containsAll(fileOutput),
 204                 "The ouput should contain all content of " + path.toAbsolutePath());
 205     }
 206 
 207     private static File getManifest(String className) throws IOException {
 208         if (manifestFile == null) {
 209             manifestFile = new File(className + ".mf");
 210             try (BufferedWriter output = new BufferedWriter(new FileWriter(manifestFile))) {
 211                 output.write("Main-Class: " + className + Utils.NEW_LINE);
 212             }
 213         }
 214         return manifestFile;
 215     }
 216 
 217     /**
 218      * Build a jar of test classes in runtime
 219      */
 220     public static File buildJar(String className) throws Exception {
 221         File jar = new File(className + ".jar");
 222 
 223         List<String> jarArgs = new ArrayList<>();
 224         jarArgs.add("-cfm");
 225         jarArgs.add(jar.getAbsolutePath());
 226         File manifestFile = getManifest(className);
 227         jarArgs.add(manifestFile.getAbsolutePath());
 228         String testClassPath = System.getProperty("test.class.path", "?");
 229         for (String path : testClassPath.split(File.pathSeparator)) {
 230             jarArgs.add("-C");
 231             jarArgs.add(path);
 232             jarArgs.add(".");
 233         }
 234 
 235         System.out.println("Running jar " + jarArgs.toString());
 236         sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
 237         if (!jarTool.run(jarArgs.toArray(new String[jarArgs.size()]))) {
 238             throw new Exception("jar failed: args=" + jarArgs.toString());
 239         }
 240 
 241         manifestFile.delete();
 242         jar.deleteOnExit();
 243 
 244         return jar;
 245     }
 246 
 247 }