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