Skip to content

Commit 0714114

Browse files
author
Alexey Semenyuk
committed
8344322: Improve capabilities of jpackage test lib to validate error output of jpackage
Reviewed-by: almatvee
1 parent 41436bb commit 0714114

File tree

5 files changed

+217
-37
lines changed

5 files changed

+217
-37
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.jpackage.test;
24+
25+
import java.util.List;
26+
import java.util.function.BiFunction;
27+
28+
public final class CannedFormattedString {
29+
30+
CannedFormattedString(BiFunction<String, Object[], String> formatter,
31+
String key, Object[] args) {
32+
this.formatter = formatter;
33+
this.key = key;
34+
this.args = args;
35+
}
36+
37+
public String getValue() {
38+
return formatter.apply(key, args);
39+
}
40+
41+
@Override
42+
public String toString() {
43+
if (args.length == 0) {
44+
return String.format("%s", key);
45+
} else {
46+
return String.format("%s+%s", key, List.of(args));
47+
}
48+
}
49+
50+
private final BiFunction<String, Object[], String> formatter;
51+
private final String key;
52+
private final Object[] args;
53+
}

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java

+24
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public JPackageCommand(JPackageCommand cmd) {
7878
prerequisiteActions = new Actions(cmd.prerequisiteActions);
7979
verifyActions = new Actions(cmd.verifyActions);
8080
appLayoutAsserts = cmd.appLayoutAsserts;
81+
outputValidator = cmd.outputValidator;
8182
executeInDirectory = cmd.executeInDirectory;
8283
}
8384

@@ -739,6 +740,24 @@ public JPackageCommand ignoreDefaultVerbose(boolean v) {
739740
return this;
740741
}
741742

743+
public JPackageCommand validateOutput(TKit.TextStreamVerifier validator) {
744+
return JPackageCommand.this.validateOutput(validator::apply);
745+
}
746+
747+
public JPackageCommand validateOutput(Consumer<Stream<String>> validator) {
748+
if (validator != null) {
749+
saveConsoleOutput(true);
750+
outputValidator = validator;
751+
} else {
752+
outputValidator = null;
753+
}
754+
return this;
755+
}
756+
757+
public JPackageCommand validateOutput(CannedFormattedString str) {
758+
return JPackageCommand.this.validateOutput(TKit.assertTextStream(str.getValue()));
759+
}
760+
742761
public boolean isWithToolProvider() {
743762
return Optional.ofNullable(withToolProvider).orElse(
744763
defaultWithToolProvider);
@@ -817,6 +836,10 @@ public Executor.Result execute(int expectedExitCode) {
817836
.createExecutor()
818837
.execute(expectedExitCode);
819838

839+
if (outputValidator != null) {
840+
outputValidator.accept(result.getOutput().stream());
841+
}
842+
820843
if (result.exitCode == 0) {
821844
executeVerifyActions();
822845
}
@@ -1187,6 +1210,7 @@ public void run() {
11871210
private final Actions verifyActions;
11881211
private Path executeInDirectory;
11891212
private Set<AppLayoutAssert> appLayoutAsserts = Set.of(AppLayoutAssert.values());
1213+
private Consumer<Stream<String>> outputValidator;
11901214
private static boolean defaultWithToolProvider;
11911215

11921216
private static final Map<String, PackageType> PACKAGE_TYPES = Functional.identity(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package jdk.jpackage.test;
25+
26+
import java.lang.reflect.InvocationTargetException;
27+
import java.lang.reflect.Method;
28+
import java.text.MessageFormat;
29+
30+
public enum JPackageStringBundle {
31+
32+
MAIN("jdk.jpackage.internal.I18N"),
33+
;
34+
35+
JPackageStringBundle(String i18nClassName) {
36+
try {
37+
i18nClass = Class.forName(i18nClassName);
38+
39+
i18nClass_getString = i18nClass.getDeclaredMethod("getString", String.class);
40+
i18nClass_getString.setAccessible(true);
41+
} catch (ClassNotFoundException|NoSuchMethodException ex) {
42+
throw Functional.rethrowUnchecked(ex);
43+
}
44+
}
45+
46+
/**
47+
* Return a string value of the given key from jpackage resources.
48+
*/
49+
private String getString(String key) {
50+
try {
51+
return (String)i18nClass_getString.invoke(i18nClass, key);
52+
} catch (IllegalAccessException|InvocationTargetException ex) {
53+
throw Functional.rethrowUnchecked(ex);
54+
}
55+
}
56+
57+
private String getFormattedString(String key, Object[] args) {
58+
return MessageFormat.format(getString(key), args);
59+
}
60+
61+
public CannedFormattedString cannedFormattedString(String key, String ... args) {
62+
return new CannedFormattedString(this::getFormattedString, key, args);
63+
}
64+
65+
private final Class<?> i18nClass;
66+
private final Method i18nClass_getString;
67+
}

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java

+31-3
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,16 @@ public TextStreamVerifier negate() {
946946
return this;
947947
}
948948

949+
public TextStreamVerifier andThen(Consumer<? super Stream<String>> anotherVerifier) {
950+
this.anotherVerifier = anotherVerifier;
951+
return this;
952+
}
953+
954+
public TextStreamVerifier andThen(TextStreamVerifier anotherVerifier) {
955+
this.anotherVerifier = anotherVerifier::apply;
956+
return this;
957+
}
958+
949959
public TextStreamVerifier orElseThrow(RuntimeException v) {
950960
return orElseThrow(() -> v);
951961
}
@@ -956,9 +966,22 @@ public TextStreamVerifier orElseThrow(Supplier<RuntimeException> v) {
956966
}
957967

958968
public void apply(Stream<String> lines) {
959-
String matchedStr = lines.filter(line -> predicate.test(line, value)).findFirst().orElse(
960-
null);
961-
String labelStr = Optional.ofNullable(label).orElse("output");
969+
final String matchedStr;
970+
971+
lines = lines.dropWhile(line -> !predicate.test(line, value));
972+
if (anotherVerifier == null) {
973+
matchedStr = lines.findFirst().orElse(null);
974+
} else {
975+
var tail = lines.toList();
976+
if (tail.isEmpty()) {
977+
matchedStr = null;
978+
} else {
979+
matchedStr = tail.get(0);
980+
}
981+
lines = tail.stream().skip(1);
982+
}
983+
984+
final String labelStr = Optional.ofNullable(label).orElse("output");
962985
if (negate) {
963986
String msg = String.format(
964987
"Check %s doesn't contain [%s] string", labelStr, value);
@@ -982,12 +1005,17 @@ public void apply(Stream<String> lines) {
9821005
}
9831006
}
9841007
}
1008+
1009+
if (anotherVerifier != null) {
1010+
anotherVerifier.accept(lines);
1011+
}
9851012
}
9861013

9871014
private BiPredicate<String, String> predicate;
9881015
private String label;
9891016
private boolean negate;
9901017
private Supplier<RuntimeException> createException;
1018+
private Consumer<? super Stream<String>> anotherVerifier;
9911019
private final String value;
9921020
}
9931021

test/jdk/tools/jpackage/share/ErrorTest.java

+42-34
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@
2424

2525
import java.util.Collection;
2626
import java.util.List;
27-
import jdk.jpackage.test.Annotations.Parameters;
27+
import java.util.Optional;
28+
import java.util.stream.Stream;
29+
import jdk.jpackage.test.Annotations.ParameterSupplier;
2830
import jdk.jpackage.test.Annotations.Test;
31+
import jdk.jpackage.test.CannedFormattedString;
2932
import jdk.jpackage.test.JPackageCommand;
33+
import jdk.jpackage.test.JPackageStringBundle;
3034
import jdk.jpackage.test.TKit;
3135

3236
/*
@@ -53,81 +57,85 @@
5357

5458
public final class ErrorTest {
5559

56-
private final String expectedError;
57-
private final JPackageCommand cmd;
58-
59-
@Parameters
6060
public static Collection input() {
6161
return List.of(new Object[][]{
6262
// non-existent arg
6363
{"Hello",
6464
new String[]{"--no-such-argument"},
6565
null,
66-
"Invalid Option: [--no-such-argument]"},
66+
JPackageStringBundle.MAIN.cannedFormattedString("ERR_InvalidOption", "--no-such-argument")},
6767
// no main jar
6868
{"Hello",
6969
null,
7070
new String[]{"--main-jar"},
71-
"--main-jar or --module"},
71+
JPackageStringBundle.MAIN.cannedFormattedString("ERR_NoEntryPoint")},
7272
// no main-class
7373
{"Hello",
7474
null,
7575
new String[]{"--main-class"},
76-
"main class was not specified"},
76+
JPackageStringBundle.MAIN.cannedFormattedString("error.no-main-class-with-main-jar", "hello.jar"),
77+
JPackageStringBundle.MAIN.cannedFormattedString("error.no-main-class-with-main-jar.advice", "hello.jar")},
7778
// non-existent main jar
7879
{"Hello",
7980
new String[]{"--main-jar", "non-existent.jar"},
8081
null,
81-
"main jar does not exist"},
82+
JPackageStringBundle.MAIN.cannedFormattedString("error.main-jar-does-not-exist", "non-existent.jar")},
8283
// non-existent runtime
8384
{"Hello",
8485
new String[]{"--runtime-image", "non-existent.runtime"},
8586
null,
86-
"does not exist"},
87+
JPackageStringBundle.MAIN.cannedFormattedString("message.runtime-image-dir-does-not-exist", "runtime-image", "non-existent.runtime")},
8788
// non-existent resource-dir
8889
{"Hello",
8990
new String[]{"--resource-dir", "non-existent.dir"},
9091
null,
91-
"does not exist"},
92+
JPackageStringBundle.MAIN.cannedFormattedString("message.resource-dir-does-not-exist", "resource-dir", "non-existent.dir")},
9293
// invalid type
9394
{"Hello",
9495
new String[]{"--type", "invalid-type"},
9596
null,
96-
"Invalid or unsupported type: [invalid-type]"},
97+
JPackageStringBundle.MAIN.cannedFormattedString("ERR_InvalidInstallerType", "invalid-type")},
9798
// no --input
9899
{"Hello",
99100
null,
100101
new String[]{"--input"},
101-
"Missing argument: --input"},
102+
JPackageStringBundle.MAIN.cannedFormattedString("ERR_MissingArgument", "--input")},
102103
// no --module-path
103104
{"com.other/com.other.Hello",
104105
null,
105106
new String[]{"--module-path"},
106-
"Missing argument: --runtime-image or --module-path"},
107+
JPackageStringBundle.MAIN.cannedFormattedString("ERR_MissingArgument", "--runtime-image or --module-path")},
107108
});
108109
}
109110

110-
public ErrorTest(String javaAppDesc, String[] jpackageArgs,
111-
String[] removeArgs,
112-
String expectedError) {
113-
this.expectedError = expectedError;
111+
@Test
112+
@ParameterSupplier("input")
113+
public static void test(String javaAppDesc, String[] jpackageArgs,
114+
String[] removeArgs, CannedFormattedString... expectedErrors) {
115+
// Init default jpackage test command line.
116+
var cmd = JPackageCommand.helloAppImage(javaAppDesc)
117+
// Disable default logic adding `--verbose` option
118+
// to jpackage command line.
119+
// It will affect jpackage error messages if the command line is malformed.
120+
.ignoreDefaultVerbose(true)
121+
// Ignore external runtime as it will interfer
122+
// with jpackage arguments in this test.
123+
.ignoreDefaultRuntime(true);
114124

115-
cmd = JPackageCommand.helloAppImage(javaAppDesc)
116-
.saveConsoleOutput(true).dumpOutput(true);
117-
if (jpackageArgs != null) {
118-
cmd.addArguments(jpackageArgs);
119-
} if (removeArgs != null) {
120-
for (String arg : removeArgs) {
121-
cmd.removeArgumentWithValue(arg);
122-
}
123-
}
124-
}
125+
// Add arguments if requested.
126+
Optional.ofNullable(jpackageArgs).ifPresent(cmd::addArguments);
125127

126-
@Test
127-
public void test() {
128-
List<String> output = cmd.execute(1).getOutput();
129-
TKit.assertNotNull(output, "output is null");
130-
TKit.assertTextStream(expectedError).apply(output.stream());
131-
}
128+
// Remove arguments if requested.
129+
Optional.ofNullable(removeArgs).map(List::of).ifPresent(
130+
args -> args.forEach(cmd::removeArgumentWithValue));
131+
132+
// Configure jpackage output verifier to look up the list of provided
133+
// errors in the order they specified.
134+
cmd.validateOutput(Stream.of(expectedErrors)
135+
.map(CannedFormattedString::getValue)
136+
.map(TKit::assertTextStream)
137+
.reduce(TKit.TextStreamVerifier::andThen).get());
132138

139+
cmd.execute(1);
140+
}
133141
}

0 commit comments

Comments
 (0)