1 /*
   2  * Copyright (c) 2014, 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.util.ArrayList;
  32 import java.util.Arrays;
  33 import java.util.List;
  34 
  35 import jdk.testlibrary.Asserts;
  36 import jdk.testlibrary.JDKToolLauncher;
  37 import jdk.testlibrary.OutputAnalyzer;
  38 import jdk.testlibrary.Utils;
  39 
  40 /**
  41  * The helper class for running jps utility and verifying output from it
  42  */
  43 public final class JpsHelper {
  44 
  45     /**
  46      * Helper class for handling jps arguments
  47      */
  48     public enum JpsArg {
  49         q,
  50         l,
  51         m,
  52         v,
  53         V;
  54 
  55         /**
  56          * Generate all possible combinations of {@link JpsArg}
  57          * (31 argument combinations and no arguments case)
  58          */
  59         public static List<List<JpsArg>> generateCombinations() {
  60             final int argCount = JpsArg.values().length;
  61             // If there are more than 30 args this algorithm will overflow.
  62             Asserts.assertLessThan(argCount, 31, "Too many args");
  63 
  64             List<List<JpsArg>> combinations = new ArrayList<>();
  65             int combinationCount = (int) Math.pow(2, argCount);
  66             for (int currCombo = 0; currCombo < combinationCount; ++currCombo) {
  67                 List<JpsArg> combination = new ArrayList<>();
  68                 for (int position = 0; position < argCount; ++position) {
  69                     int bit = 1 << position;
  70                     if ((bit & currCombo) != 0) {
  71                         combination.add(JpsArg.values()[position]);
  72                     }
  73                 }
  74                 combinations.add(combination);
  75             }
  76             return combinations;
  77         }
  78 
  79         /**
  80          *  Return combination of {@link JpsArg} as a String array
  81          */
  82         public static String[] asCmdArray(List<JpsArg> jpsArgs) {
  83             List<String> list = new ArrayList<>();
  84             for (JpsArg jpsArg : jpsArgs) {
  85                 list.add("-" + jpsArg.toString());
  86             }
  87             return list.toArray(new String[list.size()]);
  88         }
  89 
  90     }
  91 
  92     /**
  93      * VM arguments to start test application with
  94      */
  95     public static final String[] VM_ARGS = {"-Xmx512m", "-XX:+PrintGCDetails"};
  96     /**
  97      * VM flag to start test application with
  98      */
  99     public static final String VM_FLAG = "+DisableExplicitGC";
 100 
 101     private static File vmFlagsFile = null;
 102     private static List<String> testVmArgs = null;
 103     private static File manifestFile = null;
 104 
 105     /**
 106      * Create a file containing VM_FLAG in the working directory
 107      */
 108     public static File getVmFlagsFile() throws IOException {
 109         if (vmFlagsFile == null) {
 110             vmFlagsFile = new File("vmflags");
 111             try (BufferedWriter output = new BufferedWriter(new FileWriter(vmFlagsFile))) {
 112                 output.write(VM_FLAG);
 113             }
 114             vmFlagsFile.deleteOnExit();
 115         }
 116         return vmFlagsFile;
 117     }
 118 
 119     /**
 120      * Return a list of VM arguments
 121      */
 122     public static List<String> getVmArgs() throws IOException {
 123         if (testVmArgs == null) {
 124             testVmArgs = new ArrayList<>();
 125             testVmArgs.addAll(Arrays.asList(VM_ARGS));
 126             testVmArgs.add("-XX:Flags=" + getVmFlagsFile().getAbsolutePath());
 127         }
 128         return testVmArgs;
 129     }
 130 
 131     /**
 132      * Start jps utility without any arguments
 133      */
 134     public static OutputAnalyzer jps() throws Exception {
 135         return jps(null, null);
 136     }
 137 
 138     /**
 139      * Start jps utility with tool arguments
 140      */
 141     public static OutputAnalyzer jps(String... toolArgs) throws Exception {
 142         return jps(null, Arrays.asList(toolArgs));
 143     }
 144 
 145     /**
 146      * Start jps utility with VM args and tool arguments
 147      */
 148     public static OutputAnalyzer jps(List<String> vmArgs, List<String> toolArgs) throws Exception {
 149         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps");
 150         if (vmArgs != null) {
 151             for (String vmArg : vmArgs) {
 152                 launcher.addVMArg(vmArg);
 153             }
 154         }
 155         if (toolArgs != null) {
 156             for (String toolArg : toolArgs) {
 157                 launcher.addToolArg(toolArg);
 158             }
 159         }
 160 
 161         ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
 162         System.out.println(Arrays.toString(processBuilder.command().toArray()).replace(",", ""));
 163         OutputAnalyzer output = new OutputAnalyzer(processBuilder.start());
 164         System.out.println(output.getOutput());
 165 
 166         return output;
 167     }
 168 
 169     /**
 170      * Verify jps output contains pids and programs' name information.
 171      * The function will discard any lines that come before the first line with pid.
 172      * This can happen if the JVM outputs a warning message for some reason
 173      * before running jps.
 174      *
 175      * The output can look like:
 176      * 35536 Jps
 177      * 35417 Main
 178      * 31103 org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
 179      */
 180     public static void verifyJpsOutput(OutputAnalyzer output, String regex) throws Exception {
 181         output.shouldHaveExitValue(0);
 182         int matchedCount = output.shouldMatchByLineFrom(regex, regex);
 183         assertGreaterThan(matchedCount , 0, "Found no lines matching pattern: " + regex);
 184     }
 185 
 186     /**
 187      * Compare jps output with a content in a file line by line
 188      */
 189     public static void verifyOutputAgainstFile(OutputAnalyzer output) throws IOException {
 190         String testSrc = System.getProperty("test.src", "?");
 191         File file = new File(testSrc, "usage.out");
 192         List<String> fileOutput = Utils.fileAsList(file);
 193         List<String> outputAsLines = output.asLines();
 194         assertTrue(outputAsLines.containsAll(fileOutput),
 195                 "The ouput should contain all content of " + file.getAbsolutePath());
 196     }
 197 
 198     private static File getManifest(String className) throws IOException {
 199         if (manifestFile == null) {
 200             manifestFile = new File(className + ".mf");
 201             try (BufferedWriter output = new BufferedWriter(new FileWriter(manifestFile))) {
 202                 output.write("Main-Class: " + className + Utils.NEW_LINE);
 203             }
 204         }
 205         return manifestFile;
 206     }
 207 
 208     /**
 209      * Build a jar of test classes in runtime
 210      */
 211     public static File buildJar(String className) throws Exception {
 212         File jar = new File(className + ".jar");
 213 
 214         List<String> jarArgs = new ArrayList<>();
 215         jarArgs.add("-cfm");
 216         jarArgs.add(jar.getAbsolutePath());
 217         File manifestFile = getManifest(className);
 218         jarArgs.add(manifestFile.getAbsolutePath());
 219         String testClassPath = System.getProperty("test.class.path", "?");
 220         for (String path : testClassPath.split(File.pathSeparator)) {
 221             jarArgs.add("-C");
 222             jarArgs.add(path);
 223             jarArgs.add(".");
 224         }
 225 
 226         System.out.println("Running jar " + jarArgs.toString());
 227         sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
 228         if (!jarTool.run(jarArgs.toArray(new String[jarArgs.size()]))) {
 229             throw new Exception("jar failed: args=" + jarArgs.toString());
 230         }
 231 
 232         manifestFile.delete();
 233         jar.deleteOnExit();
 234 
 235         return jar;
 236     }
 237 
 238 }