|
23 | 23 |
|
24 | 24 | package jdk.jpackage.test;
|
25 | 25 |
|
| 26 | +import static java.util.stream.Collectors.groupingBy; |
| 27 | +import static java.util.stream.Collectors.mapping; |
| 28 | +import static java.util.stream.Collectors.toList; |
| 29 | +import static java.util.stream.Collectors.toMap; |
| 30 | +import static java.util.stream.Collectors.toSet; |
| 31 | +import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; |
| 32 | + |
26 | 33 | import java.io.FileOutputStream;
|
27 | 34 | import java.io.IOException;
|
28 | 35 | import java.nio.charset.StandardCharsets;
|
29 | 36 | import java.nio.file.Files;
|
| 37 | +import java.nio.file.InvalidPathException; |
30 | 38 | import java.nio.file.Path;
|
31 | 39 | import java.security.SecureRandom;
|
32 | 40 | import java.util.ArrayList;
|
|
46 | 54 | import java.util.regex.Pattern;
|
47 | 55 | import java.util.stream.Collectors;
|
48 | 56 | import java.util.stream.Stream;
|
49 |
| -import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher; |
50 | 57 | import jdk.jpackage.internal.util.function.ThrowingConsumer;
|
51 | 58 | import jdk.jpackage.internal.util.function.ThrowingFunction;
|
52 | 59 | import jdk.jpackage.internal.util.function.ThrowingRunnable;
|
@@ -78,6 +85,7 @@ public JPackageCommand(JPackageCommand cmd) {
|
78 | 85 | prerequisiteActions = new Actions(cmd.prerequisiteActions);
|
79 | 86 | verifyActions = new Actions(cmd.verifyActions);
|
80 | 87 | appLayoutAsserts = cmd.appLayoutAsserts;
|
| 88 | + readOnlyPathAsserts = cmd.readOnlyPathAsserts; |
81 | 89 | outputValidators = cmd.outputValidators;
|
82 | 90 | executeInDirectory = cmd.executeInDirectory;
|
83 | 91 | winMsiLogFile = cmd.winMsiLogFile;
|
@@ -843,10 +851,13 @@ public Executor.Result execute(int expectedExitCode) {
|
843 | 851 | }
|
844 | 852 | }
|
845 | 853 |
|
846 |
| - Executor.Result result = new JPackageCommand(this) |
847 |
| - .adjustArgumentsBeforeExecution() |
848 |
| - .createExecutor() |
849 |
| - .execute(expectedExitCode); |
| 854 | + final var copy = new JPackageCommand(this).adjustArgumentsBeforeExecution(); |
| 855 | + |
| 856 | + final var directoriesAssert = new ReadOnlyPathsAssert(copy); |
| 857 | + |
| 858 | + Executor.Result result = copy.createExecutor().execute(expectedExitCode); |
| 859 | + |
| 860 | + directoriesAssert.updateAndAssert(); |
850 | 861 |
|
851 | 862 | for (final var outputValidator: outputValidators) {
|
852 | 863 | outputValidator.accept(result.getOutput().iterator());
|
@@ -903,6 +914,136 @@ public String macroValue(Macro macro) {
|
903 | 914 | return macro.value(this);
|
904 | 915 | }
|
905 | 916 |
|
| 917 | + private static final class ReadOnlyPathsAssert { |
| 918 | + ReadOnlyPathsAssert(JPackageCommand cmd) { |
| 919 | + this.asserts = cmd.readOnlyPathAsserts.stream().map(a -> { |
| 920 | + return a.getPaths(cmd).stream().map(dir -> { |
| 921 | + return Map.entry(a, dir); |
| 922 | + }); |
| 923 | + }).flatMap(x -> x).collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList()))); |
| 924 | + snapshots = createSnapshots(); |
| 925 | + } |
| 926 | + |
| 927 | + void updateAndAssert() { |
| 928 | + final var newSnapshots = createSnapshots(); |
| 929 | + for (final var a : asserts.keySet().stream().sorted().toList()) { |
| 930 | + final var snapshopGroup = snapshots.get(a); |
| 931 | + final var newSnapshopGroup = newSnapshots.get(a); |
| 932 | + for (int i = 0; i < snapshopGroup.size(); i++) { |
| 933 | + TKit.PathSnapshot.assertEquals(snapshopGroup.get(i), newSnapshopGroup.get(i), |
| 934 | + String.format("Check jpackage didn't modify ${%s}=[%s]", a, asserts.get(a).get(i))); |
| 935 | + } |
| 936 | + } |
| 937 | + } |
| 938 | + |
| 939 | + private Map<ReadOnlyPathAssert, List<TKit.PathSnapshot>> createSnapshots() { |
| 940 | + return asserts.entrySet().stream() |
| 941 | + .map(e -> { |
| 942 | + return Map.entry(e.getKey(), e.getValue().stream().map(TKit.PathSnapshot::new).toList()); |
| 943 | + }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); |
| 944 | + } |
| 945 | + |
| 946 | + private final Map<ReadOnlyPathAssert, List<Path>> asserts; |
| 947 | + private final Map<ReadOnlyPathAssert, List<TKit.PathSnapshot>> snapshots; |
| 948 | + } |
| 949 | + |
| 950 | + public static enum ReadOnlyPathAssert{ |
| 951 | + APP_IMAGE(new Builder("--app-image").enable(cmd -> { |
| 952 | + // External app image should be R/O unless it is an app image signing on macOS. |
| 953 | + return !(TKit.isOSX() && MacHelper.signPredefinedAppImage(cmd)); |
| 954 | + }).create()), |
| 955 | + APP_CONTENT(new Builder("--app-content").multiple().create()), |
| 956 | + RESOURCE_DIR(new Builder("--resource-dir").create()), |
| 957 | + MAC_DMG_CONTENT(new Builder("--mac-dmg-content").multiple().create()), |
| 958 | + RUNTIME_IMAGE(new Builder("--runtime-image").create()); |
| 959 | + |
| 960 | + ReadOnlyPathAssert(Function<JPackageCommand, List<Path>> getPaths) { |
| 961 | + this.getPaths = getPaths; |
| 962 | + } |
| 963 | + |
| 964 | + List<Path> getPaths(JPackageCommand cmd) { |
| 965 | + return getPaths.apply(cmd).stream().toList(); |
| 966 | + } |
| 967 | + |
| 968 | + private final static class Builder { |
| 969 | + |
| 970 | + Builder(String argName) { |
| 971 | + this.argName = Objects.requireNonNull(argName); |
| 972 | + } |
| 973 | + |
| 974 | + Builder multiple() { |
| 975 | + multiple = true; |
| 976 | + return this; |
| 977 | + } |
| 978 | + |
| 979 | + Builder enable(Predicate<JPackageCommand> v) { |
| 980 | + enable = v; |
| 981 | + return this; |
| 982 | + } |
| 983 | + |
| 984 | + Function<JPackageCommand, List<Path>> create() { |
| 985 | + return cmd -> { |
| 986 | + if (enable != null && !enable.test(cmd)) { |
| 987 | + return List.of(); |
| 988 | + } else { |
| 989 | + final List<Optional<Path>> dirs; |
| 990 | + if (multiple) { |
| 991 | + dirs = Stream.of(cmd.getAllArgumentValues(argName)) |
| 992 | + .map(Builder::tokenizeValue) |
| 993 | + .flatMap(x -> x) |
| 994 | + .map(Builder::toExistingFile).toList(); |
| 995 | + } else { |
| 996 | + dirs = Optional.ofNullable(cmd.getArgumentValue(argName)) |
| 997 | + .map(Builder::toExistingFile).map(List::of).orElseGet(List::of); |
| 998 | + } |
| 999 | + |
| 1000 | + final var mutablePaths = Stream.of("--temp", "--dest") |
| 1001 | + .map(cmd::getArgumentValue) |
| 1002 | + .filter(Objects::nonNull) |
| 1003 | + .map(Builder::toExistingFile) |
| 1004 | + .filter(Optional::isPresent).map(Optional::orElseThrow) |
| 1005 | + .collect(toSet()); |
| 1006 | + |
| 1007 | + return dirs.stream() |
| 1008 | + .filter(Optional::isPresent).map(Optional::orElseThrow) |
| 1009 | + .filter(Predicate.not(mutablePaths::contains)) |
| 1010 | + .toList(); |
| 1011 | + } |
| 1012 | + }; |
| 1013 | + } |
| 1014 | + |
| 1015 | + private static Optional<Path> toExistingFile(String path) { |
| 1016 | + Objects.requireNonNull(path); |
| 1017 | + try { |
| 1018 | + return Optional.of(Path.of(path)).filter(Files::exists).map(Path::toAbsolutePath); |
| 1019 | + } catch (InvalidPathException ex) { |
| 1020 | + return Optional.empty(); |
| 1021 | + } |
| 1022 | + } |
| 1023 | + |
| 1024 | + private static Stream<String> tokenizeValue(String str) { |
| 1025 | + return Stream.of(str.split(",")); |
| 1026 | + } |
| 1027 | + |
| 1028 | + private Predicate<JPackageCommand> enable; |
| 1029 | + private final String argName; |
| 1030 | + private boolean multiple; |
| 1031 | + } |
| 1032 | + |
| 1033 | + private final Function<JPackageCommand, List<Path>> getPaths; |
| 1034 | + } |
| 1035 | + |
| 1036 | + public JPackageCommand setReadOnlyPathAsserts(ReadOnlyPathAssert... asserts) { |
| 1037 | + readOnlyPathAsserts = Set.of(asserts); |
| 1038 | + return this; |
| 1039 | + } |
| 1040 | + |
| 1041 | + public JPackageCommand excludeReadOnlyPathAssert(ReadOnlyPathAssert... asserts) { |
| 1042 | + var asSet = Set.of(asserts); |
| 1043 | + return setReadOnlyPathAsserts(readOnlyPathAsserts.stream().filter(Predicate.not( |
| 1044 | + asSet::contains)).toArray(ReadOnlyPathAssert[]::new)); |
| 1045 | + } |
| 1046 | + |
906 | 1047 | public static enum AppLayoutAssert {
|
907 | 1048 | APP_IMAGE_FILE(JPackageCommand::assertAppImageFile),
|
908 | 1049 | PACKAGE_FILE(JPackageCommand::assertPackageFile),
|
@@ -1320,6 +1461,7 @@ public void run() {
|
1320 | 1461 | private final Actions verifyActions;
|
1321 | 1462 | private Path executeInDirectory;
|
1322 | 1463 | private Path winMsiLogFile;
|
| 1464 | + private Set<ReadOnlyPathAssert> readOnlyPathAsserts = Set.of(ReadOnlyPathAssert.values()); |
1323 | 1465 | private Set<AppLayoutAssert> appLayoutAsserts = Set.of(AppLayoutAssert.values());
|
1324 | 1466 | private List<Consumer<Iterator<String>>> outputValidators = new ArrayList<>();
|
1325 | 1467 | private static boolean defaultWithToolProvider;
|
|
0 commit comments