Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/test/jdk/tools/jmod/JmodTest.java
66643 views
1
/*
2
* Copyright (c) 2015, 2022, 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 8142968 8166568 8166286 8170618 8168149 8240910 8276764 8276766
27
* @summary Basic test for jmod
28
* @library /test/lib
29
* @modules jdk.compiler
30
* jdk.jlink
31
* @build jdk.test.lib.compiler.CompilerUtils
32
* jdk.test.lib.util.FileUtils
33
* jdk.test.lib.Platform
34
* @run testng/othervm -Djava.io.tmpdir=. JmodTest
35
*/
36
37
import java.io.*;
38
import java.lang.module.ModuleDescriptor;
39
import java.lang.reflect.Method;
40
import java.nio.file.*;
41
import java.util.*;
42
import java.util.function.Consumer;
43
import java.util.regex.Pattern;
44
import java.util.spi.ToolProvider;
45
import java.util.stream.Stream;
46
import jdk.test.lib.compiler.CompilerUtils;
47
import jdk.test.lib.util.FileUtils;
48
import org.testng.annotations.BeforeTest;
49
import org.testng.annotations.Test;
50
51
import static java.io.File.pathSeparator;
52
import static java.lang.module.ModuleDescriptor.Version;
53
import static java.nio.charset.StandardCharsets.UTF_8;
54
import static java.util.stream.Collectors.toSet;
55
import static org.testng.Assert.*;
56
57
public class JmodTest {
58
59
static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
60
.orElseThrow(() ->
61
new RuntimeException("jmod tool not found")
62
);
63
static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
64
.orElseThrow(() ->
65
new RuntimeException("jar tool not found")
66
);
67
68
static final String TEST_SRC = System.getProperty("test.src", ".");
69
static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
70
static final Path EXPLODED_DIR = Paths.get("build");
71
static final Path MODS_DIR = Paths.get("jmods");
72
73
static final String CLASSES_PREFIX = "classes/";
74
static final String CMDS_PREFIX = "bin/";
75
static final String LIBS_PREFIX = "lib/";
76
static final String CONFIGS_PREFIX = "conf/";
77
78
@BeforeTest
79
public void buildExplodedModules() throws IOException {
80
if (Files.exists(EXPLODED_DIR))
81
FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR);
82
83
for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {
84
Path dir = EXPLODED_DIR.resolve(name);
85
assertTrue(compileModule(name, dir.resolve("classes")));
86
copyResource(SRC_DIR.resolve("foo"),
87
dir.resolve("classes"),
88
"jdk/test/foo/resources/foo.properties");
89
createCmds(dir.resolve("bin"));
90
createLibs(dir.resolve("lib"));
91
createConfigs(dir.resolve("conf"));
92
}
93
94
if (Files.exists(MODS_DIR))
95
FileUtils.deleteFileTreeWithRetry(MODS_DIR);
96
Files.createDirectories(MODS_DIR);
97
}
98
99
// JDK-8166286 - jmod fails on symlink to directory
100
@Test
101
public void testDirSymlinks() throws IOException {
102
Path apaDir = EXPLODED_DIR.resolve("apa");
103
Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes");
104
assertTrue(compileModule("apa", classesDir));
105
Path libDir = apaDir.resolve("lib");
106
createFiles(libDir, List.of("foo/bar/libfoo.so"));
107
try {
108
Path link = Files.createSymbolicLink(
109
libDir.resolve("baz"), libDir.resolve("foo").toAbsolutePath());
110
assertTrue(Files.exists(link));
111
} catch (IOException|UnsupportedOperationException uoe) {
112
// OS does not support symlinks. Nothing to test!
113
System.out.println("Creating symlink failed. Test passes vacuously.");
114
uoe.printStackTrace();
115
return;
116
}
117
118
Path jmod = MODS_DIR.resolve("apa.jmod");
119
jmod("create",
120
"--libs=" + libDir.toString(),
121
"--class-path", classesDir.toString(),
122
jmod.toString())
123
.assertSuccess();
124
Files.delete(jmod);
125
}
126
127
// JDK-8267583 - jmod fails on symlink to class file
128
@Test
129
public void testFileSymlinks() throws IOException {
130
Path apaDir = EXPLODED_DIR.resolve("apa");
131
Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes");
132
assertTrue(compileModule("apa", classesDir));
133
134
Files.move(classesDir.resolve("module-info.class"),
135
classesDir.resolve("module-info.class1"));
136
Files.move(classesDir.resolve(Paths.get("jdk", "test", "apa", "Apa.class")),
137
classesDir.resolve("Apa.class1"));
138
try {
139
Path link = Files.createSymbolicLink(
140
classesDir.resolve("module-info.class"),
141
classesDir.resolve("module-info.class1").toAbsolutePath());
142
assertTrue(Files.exists(link));
143
link = Files.createSymbolicLink(
144
classesDir.resolve(Paths.get("jdk", "test", "apa", "Apa.class")),
145
classesDir.resolve("Apa.class1").toAbsolutePath());
146
assertTrue(Files.exists(link));
147
} catch (IOException|UnsupportedOperationException uoe) {
148
// OS does not support symlinks. Nothing to test!
149
System.out.println("Creating symlinks failed. Test passes vacuously.");
150
uoe.printStackTrace();
151
return;
152
}
153
154
Path jmod = MODS_DIR.resolve("apa.jmod");
155
jmod("create",
156
"--class-path", classesDir.toString(),
157
jmod.toString())
158
.assertSuccess();
159
Files.delete(jmod);
160
}
161
162
// JDK-8170618 - jmod should validate if any exported or open package is missing
163
@Test
164
public void testMissingPackages() throws IOException {
165
Path apaDir = EXPLODED_DIR.resolve("apa");
166
Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes");
167
if (Files.exists(classesDir))
168
FileUtils.deleteFileTreeWithRetry(classesDir);
169
assertTrue(compileModule("apa", classesDir));
170
FileUtils.deleteFileTreeWithRetry(classesDir.resolve("jdk"));
171
Path jmod = MODS_DIR.resolve("apa.jmod");
172
jmod("create",
173
"--class-path", classesDir.toString(),
174
jmod.toString())
175
.assertFailure()
176
.resultChecker(r -> {
177
assertContains(r.output, "Packages that are exported or open in apa are not present: [jdk.test.apa]");
178
});
179
if (Files.exists(classesDir))
180
FileUtils.deleteFileTreeWithRetry(classesDir);
181
}
182
183
@Test
184
public void testList() throws IOException {
185
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
186
Path jmod = MODS_DIR.resolve("foo.jmod");
187
FileUtils.deleteFileIfExistsWithRetry(jmod);
188
jmod("create",
189
"--class-path", cp,
190
jmod.toString())
191
.assertSuccess();
192
193
jmod("list",
194
jmod.toString())
195
.assertSuccess()
196
.resultChecker(r -> {
197
// asserts dependent on the exact contents of foo
198
assertContains(r.output, CLASSES_PREFIX + "module-info.class");
199
assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class");
200
assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
201
assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
202
203
// JDK-8276764: Ensure the order is sorted for reproducible jmod content
204
// module-info, followed by <sorted classes>
205
int mod_info_i = r.output.indexOf(CLASSES_PREFIX + "module-info.class");
206
int foo_cls_i = r.output.indexOf(CLASSES_PREFIX + "jdk/test/foo/Foo.class");
207
int msg_i = r.output.indexOf(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
208
int res_i = r.output.indexOf(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
209
System.out.println("jmod classes sort order check:\n"+r.output);
210
assertTrue(mod_info_i < foo_cls_i);
211
assertTrue(foo_cls_i < msg_i);
212
assertTrue(msg_i < res_i);
213
});
214
}
215
216
@Test
217
public void testSourceDateReproducible() throws IOException {
218
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
219
Path jmod1 = MODS_DIR.resolve("foo1.jmod");
220
Path jmod2 = MODS_DIR.resolve("foo2.jmod");
221
Path jmod3 = MODS_DIR.resolve("foo3.jmod");
222
FileUtils.deleteFileIfExistsWithRetry(jmod1);
223
FileUtils.deleteFileIfExistsWithRetry(jmod2);
224
FileUtils.deleteFileIfExistsWithRetry(jmod3);
225
226
// Use source date of 15/03/2022
227
String sourceDate = "2022-03-15T00:00:00+00:00";
228
229
jmod("create",
230
"--class-path", cp,
231
"--date", sourceDate,
232
jmod1.toString())
233
.assertSuccess();
234
235
try {
236
// Sleep 5 seconds to ensure zip timestamps might be different if they could be
237
Thread.sleep(5000);
238
} catch(InterruptedException ex) {}
239
240
jmod("create",
241
"--class-path", cp,
242
"--date", sourceDate,
243
jmod2.toString())
244
.assertSuccess();
245
246
// Compare file byte content to see if they are identical
247
assertSameContent(jmod1, jmod2);
248
249
// Use a date before 1980 and assert failure error
250
sourceDate = "1976-03-15T00:00:00+00:00";
251
252
jmod("create",
253
"--class-path", cp,
254
"--date", sourceDate,
255
jmod3.toString())
256
.assertFailure()
257
.resultChecker(r -> {
258
assertContains(r.output, "is out of the valid range");
259
});
260
261
// Use a date after 2099 and assert failure error
262
sourceDate = "2100-03-15T00:00:00+00:00";
263
264
jmod("create",
265
"--class-path", cp,
266
"--date", sourceDate,
267
jmod3.toString())
268
.assertFailure()
269
.resultChecker(r -> {
270
assertContains(r.output, "is out of the valid range");
271
});
272
}
273
274
@Test
275
public void testExtractCWD() throws IOException {
276
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
277
jmod("create",
278
"--class-path", cp.toString(),
279
MODS_DIR.resolve("fooExtractCWD.jmod").toString())
280
.assertSuccess();
281
282
jmod("extract",
283
MODS_DIR.resolve("fooExtractCWD.jmod").toString())
284
.assertSuccess()
285
.resultChecker(r -> {
286
// module-info should exist, but jmod will have added its Packages attr.
287
assertTrue(Files.exists(Paths.get("classes/module-info.class")));
288
assertSameContent(cp.resolve("jdk/test/foo/Foo.class"),
289
Paths.get("classes/jdk/test/foo/Foo.class"));
290
assertSameContent(cp.resolve("jdk/test/foo/internal/Message.class"),
291
Paths.get("classes/jdk/test/foo/internal/Message.class"));
292
assertSameContent(cp.resolve("jdk/test/foo/resources/foo.properties"),
293
Paths.get("classes/jdk/test/foo/resources/foo.properties"));
294
});
295
}
296
297
@Test
298
public void testExtractDir() throws IOException {
299
if (Files.exists(Paths.get("extractTestDir")))
300
FileUtils.deleteFileTreeWithRetry(Paths.get("extractTestDir"));
301
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
302
Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");
303
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
304
Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");
305
306
jmod("create",
307
"--conf", cf.toString(),
308
"--cmds", bp.toString(),
309
"--libs", lp.toString(),
310
"--class-path", cp.toString(),
311
MODS_DIR.resolve("fooExtractDir.jmod").toString())
312
.assertSuccess();
313
314
jmod("extract",
315
"--dir", "extractTestDir",
316
MODS_DIR.resolve("fooExtractDir.jmod").toString())
317
.assertSuccess();
318
319
jmod("extract",
320
"--dir", "extractTestDir",
321
MODS_DIR.resolve("fooExtractDir.jmod").toString())
322
.assertSuccess()
323
.resultChecker(r -> {
324
// check a sample of the extracted files
325
Path p = Paths.get("extractTestDir");
326
assertTrue(Files.exists(p.resolve("classes/module-info.class")));
327
assertSameContent(cp.resolve("jdk/test/foo/Foo.class"),
328
p.resolve("classes/jdk/test/foo/Foo.class"));
329
assertSameContent(bp.resolve("first"),
330
p.resolve(CMDS_PREFIX).resolve("first"));
331
assertSameContent(lp.resolve("first.so"),
332
p.resolve(LIBS_PREFIX).resolve("second.so"));
333
assertSameContent(cf.resolve("second.cfg"),
334
p.resolve(CONFIGS_PREFIX).resolve("second.cfg"));
335
});
336
}
337
338
@Test
339
public void testMainClass() throws IOException {
340
Path jmod = MODS_DIR.resolve("fooMainClass.jmod");
341
FileUtils.deleteFileIfExistsWithRetry(jmod);
342
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
343
344
jmod("create",
345
"--class-path", cp,
346
"--main-class", "jdk.test.foo.Foo",
347
jmod.toString())
348
.assertSuccess()
349
.resultChecker(r -> {
350
Optional<String> omc = getModuleDescriptor(jmod).mainClass();
351
assertTrue(omc.isPresent());
352
assertEquals(omc.get(), "jdk.test.foo.Foo");
353
});
354
}
355
356
@Test
357
public void testModuleVersion() throws IOException {
358
Path jmod = MODS_DIR.resolve("fooVersion.jmod");
359
FileUtils.deleteFileIfExistsWithRetry(jmod);
360
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
361
362
jmod("create",
363
"--class-path", cp,
364
"--module-version", "5.4.3",
365
jmod.toString())
366
.assertSuccess()
367
.resultChecker(r -> {
368
Optional<Version> ov = getModuleDescriptor(jmod).version();
369
assertTrue(ov.isPresent());
370
assertEquals(ov.get().toString(), "5.4.3");
371
});
372
}
373
374
@Test
375
public void testConfig() throws IOException {
376
Path jmod = MODS_DIR.resolve("fooConfig.jmod");
377
FileUtils.deleteFileIfExistsWithRetry(jmod);
378
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
379
Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");
380
381
jmod("create",
382
"--class-path", cp.toString(),
383
"--config", cf.toString(),
384
jmod.toString())
385
.assertSuccess()
386
.resultChecker(r -> {
387
try (Stream<String> s1 = findFiles(cf).map(p -> CONFIGS_PREFIX + p);
388
Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {
389
Set<String> expectedFilenames = Stream.concat(s1, s2)
390
.collect(toSet());
391
assertJmodContent(jmod, expectedFilenames);
392
}
393
});
394
}
395
396
@Test
397
public void testCmds() throws IOException {
398
Path jmod = MODS_DIR.resolve("fooCmds.jmod");
399
FileUtils.deleteFileIfExistsWithRetry(jmod);
400
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
401
Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");
402
403
jmod("create",
404
"--cmds", bp.toString(),
405
"--class-path", cp.toString(),
406
jmod.toString())
407
.assertSuccess()
408
.resultChecker(r -> {
409
try (Stream<String> s1 = findFiles(bp).map(p -> CMDS_PREFIX + p);
410
Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {
411
Set<String> expectedFilenames = Stream.concat(s1,s2)
412
.collect(toSet());
413
assertJmodContent(jmod, expectedFilenames);
414
}
415
});
416
}
417
418
@Test
419
public void testLibs() throws IOException {
420
Path jmod = MODS_DIR.resolve("fooLibs.jmod");
421
FileUtils.deleteFileIfExistsWithRetry(jmod);
422
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
423
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
424
425
jmod("create",
426
"--libs=" + lp.toString(),
427
"--class-path", cp.toString(),
428
jmod.toString())
429
.assertSuccess()
430
.resultChecker(r -> {
431
try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);
432
Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {
433
Set<String> expectedFilenames = Stream.concat(s1,s2)
434
.collect(toSet());
435
assertJmodContent(jmod, expectedFilenames);
436
}
437
});
438
}
439
440
@Test
441
public void testAll() throws IOException {
442
Path jmod = MODS_DIR.resolve("fooAll.jmod");
443
FileUtils.deleteFileIfExistsWithRetry(jmod);
444
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
445
Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");
446
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
447
Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");
448
449
jmod("create",
450
"--conf", cf.toString(),
451
"--cmds=" + bp.toString(),
452
"--libs=" + lp.toString(),
453
"--class-path", cp.toString(),
454
jmod.toString())
455
.assertSuccess()
456
.resultChecker(r -> {
457
try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);
458
Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p);
459
Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p);
460
Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) {
461
Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2),
462
Stream.concat(s3, s4))
463
.collect(toSet());
464
assertJmodContent(jmod, expectedFilenames);
465
}
466
});
467
}
468
469
@Test
470
public void testExcludes() throws IOException {
471
Path jmod = MODS_DIR.resolve("fooLibs.jmod");
472
FileUtils.deleteFileIfExistsWithRetry(jmod);
473
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
474
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
475
476
jmod("create",
477
"--libs=" + lp.toString(),
478
"--class-path", cp.toString(),
479
"--exclude", "**internal**",
480
"--exclude", "first.so",
481
jmod.toString())
482
.assertSuccess()
483
.resultChecker(r -> {
484
Set<String> expectedFilenames = new HashSet<>();
485
expectedFilenames.add(CLASSES_PREFIX + "module-info.class");
486
expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class");
487
expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
488
expectedFilenames.add(LIBS_PREFIX + "second.so");
489
expectedFilenames.add(LIBS_PREFIX + "third/third.so");
490
assertJmodContent(jmod, expectedFilenames);
491
492
Set<String> unexpectedFilenames = new HashSet<>();
493
unexpectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
494
unexpectedFilenames.add(LIBS_PREFIX + "first.so");
495
assertJmodDoesNotContain(jmod, unexpectedFilenames);
496
});
497
}
498
499
@Test
500
public void describe() throws IOException {
501
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
502
jmod("create",
503
"--class-path", cp,
504
MODS_DIR.resolve("describeFoo.jmod").toString())
505
.assertSuccess();
506
507
jmod("describe",
508
MODS_DIR.resolve("describeFoo.jmod").toString())
509
.assertSuccess()
510
.resultChecker(r -> {
511
// Expect similar output: "foo... exports jdk.test.foo ...
512
// ... requires java.base mandated... contains jdk.test.foo.internal"
513
Pattern p = Pattern.compile("foo\\s+exports\\s+jdk.test.foo");
514
assertTrue(p.matcher(r.output).find(),
515
"Expecting to find \"foo... exports jdk.test.foo\"" +
516
"in output, but did not: [" + r.output + "]");
517
p = Pattern.compile(
518
"requires\\s+java.base\\s+mandated\\s+contains\\s+jdk.test.foo.internal");
519
assertTrue(p.matcher(r.output).find(),
520
"Expecting to find \"requires java.base mandated..., " +
521
"contains jdk.test.foo.internal ...\"" +
522
"in output, but did not: [" + r.output + "]");
523
});
524
}
525
526
@Test
527
public void testDuplicateEntries() throws IOException {
528
Path jmod = MODS_DIR.resolve("testDuplicates.jmod");
529
FileUtils.deleteFileIfExistsWithRetry(jmod);
530
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
531
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
532
533
jmod("create",
534
"--class-path", cp + pathSeparator + cp,
535
jmod.toString())
536
.assertSuccess()
537
.resultChecker(r ->
538
assertContains(r.output, "Warning: ignoring duplicate entry")
539
);
540
541
FileUtils.deleteFileIfExistsWithRetry(jmod);
542
jmod("create",
543
"--class-path", cp,
544
"--libs", lp.toString() + pathSeparator + lp.toString(),
545
jmod.toString())
546
.assertSuccess()
547
.resultChecker(r ->
548
assertContains(r.output, "Warning: ignoring duplicate entry")
549
);
550
}
551
552
@Test
553
public void testDuplicateEntriesFromJarFile() throws IOException {
554
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
555
Path jar = Paths.get("foo.jar");
556
Path jmod = MODS_DIR.resolve("testDuplicates.jmod");
557
FileUtils.deleteFileIfExistsWithRetry(jar);
558
FileUtils.deleteFileIfExistsWithRetry(jmod);
559
// create JAR file
560
assertTrue(JAR_TOOL.run(System.out, System.err, "cf", jar.toString(), "-C", cp, ".") == 0);
561
562
jmod("create",
563
"--class-path", jar.toString() + pathSeparator + jar.toString(),
564
jmod.toString())
565
.assertSuccess()
566
.resultChecker(r ->
567
assertContains(r.output, "Warning: ignoring duplicate entry")
568
);
569
}
570
571
@Test
572
public void testIgnoreModuleInfoInOtherSections() throws IOException {
573
Path jmod = MODS_DIR.resolve("testIgnoreModuleInfoInOtherSections.jmod");
574
FileUtils.deleteFileIfExistsWithRetry(jmod);
575
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
576
577
jmod("create",
578
"--class-path", cp,
579
"--libs", cp,
580
jmod.toString())
581
.assertSuccess()
582
.resultChecker(r ->
583
assertContains(r.output, "Warning: ignoring entry")
584
);
585
586
FileUtils.deleteFileIfExistsWithRetry(jmod);
587
jmod("create",
588
"--class-path", cp,
589
"--cmds", cp,
590
jmod.toString())
591
.assertSuccess()
592
.resultChecker(r ->
593
assertContains(r.output, "Warning: ignoring entry")
594
);
595
}
596
597
@Test
598
public void testLastOneWins() throws IOException {
599
Path workDir = Paths.get("lastOneWins");
600
if (Files.exists(workDir))
601
FileUtils.deleteFileTreeWithRetry(workDir);
602
Files.createDirectory(workDir);
603
Path jmod = MODS_DIR.resolve("lastOneWins.jmod");
604
FileUtils.deleteFileIfExistsWithRetry(jmod);
605
Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");
606
Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");
607
Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
608
Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");
609
610
Path shouldNotBeAdded = workDir.resolve("shouldNotBeAdded");
611
Files.createDirectory(shouldNotBeAdded);
612
Files.write(shouldNotBeAdded.resolve("aFile"), "hello".getBytes(UTF_8));
613
614
// Pairs of options. For options with required arguments the last one
615
// should win ( first should be effectively ignored, but may still be
616
// validated ).
617
jmod("create",
618
"--conf", shouldNotBeAdded.toString(),
619
"--conf", cf.toString(),
620
"--cmds", shouldNotBeAdded.toString(),
621
"--cmds", bp.toString(),
622
"--libs", shouldNotBeAdded.toString(),
623
"--libs", lp.toString(),
624
"--class-path", shouldNotBeAdded.toString(),
625
"--class-path", cp.toString(),
626
"--main-class", "does.NotExist",
627
"--main-class", "jdk.test.foo.Foo",
628
"--module-version", "00001",
629
"--module-version", "5.4.3",
630
"--do-not-resolve-by-default",
631
"--do-not-resolve-by-default",
632
"--warn-if-resolved=incubating",
633
"--warn-if-resolved=deprecated",
634
MODS_DIR.resolve("lastOneWins.jmod").toString())
635
.assertSuccess()
636
.resultChecker(r -> {
637
ModuleDescriptor md = getModuleDescriptor(jmod);
638
Optional<String> omc = md.mainClass();
639
assertTrue(omc.isPresent());
640
assertEquals(omc.get(), "jdk.test.foo.Foo");
641
Optional<Version> ov = md.version();
642
assertTrue(ov.isPresent());
643
assertEquals(ov.get().toString(), "5.4.3");
644
645
try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);
646
Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p);
647
Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p);
648
Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) {
649
Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2),
650
Stream.concat(s3, s4))
651
.collect(toSet());
652
assertJmodContent(jmod, expectedFilenames);
653
}
654
});
655
656
jmod("extract",
657
"--dir", "blah",
658
"--dir", "lastOneWinsExtractDir",
659
jmod.toString())
660
.assertSuccess()
661
.resultChecker(r -> {
662
assertTrue(Files.exists(Paths.get("lastOneWinsExtractDir")));
663
assertTrue(Files.notExists(Paths.get("blah")));
664
});
665
}
666
667
@Test
668
public void testPackagesAttribute() throws IOException {
669
Path jmod = MODS_DIR.resolve("foo.jmod");
670
FileUtils.deleteFileIfExistsWithRetry(jmod);
671
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
672
673
Set<String> expectedPackages = Set.of("jdk.test.foo",
674
"jdk.test.foo.internal",
675
"jdk.test.foo.resources");
676
677
jmod("create",
678
"--class-path", cp,
679
jmod.toString())
680
.assertSuccess()
681
.resultChecker(r -> {
682
Set<String> pkgs = getModuleDescriptor(jmod).packages();
683
assertEquals(pkgs, expectedPackages);
684
});
685
}
686
687
@Test
688
public void testVersion() {
689
jmod("--version")
690
.assertSuccess()
691
.resultChecker(r -> {
692
assertContains(r.output, System.getProperty("java.version"));
693
});
694
}
695
696
@Test
697
public void testHelp() {
698
jmod("--help")
699
.assertSuccess()
700
.resultChecker(r -> {
701
assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed");
702
assertFalse(r.output.contains("--do-not-resolve-by-default"));
703
assertFalse(r.output.contains("--warn-if-resolved"));
704
});
705
}
706
707
@Test
708
public void testHelpExtra() {
709
jmod("--help-extra")
710
.assertSuccess()
711
.resultChecker(r -> {
712
assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed");
713
assertContains(r.output, "--do-not-resolve-by-default");
714
assertContains(r.output, "--warn-if-resolved");
715
});
716
}
717
718
@Test
719
public void testTmpFileRemoved() throws IOException {
720
// Implementation detail: jmod tool creates <jmod-file>.tmp
721
// Ensure that it is removed in the event of a failure.
722
// The failure in this case is a class in the unnamed package.
723
724
Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod");
725
Path tmp = MODS_DIR.resolve(".testTmpFileRemoved.jmod.tmp");
726
FileUtils.deleteFileIfExistsWithRetry(jmod);
727
FileUtils.deleteFileIfExistsWithRetry(tmp);
728
String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator +
729
EXPLODED_DIR.resolve("foo").resolve("classes")
730
.resolve("jdk").resolve("test").resolve("foo").toString();
731
732
jmod("create",
733
"--class-path", cp,
734
jmod.toString())
735
.assertFailure()
736
.resultChecker(r -> {
737
assertContains(r.output, "unnamed package");
738
assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp);
739
});
740
}
741
742
// ---
743
744
static boolean compileModule(String name, Path dest) throws IOException {
745
return CompilerUtils.compile(SRC_DIR.resolve(name), dest);
746
}
747
748
static void assertContains(String output, String subString) {
749
if (output.contains(subString))
750
assertTrue(true);
751
else
752
assertTrue(false,"Expected to find [" + subString + "], in output ["
753
+ output + "]" + "\n");
754
}
755
756
static ModuleDescriptor getModuleDescriptor(Path jmod) {
757
ClassLoader cl = ClassLoader.getSystemClassLoader();
758
try (FileSystem fs = FileSystems.newFileSystem(jmod, cl)) {
759
String p = "/classes/module-info.class";
760
try (InputStream is = Files.newInputStream(fs.getPath(p))) {
761
return ModuleDescriptor.read(is);
762
}
763
} catch (IOException ioe) {
764
throw new UncheckedIOException(ioe);
765
}
766
}
767
768
static Stream<String> findFiles(Path dir) {
769
try {
770
return Files.find(dir, Integer.MAX_VALUE, (p, a) -> a.isRegularFile())
771
.map(dir::relativize)
772
.map(Path::toString)
773
.map(p -> p.replace(File.separator, "/"));
774
} catch (IOException x) {
775
throw new UncheckedIOException(x);
776
}
777
}
778
779
static Set<String> getJmodContent(Path jmod) {
780
JmodResult r = jmod("list", jmod.toString()).assertSuccess();
781
return Stream.of(r.output.split("\r?\n")).collect(toSet());
782
}
783
784
static void assertJmodContent(Path jmod, Set<String> expected) {
785
Set<String> actual = getJmodContent(jmod);
786
if (!Objects.equals(actual, expected)) {
787
Set<String> unexpected = new HashSet<>(actual);
788
unexpected.removeAll(expected);
789
Set<String> notFound = new HashSet<>(expected);
790
notFound.removeAll(actual);
791
StringBuilder sb = new StringBuilder();
792
sb.append("Unexpected but found:\n");
793
unexpected.forEach(s -> sb.append("\t" + s + "\n"));
794
sb.append("Expected but not found:\n");
795
notFound.forEach(s -> sb.append("\t" + s + "\n"));
796
assertTrue(false, "Jmod content check failed.\n" + sb.toString());
797
}
798
}
799
800
static void assertJmodDoesNotContain(Path jmod, Set<String> unexpectedNames) {
801
Set<String> actual = getJmodContent(jmod);
802
Set<String> unexpected = new HashSet<>();
803
for (String name : unexpectedNames) {
804
if (actual.contains(name))
805
unexpected.add(name);
806
}
807
if (!unexpected.isEmpty()) {
808
StringBuilder sb = new StringBuilder();
809
for (String s : unexpected)
810
sb.append("Unexpected but found: " + s + "\n");
811
sb.append("In :");
812
for (String s : actual)
813
sb.append("\t" + s + "\n");
814
assertTrue(false, "Jmod content check failed.\n" + sb.toString());
815
}
816
}
817
818
static void assertSameContent(Path p1, Path p2) {
819
try {
820
byte[] ba1 = Files.readAllBytes(p1);
821
byte[] ba2 = Files.readAllBytes(p2);
822
assertEquals(ba1, ba2);
823
} catch (IOException x) {
824
throw new UncheckedIOException(x);
825
}
826
}
827
828
static JmodResult jmod(String... args) {
829
ByteArrayOutputStream baos = new ByteArrayOutputStream();
830
PrintStream ps = new PrintStream(baos);
831
System.out.println("jmod " + Arrays.asList(args));
832
int ec = JMOD_TOOL.run(ps, ps, args);
833
return new JmodResult(ec, new String(baos.toByteArray(), UTF_8));
834
}
835
836
static class JmodResult {
837
final int exitCode;
838
final String output;
839
840
JmodResult(int exitValue, String output) {
841
this.exitCode = exitValue;
842
this.output = output;
843
}
844
JmodResult assertSuccess() { assertTrue(exitCode == 0, output); return this; }
845
JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; }
846
JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; }
847
}
848
849
static void createCmds(Path dir) throws IOException {
850
List<String> files = Arrays.asList(
851
"first", "second", "third" + File.separator + "third");
852
createFiles(dir, files);
853
}
854
855
static void createLibs(Path dir) throws IOException {
856
List<String> files = Arrays.asList(
857
"first.so", "second.so", "third" + File.separator + "third.so");
858
createFiles(dir, files);
859
}
860
861
static void createConfigs(Path dir) throws IOException {
862
List<String> files = Arrays.asList(
863
"first.cfg", "second.cfg", "third" + File.separator + "third.cfg");
864
createFiles(dir, files);
865
}
866
867
static void createFiles(Path dir, List<String> filenames) throws IOException {
868
for (String name : filenames) {
869
Path file = dir.resolve(name);
870
Files.createDirectories(file.getParent());
871
Files.createFile(file);
872
try (OutputStream os = Files.newOutputStream(file)) {
873
os.write("blahblahblah".getBytes(UTF_8));
874
}
875
}
876
}
877
878
static void copyResource(Path srcDir, Path dir, String resource) throws IOException {
879
Path dest = dir.resolve(resource);
880
Files.deleteIfExists(dest);
881
882
Files.createDirectories(dest.getParent());
883
Files.copy(srcDir.resolve(resource), dest);
884
}
885
886
// Standalone entry point.
887
public static void main(String[] args) throws Throwable {
888
JmodTest test = new JmodTest();
889
test.buildExplodedModules();
890
for (Method m : JmodTest.class.getDeclaredMethods()) {
891
if (m.getAnnotation(Test.class) != null) {
892
System.out.println("Invoking " + m.getName());
893
m.invoke(test);
894
}
895
}
896
}
897
}
898
899