1 /* 2 * Copyright (c) 2019, 2020, 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 jdk.jpackage.tests; 25 26 import java.io.IOException; 27 import java.nio.file.Files; 28 import java.nio.file.Path; 29 import java.util.List; 30 import java.util.ArrayList; 31 import java.util.function.Function; 32 import java.util.function.Predicate; 33 import java.util.function.Supplier; 34 import java.util.regex.Pattern; 35 import java.util.stream.Stream; 36 import jdk.jpackage.test.TKit; 37 import jdk.jpackage.test.JPackageCommand; 38 import jdk.jpackage.test.JavaAppDesc; 39 import jdk.jpackage.test.PackageTest; 40 import jdk.jpackage.test.HelloApp; 41 import jdk.jpackage.test.Executor; 42 import jdk.jpackage.test.JavaTool; 43 import jdk.jpackage.test.Annotations.Test; 44 import jdk.jpackage.test.Annotations.Parameter; 45 46 /* 47 * @test 48 * @summary jpackage basic testing 49 * @library ../../../../helpers 50 * @build jdk.jpackage.test.* 51 * @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal 52 * @compile BasicTest.java 53 * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main 54 * --jpt-run=jdk.jpackage.tests.BasicTest 55 */ 56 57 public final class BasicTest { 58 @Test 59 public void testNoArgs() { 60 List<String> output = 61 getJPackageToolProvider().executeAndGetOutput(); 62 TKit.assertStringListEquals(List.of("Usage: jpackage <options>", 63 "Use jpackage --help (or -h) for a list of possible options"), 64 output, "Check jpackage output"); 65 } 66 67 @Test 68 public void testJpackageProps() { 69 String appVersion = "3.0"; 70 JPackageCommand cmd = JPackageCommand.helloAppImage( 71 JavaAppDesc.parse("com.hello/com.hello.Hello")) 72 // Disable default logic adding `--verbose` option 73 // to jpackage command line. 74 .ignoreDefaultVerbose(true) 75 .saveConsoleOutput(true) 76 .addArguments("--app-version", appVersion, "--arguments", 77 "jpackage.app-version jpackage.app-path"); 78 79 cmd.executeAndAssertImageCreated(); 80 81 Path launcherPath = cmd.appLauncherPath(); 82 if (!cmd.isFakeRuntime(String.format( 83 "Not running [%s] launcher", launcherPath))) { 84 List<String> output = HelloApp.executeLauncher(cmd).getOutput(); 85 86 TKit.assertTextStream("jpackage.app-version=" + appVersion) 87 .apply(output.stream()); 88 TKit.assertTextStream("jpackage.app-path=") 89 .apply(output.stream()); 90 } 91 } 92 93 @Test 94 public void testVersion() { 95 List<String> output = 96 getJPackageToolProvider() 97 .addArgument("--version") 98 .executeAndGetOutput(); 99 TKit.assertStringListEquals(List.of(System.getProperty("java.version")), 100 output, "Check jpackage output"); 101 } 102 103 @Test 104 public void testHelp() { 105 List<String> hOutput = getJPackageToolProvider() 106 .addArgument("-h").executeAndGetOutput(); 107 List<String> helpOutput = getJPackageToolProvider() 108 .addArgument("--help").executeAndGetOutput(); 109 110 TKit.assertStringListEquals(hOutput, helpOutput, 111 "Check -h and --help parameters produce the same output"); 112 113 final String windowsPrefix = "--win-"; 114 final String linuxPrefix = "--linux-"; 115 final String osxPrefix = "--mac-"; 116 117 final String expectedPrefix; 118 final List<String> unexpectedPrefixes; 119 120 if (TKit.isWindows()) { 121 expectedPrefix = windowsPrefix; 122 unexpectedPrefixes = List.of(osxPrefix, linuxPrefix); 123 } else if (TKit.isLinux()) { 124 expectedPrefix = linuxPrefix; 125 unexpectedPrefixes = List.of(windowsPrefix, osxPrefix); 126 } else if (TKit.isOSX()) { 127 expectedPrefix = osxPrefix; 128 unexpectedPrefixes = List.of(linuxPrefix, windowsPrefix); 129 } else { 130 throw TKit.throwUnknownPlatformError(); 131 } 132 133 Function<String, Predicate<String>> createPattern = (prefix) -> { 134 return Pattern.compile("^ " + prefix).asPredicate(); 135 }; 136 137 Function<List<String>, Long> countStrings = (prefixes) -> { 138 return hOutput.stream().filter( 139 prefixes.stream().map(createPattern).reduce(x -> false, 140 Predicate::or)).peek(TKit::trace).count(); 141 }; 142 143 TKit.trace("Check parameters in help text"); 144 TKit.assertNotEquals(0, countStrings.apply(List.of(expectedPrefix)), 145 "Check help text contains plaform specific parameters"); 146 TKit.assertEquals(0, countStrings.apply(unexpectedPrefixes), 147 "Check help text doesn't contain unexpected parameters"); 148 } 149 150 @Test 151 @SuppressWarnings("unchecked") 152 public void testVerbose() { 153 JPackageCommand cmd = JPackageCommand.helloAppImage() 154 // Disable default logic adding `--verbose` option 155 // to jpackage command line. 156 .ignoreDefaultVerbose(true) 157 .saveConsoleOutput(true) 158 .setFakeRuntime().executePrerequisiteActions(); 159 160 List<String> expectedVerboseOutputStrings = new ArrayList<>(); 161 expectedVerboseOutputStrings.add("Creating app package:"); 162 if (TKit.isWindows()) { 163 expectedVerboseOutputStrings.add( 164 "Succeeded in building Windows Application Image package"); 165 } else if (TKit.isLinux()) { 166 expectedVerboseOutputStrings.add( 167 "Succeeded in building Linux Application Image package"); 168 } else if (TKit.isOSX()) { 169 expectedVerboseOutputStrings.add("Preparing Info.plist:"); 170 expectedVerboseOutputStrings.add( 171 "Succeeded in building Mac Application Image package"); 172 } else { 173 TKit.throwUnknownPlatformError(); 174 } 175 176 TKit.deleteDirectoryContentsRecursive(cmd.outputDir()); 177 List<String> nonVerboseOutput = cmd.execute().getOutput(); 178 List<String>[] verboseOutput = (List<String>[])new List<?>[1]; 179 180 // Directory clean up is not 100% reliable on Windows because of 181 // antivirus software that can lock .exe files. Setup 182 // different output directory instead of cleaning the default one for 183 // verbose jpackage run. 184 TKit.withTempDirectory("verbose-output", tempDir -> { 185 cmd.setArgumentValue("--dest", tempDir); 186 cmd.addArgument("--verbose"); 187 verboseOutput[0] = cmd.execute().getOutput(); 188 }); 189 190 TKit.assertTrue(nonVerboseOutput.size() < verboseOutput[0].size(), 191 "Check verbose output is longer than regular"); 192 193 expectedVerboseOutputStrings.forEach(str -> { 194 TKit.assertTextStream(str).label("regular output") 195 .predicate(String::contains).negate() 196 .apply(nonVerboseOutput.stream()); 197 }); 198 199 expectedVerboseOutputStrings.forEach(str -> { 200 TKit.assertTextStream(str).label("verbose output") 201 .apply(verboseOutput[0].stream()); 202 }); 203 } 204 205 @Test 206 public void testNoName() { 207 final String mainClassName = "Greetings"; 208 209 JPackageCommand cmd = JPackageCommand.helloAppImage(mainClassName) 210 .removeArgumentWithValue("--name"); 211 212 Path expectedImageDir = cmd.outputDir().resolve(mainClassName); 213 if (TKit.isOSX()) { 214 expectedImageDir = expectedImageDir.getParent().resolve( 215 expectedImageDir.getFileName().toString() + ".app"); 216 } 217 218 cmd.executeAndAssertHelloAppImageCreated(); 219 TKit.assertEquals(expectedImageDir.toAbsolutePath().normalize().toString(), 220 cmd.outputBundle().toAbsolutePath().normalize().toString(), 221 String.format( 222 "Check [%s] directory is filled with application image data", 223 expectedImageDir)); 224 } 225 226 @Test 227 // Regular app 228 @Parameter("Hello") 229 // Modular app in .jar file 230 @Parameter("com.other/com.other.Hello") 231 // Modular app in .jmod file 232 @Parameter("hello.jmod:com.other/com.other.Hello") 233 public void testApp(String javaAppDesc) { 234 JavaAppDesc appDesc = JavaAppDesc.parse(javaAppDesc); 235 JPackageCommand cmd = JPackageCommand.helloAppImage(appDesc); 236 if (appDesc.jmodFileName() != null) { 237 // .jmod files are not supported at run-time. They should be 238 // bundled in Java run-time with jlink command, so disable 239 // use of external Java run-time if any configured. 240 cmd.ignoreDefaultRuntime(true); 241 } 242 cmd.executeAndAssertHelloAppImageCreated(); 243 } 244 245 @Test 246 public void testWhitespaceInPaths() { 247 JPackageCommand.helloAppImage("a/b c.jar:Hello") 248 .setArgumentValue("--input", TKit.workDir().resolve("The quick brown fox")) 249 .setArgumentValue("--dest", TKit.workDir().resolve("jumps over the lazy dog")) 250 .executeAndAssertHelloAppImageCreated(); 251 } 252 253 @Test 254 @Parameter("ALL-MODULE-PATH") 255 @Parameter("ALL-DEFAULT") 256 @Parameter("java.desktop") 257 @Parameter("java.desktop,jdk.jartool") 258 @Parameter({ "java.desktop", "jdk.jartool" }) 259 public void testAddModules(String... addModulesArg) { 260 JPackageCommand cmd = JPackageCommand 261 .helloAppImage("goodbye.jar:com.other/com.other.Hello") 262 .ignoreDefaultRuntime(true); // because of --add-modules 263 Stream.of(addModulesArg).map(v -> Stream.of("--add-modules", v)).flatMap( 264 s -> s).forEachOrdered(cmd::addArgument); 265 cmd.executeAndAssertHelloAppImageCreated(); 266 } 267 268 /** 269 * Test --temp option. Doesn't make much sense for app image as temporary 270 * directory is used only on Windows. Test it in packaging mode. 271 * @throws IOException 272 */ 273 @Test 274 @Parameter("true") 275 @Parameter("false") 276 public void testTemp(boolean withExistingTempDir) throws IOException { 277 final Path tempRoot = TKit.createTempDirectory("tmp"); 278 // This Test has problems on windows where path in the temp dir are too long 279 // for the wix tools. We can't use a tempDir outside the TKit's WorkDir, so 280 // we minimize both the tempRoot directory name (above) and the tempDir name 281 // (below) to the extension part (which is necessary to differenciate between 282 // the multiple PackageTypes that will be run for one JPackageCommand). 283 // It might be beter if the whole work dir name was shortened from: 284 // jtreg_open_test_jdk_tools_jpackage_share_jdk_jpackage_tests_BasicTest_java. 285 Function<JPackageCommand, Path> getTempDir = cmd -> { 286 String ext = cmd.outputBundle().getFileName().toString(); 287 int i = ext.lastIndexOf("."); 288 if (i > 0 && i < (ext.length() - 1)) { 289 ext = ext.substring(i+1); 290 } 291 return tempRoot.resolve(ext); 292 }; 293 294 Supplier<PackageTest> createTest = () -> { 295 return new PackageTest() 296 .configureHelloApp() 297 // Force save of package bundle in test work directory. 298 .addInitializer(JPackageCommand::setDefaultInputOutput) 299 .addInitializer(cmd -> { 300 Path tempDir = getTempDir.apply(cmd); 301 if (withExistingTempDir) { 302 Files.createDirectories(tempDir); 303 } else { 304 Files.createDirectories(tempDir.getParent()); 305 } 306 cmd.addArguments("--temp", tempDir); 307 }); 308 }; 309 310 createTest.get() 311 .addBundleVerifier(cmd -> { 312 // Check jpackage actually used the supplied directory. 313 Path tempDir = getTempDir.apply(cmd); 314 TKit.assertNotEquals(0, tempDir.toFile().list().length, 315 String.format( 316 "Check jpackage wrote some data in the supplied temporary directory [%s]", 317 tempDir)); 318 }) 319 .run(PackageTest.Action.CREATE); 320 321 createTest.get() 322 // Temporary directory should not be empty, 323 // jpackage should exit with error. 324 .setExpectedExitCode(1) 325 .run(PackageTest.Action.CREATE); 326 } 327 328 @Test 329 public void testAtFile() throws IOException { 330 JPackageCommand cmd = JPackageCommand 331 .helloAppImage() 332 .setArgumentValue("--dest", TKit.createTempDirectory("output")); 333 334 // Init options file with the list of options configured 335 // for JPackageCommand instance. 336 final Path optionsFile = TKit.createTempFile(Path.of("options")); 337 Files.write(optionsFile, 338 List.of(String.join(" ", cmd.getAllArguments()))); 339 340 // Build app jar file. 341 cmd.executePrerequisiteActions(); 342 343 // Instead of running jpackage command through configured 344 // JPackageCommand instance, run vanilla jpackage command with @ file. 345 getJPackageToolProvider() 346 .addArgument(String.format("@%s", optionsFile)) 347 .execute(); 348 349 // Verify output of jpackage command. 350 cmd.assertImageCreated(); 351 HelloApp.executeLauncherAndVerifyOutput(cmd); 352 } 353 354 private static Executor getJPackageToolProvider() { 355 return getToolProvider(JavaTool.JPACKAGE); 356 } 357 358 private static Executor getToolProvider(JavaTool tool) { 359 return new Executor().dumpOutput().saveOutput().setToolProvider(tool); 360 } 361 }