1 /*
   2  * Copyright (c) 2015, 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  * @library /test/lib
  27  * @modules jdk.compiler
  28  *          jdk.naming.dns
  29  * @build PatchTest JarUtils
  30  *        jdk.test.lib.compiler.CompilerUtils
  31  * @run testng PatchTest
  32  * @summary Basic test for --patch-module
  33  */
  34 
  35 import java.io.File;
  36 import java.nio.file.Files;
  37 import java.nio.file.Path;
  38 import java.nio.file.Paths;
  39 import java.util.stream.Collectors;
  40 import java.util.stream.Stream;
  41 
  42 import jdk.test.lib.compiler.CompilerUtils;
  43 import static jdk.test.lib.process.ProcessTools.*;
  44 
  45 import org.testng.annotations.BeforeTest;
  46 import org.testng.annotations.Test;
  47 import static org.testng.Assert.*;
  48 
  49 /**
  50  * Compiles and launches a test that uses --patch-module with two directories
  51  * of classes to override existing classes and add new classes to modules in
  52  * the boot layer.
  53  *
  54  * The classes overridden or added via --patch-module all define a public
  55  * no-arg constructor and override toString to return "hi". This allows the
  56  * launched test to check that the overridden classes are loaded.
  57  */
  58 
  59 @Test
  60 public class PatchTest {
  61 
  62     // top-level source directory
  63     private static final String TEST_SRC = System.getProperty("test.src");
  64 
  65     // source/destination tree for the test module
  66     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
  67     private static final Path MODS_DIR = Paths.get("mods");
  68 
  69     // source/destination tree for patch tree 1
  70     private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1");
  71     private static final Path PATCHES1_DIR = Paths.get("patches1");
  72 
  73     // source/destination tree for patch tree 2
  74     private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
  75     private static final Path PATCHES2_DIR = Paths.get("patches2");
  76 
  77     // destination directory for patches packaged as JAR files
  78     private static final Path PATCHES_DIR = Paths.get("patches");
  79 
  80 
  81     // the classes overridden or added with --patch-module
  82     private static final String[] CLASSES = {
  83 
  84         // java.base = boot loader
  85         "java.base/java.text.Annotation",           // override class
  86         "java.base/java.text.AnnotationBuddy",      // add class to package
  87         "java.base/java.lang2.Object",              // new package
  88 
  89         // jdk.naming.dns = platform class loader
  90         "jdk.naming.dns/com.sun.jndi.dns.DnsClient",
  91         "jdk.naming.dns/com.sun.jndi.dns.DnsClientBuddy",
  92         "jdk.naming.dns/com.sun.jndi.dns2.Zone",
  93 
  94         // jdk.compiler = application class loaded
  95         "jdk.compiler/com.sun.tools.javac.Main",
  96         "jdk.compiler/com.sun.tools.javac.MainBuddy",
  97         "jdk.compiler/com.sun.tools.javac2.Main",
  98 
  99     };
 100 
 101 
 102     @BeforeTest
 103     public void setup() throws Exception {
 104 
 105         // javac -d mods/test src/test/**
 106         boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
 107                                                 MODS_DIR.resolve("test"));
 108         assertTrue(compiled, "classes did not compile");
 109 
 110         // javac --patch-module $MODULE=patches1/$MODULE -d patches1/$MODULE patches1/$MODULE/**
 111         // jar cf patches/$MODULE-1.jar -C patches1/$MODULE .
 112         for (Path src : Files.newDirectoryStream(SRC1_DIR)) {
 113             Path output = PATCHES1_DIR.resolve(src.getFileName());
 114             String mn = src.getFileName().toString();
 115             compiled  = CompilerUtils.compile(src, output,
 116                                               "--patch-module", mn + "=" + src.toString());
 117             assertTrue(compiled, "classes did not compile");
 118             JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-1.jar"), output);
 119         }
 120 
 121         // javac --patch-module $MODULE=patches2/$MODULE -d patches2/$MODULE patches2/$MODULE/**
 122         // jar cf patches/$MODULE-2.jar -C patches2/$MODULE .
 123         for (Path src : Files.newDirectoryStream(SRC2_DIR)) {
 124             Path output = PATCHES2_DIR.resolve(src.getFileName());
 125             String mn = src.getFileName().toString();
 126             compiled  = CompilerUtils.compile(src, output,
 127                                               "--patch-module", mn + "=" + src.toString());
 128             assertTrue(compiled, "classes did not compile");
 129             JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-2.jar"), output);
 130         }
 131 
 132     }
 133 
 134     /**
 135      * Run test with patches to java.base, jdk.naming.dns and jdk.compiler
 136      */
 137     void runTest(String basePatches, String dnsPatches, String compilerPatches)
 138         throws Exception
 139     {
 140         // the argument to the test is the list of classes overridden or added
 141         String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
 142 
 143         int exitValue
 144             =  executeTestJava("--patch-module", "java.base=" + basePatches,
 145                                "--patch-module", "jdk.naming.dns=" + dnsPatches,
 146                                "--patch-module", "jdk.compiler=" + compilerPatches,
 147                                "--add-exports", "java.base/java.lang2=test",
 148                                "--add-exports", "jdk.naming.dns/com.sun.jndi.dns=test",
 149                                "--add-exports", "jdk.naming.dns/com.sun.jndi.dns2=test",
 150                                "--add-exports", "jdk.compiler/com.sun.tools.javac2=test",
 151                                "--add-modules", "jdk.naming.dns,jdk.compiler",
 152                                "--module-path", MODS_DIR.toString(),
 153                                "-m", "test/jdk.test.Main", arg)
 154                 .outputTo(System.out)
 155                 .errorTo(System.out)
 156                 .getExitValue();
 157 
 158         assertTrue(exitValue == 0);
 159     }
 160 
 161 
 162     /**
 163      * Run test with ---patch-module and exploded patches
 164      */
 165     public void testWithExplodedPatches() throws Exception {
 166 
 167         // patches1/java.base:patches2/java.base
 168         String basePatches = PATCHES1_DIR.resolve("java.base")
 169                 + File.pathSeparator + PATCHES2_DIR.resolve("java.base");
 170 
 171         String dnsPatches = PATCHES1_DIR.resolve("jdk.naming.dns")
 172                 + File.pathSeparator + PATCHES2_DIR.resolve("jdk.naming.dns");
 173 
 174         String compilerPatches = PATCHES1_DIR.resolve("jdk.compiler")
 175                 + File.pathSeparator + PATCHES2_DIR.resolve("jdk.compiler");
 176 
 177         runTest(basePatches, dnsPatches, compilerPatches);
 178     }
 179 
 180 
 181     /**
 182      * Run test with ---patch-module and patches in JAR files
 183      */
 184     public void testWithJarPatches() throws Exception {
 185 
 186         // patches/java.base-1.jar:patches/java-base-2.jar
 187         String basePatches = PATCHES_DIR.resolve("java.base-1.jar")
 188                 + File.pathSeparator + PATCHES_DIR.resolve("java.base-2.jar");
 189 
 190         String dnsPatches = PATCHES_DIR.resolve("jdk.naming.dns-1.jar")
 191                 +  File.pathSeparator + PATCHES_DIR.resolve("jdk.naming.dns-2.jar");
 192 
 193         String compilerPatches = PATCHES_DIR.resolve("jdk.compiler-1.jar")
 194                 +  File.pathSeparator + PATCHES_DIR.resolve("jdk.compiler-2.jar");
 195 
 196         runTest(basePatches, dnsPatches, compilerPatches);
 197 
 198     }
 199 
 200 
 201     /**
 202      * Run test with ---patch-module and patches in JAR files and exploded patches
 203      */
 204     public void testWithJarAndExplodedPatches() throws Exception {
 205 
 206         // patches/java.base-1.jar:patches2/java.base
 207         String basePatches = PATCHES_DIR.resolve("java.base-1.jar")
 208                 + File.pathSeparator + PATCHES2_DIR.resolve("java.base");
 209 
 210         // patches1/jdk.naming.dns:patches/jdk.naming.dns-2.jar
 211         String dnsPatches = PATCHES1_DIR.resolve("jdk.naming.dns")
 212                 +  File.pathSeparator + PATCHES_DIR.resolve("jdk.naming.dns-2.jar");
 213 
 214         String compilerPatches = PATCHES1_DIR.resolve("jdk.compiler")
 215                 +  File.pathSeparator + PATCHES_DIR.resolve("jdk.compiler-2.jar");
 216 
 217         runTest(basePatches, dnsPatches, compilerPatches);
 218 
 219     }
 220 }