1 /* 2 * Copyright (c) 2008, 2014, 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.OutputStream; 25 import java.io.InputStream; 26 import java.lang.annotation.ElementType; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.lang.annotation.Target; 30 import java.lang.reflect.Method; 31 import java.util.regex.Pattern; 32 import java.io.StringWriter; 33 import java.io.PrintWriter; 34 import java.util.Set; 35 import java.io.BufferedReader; 36 import java.io.File; 37 import java.io.FileFilter; 38 import java.io.FileNotFoundException; 39 import java.io.FileOutputStream; 40 import java.io.IOException; 41 import java.io.InputStreamReader; 42 import java.io.PrintStream; 43 import java.nio.charset.Charset; 44 import java.nio.file.attribute.BasicFileAttributes; 45 import java.nio.file.Files; 46 import java.nio.file.FileVisitResult; 47 import java.nio.file.SimpleFileVisitor; 48 import java.nio.file.Path; 49 import java.util.ArrayList; 50 import java.util.List; 51 import java.util.Locale; 52 import java.util.Map; 53 import java.util.Arrays; 54 import javax.tools.JavaCompiler; 55 import javax.tools.ToolProvider; 56 57 import static java.nio.file.StandardCopyOption.*; 58 import static java.nio.file.StandardOpenOption.*; 59 60 /** 61 * This class provides some common utilities for the TooSmallStackSize.java 62 * test and is a copy of jdk/test/tools/launcher/TestHelper.java. 63 */ 64 public class TestHelper { 65 // commonly used jtreg constants 66 static final File TEST_CLASSES_DIR; 67 static final File TEST_SOURCES_DIR; 68 69 static final String JAVAHOME = System.getProperty("java.home"); 70 static final String JAVA_BIN; 71 static final String JAVA_LIB; 72 static final String javaCmd; 73 static final String javawCmd; 74 static final String javacCmd; 75 static final String jarCmd; 76 static final boolean haveServerVM; 77 static final boolean haveClientVM; 78 79 static final JavaCompiler compiler; 80 81 static final boolean debug = Boolean.getBoolean("TestHelper.Debug"); 82 static final boolean isWindows = 83 System.getProperty("os.name", "unknown").startsWith("Windows"); 84 static final boolean isMacOSX = 85 System.getProperty("os.name", "unknown").contains("OS X"); 86 static final boolean is64Bit = 87 System.getProperty("sun.arch.data.model").equals("64"); 88 static final boolean is32Bit = 89 System.getProperty("sun.arch.data.model").equals("32"); 90 static final boolean isSolaris = 91 System.getProperty("os.name", "unknown").startsWith("SunOS"); 92 static final boolean isLinux = 93 System.getProperty("os.name", "unknown").startsWith("Linux"); 94 static final boolean isAIX = 95 System.getProperty("os.name", "unknown").startsWith("AIX"); 96 static final String LIBJVM = isWindows 97 ? "jvm.dll" 98 : "libjvm" + (isMacOSX ? ".dylib" : ".so"); 99 100 static final boolean isSparc = System.getProperty("os.arch").startsWith("sparc"); 101 102 // make a note of the golden default locale 103 static final Locale DefaultLocale = Locale.getDefault(); 104 105 static final String JAVA_FILE_EXT = ".java"; 106 static final String CLASS_FILE_EXT = ".class"; 107 static final String JAR_FILE_EXT = ".jar"; 108 static final String EXE_FILE_EXT = ".exe"; 109 static final String JLDEBUG_KEY = "_JAVA_LAUNCHER_DEBUG"; 110 static final String EXPECTED_MARKER = "TRACER_MARKER:About to EXEC"; 111 static final String TEST_PREFIX = "###TestError###: "; 112 113 static int testExitValue = 0; 114 115 static { 116 String tmp = System.getProperty("test.classes", null); 117 if (tmp == null) { 118 throw new Error("property test.classes not defined ??"); 119 } 120 TEST_CLASSES_DIR = new File(tmp).getAbsoluteFile(); 121 122 tmp = System.getProperty("test.src", null); 123 if (tmp == null) { 124 throw new Error("property test.src not defined ??"); 125 } 126 TEST_SOURCES_DIR = new File(tmp).getAbsoluteFile(); 127 128 if (is64Bit && is32Bit) { 129 throw new RuntimeException("arch model cannot be both 32 and 64 bit"); 130 } 131 if (!is64Bit && !is32Bit) { 132 throw new RuntimeException("arch model is not 32 or 64 bit ?"); 133 } 134 compiler = ToolProvider.getSystemJavaCompiler(); 135 136 File binDir = new File(JAVAHOME, "bin"); 137 JAVA_BIN = binDir.getAbsolutePath(); 138 File libDir = new File(JAVAHOME, "lib"); 139 JAVA_LIB = libDir.getAbsolutePath(); 140 141 File javaCmdFile = (isWindows) 142 ? new File(binDir, "java.exe") 143 : new File(binDir, "java"); 144 javaCmd = javaCmdFile.getAbsolutePath(); 145 if (!javaCmdFile.canExecute()) { 146 throw new RuntimeException("java <" + TestHelper.javaCmd + 147 "> must exist and should be executable"); 148 } 149 150 File javacCmdFile = (isWindows) 151 ? new File(binDir, "javac.exe") 152 : new File(binDir, "javac"); 153 javacCmd = javacCmdFile.getAbsolutePath(); 154 155 File jarCmdFile = (isWindows) 156 ? new File(binDir, "jar.exe") 157 : new File(binDir, "jar"); 158 jarCmd = jarCmdFile.getAbsolutePath(); 159 if (!jarCmdFile.canExecute()) { 160 throw new RuntimeException("java <" + TestHelper.jarCmd + 161 "> must exist and should be executable"); 162 } 163 164 if (isWindows) { 165 File javawCmdFile = new File(binDir, "javaw.exe"); 166 javawCmd = javawCmdFile.getAbsolutePath(); 167 if (!javawCmdFile.canExecute()) { 168 throw new RuntimeException("java <" + javawCmd + 169 "> must exist and should be executable"); 170 } 171 } else { 172 javawCmd = null; 173 } 174 175 if (!javacCmdFile.canExecute()) { 176 throw new RuntimeException("java <" + javacCmd + 177 "> must exist and should be executable"); 178 } 179 180 haveClientVM = haveVmVariant("client"); 181 haveServerVM = haveVmVariant("server"); 182 } 183 private static boolean haveVmVariant(String type) { 184 if (isWindows) { 185 File vmDir = new File(JAVA_BIN, type); 186 File jvmFile = new File(vmDir, LIBJVM); 187 return jvmFile.exists(); 188 } else { 189 File vmDir = new File(JAVA_LIB, type); 190 File vmArchDir = new File(vmDir, getJreArch()); 191 File jvmFile = new File(vmArchDir, LIBJVM); 192 return jvmFile.exists(); 193 } 194 } 195 void run(String[] args) throws Exception { 196 int passed = 0, failed = 0; 197 final Pattern p = (args != null && args.length > 0) 198 ? Pattern.compile(args[0]) 199 : null; 200 for (Method m : this.getClass().getDeclaredMethods()) { 201 boolean selected = (p == null) 202 ? m.isAnnotationPresent(Test.class) 203 : p.matcher(m.getName()).matches(); 204 if (selected) { 205 try { 206 m.invoke(this, (Object[]) null); 207 System.out.println(m.getName() + ": OK"); 208 passed++; 209 System.out.printf("Passed: %d, Failed: %d, ExitValue: %d%n", 210 passed, failed, testExitValue); 211 } catch (Throwable ex) { 212 System.out.printf("Test %s failed: %s %n", m, ex); 213 System.out.println("----begin detailed exceptions----"); 214 ex.printStackTrace(System.out); 215 for (Throwable t : ex.getSuppressed()) { 216 t.printStackTrace(System.out); 217 } 218 System.out.println("----end detailed exceptions----"); 219 failed++; 220 } 221 } 222 } 223 System.out.printf("Total: Passed: %d, Failed %d%n", passed, failed); 224 if (failed > 0) { 225 throw new RuntimeException("Tests failed: " + failed); 226 } 227 if (passed == 0 && failed == 0) { 228 throw new AssertionError("No test(s) selected: passed = " + 229 passed + ", failed = " + failed + " ??????????"); 230 } 231 } 232 233 /* 234 * usually the jre/lib/arch-name is the same as os.arch, except for x86. 235 */ 236 static String getJreArch() { 237 String arch = System.getProperty("os.arch"); 238 return arch.equals("x86") ? "i386" : arch; 239 } 240 static String getArch() { 241 return System.getProperty("os.arch"); 242 } 243 static File getClassFile(File javaFile) { 244 String s = javaFile.getAbsolutePath().replace(JAVA_FILE_EXT, CLASS_FILE_EXT); 245 return new File(s); 246 } 247 248 static File getJavaFile(File classFile) { 249 String s = classFile.getAbsolutePath().replace(CLASS_FILE_EXT, JAVA_FILE_EXT); 250 return new File(s); 251 } 252 253 static String baseName(File f) { 254 String s = f.getName(); 255 return s.substring(0, s.indexOf(".")); 256 } 257 258 /* 259 * A convenience method to create a jar with jar file name and defs 260 */ 261 static void createJar(File jarName, String... mainDefs) 262 throws FileNotFoundException{ 263 createJar(null, jarName, new File("Foo"), mainDefs); 264 } 265 266 /* 267 * A convenience method to create a java file, compile and jar it up, using 268 * the sole class file name in the jar, as the Main-Class attribute value. 269 */ 270 static void createJar(File jarName, File mainClass, String... mainDefs) 271 throws FileNotFoundException { 272 createJar(null, jarName, mainClass, mainDefs); 273 } 274 275 /* 276 * A convenience method to compile java files. 277 */ 278 static void compile(String... compilerArgs) { 279 if (compiler.run(null, null, null, compilerArgs) != 0) { 280 String sarg = ""; 281 for (String x : compilerArgs) { 282 sarg.concat(x + " "); 283 } 284 throw new Error("compilation failed: " + sarg); 285 } 286 } 287 288 /* 289 * A generic jar file creator to create a java file, compile it 290 * and jar it up, a specific Main-Class entry name in the 291 * manifest can be specified or a null to use the sole class file name 292 * as the Main-Class attribute value. 293 */ 294 static void createJar(String mEntry, File jarName, File mainClass, 295 String... mainDefs) throws FileNotFoundException { 296 if (jarName.exists()) { 297 jarName.delete(); 298 } 299 try (PrintStream ps = new PrintStream(new FileOutputStream(mainClass + ".java"))) { 300 ps.println("public class Foo {"); 301 if (mainDefs != null) { 302 for (String x : mainDefs) { 303 ps.println(x); 304 } 305 } 306 ps.println("}"); 307 } 308 309 String compileArgs[] = { 310 mainClass + ".java" 311 }; 312 if (compiler.run(null, null, null, compileArgs) != 0) { 313 throw new RuntimeException("compilation failed " + mainClass + ".java"); 314 } 315 if (mEntry == null) { 316 mEntry = mainClass.getName(); 317 } 318 String jarArgs[] = { 319 (debug) ? "cvfe" : "cfe", 320 jarName.getAbsolutePath(), 321 mEntry, 322 mainClass.getName() + ".class" 323 }; 324 createJar(jarArgs); 325 } 326 327 static void createJar(String... args) { 328 List<String> cmdList = new ArrayList<>(); 329 cmdList.add(jarCmd); 330 cmdList.addAll(Arrays.asList(args)); 331 doExec(cmdList.toArray(new String[cmdList.size()])); 332 } 333 334 static void copyStream(InputStream in, OutputStream out) throws IOException { 335 byte[] buf = new byte[8192]; 336 int n = in.read(buf); 337 while (n > 0) { 338 out.write(buf, 0, n); 339 n = in.read(buf); 340 } 341 } 342 343 static void copyFile(File src, File dst) throws IOException { 344 Path parent = dst.toPath().getParent(); 345 if (parent != null) { 346 Files.createDirectories(parent); 347 } 348 Files.copy(src.toPath(), dst.toPath(), COPY_ATTRIBUTES, REPLACE_EXISTING); 349 } 350 351 /** 352 * Attempt to create a file at the given location. If an IOException 353 * occurs then back off for a moment and try again. When a number of 354 * attempts fail, give up and throw an exception. 355 */ 356 void createAFile(File aFile, List<String> contents) throws IOException { 357 IOException cause = null; 358 for (int attempts = 0; attempts < 10; attempts++) { 359 try { 360 Files.write(aFile.getAbsoluteFile().toPath(), contents, 361 Charset.defaultCharset(), CREATE, TRUNCATE_EXISTING, WRITE); 362 if (cause != null) { 363 /* 364 * report attempts and errors that were encountered 365 * for diagnostic purposes 366 */ 367 System.err.println("Created batch file " + 368 aFile + " in " + (attempts + 1) + 369 " attempts"); 370 System.err.println("Errors encountered: " + cause); 371 cause.printStackTrace(); 372 } 373 return; 374 } catch (IOException ioe) { 375 if (cause != null) { 376 // chain the exceptions so they all get reported for diagnostics 377 cause.addSuppressed(ioe); 378 } else { 379 cause = ioe; 380 } 381 } 382 383 try { 384 Thread.sleep(500); 385 } catch (InterruptedException ie) { 386 if (cause != null) { 387 // cause should alway be non-null here 388 ie.addSuppressed(cause); 389 } 390 throw new RuntimeException("Interrupted while creating batch file", ie); 391 } 392 } 393 throw new RuntimeException("Unable to create batch file", cause); 394 } 395 396 static void createFile(File outFile, List<String> content) throws IOException { 397 Files.write(outFile.getAbsoluteFile().toPath(), content, 398 Charset.defaultCharset(), CREATE_NEW); 399 } 400 401 static void recursiveDelete(File target) throws IOException { 402 if (!target.exists()) { 403 return; 404 } 405 Files.walkFileTree(target.toPath(), new SimpleFileVisitor<Path>() { 406 @Override 407 public FileVisitResult postVisitDirectory(Path dir, IOException exc) { 408 try { 409 Files.deleteIfExists(dir); 410 } catch (IOException ex) { 411 System.out.println("Error: could not delete: " + dir.toString()); 412 System.out.println(ex.getMessage()); 413 return FileVisitResult.TERMINATE; 414 } 415 return FileVisitResult.CONTINUE; 416 } 417 @Override 418 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 419 try { 420 Files.deleteIfExists(file); 421 } catch (IOException ex) { 422 System.out.println("Error: could not delete: " + file.toString()); 423 System.out.println(ex.getMessage()); 424 return FileVisitResult.TERMINATE; 425 } 426 return FileVisitResult.CONTINUE; 427 } 428 }); 429 } 430 431 static TestResult doExec(String...cmds) { 432 return doExec(null, null, cmds); 433 } 434 435 static TestResult doExec(Map<String, String> envToSet, String...cmds) { 436 return doExec(envToSet, null, cmds); 437 } 438 /* 439 * A method which executes a java cmd and returns the results in a container 440 */ 441 static TestResult doExec(Map<String, String> envToSet, 442 Set<String> envToRemove, String...cmds) { 443 String cmdStr = ""; 444 for (String x : cmds) { 445 cmdStr = cmdStr.concat(x + " "); 446 } 447 ProcessBuilder pb = new ProcessBuilder(cmds); 448 Map<String, String> env = pb.environment(); 449 if (envToRemove != null) { 450 for (String key : envToRemove) { 451 env.remove(key); 452 } 453 } 454 if (envToSet != null) { 455 env.putAll(envToSet); 456 } 457 BufferedReader rdr = null; 458 try { 459 List<String> outputList = new ArrayList<>(); 460 pb.redirectErrorStream(true); 461 Process p = pb.start(); 462 rdr = new BufferedReader(new InputStreamReader(p.getInputStream())); 463 String in = rdr.readLine(); 464 while (in != null) { 465 outputList.add(in); 466 in = rdr.readLine(); 467 } 468 p.waitFor(); 469 p.destroy(); 470 471 return new TestHelper.TestResult(cmdStr, p.exitValue(), outputList, 472 env, new Throwable("current stack of the test")); 473 } catch (Exception ex) { 474 ex.printStackTrace(); 475 throw new RuntimeException(ex.getMessage()); 476 } 477 } 478 479 static FileFilter createFilter(final String extension) { 480 return new FileFilter() { 481 @Override 482 public boolean accept(File pathname) { 483 String name = pathname.getName(); 484 if (name.endsWith(extension)) { 485 return true; 486 } 487 return false; 488 } 489 }; 490 } 491 492 static boolean isEnglishLocale() { 493 return Locale.getDefault().getLanguage().equals("en"); 494 } 495 496 /* 497 * A class to encapsulate the test results and stuff, with some ease 498 * of use methods to check the test results. 499 */ 500 static class TestResult { 501 PrintWriter status; 502 StringWriter sw; 503 int exitValue; 504 List<String> testOutput; 505 Map<String, String> env; 506 Throwable t; 507 boolean testStatus; 508 509 public TestResult(String str, int rv, List<String> oList, 510 Map<String, String> env, Throwable t) { 511 sw = new StringWriter(); 512 status = new PrintWriter(sw); 513 status.println("Executed command: " + str + "\n"); 514 exitValue = rv; 515 testOutput = oList; 516 this.env = env; 517 this.t = t; 518 testStatus = true; 519 } 520 521 void appendError(String x) { 522 testStatus = false; 523 testExitValue++; 524 status.println(TEST_PREFIX + x); 525 } 526 527 void indentStatus(String x) { 528 status.println(" " + x); 529 } 530 531 void checkNegative() { 532 if (exitValue == 0) { 533 appendError("test must not return 0 exit value"); 534 } 535 } 536 537 void checkPositive() { 538 if (exitValue != 0) { 539 appendError("test did not return 0 exit value"); 540 } 541 } 542 543 boolean isOK() { 544 return exitValue == 0; 545 } 546 547 boolean isZeroOutput() { 548 if (!testOutput.isEmpty()) { 549 appendError("No message from cmd please"); 550 return false; 551 } 552 return true; 553 } 554 555 boolean isNotZeroOutput() { 556 if (testOutput.isEmpty()) { 557 appendError("Missing message"); 558 return false; 559 } 560 return true; 561 } 562 563 @Override 564 public String toString() { 565 status.println("++++Begin Test Info++++"); 566 status.println("Test Status: " + (testStatus ? "PASS" : "FAIL")); 567 status.println("++++Test Environment++++"); 568 for (String x : env.keySet()) { 569 indentStatus(x + "=" + env.get(x)); 570 } 571 status.println("++++Test Output++++"); 572 for (String x : testOutput) { 573 indentStatus(x); 574 } 575 status.println("++++Test Stack Trace++++"); 576 status.println(t.toString()); 577 for (StackTraceElement e : t.getStackTrace()) { 578 indentStatus(e.toString()); 579 } 580 status.println("++++End of Test Info++++"); 581 status.flush(); 582 String out = sw.toString(); 583 status.close(); 584 return out; 585 } 586 587 boolean contains(String str) { 588 for (String x : testOutput) { 589 if (x.contains(str)) { 590 return true; 591 } 592 } 593 appendError("string <" + str + "> not found"); 594 return false; 595 } 596 597 boolean notContains(String str) { 598 for (String x : testOutput) { 599 if (x.contains(str)) { 600 appendError("string <" + str + "> found"); 601 return false; 602 } 603 } 604 return true; 605 } 606 607 boolean matches(String regexToMatch) { 608 for (String x : testOutput) { 609 if (x.matches(regexToMatch)) { 610 return true; 611 } 612 } 613 appendError("regex <" + regexToMatch + "> not matched"); 614 return false; 615 } 616 617 boolean notMatches(String regexToMatch) { 618 for (String x : testOutput) { 619 if (!x.matches(regexToMatch)) { 620 return true; 621 } 622 } 623 appendError("regex <" + regexToMatch + "> matched"); 624 return false; 625 } 626 } 627 /** 628 * Indicates that the annotated method is a test method. 629 */ 630 @Retention(RetentionPolicy.RUNTIME) 631 @Target(ElementType.METHOD) 632 public @interface Test {} 633 }