Relocate projects to spring-boot-project
Move projects to better reflect the way that Spring Boot is released. The following projects are under `spring-boot-project`: - `spring-boot` - `spring-boot-autoconfigure` - `spring-boot-tools` - `spring-boot-starters` - `spring-boot-actuator` - `spring-boot-actuator-autoconfigure` - `spring-boot-test` - `spring-boot-test-autoconfigure` - `spring-boot-devtools` - `spring-boot-cli` - `spring-boot-docs` See gh-9316
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Base class for testing {@link ExecutableArchiveLauncher} implementations.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class AbstractExecutableArchiveLauncherTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
protected File createJarArchive(String name, String entryPrefix) throws IOException {
|
||||
File archive = this.temp.newFile(name);
|
||||
JarOutputStream jarOutputStream = new JarOutputStream(
|
||||
new FileOutputStream(archive));
|
||||
jarOutputStream.putNextEntry(new JarEntry(entryPrefix + "/"));
|
||||
jarOutputStream.putNextEntry(new JarEntry(entryPrefix + "/classes/"));
|
||||
jarOutputStream.putNextEntry(new JarEntry(entryPrefix + "/lib/"));
|
||||
JarEntry libFoo = new JarEntry(entryPrefix + "/lib/foo.jar");
|
||||
libFoo.setMethod(ZipEntry.STORED);
|
||||
ByteArrayOutputStream fooJarStream = new ByteArrayOutputStream();
|
||||
new JarOutputStream(fooJarStream).close();
|
||||
libFoo.setSize(fooJarStream.size());
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(fooJarStream.toByteArray());
|
||||
libFoo.setCrc(crc32.getValue());
|
||||
jarOutputStream.putNextEntry(libFoo);
|
||||
jarOutputStream.write(fooJarStream.toByteArray());
|
||||
jarOutputStream.close();
|
||||
return archive;
|
||||
}
|
||||
|
||||
protected File explode(File archive) throws IOException {
|
||||
File exploded = this.temp.newFolder("exploded");
|
||||
JarFile jarFile = new JarFile(archive);
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
File entryFile = new File(exploded, entry.getName());
|
||||
if (entry.isDirectory()) {
|
||||
entryFile.mkdirs();
|
||||
}
|
||||
else {
|
||||
FileCopyUtils.copy(jarFile.getInputStream(entry),
|
||||
new FileOutputStream(entryFile));
|
||||
}
|
||||
}
|
||||
jarFile.close();
|
||||
return exploded;
|
||||
}
|
||||
|
||||
protected Set<URL> getUrls(List<Archive> archives) throws MalformedURLException {
|
||||
Set<URL> urls = new HashSet<>(archives.size());
|
||||
for (Archive archive : archives) {
|
||||
urls.add(archive.getUrl());
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
|
||||
/**
|
||||
* Hamcrest matcher to tests that a byte array starts with specific bytes.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ByteArrayStartsWith extends TypeSafeMatcher<byte[]> {
|
||||
|
||||
private final byte[] bytes;
|
||||
|
||||
public ByteArrayStartsWith(byte[] bytes) {
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("a byte array starting with ").appendValue(this.bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesSafely(byte[] item) {
|
||||
if (item.length < this.bytes.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < this.bytes.length; i++) {
|
||||
if (item[i] != this.bytes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JarLauncher}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class JarLauncherTests extends AbstractExecutableArchiveLauncherTests {
|
||||
|
||||
@Test
|
||||
public void explodedJarHasOnlyBootInfClassesAndContentsOfBootInfLibOnClasspath()
|
||||
throws Exception {
|
||||
File explodedRoot = explode(createJarArchive("archive.jar", "BOOT-INF"));
|
||||
JarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot, true));
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).hasSize(2);
|
||||
assertThat(getUrls(archives)).containsOnly(
|
||||
new File(explodedRoot, "BOOT-INF/classes").toURI().toURL(),
|
||||
new URL("jar:"
|
||||
+ new File(explodedRoot, "BOOT-INF/lib/foo.jar").toURI().toURL()
|
||||
+ "!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void archivedJarHasOnlyBootInfClassesAndContentsOfBootInfLibOnClasspath()
|
||||
throws Exception {
|
||||
File jarRoot = createJarArchive("archive.jar", "BOOT-INF");
|
||||
JarLauncher launcher = new JarLauncher(new JarFileArchive(jarRoot));
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).hasSize(2);
|
||||
assertThat(getUrls(archives)).containsOnly(
|
||||
new URL("jar:" + jarRoot.toURI().toURL() + "!/BOOT-INF/classes!/"),
|
||||
new URL("jar:" + jarRoot.toURI().toURL() + "!/BOOT-INF/lib/foo.jar!/"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.jar.JarFile;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link LaunchedURLClassLoader}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public class LaunchedURLClassLoaderTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void resolveResourceFromArchive() throws Exception {
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(
|
||||
new URL[] { new URL("jar:file:src/test/resources/jars/app.jar!/") },
|
||||
getClass().getClassLoader());
|
||||
assertThat(loader.getResource("demo/Application.java")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveResourcesFromArchive() throws Exception {
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(
|
||||
new URL[] { new URL("jar:file:src/test/resources/jars/app.jar!/") },
|
||||
getClass().getClassLoader());
|
||||
assertThat(loader.getResources("demo/Application.java").hasMoreElements())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveRootPathFromArchive() throws Exception {
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(
|
||||
new URL[] { new URL("jar:file:src/test/resources/jars/app.jar!/") },
|
||||
getClass().getClassLoader());
|
||||
assertThat(loader.getResource("")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveRootResourcesFromArchive() throws Exception {
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(
|
||||
new URL[] { new URL("jar:file:src/test/resources/jars/app.jar!/") },
|
||||
getClass().getClassLoader());
|
||||
assertThat(loader.getResources("").hasMoreElements()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveFromNested() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(file);
|
||||
JarFile jarFile = new JarFile(file);
|
||||
URL url = jarFile.getUrl();
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(new URL[] { url },
|
||||
null);
|
||||
URL resource = loader.getResource("nested.jar!/3.dat");
|
||||
assertThat(resource.toString()).isEqualTo(url + "nested.jar!/3.dat");
|
||||
assertThat(resource.openConnection().getInputStream().read()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveFromNestedWhileThreadIsInterrupted() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(file);
|
||||
JarFile jarFile = new JarFile(file);
|
||||
URL url = jarFile.getUrl();
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(new URL[] { url },
|
||||
null);
|
||||
try {
|
||||
Thread.currentThread().interrupt();
|
||||
URL resource = loader.getResource("nested.jar!/3.dat");
|
||||
assertThat(resource.toString()).isEqualTo(url + "nested.jar!/3.dat");
|
||||
assertThat(resource.openConnection().getInputStream().read()).isEqualTo(3);
|
||||
}
|
||||
finally {
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.boot.testsupport.rule.OutputCapture;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertiesLauncher}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class PropertiesLauncherTests {
|
||||
|
||||
@Rule
|
||||
public OutputCapture output = new OutputCapture();
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private ClassLoader contextClassLoader;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
this.contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
MockitoAnnotations.initMocks(this);
|
||||
System.setProperty("loader.home",
|
||||
new File("src/test/resources").getAbsolutePath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
Thread.currentThread().setContextClassLoader(this.contextClassLoader);
|
||||
System.clearProperty("loader.home");
|
||||
System.clearProperty("loader.path");
|
||||
System.clearProperty("loader.main");
|
||||
System.clearProperty("loader.config.name");
|
||||
System.clearProperty("loader.config.location");
|
||||
System.clearProperty("loader.system");
|
||||
System.clearProperty("loader.classLoader");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultHome() {
|
||||
System.clearProperty("loader.home");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getHomeDirectory())
|
||||
.isEqualTo(new File(System.getProperty("user.dir")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlternateHome() throws Exception {
|
||||
System.setProperty("loader.home", "src/test/resources/home");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getHomeDirectory())
|
||||
.isEqualTo(new File(System.getProperty("loader.home")));
|
||||
assertThat(launcher.getMainClass()).isEqualTo("demo.HomeApplication");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonExistentHome() throws Exception {
|
||||
System.setProperty("loader.home", "src/test/resources/nonexistent");
|
||||
this.expected.expectMessage("Invalid source folder");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getHomeDirectory())
|
||||
.isNotEqualTo(new File(System.getProperty("loader.home")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedMain() throws Exception {
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getMainClass()).isEqualTo("demo.Application");
|
||||
assertThat(System.getProperty("loader.main")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedConfigName() throws Exception {
|
||||
System.setProperty("loader.config.name", "foo");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getMainClass()).isEqualTo("my.Application");
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[etc/]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRootOfClasspathFirst() throws Exception {
|
||||
System.setProperty("loader.config.name", "bar");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getMainClass()).isEqualTo("my.BarApplication");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedDotPath() throws Exception {
|
||||
System.setProperty("loader.path", ".");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[.]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedSlashPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jars/]");
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedWildcardPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/*");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jars/]");
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedJarPath() throws Exception {
|
||||
System.setProperty("loader.path", "jars/app.jar");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jars/app.jar]");
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedRootOfJarPath() throws Exception {
|
||||
System.setProperty("loader.path",
|
||||
"jar:file:./src/test/resources/nested-jars/app.jar!/");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jar:file:./src/test/resources/nested-jars/app.jar!/]");
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedRootOfJarPathWithDot() throws Exception {
|
||||
System.setProperty("loader.path", "nested-jars/app.jar!/./");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedRootOfJarPathWithDotAndJarPrefix() throws Exception {
|
||||
System.setProperty("loader.path",
|
||||
"jar:file:./src/test/resources/nested-jars/app.jar!/./");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedJarFileWithNestedArchives() throws Exception {
|
||||
System.setProperty("loader.path", "nested-jars/app.jar");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).areExactly(1, endingWith("foo.jar!/"));
|
||||
assertThat(archives).areExactly(1, endingWith("app.jar!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedDirectoryContainingJarFileWithNestedArchives()
|
||||
throws Exception {
|
||||
System.setProperty("loader.path", "nested-jars");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedJarPathWithDot() throws Exception {
|
||||
System.setProperty("loader.path", "./jars/app.jar");
|
||||
System.setProperty("loader.main", "demo.Application");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jars/app.jar]");
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedClassLoader() throws Exception {
|
||||
System.setProperty("loader.path", "jars/app.jar");
|
||||
System.setProperty("loader.classLoader", URLClassLoader.class.getName());
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[jars/app.jar]");
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedClassPathOrder() throws Exception {
|
||||
System.setProperty("loader.path", "more-jars/app.jar,jars/app.jar");
|
||||
System.setProperty("loader.classLoader", URLClassLoader.class.getName());
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(ReflectionTestUtils.getField(launcher, "paths").toString())
|
||||
.isEqualTo("[more-jars/app.jar, jars/app.jar]");
|
||||
launcher.launch(new String[0]);
|
||||
waitFor("Hello Other World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomClassLoaderCreation() throws Exception {
|
||||
System.setProperty("loader.classLoader", TestLoader.class.getName());
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
ClassLoader loader = launcher.createClassLoader(archives());
|
||||
assertThat(loader).isNotNull();
|
||||
assertThat(loader.getClass().getName()).isEqualTo(TestLoader.class.getName());
|
||||
}
|
||||
|
||||
private List<Archive> archives() throws Exception {
|
||||
List<Archive> archives = new ArrayList<>();
|
||||
String path = System.getProperty("java.class.path");
|
||||
for (String url : path.split(File.pathSeparator)) {
|
||||
archives.add(archive(url));
|
||||
}
|
||||
return archives;
|
||||
}
|
||||
|
||||
private Archive archive(String url) throws IOException {
|
||||
File file = new FileSystemResource(url).getFile();
|
||||
if (url.endsWith(".jar")) {
|
||||
return new JarFileArchive(file);
|
||||
}
|
||||
return new ExplodedArchive(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserSpecifiedConfigPathWins() throws Exception {
|
||||
|
||||
System.setProperty("loader.config.name", "foo");
|
||||
System.setProperty("loader.config.location", "classpath:bar.properties");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getMainClass()).isEqualTo("my.BarApplication");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemPropertySpecifiedMain() throws Exception {
|
||||
System.setProperty("loader.main", "foo.Bar");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getMainClass()).isEqualTo("foo.Bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemPropertiesSet() throws Exception {
|
||||
System.setProperty("loader.system", "true");
|
||||
new PropertiesLauncher();
|
||||
assertThat(System.getProperty("loader.main")).isEqualTo("demo.Application");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArgsEnhanced() throws Exception {
|
||||
System.setProperty("loader.args", "foo");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(Arrays.asList(launcher.getArgs("bar")).toString())
|
||||
.isEqualTo("[foo, bar]");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testLoadPathCustomizedUsingManifest() throws Exception {
|
||||
System.setProperty("loader.home",
|
||||
this.temporaryFolder.getRoot().getAbsolutePath());
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
manifest.getMainAttributes().putValue("Loader-Path", "/foo.jar, /bar");
|
||||
File manifestFile = new File(this.temporaryFolder.getRoot(),
|
||||
"META-INF/MANIFEST.MF");
|
||||
manifestFile.getParentFile().mkdirs();
|
||||
manifest.write(new FileOutputStream(manifestFile));
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat((List<String>) ReflectionTestUtils.getField(launcher, "paths"))
|
||||
.containsExactly("/foo.jar", "/bar/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManifestWithPlaceholders() throws Exception {
|
||||
System.setProperty("loader.home", "src/test/resources/placeholders");
|
||||
PropertiesLauncher launcher = new PropertiesLauncher();
|
||||
assertThat(launcher.getMainClass()).isEqualTo("demo.FooApplication");
|
||||
}
|
||||
|
||||
private void waitFor(String value) throws Exception {
|
||||
int count = 0;
|
||||
boolean timeout = false;
|
||||
while (!timeout && count < 100) {
|
||||
count++;
|
||||
Thread.sleep(50L);
|
||||
timeout = this.output.toString().contains(value);
|
||||
}
|
||||
assertThat(timeout).as("Timed out waiting for (" + value + ")").isTrue();
|
||||
}
|
||||
|
||||
private Condition<Archive> endingWith(final String value) {
|
||||
return new Condition<Archive>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(Archive archive) {
|
||||
return archive.toString().endsWith(value);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static class TestLoader extends URLClassLoader {
|
||||
|
||||
public TestLoader(ClassLoader parent) {
|
||||
super(new URL[0], parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
return super.findClass(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* Creates a simple test jar.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public abstract class TestJarCreator {
|
||||
|
||||
public static void createTestJar(File file) throws Exception {
|
||||
createTestJar(file, false);
|
||||
}
|
||||
|
||||
public static void createTestJar(File file, boolean unpackNested) throws Exception {
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(file);
|
||||
try (JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream)) {
|
||||
writeManifest(jarOutputStream, "j1");
|
||||
writeEntry(jarOutputStream, "1.dat", 1);
|
||||
writeEntry(jarOutputStream, "2.dat", 2);
|
||||
writeDirEntry(jarOutputStream, "d/");
|
||||
writeEntry(jarOutputStream, "d/9.dat", 9);
|
||||
writeDirEntry(jarOutputStream, "special/");
|
||||
writeEntry(jarOutputStream, "special/\u00EB.dat", '\u00EB');
|
||||
|
||||
writeNestedEntry("nested.jar", unpackNested, jarOutputStream);
|
||||
writeNestedEntry("another-nested.jar", unpackNested, jarOutputStream);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeNestedEntry(String name, boolean unpackNested,
|
||||
JarOutputStream jarOutputStream) throws Exception, IOException {
|
||||
JarEntry nestedEntry = new JarEntry(name);
|
||||
byte[] nestedJarData = getNestedJarData();
|
||||
nestedEntry.setSize(nestedJarData.length);
|
||||
nestedEntry.setCompressedSize(nestedJarData.length);
|
||||
if (unpackNested) {
|
||||
nestedEntry.setComment("UNPACK:0000000000000000000000000000000000000000");
|
||||
}
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(nestedJarData);
|
||||
nestedEntry.setCrc(crc32.getValue());
|
||||
|
||||
nestedEntry.setMethod(ZipEntry.STORED);
|
||||
jarOutputStream.putNextEntry(nestedEntry);
|
||||
jarOutputStream.write(nestedJarData);
|
||||
jarOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
private static byte[] getNestedJarData() throws Exception {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
JarOutputStream jarOutputStream = new JarOutputStream(byteArrayOutputStream);
|
||||
writeManifest(jarOutputStream, "j2");
|
||||
writeEntry(jarOutputStream, "3.dat", 3);
|
||||
writeEntry(jarOutputStream, "4.dat", 4);
|
||||
writeEntry(jarOutputStream, "\u00E4.dat", '\u00E4');
|
||||
jarOutputStream.close();
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
private static void writeManifest(JarOutputStream jarOutputStream, String name)
|
||||
throws Exception {
|
||||
writeDirEntry(jarOutputStream, "META-INF/");
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().putValue("Built-By", name);
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
jarOutputStream.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
|
||||
manifest.write(jarOutputStream);
|
||||
jarOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
private static void writeDirEntry(JarOutputStream jarOutputStream, String name)
|
||||
throws IOException {
|
||||
jarOutputStream.putNextEntry(new JarEntry(name));
|
||||
jarOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
private static void writeEntry(JarOutputStream jarOutputStream, String name, int data)
|
||||
throws IOException {
|
||||
jarOutputStream.putNextEntry(new JarEntry(name));
|
||||
jarOutputStream.write(new byte[] { (byte) data });
|
||||
jarOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link WarLauncher}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class WarLauncherTests extends AbstractExecutableArchiveLauncherTests {
|
||||
|
||||
@Test
|
||||
public void explodedWarHasOnlyWebInfClassesAndContentsOfWebInfLibOnClasspath()
|
||||
throws Exception {
|
||||
File explodedRoot = explode(createJarArchive("archive.war", "WEB-INF"));
|
||||
WarLauncher launcher = new WarLauncher(new ExplodedArchive(explodedRoot, true));
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).hasSize(2);
|
||||
assertThat(getUrls(archives)).containsOnly(
|
||||
new File(explodedRoot, "WEB-INF/classes").toURI().toURL(),
|
||||
new URL("jar:"
|
||||
+ new File(explodedRoot, "WEB-INF/lib/foo.jar").toURI().toURL()
|
||||
+ "!/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void archivedWarHasOnlyWebInfClassesAndContentsOWebInfLibOnClasspath()
|
||||
throws Exception {
|
||||
File jarRoot = createJarArchive("archive.war", "WEB-INF");
|
||||
WarLauncher launcher = new WarLauncher(new JarFileArchive(jarRoot));
|
||||
List<Archive> archives = launcher.getClassPathArchives();
|
||||
assertThat(archives).hasSize(2);
|
||||
assertThat(getUrls(archives)).containsOnly(
|
||||
new URL("jar:" + jarRoot.toURI().toURL() + "!/WEB-INF/classes!/"),
|
||||
new URL("jar:" + jarRoot.toURI().toURL() + "!/WEB-INF/lib/foo.jar!/"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.archive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ExplodedArchive}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ExplodedArchiveTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private File rootFolder;
|
||||
|
||||
private ExplodedArchive archive;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
createArchive();
|
||||
}
|
||||
|
||||
private void createArchive() throws Exception {
|
||||
createArchive(null);
|
||||
}
|
||||
|
||||
private void createArchive(String folderName) throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(file);
|
||||
|
||||
this.rootFolder = StringUtils.hasText(folderName)
|
||||
? this.temporaryFolder.newFolder(folderName)
|
||||
: this.temporaryFolder.newFolder();
|
||||
JarFile jarFile = new JarFile(file);
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
File destination = new File(
|
||||
this.rootFolder.getAbsolutePath() + File.separator + entry.getName());
|
||||
destination.getParentFile().mkdirs();
|
||||
if (entry.isDirectory()) {
|
||||
destination.mkdir();
|
||||
}
|
||||
else {
|
||||
copy(jarFile.getInputStream(entry), new FileOutputStream(destination));
|
||||
}
|
||||
}
|
||||
this.archive = new ExplodedArchive(this.rootFolder);
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
private void copy(InputStream in, OutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int len = in.read(buffer);
|
||||
while (len != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
len = in.read(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManifest() throws Exception {
|
||||
assertThat(this.archive.getManifest().getMainAttributes().getValue("Built-By"))
|
||||
.isEqualTo("j1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntries() throws Exception {
|
||||
Map<String, Archive.Entry> entries = getEntriesMap(this.archive);
|
||||
assertThat(entries.size()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUrl() throws Exception {
|
||||
assertThat(this.archive.getUrl()).isEqualTo(this.rootFolder.toURI().toURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUrlWithSpaceInPath() throws Exception {
|
||||
createArchive("spaces in the name");
|
||||
assertThat(this.archive.getUrl()).isEqualTo(this.rootFolder.toURI().toURL());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedArchive() throws Exception {
|
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
Archive nested = this.archive.getNestedArchive(entry);
|
||||
assertThat(nested.getUrl().toString())
|
||||
.isEqualTo("jar:" + this.rootFolder.toURI() + "nested.jar!/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedDirArchive() throws Exception {
|
||||
Entry entry = getEntriesMap(this.archive).get("d/");
|
||||
Archive nested = this.archive.getNestedArchive(entry);
|
||||
Map<String, Entry> nestedEntries = getEntriesMap(nested);
|
||||
assertThat(nestedEntries.size()).isEqualTo(1);
|
||||
assertThat(nested.getUrl().toString())
|
||||
.isEqualTo("file:" + this.rootFolder.toURI().getPath() + "d/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonRecursiveEntriesForRoot() throws Exception {
|
||||
ExplodedArchive archive = new ExplodedArchive(new File("/"), false);
|
||||
Map<String, Archive.Entry> entries = getEntriesMap(archive);
|
||||
assertThat(entries.size()).isGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonRecursiveManifest() throws Exception {
|
||||
ExplodedArchive archive = new ExplodedArchive(
|
||||
new File("src/test/resources/root"));
|
||||
assertThat(archive.getManifest()).isNotNull();
|
||||
Map<String, Archive.Entry> entries = getEntriesMap(archive);
|
||||
assertThat(entries.size()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNonRecursiveManifestEvenIfNonRecursive() throws Exception {
|
||||
ExplodedArchive archive = new ExplodedArchive(new File("src/test/resources/root"),
|
||||
false);
|
||||
assertThat(archive.getManifest()).isNotNull();
|
||||
Map<String, Archive.Entry> entries = getEntriesMap(archive);
|
||||
assertThat(entries.size()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceAsStream() throws Exception {
|
||||
ExplodedArchive archive = new ExplodedArchive(
|
||||
new File("src/test/resources/root"));
|
||||
assertThat(archive.getManifest()).isNotNull();
|
||||
URLClassLoader loader = new URLClassLoader(new URL[] { archive.getUrl() });
|
||||
assertThat(loader.getResourceAsStream("META-INF/spring/application.xml"))
|
||||
.isNotNull();
|
||||
loader.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourceAsStreamNonRecursive() throws Exception {
|
||||
ExplodedArchive archive = new ExplodedArchive(new File("src/test/resources/root"),
|
||||
false);
|
||||
assertThat(archive.getManifest()).isNotNull();
|
||||
URLClassLoader loader = new URLClassLoader(new URL[] { archive.getUrl() });
|
||||
assertThat(loader.getResourceAsStream("META-INF/spring/application.xml"))
|
||||
.isNotNull();
|
||||
loader.close();
|
||||
}
|
||||
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) {
|
||||
Map<String, Archive.Entry> entries = new HashMap<>();
|
||||
for (Archive.Entry entry : archive) {
|
||||
entries.put(entry.getName(), entry);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.archive;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
/**
|
||||
* Tests for {@link JarFileArchive}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class JarFileArchiveTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private File rootJarFile;
|
||||
|
||||
private JarFileArchive archive;
|
||||
|
||||
private String rootJarFileUrl;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
setup(false);
|
||||
}
|
||||
|
||||
private void setup(boolean unpackNested) throws Exception {
|
||||
this.rootJarFile = this.temporaryFolder.newFile();
|
||||
this.rootJarFileUrl = this.rootJarFile.toURI().toString();
|
||||
TestJarCreator.createTestJar(this.rootJarFile, unpackNested);
|
||||
this.archive = new JarFileArchive(this.rootJarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManifest() throws Exception {
|
||||
assertThat(this.archive.getManifest().getMainAttributes().getValue("Built-By"))
|
||||
.isEqualTo("j1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntries() throws Exception {
|
||||
Map<String, Archive.Entry> entries = getEntriesMap(this.archive);
|
||||
assertThat(entries.size()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUrl() throws Exception {
|
||||
URL url = this.archive.getUrl();
|
||||
assertThat(url.toString()).isEqualTo("jar:" + this.rootJarFileUrl + "!/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedArchive() throws Exception {
|
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
Archive nested = this.archive.getNestedArchive(entry);
|
||||
assertThat(nested.getUrl().toString())
|
||||
.isEqualTo("jar:" + this.rootJarFileUrl + "!/nested.jar!/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedUnpackedArchive() throws Exception {
|
||||
setup(true);
|
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
Archive nested = this.archive.getNestedArchive(entry);
|
||||
assertThat(nested.getUrl().toString()).startsWith("file:");
|
||||
assertThat(nested.getUrl().toString()).endsWith("/nested.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unpackedLocationsAreUniquePerArchive() throws Exception {
|
||||
setup(true);
|
||||
Entry entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
URL firstNested = this.archive.getNestedArchive(entry).getUrl();
|
||||
setup(true);
|
||||
entry = getEntriesMap(this.archive).get("nested.jar");
|
||||
URL secondNested = this.archive.getNestedArchive(entry).getUrl();
|
||||
assertThat(secondNested).isNotEqualTo(firstNested);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unpackedLocationsFromSameArchiveShareSameParent() throws Exception {
|
||||
setup(true);
|
||||
File nested = new File(this.archive
|
||||
.getNestedArchive(getEntriesMap(this.archive).get("nested.jar")).getUrl()
|
||||
.toURI());
|
||||
File anotherNested = new File(
|
||||
this.archive
|
||||
.getNestedArchive(
|
||||
getEntriesMap(this.archive).get("another-nested.jar"))
|
||||
.getUrl().toURI());
|
||||
assertThat(nested.getParent()).isEqualTo(anotherNested.getParent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zip64ArchivesAreHandledGracefully() throws IOException {
|
||||
File file = this.temporaryFolder.newFile("test.jar");
|
||||
FileCopyUtils.copy(writeZip64Jar(), file);
|
||||
this.thrown.expectMessage(equalTo("Zip64 archives are not supported"));
|
||||
new JarFileArchive(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedZip64ArchivesAreHandledGracefully() throws IOException {
|
||||
File file = this.temporaryFolder.newFile("test.jar");
|
||||
JarOutputStream output = new JarOutputStream(new FileOutputStream(file));
|
||||
JarEntry zip64JarEntry = new JarEntry("nested/zip64.jar");
|
||||
output.putNextEntry(zip64JarEntry);
|
||||
byte[] zip64JarData = writeZip64Jar();
|
||||
zip64JarEntry.setSize(zip64JarData.length);
|
||||
zip64JarEntry.setCompressedSize(zip64JarData.length);
|
||||
zip64JarEntry.setMethod(ZipEntry.STORED);
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(zip64JarData);
|
||||
zip64JarEntry.setCrc(crc32.getValue());
|
||||
output.write(zip64JarData);
|
||||
output.closeEntry();
|
||||
output.close();
|
||||
JarFileArchive jarFileArchive = new JarFileArchive(file);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Failed to get nested archive for entry nested/zip64.jar"));
|
||||
jarFileArchive
|
||||
.getNestedArchive(getEntriesMap(jarFileArchive).get("nested/zip64.jar"));
|
||||
}
|
||||
|
||||
private byte[] writeZip64Jar() throws IOException {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
JarOutputStream jarOutput = new JarOutputStream(bytes);
|
||||
for (int i = 0; i < 65537; i++) {
|
||||
jarOutput.putNextEntry(new JarEntry(i + ".dat"));
|
||||
jarOutput.closeEntry();
|
||||
}
|
||||
jarOutput.close();
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) {
|
||||
Map<String, Archive.Entry> entries = new HashMap<>();
|
||||
for (Archive.Entry entry : archive) {
|
||||
entries.put(entry.getName(), entry);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.data;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ByteArrayRandomAccessData}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ByteArrayRandomAccessDataTests {
|
||||
|
||||
@Test
|
||||
public void testGetInputStream() throws Exception {
|
||||
byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5 };
|
||||
RandomAccessData data = new ByteArrayRandomAccessData(bytes);
|
||||
InputStream inputStream = data.getInputStream(ResourceAccess.PER_READ);
|
||||
assertThat(FileCopyUtils.copyToByteArray(inputStream)).isEqualTo(bytes);
|
||||
assertThat(data.getSize()).isEqualTo(bytes.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSubsection() throws Exception {
|
||||
byte[] bytes = new byte[] { 0, 1, 2, 3, 4, 5 };
|
||||
RandomAccessData data = new ByteArrayRandomAccessData(bytes);
|
||||
data = data.getSubsection(1, 4).getSubsection(1, 2);
|
||||
InputStream inputStream = data.getInputStream(ResourceAccess.PER_READ);
|
||||
assertThat(FileCopyUtils.copyToByteArray(inputStream))
|
||||
.isEqualTo(new byte[] { 2, 3 });
|
||||
assertThat(data.getSize()).isEqualTo(2L);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.data;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile.FilePool;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.BDDMockito.willAnswer;
|
||||
import static org.mockito.BDDMockito.willThrow;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
/**
|
||||
* Tests for {@link RandomAccessDataFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class RandomAccessDataFileTests {
|
||||
|
||||
private static final byte[] BYTES;
|
||||
|
||||
static {
|
||||
BYTES = new byte[256];
|
||||
for (int i = 0; i < BYTES.length; i++) {
|
||||
BYTES[i] = (byte) i;
|
||||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private File tempFile;
|
||||
|
||||
private RandomAccessDataFile file;
|
||||
|
||||
private InputStream inputStream;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.tempFile = this.temporaryFolder.newFile();
|
||||
FileOutputStream outputStream = new FileOutputStream(this.tempFile);
|
||||
outputStream.write(BYTES);
|
||||
outputStream.close();
|
||||
this.file = new RandomAccessDataFile(this.tempFile);
|
||||
this.inputStream = this.file.getInputStream(ResourceAccess.PER_READ);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() throws Exception {
|
||||
this.inputStream.close();
|
||||
this.file.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNotNull() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("File must not be null");
|
||||
new RandomAccessDataFile(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileExists() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("File must exist");
|
||||
new RandomAccessDataFile(new File("/does/not/exist"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileNotNullWithConcurrentReads() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("File must not be null");
|
||||
new RandomAccessDataFile(null, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileExistsWithConcurrentReads() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("File must exist");
|
||||
new RandomAccessDataFile(new File("/does/not/exist"), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamRead() throws Exception {
|
||||
for (int i = 0; i <= 255; i++) {
|
||||
assertThat(this.inputStream.read()).isEqualTo(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadNullBytes() throws Exception {
|
||||
this.thrown.expect(NullPointerException.class);
|
||||
this.thrown.expectMessage("Bytes must not be null");
|
||||
this.inputStream.read(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadNullBytesWithOffset() throws Exception {
|
||||
this.thrown.expect(NullPointerException.class);
|
||||
this.thrown.expectMessage("Bytes must not be null");
|
||||
this.inputStream.read(null, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadBytes() throws Exception {
|
||||
byte[] b = new byte[256];
|
||||
int amountRead = this.inputStream.read(b);
|
||||
assertThat(b).isEqualTo(BYTES);
|
||||
assertThat(amountRead).isEqualTo(256);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadOffsetBytes() throws Exception {
|
||||
byte[] b = new byte[7];
|
||||
this.inputStream.skip(1);
|
||||
int amountRead = this.inputStream.read(b, 2, 3);
|
||||
assertThat(b).isEqualTo(new byte[] { 0, 0, 1, 2, 3, 0, 0 });
|
||||
assertThat(amountRead).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadMoreBytesThanAvailable() throws Exception {
|
||||
byte[] b = new byte[257];
|
||||
int amountRead = this.inputStream.read(b);
|
||||
assertThat(b).startsWith(BYTES);
|
||||
assertThat(amountRead).isEqualTo(256);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadPastEnd() throws Exception {
|
||||
this.inputStream.skip(255);
|
||||
assertThat(this.inputStream.read()).isEqualTo(0xFF);
|
||||
assertThat(this.inputStream.read()).isEqualTo(-1);
|
||||
assertThat(this.inputStream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadZeroLength() throws Exception {
|
||||
byte[] b = new byte[] { 0x0F };
|
||||
int amountRead = this.inputStream.read(b, 0, 0);
|
||||
assertThat(b).isEqualTo(new byte[] { 0x0F });
|
||||
assertThat(amountRead).isEqualTo(0);
|
||||
assertThat(this.inputStream.read()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkip() throws Exception {
|
||||
long amountSkipped = this.inputStream.skip(4);
|
||||
assertThat(this.inputStream.read()).isEqualTo(4);
|
||||
assertThat(amountSkipped).isEqualTo(4L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipMoreThanAvailable() throws Exception {
|
||||
long amountSkipped = this.inputStream.skip(257);
|
||||
assertThat(this.inputStream.read()).isEqualTo(-1);
|
||||
assertThat(amountSkipped).isEqualTo(256L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipPastEnd() throws Exception {
|
||||
this.inputStream.skip(256);
|
||||
long amountSkipped = this.inputStream.skip(1);
|
||||
assertThat(amountSkipped).isEqualTo(0L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionNegativeOffset() throws Exception {
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(-1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionNegativeLength() throws Exception {
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(0, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionZeroLength() throws Exception {
|
||||
RandomAccessData subsection = this.file.getSubsection(0, 0);
|
||||
assertThat(subsection.getInputStream(ResourceAccess.PER_READ).read())
|
||||
.isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionTooBig() throws Exception {
|
||||
this.file.getSubsection(0, 256);
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(0, 257);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsectionTooBigWithOffset() throws Exception {
|
||||
this.file.getSubsection(1, 255);
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
this.file.getSubsection(1, 256);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsection() throws Exception {
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 1);
|
||||
assertThat(subsection.getInputStream(ResourceAccess.PER_READ).read())
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadPastSubsection() throws Exception {
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream(ResourceAccess.PER_READ);
|
||||
assertThat(inputStream.read()).isEqualTo(1);
|
||||
assertThat(inputStream.read()).isEqualTo(2);
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamReadBytesPastSubsection() throws Exception {
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream(ResourceAccess.PER_READ);
|
||||
byte[] b = new byte[3];
|
||||
int amountRead = inputStream.read(b);
|
||||
assertThat(b).isEqualTo(new byte[] { 1, 2, 0 });
|
||||
assertThat(amountRead).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipPastSubsection() throws Exception {
|
||||
RandomAccessData subsection = this.file.getSubsection(1, 2);
|
||||
InputStream inputStream = subsection.getInputStream(ResourceAccess.PER_READ);
|
||||
assertThat(inputStream.skip(3)).isEqualTo(2L);
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inputStreamSkipNegative() throws Exception {
|
||||
assertThat(this.inputStream.skip(-1)).isEqualTo(0L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFile() throws Exception {
|
||||
assertThat(this.file.getFile()).isEqualTo(this.tempFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void concurrentReads() throws Exception {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(20);
|
||||
List<Future<Boolean>> results = new ArrayList<>();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
results.add(executorService.submit(() -> {
|
||||
InputStream subsectionInputStream = RandomAccessDataFileTests.this.file
|
||||
.getSubsection(0, 256).getInputStream(ResourceAccess.PER_READ);
|
||||
byte[] b = new byte[256];
|
||||
subsectionInputStream.read(b);
|
||||
return Arrays.equals(b, BYTES);
|
||||
}));
|
||||
}
|
||||
for (Future<Boolean> future : results) {
|
||||
assertThat(future.get()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void close() throws Exception {
|
||||
this.file.getInputStream(ResourceAccess.PER_READ).read();
|
||||
this.file.close();
|
||||
Field filePoolField = RandomAccessDataFile.class.getDeclaredField("filePool");
|
||||
filePoolField.setAccessible(true);
|
||||
Object filePool = filePoolField.get(this.file);
|
||||
Field filesField = filePool.getClass().getDeclaredField("files");
|
||||
filesField.setAccessible(true);
|
||||
Queue<?> queue = (Queue<?>) filesField.get(filePool);
|
||||
assertThat(queue.size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void seekFailuresDoNotPreventSubsequentReads() throws Exception {
|
||||
FilePool filePool = (FilePool) ReflectionTestUtils.getField(this.file,
|
||||
"filePool");
|
||||
FilePool spiedPool = spy(filePool);
|
||||
ReflectionTestUtils.setField(this.file, "filePool", spiedPool);
|
||||
willAnswer((invocation) -> {
|
||||
RandomAccessFile originalFile = (RandomAccessFile) invocation
|
||||
.callRealMethod();
|
||||
if (Mockito.mockingDetails(originalFile).isSpy()) {
|
||||
return originalFile;
|
||||
}
|
||||
RandomAccessFile spiedFile = spy(originalFile);
|
||||
willThrow(new IOException("Seek failed")).given(spiedFile).seek(anyLong());
|
||||
return spiedFile;
|
||||
}).given(spiedPool).acquire();
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
try {
|
||||
this.file.getInputStream(ResourceAccess.PER_READ).read();
|
||||
fail("Read should fail due to exception from seek");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link AsciiBytes}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class AsciiBytesTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void createFromBytes() throws Exception {
|
||||
AsciiBytes bytes = new AsciiBytes(new byte[] { 65, 66 });
|
||||
assertThat(bytes.toString()).isEqualTo("AB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromBytesWithOffset() throws Exception {
|
||||
AsciiBytes bytes = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
assertThat(bytes.toString()).isEqualTo("BC");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromString() throws Exception {
|
||||
AsciiBytes bytes = new AsciiBytes("AB");
|
||||
assertThat(bytes.toString()).isEqualTo("AB");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void length() throws Exception {
|
||||
AsciiBytes b1 = new AsciiBytes(new byte[] { 65, 66 });
|
||||
AsciiBytes b2 = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
assertThat(b1.length()).isEqualTo(2);
|
||||
assertThat(b2.length()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWith() throws Exception {
|
||||
AsciiBytes abc = new AsciiBytes(new byte[] { 65, 66, 67 });
|
||||
AsciiBytes ab = new AsciiBytes(new byte[] { 65, 66 });
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67 }, 1, 2);
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
assertThat(abc.startsWith(abc)).isTrue();
|
||||
assertThat(abc.startsWith(ab)).isTrue();
|
||||
assertThat(abc.startsWith(bc)).isFalse();
|
||||
assertThat(abc.startsWith(abcd)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endsWith() throws Exception {
|
||||
AsciiBytes abc = new AsciiBytes(new byte[] { 65, 66, 67 });
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67 }, 1, 2);
|
||||
AsciiBytes ab = new AsciiBytes(new byte[] { 65, 66 });
|
||||
AsciiBytes aabc = new AsciiBytes(new byte[] { 65, 65, 66, 67 });
|
||||
assertThat(abc.endsWith(abc)).isTrue();
|
||||
assertThat(abc.endsWith(bc)).isTrue();
|
||||
assertThat(abc.endsWith(ab)).isFalse();
|
||||
assertThat(abc.endsWith(aabc)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void substringFromBeingIndex() throws Exception {
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
assertThat(abcd.substring(0).toString()).isEqualTo("ABCD");
|
||||
assertThat(abcd.substring(1).toString()).isEqualTo("BCD");
|
||||
assertThat(abcd.substring(2).toString()).isEqualTo("CD");
|
||||
assertThat(abcd.substring(3).toString()).isEqualTo("D");
|
||||
assertThat(abcd.substring(4).toString()).isEqualTo("");
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
abcd.substring(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void substring() throws Exception {
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
assertThat(abcd.substring(0, 4).toString()).isEqualTo("ABCD");
|
||||
assertThat(abcd.substring(1, 3).toString()).isEqualTo("BC");
|
||||
assertThat(abcd.substring(3, 4).toString()).isEqualTo("D");
|
||||
assertThat(abcd.substring(3, 3).toString()).isEqualTo("");
|
||||
this.thrown.expect(IndexOutOfBoundsException.class);
|
||||
abcd.substring(3, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendString() throws Exception {
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
AsciiBytes appended = bc.append("D");
|
||||
assertThat(bc.toString()).isEqualTo("BC");
|
||||
assertThat(appended.toString()).isEqualTo("BCD");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendBytes() throws Exception {
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 65, 66, 67, 68 }, 1, 2);
|
||||
AsciiBytes appended = bc.append(new byte[] { 68 });
|
||||
assertThat(bc.toString()).isEqualTo("BC");
|
||||
assertThat(appended.toString()).isEqualTo("BCD");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeAndEquals() throws Exception {
|
||||
AsciiBytes abcd = new AsciiBytes(new byte[] { 65, 66, 67, 68 });
|
||||
AsciiBytes bc = new AsciiBytes(new byte[] { 66, 67 });
|
||||
AsciiBytes bc_substring = new AsciiBytes(new byte[] { 65, 66, 67, 68 })
|
||||
.substring(1, 3);
|
||||
AsciiBytes bc_string = new AsciiBytes("BC");
|
||||
assertThat(bc.hashCode()).isEqualTo(bc.hashCode());
|
||||
assertThat(bc.hashCode()).isEqualTo(bc_substring.hashCode());
|
||||
assertThat(bc.hashCode()).isEqualTo(bc_string.hashCode());
|
||||
assertThat(bc).isEqualTo(bc);
|
||||
assertThat(bc).isEqualTo(bc_substring);
|
||||
assertThat(bc).isEqualTo(bc_string);
|
||||
assertThat(bc.hashCode()).isNotEqualTo(abcd.hashCode());
|
||||
assertThat(bc).isNotEqualTo(abcd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeSameAsString() throws Exception {
|
||||
hashCodeSameAsString("abcABC123xyz!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeSameAsStringWithSpecial() throws Exception {
|
||||
hashCodeSameAsString("special/\u00EB.dat");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeSameAsStringWithCyrillicCharacters() throws Exception {
|
||||
hashCodeSameAsString("\u0432\u0435\u0441\u043D\u0430");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeSameAsStringWithEmoji() throws Exception {
|
||||
hashCodeSameAsString("\ud83d\udca9");
|
||||
}
|
||||
|
||||
private void hashCodeSameAsString(String input) {
|
||||
assertThat(new AsciiBytes(input).hashCode()).isEqualTo(input.hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.data.RandomAccessData;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CentralDirectoryParser}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class CentralDirectoryParserTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private File jarFile;
|
||||
|
||||
private RandomAccessData jarData;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.jarFile = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(this.jarFile);
|
||||
this.jarData = new RandomAccessDataFile(this.jarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void visitsInOrder() throws Exception {
|
||||
MockCentralDirectoryVisitor visitor = new MockCentralDirectoryVisitor();
|
||||
CentralDirectoryParser parser = new CentralDirectoryParser();
|
||||
parser.addVisitor(visitor);
|
||||
parser.parse(this.jarData, false);
|
||||
List<String> invocations = visitor.getInvocations();
|
||||
assertThat(invocations).startsWith("visitStart").endsWith("visitEnd")
|
||||
.contains("visitFileHeader");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void visitRecords() throws Exception {
|
||||
Collector collector = new Collector();
|
||||
CentralDirectoryParser parser = new CentralDirectoryParser();
|
||||
parser.addVisitor(collector);
|
||||
parser.parse(this.jarData, false);
|
||||
Iterator<CentralDirectoryFileHeader> headers = collector.getHeaders().iterator();
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("META-INF/");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("META-INF/MANIFEST.MF");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("1.dat");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("2.dat");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("d/");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("d/9.dat");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("special/");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("special/\u00EB.dat");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("nested.jar");
|
||||
assertThat(headers.next().getName().toString()).isEqualTo("another-nested.jar");
|
||||
assertThat(headers.hasNext()).isFalse();
|
||||
}
|
||||
|
||||
private static class Collector implements CentralDirectoryVisitor {
|
||||
|
||||
private List<CentralDirectoryFileHeader> headers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void visitStart(CentralDirectoryEndRecord endRecord,
|
||||
RandomAccessData centralDirectoryData) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFileHeader(CentralDirectoryFileHeader fileHeader,
|
||||
int dataOffset) {
|
||||
this.headers.add(fileHeader.clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
}
|
||||
|
||||
public List<CentralDirectoryFileHeader> getHeaders() {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class MockCentralDirectoryVisitor implements CentralDirectoryVisitor {
|
||||
|
||||
private final List<String> invocations = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void visitStart(CentralDirectoryEndRecord endRecord,
|
||||
RandomAccessData centralDirectoryData) {
|
||||
this.invocations.add("visitStart");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFileHeader(CentralDirectoryFileHeader fileHeader,
|
||||
int dataOffset) {
|
||||
this.invocations.add("visitFileHeader");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
this.invocations.add("visitEnd");
|
||||
}
|
||||
|
||||
public List<String> getInvocations() {
|
||||
return this.invocations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link Handler}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class HandlerTests {
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
|
||||
@Test
|
||||
public void parseUrlWithJarRootContextAndAbsoluteSpecThatUsesContext()
|
||||
throws MalformedURLException {
|
||||
String spec = "/entry.txt";
|
||||
URL context = createUrl("file:example.jar!/");
|
||||
this.handler.parseURL(context, spec, 0, spec.length());
|
||||
assertThat(context.toExternalForm()).isEqualTo("jar:file:example.jar!/entry.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseUrlWithDirectoryEntryContextAndAbsoluteSpecThatUsesContext()
|
||||
throws MalformedURLException {
|
||||
String spec = "/entry.txt";
|
||||
URL context = createUrl("file:example.jar!/dir/");
|
||||
this.handler.parseURL(context, spec, 0, spec.length());
|
||||
assertThat(context.toExternalForm()).isEqualTo("jar:file:example.jar!/entry.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseUrlWithJarRootContextAndRelativeSpecThatUsesContext()
|
||||
throws MalformedURLException {
|
||||
String spec = "entry.txt";
|
||||
URL context = createUrl("file:example.jar!/");
|
||||
this.handler.parseURL(context, spec, 0, spec.length());
|
||||
assertThat(context.toExternalForm()).isEqualTo("jar:file:example.jar!/entry.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseUrlWithDirectoryEntryContextAndRelativeSpecThatUsesContext()
|
||||
throws MalformedURLException {
|
||||
String spec = "entry.txt";
|
||||
URL context = createUrl("file:example.jar!/dir/");
|
||||
this.handler.parseURL(context, spec, 0, spec.length());
|
||||
assertThat(context.toExternalForm())
|
||||
.isEqualTo("jar:file:example.jar!/dir/entry.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseUrlWithFileEntryContextAndRelativeSpecThatUsesContext()
|
||||
throws MalformedURLException {
|
||||
String spec = "entry.txt";
|
||||
URL context = createUrl("file:example.jar!/dir/file");
|
||||
this.handler.parseURL(context, spec, 0, spec.length());
|
||||
assertThat(context.toExternalForm())
|
||||
.isEqualTo("jar:file:example.jar!/dir/entry.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseUrlWithSpecThatIgnoresContext() throws MalformedURLException {
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
String spec = "jar:file:/other.jar!/nested!/entry.txt";
|
||||
URL context = createUrl("file:example.jar!/dir/file");
|
||||
this.handler.parseURL(context, spec, 0, spec.length());
|
||||
assertThat(context.toExternalForm())
|
||||
.isEqualTo("jar:jar:file:/other.jar!/nested!/entry.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameFileReturnsFalseForUrlsWithDifferentProtocols()
|
||||
throws MalformedURLException {
|
||||
assertThat(this.handler.sameFile(new URL("jar:file:foo.jar!/content.txt"),
|
||||
new URL("file:/foo.jar"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameFileReturnsFalseForDifferentFileInSameJar()
|
||||
throws MalformedURLException {
|
||||
assertThat(this.handler.sameFile(
|
||||
new URL("jar:file:foo.jar!/the/path/to/the/first/content.txt"),
|
||||
new URL("jar:file:/foo.jar!/content.txt"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameFileReturnsFalseForSameFileInDifferentJars()
|
||||
throws MalformedURLException {
|
||||
assertThat(this.handler.sameFile(
|
||||
new URL("jar:file:/the/path/to/the/first.jar!/content.txt"),
|
||||
new URL("jar:file:/second.jar!/content.txt"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameFileReturnsTrueForSameFileInSameJar() throws MalformedURLException {
|
||||
assertThat(this.handler.sameFile(
|
||||
new URL("jar:file:/the/path/to/the/first.jar!/content.txt"),
|
||||
new URL("jar:file:/the/path/to/the/first.jar!/content.txt"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameFileReturnsTrueForUrlsThatReferenceSameFileViaNestedArchiveAndFromRootOfJar()
|
||||
throws MalformedURLException {
|
||||
assertThat(this.handler.sameFile(
|
||||
new URL("jar:file:/test.jar!/BOOT-INF/classes!/foo.txt"),
|
||||
new URL("jar:file:/test.jar!/BOOT-INF/classes/foo.txt"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodesAreEqualForUrlsThatReferenceSameFileViaNestedArchiveAndFromRootOfJar()
|
||||
throws MalformedURLException {
|
||||
assertThat(this.handler
|
||||
.hashCode(new URL("jar:file:/test.jar!/BOOT-INF/classes!/foo.txt")))
|
||||
.isEqualTo(this.handler.hashCode(
|
||||
new URL("jar:file:/test.jar!/BOOT-INF/classes/foo.txt")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlWithSpecReferencingParentDirectory() throws MalformedURLException {
|
||||
assertStandardAndCustomHandlerUrlsAreEqual(
|
||||
"file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd",
|
||||
"../folderB/b.xsd");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlWithSpecReferencingAncestorDirectoryOutsideJarStopsAtJarRoot()
|
||||
throws MalformedURLException {
|
||||
assertStandardAndCustomHandlerUrlsAreEqual(
|
||||
"file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd",
|
||||
"../../../../../../folderB/b.xsd");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void urlWithSpecReferencingCurrentDirectory() throws MalformedURLException {
|
||||
assertStandardAndCustomHandlerUrlsAreEqual(
|
||||
"file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd",
|
||||
"./folderB/./b.xsd");
|
||||
}
|
||||
|
||||
private void assertStandardAndCustomHandlerUrlsAreEqual(String context, String spec)
|
||||
throws MalformedURLException {
|
||||
URL standardUrl = new URL(new URL("jar:" + context), spec);
|
||||
URL customHandlerUrl = new URL(new URL("jar", null, -1, context, this.handler),
|
||||
spec);
|
||||
assertThat(customHandlerUrl.toString()).isEqualTo(standardUrl.toString());
|
||||
}
|
||||
|
||||
private URL createUrl(String file) throws MalformedURLException {
|
||||
return new URL("jar", null, -1, file, this.handler);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.loader.jar.JarURLConnection.JarEntryName;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JarEntryName}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class JarEntryNameTests {
|
||||
|
||||
@Test
|
||||
public void basicName() {
|
||||
assertThat(new JarEntryName("a/b/C.class").toString()).isEqualTo("a/b/C.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nameWithSingleByteEncodedCharacters() {
|
||||
assertThat(new JarEntryName("%61/%62/%43.class").toString())
|
||||
.isEqualTo("a/b/C.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nameWithDoubleByteEncodedCharacters() {
|
||||
assertThat(new JarEntryName("%c3%a1/b/C.class").toString())
|
||||
.isEqualTo("\u00e1/b/C.class");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nameWithMixtureOfEncodedAndUnencodedDoubleByteCharacters()
|
||||
throws UnsupportedEncodingException {
|
||||
assertThat(new JarEntryName("%c3%a1/b/\u00c7.class").toString())
|
||||
.isEqualTo("\u00e1/b/\u00c7.class");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilePermission;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link JarFile}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Martin Lau
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class JarFileTests {
|
||||
|
||||
private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs";
|
||||
|
||||
private static final String HANDLERS_PACKAGE = "org.springframework.boot.loader";
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
private File rootJarFile;
|
||||
|
||||
private JarFile jarFile;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.rootJarFile = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(this.rootJarFile);
|
||||
this.jarFile = new JarFile(this.rootJarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jdkJarFile() throws Exception {
|
||||
// Sanity checks to see how the default jar file operates
|
||||
java.util.jar.JarFile jarFile = new java.util.jar.JarFile(this.rootJarFile);
|
||||
Enumeration<java.util.jar.JarEntry> entries = jarFile.entries();
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("META-INF/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("META-INF/MANIFEST.MF");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("1.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("2.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("d/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("d/9.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("special/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("special/\u00EB.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("nested.jar");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("another-nested.jar");
|
||||
assertThat(entries.hasMoreElements()).isFalse();
|
||||
URL jarUrl = new URL("jar:" + this.rootJarFile.toURI() + "!/");
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { jarUrl });
|
||||
assertThat(urlClassLoader.getResource("special/\u00EB.dat")).isNotNull();
|
||||
assertThat(urlClassLoader.getResource("d/9.dat")).isNotNull();
|
||||
jarFile.close();
|
||||
urlClassLoader.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromFile() throws Exception {
|
||||
JarFile jarFile = new JarFile(this.rootJarFile);
|
||||
assertThat(jarFile.getName()).isNotNull();
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManifest() throws Exception {
|
||||
assertThat(this.jarFile.getManifest().getMainAttributes().getValue("Built-By"))
|
||||
.isEqualTo("j1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManifestEntry() throws Exception {
|
||||
ZipEntry entry = this.jarFile.getJarEntry("META-INF/MANIFEST.MF");
|
||||
Manifest manifest = new Manifest(this.jarFile.getInputStream(entry));
|
||||
assertThat(manifest.getMainAttributes().getValue("Built-By")).isEqualTo("j1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntries() throws Exception {
|
||||
Enumeration<java.util.jar.JarEntry> entries = this.jarFile.entries();
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("META-INF/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("META-INF/MANIFEST.MF");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("1.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("2.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("d/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("d/9.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("special/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("special/\u00EB.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("nested.jar");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("another-nested.jar");
|
||||
assertThat(entries.hasMoreElements()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSpecialResourceViaClassLoader() throws Exception {
|
||||
URLClassLoader urlClassLoader = new URLClassLoader(
|
||||
new URL[] { this.jarFile.getUrl() });
|
||||
assertThat(urlClassLoader.getResource("special/\u00EB.dat")).isNotNull();
|
||||
urlClassLoader.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getJarEntry() throws Exception {
|
||||
java.util.jar.JarEntry entry = this.jarFile.getJarEntry("1.dat");
|
||||
assertThat(entry).isNotNull();
|
||||
assertThat(entry.getName()).isEqualTo("1.dat");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInputStream() throws Exception {
|
||||
InputStream inputStream = this.jarFile
|
||||
.getInputStream(this.jarFile.getEntry("1.dat"));
|
||||
assertThat(inputStream.available()).isEqualTo(1);
|
||||
assertThat(inputStream.read()).isEqualTo(1);
|
||||
assertThat(inputStream.available()).isEqualTo(0);
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getName() throws Exception {
|
||||
assertThat(this.jarFile.getName()).isEqualTo(this.rootJarFile.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSize() throws Exception {
|
||||
assertThat(this.jarFile.size()).isEqualTo((int) this.rootJarFile.length());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntryTime() throws Exception {
|
||||
java.util.jar.JarFile jdkJarFile = new java.util.jar.JarFile(this.rootJarFile);
|
||||
assertThat(this.jarFile.getEntry("META-INF/MANIFEST.MF").getTime())
|
||||
.isEqualTo(jdkJarFile.getEntry("META-INF/MANIFEST.MF").getTime());
|
||||
jdkJarFile.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void close() throws Exception {
|
||||
RandomAccessDataFile randomAccessDataFile = spy(
|
||||
new RandomAccessDataFile(this.rootJarFile, 1));
|
||||
JarFile jarFile = new JarFile(randomAccessDataFile);
|
||||
jarFile.close();
|
||||
verify(randomAccessDataFile).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUrl() throws Exception {
|
||||
URL url = this.jarFile.getUrl();
|
||||
assertThat(url.toString()).isEqualTo("jar:" + this.rootJarFile.toURI() + "!/");
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
|
||||
assertThat(jarURLConnection.getJarFile()).isSameAs(this.jarFile);
|
||||
assertThat(jarURLConnection.getJarEntry()).isNull();
|
||||
assertThat(jarURLConnection.getContentLength()).isGreaterThan(1);
|
||||
assertThat(jarURLConnection.getContent()).isSameAs(this.jarFile);
|
||||
assertThat(jarURLConnection.getContentType()).isEqualTo("x-java/jar");
|
||||
assertThat(jarURLConnection.getJarFileURL().toURI())
|
||||
.isEqualTo(this.rootJarFile.toURI());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createEntryUrl() throws Exception {
|
||||
URL url = new URL(this.jarFile.getUrl(), "1.dat");
|
||||
assertThat(url.toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/1.dat");
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
|
||||
assertThat(jarURLConnection.getJarFile()).isSameAs(this.jarFile);
|
||||
assertThat(jarURLConnection.getJarEntry())
|
||||
.isSameAs(this.jarFile.getJarEntry("1.dat"));
|
||||
assertThat(jarURLConnection.getContentLength()).isEqualTo(1);
|
||||
assertThat(jarURLConnection.getContent()).isInstanceOf(InputStream.class);
|
||||
assertThat(jarURLConnection.getContentType()).isEqualTo("content/unknown");
|
||||
assertThat(jarURLConnection.getPermission()).isInstanceOf(FilePermission.class);
|
||||
FilePermission permission = (FilePermission) jarURLConnection.getPermission();
|
||||
assertThat(permission.getActions()).isEqualTo("read");
|
||||
assertThat(permission.getName()).isEqualTo(this.rootJarFile.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMissingEntryUrl() throws Exception {
|
||||
URL url = new URL(this.jarFile.getUrl(), "missing.dat");
|
||||
assertThat(url.toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/missing.dat");
|
||||
this.thrown.expect(FileNotFoundException.class);
|
||||
((JarURLConnection) url.openConnection()).getJarEntry();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUrlStream() throws Exception {
|
||||
URL url = this.jarFile.getUrl();
|
||||
url.openConnection();
|
||||
this.thrown.expect(IOException.class);
|
||||
url.openStream();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntryUrlStream() throws Exception {
|
||||
URL url = new URL(this.jarFile.getUrl(), "1.dat");
|
||||
url.openConnection();
|
||||
InputStream stream = url.openStream();
|
||||
assertThat(stream.read()).isEqualTo(1);
|
||||
assertThat(stream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedJarFile() throws Exception {
|
||||
JarFile nestedJarFile = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
|
||||
|
||||
Enumeration<java.util.jar.JarEntry> entries = nestedJarFile.entries();
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("META-INF/");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("META-INF/MANIFEST.MF");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("3.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("4.dat");
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("\u00E4.dat");
|
||||
assertThat(entries.hasMoreElements()).isFalse();
|
||||
|
||||
InputStream inputStream = nestedJarFile
|
||||
.getInputStream(nestedJarFile.getEntry("3.dat"));
|
||||
assertThat(inputStream.read()).isEqualTo(3);
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
|
||||
URL url = nestedJarFile.getUrl();
|
||||
assertThat(url.toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar!/");
|
||||
JarURLConnection conn = (JarURLConnection) url.openConnection();
|
||||
assertThat(conn.getJarFile()).isSameAs(nestedJarFile);
|
||||
assertThat(conn.getJarFileURL().toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar");
|
||||
assertThat(conn.getInputStream()).isNotNull();
|
||||
JarInputStream jarInputStream = new JarInputStream(conn.getInputStream());
|
||||
assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("3.dat");
|
||||
assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("4.dat");
|
||||
assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("\u00E4.dat");
|
||||
jarInputStream.close();
|
||||
assertThat(conn.getPermission()).isInstanceOf(FilePermission.class);
|
||||
FilePermission permission = (FilePermission) conn.getPermission();
|
||||
assertThat(permission.getActions()).isEqualTo("read");
|
||||
assertThat(permission.getName()).isEqualTo(this.rootJarFile.getPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedJarDirectory() throws Exception {
|
||||
JarFile nestedJarFile = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("d/"));
|
||||
|
||||
Enumeration<java.util.jar.JarEntry> entries = nestedJarFile.entries();
|
||||
assertThat(entries.nextElement().getName()).isEqualTo("9.dat");
|
||||
assertThat(entries.hasMoreElements()).isFalse();
|
||||
|
||||
InputStream inputStream = nestedJarFile
|
||||
.getInputStream(nestedJarFile.getEntry("9.dat"));
|
||||
assertThat(inputStream.read()).isEqualTo(9);
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
|
||||
URL url = nestedJarFile.getUrl();
|
||||
assertThat(url.toString()).isEqualTo("jar:" + this.rootJarFile.toURI() + "!/d!/");
|
||||
assertThat(((JarURLConnection) url.openConnection()).getJarFile())
|
||||
.isSameAs(nestedJarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNestedJarEntryUrl() throws Exception {
|
||||
JarFile nestedJarFile = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
|
||||
URL url = nestedJarFile.getJarEntry("3.dat").getUrl();
|
||||
assertThat(url.toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar!/3.dat");
|
||||
InputStream inputStream = url.openStream();
|
||||
assertThat(inputStream).isNotNull();
|
||||
assertThat(inputStream.read()).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createUrlFromString() throws Exception {
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
String spec = "jar:" + this.rootJarFile.toURI() + "!/nested.jar!/3.dat";
|
||||
URL url = new URL(spec);
|
||||
assertThat(url.toString()).isEqualTo(spec);
|
||||
InputStream inputStream = url.openStream();
|
||||
assertThat(inputStream).isNotNull();
|
||||
assertThat(inputStream.read()).isEqualTo(3);
|
||||
JarURLConnection connection = (JarURLConnection) url.openConnection();
|
||||
assertThat(connection.getURL().toString()).isEqualTo(spec);
|
||||
assertThat(connection.getJarFileURL().toString())
|
||||
.isEqualTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar");
|
||||
assertThat(connection.getEntryName()).isEqualTo("3.dat");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNonNestedUrlFromString() throws Exception {
|
||||
nonNestedJarFileFromString("jar:" + this.rootJarFile.toURI() + "!/2.dat");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNonNestedUrlFromPathString() throws Exception {
|
||||
nonNestedJarFileFromString(
|
||||
"jar:" + this.rootJarFile.toPath().toUri() + "!/2.dat");
|
||||
}
|
||||
|
||||
private void nonNestedJarFileFromString(String spec) throws Exception {
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
URL url = new URL(spec);
|
||||
assertThat(url.toString()).isEqualTo(spec);
|
||||
InputStream inputStream = url.openStream();
|
||||
assertThat(inputStream).isNotNull();
|
||||
assertThat(inputStream.read()).isEqualTo(2);
|
||||
JarURLConnection connection = (JarURLConnection) url.openConnection();
|
||||
assertThat(connection.getURL().toString()).isEqualTo(spec);
|
||||
assertThat(connection.getJarFileURL().toURI())
|
||||
.isEqualTo(this.rootJarFile.toURI());
|
||||
assertThat(connection.getEntryName()).isEqualTo("2.dat");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDirectoryInputStream() throws Exception {
|
||||
InputStream inputStream = this.jarFile
|
||||
.getInputStream(this.jarFile.getEntry("d/"));
|
||||
assertThat(inputStream).isNotNull();
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDirectoryInputStreamWithoutSlash() throws Exception {
|
||||
InputStream inputStream = this.jarFile.getInputStream(this.jarFile.getEntry("d"));
|
||||
assertThat(inputStream).isNotNull();
|
||||
assertThat(inputStream.read()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensibleToString() throws Exception {
|
||||
assertThat(this.jarFile.toString()).isEqualTo(this.rootJarFile.getPath());
|
||||
assertThat(this.jarFile.getNestedJarFile(this.jarFile.getEntry("nested.jar"))
|
||||
.toString()).isEqualTo(this.rootJarFile.getPath() + "!/nested.jar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifySignedJar() throws Exception {
|
||||
String classpath = System.getProperty("java.class.path");
|
||||
String[] entries = classpath.split(System.getProperty("path.separator"));
|
||||
String signedJarFile = null;
|
||||
for (String entry : entries) {
|
||||
if (entry.contains("bcprov")) {
|
||||
signedJarFile = entry;
|
||||
}
|
||||
}
|
||||
assertThat(signedJarFile).isNotNull();
|
||||
java.util.jar.JarFile jarFile = new JarFile(new File(signedJarFile));
|
||||
jarFile.getManifest();
|
||||
Enumeration<JarEntry> jarEntries = jarFile.entries();
|
||||
while (jarEntries.hasMoreElements()) {
|
||||
JarEntry jarEntry = jarEntries.nextElement();
|
||||
InputStream inputStream = jarFile.getInputStream(jarEntry);
|
||||
inputStream.skip(Long.MAX_VALUE);
|
||||
inputStream.close();
|
||||
if (!jarEntry.getName().startsWith("META-INF") && !jarEntry.isDirectory()
|
||||
&& !jarEntry.getName().endsWith("TigerDigest.class")) {
|
||||
assertThat(jarEntry.getCertificates()).isNotNull();
|
||||
}
|
||||
}
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jarFileWithScriptAtTheStart() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
InputStream sourceJarContent = new FileInputStream(this.rootJarFile);
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
StreamUtils.copy("#/bin/bash", Charset.defaultCharset(), outputStream);
|
||||
FileCopyUtils.copy(sourceJarContent, outputStream);
|
||||
this.rootJarFile = file;
|
||||
this.jarFile = new JarFile(file);
|
||||
// Call some other tests to verify
|
||||
getEntries();
|
||||
getNestedJarFile();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotLoadMissingJar() throws Exception {
|
||||
// relates to gh-1070
|
||||
JarFile nestedJarFile = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
|
||||
URL nestedUrl = nestedJarFile.getUrl();
|
||||
URL url = new URL(nestedUrl, nestedJarFile.getUrl() + "missing.jar!/3.dat");
|
||||
this.thrown.expect(FileNotFoundException.class);
|
||||
url.openConnection().getInputStream();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerUrlProtocolHandlerWithNoExistingRegistration() {
|
||||
String original = System.getProperty(PROTOCOL_HANDLER);
|
||||
try {
|
||||
System.clearProperty(PROTOCOL_HANDLER);
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
String protocolHandler = System.getProperty(PROTOCOL_HANDLER);
|
||||
assertThat(protocolHandler).isEqualTo(HANDLERS_PACKAGE);
|
||||
}
|
||||
finally {
|
||||
if (original == null) {
|
||||
System.clearProperty(PROTOCOL_HANDLER);
|
||||
}
|
||||
else {
|
||||
System.setProperty(PROTOCOL_HANDLER, original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerUrlProtocolHandlerAddsToExistingRegistration() {
|
||||
String original = System.getProperty(PROTOCOL_HANDLER);
|
||||
try {
|
||||
System.setProperty(PROTOCOL_HANDLER, "com.example");
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
String protocolHandler = System.getProperty(PROTOCOL_HANDLER);
|
||||
assertThat(protocolHandler).isEqualTo("com.example|" + HANDLERS_PACKAGE);
|
||||
}
|
||||
finally {
|
||||
if (original == null) {
|
||||
System.clearProperty(PROTOCOL_HANDLER);
|
||||
}
|
||||
else {
|
||||
System.setProperty(PROTOCOL_HANDLER, original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jarFileCanBeDeletedOnceItHasBeenClosed() throws Exception {
|
||||
File temp = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(temp);
|
||||
JarFile jf = new JarFile(temp);
|
||||
jf.close();
|
||||
assertThat(temp.delete()).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JarURLConnection}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @author Rostyslav Dudka
|
||||
*/
|
||||
public class JarURLConnectionTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
|
||||
|
||||
private File rootJarFile;
|
||||
|
||||
private JarFile jarFile;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.rootJarFile = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(this.rootJarFile);
|
||||
this.jarFile = new JarFile(this.rootJarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToRootUsingAbsoluteUrl() throws Exception {
|
||||
URL url = new URL("jar:file:" + getAbsolutePath() + "!/");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getContent())
|
||||
.isSameAs(this.jarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToRootUsingRelativeUrl() throws Exception {
|
||||
URL url = new URL("jar:file:" + getRelativePath() + "!/");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getContent())
|
||||
.isSameAs(this.jarFile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingAbsoluteUrl() throws Exception {
|
||||
URL url = new URL("jar:file:" + getAbsolutePath() + "!/1.dat");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingRelativeUrl() throws Exception {
|
||||
URL url = new URL("jar:file:" + getRelativePath() + "!/1.dat");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingAbsoluteUrlWithFileColonSlashSlashPrefix()
|
||||
throws Exception {
|
||||
URL url = new URL("jar:file:/" + getAbsolutePath() + "!/1.dat");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 1 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingAbsoluteUrlForNestedEntry() throws Exception {
|
||||
URL url = new URL("jar:file:" + getAbsolutePath() + "!/nested.jar!/3.dat");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingRelativeUrlForNestedEntry() throws Exception {
|
||||
URL url = new URL("jar:file:" + getRelativePath() + "!/nested.jar!/3.dat");
|
||||
assertThat(JarURLConnection.get(url, this.jarFile).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingAbsoluteUrlForEntryFromNestedJarFile()
|
||||
throws Exception {
|
||||
URL url = new URL("jar:file:" + getAbsolutePath() + "!/nested.jar!/3.dat");
|
||||
JarFile nested = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
|
||||
assertThat(JarURLConnection.get(url, nested).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryUsingRelativeUrlForEntryFromNestedJarFile()
|
||||
throws Exception {
|
||||
URL url = new URL("jar:file:" + getRelativePath() + "!/nested.jar!/3.dat");
|
||||
JarFile nested = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
|
||||
assertThat(JarURLConnection.get(url, nested).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionToEntryInNestedJarFromUrlThatUsesExistingUrlAsContext()
|
||||
throws Exception {
|
||||
URL url = new URL(new URL("jar", null, -1,
|
||||
"file:" + getAbsolutePath() + "!/nested.jar!/", new Handler()), "/3.dat");
|
||||
JarFile nested = this.jarFile
|
||||
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
|
||||
assertThat(JarURLConnection.get(url, nested).getInputStream())
|
||||
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContentLengthReturnsLengthOfUnderlyingEntry() throws Exception {
|
||||
URL url = new URL(new URL("jar", null, -1,
|
||||
"file:" + getAbsolutePath() + "!/nested.jar!/", new Handler()), "/3.dat");
|
||||
assertThat(url.openConnection().getContentLength()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContentLengthLongReturnsLengthOfUnderlyingEntry() throws Exception {
|
||||
URL url = new URL(new URL("jar", null, -1,
|
||||
"file:" + getAbsolutePath() + "!/nested.jar!/", new Handler()), "/3.dat");
|
||||
assertThat(url.openConnection().getContentLengthLong()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLastModifiedReturnsLastModifiedTimeOfJarEntry() throws Exception {
|
||||
URL url = new URL("jar:file:" + getAbsolutePath() + "!/1.dat");
|
||||
JarURLConnection connection = JarURLConnection.get(url, this.jarFile);
|
||||
assertThat(connection.getLastModified())
|
||||
.isEqualTo(connection.getJarEntry().getTime());
|
||||
}
|
||||
|
||||
private String getAbsolutePath() {
|
||||
return this.rootJarFile.getAbsolutePath().replace('\\', '/');
|
||||
}
|
||||
|
||||
private String getRelativePath() {
|
||||
return this.rootJarFile.getPath().replace('\\', '/');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.loader.util;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SystemPropertyUtils}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class SystemPropertyUtilsTests {
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
System.setProperty("foo", "bar");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void close() {
|
||||
System.clearProperty("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVanillaPlaceholder() {
|
||||
assertThat(SystemPropertyUtils.resolvePlaceholders("${foo}")).isEqualTo("bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultValue() {
|
||||
assertThat(SystemPropertyUtils.resolvePlaceholders("${bar:foo}"))
|
||||
.isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedPlaceholder() {
|
||||
assertThat(SystemPropertyUtils.resolvePlaceholders("${bar:${spam:foo}}"))
|
||||
.isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnvVar() {
|
||||
assertThat(SystemPropertyUtils.getProperty("lang"))
|
||||
.isEqualTo(System.getenv("LANG"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
loader.main: demo.Application
|
||||
@@ -0,0 +1 @@
|
||||
loader.main: my.BootInfBarApplication
|
||||
@@ -0,0 +1,3 @@
|
||||
foo: Application
|
||||
loader.main: my.${foo}
|
||||
loader.path: etc
|
||||
@@ -0,0 +1 @@
|
||||
loader.main: demo.Application
|
||||
@@ -0,0 +1 @@
|
||||
loader.main: my.BarApplication
|
||||
@@ -0,0 +1 @@
|
||||
loader.main: demo.HomeApplication
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
Manifest-Version: 1.0
|
||||
Start-Class: ${foo.main}
|
||||
@@ -0,0 +1 @@
|
||||
foo.main: demo.FooApplication
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user