1 /*
2  * Copyright (c) 2016, 2018, 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/timeout=300 JImageExtractTest
31  */
32 
33 import java.io.IOException;
34 import java.nio.file.Files;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.nio.file.attribute.*;
38 import java.util.Arrays;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Set;
42 import java.util.stream.Collectors;
43 
44 import static jdk.test.lib.Asserts.assertEquals;
45 import static jdk.test.lib.Asserts.assertTrue;
46 
47 public class JImageExtractTest extends JImageCliTest {
testExtract()48     public void testExtract() throws IOException {
49         Set<Path> notJImageModules = Files.walk(Paths.get("."),1).collect(Collectors.toSet());
50         jimage("extract", getImagePath())
51                 .assertSuccess()
52                 .resultChecker(r -> {
53                     assertTrue(r.output.isEmpty(), "Output is not expected");
54                 });
55         verifyExplodedImage(Paths.get("."), notJImageModules);
56     }
57 
testExtractHelp()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 
testExtractToDir()69     public void testExtractToDir() throws IOException {
70         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
71         Set<Path> notJImageModules = Files.walk(tmp,1).collect(Collectors.toSet());
72         jimage("extract", "--dir", tmp.toString(), getImagePath())
73                 .assertSuccess()
74                 .resultChecker(r -> {
75                     assertTrue(r.output.isEmpty(), "Output is not expected");
76                 });
77         verifyExplodedImage(tmp, notJImageModules);
78     }
79 
testExtractNoImageSpecified()80     public void testExtractNoImageSpecified() {
81         jimage("extract", "")
82                 .assertFailure()
83                 .assertShowsError();
84     }
85 
testExtractNotAnImage()86     public void testExtractNotAnImage() throws IOException {
87         Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "not_an_image");
88         jimage("extract", tmp.toString())
89                 .assertFailure()
90                 .assertShowsError();
91     }
92 
testExtractNotExistingImage()93     public void testExtractNotExistingImage() throws IOException {
94         Path tmp = Paths.get(".", "not_existing_image");
95         Files.deleteIfExists(tmp);
96         jimage("extract", tmp.toString())
97                 .assertFailure()
98                 .assertShowsError();
99     }
100 
testExtractToUnspecifiedDir()101     public void testExtractToUnspecifiedDir() {
102         jimage("extract", "--dir", "--", getImagePath())
103                 .assertFailure()
104                 .assertShowsError();
105     }
106 
testExtractToNotExistingDir()107     public void testExtractToNotExistingDir() throws IOException {
108         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
109         Set<Path> notJImageModules = Files.walk(tmp,1).collect(Collectors.toSet());
110         Files.delete(tmp);
111         jimage("extract", "--dir", tmp.toString(), getImagePath())
112                 .assertSuccess()
113                 .resultChecker(r -> {
114                     assertTrue(r.output.isEmpty(), "Output is not expected");
115                 });
116         verifyExplodedImage(tmp, notJImageModules);
117     }
118 
testExtractFromDir()119     public void testExtractFromDir() {
120         Path imagePath = Paths.get(getImagePath());
121         Path imageDirPath = imagePath.subpath(0, imagePath.getNameCount() - 1);
122         jimage("extract", imageDirPath.toString())
123                 .assertFailure()
124                 .assertShowsError();
125     }
126 
testExtractToDirBySymlink()127     public void testExtractToDirBySymlink() throws IOException {
128         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
129         Path symlink;
130         try {
131             symlink = Files.createSymbolicLink(Paths.get(".", "symlink"), tmp);
132         } catch (IOException|UnsupportedOperationException e) {
133             // symlinks are not supported
134             // nothing to test
135             return;
136         }
137         Set<Path> notJImageModules = Files.walk(tmp,1).collect(Collectors.toSet());
138         jimage("extract", "--dir", symlink.toString(), getImagePath())
139                 .assertSuccess()
140                 .resultChecker(r -> {
141                     assertTrue(r.output.isEmpty(), "Output is not expected");
142                 });
143         verifyExplodedImage(tmp, notJImageModules);
144     }
145 
testExtractToReadOnlyDir()146     public void testExtractToReadOnlyDir() throws IOException {
147         Path filePath = Files.createTempDirectory(Paths.get("."), getClass().getName());
148         Set<String> supportedAttr = filePath.getFileSystem().supportedFileAttributeViews();
149         if (supportedAttr.contains("posix")) {
150             Files.setPosixFilePermissions(filePath, PosixFilePermissions.fromString("r-xr--r--"));
151         } else if (supportedAttr.contains("acl")) {
152             System.out.println("Entered into acl block");
153             UserPrincipal fileOwner = Files.getOwner(filePath);
154             AclFileAttributeView view = Files.getFileAttributeView(filePath, AclFileAttributeView.class);
155             AclEntry entry = AclEntry.newBuilder()
156                                      .setType(AclEntryType.DENY)
157                                      .setPrincipal(fileOwner)
158                                      .setPermissions(AclEntryPermission.WRITE_DATA)
159                                      .setFlags(AclEntryFlag.FILE_INHERIT, AclEntryFlag.DIRECTORY_INHERIT)
160                                      .build();
161             List<AclEntry> acl = view.getAcl();
162             acl.add(0, entry);
163             view.setAcl(acl);
164         }
165         jimage("extract", "--dir", filePath.toString(), getImagePath())
166                 .assertFailure()
167                 .assertShowsError();
168     }
169 
testExtractToNotEmptyDir()170     public void testExtractToNotEmptyDir() throws IOException {
171         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
172         Files.createFile(Paths.get(tmp.toString(), ".not_empty"));
173         jimage("extract", "--dir", tmp.toString(), getImagePath())
174                 .assertSuccess()
175                 .resultChecker(r -> {
176                     assertTrue(r.output.isEmpty(), "Output is not expected");
177                 });
178     }
179 
testExtractToFile()180     public void testExtractToFile() throws IOException {
181         Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "not_a_dir");
182         jimage("extract", "--dir", tmp.toString(), getImagePath())
183                 .assertFailure()
184                 .assertShowsError();
185     }
186 
verifyExplodedImage(Path imagePath, Set<Path> notJImageModules)187     private void verifyExplodedImage(Path imagePath, Set<Path> notJImageModules) throws IOException {
188         Set<Path> allModules = Files.walk(imagePath, 1).collect(Collectors.toSet());
189         assertTrue(allModules.stream().anyMatch(p -> "java.base".equals(p.getFileName().toString())),
190                 "Exploded image contains java.base module.");
191         Set<Path> badModules = allModules.stream()
192                 .filter(p -> !Files.exists(p.resolve("module-info.class")))
193                 .collect(Collectors.toSet());
194         // filter bad modules which are not part of jimage
195         badModules.removeAll(notJImageModules);
196         assertEquals(badModules, new HashSet<Path>() {{}},
197                 "There are no exploded modules with missing 'module-info.class'");
198     }
199 
main(String[] args)200     public static void main(String[] args) throws Throwable {
201         new JImageExtractTest().runTests();
202     }
203 }
204 
205