Path: blob/master/test/jdk/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java
41159 views
/*1* Copyright (c) 2015, 2020, 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 8132734 8144062 8159785 819407026* @summary Test that URL connections to multi-release jars can be runtime versioned27* @library /lib/testlibrary/java/util/jar /test/lib28* @modules jdk.compiler29* jdk.httpserver30* jdk.jartool31* @build CreateMultiReleaseTestJars32* jdk.test.lib.net.SimpleHttpServer33* jdk.test.lib.util.JarBuilder34* jdk.test.lib.compiler.Compiler35* @run testng MultiReleaseJarURLConnection36*/3738import java.io.IOException;39import java.io.InputStream;40import java.lang.invoke.MethodHandle;41import java.lang.invoke.MethodHandles;42import java.lang.invoke.MethodType;43import java.net.InetAddress;44import java.net.InetSocketAddress;45import java.net.JarURLConnection;46import java.net.MalformedURLException;47import java.net.URI;48import java.net.URISyntaxException;49import java.net.URL;50import java.net.URLClassLoader;51import java.net.URLConnection;52import java.nio.file.Files;53import java.nio.file.Paths;54import java.util.Enumeration;55import java.util.jar.JarFile;5657import jdk.test.lib.net.SimpleHttpServer;58import jdk.test.lib.net.URIBuilder;59import org.testng.Assert;60import org.testng.annotations.AfterClass;61import org.testng.annotations.BeforeClass;62import org.testng.annotations.DataProvider;63import org.testng.annotations.Test;6465public class MultiReleaseJarURLConnection {66String userdir = System.getProperty("user.dir", ".");67String unversioned = userdir + "/unversioned.jar";68String unsigned = userdir + "/multi-release.jar";69String signed = userdir + "/signed-multi-release.jar";70static final String TESTCONTEXT = "/multi-release.jar";71SimpleHttpServer server;7273@BeforeClass74public void initialize() throws Exception {75CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();76creator.compileEntries();77creator.buildUnversionedJar();78creator.buildMultiReleaseJar();79creator.buildSignedMultiReleaseJar();80server = new SimpleHttpServer(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), TESTCONTEXT, System.getProperty("user.dir", "."));81server.start();82}8384@AfterClass85public void close() throws IOException {86// Windows requires server to stop before file is deleted87if (server != null)88server.stop();89Files.delete(Paths.get(unversioned));90Files.delete(Paths.get(unsigned));91Files.delete(Paths.get(signed));92}9394@DataProvider(name = "data")95public Object[][] createData() {96return new Object[][]{97{"unversioned", unversioned},98{"unsigned", unsigned},99{"signed", signed}100};101}102103@Test(dataProvider = "data")104public void testRuntimeVersioning(String style, String file) throws Exception {105String urlFile = "jar:file:" + file + "!/";106String baseUrlEntry = urlFile + "version/Version.java";107String rtreturn = "return " + Runtime.version().major();108109Assert.assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8"));110// #runtime is "magic" for a multi-release jar, but not for unversioned jar111Assert.assertTrue(readAndCompare(new URL(baseUrlEntry + "#runtime"),112style.equals("unversioned") ? "return 8" : rtreturn));113// #fragment or any other fragment is not magic114Assert.assertTrue(readAndCompare(new URL(baseUrlEntry + "#fragment"), "return 8"));115// cached entities not affected116Assert.assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8"));117118// the following tests will not work with unversioned jars119if (style.equals("unversioned"))120return;121122// direct access to versioned entry123String versUrlEntry = urlFile + "META-INF/versions/" + Runtime.version().major()124+ "/version/Version.java";125Assert.assertTrue(readAndCompare(new URL(versUrlEntry), rtreturn));126// adding any fragment does not change things127Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#runtime"), rtreturn));128Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#fragment"), rtreturn));129}130131@Test(dataProvider = "data")132public void testCachedJars(String style, String file) throws Exception {133String urlFile = "jar:file:" + file + "!/";134135URL rootUrl = new URL(urlFile);136JarURLConnection juc = (JarURLConnection) rootUrl.openConnection();137JarFile rootJar = juc.getJarFile();138Runtime.Version root = rootJar.getVersion();139140URL runtimeUrl = new URL(urlFile + "#runtime");141juc = (JarURLConnection) runtimeUrl.openConnection();142JarFile runtimeJar = juc.getJarFile();143Runtime.Version runtime = runtimeJar.getVersion();144if (style.equals("unversioned")) {145Assert.assertEquals(root, runtime);146} else {147Assert.assertNotEquals(root, runtime);148}149150juc = (JarURLConnection) rootUrl.openConnection();151JarFile jar = juc.getJarFile();152Assert.assertEquals(jar.getVersion(), root);153Assert.assertEquals(jar, rootJar);154155juc = (JarURLConnection) runtimeUrl.openConnection();156jar = juc.getJarFile();157Assert.assertEquals(jar.getVersion(), runtime);158Assert.assertEquals(jar, runtimeJar);159160rootJar.close();161runtimeJar.close();162jar.close(); // probably not needed163}164165@DataProvider(name = "resourcedata")166public Object[][] createResourceData() throws Exception {167return new Object[][]{168{"unversioned", Paths.get(unversioned).toUri().toURL()},169{"unsigned", Paths.get(unsigned).toUri().toURL()},170{"signed", Paths.get(signed).toUri().toURL()},171{"unversioned", new URL("file:" + unversioned)},172{"unsigned", new URL("file:" + unsigned)},173{"signed", new URL("file:" + signed)},174{"unversioned", new URL("jar:file:" + unversioned + "!/")},175{"unsigned", new URL("jar:file:" + unsigned + "!/")},176{"signed", new URL("jar:file:" + signed + "!/")},177// external jar received via http protocol178{"http", toHttpJarURL(server.getPort(), "/multi-release.jar", "!/")},179{"http", URIBuilder.newBuilder().scheme("http").port(server.getPort())180.loopback().path("/multi-release.jar").toURL()},181};182}183184@Test(dataProvider = "resourcedata")185public void testResources(String style, URL url) throws Throwable {186// System.out.println(" testing " + style + " url: " + url);187URL[] urls = {url};188URLClassLoader cldr = new URLClassLoader(urls);189Class<?> vcls = cldr.loadClass("version.Version");190191// verify we are loading a runtime versioned class192MethodType mt = MethodType.methodType(int.class);193MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt);194Assert.assertEquals((int)mh.invoke(vcls.newInstance()),195style.equals("unversioned") ? 8 : Runtime.version().major());196197// now get a resource and verify that we don't have a fragment attached198Enumeration<URL> vclsUrlEnum = cldr.getResources("version/Version.class");199Assert.assertTrue(vclsUrlEnum.hasMoreElements());200URL vclsUrls[] = new URL[] {201vcls.getResource("/version/Version.class"),202vcls.getResource("Version.class"),203cldr.getResource("version/Version.class"),204vclsUrlEnum.nextElement()205};206Assert.assertFalse(vclsUrlEnum.hasMoreElements());207for (URL vclsUrl : vclsUrls) {208String fragment = vclsUrl.getRef();209Assert.assertNull(fragment);210211// and verify that the the url is a reified pointer to the runtime entry212String rep = vclsUrl.toString();213//System.out.println(" getResource(\"/version/Version.class\") returned: " + rep);214if (style.equals("http")) {215Assert.assertTrue(rep.startsWith("jar:http:"));216} else {217Assert.assertTrue(rep.startsWith("jar:file:"));218}219String suffix;220if (style.equals("unversioned")) {221suffix = ".jar!/version/Version.class";222} else {223suffix = ".jar!/META-INF/versions/" + Runtime.version().major()224+ "/version/Version.class";225}226Assert.assertTrue(rep.endsWith(suffix));227}228cldr.close();229}230231private static URL toHttpJarURL(int port, String jar, String file)232throws MalformedURLException, URISyntaxException {233assert file.startsWith("!/");234URI httpURI = URIBuilder.newBuilder()235.scheme("http")236.loopback()237.port(port)238.path(jar)239.build();240return new URL("jar:" + httpURI + file);241}242243private boolean readAndCompare(URL url, String match) throws Exception {244boolean result;245// necessary to do it this way, instead of openStream(), so we can246// close underlying JarFile, otherwise windows can't delete the file247URLConnection conn = url.openConnection();248try (InputStream is = conn.getInputStream()) {249byte[] bytes = is.readAllBytes();250result = (new String(bytes)).contains(match);251}252if (conn instanceof JarURLConnection) {253((JarURLConnection) conn).getJarFile().close();254}255return result;256}257}258259260