Utils.java revision 2727:db3a049ab963
155714Skris/* 255714Skris * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. 355714Skris * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 455714Skris * 555714Skris * This code is free software; you can redistribute it and/or modify it 655714Skris * under the terms of the GNU General Public License version 2 only, as 755714Skris * published by the Free Software Foundation. 8296465Sdelphij * 955714Skris * This code is distributed in the hope that it will be useful, but WITHOUT 1055714Skris * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1155714Skris * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1255714Skris * version 2 for more details (a copy is included in the LICENSE file that 1355714Skris * accompanied this code). 1455714Skris * 15296465Sdelphij * You should have received a copy of the GNU General Public License version 1655714Skris * 2 along with this work; if not, write to the Free Software Foundation, 1755714Skris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1855714Skris * 1955714Skris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2055714Skris * or visit www.oracle.com if you need additional information or have any 2155714Skris * questions. 22296465Sdelphij */ 2355714Skris 2455714Skrispackage jdk.test.lib; 2555714Skris 2655714Skrisimport java.io.File; 2755714Skrisimport java.io.IOException; 2855714Skrisimport java.net.InetAddress; 2955714Skrisimport java.net.MalformedURLException; 3055714Skrisimport java.net.ServerSocket; 3155714Skrisimport java.net.URL; 3255714Skrisimport java.net.URLClassLoader; 3355714Skrisimport java.net.UnknownHostException; 3455714Skrisimport java.nio.file.Files; 3555714Skrisimport java.nio.file.Path; 3655714Skrisimport java.nio.file.Paths; 37296465Sdelphijimport java.util.ArrayList; 3855714Skrisimport java.util.Arrays; 3955714Skrisimport java.util.Collection; 40296465Sdelphijimport java.util.Collections; 4155714Skrisimport java.util.Iterator; 4255714Skrisimport java.util.Map; 4355714Skrisimport java.util.HashMap; 4455714Skrisimport java.util.List; 4555714Skrisimport java.util.Objects; 4655714Skrisimport java.util.Random; 4755714Skrisimport java.util.function.BooleanSupplier; 4855714Skrisimport java.util.concurrent.TimeUnit; 4955714Skrisimport java.util.function.Consumer; 5055714Skrisimport java.util.function.Function; 5155714Skrisimport java.util.regex.Matcher; 52296465Sdelphijimport java.util.regex.Pattern; 5355714Skris 5455714Skrisimport static jdk.test.lib.Asserts.assertTrue; 5555714Skrisimport jdk.test.lib.process.ProcessTools; 5655714Skrisimport jdk.test.lib.process.OutputAnalyzer; 5755714Skris 5855714Skris/** 59296465Sdelphij * Common library for various test helper functions. 60296465Sdelphij */ 61296465Sdelphijpublic final class Utils { 62296465Sdelphij 6355714Skris /** 64109998Smarkm * Returns the value of 'test.class.path' system property. 65296465Sdelphij */ 6655714Skris public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", "."); 6755714Skris 6855714Skris /** 69109998Smarkm * Returns the sequence used by operating system to separate lines. 70296465Sdelphij */ 71296465Sdelphij public static final String NEW_LINE = System.getProperty("line.separator"); 7255714Skris 73296465Sdelphij /** 7455714Skris * Returns the value of 'test.vm.opts' system property. 7555714Skris */ 76160814Ssimon public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); 77160814Ssimon 78296465Sdelphij /** 79160814Ssimon * Returns the value of 'test.java.opts' system property. 80160814Ssimon */ 8155714Skris public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); 82296465Sdelphij 8355714Skris /** 8455714Skris * Returns the value of 'test.src' system property. 85296465Sdelphij */ 86296465Sdelphij public static final String TEST_SRC = System.getProperty("test.src", "").trim(); 8755714Skris 8855714Skris /* 89296465Sdelphij * Returns the value of 'test.jdk' system property 90296465Sdelphij */ 91296465Sdelphij public static final String TEST_JDK = System.getProperty("test.jdk"); 92296465Sdelphij 93296465Sdelphij /** 94296465Sdelphij * Returns the value of 'test.classes' system property 95109998Smarkm */ 96296465Sdelphij public static final String TEST_CLASSES = System.getProperty("test.classes", "."); 9755714Skris /** 9855714Skris * Defines property name for seed value. 9955714Skris */ 100296465Sdelphij public static final String SEED_PROPERTY_NAME = "jdk.test.lib.random.seed"; 10155714Skris 10255714Skris /* (non-javadoc) 10355714Skris * Random generator with (or without) predefined seed. Depends on 104296465Sdelphij * "jdk.test.lib.random.seed" property value. 105296465Sdelphij */ 106296465Sdelphij private static volatile Random RANDOM_GENERATOR; 10755714Skris 10855714Skris /** 10955714Skris * Contains the seed value used for {@link java.util.Random} creation. 11055714Skris */ 11155714Skris public static final long SEED = Long.getLong(SEED_PROPERTY_NAME, new Random().nextLong()); 11255714Skris /** 11355714Skris * Returns the value of 'test.timeout.factor' system property 11455714Skris * converted to {@code double}. 115296465Sdelphij */ 116296465Sdelphij public static final double TIMEOUT_FACTOR; 117296465Sdelphij static { 118296465Sdelphij String toFactor = System.getProperty("test.timeout.factor", "1.0"); 11955714Skris TIMEOUT_FACTOR = Double.parseDouble(toFactor); 12055714Skris } 12155714Skris 12255714Skris /** 123296465Sdelphij * Returns the value of JTREG default test timeout in milliseconds 124296465Sdelphij * converted to {@code long}. 125296465Sdelphij */ 126296465Sdelphij public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120); 127296465Sdelphij 128296465Sdelphij private Utils() { 129296465Sdelphij // Private constructor to prevent class instantiation 130296465Sdelphij } 131296465Sdelphij 132296465Sdelphij /** 133296465Sdelphij * Returns the list of VM options. 13455714Skris * 135296465Sdelphij * @return List of VM options 136296465Sdelphij */ 137296465Sdelphij public static List<String> getVmOptions() { 138296465Sdelphij return Arrays.asList(safeSplitString(VM_OPTIONS)); 139296465Sdelphij } 140296465Sdelphij 141296465Sdelphij /** 142296465Sdelphij * Returns the list of VM options with -J prefix. 143296465Sdelphij * 144296465Sdelphij * @return The list of VM options with -J prefix 145296465Sdelphij */ 146296465Sdelphij public static List<String> getForwardVmOptions() { 147296465Sdelphij String[] opts = safeSplitString(VM_OPTIONS); 148296465Sdelphij for (int i = 0; i < opts.length; i++) { 149296465Sdelphij opts[i] = "-J" + opts[i]; 15055714Skris } 151296465Sdelphij return Arrays.asList(opts); 152296465Sdelphij } 153296465Sdelphij 154296465Sdelphij /** 155296465Sdelphij * Returns the default JTReg arguments for a jvm running a test. 156296465Sdelphij * This is the combination of JTReg arguments test.vm.opts and test.java.opts. 157296465Sdelphij * @return An array of options, or an empty array if no options. 158296465Sdelphij */ 159296465Sdelphij public static String[] getTestJavaOpts() { 160296465Sdelphij List<String> opts = new ArrayList<String>(); 161296465Sdelphij Collections.addAll(opts, safeSplitString(VM_OPTIONS)); 162296465Sdelphij Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); 163296465Sdelphij return opts.toArray(new String[0]); 164296465Sdelphij } 165296465Sdelphij 16655714Skris /** 16755714Skris * Combines given arguments with default JTReg arguments for a jvm running a test. 16855714Skris * This is the combination of JTReg arguments test.vm.opts and test.java.opts 16955714Skris * @return The combination of JTReg test java options and user args. 17055714Skris */ 171296465Sdelphij public static String[] addTestJavaOpts(String... userArgs) { 172296465Sdelphij List<String> opts = new ArrayList<String>(); 173296465Sdelphij Collections.addAll(opts, getTestJavaOpts()); 174296465Sdelphij Collections.addAll(opts, userArgs); 175296465Sdelphij return opts.toArray(new String[0]); 176296465Sdelphij } 177296465Sdelphij 178296465Sdelphij /** 179296465Sdelphij * Removes any options specifying which GC to use, for example "-XX:+UseG1GC". 180296465Sdelphij * Removes any options matching: -XX:(+/-)Use*GC 181296465Sdelphij * Used when a test need to set its own GC version. Then any 182296465Sdelphij * GC specified by the framework must first be removed. 183296465Sdelphij * @return A copy of given opts with all GC options removed. 184296465Sdelphij */ 185296465Sdelphij private static final Pattern useGcPattern = Pattern.compile( 18655714Skris "(?:\\-XX\\:[\\+\\-]Use.+GC)" 187296465Sdelphij + "|(?:\\-Xconcgc)"); 188296465Sdelphij public static List<String> removeGcOpts(List<String> opts) { 189296465Sdelphij List<String> optsWithoutGC = new ArrayList<String>(); 190296465Sdelphij for (String opt : opts) { 191296465Sdelphij if (useGcPattern.matcher(opt).matches()) { 192296465Sdelphij System.out.println("removeGcOpts: removed " + opt); 193296465Sdelphij } else { 194296465Sdelphij optsWithoutGC.add(opt); 195296465Sdelphij } 196296465Sdelphij } 197296465Sdelphij return optsWithoutGC; 198296465Sdelphij } 199296465Sdelphij 200296465Sdelphij /** 201296465Sdelphij * Returns the default JTReg arguments for a jvm running a test without 20255714Skris * options that matches regular expressions in {@code filters}. 203296465Sdelphij * This is the combination of JTReg arguments test.vm.opts and test.java.opts. 204296465Sdelphij * @param filters Regular expressions used to filter out options. 205296465Sdelphij * @return An array of options, or an empty array if no options. 206296465Sdelphij */ 207296465Sdelphij public static String[] getFilteredTestJavaOpts(String... filters) { 208296465Sdelphij String options[] = getTestJavaOpts(); 209296465Sdelphij 210296465Sdelphij if (filters.length == 0) { 211296465Sdelphij return options; 212296465Sdelphij } 213296465Sdelphij 214296465Sdelphij List<String> filteredOptions = new ArrayList<String>(options.length); 215296465Sdelphij Pattern patterns[] = new Pattern[filters.length]; 216296465Sdelphij for (int i = 0; i < filters.length; i++) { 217296465Sdelphij patterns[i] = Pattern.compile(filters[i]); 21855714Skris } 21955714Skris 22055714Skris for (String option : options) { 22155714Skris boolean matched = false; 22255714Skris for (int i = 0; i < patterns.length && !matched; i++) { 223296465Sdelphij Matcher matcher = patterns[i].matcher(option); 224296465Sdelphij matched = matcher.find(); 225296465Sdelphij } 226296465Sdelphij if (!matched) { 227296465Sdelphij filteredOptions.add(option); 228296465Sdelphij } 229296465Sdelphij } 230296465Sdelphij 231296465Sdelphij return filteredOptions.toArray(new String[filteredOptions.size()]); 232296465Sdelphij } 233296465Sdelphij 234296465Sdelphij /** 235296465Sdelphij * Splits a string by white space. 236296465Sdelphij * Works like String.split(), but returns an empty array 237296465Sdelphij * if the string is null or empty. 23855714Skris */ 239296465Sdelphij private static String[] safeSplitString(String s) { 240296465Sdelphij if (s == null || s.trim().isEmpty()) { 241296465Sdelphij return new String[] {}; 242296465Sdelphij } 243296465Sdelphij return s.trim().split("\\s+"); 244296465Sdelphij } 245296465Sdelphij 246296465Sdelphij /** 247296465Sdelphij * @return The full command line for the ProcessBuilder. 248296465Sdelphij */ 249296465Sdelphij public static String getCommandLine(ProcessBuilder pb) { 250296465Sdelphij StringBuilder cmd = new StringBuilder(); 251296465Sdelphij for (String s : pb.command()) { 252296465Sdelphij cmd.append(s).append(" "); 253296465Sdelphij } 25455714Skris return cmd.toString(); 255296465Sdelphij } 256296465Sdelphij 257296465Sdelphij /** 258296465Sdelphij * Returns the free port on the local host. 259296465Sdelphij * The function will spin until a valid port number is found. 260296465Sdelphij * 261296465Sdelphij * @return The port number 262296465Sdelphij * @throws InterruptedException if any thread has interrupted the current thread 263296465Sdelphij * @throws IOException if an I/O error occurs when opening the socket 264296465Sdelphij */ 265296465Sdelphij public static int getFreePort() throws InterruptedException, IOException { 266296465Sdelphij int port = -1; 267296465Sdelphij 268296465Sdelphij while (port <= 0) { 269296465Sdelphij Thread.sleep(100); 27055714Skris 27155714Skris ServerSocket serverSocket = null; 27255714Skris try { 27355714Skris serverSocket = new ServerSocket(0); 27455714Skris port = serverSocket.getLocalPort(); 275296465Sdelphij } finally { 276296465Sdelphij serverSocket.close(); 277296465Sdelphij } 278296465Sdelphij } 279296465Sdelphij 280296465Sdelphij return port; 281296465Sdelphij } 282296465Sdelphij 283296465Sdelphij /** 284296465Sdelphij * Returns the name of the local host. 285296465Sdelphij * 286296465Sdelphij * @return The host name 287296465Sdelphij * @throws UnknownHostException if IP address of a host could not be determined 288296465Sdelphij */ 289296465Sdelphij public static String getHostname() throws UnknownHostException { 29055714Skris InetAddress inetAddress = InetAddress.getLocalHost(); 291296465Sdelphij String hostName = inetAddress.getHostName(); 292296465Sdelphij 293296465Sdelphij assertTrue((hostName != null && !hostName.isEmpty()), 294296465Sdelphij "Cannot get hostname"); 295296465Sdelphij 296296465Sdelphij return hostName; 297296465Sdelphij } 298296465Sdelphij 299296465Sdelphij /** 300296465Sdelphij * Uses "jcmd -l" to search for a jvm pid. This function will wait 301296465Sdelphij * forever (until jtreg timeout) for the pid to be found. 302296465Sdelphij * @param key Regular expression to search for 303296465Sdelphij * @return The found pid. 304296465Sdelphij */ 305296465Sdelphij public static int waitForJvmPid(String key) throws Throwable { 30655714Skris final long iterationSleepMillis = 250; 307296465Sdelphij System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); 308296465Sdelphij System.out.flush(); 309296465Sdelphij while (true) { 310296465Sdelphij int pid = tryFindJvmPid(key); 311296465Sdelphij if (pid >= 0) { 312296465Sdelphij return pid; 313296465Sdelphij } 314296465Sdelphij Thread.sleep(iterationSleepMillis); 315296465Sdelphij } 316296465Sdelphij } 317296465Sdelphij 318296465Sdelphij /** 319296465Sdelphij * Searches for a jvm pid in the output from "jcmd -l". 320296465Sdelphij * 321296465Sdelphij * Example output from jcmd is: 32255714Skris * 12498 sun.tools.jcmd.JCmd -l 32355714Skris * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar 32455714Skris * 32555714Skris * @param key A regular expression to search for. 32655714Skris * @return The found pid, or -1 if not found. 32755714Skris * @throws Exception If multiple matching jvms are found. 328296465Sdelphij */ 329296465Sdelphij public static int tryFindJvmPid(String key) throws Throwable { 330296465Sdelphij OutputAnalyzer output = null; 33155714Skris try { 33255714Skris JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); 333296465Sdelphij jcmdLauncher.addToolArg("-l"); 33455714Skris output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); 33555714Skris output.shouldHaveExitValue(0); 33655714Skris 33755714Skris // Search for a line starting with numbers (pid), follwed by the key. 338296465Sdelphij Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); 339296465Sdelphij Matcher matcher = pattern.matcher(output.getStdout()); 34055714Skris 34155714Skris int pid = -1; 34255714Skris if (matcher.find()) { 343296465Sdelphij pid = Integer.parseInt(matcher.group(1)); 344296465Sdelphij System.out.println("findJvmPid.pid: " + pid); 345296465Sdelphij if (matcher.find()) { 346296465Sdelphij throw new Exception("Found multiple JVM pids for key: " + key); 347296465Sdelphij } 34855714Skris } 34955714Skris return pid; 35055714Skris } catch (Throwable t) { 351296465Sdelphij System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); 352296465Sdelphij throw t; 353296465Sdelphij } 354296465Sdelphij } 355296465Sdelphij 356296465Sdelphij /** 357296465Sdelphij * Adjusts the provided timeout value for the TIMEOUT_FACTOR 35855714Skris * @param tOut the timeout value to be adjusted 35955714Skris * @return The timeout value adjusted for the value of "test.timeout.factor" 360296465Sdelphij * system property 361296465Sdelphij */ 36255714Skris public static long adjustTimeout(long tOut) { 36355714Skris return Math.round(tOut * Utils.TIMEOUT_FACTOR); 364296465Sdelphij } 365296465Sdelphij 36655714Skris /** 367296465Sdelphij * Return the contents of the named file as a single String, 36855714Skris * or null if not found. 369296465Sdelphij * @param filename name of the file to read 370296465Sdelphij * @return String contents of file, or null if file not found. 371296465Sdelphij * @throws IOException 372296465Sdelphij * if an I/O error occurs reading from the file or a malformed or 373296465Sdelphij * unmappable byte sequence is read 374296465Sdelphij */ 375296465Sdelphij public static String fileAsString(String filename) throws IOException { 376296465Sdelphij Path filePath = Paths.get(filename); 377296465Sdelphij if (!Files.exists(filePath)) return null; 378296465Sdelphij return new String(Files.readAllBytes(filePath)); 379296465Sdelphij } 38055714Skris 381296465Sdelphij private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 382296465Sdelphij 383296465Sdelphij /** 384296465Sdelphij * Returns hex view of byte array 385296465Sdelphij * 386296465Sdelphij * @param bytes byte array to process 387296465Sdelphij * @return Space separated hexadecimal string representation of bytes 388296465Sdelphij */ 389296465Sdelphij 39055714Skris public static String toHexString(byte[] bytes) { 391296465Sdelphij char[] hexView = new char[bytes.length * 3]; 39255714Skris int i = 0; 39355714Skris for (byte b : bytes) { 394296465Sdelphij hexView[i++] = hexArray[(b >> 4) & 0x0F]; 39555714Skris hexView[i++] = hexArray[b & 0x0F]; 396296465Sdelphij hexView[i++] = ' '; 39755714Skris } 398296465Sdelphij return new String(hexView); 39955714Skris } 400296465Sdelphij 401296465Sdelphij /** 402296465Sdelphij * Returns {@link java.util.Random} generator initialized with particular seed. 403296465Sdelphij * The seed could be provided via system property {@link Utils#SEED_PROPERTY_NAME} 404296465Sdelphij * In case no seed is provided, the method uses a random number. 405296465Sdelphij * The used seed printed to stdout. 406296465Sdelphij * @return {@link java.util.Random} generator with particular seed. 407296465Sdelphij */ 408296465Sdelphij public static Random getRandomInstance() { 409296465Sdelphij if (RANDOM_GENERATOR == null) { 41055714Skris synchronized (Utils.class) { 41155714Skris if (RANDOM_GENERATOR == null) { 412296465Sdelphij RANDOM_GENERATOR = new Random(SEED); 413296465Sdelphij System.out.printf("For random generator using seed: %d%n", SEED); 41455714Skris System.out.printf("To re-run test with same seed value please add \"-D%s=%d\" to command line.%n", SEED_PROPERTY_NAME, SEED); 41555714Skris } 416296465Sdelphij } 417296465Sdelphij } 418296465Sdelphij return RANDOM_GENERATOR; 419296465Sdelphij } 420296465Sdelphij 421296465Sdelphij /** 422296465Sdelphij * Returns random element of non empty collection 423296465Sdelphij * 424296465Sdelphij * @param <T> a type of collection element 425296465Sdelphij * @param collection collection of elements 426296465Sdelphij * @return random element of collection 427296465Sdelphij * @throws IllegalArgumentException if collection is empty 428296465Sdelphij */ 429296465Sdelphij public static <T> T getRandomElement(Collection<T> collection) 43055714Skris throws IllegalArgumentException { 431296465Sdelphij if (collection.isEmpty()) { 43255714Skris throw new IllegalArgumentException("Empty collection"); 43355714Skris } 434296465Sdelphij Random random = getRandomInstance(); 435296465Sdelphij int elementIndex = 1 + random.nextInt(collection.size() - 1); 436296465Sdelphij Iterator<T> iterator = collection.iterator(); 437296465Sdelphij while (--elementIndex != 0) { 43855714Skris iterator.next(); 43955714Skris } 440296465Sdelphij return iterator.next(); 441296465Sdelphij } 44255714Skris 44355714Skris /** 444296465Sdelphij * Returns random element of non empty array 445296465Sdelphij * 446296465Sdelphij * @param <T> a type of array element 44755714Skris * @param array array of elements 44855714Skris * @return random element of array 449296465Sdelphij * @throws IllegalArgumentException if array is empty 450296465Sdelphij */ 451296465Sdelphij public static <T> T getRandomElement(T[] array) 452296465Sdelphij throws IllegalArgumentException { 453296465Sdelphij if (array == null || array.length == 0) { 454296465Sdelphij throw new IllegalArgumentException("Empty or null array"); 45555714Skris } 456296465Sdelphij Random random = getRandomInstance(); 457296465Sdelphij return array[random.nextInt(array.length)]; 458296465Sdelphij } 459296465Sdelphij 460296465Sdelphij /** 461296465Sdelphij * Wait for condition to be true 462296465Sdelphij * 463296465Sdelphij * @param condition, a condition to wait for 464296465Sdelphij */ 465296465Sdelphij public static final void waitForCondition(BooleanSupplier condition) { 46655714Skris waitForCondition(condition, -1L, 100L); 467296465Sdelphij } 468296465Sdelphij 469296465Sdelphij /** 47055714Skris * Wait until timeout for condition to be true 471296465Sdelphij * 472296465Sdelphij * @param condition, a condition to wait for 473296465Sdelphij * @param timeout a time in milliseconds to wait for condition to be true 474296465Sdelphij * specifying -1 will wait forever 47555714Skris * @return condition value, to determine if wait was successful 47655714Skris */ 47755714Skris public static final boolean waitForCondition(BooleanSupplier condition, 478296465Sdelphij long timeout) { 479296465Sdelphij return waitForCondition(condition, timeout, 100L); 480296465Sdelphij } 481296465Sdelphij 48255714Skris /** 48355714Skris * Wait until timeout for condition to be true for specified time 484296465Sdelphij * 485296465Sdelphij * @param condition, a condition to wait for 486296465Sdelphij * @param timeout a time in milliseconds to wait for condition to be true, 487296465Sdelphij * specifying -1 will wait forever 48855714Skris * @param sleepTime a time to sleep value in milliseconds 48955714Skris * @return condition value, to determine if wait was successful 490296465Sdelphij */ 491296465Sdelphij public static final boolean waitForCondition(BooleanSupplier condition, 492296465Sdelphij long timeout, long sleepTime) { 493296465Sdelphij long startTime = System.currentTimeMillis(); 49455714Skris while (!(condition.getAsBoolean() || (timeout != -1L 49555714Skris && ((System.currentTimeMillis() - startTime) > timeout)))) { 496296465Sdelphij try { 497296465Sdelphij Thread.sleep(sleepTime); 498296465Sdelphij } catch (InterruptedException e) { 499296465Sdelphij Thread.currentThread().interrupt(); 50055714Skris throw new Error(e); 50155714Skris } 50255714Skris } 503296465Sdelphij return condition.getAsBoolean(); 504296465Sdelphij } 505296465Sdelphij 506296465Sdelphij /** 507296465Sdelphij * Interface same as java.lang.Runnable but with 508296465Sdelphij * method {@code run()} able to throw any Throwable. 509296465Sdelphij */ 510296465Sdelphij public static interface ThrowingRunnable { 511296465Sdelphij void run() throws Throwable; 512296465Sdelphij } 513296465Sdelphij 514296465Sdelphij /** 515296465Sdelphij * Filters out an exception that may be thrown by the given 516296465Sdelphij * test according to the given filter. 517296465Sdelphij * 518296465Sdelphij * @param test - method that is invoked and checked for exception. 51955714Skris * @param filter - function that checks if the thrown exception matches 52055714Skris * criteria given in the filter's implementation. 521296465Sdelphij * @return - exception that matches the filter if it has been thrown or 522296465Sdelphij * {@code null} otherwise. 523296465Sdelphij * @throws Throwable - if test has thrown an exception that does not 524296465Sdelphij * match the filter. 525296465Sdelphij */ 526296465Sdelphij public static Throwable filterException(ThrowingRunnable test, 527296465Sdelphij Function<Throwable, Boolean> filter) throws Throwable { 528296465Sdelphij try { 529296465Sdelphij test.run(); 530296465Sdelphij } catch (Throwable t) { 531296465Sdelphij if (filter.apply(t)) { 532296465Sdelphij return t; 533296465Sdelphij } else { 534296465Sdelphij throw t; 535296465Sdelphij } 536296465Sdelphij } 537296465Sdelphij return null; 538296465Sdelphij } 53955714Skris 54055714Skris /** 541296465Sdelphij * Ensures a requested class is loaded 542296465Sdelphij * @param aClass class to load 543296465Sdelphij */ 544296465Sdelphij public static void ensureClassIsLoaded(Class<?> aClass) { 545296465Sdelphij if (aClass == null) { 546296465Sdelphij throw new Error("Requested null class"); 547296465Sdelphij } 548296465Sdelphij try { 549296465Sdelphij Class.forName(aClass.getName(), /* initialize = */ true, 550296465Sdelphij ClassLoader.getSystemClassLoader()); 551296465Sdelphij } catch (ClassNotFoundException e) { 552296465Sdelphij throw new Error("Class not found", e); 553296465Sdelphij } 554296465Sdelphij } 555296465Sdelphij /** 556296465Sdelphij * @param parent a class loader to be the parent for the returned one 557296465Sdelphij * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg 558296465Sdelphij * property and with the given parent 55955714Skris */ 56055714Skris public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) { 561296465Sdelphij URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator)) 562296465Sdelphij .map(Paths::get) 563296465Sdelphij .map(Path::toUri) 564296465Sdelphij .map(x -> { 565296465Sdelphij try { 566296465Sdelphij return x.toURL(); 567296465Sdelphij } catch (MalformedURLException ex) { 568296465Sdelphij throw new Error("Test issue. JTREG property" 569296465Sdelphij + " 'test.class.path'" 570296465Sdelphij + " is not defined correctly", ex); 571296465Sdelphij } 572296465Sdelphij }).toArray(URL[]::new); 573296465Sdelphij return new URLClassLoader(urls, parent); 574296465Sdelphij } 575296465Sdelphij 576296465Sdelphij /** 577296465Sdelphij * Runs runnable and checks that it throws expected exception. If exceptionException is null it means 578296465Sdelphij * that we expect no exception to be thrown. 57955714Skris * @param runnable what we run 580296465Sdelphij * @param expectedException expected exception 581296465Sdelphij */ 582296465Sdelphij public static void runAndCheckException(Runnable runnable, Class<? extends Throwable> expectedException) { 583296465Sdelphij runAndCheckException(runnable, t -> { 584296465Sdelphij if (t == null) { 585296465Sdelphij if (expectedException != null) { 586296465Sdelphij throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); 587296465Sdelphij } 588296465Sdelphij } else { 589296465Sdelphij String message = "Got unexpected exception " + t.getClass().getSimpleName(); 590296465Sdelphij if (expectedException == null) { 591296465Sdelphij throw new AssertionError(message, t); 592296465Sdelphij } else if (!expectedException.isAssignableFrom(t.getClass())) { 593296465Sdelphij message += " instead of " + expectedException.getSimpleName(); 594296465Sdelphij throw new AssertionError(message, t); 595296465Sdelphij } 596296465Sdelphij } 597296465Sdelphij }); 59855714Skris } 599296465Sdelphij 600296465Sdelphij /** 601296465Sdelphij * Runs runnable and makes some checks to ensure that it throws expected exception. 602296465Sdelphij * @param runnable what we run 603296465Sdelphij * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise 604296465Sdelphij */ 605296465Sdelphij public static void runAndCheckException(Runnable runnable, Consumer<Throwable> checkException) { 606296465Sdelphij try { 607296465Sdelphij runnable.run(); 608296465Sdelphij checkException.accept(null); 609296465Sdelphij } catch (Throwable t) { 610296465Sdelphij checkException.accept(t); 611296465Sdelphij } 612296465Sdelphij } 613296465Sdelphij 614296465Sdelphij /** 615296465Sdelphij * Converts to VM type signature 616296465Sdelphij * 617296465Sdelphij * @param type Java type to convert 618296465Sdelphij * @return string representation of VM type 619296465Sdelphij */ 620296465Sdelphij public static String toJVMTypeSignature(Class<?> type) { 621296465Sdelphij if (type.isPrimitive()) { 622296465Sdelphij if (type == boolean.class) { 623296465Sdelphij return "Z"; 624296465Sdelphij } else if (type == byte.class) { 625296465Sdelphij return "B"; 626296465Sdelphij } else if (type == char.class) { 627296465Sdelphij return "C"; 628296465Sdelphij } else if (type == double.class) { 629296465Sdelphij return "D"; 630296465Sdelphij } else if (type == float.class) { 631296465Sdelphij return "F"; 632296465Sdelphij } else if (type == int.class) { 633296465Sdelphij return "I"; 634296465Sdelphij } else if (type == long.class) { 635296465Sdelphij return "J"; 636296465Sdelphij } else if (type == short.class) { 637296465Sdelphij return "S"; 638109998Smarkm } else if (type == void.class) { 639296465Sdelphij return "V"; 64055714Skris } else { 641296465Sdelphij throw new Error("Unsupported type: " + type); 642 } 643 } 644 String result = type.getName().replaceAll("\\.", "/"); 645 if (!type.isArray()) { 646 return "L" + result + ";"; 647 } 648 return result; 649 } 650 651 public static Object[] getNullValues(Class<?>... types) { 652 Object[] result = new Object[types.length]; 653 int i = 0; 654 for (Class<?> type : types) { 655 result[i++] = NULL_VALUES.get(type); 656 } 657 return result; 658 } 659 private static Map<Class<?>, Object> NULL_VALUES = new HashMap<>(); 660 static { 661 NULL_VALUES.put(boolean.class, false); 662 NULL_VALUES.put(byte.class, (byte) 0); 663 NULL_VALUES.put(short.class, (short) 0); 664 NULL_VALUES.put(char.class, '\0'); 665 NULL_VALUES.put(int.class, 0); 666 NULL_VALUES.put(long.class, 0L); 667 NULL_VALUES.put(float.class, 0.0f); 668 NULL_VALUES.put(double.class, 0.0d); 669 } 670 671 /** 672 * Returns mandatory property value 673 * @param propName is a name of property to request 674 * @return a String with requested property value 675 */ 676 public static String getMandatoryProperty(String propName) { 677 Objects.requireNonNull(propName, "Requested null property"); 678 String prop = System.getProperty(propName); 679 Objects.requireNonNull(prop, 680 String.format("A mandatory property '%s' isn't set", propName)); 681 return prop; 682 } 683 684 // This method is intended to be called from a jtreg test. 685 // It will identify the name of the test by means of stack walking. 686 // It can handle both jtreg tests and a testng tests wrapped inside jtreg tests. 687 // For jtreg tests the name of the test will be searched by stack-walking 688 // until the method main() is found; the class containing that method is the 689 // main test class and will be returned as the name of the test. 690 // Special handling is used for testng tests. 691 public static String getTestName() { 692 String result = null; 693 // If we are using testng, then we should be able to load the "Test" annotation. 694 Class testClassAnnotation; 695 696 try { 697 testClassAnnotation = Class.forName("org.testng.annotations.Test"); 698 } catch (ClassNotFoundException e) { 699 testClassAnnotation = null; 700 } 701 702 StackTraceElement[] elms = (new Throwable()).getStackTrace(); 703 for (StackTraceElement n: elms) { 704 String className = n.getClassName(); 705 706 // If this is a "main" method, then use its class name, but only 707 // if we are not using testng. 708 if (testClassAnnotation == null && "main".equals(n.getMethodName())) { 709 result = className; 710 break; 711 } 712 713 // If this is a testng test, the test will have no "main" method. We can 714 // detect a testng test class by looking for the org.testng.annotations.Test 715 // annotation. If present, then use the name of this class. 716 if (testClassAnnotation != null) { 717 try { 718 Class c = Class.forName(className); 719 if (c.isAnnotationPresent(testClassAnnotation)) { 720 result = className; 721 break; 722 } 723 } catch (ClassNotFoundException e) { 724 throw new RuntimeException("Unexpected exception: " + e, e); 725 } 726 } 727 } 728 729 if (result == null) { 730 throw new RuntimeException("Couldn't find main test class in stack trace"); 731 } 732 733 return result; 734 } 735 736} 737 738