blob: 243ecbd81904327095ac6d10459e9702aa3bd1ff [file] [log] [blame]
Alan Bateman36e08202016-05-03 09:09:57 +01001/**
2 * Copyright (c) 2015, 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
37import java.io.IOException;
38import java.io.InputStream;
39import java.lang.module.ModuleDescriptor;
40import java.lang.module.ModuleFinder;
41import java.lang.module.ModuleReader;
42import java.lang.module.ModuleReference;
43import java.lang.reflect.Method;
44import java.nio.file.FileVisitResult;
45import java.nio.file.Files;
46import java.nio.file.Path;
47import java.nio.file.Paths;
48import java.nio.file.SimpleFileVisitor;
49import java.nio.file.attribute.BasicFileAttributes;
50import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.Collections;
53import java.util.List;
54import java.util.Optional;
55import java.util.Set;
56import java.util.stream.Collectors;
57
58import jdk.internal.module.ConfigurableModuleFinder;
59import jdk.internal.module.ModuleHashes;
60import org.testng.annotations.BeforeTest;
61import org.testng.annotations.Test;
62
63import static org.testng.Assert.*;
64
65public 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", "--modulepath", 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", "--modulepath", jmods.toString(), "--hash-modules", "m1");
113 checkHashes(hashes("m2").get(), "m1");
114
115 // hash m1 in m2
116 jmod("m2", "--modulepath", 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", "--modulepath", 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", "--modulepath", jmods.toString(), "--hash-modules", "org.*");
131 checkHashes(hashes("org.bar").get(), "org.foo");
132
133 jmod("m3", "--modulepath", 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, "-modulesourcepath", 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}