diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java
index 20f7ac41eef..81e5da34140 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java
@@ -67,6 +67,7 @@ import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
+import jdk.internal.util.OSVersion;
import jdk.jpackage.internal.util.MemoizingSupplier;
import jdk.jpackage.internal.util.function.ExceptionBox;
import jdk.jpackage.internal.util.function.ThrowingConsumer;
@@ -233,7 +234,7 @@ import jdk.jpackage.internal.util.function.ThrowingSupplier;
* An untrusted certificate can NOT be used with /usr/bin/codesign. Use
*
*
- * /usr/bin/security security add-trusted-cert -k foo.keychain cert.pem
+ * /usr/bin/security add-trusted-cert -k foo.keychain cert.pem
*
*
* command to add trusted certificate from "cert.pem" file to "foo.keychain"
@@ -440,7 +441,21 @@ public final class MacSign {
}
Keychain unlock() {
- createExecutor("unlock-keychain").execute();
+ var exec = createExecutor("unlock-keychain");
+
+ exec.execute();
+
+ if (UnlockKeychainWithOsascript.VALUE) {
+ exec = Executor.of("osascript")
+ .addArguments(SIGN_UTILS_SCRIPT.toString(), "run-shell-script")
+ .addArgument(Stream.concat(
+ Stream.of(exec.getExecutable().orElseThrow().toString()),
+ exec.getAllArguments().stream()
+ ).collect(joining(" ")));
+
+ exec.execute();
+ }
+
return this;
}
@@ -576,29 +591,43 @@ public final class MacSign {
}
private static CertificateStats create(KeychainWithCertsSpec spec) {
- final var allCertificates = spec.keychain().findCertificates();
final List allResolvedCertificateRequests = new ArrayList<>();
final Map unmappedCertificates = new HashMap<>();
- withTempDirectory(workDir -> {
- for (final var cert : allCertificates) {
- ResolvedCertificateRequest resolvedCertificateRequest;
- try {
- resolvedCertificateRequest = new ResolvedCertificateRequest(cert);
- } catch (RuntimeException ex) {
- unmappedCertificates.put(cert, ExceptionBox.unbox(ex));
- continue;
- }
+ final Runnable workload = () -> {
+ final var allCertificates = spec.keychain().findCertificates();
+ withTempDirectory(workDir -> {
+ for (final var cert : allCertificates) {
+ ResolvedCertificateRequest resolvedCertificateRequest;
+ try {
+ resolvedCertificateRequest = new ResolvedCertificateRequest(cert);
+ } catch (RuntimeException ex) {
+ unmappedCertificates.put(cert, ExceptionBox.unbox(ex));
+ continue;
+ }
- if (spec.certificateRequests().stream().anyMatch(resolvedCertificateRequest.installed()::match)) {
- final var certFile = workDir.resolve(CertificateHash.of(cert).toString() + ".pem");
- final var verifyStatus = verifyCertificate(resolvedCertificateRequest, spec.keychain(), certFile);
- resolvedCertificateRequest = resolvedCertificateRequest.copyVerified(verifyStatus);
- }
+ if (spec.certificateRequests().stream().anyMatch(resolvedCertificateRequest.installed()::match)) {
+ final var certFile = workDir.resolve(CertificateHash.of(cert).toString() + ".pem");
+ final var verifyStatus = verifyCertificate(resolvedCertificateRequest, spec.keychain(), certFile);
+ resolvedCertificateRequest = resolvedCertificateRequest.copyVerified(verifyStatus);
+ }
- allResolvedCertificateRequests.add(resolvedCertificateRequest);
- }
- });
+ allResolvedCertificateRequests.add(resolvedCertificateRequest);
+ }
+ });
+ };
+
+ // Starting from some macOS version, it is no longer necessary to have the keychain
+ // in the list of keychains when running the "/usr/bin/security verify-cert ..." command to verify its certificate(s).
+ // The exact version when they relaxed this constraint is unknown, but it is still required on Catalina 10.15.7.
+ // On Catalina, if the keychain is not in the list of keychains, "/usr/bin/security verify-cert ..." command
+ // executed on the certificates of this keychain returns "untrusted" result.
+ if (OSVersion.current().compareTo(new OSVersion(10, 16)) < 0) {
+ // macOS Catalina or older
+ withKeychains(spec).addToSearchList().run(workload);
+ } else {
+ workload.run();
+ }
return new CertificateStats(allResolvedCertificateRequests,
List.copyOf(spec.certificateRequests()), unmappedCertificates);
@@ -1272,7 +1301,11 @@ public final class MacSign {
for (final var quite : List.of(true, false)) {
result = security("verify-cert", "-L", "-n",
quite ? "-q" : "-v",
- "-c", certFile.normalize().toString(),
+ // Use "-r" option to verify the certificate against itself.
+ // "-c" option works on newer macOS versions, but on older ones (at least on Catalina 10.15.7),
+ // in case there are two self-signed certificates with the same name in the given keychain,
+ // it links them in the certificate list and fails verification.
+ "-r", certFile.normalize().toString(),
"-k", keychain.name(),
"-p", resolvedCertificateRequest.installed().type().verifyPolicy()).saveOutput(!quite).executeWithoutExitCodeCheck();
if (result.getExitCode() == 0) {
@@ -1463,4 +1496,10 @@ public final class MacSign {
// faketime is not a standard macOS command.
// One way to get it is with Homebrew.
private static final Path FAKETIME = Path.of(Optional.ofNullable(TKit.getConfigProperty("faketime")).orElse("/usr/local/bin/faketime"));
+
+ // Run the "/usr/bin/system unlock-keychain" command in Terminal.app if
+ // the current process runs in an SSH session and the OS version is macOS Catalina or older.
+ private static final class UnlockKeychainWithOsascript {
+ static final boolean VALUE = System.getenv("SSH_CONNECTION") != null && OSVersion.current().compareTo(new OSVersion(10, 16)) < 0;
+ }
}
diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java
index 01c510070be..404811ea0f8 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java
@@ -93,8 +93,11 @@ public final class MacSignVerify {
final var exec = Executor.of(
"/usr/bin/codesign",
"-d",
- "--entitlements", "-",
- "--xml", path.toString()).saveOutput().dumpOutput().binaryOutput();
+ // `--entitlements :-` will print entitlements as XML plist in the stdout and "Executable=..." message to the stderr.
+ // Prefer this option combination to `--entitlements - --xml` as
+ // the latter doesn't work on older macOS releases (Proved unsupported on Catalina 10.15.7).
+ "--entitlements", ":-",
+ path.toString()).saveOutput().dumpOutput().binaryOutput();
final var result = exec.execute();
var xml = result.byteStdout();
if (xml.length == 0) {
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 db76309c292..04b828677ca 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java
@@ -37,7 +37,6 @@ import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
@@ -606,25 +605,6 @@ public final class TKit {
return JtregSkippedExceptionClass.INSTANCE.isInstance(t);
}
- public static Path createRelativePathCopy(final Path file) {
- Path fileCopy = ThrowingSupplier.toSupplier(() -> {
- Path localPath = createTempFile(file.getFileName());
- Files.copy(file, localPath, StandardCopyOption.REPLACE_EXISTING);
- return localPath;
- }).get().toAbsolutePath().normalize();
-
- final Path basePath = Path.of(".").toAbsolutePath().normalize();
- try {
- return basePath.relativize(fileCopy);
- } catch (IllegalArgumentException ex) {
- // May happen on Windows: java.lang.IllegalArgumentException: 'other' has different root
- trace(String.format("Failed to relativize [%s] at [%s]", fileCopy,
- basePath));
- printStackTrace(ex);
- }
- return file;
- }
-
public static void waitForFileCreated(Path fileToWaitFor,
Duration timeout, Duration afterCreatedTimeout) throws IOException {
waitForFileCreated(fileToWaitFor, timeout);
diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java
index 3f933093e97..1b89d23c301 100644
--- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java
+++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/MainTest.java
@@ -154,6 +154,7 @@ public class MainTest extends JUnitAdapter {
JPackageCommand.helloAppImage()
.ignoreDefaultVerbose(true)
+ .ignoreDefaultRuntime(true)
.useToolProvider(jpackageToolProviderMock)
.execute(jpackageExitCode);
}
diff --git a/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java b/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java
index 54021aa2a0b..11b466ed715 100644
--- a/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java
+++ b/test/jdk/tools/jpackage/macosx/SigningRuntimeImagePackageTest.java
@@ -200,7 +200,7 @@ public class SigningRuntimeImagePackageTest {
// This way we can test if jpackage keeps or replaces the signature of
// the predefined runtime bundle when backing it in the pkg or dmg installer.
return new SignKeyOptionWithKeychain(
- SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME,
+ SignKeyOption.Type.SIGN_KEY_IDENTITY_APP_IMAGE,
SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD,
SigningBase.StandardKeychain.MAIN.keychain());
}
diff --git a/test/jdk/tools/jpackage/share/FileAssociationsTest.java b/test/jdk/tools/jpackage/share/FileAssociationsTest.java
index c9bd690d73f..0af7e7a54ff 100644
--- a/test/jdk/tools/jpackage/share/FileAssociationsTest.java
+++ b/test/jdk/tools/jpackage/share/FileAssociationsTest.java
@@ -23,6 +23,8 @@
import static java.util.Map.entry;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import jdk.jpackage.test.Annotations.Parameter;
@@ -84,7 +86,7 @@ public class FileAssociationsTest {
@Test
@Parameter("true")
@Parameter("false")
- public static void test(boolean includeDescription) {
+ public static void test(boolean includeDescription) throws IOException {
PackageTest packageTest = new PackageTest();
// Not supported
@@ -96,10 +98,8 @@ public class FileAssociationsTest {
}
fa.applyTo(packageTest);
- Path icon = TKit.TEST_SRC_ROOT.resolve(Path.of("resources", "icon"
- + TKit.ICON_SUFFIX));
-
- icon = TKit.createRelativePathCopy(icon);
+ var icon = TKit.createTempDirectory("icon-dir").resolve(ICON.getFileName());
+ Files.copy(ICON, icon);
new FileAssociations("jptest2")
.setFilename("fa2")
@@ -151,4 +151,6 @@ public class FileAssociationsTest {
.addInitializer(JPackageCommand::setFakeRuntime)
.setExpectedExitCode(1);
}
+
+ private static final Path ICON = TKit.TEST_SRC_ROOT.resolve(Path.of("resources", "icon" + TKit.ICON_SUFFIX));
}
diff --git a/test/jdk/tools/jpackage/share/LicenseTest.java b/test/jdk/tools/jpackage/share/LicenseTest.java
index 9c2d1077584..bf4c26fe76a 100644
--- a/test/jdk/tools/jpackage/share/LicenseTest.java
+++ b/test/jdk/tools/jpackage/share/LicenseTest.java
@@ -21,21 +21,23 @@
* questions.
*/
+import static jdk.internal.util.OperatingSystem.LINUX;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
-import static jdk.internal.util.OperatingSystem.LINUX;
+import jdk.jpackage.internal.util.Slot;
import jdk.jpackage.test.Annotations.Test;
-import jdk.jpackage.test.JPackageCommand;
-import jdk.jpackage.test.PackageType;
-import jdk.jpackage.test.PackageTest;
-import jdk.jpackage.test.LinuxHelper;
import jdk.jpackage.test.Executor;
+import jdk.jpackage.test.JPackageCommand;
+import jdk.jpackage.test.LinuxHelper;
+import jdk.jpackage.test.PackageTest;
+import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.TKit;
/**
@@ -93,11 +95,7 @@ public class LicenseTest {
@Test
public static void testCommon() {
- PackageTest test = new PackageTest().configureHelloApp()
- .addInitializer(cmd -> {
- cmd.addArguments("--license-file", TKit.createRelativePathCopy(
- LICENSE_FILE));
- });
+ PackageTest test = new PackageTest().configureHelloApp().mutate(LicenseTest::setLicenseFile);
initMacDmgLicenseVerifier(test.forTypes(PackageType.MAC_DMG));
initLinuxLicenseVerifier(test.forTypes(PackageType.LINUX));
@@ -127,19 +125,16 @@ public class LicenseTest {
@Test(ifOS = LINUX)
public static void testCustomDebianCopyright() {
- new CustomDebianCopyrightTest().run();
+ new CustomDebianCopyrightTest(false).run();
}
@Test(ifOS = LINUX)
public static void testCustomDebianCopyrightSubst() {
- new CustomDebianCopyrightTest().withSubstitution(true).run();
+ new CustomDebianCopyrightTest(true).run();
}
private static PackageTest initMacDmgLicenseVerifier(PackageTest test) {
- return test
- .addBundleVerifier(cmd -> {
- verifyLicenseFileInDMGPackage(cmd);
- });
+ return test.addBundleVerifier(LicenseTest::verifyLicenseFileInDMGPackage);
}
private static void verifyLicenseFileInDMGPackage(JPackageCommand cmd)
@@ -179,10 +174,9 @@ public class LicenseTest {
PackageTest test = new PackageTest()
.forTypes(PackageType.LINUX)
.configureHelloApp()
+ .addInitializer(JPackageCommand::setFakeRuntime)
+ .mutate(LicenseTest::setLicenseFile)
.addInitializer(cmd -> {
- cmd.setFakeRuntime();
- cmd.addArguments("--license-file", TKit.createRelativePathCopy(
- LICENSE_FILE));
cmd.addArguments("--install-dir", installDir);
});
@@ -191,6 +185,18 @@ public class LicenseTest {
test.run();
}
+ private static void setLicenseFile(PackageTest test) {
+ var inputLicenseFile = Slot.createEmpty();
+
+ test.addRunOnceInitializer(() -> {
+ var dir = TKit.createTempDirectory("license-dir");
+ inputLicenseFile.set(dir.resolve(LICENSE_FILE.getFileName()));
+ Files.copy(LICENSE_FILE, inputLicenseFile.get());
+ }).addInitializer(cmd -> {
+ cmd.setArgumentValue("--license-file", inputLicenseFile.get());
+ });
+ }
+
private static Path rpmLicenseFile(JPackageCommand cmd) {
final Path licenseRoot = Path.of(
new Executor()
@@ -296,12 +302,36 @@ public class LicenseTest {
TKit.assertPathExists(licenseFile.getParent(), false);
}
- private static class CustomDebianCopyrightTest {
- CustomDebianCopyrightTest() {
- withSubstitution(false);
+ private record CustomDebianCopyrightTest(boolean withSubstitution) {
+
+ private String copyright() {
+ // Different values just to make easy to figure out from the test log which test was executed.
+ if (withSubstitution) {
+ return "Duke (C)";
+ } else {
+ return "Java (C)";
+ }
}
- private List licenseFileText(String copyright, String licenseText) {
+ private String licenseText() {
+ // Different values just to make easy to figure out from the test log which test was executed.
+ if (withSubstitution) {
+ return "The quick brown fox\n jumps over the lazy dog";
+ } else {
+ return "How vexingly quick daft zebras jump!";
+ }
+ }
+
+ private String name() {
+ // Different values just to make easy to figure out from the test log which test was executed.
+ if (withSubstitution) {
+ return "CustomDebianCopyrightWithSubst";
+ } else {
+ return "CustomDebianCopyright";
+ }
+ }
+
+ static private List licenseFileText(String copyright, String licenseText) {
List lines = new ArrayList<>(List.of(
String.format("Copyright=%s", copyright),
"Foo",
@@ -313,28 +343,14 @@ public class LicenseTest {
private List licenseFileText() {
if (withSubstitution) {
- return licenseFileText("APPLICATION_COPYRIGHT",
- "APPLICATION_LICENSE_TEXT");
+ return licenseFileText("APPLICATION_COPYRIGHT", "APPLICATION_LICENSE_TEXT");
} else {
return expectedLicenseFileText();
}
}
private List expectedLicenseFileText() {
- return licenseFileText(copyright, licenseText);
- }
-
- CustomDebianCopyrightTest withSubstitution(boolean v) {
- withSubstitution = v;
- // Different values just to make easy to figure out from the test log which test was executed.
- if (v) {
- copyright = "Duke (C)";
- licenseText = "The quick brown fox\n jumps over the lazy dog";
- } else {
- copyright = "Java (C)";
- licenseText = "How vexingly quick daft zebras jump!";
- }
- return this;
+ return licenseFileText(copyright(), licenseText());
}
void run() {
@@ -343,20 +359,19 @@ public class LicenseTest {
.addInitializer(cmd -> {
// Create source license file.
Files.write(srcLicenseFile, List.of(
- licenseText.split("\\R", -1)));
+ licenseText().split("\\R", -1)));
cmd.setFakeRuntime();
- cmd.setArgumentValue("--name", String.format("%s%s",
- withSubstitution ? "CustomDebianCopyrightWithSubst" : "CustomDebianCopyright",
- cmd.name()));
+ cmd.setArgumentValue("--name", String.format("%s%s", name(), cmd.name()));
cmd.addArguments("--license-file", srcLicenseFile);
- cmd.addArguments("--copyright", copyright);
- cmd.addArguments("--resource-dir", RESOURCE_DIR);
+ cmd.addArguments("--copyright", copyright());
+
+ var resourceDir = TKit.createTempDirectory("resources");
+
+ cmd.addArguments("--resource-dir", resourceDir);
// Create copyright template file in a resource dir.
- Files.createDirectories(RESOURCE_DIR);
- Files.write(RESOURCE_DIR.resolve("copyright"),
- licenseFileText());
+ Files.write(resourceDir.resolve("copyright"), licenseFileText());
})
.addInstallVerifier(cmd -> {
Path installedLicenseFile = linuxLicenseFile(cmd);
@@ -368,12 +383,6 @@ public class LicenseTest {
})
.run();
}
-
- private boolean withSubstitution;
- private String copyright;
- private String licenseText;
-
- private final Path RESOURCE_DIR = TKit.workDir().resolve("resources");
}
private static final Path LICENSE_FILE = TKit.TEST_SRC_ROOT.resolve(
diff --git a/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java b/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java
index 7dcf025a506..d6cebde6444 100644
--- a/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java
+++ b/test/jdk/tools/jpackage/windows/WinInstallerUiTest.java
@@ -21,13 +21,15 @@
* questions.
*/
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
-import jdk.jpackage.test.PackageTest;
-import jdk.jpackage.test.JPackageCommand;
-import jdk.jpackage.test.Annotations.Test;
-import jdk.jpackage.test.Annotations.Parameters;
import java.util.List;
+import jdk.jpackage.internal.util.Slot;
+import jdk.jpackage.test.Annotations.Parameters;
+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;
@@ -108,11 +110,7 @@ public class WinInstallerUiTest {
}
if (withLicense) {
- test.addInitializer(cmd -> {
- cmd.addArguments("--license-file", TKit.createRelativePathCopy(
- TKit.TEST_SRC_ROOT.resolve(Path.of("resources",
- "license.txt"))));
- });
+ setLicenseFile(test);
}
test.run();
@@ -133,7 +131,21 @@ public class WinInstallerUiTest {
cmd.setArgumentValue("--name", sb.toString());
}
+ private static void setLicenseFile(PackageTest test) {
+ var inputLicenseFile = Slot.createEmpty();
+
+ test.addRunOnceInitializer(() -> {
+ var dir = TKit.createTempDirectory("license-dir");
+ inputLicenseFile.set(dir.resolve(LICENSE_FILE.getFileName()));
+ Files.copy(LICENSE_FILE, inputLicenseFile.get());
+ }).addInitializer(cmd -> {
+ cmd.setArgumentValue("--license-file", inputLicenseFile.get());
+ });
+ }
+
private final boolean withDirChooser;
private final boolean withLicense;
private final boolean withShortcutPrompt;
+
+ private static final Path LICENSE_FILE = TKit.TEST_SRC_ROOT.resolve(Path.of("resources", "license.txt"));
}