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.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      */
  99     public static final String[] VM_ARGS = {"-Xmx512m", "-XX:+PrintGCDetails"};
 100     /**
 101      * VM flag to start test application with
 102      */
 103     public static final String VM_FLAG = "+DisableExplicitGC";
 104 
 105     private static File vmFlagsFile = null;
 106     private static List<String> testVmArgs = null;
 107     private static File manifestFile = null;
 108 
 109     /**
 110      * Create a file containing VM_FLAG in the working directory
 111      */
 112     public static File getVmFlagsFile() throws IOException {
 113         if (vmFlagsFile == null) {
 114             vmFlagsFile = new File("vmflags");
 115             try (BufferedWriter output = new BufferedWriter(new FileWriter(vmFlagsFile))) {
 116                 output.write(VM_FLAG);
 117             }
 118             vmFlagsFile.deleteOnExit();
 119         }
 120         return vmFlagsFile;
 121     }
 122 
 123     /**
 124      * Return a list of VM arguments
 125      */
 126     public static List<String> getVmArgs() throws IOException {
 127         if (testVmArgs == null) {
 128             testVmArgs = new ArrayList<>();
 129             testVmArgs.addAll(Arrays.asList(VM_ARGS));
 130             testVmArgs.add("-XX:Flags=" + getVmFlagsFile().getAbsolutePath());
 131         }
 132         return testVmArgs;
 133     }
 134 
 135     /**
 136      * Start jps utility without any arguments
 137      */
 138     public static OutputAnalyzer jps() throws Exception {
 139         return jps(null, null);
 140     }
 141 
 142     /**
 143      * Start jps utility with tool arguments
 144      */
 145     public static OutputAnalyzer jps(String... toolArgs) throws Exception {
 146         return jps(null, Arrays.asList(toolArgs));
 147     }
 148 
 149     /**
 150      * Start jps utility with VM args and tool arguments
 151      */
 152     public static OutputAnalyzer jps(List<String> vmArgs, List<String> toolArgs) throws Exception {
 153         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jps");
 154         launcher.addVMArg("-XX:+UsePerfData");
 155         if (vmArgs != null) {
 156             for (String vmArg : vmArgs) {
 157                 launcher.addVMArg(vmArg);
 158             }
 159         }
 160         if (toolArgs != null) {
 161             for (String toolArg : toolArgs) {
 162                 launcher.addToolArg(toolArg);
 163             }
 164         }
 165 
 166         ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand());
 167         System.out.println(Arrays.toString(processBuilder.command().toArray()).replace(",", ""));
 168         OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
 169         System.out.println(output.getOutput());
 170 
 171         return output;
 172     }
 173 
 174     /**
 175      * Verify jps stdout contains only pids and programs' name information.
 176      * jps stderr may contain VM warning messages which will be ignored.
 177      *
 178      * The output can look like:
 179      * 35536 Jps
 180      * 35417 Main
 181      * 31103 org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
 182      */
 183     public static void verifyJpsOutput(OutputAnalyzer output, String regex) throws Exception {
 184         output.shouldHaveExitValue(0);
 185         int matchedCount = output.stdoutShouldMatchByLine(regex);
 186         assertGreaterThan(matchedCount , 0, "Found no lines matching pattern: " + regex);
 187         output.stderrShouldNotMatch("[E|e]xception");
 188         output.stderrShouldNotMatch("[E|e]rror");
 189     }
 190 
 191     /**
 192      * Compare jps output with a content in a file line by line
 193      */
 194     public static void verifyOutputAgainstFile(OutputAnalyzer output) throws IOException {
 195         String testSrc = System.getProperty("test.src", "?");
 196         Path path = Paths.get(testSrc, "usage.out");
 197         List<String> fileOutput = Files.readAllLines(path);
 198         List<String> outputAsLines = output.asLines();
 199         assertTrue(outputAsLines.containsAll(fileOutput),
 200                 "The ouput should contain all content of " + path.toAbsolutePath());
 201     }
 202 
 203     private static File getManifest(String className) throws IOException {
 204         if (manifestFile == null) {
 205             manifestFile = new File(className + ".mf");
 206             try (BufferedWriter output = new BufferedWriter(new FileWriter(manifestFile))) {
 207                 output.write("Main-Class: " + className + Utils.NEW_LINE);
 208             }
 209         }
 210         return manifestFile;
 211     }
 212 
 213     /**
 214      * Build a jar of test classes in runtime
 215      */
 216     public static File buildJar(String className) throws Exception {
 217         File jar = new File(className + ".jar");
 218 
 219         List<String> jarArgs = new ArrayList<>();
 220         jarArgs.add("-cfm");
 221         jarArgs.add(jar.getAbsolutePath());
 222         File manifestFile = getManifest(className);
 223         jarArgs.add(manifestFile.getAbsolutePath());
 224         String testClassPath = System.getProperty("test.class.path", "?");
 225         for (String path : testClassPath.split(File.pathSeparator)) {
 226             jarArgs.add("-C");
 227             jarArgs.add(path);
 228             jarArgs.add(".");
 229         }
 230 
 231         System.out.println("Running jar " + jarArgs.toString());
 232         sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
 233         if (!jarTool.run(jarArgs.toArray(new String[jarArgs.size()]))) {
 234             throw new Exception("jar failed: args=" + jarArgs.toString());
 235         }
 236 
 237         manifestFile.delete();
 238         jar.deleteOnExit();
 239 
 240         return jar;
 241     }
 242 
 243 }