Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/tools/jmod/hashes/HashesTest.java
41149 views
1
/*
2
* Copyright (c) 2015, 2021, 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 8160286 8243666 8217527
27
* @summary Test the recording and checking of module hashes
28
* @library /test/lib
29
* @modules java.base/jdk.internal.misc
30
* java.base/jdk.internal.module
31
* jdk.compiler
32
* jdk.jartool
33
* jdk.jlink
34
* @build jdk.test.lib.compiler.ModuleInfoMaker
35
* jdk.test.lib.compiler.CompilerUtils
36
* @run testng HashesTest
37
*/
38
39
import java.io.File;
40
import java.io.IOException;
41
import java.io.InputStream;
42
import java.io.UncheckedIOException;
43
import java.lang.module.ModuleDescriptor;
44
import java.lang.module.ModuleFinder;
45
import java.lang.module.ModuleReader;
46
import java.lang.module.ModuleReference;
47
import java.nio.file.FileVisitResult;
48
import java.nio.file.Files;
49
import java.nio.file.Path;
50
import java.nio.file.Paths;
51
import java.nio.file.SimpleFileVisitor;
52
import java.nio.file.attribute.BasicFileAttributes;
53
import java.util.ArrayList;
54
import java.util.Arrays;
55
import java.util.Collections;
56
import java.util.List;
57
import java.util.Map;
58
import java.util.Set;
59
import java.util.concurrent.atomic.AtomicInteger;
60
import java.util.spi.ToolProvider;
61
import java.util.stream.Collectors;
62
import java.util.stream.Stream;
63
64
import jdk.internal.module.ModuleInfo;
65
import jdk.internal.module.ModuleHashes;
66
import jdk.internal.module.ModulePath;
67
68
import jdk.test.lib.compiler.ModuleInfoMaker;
69
70
import org.testng.annotations.BeforeMethod;
71
import org.testng.annotations.Test;
72
73
import static org.testng.Assert.*;
74
import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
75
76
public class HashesTest {
77
static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
78
.orElseThrow(() ->
79
new RuntimeException("jmod tool not found")
80
);
81
static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
82
.orElseThrow(() ->
83
new RuntimeException("jar tool not found")
84
);
85
86
static final AtomicInteger counter = new AtomicInteger(0);
87
88
private Path mods;
89
private Path lib;
90
private ModuleInfoMaker builder;
91
92
@BeforeMethod
93
public void setTestPath() throws IOException {
94
Path dest = Path.of("test" + counter.addAndGet(1));
95
if (Files.exists(dest)) {
96
deleteDirectory(dest);
97
}
98
this.mods = dest.resolve("mods");
99
this.lib = dest.resolve("lib");
100
this.builder = new ModuleInfoMaker(dest.resolve("src"));
101
102
Files.createDirectories(lib);
103
Files.createDirectories(mods);
104
}
105
106
@Test
107
public void test() throws IOException {
108
// create modules for test cases
109
makeModule("m2");
110
makeModule("m3");
111
makeModule("m1", "m2", "m3");
112
113
makeModule("org.bar", TRANSITIVE, "m1");
114
makeModule("org.foo", TRANSITIVE, "org.bar");
115
116
// create JMOD for m1, m2, m3
117
makeJmod("m2");
118
makeJmod("m3");
119
120
// no hash is recorded since m1 has outgoing edges
121
jmodHashModules("m1", ".*");
122
123
// no hash is recorded in m1, m2, m3
124
assertNull(hashes("m1"));
125
assertNull(hashes("m2"));
126
assertNull(hashes("m3"));
127
128
// hash m1 in m2
129
jmodHashModules("m2", "m1");
130
checkHashes("m2", Set.of("m1"));
131
132
// hash m1 in m2
133
jmodHashModules("m2", ".*");
134
checkHashes("m2", Set.of("m1"));
135
136
// create m2.jmod with no hash
137
makeJmod("m2");
138
// run jmod hash command to hash m1 in m2 and m3
139
runJmod(List.of("hash", "--module-path", lib.toString(),
140
"--hash-modules", ".*"));
141
checkHashes("m2", Set.of("m1"));
142
checkHashes("m3", Set.of("m1"));
143
144
// check transitive requires
145
makeJmod("org.bar");
146
makeJmod("org.foo");
147
148
jmodHashModules("org.bar", "org.*");
149
checkHashes("org.bar", Set.of("org.foo"));
150
151
jmodHashModules( "m3", ".*");
152
checkHashes("m3", Set.of("org.foo", "org.bar", "m1"));
153
}
154
155
@Test
156
public void multiBaseModules() throws IOException {
157
/*
158
* y2 -----------> y1
159
* |______
160
* | |
161
* V V
162
* z3 -> z2
163
* | |
164
* | V
165
* |---> z1
166
*/
167
168
makeModule("z1");
169
makeModule("z2", "z1");
170
makeModule("z3", "z1", "z2");
171
172
makeModule("y1");
173
makeModule("y2", "y1", "z2", "z3");
174
175
Set<String> ys = Set.of("y1", "y2");
176
Set<String> zs = Set.of("z1", "z2", "z3");
177
178
// create JMOD files
179
Stream.concat(ys.stream(), zs.stream()).forEach(this::makeJmod);
180
181
// run jmod hash command
182
runJmod(List.of("hash", "--module-path", lib.toString(),
183
"--hash-modules", ".*"));
184
185
/*
186
* z1 and y1 are the modules with hashes recorded.
187
*/
188
checkHashes("y1", Set.of("y2"));
189
checkHashes("z1", Set.of("z2", "z3", "y2"));
190
Stream.concat(ys.stream(), zs.stream())
191
.filter(mn -> !mn.equals("y1") && !mn.equals("z1"))
192
.forEach(mn -> assertNull(hashes(mn)));
193
}
194
195
@Test
196
public void mixJmodAndJarFile() throws IOException {
197
/*
198
* j3 -----------> j2
199
* |______
200
* | |
201
* V V
202
* m3 -> m2
203
* | |
204
* | V
205
* |---> m1 -> j1 -> jdk.jlink
206
*/
207
208
makeModule("j1");
209
makeModule("j2");
210
makeModule("m1", "j1");
211
makeModule("m2", "m1");
212
makeModule("m3", "m1", "m2");
213
214
makeModule("j3", "j2", "m2", "m3");
215
216
Set<String> jars = Set.of("j1", "j2", "j3");
217
Set<String> jmods = Set.of("m1", "m2", "m3");
218
219
// create JMOD and JAR files
220
jars.forEach(this::makeJar);
221
jmods.forEach(this::makeJmod);
222
223
// run jmod hash command
224
runJmod(List.of("hash", "--module-path", lib.toString(),
225
"--hash-modules", "^j.*|^m.*"));
226
227
/*
228
* j1 and j2 are the modules with hashes recorded.
229
*/
230
checkHashes("j2", Set.of("j3"));
231
checkHashes("j1", Set.of("m1", "m2", "m3", "j3"));
232
Stream.concat(jars.stream(), jmods.stream())
233
.filter(mn -> !mn.equals("j1") && !mn.equals("j2"))
234
.forEach(mn -> assertNull(hashes(mn)));
235
}
236
237
@Test
238
public void upgradeableModule() throws IOException {
239
Path mpath = Paths.get(System.getProperty("java.home"), "jmods");
240
if (!Files.exists(mpath)) {
241
return;
242
}
243
244
makeModule("m1");
245
makeModule("java.compiler", "m1");
246
makeModule("m2", "java.compiler");
247
248
makeJmod("m1");
249
makeJmod("m2");
250
makeJmod("java.compiler",
251
"--module-path",
252
lib.toString() + File.pathSeparator + mpath,
253
"--hash-modules", "java\\.(?!se)|^m.*");
254
255
checkHashes("java.compiler", Set.of("m2"));
256
}
257
258
@Test
259
public void testImageJmods() throws IOException {
260
Path mpath = Paths.get(System.getProperty("java.home"), "jmods");
261
if (!Files.exists(mpath)) {
262
return;
263
}
264
265
makeModule("m1", "jdk.compiler", "jdk.attach");
266
makeModule("m2", "m1");
267
makeModule("m3", "java.compiler");
268
269
makeJmod("m1");
270
makeJmod("m2");
271
272
runJmod(List.of("hash",
273
"--module-path",
274
mpath.toString() + File.pathSeparator + lib.toString(),
275
"--hash-modules", ".*"));
276
277
validateImageJmodsTest(mpath);
278
}
279
280
@Test
281
public void testImageJmods1() throws IOException {
282
Path mpath = Paths.get(System.getProperty("java.home"), "jmods");
283
if (!Files.exists(mpath)) {
284
return;
285
}
286
287
makeModule("m1", "jdk.compiler", "jdk.attach");
288
makeModule("m2", "m1");
289
makeModule("m3", "java.compiler");
290
291
makeJar("m2");
292
makeJar("m1",
293
"--module-path",
294
mpath.toString() + File.pathSeparator + lib.toString(),
295
"--hash-modules", ".*");
296
validateImageJmodsTest(mpath);
297
}
298
299
@Test
300
public void testReproducibibleHash() throws Exception {
301
makeModule("m4");
302
makeModule("m3", "m4");
303
makeModule("m2");
304
makeModule("m1", "m2", "m3");
305
306
// create JMOD files and run jmod hash
307
List.of("m1", "m2", "m3", "m4").forEach(this::makeJmod);
308
Map<String, ModuleHashes> hashes1 = runJmodHash();
309
310
// sleep a bit to be confident that the hashes aren't dependent on timestamps
311
Thread.sleep(2000);
312
313
// (re)create JMOD files and run jmod hash
314
List.of("m1", "m2", "m3", "m4").forEach(this::makeJmod);
315
Map<String, ModuleHashes> hashes2 = runJmodHash();
316
317
// hashes should be equal
318
assertEquals(hashes1, hashes2);
319
}
320
321
@Test
322
public void testHashModulesPattern() throws IOException {
323
// create modules for test cases
324
makeModule("m1");
325
makeModule("m2", "m1");
326
makeModule("m3");
327
makeModule("m4", "m1", "m3");
328
List.of("m1", "m2", "m3", "m4").forEach(this::makeJmod);
329
330
// compute hash for the target jmod (m1.jmod) with different regex
331
// 1) --hash-module "m2"
332
Path jmod = lib.resolve("m1.jmod");
333
runJmod("hash",
334
"--module-path", lib.toString(),
335
"--hash-modules", "m2", jmod.toString());
336
assertEquals(moduleHashes().keySet(), Set.of("m1"));
337
checkHashes("m1", Set.of("m2"));
338
339
// 2) --hash-module "m2|m4"
340
runJmod("hash",
341
"--module-path", lib.toString(),
342
"--hash-modules", "m2|m4", jmod.toString());
343
assertEquals(moduleHashes().keySet(), Set.of("m1"));
344
checkHashes("m1", Set.of("m2", "m4"));
345
346
// 3) --hash-module ".*"
347
runJmod("hash",
348
"--module-path", lib.toString(),
349
"--hash-modules", ".*", jmod.toString());
350
assertEquals(moduleHashes().keySet(), Set.of("m1"));
351
checkHashes("m1", Set.of("m2", "m4"));
352
353
// target jmod is not specified
354
// compute hash for all modules in the library
355
runJmod("hash",
356
"--module-path", lib.toString(),
357
"--hash-modules", ".*");
358
assertEquals(moduleHashes().keySet(), Set.of("m1", "m3"));
359
checkHashes("m1", Set.of("m2", "m4"));
360
checkHashes("m3", Set.of("m4"));
361
}
362
363
private void validateImageJmodsTest(Path mpath)
364
throws IOException
365
{
366
// hash is recorded in m1 and not any other packaged modules on module path
367
checkHashes("m1", Set.of("m2"));
368
assertNull(hashes("m2"));
369
370
// should not override any JDK packaged modules
371
ModuleFinder finder = ModulePath.of(Runtime.version(), true, mpath);
372
assertNull(hashes(finder, "jdk.compiler"));
373
assertNull(hashes(finder, "jdk.attach"));
374
}
375
376
private void checkHashes(String mn, Set<String> hashModules) {
377
ModuleHashes hashes = hashes(mn);
378
assertEquals(hashModules, hashes.names());
379
}
380
381
private ModuleHashes hashes(String name) {
382
ModuleFinder finder = ModulePath.of(Runtime.version(), true, lib);
383
return hashes(finder, name);
384
}
385
386
private ModuleHashes hashes(ModuleFinder finder, String name) {
387
ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
388
try {
389
try (ModuleReader reader = mref.open();
390
InputStream in = reader.open("module-info.class").get()) {
391
ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
392
System.out.format("hashes in module %s %s%n", name,
393
(hashes != null) ? "present" : "absent");
394
if (hashes != null) {
395
hashes.names().stream().sorted().forEach(n ->
396
System.out.format(" %s %s%n", n, toHex(hashes.hashFor(n)))
397
);
398
}
399
return hashes;
400
}
401
} catch (IOException e) {
402
throw new UncheckedIOException(e);
403
}
404
}
405
406
private String toHex(byte[] ba) {
407
StringBuilder sb = new StringBuilder(ba.length);
408
for (byte b: ba) {
409
sb.append(String.format("%02x", b & 0xff));
410
}
411
return sb.toString();
412
}
413
414
private void deleteDirectory(Path dir) throws IOException {
415
Files.walkFileTree(dir, new SimpleFileVisitor<>() {
416
@Override
417
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
418
throws IOException
419
{
420
Files.delete(file);
421
return FileVisitResult.CONTINUE;
422
}
423
424
@Override
425
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
426
throws IOException
427
{
428
Files.delete(dir);
429
return FileVisitResult.CONTINUE;
430
}
431
});
432
}
433
434
435
private void makeModule(String mn, String... deps) throws IOException {
436
makeModule(mn, null, deps);
437
}
438
439
private void makeModule(String mn, ModuleDescriptor.Requires.Modifier mod, String... deps)
440
throws IOException
441
{
442
if (mod != null && mod != TRANSITIVE && mod != STATIC) {
443
throw new IllegalArgumentException(mod.toString());
444
}
445
446
StringBuilder sb = new StringBuilder();
447
sb.append("module ")
448
.append(mn)
449
.append(" {")
450
.append("\n");
451
Arrays.stream(deps)
452
.forEach(req -> {
453
sb.append(" requires ");
454
if (mod != null) {
455
sb.append(mod.toString().toLowerCase())
456
.append(" ");
457
}
458
sb.append(req)
459
.append(";\n");
460
});
461
sb.append("}\n");
462
builder.writeJavaFiles(mn, sb.toString());
463
builder.compile(mn, mods);
464
}
465
466
private void jmodHashModules(String moduleName, String hashModulesPattern) {
467
makeJmod(moduleName, "--module-path", lib.toString(),
468
"--hash-modules", hashModulesPattern);
469
}
470
471
private void makeJmod(String moduleName, String... options) {
472
Path mclasses = mods.resolve(moduleName);
473
Path outfile = lib.resolve(moduleName + ".jmod");
474
List<String> args = new ArrayList<>();
475
args.add("create");
476
Collections.addAll(args, options);
477
Collections.addAll(args, "--class-path", mclasses.toString(),
478
outfile.toString());
479
480
if (Files.exists(outfile)) {
481
try {
482
Files.delete(outfile);
483
} catch (IOException e) {
484
throw new UncheckedIOException(e);
485
}
486
}
487
runJmod(args);
488
}
489
490
/**
491
* Execute jmod hash on the modules in the lib directory. Returns a map of
492
* the modules, with the module name as the key, for the modules that have
493
* a ModuleHashes class file attribute.
494
*/
495
private Map<String, ModuleHashes> runJmodHash() {
496
runJmod("hash",
497
"--module-path", lib.toString(),
498
"--hash-modules", ".*");
499
return moduleHashes();
500
}
501
502
private Map<String, ModuleHashes> moduleHashes() {
503
return ModulePath.of(Runtime.version(), true, lib)
504
.findAll()
505
.stream()
506
.map(ModuleReference::descriptor)
507
.map(ModuleDescriptor::name)
508
.filter(mn -> hashes(mn) != null)
509
.collect(Collectors.toMap(mn -> mn, this::hashes));
510
}
511
512
private static void runJmod(List<String> args) {
513
runJmod(args.toArray(new String[args.size()]));
514
}
515
516
private static void runJmod(String... args) {
517
int rc = JMOD_TOOL.run(System.out, System.out, args);
518
System.out.println("jmod " + Arrays.stream(args).collect(Collectors.joining(" ")));
519
if (rc != 0) {
520
throw new AssertionError("jmod failed: rc = " + rc);
521
}
522
}
523
524
private void makeJar(String moduleName, String... options) {
525
Path mclasses = mods.resolve(moduleName);
526
Path outfile = lib.resolve(moduleName + ".jar");
527
List<String> args = new ArrayList<>();
528
Stream.concat(Stream.of("--create",
529
"--file=" + outfile.toString()),
530
Arrays.stream(options))
531
.forEach(args::add);
532
args.add("-C");
533
args.add(mclasses.toString());
534
args.add(".");
535
536
if (Files.exists(outfile)) {
537
try {
538
Files.delete(outfile);
539
} catch (IOException e) {
540
throw new UncheckedIOException(e);
541
}
542
}
543
544
int rc = JAR_TOOL.run(System.out, System.out, args.toArray(new String[args.size()]));
545
System.out.println("jar " + args.stream().collect(Collectors.joining(" ")));
546
if (rc != 0) {
547
throw new AssertionError("jar failed: rc = " + rc);
548
}
549
}
550
}
551
552