1 /* 2 * Copyright (c) 2013, 2018, 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 package com.oracle.java.testlibrary; 25 26 import static com.oracle.java.testlibrary.Asserts.assertTrue; 27 28 import java.io.BufferedReader; 29 import java.io.File; 30 import java.io.FileReader; 31 import java.io.IOException; 32 import java.net.InetAddress; 33 import java.net.ServerSocket; 34 import java.net.UnknownHostException; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Arrays; 38 import java.util.Collections; 39 import java.util.regex.Pattern; 40 import java.util.regex.Matcher; 41 import java.lang.reflect.Field; 42 import sun.misc.Unsafe; 43 44 /** 45 * Common library for various test helper functions. 46 */ 47 public final class Utils { 48 49 /** 50 * Returns the sequence used by operating system to separate lines. 51 */ 52 public static final String NEW_LINE = System.getProperty("line.separator"); 53 54 /** 55 * Returns the value of 'test.vm.opts'system property. 56 */ 57 public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); 58 59 /** 60 * Returns the value of 'test.java.opts'system property. 61 */ 62 public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); 63 64 public static final String TEST_JDK = System.getProperty("test.jdk"); 65 66 public static final String COMPILE_JDK= System.getProperty("compile.jdk", TEST_JDK); 67 68 public static final String TEST_SRC = System.getProperty("test.src", "").trim(); 69 70 public static final String TEST_CLASSES = System.getProperty("test.classes", "."); 71 72 73 private static Unsafe unsafe = null; 74 75 /** 76 * Returns the value of 'test.timeout.factor' system property 77 * converted to {@code double}. 78 */ 79 public static final double TIMEOUT_FACTOR; 80 static { 81 String toFactor = System.getProperty("test.timeout.factor", "1.0"); 82 TIMEOUT_FACTOR = Double.parseDouble(toFactor); 83 } 84 85 private Utils() { 86 // Private constructor to prevent class instantiation 87 } 88 89 /** 90 * Returns the list of VM options. 91 * 92 * @return List of VM options 93 */ 94 public static List<String> getVmOptions() { 95 return Arrays.asList(safeSplitString(VM_OPTIONS)); 96 } 97 98 /** 99 * Returns the list of VM options with -J prefix. 100 * 101 * @return The list of VM options with -J prefix 102 */ 103 public static List<String> getForwardVmOptions() { 104 String[] opts = safeSplitString(VM_OPTIONS); 105 for (int i = 0; i < opts.length; i++) { 106 opts[i] = "-J" + opts[i]; 107 } 108 return Arrays.asList(opts); 109 } 110 111 /** 112 * Returns the default JTReg arguments for a jvm running a test. 113 * This is the combination of JTReg arguments test.vm.opts and test.java.opts. 114 * @return An array of options, or an empty array if no opptions. 115 */ 116 public static String[] getTestJavaOpts() { 117 List<String> opts = new ArrayList<String>(); 118 Collections.addAll(opts, safeSplitString(VM_OPTIONS)); 119 Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); 120 return opts.toArray(new String[0]); 121 } 122 123 /** 124 * Returns the default JTReg arguments for a jvm running a test without 125 * options that matches regular expressions in {@code filters}. 126 * This is the combination of JTReg arguments test.vm.opts and test.java.opts. 127 * @param filters Regular expressions used to filter out options. 128 * @return An array of options, or an empty array if no options. 129 */ 130 public static String[] getFilteredTestJavaOpts(String... filters) { 131 String options[] = getTestJavaOpts(); 132 133 if (filters.length == 0) { 134 return options; 135 } 136 137 List<String> filteredOptions = new ArrayList<String>(options.length); 138 Pattern patterns[] = new Pattern[filters.length]; 139 for (int i = 0; i < filters.length; i++) { 140 patterns[i] = Pattern.compile(filters[i]); 141 } 142 143 for (String option : options) { 144 boolean matched = false; 145 for (int i = 0; i < patterns.length && !matched; i++) { 146 Matcher matcher = patterns[i].matcher(option); 147 matched = matcher.find(); 148 } 149 if (!matched) { 150 filteredOptions.add(option); 151 } 152 } 153 154 return filteredOptions.toArray(new String[filteredOptions.size()]); 155 } 156 157 /** 158 * Combines given arguments with default JTReg arguments for a jvm running a test. 159 * This is the combination of JTReg arguments test.vm.opts and test.java.opts 160 * @return The combination of JTReg test java options and user args. 161 */ 162 public static String[] addTestJavaOpts(String... userArgs) { 163 List<String> opts = new ArrayList<String>(); 164 Collections.addAll(opts, getTestJavaOpts()); 165 Collections.addAll(opts, userArgs); 166 return opts.toArray(new String[0]); 167 } 168 169 /** 170 * Splits a string by white space. 171 * Works like String.split(), but returns an empty array 172 * if the string is null or empty. 173 */ 174 private static String[] safeSplitString(String s) { 175 if (s == null || s.trim().isEmpty()) { 176 return new String[] {}; 177 } 178 return s.trim().split("\\s+"); 179 } 180 181 /** 182 * @return The full command line for the ProcessBuilder. 183 */ 184 public static String getCommandLine(ProcessBuilder pb) { 185 StringBuilder cmd = new StringBuilder(); 186 for (String s : pb.command()) { 187 cmd.append(s).append(" "); 188 } 189 return cmd.toString(); 190 } 191 192 /** 193 * Returns the free port on the local host. 194 * The function will spin until a valid port number is found. 195 * 196 * @return The port number 197 * @throws InterruptedException if any thread has interrupted the current thread 198 * @throws IOException if an I/O error occurs when opening the socket 199 */ 200 public static int getFreePort() throws InterruptedException, IOException { 201 int port = -1; 202 203 while (port <= 0) { 204 Thread.sleep(100); 205 206 ServerSocket serverSocket = null; 207 try { 208 serverSocket = new ServerSocket(0); 209 port = serverSocket.getLocalPort(); 210 } finally { 211 serverSocket.close(); 212 } 213 } 214 215 return port; 216 } 217 218 /** 219 * Returns the name of the local host. 220 * 221 * @return The host name 222 * @throws UnknownHostException if IP address of a host could not be determined 223 */ 224 public static String getHostname() throws UnknownHostException { 225 InetAddress inetAddress = InetAddress.getLocalHost(); 226 String hostName = inetAddress.getHostName(); 227 228 assertTrue((hostName != null && !hostName.isEmpty()), 229 "Cannot get hostname"); 230 231 return hostName; 232 } 233 234 /** 235 * Uses "jcmd -l" to search for a jvm pid. This function will wait 236 * forever (until jtreg timeout) for the pid to be found. 237 * @param key Regular expression to search for 238 * @return The found pid. 239 */ 240 public static int waitForJvmPid(String key) throws Throwable { 241 final long iterationSleepMillis = 250; 242 System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); 243 System.out.flush(); 244 while (true) { 245 int pid = tryFindJvmPid(key); 246 if (pid >= 0) { 247 return pid; 248 } 249 Thread.sleep(iterationSleepMillis); 250 } 251 } 252 253 /** 254 * Searches for a jvm pid in the output from "jcmd -l". 255 * 256 * Example output from jcmd is: 257 * 12498 sun.tools.jcmd.JCmd -l 258 * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar 259 * 260 * @param key A regular expression to search for. 261 * @return The found pid, or -1 if Enot found. 262 * @throws Exception If multiple matching jvms are found. 263 */ 264 public static int tryFindJvmPid(String key) throws Throwable { 265 OutputAnalyzer output = null; 266 try { 267 JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); 268 jcmdLauncher.addToolArg("-l"); 269 output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); 270 output.shouldHaveExitValue(0); 271 272 // Search for a line starting with numbers (pid), followed by the key. 273 Pattern pattern = Pattern.compile("^([0-9]+)\\s.*(" + key + ")", Pattern.MULTILINE); 274 Matcher matcher = pattern.matcher(output.getStdout()); 275 276 int pid = -1; 277 if (matcher.find()) { 278 pid = Integer.parseInt(matcher.group(1)); 279 System.out.println("findJvmPid.pid: " + pid); 280 if (matcher.find()) { 281 throw new Exception("Found multiple JVM pids for key: " + key); 282 } 283 } 284 return pid; 285 } catch (Throwable t) { 286 System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); 287 throw t; 288 } 289 } 290 291 /** 292 * Returns file content as a list of strings 293 * 294 * @param file File to operate on 295 * @return List of strings 296 * @throws IOException 297 */ 298 public static List<String> fileAsList(File file) throws IOException { 299 assertTrue(file.exists() && file.isFile(), 300 file.getAbsolutePath() + " does not exist or not a file"); 301 List<String> output = new ArrayList<>(); 302 try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) { 303 while (reader.ready()) { 304 output.add(reader.readLine().replace(NEW_LINE, "")); 305 } 306 } 307 return output; 308 } 309 310 /** 311 * Return the contents of the named file as a single String, 312 * or null if not found. 313 * @param filename name of the file to read 314 * @return String contents of file, or null if file not found. 315 */ 316 public static String fileAsString(String filename) { 317 StringBuilder result = new StringBuilder(); 318 try { 319 File file = new File(filename); 320 if (file.exists()) { 321 BufferedReader reader = new BufferedReader(new FileReader(file)); 322 while (true) { 323 String line = reader.readLine(); 324 if (line == null) { 325 break; 326 } 327 result.append(line).append("\n"); 328 } 329 } else { 330 // Does not exist: 331 return null; 332 } 333 } catch (Exception e) { 334 e.printStackTrace(); 335 } 336 return result.toString(); 337 } 338 339 /** 340 * @return Unsafe instance. 341 */ 342 public static synchronized Unsafe getUnsafe() { 343 if (unsafe == null) { 344 try { 345 Field f = Unsafe.class.getDeclaredField("theUnsafe"); 346 f.setAccessible(true); 347 unsafe = (Unsafe) f.get(null); 348 } catch (NoSuchFieldException | IllegalAccessException e) { 349 throw new RuntimeException("Unable to get Unsafe instance.", e); 350 } 351 } 352 return unsafe; 353 } 354 private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 355 356 /** 357 * Returns hex view of byte array 358 * 359 * @param bytes byte array to process 360 * @return Space separated hexadecimal string representation of bytes 361 */ 362 363 public static String toHexString(byte[] bytes) { 364 char[] hexView = new char[bytes.length * 3]; 365 int i = 0; 366 for (byte b : bytes) { 367 hexView[i++] = hexArray[(b >> 4) & 0x0F]; 368 hexView[i++] = hexArray[b & 0x0F]; 369 hexView[i++] = ' '; 370 } 371 return new String(hexView); 372 } 373 }