1 /** 2 * Copyright (c) 2016, 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 8157068 27 * @summary Patch java.base and user module with Hashes attribute tied with 28 * other module. 29 * @library /lib/testlibrary 30 * @modules jdk.compiler 31 * @build CompilerUtils 32 * @run testng PatchSystemModules 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.ArrayList; 40 import java.util.List; 41 import java.util.stream.Stream; 42 43 import jdk.testlibrary.FileUtils; 44 import jdk.testlibrary.JDKToolFinder; 45 import org.testng.annotations.BeforeTest; 46 import org.testng.annotations.Test; 47 48 import static jdk.testlibrary.ProcessTools.executeCommand; 49 import static org.testng.Assert.*; 50 51 public class PatchSystemModules { 52 private static final String JAVA_HOME = System.getProperty("java.home"); 53 54 private static final Path TEST_SRC = Paths.get(System.getProperty("test.src")); 55 private static final Path PATCH_SRC_DIR = TEST_SRC.resolve("src1"); 56 57 private static final Path JMODS = Paths.get(JAVA_HOME, "jmods"); 58 private static final Path MODS_DIR = Paths.get("mods"); 59 private static final Path JARS_DIR = Paths.get("jars"); 60 private static final Path PATCH_DIR = Paths.get("patches"); 61 private static final Path IMAGE = Paths.get("image"); 62 63 private static final String JAVA_BASE = "java.base"; 64 private final String[] modules = new String[] { "m1", "m2" }; 65 66 @BeforeTest 67 private void setup() throws Throwable { 68 Path src = TEST_SRC.resolve("src"); 69 for (String name : modules) { 70 assertTrue(CompilerUtils.compile(src.resolve(name), 71 MODS_DIR, 72 "-modulesourcepath", src.toString())); 73 } 74 75 // compile patched source 76 assertTrue(CompilerUtils.compile(PATCH_SRC_DIR.resolve(JAVA_BASE), 77 PATCH_DIR.resolve(JAVA_BASE), 78 "-Xmodule:java.base")); 79 assertTrue(CompilerUtils.compile(PATCH_SRC_DIR.resolve("m2"), 80 PATCH_DIR.resolve("m2"))); 81 82 // create an image with only m1 and m2 83 if (Files.exists(JMODS)) { 84 // create an image with m1,m2 85 createImage(); 86 } 87 } 88 89 @Test 90 public void test() throws Throwable { 91 Path patchedJavaBase = PATCH_DIR.resolve(JAVA_BASE); 92 Path patchedM2 = PATCH_DIR.resolve("m2"); 93 94 Path home = Paths.get(JAVA_HOME); 95 runTest(home, 96 "-mp", MODS_DIR.toString(), 97 "-m", "m1/p1.Main", "1"); 98 runTest(home, 99 "-Xpatch:java.base=" + patchedJavaBase.toString(), 100 "-mp", MODS_DIR.toString(), 101 "-m", "m1/p1.Main", "1"); 102 103 runTest(home, 104 "-Xpatch:m2=" + patchedM2.toString(), 105 "-mp", MODS_DIR.toString(), 106 "-m", "m1/p1.Main", "2"); 107 } 108 109 @Test 110 public void testImage() throws Throwable { 111 if (Files.notExists(JMODS)) 112 return; 113 114 Path patchedJavaBase = PATCH_DIR.resolve(JAVA_BASE); 115 Path patchedM2 = PATCH_DIR.resolve("m2"); 116 117 runTest(IMAGE, 118 "-m", "m1/p1.Main", "1"); 119 runTest(IMAGE, 120 "-Xpatch:java.base=" + patchedJavaBase.toString(), 121 "-m", "m1/p1.Main", "1"); 122 runTest(IMAGE, 123 "-Xpatch:m2=" + patchedM2.toString(), 124 "-m", "m1/p1.Main", "2"); 125 } 126 127 @Test 128 public void upgradeTiedModule() throws Throwable { 129 if (Files.notExists(JMODS)) 130 return; 131 132 Path m1 = MODS_DIR.resolve("m1.jar"); 133 134 // create another m1.jar 135 jar("--create", 136 "--file=" + m1.toString(), 137 "-C", MODS_DIR.resolve("m1").toString(), "."); 138 139 // Fail to upgrade m1.jar with mismatched hash 140 runTestWithExitCode(getJava(IMAGE), 141 "-upgrademodulepath", m1.toString(), 142 "-m", "m1/p1.Main"); 143 144 runTestWithExitCode(getJava(IMAGE), 145 "-Xpatch:java.base=" + PATCH_DIR.resolve(JAVA_BASE).toString(), 146 "-upgrademodulepath", m1.toString(), 147 "-m", "m1/p1.Main", "1"); 148 } 149 150 private void runTestWithExitCode(String... options) throws Throwable { 151 assertTrue(executeCommand(options) 152 .outputTo(System.out) 153 .errorTo(System.out) 154 .shouldContain("differs to expected hash") 155 .getExitValue() != 0); 156 } 157 158 private void runTest(Path image, String... opts) throws Throwable { 159 String[] options = 160 Stream.concat(Stream.of(getJava(image)), 161 Stream.of(opts)) 162 .toArray(String[]::new); 163 164 ProcessBuilder pb = new ProcessBuilder(options); 165 int exitValue = executeCommand(pb) 166 .outputTo(System.out) 167 .errorTo(System.out) 168 .getExitValue(); 169 170 assertTrue(exitValue == 0); 171 } 172 173 static void createImage() throws Throwable { 174 FileUtils.deleteFileTreeUnchecked(JARS_DIR); 175 FileUtils.deleteFileTreeUnchecked(IMAGE); 176 177 Files.createDirectories(JARS_DIR); 178 Path m1 = JARS_DIR.resolve("m1.jar"); 179 Path m2 = JARS_DIR.resolve("m2.jar"); 180 181 // hash m1 in m2's Hashes attribute 182 jar("--create", 183 "--file=" + m1.toString(), 184 "-C", MODS_DIR.resolve("m1").toString(), "."); 185 186 jar("--create", 187 "--file=" + m2.toString(), 188 "--modulepath", JARS_DIR.toString(), 189 "--hash-modules", "m1", 190 "-C", MODS_DIR.resolve("m2").toString(), "."); 191 192 193 String mpath = JARS_DIR.toString() + File.pathSeparator + JMODS.toString(); 194 execTool("jlink", "--modulepath", mpath, 195 "--addmods", "m1", 196 "--output", IMAGE.toString()); 197 } 198 199 static void jar(String... args) throws Throwable { 200 execTool("jar", args); 201 } 202 203 static void execTool(String tool, String... args) throws Throwable { 204 String path = JDKToolFinder.getJDKTool(tool); 205 List<String> commands = new ArrayList<>(); 206 commands.add(path); 207 Stream.of(args).forEach(commands::add); 208 ProcessBuilder pb = new ProcessBuilder(commands); 209 int exitValue = executeCommand(pb) 210 .outputTo(System.out) 211 .errorTo(System.out) 212 .shouldNotContain("no module is recorded in hash") 213 .getExitValue(); 214 215 assertTrue(exitValue == 0); 216 } 217 218 static String getJava(Path image) { 219 boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("win"); 220 Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java"); 221 if (Files.notExists(java)) 222 throw new RuntimeException(java + " not found"); 223 return java.toAbsolutePath().toString(); 224 } 225 }