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 JImageCliTest
  30  * @run main/othervm JImageExtractTest
  31  */
  32 
  33 import java.io.File;
  34 import java.io.IOException;
  35 import java.nio.file.Files;
  36 import java.nio.file.Path;
  37 import java.nio.file.Paths;
  38 import java.nio.file.attribute.FileAttribute;
  39 import java.nio.file.attribute.PosixFilePermission;
  40 import java.nio.file.attribute.PosixFilePermissions;
  41 import java.util.Arrays;
  42 import java.util.HashSet;
  43 import java.util.Set;
  44 import java.util.stream.Collectors;
  45 
  46 import static jdk.test.lib.Asserts.assertEquals;
  47 import static jdk.test.lib.Asserts.assertTrue;
  48 
  49 public class JImageExtractTest extends JImageCliTest {
  50     public void beforeTest() throws IOException {
  51         Path cwd = new File(".").toPath();
  52         System.out.printf("cleaning working dir [%s]... \n", cwd.toAbsolutePath());
  53         for (File f : new File(".").listFiles()) {
  54             if (f.isDirectory()) {
  55                 jdk.test.lib.util.FileUtils.deleteFileTreeWithRetry(f.toPath());
  56             } else {
  57                 f.delete();
  58             }
  59         }
  60     }
  61 
  62     public void testExtract() throws IOException {
  63         jimage("extract", getImagePath())
  64                 .assertSuccess()
  65                 .resultChecker(r -> {
  66                     assertTrue(r.output.isEmpty(), "Output is not expected");
  67                 });
  68         verifyExplodedImage(Paths.get("."));
  69     }
  70 
  71     // do a second round to check that workspace initialization works ok
  72     public void testExtractSecondRound() throws IOException {
  73         jimage("extract", getImagePath())
  74                 .assertSuccess()
  75                 .resultChecker(r -> {
  76                     assertTrue(r.output.isEmpty(), "Output is not expected");
  77                 });
  78         verifyExplodedImage(Paths.get("."));
  79     }
  80 
  81     public void testExtractHelp() {
  82         for (String opt : Arrays.asList("-h", "--help")) {
  83             jimage("extract", "--help")
  84                     .assertSuccess()
  85                     .resultChecker(r -> {
  86                         // extract  -  descriptive text
  87                         assertMatches("\\s+extract\\s+-\\s+.*", r.output);
  88                     });
  89         }
  90     }
  91 
  92     public void testExtractToDir() throws IOException {
  93         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
  94         jimage("extract", "--dir", tmp.toString(), getImagePath())
  95                 .assertSuccess()
  96                 .resultChecker(r -> {
  97                     assertTrue(r.output.isEmpty(), "Output is not expected");
  98                 });
  99         verifyExplodedImage(tmp);
 100     }
 101 
 102     public void testExtractNoImageSpecified() {
 103         jimage("extract", "")
 104                 .assertFailure()
 105                 .assertShowsError();
 106     }
 107 
 108     public void testExtractEmptyFile() throws IOException {
 109         Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "empty_file");
 110         jimage("extract", "--dir", "some_directory", tmp.toString())
 111                 .assertFailure()
 112                 .assertShowsError();
 113     }
 114 
 115     public void testExtractNotAnImage() throws IOException {
 116         Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "not_an_image");
 117         Files.write(tmp, "This is not an image".getBytes());
 118         jimage("extract", "--dir", "some_directory", tmp.toString())
 119                 .assertFailure()
 120                 .assertShowsError();
 121     }
 122 
 123     public void testExtractNotExistingImage() throws IOException {
 124         Path tmp = Paths.get(".", "not_existing_image");
 125         Files.deleteIfExists(tmp);
 126         jimage("extract", tmp.toString())
 127                 .assertFailure()
 128                 .assertShowsError();
 129     }
 130 
 131     public void testExtractToUnspecifiedDir() {
 132         jimage("extract", "--dir", "--", getImagePath())
 133                 .assertFailure()
 134                 .assertShowsError();
 135     }
 136 
 137     public void testExtractToNotExistingDir() throws IOException {
 138         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
 139         Files.delete(tmp);
 140         jimage("extract", "--dir", tmp.toString(), getImagePath())
 141                 .assertSuccess()
 142                 .resultChecker(r -> {
 143                     assertTrue(r.output.isEmpty(), "Output is not expected");
 144                 });
 145         verifyExplodedImage(tmp);
 146     }
 147 
 148     public void testExtractFromDir() {
 149         Path imagePath = Paths.get(getImagePath());
 150         Path imageDirPath = imagePath.subpath(0, imagePath.getNameCount() - 1);
 151         jimage("extract", imageDirPath.toString())
 152                 .assertFailure()
 153                 .assertShowsError();
 154     }
 155 
 156     public void testExtractToDirBySymlink() throws IOException {
 157         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
 158         Path symlink;
 159         try {
 160             symlink = Files.createSymbolicLink(Paths.get(".", "symlink"), tmp);
 161         } catch (IOException|UnsupportedOperationException e) {
 162             // symlinks are not supported
 163             // nothing to test
 164             return;
 165         }
 166 
 167         jimage("extract", "--dir", symlink.toString(), getImagePath())
 168                 .assertSuccess()
 169                 .resultChecker(r -> {
 170                     assertTrue(r.output.isEmpty(), "Output is not expected");
 171                 });
 172         verifyExplodedImage(tmp);
 173     }
 174 
 175     public void testExtractToReadOnlyDir() throws IOException {
 176         Set<PosixFilePermission> perms = PosixFilePermissions.fromString("r-xr--r--");
 177         FileAttribute<Set<PosixFilePermission>> atts = PosixFilePermissions.asFileAttribute(perms);
 178         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName(), atts);
 179         jimage("extract", "--dir", tmp.toString(), getImagePath())
 180                 .assertFailure()
 181                 .assertShowsError();
 182     }
 183 
 184     public void testExtractToNotEmptyDir() throws IOException {
 185         Path tmp = Files.createTempDirectory(Paths.get("."), getClass().getName());
 186         Files.createFile(Paths.get(tmp.toString(), ".not_empty"));
 187         jimage("extract", "--dir", tmp.toString(), getImagePath())
 188                 .assertFailure()
 189                 .assertShowsError();
 190     }
 191 
 192     public void testExtractToFile() throws IOException {
 193         Path tmp = Files.createTempFile(Paths.get("."), getClass().getName(), "not_a_dir");
 194         jimage("extract", "--dir", tmp.toString(), getImagePath())
 195                 .assertFailure()
 196                 .assertShowsError();
 197     }
 198 
 199     private void verifyExplodedImage(Path imagePath) throws IOException {
 200         Set<Path> allModules = Files.walk(imagePath, 1).collect(Collectors.toSet());
 201         assertTrue(allModules.stream().anyMatch(p -> "java.base".equals(p.getFileName().toString())),
 202                 "Exploded image contains java.base module.");
 203 
 204         Set<Path> badModules = allModules.stream()
 205                 .filter(p -> !Files.exists(p.resolve("module-info.class")))
 206                 .collect(Collectors.toSet());
 207         assertEquals(badModules, new HashSet<Path>() {{ add(imagePath); }},
 208                 "There are no exploded modules with missing 'module-info.class'");
 209     }
 210 
 211     public static void main(String[] args) throws Throwable {
 212         new JImageExtractTest().runTests();
 213     }
 214 }
 215