JmodNegativeTest.java revision 13901:b2a69d66dc65
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 * @library /lib/testlibrary
27 * @modules jdk.jlink/jdk.tools.jmod
28 *          jdk.compiler
29 * @build jdk.testlibrary.FileUtils CompilerUtils
30 * @run testng JmodNegativeTest
31 * @summary Negative tests for jmod
32 */
33
34import java.io.*;
35import java.nio.file.Files;
36import java.nio.file.Path;
37import java.nio.file.Paths;
38import java.util.Arrays;
39import java.util.List;
40import java.util.function.Consumer;
41import java.util.function.Supplier;
42import java.util.zip.ZipOutputStream;
43import jdk.testlibrary.FileUtils;
44import org.testng.annotations.BeforeTest;
45import org.testng.annotations.DataProvider;
46import org.testng.annotations.Test;
47
48import static java.io.File.pathSeparator;
49import static java.nio.charset.StandardCharsets.UTF_8;
50import static org.testng.Assert.assertTrue;
51
52public class JmodNegativeTest {
53
54    static final String TEST_SRC = System.getProperty("test.src", ".");
55    static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
56    static final Path EXPLODED_DIR = Paths.get("build");
57    static final Path MODS_DIR = Paths.get("jmods");
58
59    @BeforeTest
60    public void buildExplodedModules() throws IOException {
61        if (Files.exists(EXPLODED_DIR))
62            FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR);
63
64        for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {
65            Path dir = EXPLODED_DIR.resolve(name);
66            assertTrue(compileModule(name, dir.resolve("classes")));
67        }
68
69        if (Files.exists(MODS_DIR))
70            FileUtils.deleteFileTreeWithRetry(MODS_DIR);
71        Files.createDirectories(MODS_DIR);
72    }
73
74    @Test
75    public void testNoArgs() {
76        jmod()
77            .assertFailure()
78            .resultChecker(r ->
79                assertContains(r.output, "Error: one of create, list, or describe must be specified")
80            );
81    }
82
83    @Test
84    public void testBadAction() {
85        jmod("badAction")
86            .assertFailure()
87            .resultChecker(r ->
88                assertContains(r.output, "Error: mode must be one of create, list, or describe")
89            );
90
91        jmod("--badOption")
92            .assertFailure()
93            .resultChecker(r ->
94                assertContains(r.output, "Error: 'badOption' is not a recognized option")
95            );
96    }
97
98    @Test
99    public void testTooManyArgs() throws IOException {
100        Path jmod = MODS_DIR.resolve("doesNotExist.jmod");
101        FileUtils.deleteFileIfExistsWithRetry(jmod);
102
103        jmod("create",
104             jmod.toString(),
105             "AAA")
106            .assertFailure()
107            .resultChecker(r ->
108                assertContains(r.output, "Error: unknown option(s): [AAA]")
109            );
110    }
111
112    @Test
113    public void testCreateNoArgs() {
114        jmod("create")
115            .assertFailure()
116            .resultChecker(r ->
117                assertContains(r.output, "Error: jmod-file must be specified")
118            );
119    }
120
121    @Test
122    public void testListNoArgs() {
123        jmod("list")
124            .assertFailure()
125            .resultChecker(r ->
126                assertContains(r.output, "Error: jmod-file must be specified")
127            );
128    }
129
130    @Test
131    public void testListFileDoesNotExist() throws IOException {
132        Path jmod = MODS_DIR.resolve("doesNotExist.jmod");
133        FileUtils.deleteFileIfExistsWithRetry(jmod);
134
135        jmod("list",
136             jmod.toString())
137            .assertFailure()
138            .resultChecker(r ->
139                assertContains(r.output, "Error: no jmod file found: "
140                        + jmod.toString())
141            );
142    }
143
144    @Test
145    public void testListJmodIsDir() throws IOException {
146        Path jmod = MODS_DIR.resolve("testListJmodIsDir.jmod");
147        if (Files.notExists(jmod))
148            Files.createDirectory(jmod);
149
150        jmod("list",
151             jmod.toString())
152            .assertFailure()
153            .resultChecker(r ->
154                assertContains(r.output, "Error: error opening jmod file")
155            );
156    }
157
158    @Test
159    public void testlistJmodMalformed() throws IOException {
160        Path jmod = MODS_DIR.resolve("testlistJmodMalformed.jmod");
161        if (Files.notExists(jmod))
162            Files.createFile(jmod);
163
164        jmod("list",
165             jmod.toString())
166            .assertFailure()
167            .resultChecker(r ->
168                assertContains(r.output, "Error: error opening jmod file")
169            );
170    }
171
172    @Test
173    public void testHashDependenciesModulePathNotSpecified() {
174        jmod("create",
175             "--hash-dependencies", "anyPattern.*",
176             "output.jmod")
177            .assertFailure()
178            .resultChecker(r ->
179                assertContains(r.output, "Error: --module-path must be "
180                        +"specified when hashing dependencies")
181            );
182    }
183
184    @Test
185    public void testCreateJmodAlreadyExists() throws IOException {
186        Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists.jmod");
187        if (Files.notExists(jmod))
188            Files.createFile(jmod);
189
190        jmod("create",
191             "--class-path", Paths.get(".").toString(), // anything that exists
192             jmod.toString())
193            .assertFailure()
194            .resultChecker(r ->
195                assertContains(r.output, "Error: file already exists: " + jmod.toString())
196            );
197    }
198
199    @Test
200    public void testCreateJmodIsDir() throws IOException {
201        Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists");
202        if (Files.notExists(jmod))
203            Files.createDirectory(jmod);
204
205        jmod("create",
206             "--class-path", Paths.get(".").toString(), // anything that exists
207             jmod.toString())
208            .assertFailure()
209            .resultChecker(r ->
210                assertContains(r.output, "Error: file already exists: " + jmod.toString())
211            );
212    }
213
214    @Test
215    public void testInvalidModuleVersion() throws IOException {
216        Path jmod = MODS_DIR.resolve("testEmptyModuleVersion.jmod");
217        FileUtils.deleteFileIfExistsWithRetry(jmod);
218        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
219
220        for (String version : new String[] { "", "NOT_A_VALID_VERSION" }) {
221            jmod("create",
222                 "--class-path", cp,
223                 "--module-version", version,
224                 jmod.toString())
225                .assertFailure()
226                .resultChecker(r ->
227                    assertContains(r.output, "Error: invalid module version")
228                );
229        }
230    }
231
232    @Test(enabled = false)  // TODO: jmod should check for duplicates before creating.
233    public void testDuplicates() throws IOException {
234        Path jmod = MODS_DIR.resolve("testDuplicates.jmod");
235        FileUtils.deleteFileIfExistsWithRetry(jmod);
236        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
237
238        jmod("create",
239             "--class-path", cp + pathSeparator + cp,
240             jmod.toString())
241            .assertFailure()
242            .resultChecker(r ->
243                assertContains(r.output, "Error: duplicate resource found, etc..")
244            );
245    }
246
247    @Test
248    public void testEmptyFileInClasspath() throws IOException {
249        Path jmod = MODS_DIR.resolve("testEmptyFileInClasspath.jmod");
250        FileUtils.deleteFileIfExistsWithRetry(jmod);
251        Path jar = MODS_DIR.resolve("NotARealJar_Empty.jar");
252        FileUtils.deleteFileIfExistsWithRetry(jar);
253        Files.createFile(jar);
254
255        jmod("create",
256             "--class-path", jar.toString(),
257             jmod.toString())
258            .assertFailure()
259            .resultChecker(r ->
260                assertContains(r.output, "Error: module-info.class not found")
261            );
262    }
263
264    @Test
265    public void testEmptyJarInClasspath() throws IOException {
266        Path jmod = MODS_DIR.resolve("testEmptyJarInClasspath.jmod");
267        FileUtils.deleteFileIfExistsWithRetry(jmod);
268        Path jar = MODS_DIR.resolve("empty.jar");
269        FileUtils.deleteFileIfExistsWithRetry(jar);
270        try (FileOutputStream fos = new FileOutputStream(jar.toFile());
271             ZipOutputStream zos = new ZipOutputStream(fos)) {
272            // empty
273        }
274
275        jmod("create",
276             "--class-path", jar.toString(),
277             jmod.toString())
278            .assertFailure()
279            .resultChecker(r ->
280                assertContains(r.output, "Error: module-info.class not found")
281            );
282    }
283
284    @Test
285    public void testModuleInfoNotFound() throws IOException {
286        Path jmod = MODS_DIR.resolve("output.jmod");
287        FileUtils.deleteFileIfExistsWithRetry(jmod);
288        Path jar = MODS_DIR.resolve("empty");
289        FileUtils.deleteFileIfExistsWithRetry(jar);
290        Files.createDirectory(jar);
291
292        jmod("create",
293             "--class-path", jar.toString(),
294             jmod.toString())
295            .assertFailure()
296            .resultChecker(r ->
297                assertContains(r.output, "Error: module-info.class not found")
298            );
299    }
300
301    @Test
302    public void testModuleInfoIsDir() throws IOException {
303        Path jmod = MODS_DIR.resolve("output.jmod");
304        FileUtils.deleteFileIfExistsWithRetry(jmod);
305        Path cp = MODS_DIR.resolve("module-info.class");
306        FileUtils.deleteFileIfExistsWithRetry(cp);
307        Files.createDirectory(cp);
308        Files.createFile(cp.resolve("nada.txt"));
309
310        jmod("create",
311             "--class-path", cp.toString(),
312             jmod.toString())
313            .assertFailure()
314            .resultChecker(r ->
315                assertContains(r.output, "Error: module-info.class not found")
316            );
317    }
318
319    @Test
320    public void testDependencyNotFound() throws IOException {
321        Path jmod = MODS_DIR.resolve("output.jmod");
322        FileUtils.deleteFileIfExistsWithRetry(jmod);
323        Path emptyDir = Paths.get("empty");
324        if (Files.exists(emptyDir))
325            FileUtils.deleteFileTreeWithRetry(emptyDir);
326        Files.createDirectory(emptyDir);
327        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
328
329        jmod("create",
330             "--class-path", cp,
331             "--hash-dependencies", ".*",
332             "--modulepath", emptyDir.toString(),
333            jmod.toString())
334            .assertFailure()
335            .resultChecker(r ->
336                assertContains(r.output, "Hashing module foo dependencies, "
337                        + "unable to find module java.base on module path")
338            );
339    }
340
341    @Test
342    public void testEmptyFileInModulePath() throws IOException {
343        Path jmod = MODS_DIR.resolve("output.jmod");
344        FileUtils.deleteFileIfExistsWithRetry(jmod);
345        Path empty = MODS_DIR.resolve("emptyFile.jmod");
346        FileUtils.deleteFileIfExistsWithRetry(empty);
347        Files.createFile(empty);
348        try {
349            String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
350
351            jmod("create",
352                 "--class-path", cp,
353                 "--hash-dependencies", ".*",
354                 "--modulepath", MODS_DIR.toString(),
355                 jmod.toString())
356                .assertFailure()
357                .resultChecker(r ->
358                    assertContains(r.output, "Error: error reading module path")
359                );
360        } finally {
361            FileUtils.deleteFileWithRetry(empty);
362        }
363    }
364
365    @Test
366    public void testFileInModulePath() throws IOException {
367        Path jmod = MODS_DIR.resolve("output.jmod");
368        FileUtils.deleteFileIfExistsWithRetry(jmod);
369        Path file = MODS_DIR.resolve("testFileInModulePath.txt");
370        FileUtils.deleteFileIfExistsWithRetry(file);
371        Files.createFile(file);
372
373        jmod("create",
374             "--hash-dependencies", ".*",
375             "--modulepath", file.toString(),
376             jmod.toString())
377            .assertFailure()
378            .resultChecker(r ->
379                assertContains(r.output, "Error: path must be a directory")
380            );
381    }
382
383    @DataProvider(name = "pathDoesNotExist")
384    public Object[][] pathDoesNotExist() throws IOException {
385        Path jmod = MODS_DIR.resolve("output.jmod");
386        FileUtils.deleteFileIfExistsWithRetry(jmod);
387        FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist"));
388
389        List<Supplier<JmodResult>> tasks = Arrays.asList(
390                () -> jmod("create",
391                           "--hash-dependencies", "anyPattern",
392                           "--modulepath", "doesNotExist",
393                           "output.jmod"),
394                () -> jmod("create",
395                           "--class-path", "doesNotExist",
396                           "output.jmod"),
397                () -> jmod("create",
398                           "--class-path", "doesNotExist.jar",
399                           "output.jmod"),
400                () -> jmod("create",
401                           "--cmds", "doesNotExist",
402                           "output.jmod"),
403                () -> jmod("create",
404                           "--config", "doesNotExist",
405                           "output.jmod"),
406                () -> jmod("create",
407                           "--libs", "doesNotExist",
408                           "output.jmod") );
409
410        String errMsg = "Error: path not found: doesNotExist";
411        return tasks.stream().map(t -> new Object[] {t, errMsg} )
412                             .toArray(Object[][]::new);
413    }
414
415    @Test(dataProvider = "pathDoesNotExist")
416    public void testPathDoesNotExist(Supplier<JmodResult> supplier,
417                                     String errMsg)
418    {
419        supplier.get()
420                .assertFailure()
421                .resultChecker(r -> {
422                    assertContains(r.output, errMsg);
423                });
424    }
425
426    @DataProvider(name = "partOfPathDoesNotExist")
427    public Object[][] partOfPathDoesNotExist() throws IOException {
428        Path jmod = MODS_DIR.resolve("output.jmod");
429        FileUtils.deleteFileIfExistsWithRetry(jmod);
430        FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist"));
431
432        Path emptyDir = Paths.get("empty");
433        if (Files.exists(emptyDir))
434            FileUtils.deleteFileTreeWithRetry(emptyDir);
435        Files.createDirectory(emptyDir);
436
437        List<Supplier<JmodResult>> tasks = Arrays.asList(
438            () -> jmod("create",
439                       "--hash-dependencies", "anyPattern",
440                       "--modulepath","empty" + pathSeparator + "doesNotExist",
441                       "output.jmod"),
442            () -> jmod("create",
443                       "--class-path", "empty" + pathSeparator + "doesNotExist",
444                       "output.jmod"),
445            () -> jmod("create",
446                       "--class-path", "empty" + pathSeparator + "doesNotExist.jar",
447                       "output.jmod"),
448            () -> jmod("create",
449                       "--cmds", "empty" + pathSeparator + "doesNotExist",
450                       "output.jmod"),
451            () -> jmod("create",
452                       "--config", "empty" + pathSeparator + "doesNotExist",
453                       "output.jmod"),
454            () -> jmod("create",
455                       "--libs", "empty" + pathSeparator + "doesNotExist",
456                       "output.jmod") );
457
458        String errMsg = "Error: path not found: doesNotExist";
459        return tasks.stream().map(t -> new Object[] {t, errMsg} )
460                             .toArray(Object[][]::new);
461    }
462
463    @Test(dataProvider = "partOfPathDoesNotExist")
464    public void testPartOfPathNotExist(Supplier<JmodResult> supplier,
465                                       String errMsg)
466    {
467        supplier.get()
468                .assertFailure()
469                .resultChecker(r -> {
470                    assertContains(r.output, errMsg);
471                });
472    }
473
474    @DataProvider(name = "pathIsFile")
475    public Object[][] pathIsFile() throws IOException {
476        Path jmod = MODS_DIR.resolve("output.jmod");
477        FileUtils.deleteFileIfExistsWithRetry(jmod);
478        Path aFile = Paths.get("aFile.txt");
479        if (Files.exists(aFile) && !Files.isRegularFile(aFile))
480            throw new InternalError("Unexpected file:" + aFile);
481        else
482            Files.createFile(aFile);
483
484        List<Supplier<JmodResult>> tasks = Arrays.asList(
485                () -> jmod("create",
486                           "--class-path", "aFile.txt",
487                           "output.jmod"),
488                () -> jmod("create",
489                           "--modulepath", "aFile.txt",
490                           "output.jmod"),
491                () -> jmod("create",
492                           "--cmds", "aFile.txt",
493                           "output.jmod"),
494                () -> jmod("create",
495                           "--config", "aFile.txt",
496                           "output.jmod"),
497                () -> jmod("create",
498                           "--libs", "aFile.txt",
499                           "output.jmod") );
500
501        String errMsg = "Error: path must be a directory: aFile.txt";
502        Object[][] a = tasks.stream().map(t -> new Object[] {t, errMsg} )
503                                     .toArray(Object[][]::new);
504        a[0][1] = "invalid class path entry: aFile.txt";  // class path err msg
505        return a;
506    }
507
508    @Test(dataProvider = "pathIsFile")
509    public void testPathIsFile(Supplier<JmodResult> supplier,
510                               String errMsg)
511    {
512        supplier.get()
513                .assertFailure()
514                .resultChecker(r -> {
515                    assertContains(r.output, errMsg);
516                });
517    }
518
519    // ---
520
521    static boolean compileModule(String name, Path dest) throws IOException {
522        return CompilerUtils.compile(SRC_DIR.resolve(name), dest);
523    }
524
525    static void assertContains(String output, String subString) {
526        if (output.contains(subString))
527            assertTrue(true);
528        else
529            assertTrue(false,"Expected to find [" + subString + "], in output ["
530                             + output + "]");
531    }
532
533    static JmodResult jmod(String... args) {
534        ByteArrayOutputStream baos = new ByteArrayOutputStream();
535        PrintStream ps = new PrintStream(baos);
536        System.out.println("jmod " + Arrays.asList(args));
537        int ec = jdk.tools.jmod.Main.run(args, ps);
538        return new JmodResult(ec, new String(baos.toByteArray(), UTF_8));
539    }
540
541    static class JmodResult {
542        final int exitCode;
543        final String output;
544
545        JmodResult(int exitValue, String output) {
546            this.exitCode = exitValue;
547            this.output = output;
548        }
549        JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; }
550        JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; }
551    }
552}
553