8282007: Assorted enhancements to jpackage testing framework

Reviewed-by: almatvee
This commit is contained in:
Alexey Semenyuk 2022-02-17 05:27:41 +00:00
parent b6e48e6782
commit cd234f5dbe
17 changed files with 562 additions and 326 deletions

View File

@ -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<String> 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

View File

@ -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<String, String>... v) {
final public AdditionalLauncher addRawProperties(
Map.Entry<String, String>... v) {
return addRawProperties(List.of(v));
}
public AdditionalLauncher addRawProperties(
final public AdditionalLauncher addRawProperties(
Collection<Map.Entry<String, String>> 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<Path, List<Map.Entry<String, String>>> 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<String, Path> consumer) {
var argIt = cmd.getAllArguments().iterator();
while (argIt.hasNext()) {
if ("--add-launcher".equals(argIt.next())) {
// <launcherName>=<propFile>
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<String> getPropertyValue(String name) {
Objects.requireNonNull(name);
return Optional.of(data.get(name));
}
public Optional<Boolean> getPropertyBooleanValue(String name) {
Objects.requireNonNull(name);
return Optional.ofNullable(data.get(name)).map(Boolean::parseBoolean);
}
private final Map<String, String> 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<String> javaOptions;

View File

@ -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());

View File

@ -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<Executor> {
}
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;
}

View File

@ -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<String> launcherArgs = List.of(args);
final List<String> 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<String> defaultLauncherArgs;
private final Map<String, String> params;
}

View File

@ -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<JPackageCommand> {
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<JPackageCommand> {
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<JPackageCommand> {
return appLauncherPath(null);
}
/**
* Returns names of all additional launchers or empty list if none
* configured.
*/
public List<String> addLauncherNames() {
List<String> 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<JPackageCommand> {
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<JPackageCommand> {
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> {
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<JPackageCommand> {
return createExecutor().getPrintableCommandLine();
}
@Override
public String toString() {
return getPrintableCommandLine();
}
public void verifyIsOfType(Collection<PackageType> types) {
verifyIsOfType(types.toArray(PackageType[]::new));
}

View File

@ -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");

View File

@ -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<Path> 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));
});
});

View File

@ -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<Path> 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<Path> CRITICAL_RUNTIME_FILES = Set.of(Path.of(
"Contents/Home/lib/server/libjvm.dylib"));
}

View File

@ -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<PackageType> 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<JPackageCommand, Executor.Result> v) {
currentTypes.forEach(type -> handlers.get(type).addBundleVerifier(
ThrowingBiConsumer.toBiConsumer(v)));
toBiConsumer(v)));
return this;
}
public PackageTest addBundleVerifier(ThrowingConsumer<JPackageCommand> 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<JPackageCommand> v) {
currentTypes.forEach(type -> handlers.get(type).addInstallVerifier(
ThrowingConsumer.toConsumer(v)));
toConsumer(v)));
return this;
}
public PackageTest addUninstallVerifier(ThrowingConsumer<JPackageCommand> v) {
currentTypes.forEach(type -> handlers.get(type).addUninstallVerifier(
ThrowingConsumer.toConsumer(v)));
toConsumer(v)));
return this;
}
public PackageTest setPackageInstaller(Consumer<JPackageCommand> v) {
public PackageTest disablePackageInstaller() {
currentTypes.forEach(
type -> packageHandlers.get(type).installHandler = v);
type -> packageHandlers.get(type).installHandler = cmd -> {});
return this;
}
public PackageTest setPackageUnpacker(
BiFunction<JPackageCommand, Path, Path> v) {
currentTypes.forEach(type -> packageHandlers.get(type).unpackHandler = v);
return this;
}
public PackageTest setPackageUninstaller(Consumer<JPackageCommand> 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<Consumer<Action>> 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<Action> createPackageTypeHandler(
PackageType type, Handler handler) {
return ThrowingConsumer.toConsumer(new ThrowingConsumer<Action>() {
return toConsumer(new ThrowingConsumer<Action>() {
@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<JPackageCommand> 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<Path> 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<PackageType, PackageHandlers> createDefaultPackageHandlers() {
HashMap<PackageType, PackageHandlers> 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<PackageType, Handler> handlers;
private Set<String> namedInitializers;
private Map<PackageType, PackageHandlers> packageHandlers;
private final List<String> launcherNames = new ArrayList();
private final static File BUNDLE_OUTPUT_DIR;

View File

@ -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<Action[]> actions) {
actions.forEach(this::runAction);
}
@ -89,6 +99,10 @@ public abstract class RunnablePackageTest {
* Uninstall package.
*/
UNINSTALL,
/**
* Purge package.
*/
PURGE,
/**
* Finalize test.
*/

View File

@ -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

View File

@ -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;
}

View File

@ -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 <logfile> - value for `jpackage.test.logfile` property.'
echo " Optional, for jtreg tests debug purposes only."
echo " -m <mode> - 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> - 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 <jdk>/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

View File

@ -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 -> {

View File

@ -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[@]}"

View File

@ -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");