Browse Source

Merge branch '5.3.x'

pull/28922/head
Brian Clozel 2 years ago
parent
commit
34266f22c7
  1. 1
      spring-core/spring-core.gradle
  2. 17
      spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java
  3. 3
      spring-core/src/main/java/org/springframework/core/io/UrlResource.java
  4. 563
      spring-core/src/test/java/org/springframework/core/io/ResourceTests.java

1
spring-core/spring-core.gradle

@ -111,6 +111,7 @@ dependencies { @@ -111,6 +111,7 @@ dependencies {
testImplementation("io.projectreactor:reactor-test")
testImplementation("io.projectreactor.tools:blockhound")
testImplementation("org.skyscreamer:jsonassert")
testImplementation("com.squareup.okhttp3:mockwebserver")
testFixturesImplementation("com.google.code.findbugs:jsr305")
testFixturesImplementation("org.junit.platform:junit-platform-launcher")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")

17
spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java

@ -57,6 +57,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -57,6 +57,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
HttpURLConnection httpCon =
(con instanceof HttpURLConnection ? (HttpURLConnection) con : null);
if (httpCon != null) {
httpCon.setRequestMethod("HEAD");
int code = httpCon.getResponseCode();
if (code == HttpURLConnection.HTTP_OK) {
return true;
@ -107,6 +108,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -107,6 +108,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
URLConnection con = url.openConnection();
customizeConnection(con);
if (con instanceof HttpURLConnection httpCon) {
httpCon.setRequestMethod("HEAD");
int code = httpCon.getResponseCode();
if (code != HttpURLConnection.HTTP_OK) {
httpCon.disconnect();
@ -244,6 +246,9 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -244,6 +246,9 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
// Try a URL connection content-length header
URLConnection con = url.openConnection();
customizeConnection(con);
if (con instanceof HttpURLConnection httpCon) {
httpCon.setRequestMethod("HEAD");
}
return con.getContentLengthLong();
}
}
@ -269,6 +274,9 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -269,6 +274,9 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
// Try a URL connection last-modified header
URLConnection con = url.openConnection();
customizeConnection(con);
if (con instanceof HttpURLConnection httpCon) {
httpCon.setRequestMethod("HEAD");
}
long lastModified = con.getLastModified();
if (fileCheck && lastModified == 0 && con.getContentLengthLong() <= 0) {
throw new FileNotFoundException(getDescription() +
@ -278,8 +286,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -278,8 +286,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
}
/**
* Customize the given {@link URLConnection}, obtained in the course of an
* {@link #exists()}, {@link #contentLength()} or {@link #lastModified()} call.
* Customize the given {@link URLConnection} before fetching the resource.
* <p>Calls {@link ResourceUtils#useCachesIfNecessary(URLConnection)} and
* delegates to {@link #customizeConnection(HttpURLConnection)} if possible.
* Can be overridden in subclasses.
@ -294,14 +301,12 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { @@ -294,14 +301,12 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
}
/**
* Customize the given {@link HttpURLConnection}, obtained in the course of an
* {@link #exists()}, {@link #contentLength()} or {@link #lastModified()} call.
* <p>Sets request method "HEAD" by default. Can be overridden in subclasses.
* Customize the given {@link HttpURLConnection} before fetching the resource.
* <p>Can be overridden in subclasses for configuring request headers and timeouts.
* @param con the HttpURLConnection to customize
* @throws IOException if thrown from HttpURLConnection methods
*/
protected void customizeConnection(HttpURLConnection con) throws IOException {
con.setRequestMethod("HEAD");
}

3
spring-core/src/main/java/org/springframework/core/io/UrlResource.java

@ -29,7 +29,6 @@ import java.net.URLConnection; @@ -29,7 +29,6 @@ import java.net.URLConnection;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
/**
@ -228,7 +227,7 @@ public class UrlResource extends AbstractFileResolvingResource { @@ -228,7 +227,7 @@ public class UrlResource extends AbstractFileResolvingResource {
@Override
public InputStream getInputStream() throws IOException {
URLConnection con = this.url.openConnection();
ResourceUtils.useCachesIfNecessary(con);
customizeConnection(con);
try {
return con.getInputStream();
}

563
spring-core/src/test/java/org/springframework/core/io/ResourceTests.java

@ -23,20 +23,32 @@ import java.io.IOException; @@ -23,20 +23,32 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.stream.Stream;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
/**
* Unit tests for various {@link Resource} implementations.
@ -44,137 +56,25 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; @@ -44,137 +56,25 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @author Juergen Hoeller
* @author Chris Beams
* @author Sam Brannen
* @since 09.09.2004
* @author Brian Clozel
*/
class ResourceTests {
@Test
void byteArrayResource() throws IOException {
Resource resource = new ByteArrayResource("testString".getBytes());
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isFalse();
String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
assertThat(content).isEqualTo("testString");
assertThat(new ByteArrayResource("testString".getBytes())).isEqualTo(resource);
}
@Test
void byteArrayResourceWithDescription() throws IOException {
Resource resource = new ByteArrayResource("testString".getBytes(), "my description");
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isFalse();
String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
assertThat(content).isEqualTo("testString");
assertThat(resource.getDescription().contains("my description")).isTrue();
assertThat(new ByteArrayResource("testString".getBytes())).isEqualTo(resource);
}
@Test
void inputStreamResource() throws IOException {
InputStream is = new ByteArrayInputStream("testString".getBytes());
Resource resource = new InputStreamResource(is);
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isTrue();
String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
assertThat(content).isEqualTo("testString");
assertThat(new InputStreamResource(is)).isEqualTo(resource);
}
@Test
void inputStreamResourceWithDescription() throws IOException {
InputStream is = new ByteArrayInputStream("testString".getBytes());
Resource resource = new InputStreamResource(is, "my description");
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isTrue();
String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
assertThat(content).isEqualTo("testString");
assertThat(resource.getDescription().contains("my description")).isTrue();
assertThat(new InputStreamResource(is)).isEqualTo(resource);
}
@Test
void classPathResource() throws IOException {
Resource resource = new ClassPathResource("org/springframework/core/io/Resource.class");
doTestResource(resource);
Resource resource2 = new ClassPathResource("org/springframework/core/../core/io/./Resource.class");
assertThat(resource2).isEqualTo(resource);
Resource resource3 = new ClassPathResource("org/springframework/core/").createRelative("../core/io/./Resource.class");
assertThat(resource3).isEqualTo(resource);
// Check whether equal/hashCode works in a HashSet.
HashSet<Resource> resources = new HashSet<>();
resources.add(resource);
resources.add(resource2);
assertThat(resources.size()).isEqualTo(1);
}
@Test
void classPathResourceWithClassLoader() throws IOException {
Resource resource =
new ClassPathResource("org/springframework/core/io/Resource.class", getClass().getClassLoader());
doTestResource(resource);
assertThat(new ClassPathResource("org/springframework/core/../core/io/./Resource.class", getClass().getClassLoader())).isEqualTo(resource);
}
@Test
void classPathResourceWithClass() throws IOException {
Resource resource = new ClassPathResource("Resource.class", getClass());
doTestResource(resource);
assertThat(new ClassPathResource("Resource.class", getClass())).isEqualTo(resource);
}
@Test
void fileSystemResource() throws IOException {
String file = getClass().getResource("Resource.class").getFile();
Resource resource = new FileSystemResource(file);
doTestResource(resource);
assertThat(resource).isEqualTo(new FileSystemResource(file));
}
@Test
void fileSystemResourceWithFile() throws IOException {
File file = new File(getClass().getResource("Resource.class").getFile());
Resource resource = new FileSystemResource(file);
doTestResource(resource);
assertThat(resource).isEqualTo(new FileSystemResource(file));
}
@Test
void fileSystemResourceWithFilePath() throws Exception {
Path filePath = Paths.get(getClass().getResource("Resource.class").toURI());
Resource resource = new FileSystemResource(filePath);
doTestResource(resource);
assertThat(resource).isEqualTo(new FileSystemResource(filePath));
}
@Test
void fileSystemResourceWithPlainPath() {
Resource resource = new FileSystemResource("core/io/Resource.class");
assertThat(new FileSystemResource("core/../core/io/./Resource.class")).isEqualTo(resource);
}
@Test
void urlResource() throws IOException {
Resource resource = new UrlResource(getClass().getResource("Resource.class"));
doTestResource(resource);
assertThat(resource).isEqualTo(new UrlResource(getClass().getResource("Resource.class")));
Resource resource2 = new UrlResource("file:core/io/Resource.class");
assertThat(new UrlResource("file:core/../core/io/./Resource.class")).isEqualTo(resource2);
assertThat(new UrlResource("file:/dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(new UrlResource("file:\\dir\\test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(new UrlResource("file:\\dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
}
private void doTestResource(Resource resource) throws IOException {
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void resourceIsValid(Resource resource) throws Exception {
assertThat(resource.getFilename()).isEqualTo("Resource.class");
assertThat(resource.getURL().getFile().endsWith("Resource.class")).isTrue();
assertThat(resource.exists()).isTrue();
assertThat(resource.isReadable()).isTrue();
assertThat(resource.contentLength() > 0).isTrue();
assertThat(resource.lastModified() > 0).isTrue();
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void resourceCreateRelative(Resource resource) throws Exception {
Resource relative1 = resource.createRelative("ClassPathResource.class");
assertThat(relative1.getFilename()).isEqualTo("ClassPathResource.class");
assertThat(relative1.getURL().getFile().endsWith("ClassPathResource.class")).isTrue();
@ -182,7 +82,11 @@ class ResourceTests { @@ -182,7 +82,11 @@ class ResourceTests {
assertThat(relative1.isReadable()).isTrue();
assertThat(relative1.contentLength() > 0).isTrue();
assertThat(relative1.lastModified() > 0).isTrue();
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void resourceCreateRelativeWithFolder(Resource resource) throws Exception {
Resource relative2 = resource.createRelative("support/ResourcePatternResolver.class");
assertThat(relative2.getFilename()).isEqualTo("ResourcePatternResolver.class");
assertThat(relative2.getURL().getFile().endsWith("ResourcePatternResolver.class")).isTrue();
@ -190,7 +94,11 @@ class ResourceTests { @@ -190,7 +94,11 @@ class ResourceTests {
assertThat(relative2.isReadable()).isTrue();
assertThat(relative2.contentLength() > 0).isTrue();
assertThat(relative2.lastModified() > 0).isTrue();
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void resourceCreateRelativeWithDotPath(Resource resource) throws Exception {
Resource relative3 = resource.createRelative("../SpringVersion.class");
assertThat(relative3.getFilename()).isEqualTo("SpringVersion.class");
assertThat(relative3.getURL().getFile().endsWith("SpringVersion.class")).isTrue();
@ -198,7 +106,11 @@ class ResourceTests { @@ -198,7 +106,11 @@ class ResourceTests {
assertThat(relative3.isReadable()).isTrue();
assertThat(relative3.contentLength() > 0).isTrue();
assertThat(relative3.lastModified() > 0).isTrue();
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void resourceCreateRelativeUnknown(Resource resource) throws Exception {
Resource relative4 = resource.createRelative("X.class");
assertThat(relative4.exists()).isFalse();
assertThat(relative4.isReadable()).isFalse();
@ -208,141 +120,338 @@ class ResourceTests { @@ -208,141 +120,338 @@ class ResourceTests {
relative4::lastModified);
}
@Test
void urlResourceFactoryMethods() throws IOException {
Resource resource1 = new UrlResource("file:core/io/Resource.class");
Resource resource2 = UrlResource.from("file:core/io/Resource.class");
Resource resource3 = UrlResource.from(resource1.getURI());
assertThat(resource2.getURL()).isEqualTo(resource1.getURL());
assertThat(resource3.getURL()).isEqualTo(resource1.getURL());
assertThat(UrlResource.from("file:core/../core/io/./Resource.class")).isEqualTo(resource1);
assertThat(UrlResource.from("file:/dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(UrlResource.from("file:\\dir\\test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(UrlResource.from("file:\\dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void loadingMissingResourceFails(Resource resource) {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
resource.createRelative("X").getInputStream());
}
@Test
void classPathResourceWithRelativePath() throws IOException {
Resource resource = new ClassPathResource("dir/");
Resource relative = resource.createRelative("subdir");
assertThat(relative).isEqualTo(new ClassPathResource("dir/subdir"));
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void readingMissingResourceFails(Resource resource) {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
resource.createRelative("X").readableChannel());
}
@Test
void fileSystemResourceWithRelativePath() throws IOException {
Resource resource = new FileSystemResource("dir/");
Resource relative = resource.createRelative("subdir");
assertThat(relative).isEqualTo(new FileSystemResource("dir/subdir"));
private static Stream<Arguments> resource() throws URISyntaxException {
URL resourceClass = ResourceTests.class.getResource("Resource.class");
Path resourceClassFilePath = Paths.get(resourceClass.toURI());
return Stream.of(
Arguments.of(Named.of("ClassPathResource", new ClassPathResource("org/springframework/core/io/Resource.class"))),
Arguments.of(Named.of("ClassPathResource with ClassLoader", new ClassPathResource("org/springframework/core/io/Resource.class", ResourceTests.class.getClassLoader()))),
Arguments.of(Named.of("ClassPathResource with Class", new ClassPathResource("Resource.class", ResourceTests.class))),
Arguments.of(Named.of("FileSystemResource", new FileSystemResource(resourceClass.getFile()))),
Arguments.of(Named.of("FileSystemResource with File", new FileSystemResource(new File(resourceClass.getFile())))),
Arguments.of(Named.of("FileSystemResource with File path", new FileSystemResource(resourceClassFilePath))),
Arguments.of(Named.of("UrlResource", new UrlResource(resourceClass)))
);
}
@Test
void urlResourceWithRelativePath() throws IOException {
Resource resource = new UrlResource("file:dir/");
Resource relative = resource.createRelative("subdir");
assertThat(relative).isEqualTo(new UrlResource("file:dir/subdir"));
@Nested
class ByteArrayResourceTests {
@Test
void hasContent() throws Exception {
Resource resource = new ByteArrayResource("testString".getBytes());
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isFalse();
String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
assertThat(content).isEqualTo("testString");
assertThat(new ByteArrayResource("testString".getBytes())).isEqualTo(resource);
}
@Test
void isNotOpen() {
Resource resource = new ByteArrayResource("testString".getBytes());
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isFalse();
}
@Test
void hasDescription() {
Resource resource = new ByteArrayResource("testString".getBytes(), "my description");
assertThat(resource.getDescription().contains("my description")).isTrue();
}
}
@Test
void nonFileResourceExists() throws Exception {
URL url = new URL("https://spring.io/");
@Nested
class InputStreamResourceTests {
// Abort if spring.io is not reachable.
assumeTrue(urlIsReachable(url));
@Test
void hasContent() throws Exception {
InputStream is = new ByteArrayInputStream("testString".getBytes());
Resource resource = new InputStreamResource(is);
String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));
assertThat(content).isEqualTo("testString");
assertThat(new InputStreamResource(is)).isEqualTo(resource);
}
Resource resource = new UrlResource(url);
assertThat(resource.exists()).isTrue();
@Test
void isOpen() {
InputStream is = new ByteArrayInputStream("testString".getBytes());
Resource resource = new InputStreamResource(is);
assertThat(resource.exists()).isTrue();
assertThat(resource.isOpen()).isTrue();
}
@Test
void hasDescription() {
InputStream is = new ByteArrayInputStream("testString".getBytes());
Resource resource = new InputStreamResource(is, "my description");
assertThat(resource.getDescription().contains("my description")).isTrue();
}
}
private boolean urlIsReachable(URL url) {
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD");
connection.setReadTimeout(5_000);
return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
@Nested
class ClassPathResourceTests {
@Test
void equalsAndHashCode() {
Resource resource = new ClassPathResource("org/springframework/core/io/Resource.class");
Resource resource2 = new ClassPathResource("org/springframework/core/../core/io/./Resource.class");
Resource resource3 = new ClassPathResource("org/springframework/core/").createRelative("../core/io/./Resource.class");
assertThat(resource2).isEqualTo(resource);
assertThat(resource3).isEqualTo(resource);
// Check whether equal/hashCode works in a HashSet.
HashSet<Resource> resources = new HashSet<>();
resources.add(resource);
resources.add(resource2);
assertThat(resources.size()).isEqualTo(1);
}
@Test
void resourcesWithDifferentPathsAreEqual() {
Resource resource = new ClassPathResource("org/springframework/core/io/Resource.class", getClass().getClassLoader());
ClassPathResource sameResource = new ClassPathResource("org/springframework/core/../core/io/./Resource.class", getClass().getClassLoader());
assertThat(sameResource).isEqualTo(resource);
}
catch (Exception ex) {
return false;
@Test
void relativeResourcesAreEqual() throws Exception {
Resource resource = new ClassPathResource("dir/");
Resource relative = resource.createRelative("subdir");
assertThat(relative).isEqualTo(new ClassPathResource("dir/subdir"));
}
}
@Test
void abstractResourceExceptions() throws Exception {
final String name = "test-resource";
@Nested
class FileSystemResourceTests {
Resource resource = new AbstractResource() {
@Override
public String getDescription() {
return name;
}
@Override
public InputStream getInputStream() throws IOException {
throw new FileNotFoundException();
}
};
@Test
void sameResourceIsEqual() {
String file = getClass().getResource("Resource.class").getFile();
Resource resource = new FileSystemResource(file);
assertThat(resource).isEqualTo(new FileSystemResource(file));
}
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(
resource::getURL)
.withMessageContaining(name);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(
resource::getFile)
.withMessageContaining(name);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
resource.createRelative("/testing"))
.withMessageContaining(name);
@Test
void sameResourceFromFileIsEqual() {
File file = new File(getClass().getResource("Resource.class").getFile());
Resource resource = new FileSystemResource(file);
assertThat(resource).isEqualTo(new FileSystemResource(file));
}
@Test
void sameResourceFromFilePathIsEqual() throws Exception {
Path filePath = Paths.get(getClass().getResource("Resource.class").toURI());
Resource resource = new FileSystemResource(filePath);
assertThat(resource).isEqualTo(new FileSystemResource(filePath));
}
@Test
void sameResourceFromDotPathIsEqual() {
Resource resource = new FileSystemResource("core/io/Resource.class");
assertThat(new FileSystemResource("core/../core/io/./Resource.class")).isEqualTo(resource);
}
@Test
void relativeResourcesAreEqual() throws Exception {
Resource resource = new FileSystemResource("dir/");
Resource relative = resource.createRelative("subdir");
assertThat(relative).isEqualTo(new FileSystemResource("dir/subdir"));
}
@Test
void readableChannelProvidesContent() throws Exception {
Resource resource = new FileSystemResource(getClass().getResource("Resource.class").getFile());
try (ReadableByteChannel channel = resource.readableChannel()) {
ByteBuffer buffer = ByteBuffer.allocate((int) resource.contentLength());
channel.read(buffer);
buffer.rewind();
assertThat(buffer.limit() > 0).isTrue();
}
}
assertThat(resource.getFilename()).isNull();
}
@Test
void contentLength() throws IOException {
AbstractResource resource = new AbstractResource() {
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(new byte[] { 'a', 'b', 'c' });
@Nested
class UrlResourceTests {
private MockWebServer server = new MockWebServer();
@Test
void sameResourceWithRelativePathIsEqual() throws Exception {
Resource resource = new UrlResource("file:core/io/Resource.class");
assertThat(new UrlResource("file:core/../core/io/./Resource.class")).isEqualTo(resource);
}
@Test
void filenameIsExtractedFromFilePath() throws Exception {
assertThat(new UrlResource("file:/dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(new UrlResource("file:\\dir\\test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(new UrlResource("file:\\dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
}
@Test
void factoryMethodsProduceEqualResources() throws Exception {
Resource resource1 = new UrlResource("file:core/io/Resource.class");
Resource resource2 = UrlResource.from("file:core/io/Resource.class");
Resource resource3 = UrlResource.from(resource1.getURI());
assertThat(resource2.getURL()).isEqualTo(resource1.getURL());
assertThat(resource3.getURL()).isEqualTo(resource1.getURL());
assertThat(UrlResource.from("file:core/../core/io/./Resource.class")).isEqualTo(resource1);
assertThat(UrlResource.from("file:/dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(UrlResource.from("file:\\dir\\test.txt?argh").getFilename()).isEqualTo("test.txt");
assertThat(UrlResource.from("file:\\dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
}
@Test
void relativeResourcesAreEqual() throws Exception {
Resource resource = new UrlResource("file:dir/");
Resource relative = resource.createRelative("subdir");
assertThat(relative).isEqualTo(new UrlResource("file:dir/subdir"));
}
@Test
void missingRemoteResourceDoesNotExist() throws Exception {
String baseUrl = startServer();
UrlResource resource = new UrlResource(baseUrl + "/missing");
assertThat(resource.exists()).isFalse();
}
@Test
void remoteResourceExists() throws Exception {
String baseUrl = startServer();
UrlResource resource = new UrlResource(baseUrl + "/resource");
assertThat(resource.exists()).isTrue();
assertThat(resource.contentLength()).isEqualTo(6);
}
@Test
void canCustomizeHttpUrlConnectionForExists() throws Exception {
String baseUrl = startServer();
CustomResource resource = new CustomResource(baseUrl + "/resource");
assertThat(resource.exists()).isTrue();
RecordedRequest request = this.server.takeRequest();
assertThat(request.getMethod()).isEqualTo("HEAD");
assertThat(request.getHeader("Framework-Name")).isEqualTo("Spring");
}
@Test
void canCustomizeHttpUrlConnectionForRead() throws Exception {
String baseUrl = startServer();
CustomResource resource = new CustomResource(baseUrl + "/resource");
assertThat(resource.getInputStream()).hasContent("Spring");
RecordedRequest request = this.server.takeRequest();
assertThat(request.getMethod()).isEqualTo("GET");
assertThat(request.getHeader("Framework-Name")).isEqualTo("Spring");
}
@AfterEach
void shutdown() throws Exception {
this.server.shutdown();
}
private String startServer() throws Exception {
this.server.setDispatcher(new ResourceDispatcher());
this.server.start();
return "http://localhost:" + this.server.getPort();
}
class CustomResource extends UrlResource {
public CustomResource(String path) throws MalformedURLException {
super(path);
}
@Override
public String getDescription() {
return "";
protected void customizeConnection(HttpURLConnection con) throws IOException {
con.setRequestProperty("Framework-Name", "Spring");
}
};
assertThat(resource.contentLength()).isEqualTo(3L);
}
@Test
void readableChannel() throws IOException {
Resource resource = new FileSystemResource(getClass().getResource("Resource.class").getFile());
try (ReadableByteChannel channel = resource.readableChannel()) {
ByteBuffer buffer = ByteBuffer.allocate((int) resource.contentLength());
channel.read(buffer);
buffer.rewind();
assertThat(buffer.limit() > 0).isTrue();
}
}
@Test
void inputStreamNotFoundOnFileSystemResource() throws IOException {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
new FileSystemResource(getClass().getResource("Resource.class").getFile()).createRelative("X").getInputStream());
}
class ResourceDispatcher extends Dispatcher {
@Test
void readableChannelNotFoundOnFileSystemResource() throws IOException {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
new FileSystemResource(getClass().getResource("Resource.class").getFile()).createRelative("X").readableChannel());
@Override
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
if (request.getPath().equals("/resource")) {
switch (request.getMethod()) {
case "HEAD":
return new MockResponse()
.addHeader("Content-Length", "6");
case "GET":
return new MockResponse()
.addHeader("Content-Length", "6")
.addHeader("Content-Type", "text/plain")
.setBody("Spring");
}
}
return new MockResponse().setResponseCode(404);
}
}
}
@Test
void inputStreamNotFoundOnClassPathResource() throws IOException {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
new ClassPathResource("Resource.class", getClass()).createRelative("X").getInputStream());
}
@Nested
class AbstractResourceTests {
@Test
void missingResourceIsNotReadable() {
final String name = "test-resource";
Resource resource = new AbstractResource() {
@Override
public String getDescription() {
return name;
}
@Override
public InputStream getInputStream() throws IOException {
throw new FileNotFoundException();
}
};
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(resource::getURL)
.withMessageContaining(name);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(resource::getFile)
.withMessageContaining(name);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
resource.createRelative("/testing")).withMessageContaining(name);
assertThat(resource.getFilename()).isNull();
}
@Test
void hasContentLength() throws Exception {
AbstractResource resource = new AbstractResource() {
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(new byte[] {'a', 'b', 'c'});
}
@Override
public String getDescription() {
return "";
}
};
assertThat(resource.contentLength()).isEqualTo(3L);
}
@Test
void readableChannelNotFoundOnClassPathResource() throws IOException {
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
new ClassPathResource("Resource.class", getClass()).createRelative("X").readableChannel());
}
}

Loading…
Cancel
Save