24 /* |
24 /* |
25 * @test |
25 * @test |
26 * @bug 8132734 |
26 * @bug 8132734 |
27 * @summary Test that URL connections to multi-release jars can be runtime versioned |
27 * @summary Test that URL connections to multi-release jars can be runtime versioned |
28 * @library /lib/testlibrary/java/util/jar |
28 * @library /lib/testlibrary/java/util/jar |
29 * @build Compiler JarBuilder CreateMultiReleaseTestJars |
29 * @build Compiler JarBuilder CreateMultiReleaseTestJars SimpleHttpServer |
30 * @run testng MultiReleaseJarURLConnection |
30 * @run testng MultiReleaseJarURLConnection |
31 */ |
31 */ |
32 |
32 |
33 import java.io.IOException; |
33 import java.io.IOException; |
34 import java.io.InputStream; |
34 import java.io.InputStream; |
|
35 import java.lang.invoke.MethodHandle; |
|
36 import java.lang.invoke.MethodHandles; |
|
37 import java.lang.invoke.MethodType; |
35 import java.net.JarURLConnection; |
38 import java.net.JarURLConnection; |
36 import java.net.URL; |
39 import java.net.URL; |
|
40 import java.net.URLClassLoader; |
37 import java.net.URLConnection; |
41 import java.net.URLConnection; |
38 import java.nio.file.Files; |
42 import java.nio.file.Files; |
39 import java.nio.file.Paths; |
43 import java.nio.file.Paths; |
40 import java.util.jar.JarFile; |
44 import java.util.jar.JarFile; |
|
45 |
|
46 import jdk.Version; |
41 |
47 |
42 import org.testng.Assert; |
48 import org.testng.Assert; |
43 import org.testng.annotations.AfterClass; |
49 import org.testng.annotations.AfterClass; |
44 import org.testng.annotations.BeforeClass; |
50 import org.testng.annotations.BeforeClass; |
45 import org.testng.annotations.DataProvider; |
51 import org.testng.annotations.DataProvider; |
46 import org.testng.annotations.Test; |
52 import org.testng.annotations.Test; |
47 |
53 |
48 public class MultiReleaseJarURLConnection { |
54 public class MultiReleaseJarURLConnection { |
49 String userdir = System.getProperty("user.dir","."); |
55 String userdir = System.getProperty("user.dir","."); |
50 String file = userdir + "/signed-multi-release.jar"; |
56 String unversioned = userdir + "/unversioned.jar"; |
|
57 String unsigned = userdir + "/multi-release.jar"; |
|
58 String signed = userdir + "/signed-multi-release.jar"; |
|
59 SimpleHttpServer server; |
51 |
60 |
52 @BeforeClass |
61 @BeforeClass |
53 public void initialize() throws Exception { |
62 public void initialize() throws Exception { |
54 CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); |
63 CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); |
55 creator.compileEntries(); |
64 creator.compileEntries(); |
|
65 creator.buildUnversionedJar(); |
56 creator.buildMultiReleaseJar(); |
66 creator.buildMultiReleaseJar(); |
57 creator.buildSignedMultiReleaseJar(); |
67 creator.buildSignedMultiReleaseJar(); |
|
68 |
|
69 server = new SimpleHttpServer(); |
|
70 server.start(); |
|
71 |
58 } |
72 } |
59 |
73 |
60 @AfterClass |
74 @AfterClass |
61 public void close() throws IOException { |
75 public void close() throws IOException { |
62 Files.delete(Paths.get(userdir, "multi-release.jar")); |
76 // Windows requires server to stop before file is deleted |
63 Files.delete(Paths.get(userdir, "signed-multi-release.jar")); |
77 if (server != null) |
|
78 server.stop(); |
|
79 Files.delete(Paths.get(unversioned)); |
|
80 Files.delete(Paths.get(unsigned)); |
|
81 Files.delete(Paths.get(signed)); |
64 } |
82 } |
65 |
83 |
66 @DataProvider(name = "data") |
84 @DataProvider(name = "data") |
67 public Object[][] createData() { |
85 public Object[][] createData() { |
68 return new Object[][]{ |
86 return new Object[][]{ |
69 {"unsigned file", userdir + "/multi-release.jar"}, |
87 {"unversioned", unversioned}, |
70 {"signed file", userdir + "/signed-multi-release.jar"}, |
88 {"unsigned", unsigned}, |
|
89 {"signed", signed} |
71 }; |
90 }; |
72 } |
91 } |
73 |
92 |
74 @Test(dataProvider = "data") |
93 @Test(dataProvider = "data") |
75 public void testRuntimeVersioning(String ignore, String file) throws Exception { |
94 public void testRuntimeVersioning(String style, String file) throws Exception { |
76 String urlFile = "jar:file:" + file + "!/"; |
95 String urlFile = "jar:file:" + file + "!/"; |
77 String urlEntry = urlFile + "version/Version.java"; |
96 String baseUrlEntry = urlFile + "version/Version.java"; |
78 |
97 String rtreturn = "return " + Version.current().major(); |
79 Assert.assertTrue(readAndCompare(new URL(urlEntry), "return 8")); |
98 |
80 // #runtime is "magic" |
99 Assert.assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8")); |
81 Assert.assertTrue(readAndCompare(new URL(urlEntry + "#runtime"), "return 9")); |
100 // #runtime is "magic" for a multi-release jar, but not for unversioned jar |
|
101 Assert.assertTrue(readAndCompare(new URL(baseUrlEntry + "#runtime"), |
|
102 style.equals("unversioned") ? "return 8" : rtreturn)); |
82 // #fragment or any other fragment is not magic |
103 // #fragment or any other fragment is not magic |
83 Assert.assertTrue(readAndCompare(new URL(urlEntry + "#fragment"), "return 8")); |
104 Assert.assertTrue(readAndCompare(new URL(baseUrlEntry + "#fragment"), "return 8")); |
84 // cached entities not affected |
105 // cached entities not affected |
85 Assert.assertTrue(readAndCompare(new URL(urlEntry), "return 8")); |
106 Assert.assertTrue(readAndCompare(new URL(baseUrlEntry), "return 8")); |
|
107 |
|
108 // the following tests will not work with unversioned jars |
|
109 if (style.equals("unversioned")) return; |
|
110 |
|
111 // direct access to versioned entry |
|
112 String versUrlEntry = urlFile + "META-INF/versions/" + Version.current().major() |
|
113 + "/version/Version.java"; |
|
114 Assert.assertTrue(readAndCompare(new URL(versUrlEntry), rtreturn)); |
|
115 // adding any fragment does not change things |
|
116 Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#runtime"), rtreturn)); |
|
117 Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#fragment"), rtreturn)); |
|
118 |
|
119 // it really doesn't change things |
|
120 versUrlEntry = urlFile + "META-INF/versions/10/version/Version.java"; |
|
121 Assert.assertTrue(readAndCompare(new URL(versUrlEntry), "return 10")); |
|
122 Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#runtime"), "return 10")); |
|
123 Assert.assertTrue(readAndCompare(new URL(versUrlEntry + "#fragment"), "return 10")); |
86 } |
124 } |
87 |
125 |
88 @Test(dataProvider = "data") |
126 @Test(dataProvider = "data") |
89 public void testCachedJars(String ignore, String file) throws Exception { |
127 public void testCachedJars(String style, String file) throws Exception { |
90 String urlFile = "jar:file:" + file + "!/"; |
128 String urlFile = "jar:file:" + file + "!/"; |
91 |
129 |
92 URL rootUrl = new URL(urlFile); |
130 URL rootUrl = new URL(urlFile); |
93 JarURLConnection juc = (JarURLConnection)rootUrl.openConnection(); |
131 JarURLConnection juc = (JarURLConnection)rootUrl.openConnection(); |
94 JarFile rootJar = juc.getJarFile(); |
132 JarFile rootJar = juc.getJarFile(); |
112 |
154 |
113 rootJar.close(); |
155 rootJar.close(); |
114 runtimeJar.close(); |
156 runtimeJar.close(); |
115 jar.close(); // probably not needed |
157 jar.close(); // probably not needed |
116 } |
158 } |
|
159 |
|
160 @DataProvider(name = "resourcedata") |
|
161 public Object[][] createResourceData() throws Exception { |
|
162 return new Object[][]{ |
|
163 {"unversioned", Paths.get(unversioned).toUri().toURL()}, |
|
164 {"unsigned", Paths.get(unsigned).toUri().toURL()}, |
|
165 {"signed", Paths.get(signed).toUri().toURL()}, |
|
166 {"unversioned", new URL("file:" + unversioned)}, |
|
167 {"unsigned", new URL("file:" + unsigned)}, |
|
168 {"signed", new URL("file:" + signed)}, |
|
169 {"unversioned", new URL("jar:file:" + unversioned + "!/")}, |
|
170 {"unsigned", new URL("jar:file:" + unsigned + "!/")}, |
|
171 {"signed", new URL("jar:file:" + signed + "!/")}, |
|
172 // external jar received via http protocol |
|
173 {"http", new URL("jar:http://localhost:" + server.getPort() + "/multi-release.jar!/")}, |
|
174 {"http", new URL("http://localhost:" + server.getPort() + "/multi-release.jar")}, |
|
175 |
|
176 }; |
|
177 } |
|
178 |
|
179 @Test(dataProvider = "resourcedata") |
|
180 public void testResources(String style, URL url) throws Throwable { |
|
181 //System.out.println(" testing " + style + " url: " + url); |
|
182 URL[] urls = {url}; |
|
183 URLClassLoader cldr = new URLClassLoader(urls); |
|
184 Class<?> vcls = cldr.loadClass("version.Version"); |
|
185 |
|
186 // verify we are loading a runtime versioned class |
|
187 MethodType mt = MethodType.methodType(int.class); |
|
188 MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt); |
|
189 Assert.assertEquals((int)mh.invoke(vcls.newInstance()), |
|
190 style.equals("unversioned") ? 8 : Version.current().major()); |
|
191 |
|
192 // now get a resource and verify that we don't have a fragment attached |
|
193 URL vclsUrl = vcls.getResource("/version/Version.class"); |
|
194 String fragment = vclsUrl.getRef(); |
|
195 Assert.assertNull(fragment); |
|
196 |
|
197 // and verify that the the url is a reified pointer to the runtime entry |
|
198 String rep = vclsUrl.toString(); |
|
199 //System.out.println(" getResource(\"/version/Version.class\") returned: " + rep); |
|
200 if (style.equals("http")) { |
|
201 Assert.assertTrue(rep.startsWith("jar:http:")); |
|
202 } else { |
|
203 Assert.assertTrue(rep.startsWith("jar:file:")); |
|
204 } |
|
205 String suffix; |
|
206 if (style.equals("unversioned")) { |
|
207 suffix = ".jar!/version/Version.class"; |
|
208 } else { |
|
209 suffix = ".jar!/META-INF/versions/" + Version.current().major() |
|
210 + "/version/Version.class"; |
|
211 } |
|
212 Assert.assertTrue(rep.endsWith(suffix)); |
|
213 cldr.close(); |
|
214 } |
|
215 |
117 |
216 |
118 private boolean readAndCompare(URL url, String match) throws Exception { |
217 private boolean readAndCompare(URL url, String match) throws Exception { |
119 boolean result; |
218 boolean result; |
120 // necessary to do it this way, instead of openStream(), so we can |
219 // necessary to do it this way, instead of openStream(), so we can |
121 // close underlying JarFile, otherwise windows can't delete the file |
220 // close underlying JarFile, otherwise windows can't delete the file |