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 package jdk.jpackage.test; 24 25 import java.io.BufferedOutputStream; 26 import java.io.FileNotFoundException; 27 import java.io.FileOutputStream; 28 import java.io.IOException; 29 import java.io.PrintStream; 30 import java.nio.file.FileSystems; 31 import java.nio.file.Files; 32 import java.nio.file.Path; 33 import java.nio.file.StandardWatchEventKinds; 34 import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; 35 import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; 36 import java.nio.file.WatchEvent; 37 import java.nio.file.WatchKey; 38 import java.nio.file.WatchService; 39 import java.util.Collection; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.Set; 43 import java.util.concurrent.TimeUnit; 44 import java.util.function.Consumer; 45 import java.util.function.Supplier; 46 import java.util.stream.Collectors; 47 import jdk.jpackage.internal.IOUtils; 48 49 final public class Test { 50 51 public static final Path TEST_SRC_ROOT = new Supplier<Path>() { 52 @Override 53 public Path get() { 54 Path root = Path.of(System.getProperty("test.src")); 55 56 for (int i = 0; i != 10; ++i) { 57 if (root.resolve("apps").toFile().isDirectory()) { 58 return root.toAbsolutePath(); 59 } 60 root = root.resolve(".."); 61 } 62 63 throw new RuntimeException("Failed to locate apps directory"); 64 } 65 }.get(); 66 67 private static class Instance implements AutoCloseable { 204 if (TRACE_ASSERTS) { 205 log("TRACE: " + v); 206 } 207 } 208 209 public static void error(String v) { 210 log("ERROR: " + v); 211 throw new AssertionError(v); 212 } 213 214 private static final String TEMP_FILE_PREFIX = null; 215 216 public static Path createTempDirectory() throws IOException { 217 return Files.createTempDirectory(workDir(), TEMP_FILE_PREFIX); 218 } 219 220 public static Path createTempFile(String suffix) throws IOException { 221 return Files.createTempFile(workDir(), TEMP_FILE_PREFIX, suffix); 222 } 223 224 public static void withTempFile(String suffix, Consumer<Path> action) { 225 Path tempFile = null; 226 boolean keepIt = true; 227 try { 228 tempFile = createTempFile(suffix); 229 action.accept(tempFile); 230 keepIt = false; 231 } catch (IOException ex) { 232 throw new RuntimeException(ex); 233 } finally { 234 if (tempFile != null && !keepIt) { 235 try { 236 Files.deleteIfExists(tempFile); 237 } catch (IOException ex) { 238 throw new RuntimeException(ex); 239 } 240 } 241 } 242 } 243 244 public static void withTempDirectory(Consumer<Path> action) { 245 Path tempDir = null; 246 boolean keepIt = true; 247 try { 248 tempDir = createTempDirectory(); 249 action.accept(tempDir); 250 keepIt = false; 251 } catch (IOException ex) { 252 throw new RuntimeException(ex); 253 } finally { 254 try { 255 if (tempDir != null && tempDir.toFile().isDirectory() && !keepIt) { 256 IOUtils.deleteRecursive(tempDir.toFile()); 257 } 258 } catch (IOException ex) { 259 throw new RuntimeException(ex); 260 } 261 } 262 } 263 264 public static void waitForFileCreated(Path fileToWaitFor, 265 long timeoutSeconds) throws IOException { 266 267 trace(String.format("Wait for file [%s] to be available", fileToWaitFor)); 268 269 WatchService ws = FileSystems.getDefault().newWatchService(); 270 271 Path watchDirectory = fileToWaitFor.toAbsolutePath().getParent(); 272 watchDirectory.register(ws, ENTRY_CREATE, ENTRY_MODIFY); 273 274 long waitUntil = System.currentTimeMillis() + timeoutSeconds * 1000; 275 for (;;) { 276 long timeout = waitUntil - System.currentTimeMillis(); 277 assertTrue(timeout > 0, String.format( 278 "Check timeout value %d is positive", timeout)); 279 280 WatchKey key = null; 281 try { 282 key = ws.poll(timeout, TimeUnit.MILLISECONDS); 283 } catch (InterruptedException ex) { 284 throw new RuntimeException(ex); 420 "Check [%s] is a directory", path)); 421 } 422 } 423 424 public static void assertFileExists(Path path, boolean exists) { 425 assertPathExists(path, exists); 426 if (exists) { 427 assertTrue(path.toFile().isFile(), String.format( 428 "Check [%s] is a file", path)); 429 } 430 } 431 432 public static void assertExecutableFileExists(Path path, boolean exists) { 433 assertFileExists(path, exists); 434 if (exists) { 435 assertTrue(path.toFile().canExecute(), String.format( 436 "Check [%s] file is executable", path)); 437 } 438 } 439 440 public static void assertUnexpected(String msg) { 441 currentTest.notifyAssert(); 442 error(concatMessages("Unexpected", msg)); 443 } 444 445 private static PrintStream openLogStream() { 446 if (LOG_FILE == null) { 447 return null; 448 } 449 450 try { 451 return new PrintStream(new FileOutputStream(LOG_FILE.toFile(), true)); 452 } catch (FileNotFoundException ex) { 453 throw new RuntimeException(ex); 454 } 455 } 456 457 private static Instance currentTest; 458 459 private static final boolean TRACE; 460 private static final boolean TRACE_ASSERTS; 461 462 static final boolean VERBOSE_JPACKAGE; 463 464 static String getConfigProperty(String propertyName) { 465 return System.getProperty(getConfigPropertyName(propertyName)); 466 } 467 468 static String getConfigPropertyName(String propertyName) { 469 return "jpackage.test." + propertyName; 470 } 471 472 static final Path LOG_FILE = new Supplier<Path>() { 473 @Override 474 public Path get() { 475 String val = getConfigProperty("logfile"); 476 if (val == null) { 477 return null; 478 } 479 return Path.of(val); 480 } 481 }.get(); 482 483 static { 484 String val = getConfigProperty("suppress-logging"); 485 if (val == null) { 486 TRACE = true; 487 TRACE_ASSERTS = true; 488 VERBOSE_JPACKAGE = true; 489 } else if ("all".equals(val.toLowerCase())) { 490 TRACE = false; 491 TRACE_ASSERTS = false; 492 VERBOSE_JPACKAGE = false; 493 } else { 494 Set<String> logOptions = Set.of(val.toLowerCase().split(",")); 495 TRACE = !(logOptions.contains("trace") || logOptions.contains("t")); 496 TRACE_ASSERTS = !(logOptions.contains("assert") || logOptions.contains( 497 "a")); 498 VERBOSE_JPACKAGE = !(logOptions.contains("jpackage") || logOptions.contains( 499 "jp")); 500 } 501 } | 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 package jdk.jpackage.test; 24 25 import java.io.File; 26 import java.io.FileNotFoundException; 27 import java.io.FileOutputStream; 28 import java.io.IOException; 29 import java.io.PrintStream; 30 import java.nio.file.FileSystems; 31 import java.nio.file.Files; 32 import java.nio.file.Path; 33 import java.nio.file.StandardWatchEventKinds; 34 import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; 35 import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; 36 import java.nio.file.WatchEvent; 37 import java.nio.file.WatchKey; 38 import java.nio.file.WatchService; 39 import java.util.Collection; 40 import java.util.Comparator; 41 import java.util.Iterator; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.Set; 45 import java.util.concurrent.TimeUnit; 46 import java.util.concurrent.atomic.AtomicInteger; 47 import java.util.function.Supplier; 48 import java.util.stream.Collectors; 49 import jdk.jpackage.test.Functional.ThrowingConsumer; 50 import jdk.jpackage.test.Functional.ThrowingRunnable; 51 import jdk.jpackage.test.Functional.ThrowingSupplier; 52 53 final public class Test { 54 55 public static final Path TEST_SRC_ROOT = new Supplier<Path>() { 56 @Override 57 public Path get() { 58 Path root = Path.of(System.getProperty("test.src")); 59 60 for (int i = 0; i != 10; ++i) { 61 if (root.resolve("apps").toFile().isDirectory()) { 62 return root.toAbsolutePath(); 63 } 64 root = root.resolve(".."); 65 } 66 67 throw new RuntimeException("Failed to locate apps directory"); 68 } 69 }.get(); 70 71 private static class Instance implements AutoCloseable { 208 if (TRACE_ASSERTS) { 209 log("TRACE: " + v); 210 } 211 } 212 213 public static void error(String v) { 214 log("ERROR: " + v); 215 throw new AssertionError(v); 216 } 217 218 private static final String TEMP_FILE_PREFIX = null; 219 220 public static Path createTempDirectory() throws IOException { 221 return Files.createTempDirectory(workDir(), TEMP_FILE_PREFIX); 222 } 223 224 public static Path createTempFile(String suffix) throws IOException { 225 return Files.createTempFile(workDir(), TEMP_FILE_PREFIX, suffix); 226 } 227 228 public static void withTempFile(String suffix, ThrowingConsumer<Path> action) { 229 final Path tempFile = ThrowingSupplier.toSupplier(() -> createTempFile( 230 suffix)).get(); 231 boolean keepIt = true; 232 try { 233 ThrowingConsumer.toConsumer(action).accept(tempFile); 234 keepIt = false; 235 } finally { 236 if (tempFile != null && !keepIt) { 237 ThrowingRunnable.toRunnable(() -> Files.deleteIfExists(tempFile)).run(); 238 } 239 } 240 } 241 242 public static void withTempDirectory(ThrowingConsumer<Path> action) { 243 final Path tempDir = ThrowingSupplier.toSupplier( 244 () -> createTempDirectory()).get(); 245 boolean keepIt = true; 246 try { 247 ThrowingConsumer.toConsumer(action).accept(tempDir); 248 keepIt = false; 249 } finally { 250 if (tempDir != null && tempDir.toFile().isDirectory() && !keepIt) { 251 deleteDirectoryRecursive(tempDir); 252 } 253 } 254 } 255 256 static void deleteDirectoryRecursive(Path path) { 257 ThrowingRunnable.toRunnable(() -> Files.walk(path).sorted( 258 Comparator.reverseOrder()).map(Path::toFile).forEach( 259 File::delete)).run(); 260 } 261 262 static void waitForFileCreated(Path fileToWaitFor, 263 long timeoutSeconds) throws IOException { 264 265 trace(String.format("Wait for file [%s] to be available", fileToWaitFor)); 266 267 WatchService ws = FileSystems.getDefault().newWatchService(); 268 269 Path watchDirectory = fileToWaitFor.toAbsolutePath().getParent(); 270 watchDirectory.register(ws, ENTRY_CREATE, ENTRY_MODIFY); 271 272 long waitUntil = System.currentTimeMillis() + timeoutSeconds * 1000; 273 for (;;) { 274 long timeout = waitUntil - System.currentTimeMillis(); 275 assertTrue(timeout > 0, String.format( 276 "Check timeout value %d is positive", timeout)); 277 278 WatchKey key = null; 279 try { 280 key = ws.poll(timeout, TimeUnit.MILLISECONDS); 281 } catch (InterruptedException ex) { 282 throw new RuntimeException(ex); 418 "Check [%s] is a directory", path)); 419 } 420 } 421 422 public static void assertFileExists(Path path, boolean exists) { 423 assertPathExists(path, exists); 424 if (exists) { 425 assertTrue(path.toFile().isFile(), String.format( 426 "Check [%s] is a file", path)); 427 } 428 } 429 430 public static void assertExecutableFileExists(Path path, boolean exists) { 431 assertFileExists(path, exists); 432 if (exists) { 433 assertTrue(path.toFile().canExecute(), String.format( 434 "Check [%s] file is executable", path)); 435 } 436 } 437 438 public static void assertReadableFileExists(Path path) { 439 assertFileExists(path, true); 440 assertTrue(path.toFile().canRead(), String.format( 441 "Check [%s] file is readable", path)); 442 } 443 444 public static void assertUnexpected(String msg) { 445 currentTest.notifyAssert(); 446 error(concatMessages("Unexpected", msg)); 447 } 448 449 public static void assertStringListEquals(List<String> expected, 450 List<String> actual, String msg) { 451 currentTest.notifyAssert(); 452 453 if (expected.size() < actual.size()) { 454 // Actual string list is longer than expected 455 error(concatMessages(String.format( 456 "Actual list is longer than expected by %d elements", 457 actual.size() - expected.size()), msg)); 458 } 459 460 if (actual.size() < expected.size()) { 461 // Actual string list is shorter than expected 462 error(concatMessages(String.format( 463 "Actual list is longer than expected by %d elements", 464 expected.size() - actual.size()), msg)); 465 } 466 467 traceAssert(String.format("assertStringListEquals(): %s", msg)); 468 469 String idxFieldFormat = Functional.identity(() -> { 470 int listSize = expected.size(); 471 int width = 0; 472 while (listSize != 0) { 473 listSize = listSize / 10; 474 width++; 475 } 476 return "%" + width + "d"; 477 }).get(); 478 479 AtomicInteger counter = new AtomicInteger(0); 480 Iterator<String> actualIt = actual.iterator(); 481 expected.stream().sequential().filter(expectedStr -> actualIt.hasNext()).forEach(expectedStr -> { 482 int idx = counter.incrementAndGet(); 483 String actualStr = actualIt.next(); 484 485 if ((actualStr != null && !actualStr.equals(expectedStr)) 486 || (expectedStr != null && !expectedStr.equals(actualStr))) { 487 error(concatMessages(String.format( 488 "(" + idxFieldFormat + ") Expected [%s]. Actual [%s]", 489 idx, expectedStr, actualStr), msg)); 490 } 491 492 traceAssert(String.format( 493 "assertStringListEquals(" + idxFieldFormat + ", %s)", idx, 494 expectedStr)); 495 }); 496 } 497 498 private static PrintStream openLogStream() { 499 if (LOG_FILE == null) { 500 return null; 501 } 502 503 try { 504 return new PrintStream(new FileOutputStream(LOG_FILE.toFile(), true)); 505 } catch (FileNotFoundException ex) { 506 throw new RuntimeException(ex); 507 } 508 } 509 510 private static Instance currentTest; 511 512 private static final boolean TRACE; 513 private static final boolean TRACE_ASSERTS; 514 515 static final boolean VERBOSE_JPACKAGE; 516 517 static String getConfigProperty(String propertyName) { 518 return System.getProperty(getConfigPropertyName(propertyName)); 519 } 520 521 static String getConfigPropertyName(String propertyName) { 522 return "jpackage.test." + propertyName; 523 } 524 525 static final Path LOG_FILE = Functional.identity(() -> { 526 String val = getConfigProperty("logfile"); 527 if (val == null) { 528 return null; 529 } 530 return Path.of(val); 531 }).get(); 532 533 static { 534 String val = getConfigProperty("suppress-logging"); 535 if (val == null) { 536 TRACE = true; 537 TRACE_ASSERTS = true; 538 VERBOSE_JPACKAGE = true; 539 } else if ("all".equals(val.toLowerCase())) { 540 TRACE = false; 541 TRACE_ASSERTS = false; 542 VERBOSE_JPACKAGE = false; 543 } else { 544 Set<String> logOptions = Set.of(val.toLowerCase().split(",")); 545 TRACE = !(logOptions.contains("trace") || logOptions.contains("t")); 546 TRACE_ASSERTS = !(logOptions.contains("assert") || logOptions.contains( 547 "a")); 548 VERBOSE_JPACKAGE = !(logOptions.contains("jpackage") || logOptions.contains( 549 "jp")); 550 } 551 } |