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