1/*
2 * Copyright (c) 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 Tests to verify jimage 'extract' action
27 * @library /test/lib
28 * @modules jdk.jlink/jdk.tools.jimage
29 * @build jdk.test.lib.Asserts
30 * @run main/othervm JImageExtractTest
31 */
32
33import java.io.IOException;
34import java.nio.file.Files;
35import java.nio.file.Path;
36import java.nio.file.Paths;
37import java.nio.file.attribute.FileAttribute;
38import java.nio.file.attribute.PosixFilePermission;
39import java.nio.file.attribute.PosixFilePermissions;
40import java.util.Arrays;
41import java.util.HashSet;
42import java.util.Set;
43import java.util.stream.Collectors;
44
45import static jdk.test.lib.Asserts.assertEquals;
46import static jdk.test.lib.Asserts.assertTrue;
47
48public class JImageExtractTest extends JImageCliTest {
49    public void testExtract() throws IOException {
50        jimage("extract", getImagePath())
51                .assertSuccess()
52                .resultChecker(r -> {
53                    assertTrue(r.output.isEmpty(), "Output is not expected");
54                });
55        verifyExplodedImage(Paths.get("."));
56    }
57
58    public void testExtractHelp() {
59        for (String opt : Arrays.asList("-h", "--help")) {
60            jimage("extract", "--help")
61                    .assertSuccess()
62                    .resultChecker(r -> {
63                        // extract  -  descriptive text
64                        assertMatches("\\s+extract\\s+-\\s+.*", r.output);
65                    });
66        }
67    }
68
69    public void testExtractToDir() throws IOException {
70        Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
71        jimage("extract", "--dir", tmp.toString(), getImagePath())
72                .assertSuccess()
73                .resultChecker(r -> {
74                    assertTrue(r.output.isEmpty(), "Output is not expected");
75                });
76        verifyExplodedImage(tmp);
77    }
78
79    public void testExtractNoImageSpecified() {
80        jimage("extract", "")
81                .assertFailure()
82                .assertShowsError();
83    }
84
85    public void testExtractNotAnImage() throws IOException {
86        Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "not_an_image");
87        jimage("extract", tmp.toString())
88                .assertFailure()
89                .assertShowsError();
90    }
91
92    public void testExtractNotExistingImage() throws IOException {
93        Path tmp = Paths.get(".", "not_existing_image");
94        Files.deleteIfExists(tmp);
95        jimage("extract", tmp.toString())
96                .assertFailure()
97                .assertShowsError();
98    }
99
100    public void testExtractToUnspecifiedDir() {
101        jimage("extract", "--dir", "--", getImagePath())
102                .assertFailure()
103                .assertShowsError();
104    }
105
106    public void testExtractToNotExistingDir() throws IOException {
107        Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
108        Files.delete(tmp);
109        jimage("extract", "--dir", tmp.toString(), getImagePath())
110                .assertSuccess()
111                .resultChecker(r -> {
112                    assertTrue(r.output.isEmpty(), "Output is not expected");
113                });
114        verifyExplodedImage(tmp);
115    }
116
117    public void testExtractFromDir() {
118        Path imagePath = Paths.get(getImagePath());
119        Path imageDirPath = imagePath.subpath(0, imagePath.getNameCount() - 1);
120        jimage("extract", imageDirPath.toString())
121                .assertFailure()
122                .assertShowsError();
123    }
124
125    public void testExtractToDirBySymlink() throws IOException {
126        Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
127        try {
128            Path symlink = Files.createSymbolicLink(Paths.get(".", "symlink"), tmp);
129            jimage("extract", "--dir", symlink.toString(), getImagePath())
130                    .assertSuccess()
131                    .resultChecker(r -> {
132                        assertTrue(r.output.isEmpty(), "Output is not expected");
133                    });
134            verifyExplodedImage(tmp);
135        } catch (UnsupportedOperationException e) {
136            // symlinks are not supported
137            // nothing to test
138        }
139    }
140
141    public void testExtractToReadOnlyDir() throws IOException {
142        Set<PosixFilePermission> perms = PosixFilePermissions.fromString("r-xr--r--");
143        FileAttribute<Set<PosixFilePermission>> atts = PosixFilePermissions.asFileAttribute(perms);
144        Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName(), atts);
145        jimage("extract", "--dir", tmp.toString(), getImagePath())
146                .assertFailure()
147                .assertShowsError();
148    }
149
150    public void testExtractToNotEmptyDir() throws IOException {
151        Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
152        Files.createFile(Paths.get(tmp.toString(), ".not_empty"));
153        jimage("extract", "--dir", tmp.toString(), getImagePath())
154                .assertFailure()
155                .assertShowsError();
156    }
157
158    public void testExtractToFile() throws IOException {
159        Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "not_a_dir");
160        jimage("extract", "--dir", tmp.toString(), getImagePath())
161                .assertFailure()
162                .assertShowsError();
163    }
164
165    private void verifyExplodedImage(Path imagePath) throws IOException {
166        Set<Path> allModules = Files.walk(imagePath, 1).collect(Collectors.toSet());
167        assertTrue(allModules.stream().anyMatch(p -> "java.base".equals(p.getFileName().toString())),
168                "Exploded image contains java.base module.");
169
170        Set<Path> badModules = allModules.stream()
171                .filter(p -> !Files.exists(p.resolve("module-info.class")))
172                .collect(Collectors.toSet());
173        assertEquals(badModules, new HashSet<Path>() {{ add(imagePath); }},
174                "There are no exploded modules with missing 'module-info.class'");
175    }
176
177    public static void main(String[] args) throws Throwable {
178        new JImageExtractTest().runTests();
179    }
180}
181
182