1/*
2 * Copyright (c) 2016, 2017, 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/*
25 * @test
26 * @bug 8153654 8176333
27 * @summary Tests for jdeps tool with multi-release jar files
28 * @modules jdk.jdeps/com.sun.tools.jdeps
29 * @library mrjar mrjar/base mrjar/9 mrjar/10 mrjar/v9 mrjar/v10
30 * @build test.* p.* q.*
31 * @run testng MultiReleaseJar
32 */
33
34import org.testng.Assert;
35import org.testng.annotations.AfterClass;
36import org.testng.annotations.BeforeClass;
37import org.testng.annotations.Test;
38
39import java.io.File;
40import java.io.IOException;
41import java.io.InputStream;
42import java.nio.file.Path;
43import java.nio.file.Paths;
44import java.util.concurrent.TimeUnit;
45import java.util.stream.Stream;
46
47public class MultiReleaseJar {
48    Path mrjar;
49    String testJdk;
50    String fileSep;
51    Path cmdPath;
52
53    @BeforeClass
54    public void initialize() throws Exception {
55        String testClassPath = System.getProperty("test.class.path", "");
56        mrjar = Stream.of(testClassPath.split(File.pathSeparator))
57                .map(Paths::get)
58                .filter(e -> e.endsWith("mrjar"))
59                .findAny()
60                .orElseThrow(() -> new InternalError("mrjar not found"));
61        testJdk = System.getProperty("test.jdk");
62        fileSep = System.getProperty("file.separator");
63        cmdPath = Paths.get(testJdk, "bin");
64    }
65
66    @Test
67    public void basic() throws Exception {
68        // build the jar file
69        Result r = run("jar -cf Version.jar -C base test --release 9 -C 9 test --release 10 -C 10 test");
70        checkResult(r);
71
72        // try out a bunch of things
73        r = run("jdeps --multi-release 9  -v missing.jar");
74        checkResult(r, false, "Warning: Path does not exist: missing.jar");
75
76        r = run("jdeps -v Version.jar");
77        checkResult(r, false, "--multi-release option is not set");
78
79        r = run("jdeps --multi-release base  -v Version.jar");
80        checkResult(r, true,
81                "Version.jar ->",
82                "test.Version",
83                "test.Version"
84        );
85
86        r = run("jdeps --multi-release 9  -v Version.jar");
87        checkResult(r, true,
88                "Version.jar ->",
89                "9/test.NonPublic",
90                "9/test.NonPublic",
91                "9/test.Version",
92                "9/test.Version",
93                "9/test.Version",
94                "9/test.Version"
95        );
96
97        r = run("jdeps --multi-release 10  -v Version.jar");
98        checkResult(r, true,
99                "Version.jar ->",
100                "10/test.Version",
101                "10/test.Version",
102                "10/test.Version",
103                "10/test.Version",
104                "9/test.NonPublic",
105                "9/test.NonPublic"
106        );
107
108        r = run("jdeps --multi-release 8  -v Version.jar");
109        checkResult(r, false, "Error: invalid argument for option: 8");
110
111        r = run("jdeps --multi-release 9.1  -v Version.jar");
112        checkResult(r, false, "Error: invalid argument for option: 9.1");
113
114        r = run("jdeps -v -R -cp Version.jar test/Main.class");
115        checkResult(r, false, "--multi-release option is not set");
116
117        r = run("jdeps -v -R -cp Version.jar -multi-release 9 test/Main.class");
118        checkResult(r, false,
119                "Error: unknown option: -multi-release",
120                "Usage: jdeps <options> <path",
121                "use -h, -?, -help, or --help"
122        );
123
124        r = run("jdeps -v -R -cp Version.jar --multi-release 9 test/Main.class");
125        checkResult(r, true,
126                "Main.class ->",
127                "Main.class ->",
128                "test.Main",
129                "test.Main",
130                "test.Main",
131                "Version.jar ->",
132                "9/test.NonPublic",
133                "9/test.NonPublic",
134                "9/test.Version",
135                "9/test.Version",
136                "9/test.Version",
137                "9/test.Version"
138        );
139
140        r = run("jdeps -v -R -cp Version.jar --multi-release 10 test/Main.class");
141        checkResult(r, true,
142                "Main.class ->",
143                "Main.class ->",
144                "test.Main",
145                "test.Main",
146                "test.Main",
147                "Version.jar ->",
148                "10/test.Version",
149                "10/test.Version",
150                "10/test.Version",
151                "10/test.Version",
152                "9/test.NonPublic",
153                "9/test.NonPublic"
154        );
155
156        r = run("jdeps -v -R -cp Version.jar --multi-release base test/Main.class");
157        checkResult(r, true,
158                "Main.class ->",
159                "Main.class ->",
160                "test.Main",
161                "test.Main",
162                "test.Main",
163                "Version.jar ->",
164                "test.Version",
165                "test.Version"
166        );
167
168        r = run("jdeps -v -R -cp Version.jar --multi-release 9.1 test/Main.class");
169        checkResult(r, false, "Error: invalid argument for option: 9.1");
170
171        // Rebuild jar without version 10
172        r = run("jar -cf Version.jar -C base test --release 9 -C 9 test");
173        checkResult(r);
174
175        // but ask for version 10
176        r = run("jdeps -v -R -cp Version.jar --multi-release 10 test/Main.class");
177        checkResult(r, true,
178                "Main.class ->",
179                "Main.class ->",
180                "test.Main",
181                "test.Main",
182                "test.Main",
183                "Version.jar ->",
184                "9/test.NonPublic",
185                "9/test.NonPublic",
186                "9/test.Version",
187                "9/test.Version",
188                "9/test.Version",
189                "9/test.Version"
190        );
191    }
192
193    @Test
194    public void ps_and_qs() throws Exception {
195        // build the jar file
196        Result r = run("jar -cf PQ.jar -C base p --release 9 -C v9 p -C v9 q --release 10 -C v10 q");
197        checkResult(r);
198
199        r = run("jdeps -v -R -cp PQ.jar --multi-release base PQ.jar");
200        checkResult(r, true,
201                "PQ.jar -> java.base",
202                "p.Foo"
203        );
204
205        r = run("jdeps -v -R -cp PQ.jar --multi-release 9 PQ.jar");
206        checkResult(r, true,
207                "PQ.jar -> java.base",
208                "9/p.Foo",
209                "9/p.Foo",
210                "9/q.Bar"
211        );
212
213
214        r = run("jdeps -v -R -cp PQ.jar --multi-release 10 PQ.jar");
215        checkResult(r, true,
216                "PQ.jar -> java.base",
217                "10/q.Bar",
218                "10/q.Bar",
219                "10/q.Gee",
220                "9/p.Foo",
221                "9/p.Foo"
222        );
223    }
224
225    static class Result {
226        final String cmd;
227        final int rc;
228        final String out;
229        final String err;
230        Result(String cmd, int rc, String out, String err) {
231            this.cmd = cmd;
232            this.rc = rc;
233            this.out = out;
234            this.err = err;
235        }
236    }
237
238    Result run(String cmd) throws Exception {
239        String[] cmds = cmd.split(" +");
240        cmds[0] = cmdPath.resolve(cmds[0]).toString();
241        ProcessBuilder pb = new ProcessBuilder(cmds);
242        pb.directory(mrjar.toFile());
243        Process p = pb.start();
244        p.waitFor(10, TimeUnit.SECONDS);
245        String out;
246        try (InputStream is = p.getInputStream()) {
247            out = new String(is.readAllBytes());
248        }
249        String err;
250        try (InputStream is = p.getErrorStream()) {
251            err = new String(is.readAllBytes());
252        }
253        return new Result(cmd, p.exitValue(), out, err);
254    }
255
256    void checkResult(Result r) throws Exception {
257        System.out.println(r.cmd);
258        System.out.println(r.out);
259        if (r.rc != 0) {
260            System.out.println(r.err);
261            throw new Exception("rc=" + r.rc);
262        }
263        System.out.println();
264    }
265
266    void checkResult(Result r, boolean checkrc, String... lines) throws Exception {
267        System.out.println(r.cmd);
268        System.out.println(r.out);
269        if (checkrc && r.rc != 0) {
270            System.out.println(r.err);
271            throw new Exception("rc=" + r.rc);
272        }
273        String[] out = r.out.split("\r?\n");
274        Assert.assertEquals(out.length, lines.length);
275        int n = 0;
276        for (String line : lines) {
277            Assert.assertTrue(out[n++].contains(line), "\"" + line + "\"");
278        }
279        System.out.println();
280    }
281}
282