test/jdk/tools/jpackage/share/jdk/jpackage/tests/MainClassTest.java
branchJDK-8200758-branch
changeset 58696 61c44899b4eb
parent 58695 64adf683bc7b
child 58762 0fe62353385b
equal deleted inserted replaced
58695:64adf683bc7b 58696:61c44899b4eb
    51  * @modules jdk.jpackage/jdk.jpackage.internal
    51  * @modules jdk.jpackage/jdk.jpackage.internal
    52  * @compile MainClassTest.java
    52  * @compile MainClassTest.java
    53  * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
    53  * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
    54  *  --jpt-run=jdk.jpackage.tests.MainClassTest
    54  *  --jpt-run=jdk.jpackage.tests.MainClassTest
    55  *  --jpt-space-subst=_
    55  *  --jpt-space-subst=_
    56  *  --jpt-exclude=modular=y;_main-class=n;_jar-main-class=b;_jlink=y
       
    57  */
    56  */
    58 
    57 
    59 public final class MainClassTest {
    58 public final class MainClassTest {
    60 
    59 
    61     static final class Script {
    60     static final class Script {
    62         Script() {
    61         Script() {
    63             appDesc = JavaAppDesc.parse("test.Hello");
    62             appDesc = JavaAppDesc.parse("test.Hello");
    64         }
    63         }
    65 
    64 
    66         Script modular(boolean v) {
    65         Script modular(boolean v) {
    67             appDesc.setModuleName(v ? null : "com.other");
    66             appDesc.setModuleName(v ? "com.other" : null);
    68             return this;
    67             return this;
    69         }
    68         }
    70 
    69 
    71         Script withJLink(boolean v) {
    70         Script withJLink(boolean v) {
    72             withJLink = v;
    71             withJLink = v;
   136 
   135 
   137         nonExistingMainClass = Stream.of(
   136         nonExistingMainClass = Stream.of(
   138                 script.appDesc.packageName(), "ThereIsNoSuchClass").filter(
   137                 script.appDesc.packageName(), "ThereIsNoSuchClass").filter(
   139                 Objects::nonNull).collect(Collectors.joining("."));
   138                 Objects::nonNull).collect(Collectors.joining("."));
   140 
   139 
   141         cmd = JPackageCommand.helloAppImage(script.appDesc);
   140         cmd = JPackageCommand
       
   141                 .helloAppImage(script.appDesc)
       
   142                 .ignoreDefaultRuntime(true);
   142         if (!script.withJLink) {
   143         if (!script.withJLink) {
   143             cmd.setFakeRuntime();
   144             cmd.addArguments("--runtime-image", Path.of(System.getProperty(
       
   145                     "java.home")));
   144         }
   146         }
   145 
   147 
   146         final String moduleName = script.appDesc.moduleName();
   148         final String moduleName = script.appDesc.moduleName();
   147         switch (script.mainClass) {
   149         switch (script.mainClass) {
   148             case NotSet:
   150             case NotSet:
   171         List<Script[]> scripts = new ArrayList<>();
   173         List<Script[]> scripts = new ArrayList<>();
   172         for (var withJLink : List.of(true, false)) {
   174         for (var withJLink : List.of(true, false)) {
   173             for (var modular : List.of(true, false)) {
   175             for (var modular : List.of(true, false)) {
   174                 for (var mainClass : Script.MainClassType.values()) {
   176                 for (var mainClass : Script.MainClassType.values()) {
   175                     for (var jarMainClass : Script.MainClassType.values()) {
   177                     for (var jarMainClass : Script.MainClassType.values()) {
   176                         if (!withJLink && (jarMainClass == SetWrong || mainClass
       
   177                                 == SetWrong)) {
       
   178                             // Without runtime can't run app to verify it will fail, so
       
   179                             // there is no point in such testing.
       
   180                             continue;
       
   181                         }
       
   182 
       
   183                         Script script = new Script()
   178                         Script script = new Script()
   184                             .modular(modular)
   179                             .modular(modular)
   185                             .withJLink(withJLink)
   180                             .withJLink(withJLink)
   186                             .withMainClass(mainClass)
   181                             .withMainClass(mainClass)
   187                             .withJarMainClass(jarMainClass);
   182                             .withJarMainClass(jarMainClass);
   188 
   183 
   189                         if (withMainClass.contains(jarMainClass)
   184                         if (withMainClass.contains(jarMainClass)
   190                                 || withMainClass.contains(mainClass)) {
   185                                 || withMainClass.contains(mainClass)) {
   191                         } else if (modular) {
   186                         } else if (modular) {
   192                             script.expectedErrorMessage(
   187                             script.expectedErrorMessage(
   193                                     "A main class was not specified nor was one found in the jar");
   188                                     "Error: Main application class is missing");
   194                         } else {
   189                         } else {
   195                             script.expectedErrorMessage(
   190                             script.expectedErrorMessage(
   196                                     "Error: Main application class is missing");
   191                                     "A main class was not specified nor was one found in the jar");
   197                         }
   192                         }
   198 
   193 
   199                         scripts.add(new Script[]{script});
   194                         scripts.add(new Script[]{script});
   200                     }
   195                     }
   201                 }
   196                 }
   248                         nonExistingMainClass)).apply(output.stream());
   243                         nonExistingMainClass)).apply(output.stream());
   249             }
   244             }
   250         }
   245         }
   251     }
   246     }
   252 
   247 
   253     private void initJarWithWrongMainClass() {
   248     private void initJarWithWrongMainClass() throws IOException {
   254         // Call JPackageCommand.executePrerequisiteActions() to build app's jar.
   249         // Call JPackageCommand.executePrerequisiteActions() to build app's jar.
   255         // executePrerequisiteActions() is called by JPackageCommand instance
   250         // executePrerequisiteActions() is called by JPackageCommand instance
   256         // only once.
   251         // only once.
   257         cmd.executePrerequisiteActions();
   252         cmd.executePrerequisiteActions();
   258 
   253 
   259         Path jarFile;
   254         final Path jarFile;
   260         if (script.appDesc.moduleName() != null) {
   255         if (script.appDesc.moduleName() != null) {
   261             jarFile = Path.of(cmd.getArgumentValue("--module-path"),
   256             jarFile = Path.of(cmd.getArgumentValue("--module-path"),
   262                     script.appDesc.jarFileName());
   257                     script.appDesc.jarFileName());
   263         } else {
   258         } else {
   264             jarFile = cmd.inputDir().resolve(cmd.getArgumentValue("--main-jar"));
   259             jarFile = cmd.inputDir().resolve(cmd.getArgumentValue("--main-jar"));
   265         }
   260         }
   266 
   261 
   267         // Create jar file with the main class attribute in manifest set to
   262         // Create new jar file filtering out main class from the old jar file.
   268         // non-existing class.
       
   269         TKit.withTempDirectory("repack-jar", workDir -> {
   263         TKit.withTempDirectory("repack-jar", workDir -> {
   270             Path manifestFile = workDir.resolve("META-INF/MANIFEST.MF");
   264             // Extract app's class from the old jar.
   271             try (var jar = new JarFile(jarFile.toFile())) {
   265             explodeJar(jarFile, workDir,
   272                 jar.stream()
   266                     jarEntry -> Path.of(jarEntry.getName()).equals(
   273                 .filter(Predicate.not(JarEntry::isDirectory))
   267                             script.appDesc.classFilePath()));
   274                 .sequential().forEachOrdered(ThrowingConsumer.toConsumer(
   268 
   275                     jarEntry -> {
   269             // Create app's jar file with different main class.
   276                         try (var in = jar.getInputStream(jarEntry)) {
   270             var badAppDesc = JavaAppDesc.parse(script.appDesc.toString()).setClassName(
   277                             Path fileName = workDir.resolve(jarEntry.getName());
   271                     nonExistingMainClass);
   278                             Files.createDirectories(fileName.getParent());
   272             JPackageCommand.helloAppImage(badAppDesc).executePrerequisiteActions();
   279                             Files.copy(in, fileName);
   273 
   280                         }
   274             // Extract new jar but skip app's class.
   281                     }));
   275             explodeJar(jarFile, workDir,
   282             }
   276                     jarEntry -> !Path.of(jarEntry.getName()).equals(
       
   277                             badAppDesc.classFilePath()));
       
   278 
       
   279             // At this point we should have:
       
   280             // 1. Manifest from the new jar referencing non-existing class
       
   281             //  as the main class.
       
   282             // 2. Module descriptor referencing non-existing class as the main
       
   283             //  class in case of modular app.
       
   284             // 3. App's class from the old jar. We need it to let jlink find some
       
   285             //  classes in the package declared in module descriptor
       
   286             //  in case of modular app.
   283 
   287 
   284             Files.delete(jarFile);
   288             Files.delete(jarFile);
   285 
       
   286             // Adjust manifest.
       
   287             TKit.createTextFile(manifestFile, Files.readAllLines(
       
   288                     manifestFile).stream().map(line -> line.replace(
       
   289                     script.appDesc.className(), nonExistingMainClass)));
       
   290 
       
   291             new Executor().setToolProvider(JavaTool.JAR)
   289             new Executor().setToolProvider(JavaTool.JAR)
   292             .addArguments("-c", "-M", "-f", jarFile.toString())
   290             .addArguments("-v", "-c", "-M", "-f", jarFile.toString())
   293             .addArguments("-C", workDir.toString(), ".")
   291             .addArguments("-C", workDir.toString(), ".")
       
   292             .dumpOutput()
   294             .execute().assertExitCodeIsZero();
   293             .execute().assertExitCodeIsZero();
   295         });
   294         });
       
   295     }
       
   296 
       
   297     private static void explodeJar(Path jarFile, Path workDir,
       
   298             Predicate<JarEntry> filter) throws IOException {
       
   299         try (var jar = new JarFile(jarFile.toFile())) {
       
   300             jar.stream()
       
   301             .filter(Predicate.not(JarEntry::isDirectory))
       
   302             .filter(filter)
       
   303             .sequential().forEachOrdered(ThrowingConsumer.toConsumer(
       
   304                 jarEntry -> {
       
   305                     try (var in = jar.getInputStream(jarEntry)) {
       
   306                         Path fileName = workDir.resolve(jarEntry.getName());
       
   307                         Files.createDirectories(fileName.getParent());
       
   308                         Files.copy(in, fileName);
       
   309                     }
       
   310                 }));
       
   311         }
   296     }
   312     }
   297 
   313 
   298     private final JPackageCommand cmd;
   314     private final JPackageCommand cmd;
   299     private final Script script;
   315     private final Script script;
   300     private final String nonExistingMainClass;
   316     private final String nonExistingMainClass;