1 /** 2 * Copyright (c) 2015, 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 * @summary Test the recording and checking of module hashes 27 * @author Andrei Eremeev 28 * @library /lib/testlibrary 29 * @modules java.base/jdk.internal.misc 30 * java.base/jdk.internal.module 31 * jdk.jlink 32 * jdk.compiler 33 * @build CompilerUtils 34 * @run testng HashesTest 35 */ 36 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.lang.module.ModuleDescriptor; 40 import java.lang.module.ModuleFinder; 41 import java.lang.module.ModuleReader; 42 import java.lang.module.ModuleReference; 43 import java.nio.file.FileVisitResult; 44 import java.nio.file.Files; 45 import java.nio.file.Path; 46 import java.nio.file.Paths; 47 import java.nio.file.SimpleFileVisitor; 48 import java.nio.file.attribute.BasicFileAttributes; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.Collections; 52 import java.util.List; 53 import java.util.Set; 54 import java.util.spi.ToolProvider; 55 import java.util.stream.Collectors; 56 57 import jdk.internal.module.ModuleInfo; 58 import jdk.internal.module.ModuleHashes; 59 import jdk.internal.module.ModulePath; 60 61 import org.testng.annotations.BeforeTest; 62 import org.testng.annotations.Test; 63 64 import static org.testng.Assert.*; 65 66 public class HashesTest { 67 static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") 68 .orElseThrow(() -> 69 new RuntimeException("jmod tool not found") 70 ); 71 72 private final Path testSrc = Paths.get(System.getProperty("test.src")); 73 private final Path modSrc = testSrc.resolve("src"); 74 private final Path mods = Paths.get("mods"); 75 private final Path jmods = Paths.get("jmods"); 76 private final String[] modules = new String[] { "m1", "m2", "m3"}; 77 78 @BeforeTest 79 private void setup() throws Exception { 80 if (Files.exists(jmods)) { 81 deleteDirectory(jmods); 82 } 83 Files.createDirectories(jmods); 84 85 // build m2, m3 required by m1 86 compileModule("m2", modSrc); 87 jmod("m2"); 88 89 compileModule("m3", modSrc); 90 jmod("m3"); 91 92 // build m1 93 compileModule("m1", modSrc); 94 // no hash is recorded since m1 has outgoing edges 95 jmod("m1", "--module-path", jmods.toString(), "--hash-modules", ".*"); 96 97 // compile org.bar and org.foo 98 compileModule("org.bar", modSrc); 99 compileModule("org.foo", modSrc); 100 } 101 102 @Test 103 public void test() throws Exception { 104 for (String mn : modules) { 105 assertTrue(hashes(mn) == null); 106 } 107 108 // hash m1 in m2 109 jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1"); 110 checkHashes(hashes("m2"), "m1"); 111 112 // hash m1 in m2 113 jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*"); 114 checkHashes(hashes("m2"), "m1"); 115 116 // create m2.jmod with no hash 117 jmod("m2"); 118 // run jmod hash command to hash m1 in m2 and m3 119 runJmod(Arrays.asList("hash", "--module-path", jmods.toString(), 120 "--hash-modules", ".*")); 121 checkHashes(hashes("m2"), "m1"); 122 checkHashes(hashes("m3"), "m1"); 123 124 jmod("org.bar"); 125 jmod("org.foo"); 126 127 jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*"); 128 checkHashes(hashes("org.bar"), "org.foo"); 129 130 jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*"); 131 checkHashes(hashes("m3"), "org.foo", "org.bar", "m1"); 132 } 133 134 private void checkHashes(ModuleHashes hashes, String... hashModules) { 135 assertTrue(hashes.names().equals(Set.of(hashModules))); 136 } 137 138 private ModuleHashes hashes(String name) throws Exception { 139 ModuleFinder finder = new ModulePath(Runtime.version(), 140 true, 141 jmods.resolve(name + ".jmod")); 142 ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new); 143 ModuleReader reader = mref.open(); 144 try (InputStream in = reader.open("module-info.class").get()) { 145 ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes(); 146 System.out.format("hashes in module %s %s%n", name, 147 (hashes != null) ? "present" : "absent"); 148 if (hashes != null) { 149 hashes.names().stream() 150 .sorted() 151 .forEach(n -> System.out.format(" %s %s%n", n, hashes.hashFor(n))); 152 } 153 return hashes; 154 } finally { 155 reader.close(); 156 } 157 } 158 159 private void deleteDirectory(Path dir) throws IOException { 160 Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 161 @Override 162 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 163 throws IOException 164 { 165 Files.delete(file); 166 return FileVisitResult.CONTINUE; 167 } 168 169 @Override 170 public FileVisitResult postVisitDirectory(Path dir, IOException exc) 171 throws IOException 172 { 173 Files.delete(dir); 174 return FileVisitResult.CONTINUE; 175 } 176 }); 177 } 178 179 private void compileModule(String moduleName, Path src) throws IOException { 180 Path msrc = src.resolve(moduleName); 181 assertTrue(CompilerUtils.compile(msrc, mods, "--module-source-path", src.toString())); 182 } 183 184 private void jmod(String moduleName, String... options) throws IOException { 185 Path mclasses = mods.resolve(moduleName); 186 Path outfile = jmods.resolve(moduleName + ".jmod"); 187 List<String> args = new ArrayList<>(); 188 args.add("create"); 189 Collections.addAll(args, options); 190 Collections.addAll(args, "--class-path", mclasses.toString(), 191 outfile.toString()); 192 193 if (Files.exists(outfile)) 194 Files.delete(outfile); 195 196 runJmod(args); 197 } 198 199 private void runJmod(List<String> args) { 200 int rc = JMOD_TOOL.run(System.out, System.out, args.toArray(new String[args.size()])); 201 System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" "))); 202 if (rc != 0) { 203 throw new AssertionError("Jmod failed: rc = " + rc); 204 } 205 } 206 }