1 /*
   2  * Copyright (c) 2016, 2018, 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.* foo/* Main
  31  * @run testng MultiReleaseJar
  32  */
  33 
  34 import org.testng.Assert;
  35 import org.testng.annotations.AfterClass;
  36 import org.testng.annotations.BeforeClass;
  37 import org.testng.annotations.Test;
  38 
  39 import java.io.File;
  40 import java.io.InputStream;
  41 import java.nio.file.Path;
  42 import java.nio.file.Paths;
  43 import java.util.stream.Stream;
  44 
  45 public class MultiReleaseJar {
  46     Path mrjar;
  47     String testJdk;
  48     String fileSep;
  49     Path cmdPath;
  50 
  51     @BeforeClass
  52     public void initialize() throws Exception {
  53         String testClassPath = System.getProperty("test.class.path", "");
  54         mrjar = Stream.of(testClassPath.split(File.pathSeparator))
  55                       .map(Paths::get)
  56                       .filter(e -> e.endsWith("mrjar"))
  57                       .findAny()
  58                       .orElseThrow(() -> new InternalError("mrjar not found"));
  59         testJdk = System.getProperty("test.jdk");
  60         fileSep = System.getProperty("file.separator");
  61         cmdPath = Paths.get(testJdk, "bin");
  62 
  63         // build Version.jar, Version_9.jar and main.jar
  64         Result r = run("jar -cf Version.jar -C base test --release 9 -C 9 test --release 10 -C 10 test");
  65         checkResult(r);
  66 
  67         r = run("jar -cf Version_9.jar -C base test --release 9 -C 9 test");
  68         checkResult(r);
  69 
  70         r = run("jar -cf Main.jar Main.class");
  71         checkResult(r);
  72 
  73         r = run("jar -cf Foo.jar -C base p");
  74         checkResult(r);
  75 
  76         Path foo = Paths.get(System.getProperty("test.classes")).resolve("modules").resolve("foo");
  77         r = run("jar -uf Foo.jar --release 9 -C " + foo.toString() + " module-info.class --release 10 -C v10 q");
  78         checkResult(r);
  79     }
  80 
  81     @Test
  82     public void basic() throws Exception {
  83         Result r = run("jdeps --multi-release 9  -v missing.jar");
  84         checkResult(r, false, "Warning: Path does not exist: missing.jar");
  85 
  86         r = run("jdeps -v Version.jar");
  87         checkResult(r, false, "--multi-release option is not set");
  88 
  89         r = run("jdeps --multi-release base  -v Version.jar");
  90         checkResult(r, true,
  91             "Version.jar ->",
  92             "test.Version",
  93             "test.Version"
  94         );
  95 
  96         r = run("jdeps --multi-release 9  -v Version.jar");
  97         checkResult(r, true,
  98             "Version.jar ->",
  99             "9/test.NonPublic",
 100             "9/test.NonPublic",
 101             "9/test.Version",
 102             "9/test.Version",
 103             "9/test.Version",
 104             "9/test.Version"
 105         );
 106 
 107         r = run("jdeps --multi-release 10  -v Version.jar");
 108         checkResult(r, true,
 109             "Version.jar ->",
 110             "10/test.Version",
 111             "10/test.Version",
 112             "10/test.Version",
 113             "10/test.Version",
 114             "9/test.NonPublic",
 115             "9/test.NonPublic"
 116         );
 117 
 118         r = run("jdeps --multi-release 8  -v Version.jar");
 119         checkResult(r, false, "Error: invalid argument for option: 8");
 120 
 121         r = run("jdeps --multi-release 9.1  -v Version.jar");
 122         checkResult(r, false, "Error: invalid argument for option: 9.1");
 123 
 124         runJdeps("Main.class");
 125         runJdeps("Main.jar");
 126     }
 127 
 128 
 129     private void runJdeps(String path) throws Exception {
 130         Result r = run("jdeps -v -R -cp Version.jar " + path);
 131         checkResult(r, false, "--multi-release option is not set");
 132 
 133         r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar -multi-release 9 " + path);
 134         checkResult(r, false,
 135             "Error: unknown option: -multi-release",
 136             "Usage: jdeps <options> <path",
 137             "use --help"
 138         );
 139 
 140         r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 9 " + path);
 141 
 142         String name = path;
 143         int index = path.lastIndexOf('/');
 144         if (index >= 0) {
 145             name = path.substring(index + 1, path.length());
 146         }
 147         checkResult(r, true,
 148             name + " -> Version.jar",
 149             name + " -> foo",
 150             name + " -> java.base",
 151             "Main",
 152             "Main",
 153             "Main",
 154             "Main",
 155             "Version.jar -> java.base",
 156             "9/test.NonPublic",
 157             "9/test.NonPublic",
 158             "9/test.Version",
 159             "9/test.Version",
 160             "9/test.Version",
 161             "9/test.Version",
 162             "foo",
 163             "Foo.jar",
 164             "requires mandated java.base",
 165             "foo -> java.base",
 166             "p.Foo"
 167         );
 168 
 169         r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 10 " + path);
 170         checkResult(r, true,
 171             name + " -> Version.jar",
 172             name + " -> foo",
 173             name + " -> java.base",
 174             "Main",
 175             "Main",
 176             "Main",
 177             "Main",
 178             "Version.jar ->",
 179             "10/test.Version",
 180             "10/test.Version",
 181             "10/test.Version",
 182             "10/test.Version",
 183             "9/test.NonPublic",
 184             "9/test.NonPublic",
 185             "foo",
 186             "Foo.jar",
 187             "requires mandated java.base",
 188             "foo -> java.base",
 189             "p.Foo"
 190         );
 191 
 192         r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release base " + path);
 193         checkResult(r, true,
 194             name + " -> Version.jar",
 195             name + " -> foo",
 196             name + " -> java.base",
 197             "Main",
 198             "Main",
 199             "Main",
 200             "Main",
 201             "Version.jar ->",
 202             "test.Version",
 203             "test.Version",
 204             "foo",
 205             "Foo.jar",
 206             "requires mandated java.base",
 207             "foo -> java.base",
 208             "p.Foo"
 209         );
 210 
 211         r = run("jdeps -v -R -cp Version.jar --module-path  Foo.jar --multi-release 9.1 " + path);
 212         checkResult(r, false, "Error: invalid argument for option: 9.1");
 213 
 214         // Version_9.jar does not have any version 10 entry
 215         r = run("jdeps -v -R -cp Version_9.jar --module-path Foo.jar --multi-release 10 " + path);
 216         checkResult(r, true,
 217             name + " -> Version_9.jar",
 218             name + " -> foo",
 219             name + " -> java.base",
 220             "Main",
 221             "Main",
 222             "Main",
 223             "Main",
 224             "Version_9.jar ->",
 225             "9/test.NonPublic",
 226             "9/test.NonPublic",
 227             "9/test.Version",
 228             "9/test.Version",
 229             "9/test.Version",
 230             "9/test.Version",
 231             "foo",
 232             "Foo.jar",
 233             "requires mandated java.base",
 234             "foo -> java.base",
 235             "p.Foo"
 236         );
 237     }
 238 
 239     @Test
 240     public void ps_and_qs() throws Exception {
 241         // build the jar file
 242         Result r = run("jar -cf PQ.jar -C base p --release 9 -C v9 p -C v9 q --release 10 -C v10 q");
 243         checkResult(r);
 244 
 245         r = run("jdeps -v -R -cp PQ.jar --multi-release base PQ.jar");
 246         checkResult(r, true,
 247             "PQ.jar -> java.base",
 248             "p.Foo"
 249         );
 250 
 251         r = run("jdeps -v -R -cp PQ.jar --multi-release 9 PQ.jar");
 252         checkResult(r, true,
 253             "PQ.jar -> java.base",
 254             "9/p.Foo",
 255             "9/p.Foo",
 256             "9/q.Bar"
 257         );
 258 
 259 
 260         r = run("jdeps -v -R -cp PQ.jar --multi-release 10 PQ.jar");
 261         checkResult(r, true,
 262             "PQ.jar -> java.base",
 263             "10/q.Bar",
 264             "10/q.Bar",
 265             "10/q.Gee",
 266             "9/p.Foo",
 267             "9/p.Foo"
 268         );
 269     }
 270 
 271     @Test
 272     public void modularJar() throws Exception {
 273         Result r = run("jdeps -v --multi-release 10 --module-path Foo.jar -m foo");
 274         checkResult(r, true,
 275             "foo",                   // module name
 276             "Foo.jar",                      // the path to Foo.jar
 277             "requires mandated java.base",  // module dependences
 278             "foo -> java.base",
 279             "10/q.Bar",
 280             "10/q.Bar",
 281             "10/q.Gee",
 282             "p.Foo"
 283         );
 284 
 285         r = run("jdeps --multi-release 9 -cp Version.jar --module-path Foo.jar Main.jar");
 286         checkResult(r, true,
 287             "Main.jar -> Version.jar",
 288             "Main.jar -> foo",
 289             "Main.jar -> java.base",
 290             "-> java.lang",
 291             "-> p",
 292             "-> test"
 293         );
 294 
 295         r = run("jdeps --multi-release 10 -cp Version.jar --module-path Foo.jar Main.jar");
 296         checkResult(r, true,
 297             "Main.jar -> Version.jar",
 298             "Main.jar -> foo",
 299             "Main.jar -> java.base",
 300             "-> java.lang",
 301             "-> p",
 302             "-> test"
 303         );
 304     }
 305 
 306     static class Result {
 307         final String cmd;
 308         final int rc;
 309         final String out;
 310         final String err;
 311         Result(String cmd, int rc, String out, String err) {
 312             this.cmd = cmd;
 313             this.rc = rc;
 314             this.out = out;
 315             this.err = err;
 316         }
 317     }
 318 
 319     Result run(String cmd) throws Exception {
 320         String[] cmds = cmd.split(" +");
 321         cmds[0] = cmdPath.resolve(cmds[0]).toString();
 322         ProcessBuilder pb = new ProcessBuilder(cmds);
 323         pb.directory(mrjar.toFile());
 324         Process p = null;
 325         try {
 326             p = pb.start();
 327             p.waitFor();
 328 
 329             String out;
 330             try (InputStream is = p.getInputStream()) {
 331                 out = new String(is.readAllBytes());
 332             }
 333             String err;
 334             try (InputStream is = p.getErrorStream()) {
 335                 err = new String(is.readAllBytes());
 336             }
 337             return new Result(cmd, p.exitValue(), out, err);
 338         } catch (Throwable t) {
 339             if (p != null) {
 340                 p.destroyForcibly().waitFor();
 341             }
 342             throw t;
 343         }
 344     }
 345 
 346     void checkResult(Result r) throws Exception {
 347         System.out.println(r.cmd);
 348         System.out.println(r.out);
 349         if (r.rc != 0) {
 350             System.out.println(r.err);
 351             throw new Exception("rc=" + r.rc);
 352         }
 353         System.out.println();
 354     }
 355 
 356     void checkResult(Result r, boolean checkrc, String... lines) throws Exception {
 357         System.out.println(r.cmd);
 358         System.out.println(r.out);
 359         if (checkrc && r.rc != 0) {
 360             System.out.println(r.err);
 361             throw new Exception("rc=" + r.rc);
 362         }
 363         String[] out = r.out.split("\r?\n");
 364         Assert.assertEquals(out.length, lines.length);
 365         int n = 0;
 366         for (String line : lines) {
 367             Assert.assertTrue(out[n++].contains(line), "\"" + line + "\"");
 368         }
 369         System.out.println();
 370     }
 371 }