8371184: Improve jpackage test coverage for "--app-image" option

Reviewed-by: almatvee
This commit is contained in:
Alexey Semenyuk 2025-11-04 22:41:17 +00:00
parent 463f5dc112
commit c8f5fd6ff3
20 changed files with 331 additions and 181 deletions

View File

@ -351,7 +351,8 @@ public class PackageTestTest extends JUnitAdapter {
}
@Override
public void verifyIsOfType(PackageType ... types) {
public JPackageCommand verifyIsOfType(Set<PackageType> types) {
return this;
}
@Override

View File

@ -165,7 +165,7 @@ public final class AdditionalLauncher {
public void applyTo(JPackageCommand cmd) {
cmd.addPrerequisiteAction(this::initialize);
cmd.addVerifyAction(createVerifierAsConsumer());
cmd.addVerifyAction(createVerifierAsConsumer(), JPackageCommand.ActionRole.LAUNCHER_VERIFIER);
}
public void applyTo(PackageTest test) {

View File

@ -192,9 +192,7 @@ final class ConfigFilesStasher {
}
private static ApplicationLayout appImageAppLayout(JPackageCommand cmd) {
if (cmd.isRuntime()) {
throw new UnsupportedOperationException();
}
cmd.verifyNotRuntime();
if (cmd.isImagePackageType()) {
return platformAppImage();

View File

@ -28,13 +28,16 @@ import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Collectors.toCollection;
import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.util.ArrayList;
@ -48,6 +51,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@ -56,6 +60,7 @@ import java.util.regex.Pattern;
import java.util.spi.ToolProvider;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.jpackage.internal.util.function.ThrowingConsumer;
import jdk.jpackage.internal.util.function.ThrowingFunction;
import jdk.jpackage.internal.util.function.ThrowingRunnable;
@ -85,7 +90,6 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
ignoreDefaultRuntime = cmd.ignoreDefaultRuntime;
ignoreDefaultVerbose = cmd.ignoreDefaultVerbose;
this.immutable = immutable;
dmgInstallDir = cmd.dmgInstallDir;
prerequisiteActions = new Actions(cmd.prerequisiteActions);
verifyActions = new Actions(cmd.verifyActions);
standardAsserts = cmd.standardAsserts;
@ -165,11 +169,6 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
return null;
}
public String getArgumentValue(String argName,
Function<JPackageCommand, String> defaultValueSupplier) {
return getArgumentValue(argName, defaultValueSupplier, v -> v);
}
public <T> T getArgumentValue(String argName,
Supplier<T> defaultValueSupplier,
Function<String, T> stringConverter) {
@ -332,16 +331,35 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
return this;
}
public JPackageCommand usePredefinedAppImage(Path predefinedAppImagePath) {
return setArgumentValue("--app-image", Objects.requireNonNull(predefinedAppImagePath))
.removeArgumentWithValue("--input");
}
JPackageCommand addPrerequisiteAction(ThrowingConsumer<JPackageCommand> action) {
prerequisiteActions.add(action);
return this;
}
JPackageCommand addVerifyAction(ThrowingConsumer<JPackageCommand> action) {
verifyActions.add(action);
return addVerifyAction(action, ActionRole.DEFAULT);
}
enum ActionRole {
DEFAULT,
LAUNCHER_VERIFIER,
;
}
JPackageCommand addVerifyAction(ThrowingConsumer<JPackageCommand> action, ActionRole actionRole) {
verifyActions.add(action, actionRole);
return this;
}
Stream<ThrowingConsumer<JPackageCommand>> getVerifyActionsWithRole(ActionRole actionRole) {
return verifyActions.actionsWithRole(actionRole);
}
/**
* Shorthand for {@code helloAppImage(null)}.
*/
@ -550,11 +568,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
}
if (TKit.isOSX()) {
if (packageType() == PackageType.MAC_DMG && dmgInstallDir != null) {
return dmgInstallDir;
} else {
return MacHelper.getInstallationDirectory(this);
}
return MacHelper.getInstallationDirectory(this);
}
throw TKit.throwUnknownPlatformError();
@ -676,10 +690,11 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
return Collections.unmodifiableList(names);
}
private void verifyNotRuntime() {
JPackageCommand verifyNotRuntime() {
if (isRuntime()) {
throw new IllegalArgumentException("Java runtime packaging");
throw new UnsupportedOperationException("Java runtime packaging");
}
return this;
}
/**
@ -1212,6 +1227,52 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
MacHelper.verifyUnsignedBundleSignature(cmd);
}
}),
PREDEFINED_APP_IMAGE_COPY(cmd -> {
Optional.ofNullable(cmd.getArgumentValue("--app-image")).filter(_ -> {
return !TKit.isOSX() || !MacHelper.signPredefinedAppImage(cmd);
}).map(Path::of).ifPresent(predefinedAppImage -> {
TKit.trace(String.format(
"Check contents of the predefined app image [%s] copied verbatim",
predefinedAppImage));
var outputAppImageDir = cmd.pathToUnpackedPackageFile(cmd.appInstallationDirectory());
try (var walk = Files.walk(predefinedAppImage)) {
var filteredWalk = walk;
if (!cmd.expectAppImageFile()) {
var appImageFile = AppImageFile.getPathInAppImage(predefinedAppImage);
// Exclude ".jpackage.xml" as it should no be in the output bundle.
var pred = Predicate.<Path>isEqual(appImageFile).negate();
if (TKit.isOSX()) {
// On MacOS exclude files that can be signed as their digests change.
pred = pred.and(path -> {
return MacHelper.isVerbatimCopyFromPredefinedAppImage(cmd, path);
});
}
filteredWalk = walk.filter(pred);
}
var verbatimPaths = filteredWalk.collect(toCollection(TreeSet::new));
// Remove nonempty directories from the collection of paths copied verbatim.
verbatimPaths.removeAll(verbatimPaths.stream().map(Path::getParent).toList());
verbatimPaths.forEach(ThrowingConsumer.toConsumer(p -> {
if (Files.isDirectory(p, LinkOption.NOFOLLOW_LINKS)) {
TKit.assertDirectoryExists(p);
} else {
TKit.assertSameFileContent(p, outputAppImageDir.resolve(predefinedAppImage.relativize(p)));
}
}));
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
TKit.trace("Done");
});
})
;
StandardAssert(Consumer<JPackageCommand> action) {
@ -1220,9 +1281,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
private static JPackageCommand convertFromRuntime(JPackageCommand cmd) {
var copy = cmd.createMutableCopy();
copy.immutable = false;
copy.removeArgumentWithValue("--runtime-image");
copy.dmgInstallDir = cmd.appInstallationDirectory();
if (!copy.hasArgument("--name")) {
copy.addArguments("--name", cmd.nameFromRuntimeImage().orElseThrow());
}
@ -1440,29 +1499,35 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
return getPrintableCommandLine();
}
public void verifyIsOfType(Collection<PackageType> types) {
verifyIsOfType(types.toArray(PackageType[]::new));
public final JPackageCommand verifyIsOfType(PackageType ... types) {
return verifyIsOfType(Set.of(types));
}
public void verifyIsOfType(PackageType ... types) {
final var typesSet = Stream.of(types).collect(Collectors.toSet());
public final JPackageCommand verifyIsOfType(Iterable<PackageType> types) {
return verifyIsOfType(StreamSupport.stream(types.spliterator(), false).collect(toSet()));
}
public JPackageCommand verifyIsOfType(Set<PackageType> types) {
Objects.requireNonNull(types);
if (!hasArgument("--type")) {
if (!isImagePackageType()) {
if ((TKit.isLinux() && typesSet.equals(PackageType.LINUX)) || (TKit.isWindows() && typesSet.equals(PackageType.WINDOWS))) {
return;
if ((TKit.isLinux() && types.equals(PackageType.LINUX)) || (TKit.isWindows() && types.equals(PackageType.WINDOWS))) {
return this;
}
if (TKit.isOSX() && typesSet.equals(PackageType.MAC)) {
return;
if (TKit.isOSX() && types.equals(PackageType.MAC)) {
return this;
}
} else if (typesSet.equals(Set.of(PackageType.IMAGE))) {
return;
} else if (types.equals(Set.of(PackageType.IMAGE))) {
return this;
}
}
if (!typesSet.contains(packageType())) {
throw new IllegalArgumentException("Unexpected type");
if (!types.contains(packageType())) {
throw new UnsupportedOperationException(String.format("Unsupported operation for type [%s]", packageType().getType()));
}
return this;
}
public CfgFile readLauncherCfgFile() {
@ -1558,18 +1623,47 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
}
void add(ThrowingConsumer<JPackageCommand> action) {
Objects.requireNonNull(action);
add(action, ActionRole.DEFAULT);
}
void add(ThrowingConsumer<JPackageCommand> action, ActionRole role) {
verifyMutable();
actions.add(new Consumer<JPackageCommand>() {
@Override
public void accept(JPackageCommand t) {
if (!executed) {
executed = true;
ThrowingConsumer.toConsumer(action).accept(t);
}
actions.add(new Action(action, role));
}
Stream<ThrowingConsumer<JPackageCommand>> actionsWithRole(ActionRole role) {
Objects.requireNonNull(role);
return actions.stream().filter(action -> {
return Objects.equals(action.role(), role);
}).map(Action::impl);
}
private static final class Action implements Consumer<JPackageCommand> {
Action(ThrowingConsumer<JPackageCommand> impl, ActionRole role) {
this.impl = Objects.requireNonNull(impl);
this.role = Objects.requireNonNull(role);
}
ActionRole role() {
return role;
}
ThrowingConsumer<JPackageCommand> impl() {
return impl;
}
@Override
public void accept(JPackageCommand cmd) {
if (!executed) {
executed = true;
ThrowingConsumer.toConsumer(impl).accept(cmd);
}
private boolean executed;
});
}
private final ActionRole role;
private final ThrowingConsumer<JPackageCommand> impl;
private boolean executed;
}
@Override
@ -1578,7 +1672,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
actions.forEach(action -> action.accept(JPackageCommand.this));
}
private final List<Consumer<JPackageCommand>> actions;
private final List<Action> actions;
}
private Boolean withToolProvider;
@ -1589,7 +1683,6 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
private boolean ignoreDefaultRuntime;
private boolean ignoreDefaultVerbose;
private boolean immutable;
private Path dmgInstallDir;
private final Actions prerequisiteActions;
private final Actions verifyActions;
private Path executeInDirectory;

View File

@ -24,6 +24,7 @@ package jdk.jpackage.test;
import static java.util.stream.Collectors.toMap;
import static jdk.jpackage.test.AdditionalLauncher.NO_ICON;
import static jdk.jpackage.test.AdditionalLauncher.getAdditionalLauncherProperties;
import static jdk.jpackage.test.LauncherShortcut.LINUX_SHORTCUT;
import java.io.IOException;
@ -34,6 +35,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@ -72,6 +74,12 @@ public final class LauncherVerifier {
new LauncherVerifier(cmd).verify(cmd, Action.EXECUTE_LAUNCHER);
}
static String launcherDescription(JPackageCommand cmd, String launcherName) {
return launcherDescription(cmd, launcherName, (theCmd, theLauncherName) -> {
return getAdditionalLauncherProperties(theCmd, theLauncherName);
});
}
public enum Action {
VERIFY_ICON(LauncherVerifier::verifyIcon),
@ -137,8 +145,8 @@ public final class LauncherVerifier {
}
private String getDescription(JPackageCommand cmd) {
return findProperty("description").orElseGet(() -> {
return cmd.getArgumentValue("--description", cmd::name);
return launcherDescription(cmd, name, (theCmd, theLauncherName) -> {
return properties.orElseThrow();
});
}
@ -272,7 +280,11 @@ public final class LauncherVerifier {
}
private void verifyDescription(JPackageCommand cmd) throws IOException {
if (TKit.isWindows()) {
if (TKit.isWindows() && !cmd.hasArgument("--app-image")) {
// On Windows, check the description if the predefined app image is not configured.
// The description and the icon are encoded in the launcher executable, which should be
// copied verbatim from the predefined app image into the output bundle.
// This check is done in the JPackageCommand class, so there is no need to duplicate it here.
String expectedDescription = getDescription(cmd);
Path launcherPath = cmd.appLauncherPath(name);
String actualDescription =
@ -424,6 +436,24 @@ public final class LauncherVerifier {
});
}
private static String launcherDescription(
JPackageCommand cmd,
String launcherName,
BiFunction<JPackageCommand, String, PropertyFile> addLauncherPropertyFileGetter) {
return PropertyFinder.findLauncherProperty(cmd, launcherName,
PropertyFinder.cmdlineOptionWithValue("--description"),
PropertyFinder.launcherPropertyFile("description"),
PropertyFinder.nop()
).orElseGet(() -> {
if (cmd.isMainLauncher(launcherName)) {
return cmd.mainLauncherName();
} else {
return launcherDescription(cmd, null, addLauncherPropertyFileGetter);
}
});
}
private static final class DefaultEntitlements {
private static Map<String, Object> loadFromResources(String resourceName) {

View File

@ -26,7 +26,6 @@ import static java.util.Collections.unmodifiableSortedSet;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
import static jdk.jpackage.test.AdditionalLauncher.getAdditionalLauncherProperties;
import java.io.IOException;
import java.io.UncheckedIOException;
@ -560,14 +559,7 @@ public final class LinuxHelper {
TKit.assertTrue(mandatoryKeys.isEmpty(), String.format(
"Check for missing %s keys in the file", mandatoryKeys));
final String launcherDescription;
if (cmd.name().equals(launcherName) || predefinedAppImage.isPresent()) {
launcherDescription = Optional.ofNullable(cmd.getArgumentValue("--description")).orElseGet(cmd::name);
} else {
launcherDescription = getAdditionalLauncherProperties(cmd, launcherName).findProperty("description").or(() -> {
return Optional.ofNullable(cmd.getArgumentValue("--description"));
}).orElseGet(cmd::name);
}
final var launcherDescription = LauncherVerifier.launcherDescription(cmd, launcherName);
for (var e : List.of(
Map.entry("Type", "Application"),

View File

@ -545,6 +545,43 @@ public final class MacHelper {
}
}
static boolean isVerbatimCopyFromPredefinedAppImage(JPackageCommand cmd, Path path) {
cmd.verifyIsOfType(PackageType.MAC);
final var predefinedAppImage = Path.of(cmd.getArgumentValue("--app-image"));
final var appLayout = ApplicationLayout.macAppImage().resolveAt(predefinedAppImage);
if (!path.startsWith(predefinedAppImage)) {
throw new IllegalArgumentException(
String.format("Path [%s] is not in directory [%s]", path, predefinedAppImage));
}
if (path.startsWith(appLayout.contentDirectory().resolve("_CodeSignature"))) {
// A file in the "Contents/_CodeSignature" directory.
return false;
}
final var outputAppImageDir = cmd.pathToUnpackedPackageFile(cmd.appInstallationDirectory());
final var outputAppImagePath = outputAppImageDir.resolve(predefinedAppImage.relativize(path));
if (path.startsWith(appLayout.launchersDirectory()) &&
cmd.launcherNames(true).stream().map(cmd::appLauncherPath).collect(toSet()).contains(outputAppImagePath)) {
// The `path` references a launcher.
// It can be signed and its digest may change.
return false;
}
if (path.startsWith(appLayout.runtimeHomeDirectory().resolve("bin"))) {
// The `path` references an executable native command in JDK's "bin" subdirectory.
// It can be signed and its digest may change.
return false;
}
return true;
}
static void verifyUnsignedBundleSignature(JPackageCommand cmd) {
if (!cmd.isImagePackageType()) {
MacSignVerify.assertUnsigned(cmd.outputBundle());
@ -716,12 +753,8 @@ public final class MacHelper {
final var defaultInstallLocation = Path.of(
cmd.isRuntime() ? "/Library/Java/JavaVirtualMachines" : "/Applications");
final Path installLocation;
if (cmd.packageType() == PackageType.MAC_DMG) {
installLocation = defaultInstallLocation;
} else {
installLocation = cmd.getArgumentValue("--install-dir", () -> defaultInstallLocation, Path::of);
}
final Path installLocation = Optional.ofNullable(cmd.getArgumentValue("--install-dir"))
.map(Path::of).orElse(defaultInstallLocation);
return installLocation.resolve(cmd.name() + (cmd.isRuntime() ? ".jdk" : ".app"));
}

View File

@ -60,6 +60,7 @@ import java.util.stream.StreamSupport;
import jdk.jpackage.internal.util.function.ThrowingBiConsumer;
import jdk.jpackage.internal.util.function.ThrowingConsumer;
import jdk.jpackage.internal.util.function.ThrowingRunnable;
import jdk.jpackage.test.JPackageCommand.ActionRole;
/**
@ -233,6 +234,15 @@ public final class PackageTest extends RunnablePackageTest {
return this;
}
public PackageTest usePredefinedAppImage(JPackageCommand appImageCmd) {
appImageCmd.verifyIsOfType(PackageType.IMAGE);
addInitializer(cmd -> {
cmd.usePredefinedAppImage(appImageCmd.outputBundle());
});
appImageCmd.getVerifyActionsWithRole(ActionRole.LAUNCHER_VERIFIER).forEach(this::addInstallVerifier);
return this;
}
public PackageTest disablePackageInstaller() {
currentTypes.forEach(disabledInstallers::add);
return this;

View File

@ -26,7 +26,9 @@ import static jdk.jpackage.test.AdditionalLauncher.getAdditionalLauncherProperti
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import jdk.jpackage.test.AdditionalLauncher.PropertyFile;
@ -42,6 +44,12 @@ final class PropertyFinder {
};
}
default Finder<T> defaultValue(Supplier<String> v) {
return target -> {
return Optional.of(find(target).orElseGet(v));
};
}
default Finder<T> map(UnaryOperator<String> v) {
Objects.requireNonNull(v);
return target -> {
@ -134,7 +142,27 @@ final class PropertyFinder {
Finder<PropertyFile> addLauncherPropertyFileFinder,
Finder<AppImageFile> appImageFileFinder) {
return findLauncherProperty(
cmd,
launcherName,
(theCmd, theLauncherName) -> {
return getAdditionalLauncherProperties(theCmd, theLauncherName);
},
cmdlineFinder,
addLauncherPropertyFileFinder,
appImageFileFinder);
}
static Optional<String> findLauncherProperty(
JPackageCommand cmd,
String launcherName,
BiFunction<JPackageCommand, String, PropertyFile> addLauncherPropertyFileGetter,
Finder<JPackageCommand> cmdlineFinder,
Finder<PropertyFile> addLauncherPropertyFileFinder,
Finder<AppImageFile> appImageFileFinder) {
Objects.requireNonNull(cmd);
Objects.requireNonNull(addLauncherPropertyFileGetter);
Objects.requireNonNull(cmdlineFinder);
Objects.requireNonNull(addLauncherPropertyFileFinder);
Objects.requireNonNull(appImageFileFinder);
@ -148,7 +176,7 @@ final class PropertyFinder {
if (mainLauncher) {
reply = cmdlineFinder.find(cmd);
} else if (appImageFilePath.isEmpty()) {
var props = getAdditionalLauncherProperties(cmd, launcherName);
var props = addLauncherPropertyFileGetter.apply(cmd, launcherName);
reply = addLauncherPropertyFileFinder.find(props);
} else {
reply = Optional.empty();

View File

@ -199,10 +199,8 @@ public class SigningPackageTwoStepTest {
test.forTypes(signPackage.keySet()).addRunOnceInitializer(() -> {
appImageCmd.setArgumentValue("--dest", TKit.createTempDirectory("appimage")).execute(0);
}).addInitializer(cmd -> {
}).usePredefinedAppImage(appImageCmd).addInitializer(cmd -> {
MacHelper.useKeychain(cmd, keychain);
cmd.addArguments("--app-image", appImageCmd.outputBundle());
cmd.removeArgumentWithValue("--input");
Optional.ofNullable(signPackage.get(cmd.packageType())).ifPresent(signOption -> {
signOption.setTo(cmd);
});

View File

@ -196,27 +196,22 @@ public class AddLShortcutTest {
// and applies shortcut configuration to the main launcher in the native packaging jpackage command.
//
Path[] predefinedAppImage = new Path[1];
var appImageCmd = JPackageCommand.helloAppImage()
.setArgumentValue("--name", "foo")
.setFakeRuntime();
new PackageTest().addRunOnceInitializer(() -> {
var cmd = JPackageCommand.helloAppImage()
.setArgumentValue("--name", "foo")
.setFakeRuntime();
for (var i = 1; i != cfgs.length; ++i) {
var al = new AdditionalLauncher("launcher-" + i);
cfgs[i].applyToAdditionalLauncher(al);
al.withoutVerifyActions(Action.EXECUTE_LAUNCHER).applyTo(appImageCmd);
}
for (var i = 1; i != cfgs.length; ++i) {
var al = new AdditionalLauncher("launcher-" + i);
cfgs[i].applyToAdditionalLauncher(al);
al.withoutVerifyActions(Action.EXECUTE_LAUNCHER).applyTo(cmd);
}
cmd.execute();
predefinedAppImage[0] = cmd.outputBundle();
}).addInitializer(cmd -> {
new PackageTest()
.addRunOnceInitializer(appImageCmd::execute)
.usePredefinedAppImage(appImageCmd)
.addInitializer(cmd -> {
cfgs[0].applyToMainLauncher(cmd);
cmd.removeArgumentWithValue("--input");
cmd.setArgumentValue("--name", "AddLShortcutDir2Test");
cmd.addArguments("--app-image", predefinedAppImage[0]);
}).run(RunnablePackageTest.Action.CREATE_AND_UNPACK);
}
@ -237,20 +232,15 @@ public class AddLShortcutTest {
shortcutArgs.add(startupDirectory.asStringValue());
}
Path[] predefinedAppImage = new Path[1];
var appImageCmd = JPackageCommand.helloAppImage()
.setArgumentValue("--name", "foo")
.setFakeRuntime();
new PackageTest().addRunOnceInitializer(() -> {
var cmd = JPackageCommand.helloAppImage()
.setArgumentValue("--name", "foo")
.setFakeRuntime();
cmd.execute();
predefinedAppImage[0] = cmd.outputBundle();
}).addInitializer(cmd -> {
cmd.removeArgumentWithValue("--input");
new PackageTest()
.addRunOnceInitializer(appImageCmd::execute)
.usePredefinedAppImage(appImageCmd)
.addInitializer(cmd -> {
cmd.setArgumentValue("--name", "AddLShortcutDir3Test");
cmd.addArguments("--app-image", predefinedAppImage[0]);
cmd.ignoreDefaultVerbose(true);
}).addInitializer(cmd -> {
cmd.addArguments(shortcutArgs);

View File

@ -275,10 +275,9 @@ public class AddLauncherTest {
if (withPredefinedAppImage) {
new PackageTest().addInitializer(cmd -> {
cmd.setArgumentValue("--name", "Bar");
// Should not have impact of launcher descriptions, but it does.
// Should not have impact on launcher descriptions, but it does.
cmd.setArgumentValue("--description", "Installer");
cmd.removeArgumentWithValue("--input").setArgumentValue("--app-image", target.cmd().orElseThrow().outputBundle());
}).mutate(addLinuxShortcuts()).run(Action.CREATE_AND_UNPACK);
}).usePredefinedAppImage(target.cmd().orElseThrow()).mutate(addLinuxShortcuts()).run(Action.CREATE_AND_UNPACK);
}
}

View File

@ -499,11 +499,11 @@ public class AppContentTest {
return new FileContentFactory(() -> {
var basedir = TKit.createTempDirectory("content").resolve(path);
for (var textFile : Map.ofEntries(
for (var textFile : List.of(
entry("woods/moose", "The moose"),
entry("woods/bear", "The bear"),
entry("woods/trees/jay", "The gray jay")
).entrySet()) {
)) {
var src = basedir.resolve(textFile.getKey());
Files.createDirectories(src.getParent());
TKit.createTextFile(src, Stream.of(textFile.getValue()));

View File

@ -62,15 +62,12 @@ public class AppImagePackageTest {
@Test
public static void test() {
var appImageCmd = JPackageCommand.helloAppImage()
.setArgumentValue("--dest", TKit.createTempDirectory("appimage"));
final var appImageCmd = createAppImageCommand();
new PackageTest()
.addRunOnceInitializer(appImageCmd::execute)
.addInitializer(cmd -> {
cmd.addArguments("--app-image", appImageCmd.outputBundle());
cmd.removeArgumentWithValue("--input");
}).addBundleDesktopIntegrationVerifier(false).run();
.usePredefinedAppImage(appImageCmd)
.addBundleDesktopIntegrationVerifier(false).run();
}
/**
@ -85,10 +82,7 @@ public class AppImagePackageTest {
@Parameter("false")
public static void testEmpty(boolean withIcon) throws IOException {
var appImageCmd = JPackageCommand.helloAppImage()
.setFakeRuntime()
.setArgumentValue("--name", "EmptyAppImagePackageTest")
.setArgumentValue("--dest", TKit.createTempDirectory("appimage"));
final var appImageCmd = createAppImageCommand();
new PackageTest()
.addRunOnceInitializer(appImageCmd::execute)
@ -116,12 +110,11 @@ public class AppImagePackageTest {
TKit.trace("Done");
}
})
.usePredefinedAppImage(appImageCmd)
.addInitializer(cmd -> {
cmd.addArguments("--app-image", appImageCmd.outputBundle());
if (withIcon) {
cmd.addArguments("--icon", iconPath("icon"));
cmd.setArgumentValue("--icon", iconPath("icon"));
}
cmd.removeArgumentWithValue("--input");
cmd.excludeStandardAsserts(
StandardAssert.MAIN_JAR_FILE,
@ -160,10 +153,8 @@ public class AppImagePackageTest {
*/
@Test
public static void testBadAppImage3() {
Path appImageDir = TKit.createTempDirectory("appimage");
JPackageCommand appImageCmd = JPackageCommand.helloAppImage().
setFakeRuntime().setArgumentValue("--dest", appImageDir);
final var appImageCmd = createAppImageCommand();
configureBadAppImage(appImageCmd.outputBundle()).addRunOnceInitializer(() -> {
appImageCmd.execute();
@ -176,10 +167,8 @@ public class AppImagePackageTest {
*/
@Test
public static void testBadAppImageFile() {
final var appImageRoot = TKit.createTempDirectory("appimage");
final var appImageCmd = JPackageCommand.helloAppImage().
setFakeRuntime().setArgumentValue("--dest", appImageRoot);
final var appImageCmd = createAppImageCommand();
final var appImageDir = appImageCmd.outputBundle();
@ -202,13 +191,17 @@ public class AppImagePackageTest {
private static PackageTest configureBadAppImage(Path appImageDir, CannedFormattedString expectedError) {
return new PackageTest().addInitializer(cmd -> {
cmd.addArguments("--app-image", appImageDir);
cmd.removeArgumentWithValue("--input");
cmd.usePredefinedAppImage(appImageDir);
cmd.ignoreDefaultVerbose(true); // no "--verbose" option
cmd.validateOutput(expectedError);
}).setExpectedExitCode(1);
}
private static JPackageCommand createAppImageCommand() {
final var appImageRoot = TKit.createTempDirectory("appimage");
return JPackageCommand.helloAppImage().setFakeRuntime().setArgumentValue("--dest", appImageRoot);
}
private static Path iconPath(String name) {
return TKit.TEST_SRC_ROOT.resolve(Path.of("resources", name
+ TKit.ICON_SUFFIX));

View File

@ -34,8 +34,6 @@ import jdk.jpackage.test.JPackageStringBundle;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.RunnablePackageTest.Action;
import jdk.jpackage.test.TKit;
import jdk.jpackage.test.TKit.TextStreamVerifier;
/**
* Test --install-dir parameter. Output of the test should be
@ -113,9 +111,9 @@ public class InstallDirTest {
.run();
}
record DmgTestSpec(Path installDir, boolean runtimeInstaller) {
record TestSpec(Path installDir, boolean runtimeInstaller) {
DmgTestSpec {
TestSpec {
Objects.requireNonNull(installDir);
}
@ -135,8 +133,8 @@ public class InstallDirTest {
return this;
}
DmgTestSpec create() {
return new DmgTestSpec(installDir, runtimeInstaller);
TestSpec create() {
return new TestSpec(installDir, runtimeInstaller);
}
private Path installDir;
@ -154,7 +152,7 @@ public class InstallDirTest {
}
void run() {
final var test = new PackageTest().forTypes(PackageType.MAC_DMG).ignoreBundleOutputDir();
final var test = new PackageTest().ignoreBundleOutputDir();
if (runtimeInstaller) {
test.addInitializer(cmd -> {
cmd.removeArgumentWithValue("--input");
@ -164,33 +162,33 @@ public class InstallDirTest {
}
test.addInitializer(JPackageCommand::setFakeRuntime).addInitializer(cmd -> {
cmd.addArguments("--install-dir", installDir);
cmd.setArgumentValue("--install-dir", installDir);
}).run(Action.CREATE_AND_UNPACK);
}
}
@Test(ifOS = OperatingSystem.MACOS)
@ParameterSupplier
public static void testDmg(DmgTestSpec testSpec) {
public static void testMac(TestSpec testSpec) {
testSpec.run();
}
public static List<Object[]> testDmg() {
public static List<Object[]> testMac() {
return Stream.of(
DmgTestSpec.build().acceptedInstallDir("/foo"),
DmgTestSpec.build().acceptedInstallDir("/foo/bar"),
DmgTestSpec.build().acceptedInstallDir("/foo").runtimeInstaller(),
DmgTestSpec.build().acceptedInstallDir("/foo/bar").runtimeInstaller(),
TestSpec.build().acceptedInstallDir("/foo"),
TestSpec.build().acceptedInstallDir("/foo/bar"),
TestSpec.build().acceptedInstallDir("/foo").runtimeInstaller(),
TestSpec.build().acceptedInstallDir("/foo/bar").runtimeInstaller(),
DmgTestSpec.build().acceptedInstallDir("/Library/Java/JavaVirtualMachines"),
DmgTestSpec.build().acceptedInstallDir("/Applications").runtimeInstaller(),
TestSpec.build().acceptedInstallDir("/Library/Java/JavaVirtualMachines"),
TestSpec.build().acceptedInstallDir("/Applications").runtimeInstaller(),
DmgTestSpec.build().acceptedInstallDir("/Applications"),
DmgTestSpec.build().acceptedInstallDir("/Applications/foo/bar/buz"),
TestSpec.build().acceptedInstallDir("/Applications"),
TestSpec.build().acceptedInstallDir("/Applications/foo/bar/buz"),
DmgTestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines"),
DmgTestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines/foo/bar/buz")
).map(DmgTestSpec.Builder::create).map(testSpec -> {
TestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines"),
TestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines/foo/bar/buz")
).map(TestSpec.Builder::create).map(testSpec -> {
return new Object[] { testSpec };
}).toList();
}

View File

@ -22,13 +22,12 @@
*/
import java.nio.file.Path;
import java.io.IOException;
import jdk.jpackage.test.AdditionalLauncher;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.TKit;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
/**
* Test multiple launchers in two phases. First test creates app image and then
@ -55,7 +54,7 @@ import jdk.jpackage.test.JPackageCommand;
public class MultiLauncherTwoPhaseTest {
@Test
public static void test() throws IOException {
public static void test() {
Path appimageOutput = TKit.createTempDirectory("appimage");
JPackageCommand appImageCmd = JPackageCommand.helloAppImage()
@ -68,12 +67,9 @@ public class MultiLauncherTwoPhaseTest {
launcher2.applyTo(appImageCmd);
PackageTest packageTest = new PackageTest()
.addRunOnceInitializer(() -> appImageCmd.execute())
.addRunOnceInitializer(appImageCmd::execute)
.addBundleDesktopIntegrationVerifier(true)
.addInitializer(cmd -> {
cmd.addArguments("--app-image", appImageCmd.outputBundle());
cmd.removeArgumentWithValue("--input");
})
.usePredefinedAppImage(appImageCmd)
.forTypes(PackageType.WINDOWS)
.addInitializer(cmd -> {
cmd.addArguments("--win-shortcut", "--win-menu",

View File

@ -22,13 +22,12 @@
*/
import java.nio.file.Path;
import java.io.IOException;
import jdk.jpackage.test.Annotations.Parameter;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.TKit;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.Annotations.Parameter;
import jdk.jpackage.test.JPackageCommand;
/**
* Test creation of packages in tho phases with different names.
@ -58,9 +57,7 @@ public class MultiNameTwoPhaseTest {
@Parameter({"MultiNameTest", ""})
@Parameter({"", "MultiNameTestInstaller"})
@Parameter({"", ""})
public static void test(String... testArgs) throws IOException {
String appName = testArgs[0];
String installName = testArgs[1];
public static void test(String appName, String installName) {
Path appimageOutput = TKit.createTempDirectory("appimage");
@ -74,9 +71,8 @@ public class MultiNameTwoPhaseTest {
PackageTest packageTest = new PackageTest()
.addRunOnceInitializer(() -> appImageCmd.execute())
.addBundleDesktopIntegrationVerifier(true)
.usePredefinedAppImage(appImageCmd)
.addInitializer(cmd -> {
cmd.addArguments("--app-image", appImageCmd.outputBundle());
cmd.removeArgumentWithValue("--input");
cmd.removeArgumentWithValue("--name");
if (!installName.isEmpty()) {
cmd.addArguments("--name", installName);

View File

@ -107,10 +107,7 @@ public class PostImageScriptTest {
});
}
case EXTERNAL_APP_IMAGE -> {
test.addInitializer(cmd -> {
cmd.removeArgumentWithValue("--input");
cmd.addArguments("--app-image", appImageCmd.outputBundle());
});
test.usePredefinedAppImage(appImageCmd);
}
}

View File

@ -243,10 +243,7 @@ public class ServiceTest {
new PackageTest().excludeTypes(MAC_DMG)
.addRunOnceInitializer(appImageCmd.cmd().orElseThrow()::execute)
.addInitializer(cmd -> {
cmd.removeArgumentWithValue("--input");
cmd.addArguments("--app-image", appImageCmd.cmd().orElseThrow().outputBundle());
})
.usePredefinedAppImage(appImageCmd.cmd().orElseThrow())
.addInitializer(cmd -> {
if (mainLauncherAsService) {
cmd.addArgument("--launcher-as-service");

View File

@ -24,9 +24,11 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.JPackageCommand;
import java.util.List;
import java.util.stream.Stream;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.RunnablePackageTest.Action;
import jdk.jpackage.test.TKit;
@ -48,13 +50,13 @@ import jdk.jpackage.test.TKit;
public class Win8282351Test {
@Test
public void test() throws IOException {
public void test() {
Path appimageOutput = TKit.createTempDirectory("appimage");
JPackageCommand appImageCmd = JPackageCommand.helloAppImage()
.setFakeRuntime().setArgumentValue("--dest", appimageOutput);
String[] filesWithDollarCharsInNames = new String[]{
var filesWithDollarCharsInNames = Stream.of(
"Pane$$anon$$greater$1.class",
"$",
"$$",
@ -63,11 +65,11 @@ public class Win8282351Test {
"$$$$$",
"foo$.class",
"1$b$$a$$$r$$$$.class"
};
).map(Path::of).toList();
String[] dirsWithDollarCharsInNames = new String[]{
Path.of("foo", String.join("/", filesWithDollarCharsInNames)).toString()
};
var dirsWithDollarCharsInNames = List.of(
filesWithDollarCharsInNames.stream().reduce(Path.of("foo"), Path::resolve)
);
String name = appImageCmd.name() + "$-$$-$$$";
@ -75,7 +77,7 @@ public class Win8282351Test {
.addRunOnceInitializer(() -> {
appImageCmd.execute();
for (var path : filesWithDollarCharsInNames) {
createImageFile(appImageCmd, Path.of(path));
createImageFile(appImageCmd, path);
}
for (var path : dirsWithDollarCharsInNames) {
@ -83,16 +85,15 @@ public class Win8282351Test {
appImageCmd.outputBundle().resolve(path));
}
})
.usePredefinedAppImage(appImageCmd)
.addInitializer(cmd -> {
cmd.setArgumentValue("--name", name);
cmd.addArguments("--app-image", appImageCmd.outputBundle());
cmd.removeArgumentWithValue("--input");
cmd.addArgument("--win-menu");
cmd.addArgument("--win-shortcut");
})
.addInstallVerifier(cmd -> {
for (var path : filesWithDollarCharsInNames) {
verifyImageFile(appImageCmd, Path.of(path));
verifyImageFile(appImageCmd, path);
}
for (var path : dirsWithDollarCharsInNames) {