1 /* 2 * Copyright (c) 2013, 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 java.io.IOException; 25 import java.io.File; 26 import java.nio.file.Files; 27 import java.util.Arrays; 28 import java.util.regex.Pattern; 29 import java.util.regex.Matcher; 30 31 import jdk.testlibrary.OutputAnalyzer; 32 import jdk.testlibrary.ProcessTools; 33 import jdk.testlibrary.Utils; 34 import jdk.testlibrary.ProcessThread; 35 36 /* 37 * Utility functions for test runners. 38 * (Test runner = class that launch a test) 39 */ 40 public class RunnerUtil { 41 42 /** 43 * The Application process must be run concurrently with our tests since 44 * the tests will attach to the Application. 45 * We will run the Application process in a separate thread. 46 * 47 * The Application must be started with flag "-Xshare:off" for the Retransform 48 * test in TestBasics to pass on all platforms. 49 * 50 * The Application will write its pid and shutdownPort in the given outFile. 51 */ 52 public static ProcessThread startApplication(String outFile, String... additionalOpts) throws Throwable { 53 String classpath = System.getProperty("test.class.path", "."); 54 String[] myArgs = concat(additionalOpts, new String [] { "-Dattach.test=true", "-classpath", classpath, "Application", outFile }); 55 String[] args = Utils.addTestJavaOpts(myArgs); 56 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args); 57 ProcessThread pt = new ProcessThread("runApplication", pb); 58 pt.start(); 59 return pt; 60 } 61 62 public static String[] concat(String[] a, String[] b) { 63 if (a == null) { 64 return b; 65 } 66 if (b == null) { 67 return a; 68 } 69 int aLen = a.length; 70 int bLen = b.length; 71 String[] c = new String[aLen + bLen]; 72 System.arraycopy(a, 0, c, 0, aLen); 73 System.arraycopy(b, 0, c, aLen, bLen); 74 return c; 75 } 76 77 /** 78 * Will stop the running Application. 79 * First tries to shutdown nicely by connecting to the shut down port. 80 * If that fails, the process will be killed hard with stopProcess(). 81 * 82 * If the nice shutdown fails, then an Exception is thrown and the test should fail. 83 * 84 * @param port The shut down port. 85 * @param processThread The process to stop. 86 */ 87 public static void stopApplication(int port, ProcessThread processThread) throws Throwable { 88 if (processThread == null) { 89 System.out.println("RunnerUtil.stopApplication ignored since proc is null"); 90 return; 91 } 92 try { 93 System.out.println("RunnerUtil.stopApplication waiting to for shutdown"); 94 OutputAnalyzer output = ProcessTools.executeTestJvm( 95 "-classpath", 96 System.getProperty("test.class.path", "."), 97 "Shutdown", 98 Integer.toString(port)); 99 // Verify that both the Shutdown command and the Application finished ok. 100 output.shouldHaveExitValue(0); 101 processThread.joinAndThrow(); 102 processThread.getOutput().shouldHaveExitValue(0); 103 } catch (Throwable t) { 104 System.out.println("RunnerUtil.stopApplication failed. Will kill it hard: " + t); 105 processThread.stopProcess(); 106 throw t; 107 } 108 } 109 110 /** 111 * Creates a jar file. 112 * @param args Command to the jar tool. 113 */ 114 public static void createJar(String... args) { 115 System.out.println("Running: jar " + Arrays.toString(args)); 116 sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar"); 117 if (!jar.run(args)) { 118 throw new RuntimeException("jar failed: args=" + Arrays.toString(args)); 119 } 120 } 121 122 /** 123 * Read process info for the running Application. 124 * The Application writes its info to a file with this format: 125 * shutdownPort=42994 126 * pid=19597 127 * done 128 * 129 * The final "done" is used to make sure the complete file has been written 130 * before we try to read it. 131 * This function will wait until the file is available. 132 * 133 * @param filename Path to file to read. 134 * @return The ProcessInfo containing pid and shutdownPort. 135 */ 136 public static ProcessInfo readProcessInfo(String filename) throws Throwable { 137 System.out.println("Reading port and pid from file: " + filename); 138 File file = new File(filename); 139 String content = null; 140 141 // Read file or wait for it to be created. 142 while (true) { 143 content = readFile(file); 144 if (content != null && content.indexOf("done") >= 0) { 145 break; 146 } 147 Thread.sleep(100); 148 } 149 150 ProcessInfo info = new ProcessInfo(); 151 // search for a line with format: key=nnn 152 Pattern pattern = Pattern.compile("(\\w*)=([0-9]+)\\r?\\n"); 153 Matcher matcher = pattern.matcher(content); 154 while (matcher.find()) { 155 String key = matcher.group(1); 156 int value = Integer.parseInt(matcher.group(2)); 157 if ("pid".equals(key)) { 158 info.pid = value; 159 } else if ("shutdownPort".equals(key)) { 160 info.shutdownPort = value; 161 } 162 } 163 System.out.println("processInfo.pid:" + info.pid); 164 System.out.println("processInfo.shutdownPort:" + info.shutdownPort); 165 return info; 166 } 167 168 /** 169 * Read the content of a file. 170 * @param file The file to read. 171 * @return The file content or null if file does not exists. 172 */ 173 public static String readFile(File file) throws IOException { 174 if (!file.exists()) { 175 return null; 176 } 177 try { 178 byte[] bytes = Files.readAllBytes(file.toPath()); 179 String content = new String(bytes); 180 return content; 181 } catch (IOException e) { 182 e.printStackTrace(); 183 throw e; 184 } 185 } 186 187 /** 188 * Helper class with info of the running Application. 189 */ 190 public static class ProcessInfo { 191 public int pid = -1; 192 public int shutdownPort = -1; 193 } 194 195 }