Path: blob/master/test/jdk/tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java
41149 views
/*1* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 815649926* @summary Test image creation from Multi-Release JAR27* @author Steve Drach28* @library /test/lib29* @modules java.base/jdk.internal.jimage30* java.base/jdk.internal.module31* jdk.compiler32* jdk.jartool33* jdk.jlink34* jdk.zipfs35* @build jdk.test.lib.Utils36* jdk.test.lib.Asserts37* jdk.test.lib.JDKToolFinder38* jdk.test.lib.JDKToolLauncher39* jdk.test.lib.Platform40* jdk.test.lib.process.*41* @run testng JLinkMultiReleaseJarTest42*/4344import java.io.ByteArrayInputStream;45import java.io.IOException;46import java.lang.invoke.MethodHandle;47import java.lang.invoke.MethodHandles;48import java.lang.invoke.MethodType;49import java.lang.module.ModuleDescriptor;50import java.nio.file.Files;51import java.nio.file.Path;52import java.nio.file.Paths;53import java.nio.file.StandardCopyOption;54import java.util.ArrayList;55import java.util.Arrays;56import java.util.List;57import java.util.Set;58import java.util.jar.JarFile;59import java.util.spi.ToolProvider;60import java.util.stream.Collectors;61import java.util.stream.Stream;6263import jdk.internal.jimage.BasicImageReader;64import jdk.test.lib.process.ProcessTools;65import jdk.test.lib.process.OutputAnalyzer;6667import org.testng.Assert;68import org.testng.annotations.BeforeClass;69import org.testng.annotations.Test;7071public class JLinkMultiReleaseJarTest {72private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")73.orElseThrow(() -> new RuntimeException("jar tool not found"));74private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")75.orElseThrow(() -> new RuntimeException("javac tool not found"));76private static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")77.orElseThrow(() -> new RuntimeException("jlink tool not found"));7879private final Path userdir = Paths.get(System.getProperty("user.dir", "."));80private final Path javahome = Paths.get(System.getProperty("java.home"));81private final Path jmodsdir = javahome.resolve("jmods");8283private final String pathsep = System.getProperty("path.separator");8485private byte[] resource = (Runtime.version().major() + " resource file").getBytes();8687@BeforeClass88public void initialize() throws IOException {89Path srcdir = Paths.get(System.getProperty("test.src"));9091// create class files from source92Path base = srcdir.resolve("base");93Path basemods = userdir.resolve("basemods");94javac(base, basemods, base.toString());9596Path rt = srcdir.resolve("rt");97Path rtmods = userdir.resolve("rtmods");98javac(rt, rtmods, rt.toString());99100// create resources in basemods and rtmods101Path dest = basemods.resolve("m1").resolve("resource.txt");102byte[] text = "base resource file".getBytes();103ByteArrayInputStream is = new ByteArrayInputStream(text);104Files.copy(is, dest);105106dest = rtmods.resolve("m1").resolve("resource.txt");107is = new ByteArrayInputStream(resource);108Files.copy(is, dest);109110// build multi-release jar file with different module-infos111String[] args = {112"-cf", "m1.jar",113"-C", basemods.resolve("m1").toString(), ".",114"--release ", String.valueOf(JarFile.runtimeVersion().major()),115"-C", rtmods.resolve("m1").toString(), "."116};117JAR_TOOL.run(System.out, System.err, args);118119// now move the module-info that requires logging to temporary place120Files.move(rtmods.resolve("m1").resolve("module-info.class"),121userdir.resolve("module-info.class"));122123// and build another jar124args[1] = "m1-no-logging.jar";125JAR_TOOL.run(System.out, System.err, args);126127// replace the no logging module-info with the logging module-info128Files.move(userdir.resolve("module-info.class"),129basemods.resolve("m1").resolve("module-info.class"),130StandardCopyOption.REPLACE_EXISTING);131132// and build another jar133args[1] = "m1-logging.jar";134JAR_TOOL.run(System.out, System.err, args);135}136137private void javac(Path source, Path destination, String srcpath) throws IOException {138var args = Stream.of("-d", destination.toString(), "--module-source-path", srcpath);139try (Stream<Path> pathStream = Files.walk(source)) {140args = Stream.concat(args,141pathStream.map(Path::toString)142.filter(s -> s.endsWith(".java")));143144int rc = JAVAC_TOOL.run(System.out, System.err, args.toArray(String[]::new));145Assert.assertEquals(rc, 0);146}147}148149@Test150public void basicTest() throws Throwable {151if (ignoreTest()) return;152153// use jlink to build image from multi-release jar154jlink("m1.jar", "myimage");155156// validate image157Path jimage = userdir.resolve("myimage").resolve("lib").resolve("modules");158try (BasicImageReader reader = BasicImageReader.open(jimage)) {159160// do we have the right entry names?161Set<String> names = Arrays.stream(reader.getEntryNames())162.filter(n -> n.startsWith("/m1"))163.collect(Collectors.toSet());164Assert.assertEquals(names, Set.of(165"/m1/module-info.class",166"/m1/p/Main.class",167"/m1/p/Type.class",168"/m1/q/PublicClass.class",169"/m1/META-INF/MANIFEST.MF",170"/m1/resource.txt"));171172// do we have the right module-info.class?173byte[] b = reader.getResource("/m1/module-info.class");174Set<String> requires = ModuleDescriptor175.read(new ByteArrayInputStream(b))176.requires()177.stream()178.map(mdr -> mdr.name())179.filter(nm -> !nm.equals("java.base"))180.collect(Collectors.toSet());181Assert.assertEquals(requires, Set.of("java.logging"));182183// do we have the right resource?184b = reader.getResource("/m1/resource.txt");185Assert.assertEquals(b, resource);186187// do we have the right class?188b = reader.getResource("/m1/p/Main.class");189Class<?> clazz = (new ByteArrayClassLoader()).loadClass("p.Main", b);190MethodHandle getVersion = MethodHandles.lookup()191.findVirtual(clazz, "getVersion", MethodType.methodType(int.class));192int version = (int) getVersion.invoke(clazz.getConstructor().newInstance());193Assert.assertEquals(version, JarFile.runtimeVersion().major());194}195}196197@Test198public void noLoggingTest() throws Throwable {199if (ignoreTest()) return;200201jlink("m1-no-logging.jar", "no-logging-image");202runImage("no-logging-image", false);203}204205@Test206public void loggingTest() throws Throwable {207if (ignoreTest()) return;208209jlink("m1-logging.jar", "logging-image");210runImage("logging-image", true);211212}213214// java.base.jmod must exist for this test to make sense215private boolean ignoreTest() {216if (Files.isRegularFile(jmodsdir.resolve("java.base.jmod"))) {217return false;218}219System.err.println("Test skipped. NO jmods/java.base.jmod");220return true;221}222223224private void jlink(String jar, String image) {225String args = "--output " + image + " --add-modules m1 --module-path " +226jar + pathsep + jmodsdir.toString();227int exitCode = JLINK_TOOL.run(System.out, System.err, args.split(" +"));228Assert.assertEquals(exitCode, 0);229}230231public void runImage(String image, boolean expected) throws Throwable {232Path java = Paths.get(image, "bin", "java");233OutputAnalyzer oa = ProcessTools.executeProcess(java.toString(), "-m", "m1/p.Main");234String sout = oa.getStdout();235boolean actual = sout.contains("logging found");236Assert.assertEquals(actual, expected);237System.out.println(sout);238System.err.println(oa.getStderr());239Assert.assertEquals(oa.getExitValue(), 0);240}241242private static class ByteArrayClassLoader extends ClassLoader {243public Class<?> loadClass(String name, byte[] bytes) {244return defineClass(name, bytes, 0, bytes.length);245}246}247}248249250