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