diff --git a/test/jdk/tools/jpackage/apps/Hello.java b/test/jdk/tools/jpackage/apps/Hello.java index dd6f114a421..000573c933f 100644 --- a/test/jdk/tools/jpackage/apps/Hello.java +++ b/test/jdk/tools/jpackage/apps/Hello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.util.List; import java.util.ArrayList; import java.util.stream.Stream; import java.util.Collections; +import java.util.Optional; public class Hello implements OpenFilesHandler { @@ -60,6 +61,15 @@ public class Hello implements OpenFilesHandler { var outputFile = getOutputFile(args); trace(String.format("Output file: [%s]", outputFile)); Files.write(outputFile, lines); + + if (Optional.ofNullable(System.getProperty("jpackage.test.noexit")).map( + Boolean::parseBoolean).orElse(false)) { + trace("noexit"); + var lock = new Object(); + synchronized (lock) { + lock.wait(); + } + } } private static List printArgs(String[] args) { @@ -87,7 +97,8 @@ public class Hello implements OpenFilesHandler { } private static Path getOutputFile(String[] args) { - Path outputFilePath = Path.of("appOutput.txt"); + Path outputFilePath = Path.of(Optional.ofNullable(System.getProperty( + "jpackage.test.appOutput")).orElse("appOutput.txt")); // If first arg is a file (most likely from fa), then put output in the same folder as // the file from fa. @@ -101,7 +112,7 @@ public class Hello implements OpenFilesHandler { try { // Try writing in the default output file. Files.write(outputFilePath, Collections.emptyList()); - return outputFilePath; + return outputFilePath.toAbsolutePath(); } catch (IOException ex) { // Log reason of a failure. StringWriter errors = new StringWriter(); @@ -109,7 +120,7 @@ public class Hello implements OpenFilesHandler { Stream.of(errors.toString().split("\\R")).forEachOrdered(Hello::trace); } - return Path.of(System.getProperty("user.home")).resolve(outputFilePath); + return Path.of(System.getProperty("user.home")).resolve(outputFilePath).toAbsolutePath(); } @Override diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java index 10033db4802..44d75d98ec9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/AdditionalLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,13 +29,17 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import static jdk.jpackage.test.Functional.ThrowingFunction.toFunction; -public final class AdditionalLauncher { +public class AdditionalLauncher { public AdditionalLauncher(String name) { this.name = name; @@ -43,12 +47,12 @@ public final class AdditionalLauncher { setPersistenceHandler(null); } - public AdditionalLauncher setDefaultArguments(String... v) { + final public AdditionalLauncher setDefaultArguments(String... v) { defaultArguments = new ArrayList<>(List.of(v)); return this; } - public AdditionalLauncher addDefaultArguments(String... v) { + final public AdditionalLauncher addDefaultArguments(String... v) { if (defaultArguments == null) { return setDefaultArguments(v); } @@ -57,12 +61,12 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher setJavaOptions(String... v) { + final public AdditionalLauncher setJavaOptions(String... v) { javaOptions = new ArrayList<>(List.of(v)); return this; } - public AdditionalLauncher addJavaOptions(String... v) { + final public AdditionalLauncher addJavaOptions(String... v) { if (javaOptions == null) { return setJavaOptions(v); } @@ -71,23 +75,24 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher addRawProperties(Map.Entry... v) { + final public AdditionalLauncher addRawProperties( + Map.Entry... v) { return addRawProperties(List.of(v)); } - public AdditionalLauncher addRawProperties( + final public AdditionalLauncher addRawProperties( Collection> v) { rawProperties.addAll(v); return this; } - public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { + final public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) { withMenuShortcut = menu; withShortcut = shortcut; return this; } - public AdditionalLauncher setIcon(Path iconPath) { + final public AdditionalLauncher setIcon(Path iconPath) { if (iconPath == NO_ICON) { throw new IllegalArgumentException(); } @@ -96,12 +101,12 @@ public final class AdditionalLauncher { return this; } - public AdditionalLauncher setNoIcon() { + final public AdditionalLauncher setNoIcon() { icon = NO_ICON; return this; } - public AdditionalLauncher setPersistenceHandler( + final public AdditionalLauncher setPersistenceHandler( ThrowingBiConsumer>> handler) { if (handler != null) { createFileHandler = ThrowingBiConsumer.toBiConsumer(handler); @@ -111,19 +116,53 @@ public final class AdditionalLauncher { return this; } - public void applyTo(JPackageCommand cmd) { + final public void applyTo(JPackageCommand cmd) { cmd.addPrerequisiteAction(this::initialize); cmd.addVerifyAction(this::verify); } - public void applyTo(PackageTest test) { - test.addLauncherName(name); + final public void applyTo(PackageTest test) { test.addInitializer(this::initialize); test.addInstallVerifier(this::verify); } + static void forEachAdditionalLauncher(JPackageCommand cmd, + BiConsumer consumer) { + var argIt = cmd.getAllArguments().iterator(); + while (argIt.hasNext()) { + if ("--add-launcher".equals(argIt.next())) { + // = + var arg = argIt.next(); + var items = arg.split("=", 2); + consumer.accept(items[0], Path.of(items[1])); + } + } + } + + static PropertyFile getAdditionalLauncherProperties( + JPackageCommand cmd, String launcherName) { + PropertyFile shell[] = new PropertyFile[1]; + forEachAdditionalLauncher(cmd, (name, propertiesFilePath) -> { + if (name.equals(launcherName)) { + shell[0] = toFunction(PropertyFile::new).apply( + propertiesFilePath); + } + }); + return Optional.of(shell[0]).get(); + } + private void initialize(JPackageCommand cmd) { - final Path propsFile = TKit.workDir().resolve(name + ".properties"); + Path propsFile = TKit.workDir().resolve(name + ".properties"); + if (Files.exists(propsFile)) { + // File with the given name exists, pick another name that + // will not reference existing file. + try { + propsFile = TKit.createTempFile(propsFile); + TKit.deleteIfExists(propsFile); + } catch (IOException ex) { + Functional.rethrowUnchecked(ex); + } + } cmd.addArguments("--add-launcher", String.format("%s=%s", name, propsFile)); @@ -242,7 +281,7 @@ public final class AdditionalLauncher { } } - private void verify(JPackageCommand cmd) throws IOException { + protected void verify(JPackageCommand cmd) throws IOException { verifyIcon(cmd); verifyShortcuts(cmd); @@ -255,14 +294,60 @@ public final class AdditionalLauncher { return; } - HelloApp.assertApp(launcherPath) - .addDefaultArguments(Optional - .ofNullable(defaultArguments) - .orElseGet(() -> List.of(cmd.getAllArgumentValues("--arguments")))) - .addJavaOptions(Optional - .ofNullable(javaOptions) - .orElseGet(() -> List.of(cmd.getAllArgumentValues("--java-options")))) - .executeAndVerifyOutput(); + var appVerifier = HelloApp.assertApp(launcherPath) + .addDefaultArguments(Optional + .ofNullable(defaultArguments) + .orElseGet(() -> List.of(cmd.getAllArgumentValues("--arguments")))) + .addJavaOptions(Optional + .ofNullable(javaOptions) + .orElseGet(() -> List.of(cmd.getAllArgumentValues( + "--java-options"))).stream().map( + str -> resolveVariables(cmd, str)).toList()); + + appVerifier.executeAndVerifyOutput(); + } + + public static final class PropertyFile { + + PropertyFile(Path path) throws IOException { + data = Files.readAllLines(path).stream().map(str -> { + return str.split("=", 2); + }).collect( + Collectors.toMap(tokens -> tokens[0], tokens -> tokens[1], + (oldValue, newValue) -> { + return newValue; + })); + } + + public boolean isPropertySet(String name) { + Objects.requireNonNull(name); + return data.containsKey(name); + } + + public Optional getPropertyValue(String name) { + Objects.requireNonNull(name); + return Optional.of(data.get(name)); + } + + public Optional getPropertyBooleanValue(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(data.get(name)).map(Boolean::parseBoolean); + } + + private final Map data; + } + + private static String resolveVariables(JPackageCommand cmd, String str) { + var map = Map.of( + "$APPDIR", cmd.appLayout().appDirectory(), + "$ROOTDIR", + cmd.isImagePackageType() ? cmd.outputBundle() : cmd.appInstallationDirectory(), + "$BINDIR", cmd.appLayout().launchersDirectory()); + for (var e : map.entrySet()) { + str = str.replaceAll(Pattern.quote(e.getKey()), + Matcher.quoteReplacement(e.getValue().toString())); + } + return str; } private List javaOptions; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java index e2a380366e8..31bf0520a31 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CfgFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -85,7 +86,8 @@ public final class CfgFile { } if (!currentSection.isEmpty()) { - result.put("", Collections.unmodifiableMap(currentSection)); + result.put(Optional.ofNullable(currentSectionName).orElse(""), + Collections.unmodifiableMap(currentSection)); } return new CfgFile(Collections.unmodifiableMap(result), path.toString()); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index d65fe4e667b..3fed83ddb36 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,8 +90,10 @@ public final class Executor extends CommandArguments { } public Executor setWindowsTmpDir(String tmp) { - TKit.assertTrue(TKit.isWindows(), - "setWindowsTmpDir is only valid on Windows platform"); + if (!TKit.isWindows()) { + throw new UnsupportedOperationException( + "setWindowsTmpDir is only valid on Windows platform"); + } winTmpDir = tmp; return this; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 71561a51cf3..2d0d23dae26 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -351,6 +351,7 @@ public final class HelloApp { public final static class AppOutputVerifier { AppOutputVerifier(Path helloAppLauncher) { this.launcherPath = helloAppLauncher; + this.outputFilePath = TKit.workDir().resolve(OUTPUT_FILENAME); this.params = new HashMap<>(); this.defaultLauncherArgs = new ArrayList<>(); } @@ -367,6 +368,8 @@ public final class HelloApp { public AppOutputVerifier addParam(String name, String value) { if (name.startsWith("param")) { params.put(name, value); + } else if ("jpackage.test.appOutput".equals(name)) { + outputFilePath = Path.of(value); } return this; } @@ -397,6 +400,18 @@ public final class HelloApp { .collect(Collectors.toList())); } + public void verifyOutput(String... args) { + final List launcherArgs = List.of(args); + final List appArgs; + if (launcherArgs.isEmpty()) { + appArgs = defaultLauncherArgs; + } else { + appArgs = launcherArgs; + } + + verifyOutputFile(outputFilePath, appArgs, params); + } + public void executeAndVerifyOutput(String... args) { executeAndVerifyOutput(false, args); } @@ -408,8 +423,7 @@ public final class HelloApp { getExecutor(launcherArgs.toArray(new String[0])).dumpOutput().setRemovePath( removePath).executeAndRepeatUntilExitCode(0, attempts, waitBetweenAttemptsSeconds); - Path outputFile = TKit.workDir().resolve(OUTPUT_FILENAME); - verifyOutputFile(outputFile, appArgs, params); + verifyOutputFile(outputFilePath, appArgs, params); } public void executeAndVerifyOutput(boolean removePath, String... args) { @@ -453,6 +467,7 @@ public final class HelloApp { } private final Path launcherPath; + private Path outputFilePath; private final List defaultLauncherArgs; private final Map params; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index b68fe08bd1e..d30f96ff786 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; +import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; import jdk.jpackage.test.Functional.ThrowingSupplier; @@ -242,6 +243,17 @@ public final class JPackageCommand extends CommandArguments { return this; } + public JPackageCommand setInputToEmptyDirectory() { + if (Files.exists(inputDir())) { + try { + setArgumentValue("--input", TKit.createTempDirectory("input")); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + return this; + } + public JPackageCommand setFakeRuntime() { verifyMutable(); @@ -414,6 +426,28 @@ public final class JPackageCommand extends CommandArguments { return unpackDir.resolve(TKit.removeRootFromAbsolutePath(path)); } + /** + * Returns path to package file from the path in unpacked package directory + * or the given path if the package is not unpacked. + */ + public Path pathToPackageFile(Path path) { + Path unpackDir = unpackedPackageDirectory(); + if (unpackDir == null) { + if (!path.isAbsolute()) { + throw new IllegalArgumentException(String.format( + "Path [%s] is not absolute", path)); + } + return path; + } + + if (!path.startsWith(unpackDir)) { + throw new IllegalArgumentException(String.format( + "Path [%s] doesn't start with [%s] path", path, unpackDir)); + } + + return Path.of("/").resolve(unpackDir.relativize(path)); + } + Path unpackedPackageDirectory() { verifyIsOfType(PackageType.NATIVE); return getArgumentValue(UNPACKED_PATH_ARGNAME, () -> null, Path::of); @@ -497,6 +531,18 @@ public final class JPackageCommand extends CommandArguments { return appLauncherPath(null); } + /** + * Returns names of all additional launchers or empty list if none + * configured. + */ + public List addLauncherNames() { + List names = new ArrayList<>(); + forEachAdditionalLauncher(this, (launcherName, propFile) -> { + names.add(launcherName); + }); + return names; + } + private void verifyNotRuntime() { if (isRuntime()) { throw new IllegalArgumentException("Java runtime packaging"); @@ -537,9 +583,9 @@ public final class JPackageCommand extends CommandArguments { throw TKit.throwUnknownPlatformError(); } - if (criticalRuntimeFiles.stream().filter( - v -> runtimeDir.resolve(v).toFile().exists()).findFirst().orElse( - null) == null) { + if (!criticalRuntimeFiles.stream().anyMatch(v -> { + return runtimeDir.resolve(v).toFile().exists(); + })) { // Fake runtime TKit.trace(String.format( "%s because application runtime directory [%s] is incomplete", @@ -738,7 +784,7 @@ public final class JPackageCommand extends CommandArguments { appImageFileName)); } } - } else if (TKit.isOSX()) { + } else if (TKit.isOSX() && !isRuntime()) { TKit.assertFileExists(AppImageFile.getPathInAppImage( appInstallationDirectory())); } else { @@ -763,7 +809,11 @@ public final class JPackageCommand extends CommandArguments { JPackageCommand setUnpackedPackageLocation(Path path) { verifyIsOfType(PackageType.NATIVE); - setArgumentValue(UNPACKED_PATH_ARGNAME, path); + if (path != null) { + setArgumentValue(UNPACKED_PATH_ARGNAME, path); + } else { + removeArgumentWithValue(UNPACKED_PATH_ARGNAME); + } return this; } @@ -788,6 +838,11 @@ public final class JPackageCommand extends CommandArguments { return createExecutor().getPrintableCommandLine(); } + @Override + public String toString() { + return getPrintableCommandLine(); + } + public void verifyIsOfType(Collection types) { verifyIsOfType(types.toArray(PackageType[]::new)); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java index de5a4e4d8e4..7b217b2431c 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public enum JavaTool { } } - Path getPath() { + public Path getPath() { return path; } @@ -48,7 +48,7 @@ public enum JavaTool { return ToolProvider.findFirst(toolName()).orElse(null); } - Path relativePathInJavaHome() { + private Path relativePathInJavaHome() { Path path = Path.of("bin", toolName()); if (TKit.isWindows()) { path = path.getParent().resolve(path.getFileName().toString() + ".exe"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 5b91b829457..4d096198c9d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,7 @@ import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.PackageTest.PackageHandlers; - -public class LinuxHelper { +public final class LinuxHelper { private static String getReleaseSuffix(JPackageCommand cmd) { String value = null; final PackageType packageType = cmd.packageType(); @@ -183,7 +182,10 @@ public class LinuxHelper { }; deb.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_DEB); - Executor.of("sudo", "dpkg", "-r", getPackageName(cmd)).execute(); + var packageName = getPackageName(cmd); + String script = String.format("! dpkg -s %s || sudo dpkg -r %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); }; deb.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.LINUX_DEB); @@ -200,13 +202,16 @@ public class LinuxHelper { PackageHandlers rpm = new PackageHandlers(); rpm.installHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-i") + Executor.of("sudo", "rpm", "-U") .addArgument(cmd.outputBundle()) .execute(); }; rpm.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); - Executor.of("sudo", "rpm", "-e", getPackageName(cmd)).execute(); + var packageName = getPackageName(cmd); + String script = String.format("! rpm -q %s || sudo rpm -e %s", + packageName, packageName); + Executor.of("sh", "-c", script).execute(); }; rpm.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.LINUX_RPM); @@ -363,10 +368,10 @@ public class LinuxHelper { test.addInstallVerifier(cmd -> { // Verify .desktop files. - try (var files = Files.walk(cmd.appLayout().destktopIntegrationDirectory(), 1)) { + try (var files = Files.list(cmd.appLayout().destktopIntegrationDirectory())) { List desktopFiles = files .filter(path -> path.getFileName().toString().endsWith(".desktop")) - .collect(Collectors.toList()); + .toList(); if (!integrated) { TKit.assertStringListEquals(List.of(), desktopFiles.stream().map(Path::toString).collect( @@ -470,23 +475,18 @@ public class LinuxHelper { String desktopFileName = queryMimeTypeDefaultHandler(mimeType); - Path desktopFile = getSystemDesktopFilesFolder().resolve( + Path systemDesktopFile = getSystemDesktopFilesFolder().resolve( + desktopFileName); + Path appDesktopFile = cmd.appLayout().destktopIntegrationDirectory().resolve( desktopFileName); - TKit.assertFileExists(desktopFile); - - TKit.trace(String.format("Reading [%s] file...", desktopFile)); - String mimeHandler = Files.readAllLines(desktopFile).stream().peek( - v -> TKit.trace(v)).filter( - v -> v.startsWith("Exec=")).map( - v -> v.split("=", 2)[1]).findFirst().orElseThrow(); - - TKit.trace(String.format("Done")); - - TKit.assertEquals(cmd.appLauncherPath().toString(), - mimeHandler, String.format( - "Check mime type handler is the main application launcher")); + TKit.assertFileExists(systemDesktopFile); + TKit.assertFileExists(appDesktopFile); + TKit.assertStringListEquals(Files.readAllLines(appDesktopFile), + Files.readAllLines(systemDesktopFile), String.format( + "Check [%s] file is a copy of [%s] file", + systemDesktopFile, appDesktopFile)); }); }); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 9b6457ccc58..7f5887f0ac3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.IOUtils; import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingSupplier; import jdk.jpackage.test.PackageTest.PackageHandlers; @@ -46,7 +47,7 @@ import jdk.jpackage.internal.RetryExecutor; import org.xml.sax.SAXException; import org.w3c.dom.NodeList; -public class MacHelper { +public final class MacHelper { public static void withExplodedDmg(JPackageCommand cmd, ThrowingConsumer consumer) { @@ -172,41 +173,62 @@ public class MacHelper { pkg.installHandler = cmd -> { cmd.verifyIsOfType(PackageType.MAC_PKG); Executor.of("sudo", "/usr/sbin/installer", "-allowUntrusted", "-pkg") - .addArgument(cmd.outputBundle()) - .addArguments("-target", "/") - .execute(); + .addArgument(cmd.outputBundle()) + .addArguments("-target", "/") + .execute(); }; pkg.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.MAC_PKG); + + var dataDir = destinationDir.resolve("data"); + Executor.of("pkgutil", "--expand") - .addArgument(cmd.outputBundle()) - .addArgument(destinationDir.resolve("data")) // We need non-existing folder - .execute(); + .addArgument(cmd.outputBundle()) + .addArgument(dataDir) // We need non-existing folder + .execute(); final Path unpackRoot = destinationDir.resolve("unpacked"); - Path installDir = TKit.removeRootFromAbsolutePath( - getInstallationDirectory(cmd)).getParent(); - final Path unpackDir = unpackRoot.resolve(installDir); - try { - Files.createDirectories(unpackDir); + // Unpack all ".pkg" files from $dataDir folder in $unpackDir folder + try (var dataListing = Files.list(dataDir)) { + dataListing.filter(file -> { + return ".pkg".equals(IOUtils.getSuffix(file.getFileName())); + }).forEach(ThrowingConsumer.toConsumer(pkgDir -> { + // Installation root of the package is stored in + // /pkg-info@install-location attribute in $pkgDir/PackageInfo xml file + var doc = createDocumentBuilder().parse( + new ByteArrayInputStream(Files.readAllBytes( + pkgDir.resolve("PackageInfo")))); + var xPath = XPathFactory.newInstance().newXPath(); + + final String installRoot = (String) xPath.evaluate( + "/pkg-info/@install-location", doc, + XPathConstants.STRING); + + final Path unpackDir = unpackRoot.resolve( + TKit.removeRootFromAbsolutePath(Path.of(installRoot))); + + Files.createDirectories(unpackDir); + + Executor.of("tar", "-C") + .addArgument(unpackDir) + .addArgument("-xvf") + .addArgument(pkgDir.resolve("Payload")) + .execute(); + })); } catch (IOException ex) { throw new RuntimeException(ex); } - Executor.of("tar", "-C") - .addArgument(unpackDir) - .addArgument("-xvf") - .addArgument(Path.of(destinationDir.toString(), "data", - cmd.name() + "-app.pkg", "Payload")) - .execute(); return unpackRoot; }; pkg.uninstallHandler = cmd -> { cmd.verifyIsOfType(PackageType.MAC_PKG); + Executor.of("sudo", "rm", "-rf") - .addArgument(cmd.appInstallationDirectory()) - .execute(); + .addArgument(cmd.appInstallationDirectory()) + .execute(); + }; return pkg; @@ -220,13 +242,13 @@ public class MacHelper { static Path getInstallationDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.MAC); - return Path.of(cmd.getArgumentValue("--install-dir", () -> "/Applications")) - .resolve(cmd.name() + (cmd.isRuntime() ? "" : ".app")); + return Path.of(cmd.getArgumentValue("--install-dir", + () -> cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications")).resolve( + cmd.name() + (cmd.isRuntime() ? "" : ".app")); } private static String getPackageName(JPackageCommand cmd) { - return cmd.getArgumentValue("--mac-package-name", - () -> cmd.installerName()); + return cmd.getArgumentValue("--mac-package-name", cmd::installerName); } public static final class PListWrapper { @@ -274,25 +296,24 @@ public class MacHelper { return values; } - PListWrapper(String xml) throws ParserConfigurationException, + private PListWrapper(String xml) throws ParserConfigurationException, SAXException, IOException { doc = createDocumentBuilder().parse(new ByteArrayInputStream( xml.getBytes(StandardCharsets.UTF_8))); } - private static DocumentBuilder createDocumentBuilder() throws - ParserConfigurationException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - return dbf.newDocumentBuilder(); - } - private final org.w3c.dom.Document doc; } + private static DocumentBuilder createDocumentBuilder() throws + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + dbf.setFeature( + "http://apache.org/xml/features/nonvalidating/load-external-dtd", + false); + return dbf.newDocumentBuilder(); + } + static final Set CRITICAL_RUNTIME_FILES = Set.of(Path.of( "Contents/Home/lib/server/libjvm.dylib")); - } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index f81fb1c170c..0884b41dc55 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package jdk.jpackage.test; import java.awt.Desktop; import java.awt.GraphicsEnvironment; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -36,19 +37,32 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile; import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.Functional.ThrowingBiConsumer; +import static jdk.jpackage.test.Functional.ThrowingBiConsumer.toBiConsumer; import jdk.jpackage.test.Functional.ThrowingConsumer; +import static jdk.jpackage.test.Functional.ThrowingConsumer.toConsumer; import jdk.jpackage.test.Functional.ThrowingRunnable; - +import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; +import static jdk.jpackage.test.Functional.rethrowUnchecked; +import static jdk.jpackage.test.PackageType.LINUX; +import static jdk.jpackage.test.PackageType.LINUX_DEB; +import static jdk.jpackage.test.PackageType.LINUX_RPM; +import static jdk.jpackage.test.PackageType.MAC_DMG; +import static jdk.jpackage.test.PackageType.MAC_PKG; +import static jdk.jpackage.test.PackageType.NATIVE; +import static jdk.jpackage.test.PackageType.WINDOWS; +import static jdk.jpackage.test.PackageType.WIN_EXE; +import static jdk.jpackage.test.PackageType.WIN_MSI; /** @@ -82,7 +96,7 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest forTypes(PackageType... types) { Collection newTypes; if (types == null || types.length == 0) { - newTypes = PackageType.NATIVE; + newTypes = NATIVE; } else { newTypes = Stream.of(types).collect(Collectors.toSet()); } @@ -122,7 +136,7 @@ public final class PackageTest extends RunnablePackageTest { namedInitializers.add(id); } currentTypes.forEach(type -> handlers.get(type).addInitializer( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } @@ -151,13 +165,12 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest addBundleVerifier( ThrowingBiConsumer v) { currentTypes.forEach(type -> handlers.get(type).addBundleVerifier( - ThrowingBiConsumer.toBiConsumer(v))); + toBiConsumer(v))); return this; } public PackageTest addBundleVerifier(ThrowingConsumer v) { - return addBundleVerifier( - (cmd, unused) -> ThrowingConsumer.toConsumer(v).accept(cmd)); + return addBundleVerifier((cmd, unused) -> toConsumer(v).accept(cmd)); } public PackageTest addBundlePropertyVerifier(String propertyName, @@ -184,7 +197,7 @@ public final class PackageTest extends RunnablePackageTest { } public PackageTest addBundleDesktopIntegrationVerifier(boolean integrated) { - forTypes(PackageType.LINUX, () -> { + forTypes(LINUX, () -> { LinuxHelper.addBundleDesktopIntegrationVerifier(this, integrated); }); return this; @@ -192,31 +205,25 @@ public final class PackageTest extends RunnablePackageTest { public PackageTest addInstallVerifier(ThrowingConsumer v) { currentTypes.forEach(type -> handlers.get(type).addInstallVerifier( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } public PackageTest addUninstallVerifier(ThrowingConsumer v) { currentTypes.forEach(type -> handlers.get(type).addUninstallVerifier( - ThrowingConsumer.toConsumer(v))); + toConsumer(v))); return this; } - public PackageTest setPackageInstaller(Consumer v) { + public PackageTest disablePackageInstaller() { currentTypes.forEach( - type -> packageHandlers.get(type).installHandler = v); + type -> packageHandlers.get(type).installHandler = cmd -> {}); return this; } - public PackageTest setPackageUnpacker( - BiFunction v) { - currentTypes.forEach(type -> packageHandlers.get(type).unpackHandler = v); - return this; - } - - public PackageTest setPackageUninstaller(Consumer v) { + public PackageTest disablePackageUninstaller() { currentTypes.forEach( - type -> packageHandlers.get(type).uninstallHandler = v); + type -> packageHandlers.get(type).uninstallHandler = cmd -> {}); return this; } @@ -238,7 +245,7 @@ public final class PackageTest extends RunnablePackageTest { // running check of type of environment. addHelloAppInitializer(null); - forTypes(PackageType.LINUX, () -> { + forTypes(LINUX, () -> { LinuxHelper.addFileAssociationsVerifier(this, fa); }); @@ -317,11 +324,6 @@ public final class PackageTest extends RunnablePackageTest { return this; } - public PackageTest addLauncherName(String name) { - launcherNames.add(name); - return this; - } - public final static class Group extends RunnablePackageTest { public Group(PackageTest... tests) { handlers = Stream.of(tests) @@ -372,7 +374,7 @@ public final class PackageTest extends RunnablePackageTest { } private List> createPackageTypeHandlers() { - return PackageType.NATIVE.stream() + return NATIVE.stream() .map(type -> { Handler handler = handlers.entrySet().stream() .filter(entry -> !entry.getValue().isVoid()) @@ -393,29 +395,39 @@ public final class PackageTest extends RunnablePackageTest { private Consumer createPackageTypeHandler( PackageType type, Handler handler) { - return ThrowingConsumer.toConsumer(new ThrowingConsumer() { + return toConsumer(new ThrowingConsumer() { @Override public void accept(Action action) throws Throwable { + if (terminated) { + throw new IllegalStateException(); + } + if (action == Action.FINALIZE) { - if (unpackDir != null && Files.isDirectory(unpackDir) - && !unpackDir.startsWith(TKit.workDir())) { - TKit.deleteDirectoryRecursive(unpackDir); + if (unpackDir != null) { + if (Files.isDirectory(unpackDir) + && !unpackDir.startsWith(TKit.workDir())) { + TKit.deleteDirectoryRecursive(unpackDir); + } + unpackDir = null; } + terminated = true; } if (aborted) { return; } - final JPackageCommand curCmd; - if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { - curCmd = cmd; - } else { - curCmd = cmd.createImmutableCopy(); - } + final Supplier curCmd = () -> { + if (Set.of(Action.INITIALIZE, Action.CREATE).contains(action)) { + return cmd; + } else { + return cmd.createImmutableCopy(); + } + }; switch (action) { case UNPACK: { + cmd.setUnpackedPackageLocation(null); var handler = packageHandlers.get(type).unpackHandler; if (!(aborted = (handler == null))) { unpackDir = TKit.createTempDirectory( @@ -428,9 +440,10 @@ public final class PackageTest extends RunnablePackageTest { } case INSTALL: { + cmd.setUnpackedPackageLocation(null); var handler = packageHandlers.get(type).installHandler; if (!(aborted = (handler == null))) { - handler.accept(curCmd); + handler.accept(curCmd.get()); } break; } @@ -438,18 +451,19 @@ public final class PackageTest extends RunnablePackageTest { case UNINSTALL: { var handler = packageHandlers.get(type).uninstallHandler; if (!(aborted = (handler == null))) { - handler.accept(curCmd); + handler.accept(curCmd.get()); } break; } case CREATE: - handler.accept(action, curCmd); + cmd.setUnpackedPackageLocation(null); + handler.accept(action, curCmd.get()); aborted = (expectedJPackageExitCode != 0); return; default: - handler.accept(action, curCmd); + handler.accept(action, curCmd.get()); break; } @@ -462,6 +476,7 @@ public final class PackageTest extends RunnablePackageTest { private Path unpackDir; private boolean aborted; + private boolean terminated; private final JPackageCommand cmd = Functional.identity(() -> { JPackageCommand result = new JPackageCommand(); result.setDefaultInputOutput().setDefaultAppName(); @@ -535,13 +550,23 @@ public final class PackageTest extends RunnablePackageTest { verifyPackageUninstalled(cmd); } break; + + case PURGE: + if (expectedJPackageExitCode == 0) { + var bundle = cmd.outputBundle(); + if (toSupplier(() -> TKit.deleteIfExists(bundle)).get()) { + TKit.trace(String.format("Deleted [%s] package", + bundle)); + } + } + break; } } private void verifyPackageBundle(JPackageCommand cmd, Executor.Result result) { if (expectedJPackageExitCode == 0) { - if (PackageType.LINUX.contains(cmd.packageType())) { + if (LINUX.contains(cmd.packageType())) { LinuxHelper.verifyPackageBundleEssential(cmd); } } @@ -557,35 +582,85 @@ public final class PackageTest extends RunnablePackageTest { } TKit.trace(String.format(formatString, cmd.getPrintableCommandLine())); + Optional.ofNullable(cmd.unpackedPackageDirectory()).ifPresent( + unpackedDir -> { + verifyRootCountInUnpackedPackage(cmd, unpackedDir); + }); + if (!cmd.isRuntime()) { - if (PackageType.WINDOWS.contains(cmd.packageType()) + if (WINDOWS.contains(cmd.packageType()) && !cmd.isPackageUnpacked( "Not verifying desktop integration")) { // Check main launcher - new WindowsHelper.DesktopIntegrationVerifier(cmd, null); + WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers - launcherNames.forEach(name -> { - new WindowsHelper.DesktopIntegrationVerifier(cmd, name); + cmd.addLauncherNames().forEach(name -> { + WindowsHelper.verifyDesktopIntegration(cmd, name); }); } } + cmd.assertAppLayout(); installVerifiers.forEach(v -> v.accept(cmd)); } + private void verifyRootCountInUnpackedPackage(JPackageCommand cmd, + Path unpackedDir) { + + final long expectedRootCount; + if (WINDOWS.contains(cmd.packageType())) { + // On Windows it is always two entries: + // installation home directory and MSI file + expectedRootCount = 2; + } else if (LINUX.contains(cmd.packageType())) { + Set roots = new HashSet<>(); + roots.add(Path.of("/").resolve(Path.of(cmd.getArgumentValue( + "--install-dir", () -> "/opt")).getName(0))); + if (cmd.hasArgument("--license-file")) { + switch (cmd.packageType()) { + case LINUX_RPM -> { + // License file is in /usr/share/licenses subtree + roots.add(Path.of("/usr")); + } + + case LINUX_DEB -> { + Path installDir = cmd.appInstallationDirectory(); + if (installDir.equals(Path.of("/")) + || installDir.startsWith("/usr")) { + // License file is in /usr/share/doc subtree + roots.add(Path.of("/usr")); + } + } + } + } + expectedRootCount = roots.size(); + } else { + expectedRootCount = 1; + } + + try ( var files = Files.list(unpackedDir)) { + TKit.assertEquals(expectedRootCount, files.count(), + String.format( + "Check the package has %d top installation directories", + expectedRootCount)); + } catch (IOException ex) { + rethrowUnchecked(ex); + } + } + private void verifyPackageUninstalled(JPackageCommand cmd) { TKit.trace(String.format("Verify uninstalled: %s", cmd.getPrintableCommandLine())); if (!cmd.isRuntime()) { TKit.assertPathExists(cmd.appLauncherPath(), false); - if (PackageType.WINDOWS.contains(cmd.packageType())) { + if (WINDOWS.contains(cmd.packageType())) { // Check main launcher - new WindowsHelper.DesktopIntegrationVerifier(cmd, null); + WindowsHelper.verifyDesktopIntegration(cmd, null); // Check additional launchers - launcherNames.forEach(name -> { - new WindowsHelper.DesktopIntegrationVerifier(cmd, name); + cmd.addLauncherNames().forEach(name -> { + WindowsHelper.verifyDesktopIntegration(cmd, name); }); } } @@ -610,18 +685,18 @@ public final class PackageTest extends RunnablePackageTest { private static Map createDefaultPackageHandlers() { HashMap handlers = new HashMap<>(); if (TKit.isLinux()) { - handlers.put(PackageType.LINUX_DEB, LinuxHelper.createDebPackageHandlers()); - handlers.put(PackageType.LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); + handlers.put(LINUX_DEB, LinuxHelper.createDebPackageHandlers()); + handlers.put(LINUX_RPM, LinuxHelper.createRpmPackageHandlers()); } if (TKit.isWindows()) { - handlers.put(PackageType.WIN_MSI, WindowsHelper.createMsiPackageHandlers()); - handlers.put(PackageType.WIN_EXE, WindowsHelper.createExePackageHandlers()); + handlers.put(WIN_MSI, WindowsHelper.createMsiPackageHandlers()); + handlers.put(WIN_EXE, WindowsHelper.createExePackageHandlers()); } if (TKit.isOSX()) { - handlers.put(PackageType.MAC_DMG, MacHelper.createDmgPackageHandlers()); - handlers.put(PackageType.MAC_PKG, MacHelper.createPkgPackageHandlers()); + handlers.put(MAC_DMG, MacHelper.createDmgPackageHandlers()); + handlers.put(MAC_PKG, MacHelper.createPkgPackageHandlers()); } return handlers; @@ -633,7 +708,6 @@ public final class PackageTest extends RunnablePackageTest { private Map handlers; private Set namedInitializers; private Map packageHandlers; - private final List launcherNames = new ArrayList(); private final static File BUNDLE_OUTPUT_DIR; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java index 6f98cfc234d..a5cedc5c34e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/RunnablePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,12 @@ public abstract class RunnablePackageTest { .filter(Predicate.not(Action.INITIALIZE::equals)) .filter(Predicate.not(Action.FINALIZE::equals)) .collect(Collectors.toList())); + if (hasAction(Action.PURGE) && !actionList.contains(Action.PURGE)) { + // Default action list contains "purge" action meaning + // packages are not needed for further processing. + // Copy this behavior in custom action list. + actionList.add(Action.PURGE); + } } actionList.add(Action.FINALIZE); @@ -51,6 +57,10 @@ public abstract class RunnablePackageTest { runActions(actionGroups); } + public static boolean hasAction(Action a) { + return DEFAULT_ACTIONS.contains(a); + } + protected void runActions(List actions) { actions.forEach(this::runAction); } @@ -89,6 +99,10 @@ public abstract class RunnablePackageTest { * Uninstall package. */ UNINSTALL, + /** + * Purge package. + */ + PURGE, /** * Finalize test. */ diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index fb88d4cd21d..1907c074504 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java index 528973bea22..a3f67e01d46 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WindowsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public class WindowsHelper { private static Path getInstallationSubDirectory(JPackageCommand cmd) { cmd.verifyIsOfType(PackageType.WINDOWS); - return Path.of(cmd.getArgumentValue("--install-dir", () -> cmd.name())); + return Path.of(cmd.getArgumentValue("--install-dir", cmd::name)); } private static void runMsiexecWithRetries(Executor misexec) { @@ -66,7 +66,13 @@ public class WindowsHelper { for (int attempt = 0; attempt < 8; ++attempt) { result = misexec.executeWithoutExitCodeCheck(); - // The given Executor may either be of an msiexe command or an + if (result.exitCode == 1605) { + // ERROR_UNKNOWN_PRODUCT, attempt to uninstall not installed + // package + return; + } + + // The given Executor may either be of an msiexec command or an // unpack.bat script containing the msiexec command. In the later // case, when misexec returns 1618, the unpack.bat may return 1603 if ((result.exitCode == 1618) || (result.exitCode == 1603)) { @@ -91,16 +97,25 @@ public class WindowsHelper { PackageHandlers msi = new PackageHandlers(); msi.installHandler = cmd -> installMsi.accept(cmd, true); - msi.uninstallHandler = cmd -> installMsi.accept(cmd, false); + msi.uninstallHandler = cmd -> { + if (Files.exists(cmd.outputBundle())) { + installMsi.accept(cmd, false); + } + }; msi.unpackHandler = (cmd, destinationDir) -> { cmd.verifyIsOfType(PackageType.WIN_MSI); final Path unpackBat = destinationDir.resolve("unpack.bat"); final Path unpackDir = destinationDir.resolve( TKit.removeRootFromAbsolutePath( getInstallationRootDirectory(cmd))); + // Put msiexec in .bat file because can't pass value of TARGETDIR // property containing spaces through ProcessBuilder properly. - TKit.createTextFile(unpackBat, List.of(String.join(" ", List.of( + // Set folder permissions to allow msiexec unpack msi bundle. + TKit.createTextFile(unpackBat, List.of( + String.format("icacls \"%s\" /inheritance:e /grant Users:M", + destinationDir), + String.join(" ", List.of( "msiexec", "/a", String.format("\"%s\"", cmd.outputBundle().normalize()), @@ -125,10 +140,19 @@ public class WindowsHelper { PackageHandlers exe = new PackageHandlers(); exe.installHandler = cmd -> installExe.accept(cmd, true); - exe.uninstallHandler = cmd -> installExe.accept(cmd, false); + exe.uninstallHandler = cmd -> { + if (Files.exists(cmd.outputBundle())) { + installExe.accept(cmd, false); + } + }; return exe; } + static void verifyDesktopIntegration(JPackageCommand cmd, + String launcherName) { + new DesktopIntegrationVerifier(cmd, launcherName); + } + public static String getMsiProperty(JPackageCommand cmd, String propertyName) { cmd.verifyIsOfType(PackageType.WIN_MSI); return Executor.of("cscript.exe", "//Nologo") @@ -143,21 +167,45 @@ public class WindowsHelper { return cmd.hasArgument("--win-per-user-install"); } - static class DesktopIntegrationVerifier { + private static class DesktopIntegrationVerifier { - DesktopIntegrationVerifier(JPackageCommand cmd, String name) { + DesktopIntegrationVerifier(JPackageCommand cmd, String launcherName) { cmd.verifyIsOfType(PackageType.WINDOWS); - this.cmd = cmd; - this.name = (name == null ? cmd.name() : name); + + name = Optional.ofNullable(launcherName).orElseGet(cmd::name); + + isUserLocalInstall = isUserLocalInstall(cmd); + + appInstalled = cmd.appLauncherPath(launcherName).toFile().exists(); + + desktopShortcutPath = Path.of(name + ".lnk"); + + startMenuShortcutPath = Path.of(cmd.getArgumentValue( + "--win-menu-group", () -> "Unknown"), name + ".lnk"); + + if (name.equals(cmd.name())) { + isWinMenu = cmd.hasArgument("--win-menu"); + isDesktop = cmd.hasArgument("--win-shortcut"); + } else { + var props = AdditionalLauncher.getAdditionalLauncherProperties(cmd, + launcherName); + isWinMenu = props.getPropertyBooleanValue("win-menu").orElseGet( + () -> cmd.hasArgument("--win-menu")); + isDesktop = props.getPropertyBooleanValue("win-shortcut").orElseGet( + () -> cmd.hasArgument("--win-shortcut")); + } + verifyStartMenuShortcut(); + verifyDesktopShortcut(); - verifyFileAssociationsRegistry(); + + Stream.of(cmd.getAllArgumentValues("--file-associations")).map( + Path::of).forEach(this::verifyFileAssociationsRegistry); } private void verifyDesktopShortcut() { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); - if (cmd.hasArgument("--win-shortcut")) { - if (isUserLocalInstall(cmd)) { + if (isDesktop) { + if (isUserLocalInstall) { verifyUserLocalDesktopShortcut(appInstalled); verifySystemDesktopShortcut(false); } else { @@ -170,10 +218,6 @@ public class WindowsHelper { } } - private Path desktopShortcutPath() { - return Path.of(name + ".lnk"); - } - private void verifyShortcut(Path path, boolean exists) { if (exists) { TKit.assertFileExists(path); @@ -185,19 +229,18 @@ public class WindowsHelper { private void verifySystemDesktopShortcut(boolean exists) { Path dir = Path.of(queryRegistryValueCache( SYSTEM_SHELL_FOLDERS_REGKEY, "Common Desktop")); - verifyShortcut(dir.resolve(desktopShortcutPath()), exists); + verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyUserLocalDesktopShortcut(boolean exists) { Path dir = Path.of( queryRegistryValueCache(USER_SHELL_FOLDERS_REGKEY, "Desktop")); - verifyShortcut(dir.resolve(desktopShortcutPath()), exists); + verifyShortcut(dir.resolve(desktopShortcutPath), exists); } private void verifyStartMenuShortcut() { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); - if (cmd.hasArgument("--win-menu")) { - if (isUserLocalInstall(cmd)) { + if (isWinMenu) { + if (isUserLocalInstall) { verifyUserLocalStartMenuShortcut(appInstalled); verifySystemStartMenuShortcut(false); } else { @@ -210,13 +253,8 @@ public class WindowsHelper { } } - private Path startMenuShortcutPath() { - return Path.of(cmd.getArgumentValue("--win-menu-group", - () -> "Unknown"), name + ".lnk"); - } - private void verifyStartMenuShortcut(Path shortcutsRoot, boolean exists) { - Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath()); + Path shortcutPath = shortcutsRoot.resolve(startMenuShortcutPath); verifyShortcut(shortcutPath, exists); if (!exists) { TKit.assertPathNotEmptyDirectory(shortcutPath.getParent()); @@ -234,13 +272,7 @@ public class WindowsHelper { USER_SHELL_FOLDERS_REGKEY, "Programs")), exists); } - private void verifyFileAssociationsRegistry() { - Stream.of(cmd.getAllArgumentValues("--file-associations")).map( - Path::of).forEach(this::verifyFileAssociationsRegistry); - } - private void verifyFileAssociationsRegistry(Path faFile) { - boolean appInstalled = cmd.appLauncherPath(name).toFile().exists(); try { TKit.trace(String.format( "Get file association properties from [%s] file", @@ -290,7 +322,12 @@ public class WindowsHelper { } } - private final JPackageCommand cmd; + private final Path desktopShortcutPath; + private final Path startMenuShortcutPath; + private final boolean isUserLocalInstall; + private final boolean appInstalled; + private final boolean isWinMenu; + private final boolean isDesktop; private final String name; } diff --git a/test/jdk/tools/jpackage/run_tests.sh b/test/jdk/tools/jpackage/run_tests.sh index a5cb03fc3aa..2639f38cd68 100644 --- a/test/jdk/tools/jpackage/run_tests.sh +++ b/test/jdk/tools/jpackage/run_tests.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -78,15 +78,25 @@ help_usage () echo " Optional, for jtreg tests debug purposes only." echo ' -l - value for `jpackage.test.logfile` property.' echo " Optional, for jtreg tests debug purposes only." - echo " -m - mode to run jtreg tests." - echo ' Should be one of `create`, `update` or `print-default-tests`.' - echo ' Optional, default mode is `update`.' + echo " -m - mode to run jtreg tests. Supported values:" echo ' - `create`' echo ' Remove all package bundles from the output directory before running jtreg tests.' echo ' - `update`' echo ' Run jtreg tests and overrite existing package bundles in the output directory.' echo ' - `print-default-tests`' echo ' Print default list of packaging tests and exit.' + echo ' - `create-small-runtime`' + echo ' Create small Java runtime using /bin/jlink command in the output directory.' + echo ' - `create-packages`' + echo ' Create packages.' + echo ' The script will set `jpackage.test.action` property.' + echo ' - `test-packages`' + echo ' Create and fully test packages. Will create, unpack, install, and uninstall packages.' + echo ' The script will set `jpackage.test.action` property.' + echo ' - `do-packages`' + echo " Create, unpack and verify packages." + echo ' The script will not set `jpackage.test.action` property.' + echo ' Optional, defaults are `update` and `create-packages`.' } error () @@ -133,8 +143,6 @@ exec_command () test_jdk= # Path to local copy of open jdk repo with jpackage jtreg tests -# hg clone http://hg.openjdk.java.net/jdk/sandbox -# cd sandbox; hg update -r JDK-8200758-branch open_jdk_with_jpackage_jtreg_tests=$(dirname $0)/../../../../ # Directory where to save artifacts for testing. @@ -152,12 +160,27 @@ mode=update # jtreg extra arguments declare -a jtreg_args -# Create packages only -jtreg_args+=("-Djpackage.test.action=create") - # run all tests run_all_tests= +test_actions= + +set_mode () +{ + case "$1" in + create-packages) test_actions='-Djpackage.test.action=create';; + test-packages) test_actions='-Djpackage.test.action=uninstall,create,unpack,verify-install,install,verify-install,uninstall,verify-uninstall,purge';; + do-packages) test_actions=;; + create-small-runtime) mode=$1;; + print-default-tests) mode=$1;; + create) mode=$1;; + update) mode=$1;; + *) fatal_with_help_usage 'Invalid value of -m option:' [$1];; + esac +} + +set_mode 'create-packages' + mapfile -t tests < <(find_all_packaging_tests) while getopts "vahdct:j:o:r:m:l:" argname; do @@ -171,7 +194,7 @@ while getopts "vahdct:j:o:r:m:l:" argname; do o) output_dir="$OPTARG";; r) runtime_dir="$OPTARG";; l) logfile="$OPTARG";; - m) mode="$OPTARG";; + m) set_mode "$OPTARG";; h) help_usage; exit 0;; ?) help_usage; exit 1;; esac @@ -201,6 +224,11 @@ if [ ! -e "$JAVA_HOME/bin/java" ]; then fatal JAVA_HOME variable is set to [$JAVA_HOME] value, but $JAVA_HOME/bin/java not found. fi +if [ "$mode" = "create-small-runtime" ]; then + exec_command "$test_jdk/bin/jlink" --add-modules java.base,java.datatransfer,java.xml,java.prefs,java.desktop --compress=2 --no-header-files --no-man-pages --strip-debug --output "$output_dir" + exit +fi + if [ -z "$JT_HOME" ]; then if [ -z "$JT_BUNDLE_URL" ]; then fatal 'JT_HOME or JT_BUNDLE_URL environment variable is not set. Link to JTREG bundle can be found at https://openjdk.java.net/jtreg/'. @@ -222,18 +250,12 @@ if [ -n "$logfile" ]; then jtreg_args+=("-Djpackage.test.logfile=$(to_native_path "$logfile")") fi -if [ "$mode" = create ]; then - true -elif [ "$mode" = update ]; then - true -else - fatal_with_help_usage 'Invalid value of -m option:' [$mode] -fi - if [ -z "$run_all_tests" ]; then jtreg_args+=(-Djpackage.test.SQETest=yes) fi +jtreg_args+=("$test_actions") + # Drop arguments separator [ "$1" != "--" ] || shift @@ -249,10 +271,10 @@ installJtreg () if [ ! -f "$jtreg_jar" ]; then exec_command mkdir -p "$workdir" if [[ ${jtreg_bundle: -7} == ".tar.gz" ]]; then - exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" + exec_command "(" cd "$workdir" "&&" wget --no-check-certificate "$jtreg_bundle" "&&" tar -xzf "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" else if [[ ${jtreg_bundle: -4} == ".zip" ]]; then - exec_command "(" cd "$workdir" "&&" wget "$jtreg_bundle" "&&" unzip "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" + exec_command "(" cd "$workdir" "&&" wget --no-check-certificate "$jtreg_bundle" "&&" unzip "$(basename $jtreg_bundle)" ";" rm -f "$(basename $jtreg_bundle)" ")" else fatal 'Unsupported extension of JREG bundle ['$JT_BUNDLE_URL']. Only *.zip or *.tar.gz is supported.' fi diff --git a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java index 5df3609e3ba..b048d6db335 100644 --- a/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java +++ b/test/jdk/tools/jpackage/share/MultiLauncherTwoPhaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,8 +69,6 @@ public class MultiLauncherTwoPhaseTest { launcher2.applyTo(appImageCmd); PackageTest packageTest = new PackageTest() - .addLauncherName("bar") // Add launchers name for verification - .addLauncherName("foo") .addRunOnceInitializer(() -> appImageCmd.execute()) .addBundleDesktopIntegrationVerifier(true) .addInitializer(cmd -> { diff --git a/test/jdk/tools/jpackage/test_jpackage.sh b/test/jdk/tools/jpackage/test_jpackage.sh deleted file mode 100644 index c4b28020bc0..00000000000 --- a/test/jdk/tools/jpackage/test_jpackage.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/bash - -# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. - - -# -# Complete testing of jpackage platform-specific packaging. -# -# The script does the following: -# 1. Create packages. -# 2. Install created packages. -# 3. Verifies packages are installed. -# 4. Uninstall created packages. -# 5. Verifies packages are uninstalled. -# -# For the list of accepted command line arguments see `run_tests.sh` script. -# - -# Fail fast -set -e; set -o pipefail; - -# Script debug -dry_run=${JPACKAGE_TEST_DRY_RUN} - -# Default directory where jpackage should write bundle files -output_dir=~/jpackage_bundles - - -set_args () -{ - args=() - local arg_is_output_dir= - local arg_is_mode= - local output_dir_set= - local with_append_actions=yes - for arg in "$@"; do - if [ "$arg" == "-o" ]; then - arg_is_output_dir=yes - output_dir_set=yes - elif [ "$arg" == "-m" ]; then - arg_is_mode=yes - continue - elif [ "$arg" == '--' ]; then - append_actions - with_append_actions= - continue - elif ! case "$arg" in -Djpackage.test.action=*) false;; esac; then - continue - elif [ -n "$arg_is_output_dir" ]; then - arg_is_output_dir= - output_dir="$arg" - elif [ -n "$arg_is_mode" ]; then - arg_is_mode= - continue - fi - - args+=( "$arg" ) - done - [ -n "$output_dir_set" ] || args=( -o "$output_dir" "${args[@]}" ) - [ -z "$with_append_actions" ] || append_actions -} - - -append_actions () -{ - args+=( '--' '-Djpackage.test.action=create,install,verify-install,uninstall,verify-uninstall' ) -} - - -exec_command () -{ - if [ -n "$dry_run" ]; then - echo "$@" - else - eval "$@" - fi -} - -set_args "$@" -basedir="$(dirname $0)" -exec_command ${SHELL} "$basedir/run_tests.sh" -m create "${args[@]}" diff --git a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java index 0c233b0e652..968ed94b345 100644 --- a/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java +++ b/test/jdk/tools/jpackage/windows/WinUpgradeUUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,7 +100,7 @@ public class WinUpgradeUUIDTest { // It will be uninstalled automatically when the second // package will be installed. // However uninstall verification for the first package will be executed. - PackageTest test1 = init.get().setPackageUninstaller(cmd -> {}); + PackageTest test1 = init.get().disablePackageUninstaller(); PackageTest test2 = init.get().addInitializer(cmd -> { cmd.setArgumentValue("--app-version", "2.0");