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