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