Use Gradle test fixture support for spring-web

See gh-23550
This commit is contained in:
Sam Brannen
2019-12-31 14:58:51 +01:00
parent 8a371c7669
commit 7b6d83a106
463 changed files with 1055 additions and 1003 deletions

View File

@@ -46,6 +46,7 @@ import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.protobuf.Msg;
import org.springframework.protobuf.SecondMsg;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
/**
* Test scenarios for data buffer leaks.

View File

@@ -37,10 +37,10 @@ import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;

View File

@@ -32,9 +32,9 @@ import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -31,9 +31,9 @@ import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests;
import org.springframework.core.testfixture.io.buffer.DataBufferTestUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -1,76 +0,0 @@
/*
* Copyright 2002-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
*
* https://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.http.codec;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @author Sebastien Deleuze
*/
@XmlRootElement
public class Pojo {
private String foo;
private String bar;
public Pojo() {
}
public Pojo(String foo, String bar) {
this.foo = foo;
this.bar = bar;
}
public String getFoo() {
return this.foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof Pojo) {
Pojo other = (Pojo) o;
return this.foo.equals(other.foo) && this.bar.equals(other.bar);
}
return false;
}
@Override
public int hashCode() {
return 31 * foo.hashCode() + bar.hashCode();
}
@Override
public String toString() {
return "Pojo[foo='" + this.foo + "\'" + ", bar='" + this.bar + "\']";
}
}

View File

@@ -30,14 +30,14 @@ import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRange;
import org.springframework.http.HttpStatus;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.http.MediaType.TEXT_PLAIN;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;
import static org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest.get;
/**
* Unit tests for {@link ResourceHttpMessageWriter}.

View File

@@ -30,7 +30,8 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -36,7 +36,8 @@ import org.springframework.core.testfixture.io.buffer.DataBufferTestUtils;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.ResolvableType.forClass;

View File

@@ -27,9 +27,9 @@ import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractDecoderTests;
import org.springframework.http.codec.Pojo;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -28,10 +28,10 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests;
import org.springframework.core.testfixture.io.buffer.DataBufferTestUtils;
import org.springframework.http.codec.Pojo;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -39,10 +39,10 @@ import org.springframework.core.codec.DecodingException;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractDecoderTests;
import org.springframework.http.MediaType;
import org.springframework.http.codec.Pojo;
import org.springframework.http.codec.json.JacksonViewBean.MyJacksonView1;
import org.springframework.http.codec.json.JacksonViewBean.MyJacksonView3;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;

View File

@@ -36,12 +36,12 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.testfixture.codec.AbstractEncoderTests;
import org.springframework.http.MediaType;
import org.springframework.http.codec.Pojo;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.codec.json.JacksonViewBean.MyJacksonView1;
import org.springframework.http.codec.json.JacksonViewBean.MyJacksonView3;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.testfixture.xml.Pojo;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -27,9 +27,9 @@ import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractDecoderTests;
import org.springframework.http.codec.Pojo;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.ResolvableType.forClass;

View File

@@ -31,10 +31,10 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractEncoderTests;
import org.springframework.core.testfixture.io.buffer.DataBufferTestUtils;
import org.springframework.http.codec.Pojo;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.io.buffer.DataBufferUtils.release;

View File

@@ -40,9 +40,9 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.MediaType;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;

View File

@@ -42,9 +42,9 @@ import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.client.reactive.test.MockClientHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.testfixture.http.client.reactive.MockClientHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;

View File

@@ -32,13 +32,13 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests;
import org.springframework.http.MediaType;
import org.springframework.http.codec.Pojo;
import org.springframework.http.codec.xml.jaxb.XmlRootElement;
import org.springframework.http.codec.xml.jaxb.XmlRootElementWithName;
import org.springframework.http.codec.xml.jaxb.XmlRootElementWithNameAndNamespace;
import org.springframework.http.codec.xml.jaxb.XmlType;
import org.springframework.http.codec.xml.jaxb.XmlTypeWithName;
import org.springframework.http.codec.xml.jaxb.XmlTypeWithNameAndNamespace;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -33,7 +33,7 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractEncoderTests;
import org.springframework.core.testfixture.xml.XmlContent;
import org.springframework.http.MediaType;
import org.springframework.http.codec.Pojo;
import org.springframework.web.testfixture.xml.Pojo;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -31,8 +31,8 @@ import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

View File

@@ -28,8 +28,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -26,8 +26,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -1,137 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.server.reactive;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.time.Duration;
import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import reactor.core.publisher.Flux;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.http.server.reactive.bootstrap.JettyHttpServer;
import org.springframework.http.server.reactive.bootstrap.ReactorHttpServer;
import org.springframework.http.server.reactive.bootstrap.TomcatHttpServer;
import org.springframework.http.server.reactive.bootstrap.UndertowHttpServer;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpServerErrorException;
public abstract class AbstractHttpHandlerIntegrationTests {
/**
* Custom JUnit Jupiter extension that handles exceptions thrown by test methods.
*
* <p>If the test method throws an {@link HttpServerErrorException}, this
* extension will throw an {@link AssertionError} that wraps the
* {@code HttpServerErrorException} using the
* {@link HttpServerErrorException#getResponseBodyAsString() response body}
* as the failure message.
*
* <p>This mechanism provides an actually meaningful failure message if the
* test fails due to an {@code AssertionError} on the server.
*/
@RegisterExtension
TestExecutionExceptionHandler serverErrorToAssertionErrorConverter = (context, throwable) -> {
if (throwable instanceof HttpServerErrorException) {
HttpServerErrorException ex = (HttpServerErrorException) throwable;
String responseBody = ex.getResponseBodyAsString();
if (StringUtils.hasText(responseBody)) {
String prefix = AssertionError.class.getName() + ": ";
if (responseBody.startsWith(prefix)) {
responseBody = responseBody.substring(prefix.length());
}
throw new AssertionError(responseBody, ex);
}
}
// Else throw as-is in order to comply with the contract of TestExecutionExceptionHandler.
throw throwable;
};
protected final Log logger = LogFactory.getLog(getClass());
protected HttpServer server;
protected int port;
protected void startServer(HttpServer httpServer) throws Exception {
this.server = httpServer;
this.server.setHandler(createHttpHandler());
this.server.afterPropertiesSet();
this.server.start();
// Set dynamically chosen port
this.port = this.server.getPort();
}
@AfterEach
void stopServer() {
if (this.server != null) {
this.server.stop();
this.port = 0;
}
}
protected abstract HttpHandler createHttpHandler();
/**
* Return an interval stream of N number of ticks and buffer the emissions
* to avoid back pressure failures (e.g. on slow CI server).
*
* <p>Use this method as follows:
* <ul>
* <li>Tests that verify N number of items followed by verifyOnComplete()
* should set the number of emissions to N.
* <li>Tests that verify N number of items followed by thenCancel() should
* set the number of buffered to an arbitrary number greater than N.
* </ul>
*/
public static Flux<Long> testInterval(Duration period, int count) {
return Flux.interval(period).take(count).onBackpressureBuffer(count);
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ParameterizedTest(name = "[{index}] {0}")
@MethodSource("org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests#httpServers()")
// public for Kotlin
public @interface ParameterizedHttpServerTest {
}
static Stream<HttpServer> httpServers() {
return Stream.of(
new JettyHttpServer(),
new ReactorHttpServer(),
new TomcatHttpServer(),
new UndertowHttpServer()
);
}
}

View File

@@ -28,8 +28,9 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -27,8 +27,8 @@ import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

View File

@@ -27,8 +27,9 @@ import org.springframework.http.HttpCookie;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -23,8 +23,9 @@ import reactor.core.publisher.Mono;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -23,9 +23,10 @@ import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -25,7 +25,7 @@ import reactor.core.publisher.Flux;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.core.testfixture.io.buffer.LeakAwareDataBufferFactory;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -32,13 +32,14 @@ import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.FormFieldPart;
import org.springframework.http.codec.multipart.Part;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -28,8 +28,9 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -23,8 +23,9 @@ import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -29,11 +29,11 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.test.DelegatingServletInputStream;
import org.springframework.mock.web.test.MockAsyncContext;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.testfixture.servlet.DelegatingServletInputStream;
import org.springframework.web.testfixture.servlet.MockAsyncContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

View File

@@ -33,9 +33,9 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.http.server.reactive.bootstrap.ReactorHttpsServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.ReactorHttpsServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -26,8 +26,9 @@ import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -27,10 +27,11 @@ import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.ZeroCopyHttpOutputMessage;
import org.springframework.http.server.reactive.bootstrap.HttpServer;
import org.springframework.http.server.reactive.bootstrap.ReactorHttpServer;
import org.springframework.http.server.reactive.bootstrap.UndertowHttpServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.AbstractHttpHandlerIntegrationTests;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.ReactorHttpServer;
import org.springframework.web.testfixture.http.server.reactive.bootstrap.UndertowHttpServer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@@ -38,7 +39,9 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
/**
* @author Arjen Poutsma
*/
public class ZeroCopyIntegrationTests extends AbstractHttpHandlerIntegrationTests {
class ZeroCopyIntegrationTests extends AbstractHttpHandlerIntegrationTests {
private static final Resource springLogoResource = new ClassPathResource("/org/springframework/web/spring.png");
private final ZeroCopyHandler handler = new ZeroCopyHandler();
@@ -50,9 +53,9 @@ public class ZeroCopyIntegrationTests extends AbstractHttpHandlerIntegrationTest
@ParameterizedHttpServerTest
public void zeroCopy(HttpServer httpServer) throws Exception {
void zeroCopy(HttpServer httpServer) throws Exception {
assumeTrue(httpServer instanceof ReactorHttpServer || httpServer instanceof UndertowHttpServer,
"Zero-copy only does not support servlet");
"Zero-copy does not support Servlet");
startServer(httpServer);
@@ -60,11 +63,9 @@ public class ZeroCopyIntegrationTests extends AbstractHttpHandlerIntegrationTest
RequestEntity<?> request = RequestEntity.get(url).build();
ResponseEntity<byte[]> response = new RestTemplate().exchange(request, byte[].class);
Resource logo = new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class);
assertThat(response.hasBody()).isTrue();
assertThat(response.getHeaders().getContentLength()).isEqualTo(logo.contentLength());
assertThat(response.getBody().length).isEqualTo(logo.contentLength());
assertThat(response.getHeaders().getContentLength()).isEqualTo(springLogoResource.contentLength());
assertThat(response.getBody().length).isEqualTo(springLogoResource.contentLength());
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.IMAGE_PNG);
}
@@ -75,8 +76,7 @@ public class ZeroCopyIntegrationTests extends AbstractHttpHandlerIntegrationTest
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
try {
ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
Resource logo = new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class);
File logoFile = logo.getFile();
File logoFile = springLogoResource.getFile();
zeroCopyResponse.getHeaders().setContentType(MediaType.IMAGE_PNG);
zeroCopyResponse.getHeaders().setContentLength(logoFile.length());
return zeroCopyResponse.writeWith(logoFile, 0, logoFile.length());

View File

@@ -1,183 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.server.reactive.bootstrap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.util.Assert;
import org.springframework.util.StopWatch;
/**
* @author Rossen Stoyanchev
*/
public abstract class AbstractHttpServer implements HttpServer {
protected Log logger = LogFactory.getLog(getClass().getName());
private String host = "0.0.0.0";
private int port = 0;
private HttpHandler httpHandler;
private Map<String, HttpHandler> handlerMap;
private volatile boolean running;
private final Object lifecycleMonitor = new Object();
@Override
public void setHost(String host) {
this.host = host;
}
public String getHost() {
return host;
}
@Override
public void setPort(int port) {
this.port = port;
}
@Override
public int getPort() {
return this.port;
}
@Override
public void setHandler(HttpHandler handler) {
this.httpHandler = handler;
}
public HttpHandler getHttpHandler() {
return this.httpHandler;
}
public void registerHttpHandler(String contextPath, HttpHandler handler) {
if (this.handlerMap == null) {
this.handlerMap = new LinkedHashMap<>();
}
this.handlerMap.put(contextPath, handler);
}
public Map<String, HttpHandler> getHttpHandlerMap() {
return this.handlerMap;
}
protected HttpHandler resolveHttpHandler() {
return (getHttpHandlerMap() != null ?
new ContextPathCompositeHandler(getHttpHandlerMap()) : getHttpHandler());
}
// InitializingBean
@Override
public final void afterPropertiesSet() throws Exception {
Assert.notNull(this.host, "Host must not be null");
Assert.isTrue(this.port >= 0, "Port must not be a negative number");
Assert.isTrue(this.httpHandler != null || this.handlerMap != null, "No HttpHandler configured");
Assert.state(!this.running, "Cannot reconfigure while running");
synchronized (this.lifecycleMonitor) {
initServer();
}
}
protected abstract void initServer() throws Exception;
// Lifecycle
@Override
public final void start() {
synchronized (this.lifecycleMonitor) {
if (!isRunning()) {
String serverName = getClass().getSimpleName();
if (logger.isDebugEnabled()) {
logger.debug("Starting " + serverName + "...");
}
this.running = true;
try {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
startInternal();
long millis = stopWatch.getTotalTimeMillis();
if (logger.isDebugEnabled()) {
logger.debug("Server started on port " + getPort() + "(" + millis + " millis).");
}
}
catch (Throwable ex) {
throw new IllegalStateException(ex);
}
}
}
}
protected abstract void startInternal() throws Exception;
@Override
public final void stop() {
synchronized (this.lifecycleMonitor) {
if (isRunning()) {
String serverName = getClass().getSimpleName();
logger.debug("Stopping " + serverName + "...");
this.running = false;
try {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
stopInternal();
logger.debug("Server stopped (" + stopWatch.getTotalTimeMillis() + " millis).");
}
catch (Throwable ex) {
throw new IllegalStateException(ex);
}
finally {
reset();
}
}
}
}
protected abstract void stopInternal() throws Exception;
@Override
public boolean isRunning() {
return this.running;
}
private void reset() {
this.host = "0.0.0.0";
this.port = 0;
this.httpHandler = null;
this.handlerMap = null;
resetInternal();
}
protected abstract void resetInternal();
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2002-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
*
* https://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.http.server.reactive.bootstrap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.Lifecycle;
import org.springframework.http.server.reactive.HttpHandler;
/**
* @author Rossen Stoyanchev
*/
public interface HttpServer extends InitializingBean, Lifecycle {
void setHost(String host);
void setPort(int port);
int getPort();
void setHandler(HttpHandler handler);
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright 2002-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
*
* https://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.http.server.reactive.bootstrap;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.http.server.reactive.JettyHttpHandlerAdapter;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
/**
* @author Rossen Stoyanchev
*/
public class JettyHttpServer extends AbstractHttpServer {
private Server jettyServer;
private ServletContextHandler contextHandler;
@Override
protected void initServer() throws Exception {
this.jettyServer = new Server();
ServletHttpHandlerAdapter servlet = createServletAdapter();
ServletHolder servletHolder = new ServletHolder(servlet);
servletHolder.setAsyncSupported(true);
this.contextHandler = new ServletContextHandler(this.jettyServer, "", false, false);
this.contextHandler.addServlet(servletHolder, "/");
this.contextHandler.start();
ServerConnector connector = new ServerConnector(this.jettyServer);
connector.setHost(getHost());
connector.setPort(getPort());
this.jettyServer.addConnector(connector);
}
private ServletHttpHandlerAdapter createServletAdapter() {
return new JettyHttpHandlerAdapter(resolveHttpHandler());
}
@Override
protected void startInternal() throws Exception {
this.jettyServer.start();
setPort(((ServerConnector) this.jettyServer.getConnectors()[0]).getLocalPort());
}
@Override
protected void stopInternal() throws Exception {
try {
if (this.contextHandler.isRunning()) {
this.contextHandler.stop();
}
}
finally {
try {
if (this.jettyServer.isRunning()) {
this.jettyServer.setStopTimeout(5000);
this.jettyServer.stop();
this.jettyServer.destroy();
}
}
catch (Exception ex) {
// ignore
}
}
}
@Override
protected void resetInternal() {
try {
if (this.jettyServer.isRunning()) {
this.jettyServer.setStopTimeout(5000);
this.jettyServer.stop();
this.jettyServer.destroy();
}
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
finally {
this.jettyServer = null;
this.contextHandler = null;
}
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.server.reactive.bootstrap;
import java.util.concurrent.atomic.AtomicReference;
import reactor.netty.DisposableServer;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
/**
* @author Stephane Maldini
*/
public class ReactorHttpServer extends AbstractHttpServer {
private ReactorHttpHandlerAdapter reactorHandler;
private reactor.netty.http.server.HttpServer reactorServer;
private AtomicReference<DisposableServer> serverRef = new AtomicReference<>();
@Override
protected void initServer() {
this.reactorHandler = createHttpHandlerAdapter();
this.reactorServer = reactor.netty.http.server.HttpServer.create()
.tcpConfiguration(server -> server.host(getHost()))
.port(getPort());
}
private ReactorHttpHandlerAdapter createHttpHandlerAdapter() {
return new ReactorHttpHandlerAdapter(resolveHttpHandler());
}
@Override
protected void startInternal() {
DisposableServer server = this.reactorServer.handle(this.reactorHandler).bind().block();
setPort(server.address().getPort());
this.serverRef.set(server);
}
@Override
protected void stopInternal() {
this.serverRef.get().dispose();
}
@Override
protected void resetInternal() {
this.reactorServer = null;
this.reactorHandler = null;
this.serverRef.set(null);
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.http.server.reactive.bootstrap;
import java.util.concurrent.atomic.AtomicReference;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import reactor.netty.DisposableServer;
import reactor.netty.tcp.SslProvider.DefaultConfigurationType;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
/**
* @author Stephane Maldini
*/
public class ReactorHttpsServer extends AbstractHttpServer {
private ReactorHttpHandlerAdapter reactorHandler;
private reactor.netty.http.server.HttpServer reactorServer;
private AtomicReference<DisposableServer> serverRef = new AtomicReference<>();
@Override
protected void initServer() throws Exception {
SelfSignedCertificate cert = new SelfSignedCertificate();
SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey());
this.reactorHandler = createHttpHandlerAdapter();
this.reactorServer = reactor.netty.http.server.HttpServer.create()
.host(getHost())
.port(getPort())
.secure(spec -> spec.sslContext(builder).defaultConfiguration(DefaultConfigurationType.TCP));
}
private ReactorHttpHandlerAdapter createHttpHandlerAdapter() {
return new ReactorHttpHandlerAdapter(resolveHttpHandler());
}
@Override
protected void startInternal() {
DisposableServer server = this.reactorServer.handle(this.reactorHandler).bind().block();
setPort(server.address().getPort());
this.serverRef.set(server);
}
@Override
protected void stopInternal() {
this.serverRef.get().dispose();
}
@Override
protected void resetInternal() {
this.reactorServer = null;
this.reactorHandler = null;
this.serverRef.set(null);
}
}

View File

@@ -1,114 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.http.server.reactive.bootstrap;
import java.io.File;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
import org.springframework.http.server.reactive.TomcatHttpHandlerAdapter;
import org.springframework.util.Assert;
/**
* @author Rossen Stoyanchev
*/
public class TomcatHttpServer extends AbstractHttpServer {
private final String baseDir;
private final Class<?> wsListener;
private String contextPath = "";
private String servletMapping = "/";
private Tomcat tomcatServer;
/**
* Create a new Tomcat HTTP server using the {@code java.io.tmpdir} JVM
* system property as the {@code baseDir}.
* @since 5.2
*/
public TomcatHttpServer() {
this(new File(System.getProperty("java.io.tmpdir")).getAbsolutePath());
}
public TomcatHttpServer(String baseDir) {
this(baseDir, null);
}
public TomcatHttpServer(String baseDir, Class<?> wsListener) {
Assert.notNull(baseDir, "Base dir must not be null");
this.baseDir = baseDir;
this.wsListener = wsListener;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public void setServletMapping(String servletMapping) {
this.servletMapping = servletMapping;
}
@Override
protected void initServer() throws Exception {
this.tomcatServer = new Tomcat();
this.tomcatServer.setBaseDir(baseDir);
this.tomcatServer.setHostname(getHost());
this.tomcatServer.setPort(getPort());
ServletHttpHandlerAdapter servlet = initServletAdapter();
File base = new File(System.getProperty("java.io.tmpdir"));
Context rootContext = tomcatServer.addContext(this.contextPath, base.getAbsolutePath());
Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet).setAsyncSupported(true);
rootContext.addServletMappingDecoded(this.servletMapping, "httpHandlerServlet");
if (wsListener != null) {
rootContext.addApplicationListener(wsListener.getName());
}
}
private ServletHttpHandlerAdapter initServletAdapter() {
return new TomcatHttpHandlerAdapter(resolveHttpHandler());
}
@Override
protected void startInternal() throws LifecycleException {
this.tomcatServer.start();
setPort(this.tomcatServer.getConnector().getLocalPort());
}
@Override
protected void stopInternal() throws Exception {
this.tomcatServer.stop();
this.tomcatServer.destroy();
}
@Override
protected void resetInternal() {
this.tomcatServer = null;
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2002-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
*
* https://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.http.server.reactive.bootstrap;
import java.net.InetSocketAddress;
import io.undertow.Undertow;
import org.springframework.http.server.reactive.UndertowHttpHandlerAdapter;
/**
* @author Marek Hawrylczak
*/
public class UndertowHttpServer extends AbstractHttpServer {
private Undertow server;
@Override
protected void initServer() throws Exception {
this.server = Undertow.builder().addHttpListener(getPort(), getHost())
.setHandler(initHttpHandlerAdapter())
.build();
}
private UndertowHttpHandlerAdapter initHttpHandlerAdapter() {
return new UndertowHttpHandlerAdapter(resolveHttpHandler());
}
@Override
protected void startInternal() {
this.server.start();
Undertow.ListenerInfo info = this.server.getListenerInfo().get(0);
setPort(((InetSocketAddress) info.getAddress()).getPort());
}
@Override
protected void stopInternal() {
this.server.stop();
}
@Override
protected void resetInternal() {
this.server = null;
}
}

View File

@@ -1,5 +0,0 @@
/**
* This package contains temporary interfaces and classes for running embedded servers.
* They are expected to be replaced by an upcoming Spring Boot support.
*/
package org.springframework.http.server.reactive.bootstrap;

View File

@@ -1,168 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.http.client.reactive.test;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Function;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.AbstractClientHttpRequest;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Mock implementation of {@link ClientHttpRequest}.
*
* @author Brian Clozel
* @author Rossen Stoyanchev
* @since 5.0
*/
public class MockClientHttpRequest extends AbstractClientHttpRequest {
private HttpMethod httpMethod;
private URI url;
private final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
private Flux<DataBuffer> body = Flux.error(
new IllegalStateException("The body is not set. " +
"Did handling complete with success? Is a custom \"writeHandler\" configured?"));
private Function<Flux<DataBuffer>, Mono<Void>> writeHandler;
public MockClientHttpRequest(HttpMethod httpMethod, String urlTemplate, Object... vars) {
this(httpMethod, UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri());
}
public MockClientHttpRequest(HttpMethod httpMethod, URI url) {
this.httpMethod = httpMethod;
this.url = url;
this.writeHandler = body -> {
this.body = body.cache();
return this.body.then();
};
}
/**
* Configure a custom handler for writing the request body.
*
* <p>The default write handler consumes and caches the request body so it
* may be accessed subsequently, e.g. in test assertions. Use this property
* when the request body is an infinite stream.
*
* @param writeHandler the write handler to use returning {@code Mono<Void>}
* when the body has been "written" (i.e. consumed).
*/
public void setWriteHandler(Function<Flux<DataBuffer>, Mono<Void>> writeHandler) {
Assert.notNull(writeHandler, "'writeHandler' is required");
this.writeHandler = writeHandler;
}
@Override
public HttpMethod getMethod() {
return this.httpMethod;
}
@Override
public URI getURI() {
return this.url;
}
@Override
public DataBufferFactory bufferFactory() {
return this.bufferFactory;
}
@Override
protected void applyHeaders() {
}
@Override
protected void applyCookies() {
getCookies().values().stream().flatMap(Collection::stream)
.forEach(cookie -> getHeaders().add(HttpHeaders.COOKIE, cookie.toString()));
}
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
return doCommit(() -> Mono.defer(() -> this.writeHandler.apply(Flux.from(body))));
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return writeWith(Flux.from(body).flatMap(p -> p));
}
@Override
public Mono<Void> setComplete() {
return writeWith(Flux.empty());
}
/**
* Return the request body, or an error stream if the body was never set
* or when {@link #setWriteHandler} is configured.
*/
public Flux<DataBuffer> getBody() {
return this.body;
}
/**
* Aggregate response data and convert to a String using the "Content-Type"
* charset or "UTF-8" by default.
*/
public Mono<String> getBodyAsString() {
Charset charset = Optional.ofNullable(getHeaders().getContentType()).map(MimeType::getCharset)
.orElse(StandardCharsets.UTF_8);
return getBody()
.reduce(bufferFactory().allocateBuffer(), (previous, current) -> {
previous.write(current);
DataBufferUtils.release(current);
return previous;
})
.map(buffer -> bufferToString(buffer, charset));
}
private static String bufferToString(DataBuffer buffer, Charset charset) {
Assert.notNull(charset, "'charset' must not be null");
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
return new String(bytes, charset);
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.http.client.reactive.test;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie;
import org.springframework.http.client.reactive.ClientHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* Mock implementation of {@link ClientHttpResponse}.
*
* @author Brian Clozel
* @author Rossen Stoyanchev
* @since 5.0
*/
public class MockClientHttpResponse implements ClientHttpResponse {
private final int status;
private final HttpHeaders headers = new HttpHeaders();
private final MultiValueMap<String, ResponseCookie> cookies = new LinkedMultiValueMap<>();
private Flux<DataBuffer> body = Flux.empty();
private final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
public MockClientHttpResponse(HttpStatus status) {
Assert.notNull(status, "HttpStatus is required");
this.status = status.value();
}
public MockClientHttpResponse(int status) {
Assert.isTrue(status > 99 && status < 1000, "Status must be between 100 and 999");
this.status = status;
}
@Override
public HttpStatus getStatusCode() {
return HttpStatus.valueOf(this.status);
}
@Override
public int getRawStatusCode() {
return this.status;
}
@Override
public HttpHeaders getHeaders() {
if (!getCookies().isEmpty() && this.headers.get(HttpHeaders.SET_COOKIE) == null) {
getCookies().values().stream().flatMap(Collection::stream)
.forEach(cookie -> getHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString()));
}
return this.headers;
}
@Override
public MultiValueMap<String, ResponseCookie> getCookies() {
return this.cookies;
}
public void setBody(Publisher<DataBuffer> body) {
this.body = Flux.from(body);
}
public void setBody(String body) {
setBody(body, StandardCharsets.UTF_8);
}
public void setBody(String body, Charset charset) {
DataBuffer buffer = toDataBuffer(body, charset);
this.body = Flux.just(buffer);
}
private DataBuffer toDataBuffer(String body, Charset charset) {
byte[] bytes = body.getBytes(charset);
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
return this.bufferFactory.wrap(byteBuffer);
}
@Override
public Flux<DataBuffer> getBody() {
return this.body;
}
/**
* Return the response body aggregated and converted to a String using the
* charset of the Content-Type response or otherwise as "UTF-8".
*/
public Mono<String> getBodyAsString() {
Charset charset = getCharset();
return Flux.from(getBody())
.reduce(this.bufferFactory.allocateBuffer(), (previous, current) -> {
previous.write(current);
DataBufferUtils.release(current);
return previous;
})
.map(buffer -> dumpString(buffer, charset));
}
private static String dumpString(DataBuffer buffer, Charset charset) {
Assert.notNull(charset, "'charset' must not be null");
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
return new String(bytes, charset);
}
private Charset getCharset() {
Charset charset = null;
MediaType contentType = getHeaders().getContentType();
if (contentType != null) {
charset = contentType.getCharset();
}
return (charset != null ? charset : StandardCharsets.UTF_8);
}
@Override
public String toString() {
HttpStatus code = HttpStatus.resolve(this.status);
return (code != null ? code.name() + "(" + this.status + ")" : "Status (" + this.status + ")") + this.headers;
}
}

View File

@@ -1,595 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.http.server.reactive.test;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRange;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.AbstractServerHttpRequest;
import org.springframework.http.server.reactive.SslInfo;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MimeType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Mock extension of {@link AbstractServerHttpRequest} for use in tests without
* an actual server. Use the static methods to obtain a builder.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public final class MockServerHttpRequest extends AbstractServerHttpRequest {
private final HttpMethod httpMethod;
private final MultiValueMap<String, HttpCookie> cookies;
@Nullable
private final InetSocketAddress remoteAddress;
@Nullable
private final InetSocketAddress localAddress;
@Nullable
private final SslInfo sslInfo;
private final Flux<DataBuffer> body;
private MockServerHttpRequest(HttpMethod httpMethod, URI uri, @Nullable String contextPath,
HttpHeaders headers, MultiValueMap<String, HttpCookie> cookies,
@Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress,
@Nullable SslInfo sslInfo, Publisher<? extends DataBuffer> body) {
super(uri, contextPath, headers);
this.httpMethod = httpMethod;
this.cookies = cookies;
this.remoteAddress = remoteAddress;
this.localAddress = localAddress;
this.sslInfo = sslInfo;
this.body = Flux.from(body);
}
@Override
public HttpMethod getMethod() {
return this.httpMethod;
}
@Override
public String getMethodValue() {
return this.httpMethod.name();
}
@Override
@Nullable
public InetSocketAddress getRemoteAddress() {
return this.remoteAddress;
}
@Nullable
@Override
public InetSocketAddress getLocalAddress() {
return this.localAddress;
}
@Nullable
@Override
protected SslInfo initSslInfo() {
return this.sslInfo;
}
@Override
public Flux<DataBuffer> getBody() {
return this.body;
}
@Override
protected MultiValueMap<String, HttpCookie> initCookies() {
return this.cookies;
}
@Override
public <T> T getNativeRequest() {
throw new IllegalStateException("This is a mock. No running server, no native request.");
}
// Static builder methods
/**
* Create a builder with the given HTTP method and a {@link URI}.
* @param method the HTTP method (GET, POST, etc)
* @param url the URL
* @return the created builder
*/
public static BodyBuilder method(HttpMethod method, URI url) {
return new DefaultBodyBuilder(method, url);
}
/**
* Alternative to {@link #method(HttpMethod, URI)} that accepts a URI template.
* The given URI may contain query parameters, or those may be added later via
* {@link BaseBuilder#queryParam queryParam} builder methods.
* @param method the HTTP method (GET, POST, etc)
* @param urlTemplate the URL template
* @param vars variables to expand into the template
* @return the created builder
*/
public static BodyBuilder method(HttpMethod method, String urlTemplate, Object... vars) {
URI url = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(vars).encode().toUri();
return new DefaultBodyBuilder(method, url);
}
/**
* Create an HTTP GET builder with the given URI template. The given URI may
* contain query parameters, or those may be added later via
* {@link BaseBuilder#queryParam queryParam} builder methods.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BaseBuilder<?> get(String urlTemplate, Object... uriVars) {
return method(HttpMethod.GET, urlTemplate, uriVars);
}
/**
* HTTP HEAD variant. See {@link #get(String, Object...)} for general info.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BaseBuilder<?> head(String urlTemplate, Object... uriVars) {
return method(HttpMethod.HEAD, urlTemplate, uriVars);
}
/**
* HTTP POST variant. See {@link #get(String, Object...)} for general info.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BodyBuilder post(String urlTemplate, Object... uriVars) {
return method(HttpMethod.POST, urlTemplate, uriVars);
}
/**
* HTTP PUT variant. See {@link #get(String, Object...)} for general info.
* {@link BaseBuilder#queryParam queryParam} builder methods.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BodyBuilder put(String urlTemplate, Object... uriVars) {
return method(HttpMethod.PUT, urlTemplate, uriVars);
}
/**
* HTTP PATCH variant. See {@link #get(String, Object...)} for general info.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BodyBuilder patch(String urlTemplate, Object... uriVars) {
return method(HttpMethod.PATCH, urlTemplate, uriVars);
}
/**
* HTTP DELETE variant. See {@link #get(String, Object...)} for general info.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BaseBuilder<?> delete(String urlTemplate, Object... uriVars) {
return method(HttpMethod.DELETE, urlTemplate, uriVars);
}
/**
* HTTP OPTIONS variant. See {@link #get(String, Object...)} for general info.
* @param urlTemplate a URL template; the resulting URL will be encoded
* @param uriVars zero or more URI variables
* @return the created builder
*/
public static BaseBuilder<?> options(String urlTemplate, Object... uriVars) {
return method(HttpMethod.OPTIONS, urlTemplate, uriVars);
}
/**
* Request builder exposing properties not related to the body.
* @param <B> the builder sub-class
*/
public interface BaseBuilder<B extends BaseBuilder<B>> {
/**
* Set the contextPath to return.
*/
B contextPath(String contextPath);
/**
* Append the given query parameter to the existing query parameters.
* If no values are given, the resulting URI will contain the query
* parameter name only (i.e. {@code ?foo} instead of {@code ?foo=bar}).
* <p>The provided query name and values will be encoded.
* @param name the query parameter name
* @param values the query parameter values
* @return this UriComponentsBuilder
*/
B queryParam(String name, Object... values);
/**
* Add the given query parameters and values. The provided query name
* and corresponding values will be encoded.
* @param params the params
* @return this UriComponentsBuilder
*/
B queryParams(MultiValueMap<String, String> params);
/**
* Set the remote address to return.
*/
B remoteAddress(InetSocketAddress remoteAddress);
/**
* Set the local address to return.
* @since 5.2.3
*/
B localAddress(InetSocketAddress localAddress);
/**
* Set SSL session information and certificates.
*/
void sslInfo(SslInfo sslInfo);
/**
* Add one or more cookies.
*/
B cookie(HttpCookie... cookie);
/**
* Add the given cookies.
* @param cookies the cookies.
*/
B cookies(MultiValueMap<String, HttpCookie> cookies);
/**
* Add the given, single header value under the given name.
* @param headerName the header name
* @param headerValues the header value(s)
* @see HttpHeaders#add(String, String)
*/
B header(String headerName, String... headerValues);
/**
* Add the given header values.
* @param headers the header values
*/
B headers(MultiValueMap<String, String> headers);
/**
* Set the list of acceptable {@linkplain MediaType media types}, as
* specified by the {@code Accept} header.
* @param acceptableMediaTypes the acceptable media types
*/
B accept(MediaType... acceptableMediaTypes);
/**
* Set the list of acceptable {@linkplain Charset charsets}, as specified
* by the {@code Accept-Charset} header.
* @param acceptableCharsets the acceptable charsets
*/
B acceptCharset(Charset... acceptableCharsets);
/**
* Set the list of acceptable {@linkplain Locale locales}, as specified
* by the {@code Accept-Languages} header.
* @param acceptableLocales the acceptable locales
*/
B acceptLanguageAsLocales(Locale... acceptableLocales);
/**
* Set the value of the {@code If-Modified-Since} header.
* <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
* @param ifModifiedSince the new value of the header
*/
B ifModifiedSince(long ifModifiedSince);
/**
* Set the (new) value of the {@code If-Unmodified-Since} header.
* <p>The date should be specified as the number of milliseconds since
* January 1, 1970 GMT.
* @param ifUnmodifiedSince the new value of the header
* @see HttpHeaders#setIfUnmodifiedSince(long)
*/
B ifUnmodifiedSince(long ifUnmodifiedSince);
/**
* Set the values of the {@code If-None-Match} header.
* @param ifNoneMatches the new value of the header
*/
B ifNoneMatch(String... ifNoneMatches);
/**
* Set the (new) value of the Range header.
* @param ranges the HTTP ranges
* @see HttpHeaders#setRange(List)
*/
B range(HttpRange... ranges);
/**
* Builds the request with no body.
* @return the request
* @see BodyBuilder#body(Publisher)
* @see BodyBuilder#body(String)
*/
MockServerHttpRequest build();
}
/**
* A builder that adds a body to the request.
*/
public interface BodyBuilder extends BaseBuilder<BodyBuilder> {
/**
* Set the length of the body in bytes, as specified by the
* {@code Content-Length} header.
* @param contentLength the content length
* @return this builder
* @see HttpHeaders#setContentLength(long)
*/
BodyBuilder contentLength(long contentLength);
/**
* Set the {@linkplain MediaType media type} of the body, as specified
* by the {@code Content-Type} header.
* @param contentType the content type
* @return this builder
* @see HttpHeaders#setContentType(MediaType)
*/
BodyBuilder contentType(MediaType contentType);
/**
* Set the body of the request and build it.
* @param body the body
* @return the built request entity
*/
MockServerHttpRequest body(Publisher<? extends DataBuffer> body);
/**
* Set the body of the request and build it.
* <p>The String is assumed to be UTF-8 encoded unless the request has a
* "content-type" header with a charset attribute.
* @param body the body as text
* @return the built request entity
*/
MockServerHttpRequest body(String body);
}
private static class DefaultBodyBuilder implements BodyBuilder {
private static final DataBufferFactory BUFFER_FACTORY = new DefaultDataBufferFactory();
private final HttpMethod method;
private final URI url;
@Nullable
private String contextPath;
private final UriComponentsBuilder queryParamsBuilder = UriComponentsBuilder.newInstance();
private final HttpHeaders headers = new HttpHeaders();
private final MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();
@Nullable
private InetSocketAddress remoteAddress;
@Nullable
private InetSocketAddress localAddress;
@Nullable
private SslInfo sslInfo;
public DefaultBodyBuilder(HttpMethod method, URI url) {
this.method = method;
this.url = url;
}
@Override
public BodyBuilder contextPath(String contextPath) {
this.contextPath = contextPath;
return this;
}
@Override
public BodyBuilder queryParam(String name, Object... values) {
this.queryParamsBuilder.queryParam(name, values);
return this;
}
@Override
public BodyBuilder queryParams(MultiValueMap<String, String> params) {
this.queryParamsBuilder.queryParams(params);
return this;
}
@Override
public BodyBuilder remoteAddress(InetSocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
@Override
public BodyBuilder localAddress(InetSocketAddress localAddress) {
this.localAddress = localAddress;
return this;
}
@Override
public void sslInfo(SslInfo sslInfo) {
this.sslInfo = sslInfo;
}
@Override
public BodyBuilder cookie(HttpCookie... cookies) {
Arrays.stream(cookies).forEach(cookie -> this.cookies.add(cookie.getName(), cookie));
return this;
}
@Override
public BodyBuilder cookies(MultiValueMap<String, HttpCookie> cookies) {
this.cookies.putAll(cookies);
return this;
}
@Override
public BodyBuilder header(String headerName, String... headerValues) {
for (String headerValue : headerValues) {
this.headers.add(headerName, headerValue);
}
return this;
}
@Override
public BodyBuilder headers(MultiValueMap<String, String> headers) {
this.headers.putAll(headers);
return this;
}
@Override
public BodyBuilder accept(MediaType... acceptableMediaTypes) {
this.headers.setAccept(Arrays.asList(acceptableMediaTypes));
return this;
}
@Override
public BodyBuilder acceptCharset(Charset... acceptableCharsets) {
this.headers.setAcceptCharset(Arrays.asList(acceptableCharsets));
return this;
}
@Override
public BodyBuilder acceptLanguageAsLocales(Locale... acceptableLocales) {
this.headers.setAcceptLanguageAsLocales(Arrays.asList(acceptableLocales));
return this;
}
@Override
public BodyBuilder contentLength(long contentLength) {
this.headers.setContentLength(contentLength);
return this;
}
@Override
public BodyBuilder contentType(MediaType contentType) {
this.headers.setContentType(contentType);
return this;
}
@Override
public BodyBuilder ifModifiedSince(long ifModifiedSince) {
this.headers.setIfModifiedSince(ifModifiedSince);
return this;
}
@Override
public BodyBuilder ifUnmodifiedSince(long ifUnmodifiedSince) {
this.headers.setIfUnmodifiedSince(ifUnmodifiedSince);
return this;
}
@Override
public BodyBuilder ifNoneMatch(String... ifNoneMatches) {
this.headers.setIfNoneMatch(Arrays.asList(ifNoneMatches));
return this;
}
@Override
public BodyBuilder range(HttpRange... ranges) {
this.headers.setRange(Arrays.asList(ranges));
return this;
}
@Override
public MockServerHttpRequest build() {
return body(Flux.empty());
}
@Override
public MockServerHttpRequest body(String body) {
return body(Flux.just(BUFFER_FACTORY.wrap(body.getBytes(getCharset()))));
}
private Charset getCharset() {
return Optional.ofNullable(this.headers.getContentType())
.map(MimeType::getCharset).orElse(StandardCharsets.UTF_8);
}
@Override
public MockServerHttpRequest body(Publisher<? extends DataBuffer> body) {
applyCookiesIfNecessary();
return new MockServerHttpRequest(this.method, getUrlToUse(), this.contextPath,
this.headers, this.cookies, this.remoteAddress, this.localAddress, this.sslInfo, body);
}
private void applyCookiesIfNecessary() {
if (this.headers.get(HttpHeaders.COOKIE) == null) {
this.cookies.values().stream().flatMap(Collection::stream)
.forEach(cookie -> this.headers.add(HttpHeaders.COOKIE, cookie.toString()));
}
}
private URI getUrlToUse() {
MultiValueMap<String, String> params =
this.queryParamsBuilder.buildAndExpand().encode().getQueryParams();
if (!params.isEmpty()) {
return UriComponentsBuilder.fromUri(this.url).queryParams(params).build(true).toUri();
}
return this.url;
}
}
}

View File

@@ -1,162 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.http.server.reactive.test;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoProcessor;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
/**
* Mock extension of {@link AbstractServerHttpResponse} for use in tests without
* an actual server.
*
* <p>By default response content is consumed in full upon writing and cached
* for subsequent access, however it is also possible to set a custom
* {@link #setWriteHandler(Function) writeHandler}.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class MockServerHttpResponse extends AbstractServerHttpResponse {
private Flux<DataBuffer> body = Flux.error(new IllegalStateException(
"No content was written nor was setComplete() called on this response."));
private Function<Flux<DataBuffer>, Mono<Void>> writeHandler;
public MockServerHttpResponse() {
this(new DefaultDataBufferFactory());
}
public MockServerHttpResponse(DataBufferFactory dataBufferFactory) {
super(dataBufferFactory);
this.writeHandler = body -> {
// Avoid .then() which causes data buffers to be released
MonoProcessor<Void> completion = MonoProcessor.create();
this.body = body.doOnComplete(completion::onComplete).doOnError(completion::onError).cache();
this.body.subscribe();
return completion;
};
}
/**
* Configure a custom handler to consume the response body.
* <p>By default, response body content is consumed in full and cached for
* subsequent access in tests. Use this option to take control over how the
* response body is consumed.
* @param writeHandler the write handler to use returning {@code Mono<Void>}
* when the body has been "written" (i.e. consumed).
*/
public void setWriteHandler(Function<Flux<DataBuffer>, Mono<Void>> writeHandler) {
Assert.notNull(writeHandler, "'writeHandler' is required");
this.body = Flux.error(new IllegalStateException("Not available with custom write handler."));
this.writeHandler = writeHandler;
}
@Override
public <T> T getNativeResponse() {
throw new IllegalStateException("This is a mock. No running server, no native response.");
}
@Override
protected void applyStatusCode() {
}
@Override
protected void applyHeaders() {
}
@Override
protected void applyCookies() {
for (List<ResponseCookie> cookies : getCookies().values()) {
for (ResponseCookie cookie : cookies) {
getHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString());
}
}
}
@Override
protected Mono<Void> writeWithInternal(Publisher<? extends DataBuffer> body) {
return this.writeHandler.apply(Flux.from(body));
}
@Override
protected Mono<Void> writeAndFlushWithInternal(
Publisher<? extends Publisher<? extends DataBuffer>> body) {
return this.writeHandler.apply(Flux.from(body).concatMap(Flux::from));
}
@Override
public Mono<Void> setComplete() {
return doCommit(() -> Mono.defer(() -> this.writeHandler.apply(Flux.empty())));
}
/**
* Return the response body or an error stream if the body was not set.
*/
public Flux<DataBuffer> getBody() {
return this.body;
}
/**
* Aggregate response data and convert to a String using the "Content-Type"
* charset or "UTF-8" by default.
*/
public Mono<String> getBodyAsString() {
Charset charset = Optional.ofNullable(getHeaders().getContentType()).map(MimeType::getCharset)
.orElse(StandardCharsets.UTF_8);
return getBody()
.reduce(bufferFactory().allocateBuffer(), (previous, current) -> {
previous.write(current);
DataBufferUtils.release(current);
return previous;
})
.map(buffer -> bufferToString(buffer, charset));
}
private static String bufferToString(DataBuffer buffer, Charset charset) {
Assert.notNull(charset, "'charset' must not be null");
byte[] bytes = new byte[buffer.readableByteCount()];
buffer.read(bytes);
DataBufferUtils.release(buffer);
return new String(bytes, charset);
}
}

View File

@@ -1,9 +0,0 @@
/**
* For @NonNull annotations on implementation classes
*/
@NonNullApi
@NonNullFields
package org.springframework.mock.http.server.reactive.test;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,96 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import org.springframework.util.Assert;
/**
* Delegating implementation of {@link javax.servlet.ServletInputStream}.
*
* <p>Used by {@link MockHttpServletRequest}; typically not directly
* used for testing application controllers.
*
* @author Juergen Hoeller
* @since 1.0.2
* @see MockHttpServletRequest
*/
public class DelegatingServletInputStream extends ServletInputStream {
private final InputStream sourceStream;
private boolean finished = false;
/**
* Create a DelegatingServletInputStream for the given source stream.
* @param sourceStream the source stream (never {@code null})
*/
public DelegatingServletInputStream(InputStream sourceStream) {
Assert.notNull(sourceStream, "Source InputStream must not be null");
this.sourceStream = sourceStream;
}
/**
* Return the underlying source stream (never {@code null}).
*/
public final InputStream getSourceStream() {
return this.sourceStream;
}
@Override
public int read() throws IOException {
int data = this.sourceStream.read();
if (data == -1) {
this.finished = true;
}
return data;
}
@Override
public int available() throws IOException {
return this.sourceStream.available();
}
@Override
public void close() throws IOException {
super.close();
this.sourceStream.close();
}
@Override
public boolean isFinished() {
return this.finished;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
throw new UnsupportedOperationException();
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2002-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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import org.springframework.util.Assert;
/**
* Delegating implementation of {@link javax.servlet.ServletOutputStream}.
*
* <p>Used by {@link MockHttpServletResponse}; typically not directly
* used for testing application controllers.
*
* @author Juergen Hoeller
* @since 1.0.2
* @see MockHttpServletResponse
*/
public class DelegatingServletOutputStream extends ServletOutputStream {
private final OutputStream targetStream;
/**
* Create a DelegatingServletOutputStream for the given target stream.
* @param targetStream the target stream (never {@code null})
*/
public DelegatingServletOutputStream(OutputStream targetStream) {
Assert.notNull(targetStream, "Target OutputStream must not be null");
this.targetStream = targetStream;
}
/**
* Return the underlying target stream (never {@code null}).
*/
public final OutputStream getTargetStream() {
return this.targetStream;
}
@Override
public void write(int b) throws IOException {
this.targetStream.write(b);
}
@Override
public void flush() throws IOException {
super.flush();
this.targetStream.flush();
}
@Override
public void close() throws IOException {
super.close();
this.targetStream.close();
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {
throw new UnsupportedOperationException();
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Internal helper class that serves as value holder for request headers.
*
* @author Juergen Hoeller
* @author Rick Evans
* @since 2.0.1
*/
class HeaderValueHolder {
private final List<Object> values = new LinkedList<>();
public void setValue(@Nullable Object value) {
this.values.clear();
if (value != null) {
this.values.add(value);
}
}
public void addValue(Object value) {
this.values.add(value);
}
public void addValues(Collection<?> values) {
this.values.addAll(values);
}
public void addValueArray(Object values) {
CollectionUtils.mergeArrayIntoCollection(values, this.values);
}
public List<Object> getValues() {
return Collections.unmodifiableList(this.values);
}
public List<String> getStringValues() {
List<String> stringList = new ArrayList<>(this.values.size());
for (Object value : this.values) {
stringList.add(value.toString());
}
return Collections.unmodifiableList(stringList);
}
@Nullable
public Object getValue() {
return (!this.values.isEmpty() ? this.values.get(0) : null);
}
@Nullable
public String getStringValue() {
return (!this.values.isEmpty() ? String.valueOf(this.values.get(0)) : null);
}
@Override
public String toString() {
return this.values.toString();
}
/**
* Find a HeaderValueHolder by name, ignoring casing.
* @param headers the Map of header names to HeaderValueHolders
* @param name the name of the desired header
* @return the corresponding HeaderValueHolder, or {@code null} if none found
*/
@Nullable
public static HeaderValueHolder getByName(Map<String, HeaderValueHolder> headers, String name) {
Assert.notNull(name, "Header name must not be null");
for (String headerName : headers.keySet()) {
if (headerName.equalsIgnoreCase(name)) {
return headers.get(headerName);
}
}
return null;
}
}

View File

@@ -1,179 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link AsyncContext} interface.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class MockAsyncContext implements AsyncContext {
private final HttpServletRequest request;
@Nullable
private final HttpServletResponse response;
private final List<AsyncListener> listeners = new ArrayList<>();
@Nullable
private String dispatchedPath;
private long timeout = 10 * 1000L;
private final List<Runnable> dispatchHandlers = new ArrayList<>();
public MockAsyncContext(ServletRequest request, @Nullable ServletResponse response) {
this.request = (HttpServletRequest) request;
this.response = (HttpServletResponse) response;
}
public void addDispatchHandler(Runnable handler) {
Assert.notNull(handler, "Dispatch handler must not be null");
synchronized (this) {
if (this.dispatchedPath == null) {
this.dispatchHandlers.add(handler);
}
else {
handler.run();
}
}
}
@Override
public ServletRequest getRequest() {
return this.request;
}
@Override
@Nullable
public ServletResponse getResponse() {
return this.response;
}
@Override
public boolean hasOriginalRequestAndResponse() {
return (this.request instanceof MockHttpServletRequest && this.response instanceof MockHttpServletResponse);
}
@Override
public void dispatch() {
dispatch(this.request.getRequestURI());
}
@Override
public void dispatch(String path) {
dispatch(null, path);
}
@Override
public void dispatch(@Nullable ServletContext context, String path) {
synchronized (this) {
this.dispatchedPath = path;
this.dispatchHandlers.forEach(Runnable::run);
}
}
@Nullable
public String getDispatchedPath() {
return this.dispatchedPath;
}
@Override
public void complete() {
MockHttpServletRequest mockRequest = WebUtils.getNativeRequest(this.request, MockHttpServletRequest.class);
if (mockRequest != null) {
mockRequest.setAsyncStarted(false);
}
for (AsyncListener listener : this.listeners) {
try {
listener.onComplete(new AsyncEvent(this, this.request, this.response));
}
catch (IOException ex) {
throw new IllegalStateException("AsyncListener failure", ex);
}
}
}
@Override
public void start(Runnable runnable) {
runnable.run();
}
@Override
public void addListener(AsyncListener listener) {
this.listeners.add(listener);
}
@Override
public void addListener(AsyncListener listener, ServletRequest request, ServletResponse response) {
this.listeners.add(listener);
}
public List<AsyncListener> getListeners() {
return this.listeners;
}
@Override
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException {
return BeanUtils.instantiateClass(clazz);
}
/**
* By default this is set to 10000 (10 seconds) even though the Servlet API
* specifies a default async request timeout of 30 seconds. Keep in mind the
* timeout could further be impacted by global configuration through the MVC
* Java config or the XML namespace, as well as be overridden per request on
* {@link org.springframework.web.context.request.async.DeferredResult DeferredResult}
* or on
* {@link org.springframework.web.servlet.mvc.method.annotation.SseEmitter SseEmitter}.
* @param timeout the timeout value to use.
* @see AsyncContext#setTimeout(long)
*/
@Override
public void setTimeout(long timeout) {
this.timeout = timeout;
}
@Override
public long getTimeout() {
return this.timeout;
}
}

View File

@@ -1,226 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import org.springframework.lang.Nullable;
/**
* Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class.
* Only necessary for testing applications when testing custom JSP tags.
*
* @author Juergen Hoeller
* @since 2.5
*/
public class MockBodyContent extends BodyContent {
private final String content;
/**
* Create a MockBodyContent for the given response.
* @param content the body content to expose
* @param response the servlet response to wrap
*/
public MockBodyContent(String content, HttpServletResponse response) {
this(content, response, null);
}
/**
* Create a MockBodyContent for the given response.
* @param content the body content to expose
* @param targetWriter the target Writer to wrap
*/
public MockBodyContent(String content, Writer targetWriter) {
this(content, null, targetWriter);
}
/**
* Create a MockBodyContent for the given response.
* @param content the body content to expose
* @param response the servlet response to wrap
* @param targetWriter the target Writer to wrap
*/
public MockBodyContent(String content, @Nullable HttpServletResponse response, @Nullable Writer targetWriter) {
super(adaptJspWriter(targetWriter, response));
this.content = content;
}
private static JspWriter adaptJspWriter(@Nullable Writer targetWriter, @Nullable HttpServletResponse response) {
if (targetWriter instanceof JspWriter) {
return (JspWriter) targetWriter;
}
else {
return new MockJspWriter(response, targetWriter);
}
}
@Override
public Reader getReader() {
return new StringReader(this.content);
}
@Override
public String getString() {
return this.content;
}
@Override
public void writeOut(Writer writer) throws IOException {
writer.write(this.content);
}
//---------------------------------------------------------------------
// Delegating implementations of JspWriter's abstract methods
//---------------------------------------------------------------------
@Override
public void clear() throws IOException {
getEnclosingWriter().clear();
}
@Override
public void clearBuffer() throws IOException {
getEnclosingWriter().clearBuffer();
}
@Override
public void close() throws IOException {
getEnclosingWriter().close();
}
@Override
public int getRemaining() {
return getEnclosingWriter().getRemaining();
}
@Override
public void newLine() throws IOException {
getEnclosingWriter().println();
}
@Override
public void write(char[] value, int offset, int length) throws IOException {
getEnclosingWriter().write(value, offset, length);
}
@Override
public void print(boolean value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(char value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(char[] value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(double value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(float value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(int value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(long value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(Object value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void print(String value) throws IOException {
getEnclosingWriter().print(value);
}
@Override
public void println() throws IOException {
getEnclosingWriter().println();
}
@Override
public void println(boolean value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(char value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(char[] value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(double value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(float value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(int value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(long value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(Object value) throws IOException {
getEnclosingWriter().println(value);
}
@Override
public void println(String value) throws IOException {
getEnclosingWriter().println(value);
}
}

View File

@@ -1,155 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.web.test;
import java.time.DateTimeException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.servlet.http.Cookie;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Extension of {@code Cookie} with extra attributes, as defined in
* <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>.
*
* @author Vedran Pavic
* @author Juergen Hoeller
* @author Sam Brannen
* @since 5.1
*/
public class MockCookie extends Cookie {
private static final long serialVersionUID = 4312531139502726325L;
@Nullable
private ZonedDateTime expires;
@Nullable
private String sameSite;
/**
* Construct a new {@link MockCookie} with the supplied name and value.
* @param name the name
* @param value the value
* @see Cookie#Cookie(String, String)
*/
public MockCookie(String name, String value) {
super(name, value);
}
/**
* Set the "Expires" attribute for this cookie.
* @since 5.1.11
*/
public void setExpires(@Nullable ZonedDateTime expires) {
this.expires = expires;
}
/**
* Get the "Expires" attribute for this cookie.
* @since 5.1.11
* @return the "Expires" attribute for this cookie, or {@code null} if not set
*/
@Nullable
public ZonedDateTime getExpires() {
return this.expires;
}
/**
* Set the "SameSite" attribute for this cookie.
* <p>This limits the scope of the cookie such that it will only be attached
* to same-site requests if the supplied value is {@code "Strict"} or cross-site
* requests if the supplied value is {@code "Lax"}.
* @see <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis#section-4.1.2.7">RFC6265 bis</a>
*/
public void setSameSite(@Nullable String sameSite) {
this.sameSite = sameSite;
}
/**
* Get the "SameSite" attribute for this cookie.
* @return the "SameSite" attribute for this cookie, or {@code null} if not set
*/
@Nullable
public String getSameSite() {
return this.sameSite;
}
/**
* Factory method that parses the value of the supplied "Set-Cookie" header.
* @param setCookieHeader the "Set-Cookie" value; never {@code null} or empty
* @return the created cookie
*/
public static MockCookie parse(String setCookieHeader) {
Assert.notNull(setCookieHeader, "Set-Cookie header must not be null");
String[] cookieParts = setCookieHeader.split("\\s*=\\s*", 2);
Assert.isTrue(cookieParts.length == 2, () -> "Invalid Set-Cookie header '" + setCookieHeader + "'");
String name = cookieParts[0];
String[] valueAndAttributes = cookieParts[1].split("\\s*;\\s*", 2);
String value = valueAndAttributes[0];
String[] attributes =
(valueAndAttributes.length > 1 ? valueAndAttributes[1].split("\\s*;\\s*") : new String[0]);
MockCookie cookie = new MockCookie(name, value);
for (String attribute : attributes) {
if (StringUtils.startsWithIgnoreCase(attribute, "Domain")) {
cookie.setDomain(extractAttributeValue(attribute, setCookieHeader));
}
else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
}
else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
try {
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
DateTimeFormatter.RFC_1123_DATE_TIME));
}
catch (DateTimeException ex) {
// ignore invalid date formats
}
}
else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
}
else if (StringUtils.startsWithIgnoreCase(attribute, "Secure")) {
cookie.setSecure(true);
}
else if (StringUtils.startsWithIgnoreCase(attribute, "HttpOnly")) {
cookie.setHttpOnly(true);
}
else if (StringUtils.startsWithIgnoreCase(attribute, "SameSite")) {
cookie.setSameSite(extractAttributeValue(attribute, setCookieHeader));
}
}
return cookie;
}
private static String extractAttributeValue(String attribute, String header) {
String[] nameAndValue = attribute.split("=");
Assert.isTrue(nameAndValue.length == 2,
() -> "No value in attribute '" + nameAndValue[0] + "' for Set-Cookie header '" + header + "'");
return nameAndValue[1];
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
/**
* Mock implementation of the JSP 2.0 {@link javax.servlet.jsp.el.ExpressionEvaluator}
* interface, delegating to the Apache JSTL {@link ExpressionEvaluatorManager}.
* Only necessary for testing applications when testing custom JSP tags.
*
* <p>Note that the Apache JSTL implementation (jstl.jar, standard.jar) has to be
* available on the classpath to use this expression evaluator.
*
* @author Juergen Hoeller
* @since 1.1.5
* @see org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager
*/
@SuppressWarnings("deprecation")
public class MockExpressionEvaluator extends javax.servlet.jsp.el.ExpressionEvaluator {
private final PageContext pageContext;
/**
* Create a new MockExpressionEvaluator for the given PageContext.
* @param pageContext the JSP PageContext to run in
*/
public MockExpressionEvaluator(PageContext pageContext) {
this.pageContext = pageContext;
}
@Override
@SuppressWarnings("rawtypes")
public javax.servlet.jsp.el.Expression parseExpression(final String expression, final Class expectedType,
final javax.servlet.jsp.el.FunctionMapper functionMapper) throws javax.servlet.jsp.el.ELException {
return new javax.servlet.jsp.el.Expression() {
@Override
public Object evaluate(javax.servlet.jsp.el.VariableResolver variableResolver) throws javax.servlet.jsp.el.ELException {
return doEvaluate(expression, expectedType, functionMapper);
}
};
}
@Override
@SuppressWarnings("rawtypes")
public Object evaluate(String expression, Class expectedType, javax.servlet.jsp.el.VariableResolver variableResolver,
javax.servlet.jsp.el.FunctionMapper functionMapper) throws javax.servlet.jsp.el.ELException {
return doEvaluate(expression, expectedType, functionMapper);
}
@SuppressWarnings("rawtypes")
protected Object doEvaluate(String expression, Class expectedType, javax.servlet.jsp.el.FunctionMapper functionMapper)
throws javax.servlet.jsp.el.ELException {
try {
return ExpressionEvaluatorManager.evaluate("JSP EL expression", expression, expectedType, this.pageContext);
}
catch (JspException ex) {
throw new javax.servlet.jsp.el.ELException("Parsing of JSP EL expression \"" + expression + "\" failed", ex);
}
}
}

View File

@@ -1,184 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Mock implementation of the {@link javax.servlet.FilterChain} interface.
*
* <p>A {@link MockFilterChain} can be configured with one or more filters and a
* Servlet to invoke. The first time the chain is called, it invokes all filters
* and the Servlet, and saves the request and response. Subsequent invocations
* raise an {@link IllegalStateException} unless {@link #reset()} is called.
*
* @author Juergen Hoeller
* @author Rob Winch
* @author Rossen Stoyanchev
* @since 2.0.3
* @see MockFilterConfig
* @see PassThroughFilterChain
*/
public class MockFilterChain implements FilterChain {
@Nullable
private ServletRequest request;
@Nullable
private ServletResponse response;
private final List<Filter> filters;
@Nullable
private Iterator<Filter> iterator;
/**
* Register a single do-nothing {@link Filter} implementation. The first
* invocation saves the request and response. Subsequent invocations raise
* an {@link IllegalStateException} unless {@link #reset()} is called.
*/
public MockFilterChain() {
this.filters = Collections.emptyList();
}
/**
* Create a FilterChain with a Servlet.
* @param servlet the Servlet to invoke
* @since 3.2
*/
public MockFilterChain(Servlet servlet) {
this.filters = initFilterList(servlet);
}
/**
* Create a {@code FilterChain} with Filter's and a Servlet.
* @param servlet the {@link Servlet} to invoke in this {@link FilterChain}
* @param filters the {@link Filter}'s to invoke in this {@link FilterChain}
* @since 3.2
*/
public MockFilterChain(Servlet servlet, Filter... filters) {
Assert.notNull(filters, "filters cannot be null");
Assert.noNullElements(filters, "filters cannot contain null values");
this.filters = initFilterList(servlet, filters);
}
private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {
Filter[] allFilters = ObjectUtils.addObjectToArray(filters, new ServletFilterProxy(servlet));
return Arrays.asList(allFilters);
}
/**
* Return the request that {@link #doFilter} has been called with.
*/
@Nullable
public ServletRequest getRequest() {
return this.request;
}
/**
* Return the response that {@link #doFilter} has been called with.
*/
@Nullable
public ServletResponse getResponse() {
return this.response;
}
/**
* Invoke registered {@link Filter Filters} and/or {@link Servlet} also saving the
* request and response.
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
Assert.state(this.request == null, "This FilterChain has already been called!");
if (this.iterator == null) {
this.iterator = this.filters.iterator();
}
if (this.iterator.hasNext()) {
Filter nextFilter = this.iterator.next();
nextFilter.doFilter(request, response, this);
}
this.request = request;
this.response = response;
}
/**
* Reset the {@link MockFilterChain} allowing it to be invoked again.
*/
public void reset() {
this.request = null;
this.response = null;
this.iterator = null;
}
/**
* A filter that simply delegates to a Servlet.
*/
private static final class ServletFilterProxy implements Filter {
private final Servlet delegateServlet;
private ServletFilterProxy(Servlet servlet) {
Assert.notNull(servlet, "servlet cannot be null");
this.delegateServlet = servlet;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
this.delegateServlet.service(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public String toString() {
return this.delegateServlet.toString();
}
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.FilterConfig} interface.
*
* <p>Used for testing the web framework; also useful for testing
* custom {@link javax.servlet.Filter} implementations.
*
* @author Juergen Hoeller
* @since 1.0.2
* @see MockFilterChain
* @see PassThroughFilterChain
*/
public class MockFilterConfig implements FilterConfig {
private final ServletContext servletContext;
private final String filterName;
private final Map<String, String> initParameters = new LinkedHashMap<>();
/**
* Create a new MockFilterConfig with a default {@link MockServletContext}.
*/
public MockFilterConfig() {
this(null, "");
}
/**
* Create a new MockFilterConfig with a default {@link MockServletContext}.
* @param filterName the name of the filter
*/
public MockFilterConfig(String filterName) {
this(null, filterName);
}
/**
* Create a new MockFilterConfig.
* @param servletContext the ServletContext that the servlet runs in
*/
public MockFilterConfig(@Nullable ServletContext servletContext) {
this(servletContext, "");
}
/**
* Create a new MockFilterConfig.
* @param servletContext the ServletContext that the servlet runs in
* @param filterName the name of the filter
*/
public MockFilterConfig(@Nullable ServletContext servletContext, String filterName) {
this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
this.filterName = filterName;
}
@Override
public String getFilterName() {
return this.filterName;
}
@Override
public ServletContext getServletContext() {
return this.servletContext;
}
public void addInitParameter(String name, String value) {
Assert.notNull(name, "Parameter name must not be null");
this.initParameters.put(name, value);
}
@Override
public String getInitParameter(String name) {
Assert.notNull(name, "Parameter name must not be null");
return this.initParameters.get(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(this.initParameters.keySet());
}
}

View File

@@ -1,826 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.web.test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface.
*
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson
* @author Brian Clozel
* @author Vedran Pavic
* @author Sebastien Deleuze
* @author Sam Brannen
* @since 1.0.2
*/
public class MockHttpServletResponse implements HttpServletResponse {
private static final String CHARSET_PREFIX = "charset=";
private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
//---------------------------------------------------------------------
// ServletResponse properties
//---------------------------------------------------------------------
private boolean outputStreamAccessAllowed = true;
private boolean writerAccessAllowed = true;
@Nullable
private String characterEncoding = WebUtils.DEFAULT_CHARACTER_ENCODING;
private boolean charset = false;
private final ByteArrayOutputStream content = new ByteArrayOutputStream(1024);
private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content);
@Nullable
private PrintWriter writer;
private long contentLength = 0;
@Nullable
private String contentType;
private int bufferSize = 4096;
private boolean committed;
private Locale locale = Locale.getDefault();
//---------------------------------------------------------------------
// HttpServletResponse properties
//---------------------------------------------------------------------
private final List<Cookie> cookies = new ArrayList<>();
private final Map<String, HeaderValueHolder> headers = new LinkedCaseInsensitiveMap<>();
private int status = HttpServletResponse.SC_OK;
@Nullable
private String errorMessage;
@Nullable
private String forwardedUrl;
private final List<String> includedUrls = new ArrayList<>();
//---------------------------------------------------------------------
// ServletResponse interface
//---------------------------------------------------------------------
/**
* Set whether {@link #getOutputStream()} access is allowed.
* <p>Default is {@code true}.
*/
public void setOutputStreamAccessAllowed(boolean outputStreamAccessAllowed) {
this.outputStreamAccessAllowed = outputStreamAccessAllowed;
}
/**
* Return whether {@link #getOutputStream()} access is allowed.
*/
public boolean isOutputStreamAccessAllowed() {
return this.outputStreamAccessAllowed;
}
/**
* Set whether {@link #getWriter()} access is allowed.
* <p>Default is {@code true}.
*/
public void setWriterAccessAllowed(boolean writerAccessAllowed) {
this.writerAccessAllowed = writerAccessAllowed;
}
/**
* Return whether {@link #getOutputStream()} access is allowed.
*/
public boolean isWriterAccessAllowed() {
return this.writerAccessAllowed;
}
/**
* Return whether the character encoding has been set.
* <p>If {@code false}, {@link #getCharacterEncoding()} will return a default encoding value.
*/
public boolean isCharset() {
return this.charset;
}
@Override
public void setCharacterEncoding(String characterEncoding) {
this.characterEncoding = characterEncoding;
this.charset = true;
updateContentTypeHeader();
}
private void updateContentTypeHeader() {
if (this.contentType != null) {
String value = this.contentType;
if (this.charset && !this.contentType.toLowerCase().contains(CHARSET_PREFIX)) {
value = value + ';' + CHARSET_PREFIX + this.characterEncoding;
}
doAddHeaderValue(HttpHeaders.CONTENT_TYPE, value, true);
}
}
@Override
@Nullable
public String getCharacterEncoding() {
return this.characterEncoding;
}
@Override
public ServletOutputStream getOutputStream() {
Assert.state(this.outputStreamAccessAllowed, "OutputStream access not allowed");
return this.outputStream;
}
@Override
public PrintWriter getWriter() throws UnsupportedEncodingException {
Assert.state(this.writerAccessAllowed, "Writer access not allowed");
if (this.writer == null) {
Writer targetWriter = (this.characterEncoding != null ?
new OutputStreamWriter(this.content, this.characterEncoding) :
new OutputStreamWriter(this.content));
this.writer = new ResponsePrintWriter(targetWriter);
}
return this.writer;
}
public byte[] getContentAsByteArray() {
return this.content.toByteArray();
}
/**
* Get the content of the response body as a {@code String}, using the charset
* specified for the response by the application, either through
* {@link HttpServletResponse} methods or through a charset parameter on the
* {@code Content-Type}.
* @return the content as a {@code String}
* @throws UnsupportedEncodingException if the character encoding is not supported
* @see #getContentAsString(Charset)
*/
public String getContentAsString() throws UnsupportedEncodingException {
return (this.characterEncoding != null ?
this.content.toString(this.characterEncoding) : this.content.toString());
}
/**
* Get the content of the response body as a {@code String}, using the provided
* {@code fallbackCharset} if no charset has been explicitly defined and otherwise
* using the charset specified for the response by the application, either
* through {@link HttpServletResponse} methods or through a charset parameter on the
* {@code Content-Type}.
* @return the content as a {@code String}
* @throws UnsupportedEncodingException if the character encoding is not supported
* @since 5.2
* @see #getContentAsString()
*/
public String getContentAsString(Charset fallbackCharset) throws UnsupportedEncodingException {
return (isCharset() && this.characterEncoding != null ?
this.content.toString(this.characterEncoding) :
this.content.toString(fallbackCharset.name()));
}
@Override
public void setContentLength(int contentLength) {
this.contentLength = contentLength;
doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true);
}
public int getContentLength() {
return (int) this.contentLength;
}
@Override
public void setContentLengthLong(long contentLength) {
this.contentLength = contentLength;
doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true);
}
public long getContentLengthLong() {
return this.contentLength;
}
@Override
public void setContentType(@Nullable String contentType) {
this.contentType = contentType;
if (contentType != null) {
try {
MediaType mediaType = MediaType.parseMediaType(contentType);
if (mediaType.getCharset() != null) {
this.characterEncoding = mediaType.getCharset().name();
this.charset = true;
}
}
catch (Exception ex) {
// Try to get charset value anyway
int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
if (charsetIndex != -1) {
this.characterEncoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length());
this.charset = true;
}
}
updateContentTypeHeader();
}
}
@Override
@Nullable
public String getContentType() {
return this.contentType;
}
@Override
public void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
@Override
public int getBufferSize() {
return this.bufferSize;
}
@Override
public void flushBuffer() {
setCommitted(true);
}
@Override
public void resetBuffer() {
Assert.state(!isCommitted(), "Cannot reset buffer - response is already committed");
this.content.reset();
}
private void setCommittedIfBufferSizeExceeded() {
int bufSize = getBufferSize();
if (bufSize > 0 && this.content.size() > bufSize) {
setCommitted(true);
}
}
public void setCommitted(boolean committed) {
this.committed = committed;
}
@Override
public boolean isCommitted() {
return this.committed;
}
@Override
public void reset() {
resetBuffer();
this.characterEncoding = null;
this.contentLength = 0;
this.contentType = null;
this.locale = Locale.getDefault();
this.cookies.clear();
this.headers.clear();
this.status = HttpServletResponse.SC_OK;
this.errorMessage = null;
}
@Override
public void setLocale(Locale locale) {
this.locale = locale;
doAddHeaderValue(HttpHeaders.CONTENT_LANGUAGE, locale.toLanguageTag(), true);
}
@Override
public Locale getLocale() {
return this.locale;
}
//---------------------------------------------------------------------
// HttpServletResponse interface
//---------------------------------------------------------------------
@Override
public void addCookie(Cookie cookie) {
Assert.notNull(cookie, "Cookie must not be null");
this.cookies.add(cookie);
doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), false);
}
private String getCookieHeader(Cookie cookie) {
StringBuilder buf = new StringBuilder();
buf.append(cookie.getName()).append('=').append(cookie.getValue() == null ? "" : cookie.getValue());
if (StringUtils.hasText(cookie.getPath())) {
buf.append("; Path=").append(cookie.getPath());
}
if (StringUtils.hasText(cookie.getDomain())) {
buf.append("; Domain=").append(cookie.getDomain());
}
int maxAge = cookie.getMaxAge();
if (maxAge >= 0) {
buf.append("; Max-Age=").append(maxAge);
buf.append("; Expires=");
ZonedDateTime expires = (cookie instanceof MockCookie ? ((MockCookie) cookie).getExpires() : null);
if (expires != null) {
buf.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
}
else {
HttpHeaders headers = new HttpHeaders();
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
}
}
if (cookie.getSecure()) {
buf.append("; Secure");
}
if (cookie.isHttpOnly()) {
buf.append("; HttpOnly");
}
if (cookie instanceof MockCookie) {
MockCookie mockCookie = (MockCookie) cookie;
if (StringUtils.hasText(mockCookie.getSameSite())) {
buf.append("; SameSite=").append(mockCookie.getSameSite());
}
}
return buf.toString();
}
public Cookie[] getCookies() {
return this.cookies.toArray(new Cookie[0]);
}
@Nullable
public Cookie getCookie(String name) {
Assert.notNull(name, "Cookie name must not be null");
for (Cookie cookie : this.cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
@Override
public boolean containsHeader(String name) {
return (this.headers.get(name) != null);
}
/**
* Return the names of all specified headers as a Set of Strings.
* <p>As of Servlet 3.0, this method is also defined HttpServletResponse.
* @return the {@code Set} of header name {@code Strings}, or an empty {@code Set} if none
*/
@Override
public Collection<String> getHeaderNames() {
return this.headers.keySet();
}
/**
* Return the primary value for the given header as a String, if any.
* Will return the first value in case of multiple values.
* <p>As of Servlet 3.0, this method is also defined in HttpServletResponse.
* As of Spring 3.1, it returns a stringified value for Servlet 3.0 compatibility.
* Consider using {@link #getHeaderValue(String)} for raw Object access.
* @param name the name of the header
* @return the associated header value, or {@code null} if none
*/
@Override
@Nullable
public String getHeader(String name) {
HeaderValueHolder header = this.headers.get(name);
return (header != null ? header.getStringValue() : null);
}
/**
* Return all values for the given header as a List of Strings.
* <p>As of Servlet 3.0, this method is also defined in HttpServletResponse.
* As of Spring 3.1, it returns a List of stringified values for Servlet 3.0 compatibility.
* Consider using {@link #getHeaderValues(String)} for raw Object access.
* @param name the name of the header
* @return the associated header values, or an empty List if none
*/
@Override
public List<String> getHeaders(String name) {
HeaderValueHolder header = this.headers.get(name);
if (header != null) {
return header.getStringValues();
}
else {
return Collections.emptyList();
}
}
/**
* Return the primary value for the given header, if any.
* <p>Will return the first value in case of multiple values.
* @param name the name of the header
* @return the associated header value, or {@code null} if none
*/
@Nullable
public Object getHeaderValue(String name) {
HeaderValueHolder header = this.headers.get(name);
return (header != null ? header.getValue() : null);
}
/**
* Return all values for the given header as a List of value objects.
* @param name the name of the header
* @return the associated header values, or an empty List if none
*/
public List<Object> getHeaderValues(String name) {
HeaderValueHolder header = this.headers.get(name);
if (header != null) {
return header.getValues();
}
else {
return Collections.emptyList();
}
}
/**
* The default implementation returns the given URL String as-is.
* <p>Can be overridden in subclasses, appending a session id or the like.
*/
@Override
public String encodeURL(String url) {
return url;
}
/**
* The default implementation delegates to {@link #encodeURL},
* returning the given URL String as-is.
* <p>Can be overridden in subclasses, appending a session id or the like
* in a redirect-specific fashion. For general URL encoding rules,
* override the common {@link #encodeURL} method instead, applying
* to redirect URLs as well as to general URLs.
*/
@Override
public String encodeRedirectURL(String url) {
return encodeURL(url);
}
@Override
@Deprecated
public String encodeUrl(String url) {
return encodeURL(url);
}
@Override
@Deprecated
public String encodeRedirectUrl(String url) {
return encodeRedirectURL(url);
}
@Override
public void sendError(int status, String errorMessage) throws IOException {
Assert.state(!isCommitted(), "Cannot set error status - response is already committed");
this.status = status;
this.errorMessage = errorMessage;
setCommitted(true);
}
@Override
public void sendError(int status) throws IOException {
Assert.state(!isCommitted(), "Cannot set error status - response is already committed");
this.status = status;
setCommitted(true);
}
@Override
public void sendRedirect(String url) throws IOException {
Assert.state(!isCommitted(), "Cannot send redirect - response is already committed");
Assert.notNull(url, "Redirect URL must not be null");
setHeader(HttpHeaders.LOCATION, url);
setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
setCommitted(true);
}
@Nullable
public String getRedirectedUrl() {
return getHeader(HttpHeaders.LOCATION);
}
@Override
public void setDateHeader(String name, long value) {
setHeaderValue(name, formatDate(value));
}
@Override
public void addDateHeader(String name, long value) {
addHeaderValue(name, formatDate(value));
}
public long getDateHeader(String name) {
String headerValue = getHeader(name);
if (headerValue == null) {
return -1;
}
try {
return newDateFormat().parse(getHeader(name)).getTime();
}
catch (ParseException ex) {
throw new IllegalArgumentException(
"Value for header '" + name + "' is not a valid Date: " + headerValue);
}
}
private String formatDate(long date) {
return newDateFormat().format(new Date(date));
}
private DateFormat newDateFormat() {
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
dateFormat.setTimeZone(GMT);
return dateFormat;
}
@Override
public void setHeader(String name, String value) {
setHeaderValue(name, value);
}
@Override
public void addHeader(String name, String value) {
addHeaderValue(name, value);
}
@Override
public void setIntHeader(String name, int value) {
setHeaderValue(name, value);
}
@Override
public void addIntHeader(String name, int value) {
addHeaderValue(name, value);
}
private void setHeaderValue(String name, Object value) {
boolean replaceHeader = true;
if (setSpecialHeader(name, value, replaceHeader)) {
return;
}
doAddHeaderValue(name, value, replaceHeader);
}
private void addHeaderValue(String name, Object value) {
boolean replaceHeader = false;
if (setSpecialHeader(name, value, replaceHeader)) {
return;
}
doAddHeaderValue(name, value, replaceHeader);
}
private boolean setSpecialHeader(String name, Object value, boolean replaceHeader) {
if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)) {
setContentType(value.toString());
return true;
}
else if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)) {
setContentLength(value instanceof Number ? ((Number) value).intValue() :
Integer.parseInt(value.toString()));
return true;
}
else if (HttpHeaders.CONTENT_LANGUAGE.equalsIgnoreCase(name)) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_LANGUAGE, value.toString());
Locale language = headers.getContentLanguage();
setLocale(language != null ? language : Locale.getDefault());
return true;
}
else if (HttpHeaders.SET_COOKIE.equalsIgnoreCase(name)) {
MockCookie cookie = MockCookie.parse(value.toString());
if (replaceHeader) {
setCookie(cookie);
}
else {
addCookie(cookie);
}
return true;
}
else {
return false;
}
}
private void doAddHeaderValue(String name, Object value, boolean replace) {
HeaderValueHolder header = this.headers.get(name);
Assert.notNull(value, "Header value must not be null");
if (header == null) {
header = new HeaderValueHolder();
this.headers.put(name, header);
}
if (replace) {
header.setValue(value);
}
else {
header.addValue(value);
}
}
/**
* Set the {@code Set-Cookie} header to the supplied {@link Cookie},
* overwriting any previous cookies.
* @param cookie the {@code Cookie} to set
* @since 5.1.10
* @see #addCookie(Cookie)
*/
private void setCookie(Cookie cookie) {
Assert.notNull(cookie, "Cookie must not be null");
this.cookies.clear();
this.cookies.add(cookie);
doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), true);
}
@Override
public void setStatus(int status) {
if (!this.isCommitted()) {
this.status = status;
}
}
@Override
@Deprecated
public void setStatus(int status, String errorMessage) {
if (!this.isCommitted()) {
this.status = status;
this.errorMessage = errorMessage;
}
}
@Override
public int getStatus() {
return this.status;
}
@Nullable
public String getErrorMessage() {
return this.errorMessage;
}
//---------------------------------------------------------------------
// Methods for MockRequestDispatcher
//---------------------------------------------------------------------
public void setForwardedUrl(@Nullable String forwardedUrl) {
this.forwardedUrl = forwardedUrl;
}
@Nullable
public String getForwardedUrl() {
return this.forwardedUrl;
}
public void setIncludedUrl(@Nullable String includedUrl) {
this.includedUrls.clear();
if (includedUrl != null) {
this.includedUrls.add(includedUrl);
}
}
@Nullable
public String getIncludedUrl() {
int count = this.includedUrls.size();
Assert.state(count <= 1,
() -> "More than 1 URL included - check getIncludedUrls instead: " + this.includedUrls);
return (count == 1 ? this.includedUrls.get(0) : null);
}
public void addIncludedUrl(String includedUrl) {
Assert.notNull(includedUrl, "Included URL must not be null");
this.includedUrls.add(includedUrl);
}
public List<String> getIncludedUrls() {
return this.includedUrls;
}
/**
* Inner class that adapts the ServletOutputStream to mark the
* response as committed once the buffer size is exceeded.
*/
private class ResponseServletOutputStream extends DelegatingServletOutputStream {
public ResponseServletOutputStream(OutputStream out) {
super(out);
}
@Override
public void write(int b) throws IOException {
super.write(b);
super.flush();
setCommittedIfBufferSizeExceeded();
}
@Override
public void flush() throws IOException {
super.flush();
setCommitted(true);
}
}
/**
* Inner class that adapts the PrintWriter to mark the
* response as committed once the buffer size is exceeded.
*/
private class ResponsePrintWriter extends PrintWriter {
public ResponsePrintWriter(Writer out) {
super(out, true);
}
@Override
public void write(char[] buf, int off, int len) {
super.write(buf, off, len);
super.flush();
setCommittedIfBufferSizeExceeded();
}
@Override
public void write(String s, int off, int len) {
super.write(s, off, len);
super.flush();
setCommittedIfBufferSizeExceeded();
}
@Override
public void write(int c) {
super.write(c);
super.flush();
setCommittedIfBufferSizeExceeded();
}
@Override
public void flush() {
super.flush();
setCommitted(true);
}
@Override
public void close() {
super.flush();
super.close();
setCommitted(true);
}
}
}

View File

@@ -1,306 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.Serializable;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Mock implementation of the {@link javax.servlet.http.HttpSession} interface.
*
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson
* @author Mark Fisher
* @author Sam Brannen
* @author Vedran Pavic
* @since 1.0.2
*/
@SuppressWarnings("deprecation")
public class MockHttpSession implements HttpSession {
/**
* The session cookie name.
*/
public static final String SESSION_COOKIE_NAME = "JSESSION";
private static int nextId = 1;
private String id;
private final long creationTime = System.currentTimeMillis();
private int maxInactiveInterval;
private long lastAccessedTime = System.currentTimeMillis();
private final ServletContext servletContext;
private final Map<String, Object> attributes = new LinkedHashMap<>();
private boolean invalid = false;
private boolean isNew = true;
/**
* Create a new MockHttpSession with a default {@link MockServletContext}.
* @see MockServletContext
*/
public MockHttpSession() {
this(null);
}
/**
* Create a new MockHttpSession.
* @param servletContext the ServletContext that the session runs in
*/
public MockHttpSession(@Nullable ServletContext servletContext) {
this(servletContext, null);
}
/**
* Create a new MockHttpSession.
* @param servletContext the ServletContext that the session runs in
* @param id a unique identifier for this session
*/
public MockHttpSession(@Nullable ServletContext servletContext, @Nullable String id) {
this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
this.id = (id != null ? id : Integer.toString(nextId++));
}
@Override
public long getCreationTime() {
assertIsValid();
return this.creationTime;
}
@Override
public String getId() {
return this.id;
}
/**
* As of Servlet 3.1, the id of a session can be changed.
* @return the new session id
* @since 4.0.3
*/
public String changeSessionId() {
this.id = Integer.toString(nextId++);
return this.id;
}
public void access() {
this.lastAccessedTime = System.currentTimeMillis();
this.isNew = false;
}
@Override
public long getLastAccessedTime() {
assertIsValid();
return this.lastAccessedTime;
}
@Override
public ServletContext getServletContext() {
return this.servletContext;
}
@Override
public void setMaxInactiveInterval(int interval) {
this.maxInactiveInterval = interval;
}
@Override
public int getMaxInactiveInterval() {
return this.maxInactiveInterval;
}
@Override
public javax.servlet.http.HttpSessionContext getSessionContext() {
throw new UnsupportedOperationException("getSessionContext");
}
@Override
public Object getAttribute(String name) {
assertIsValid();
Assert.notNull(name, "Attribute name must not be null");
return this.attributes.get(name);
}
@Override
public Object getValue(String name) {
return getAttribute(name);
}
@Override
public Enumeration<String> getAttributeNames() {
assertIsValid();
return Collections.enumeration(new LinkedHashSet<>(this.attributes.keySet()));
}
@Override
public String[] getValueNames() {
assertIsValid();
return StringUtils.toStringArray(this.attributes.keySet());
}
@Override
public void setAttribute(String name, @Nullable Object value) {
assertIsValid();
Assert.notNull(name, "Attribute name must not be null");
if (value != null) {
Object oldValue = this.attributes.put(name, value);
if (value != oldValue) {
if (oldValue instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) oldValue).valueUnbound(new HttpSessionBindingEvent(this, name, oldValue));
}
if (value instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value));
}
}
}
else {
removeAttribute(name);
}
}
@Override
public void putValue(String name, Object value) {
setAttribute(name, value);
}
@Override
public void removeAttribute(String name) {
assertIsValid();
Assert.notNull(name, "Attribute name must not be null");
Object value = this.attributes.remove(name);
if (value instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
}
}
@Override
public void removeValue(String name) {
removeAttribute(name);
}
/**
* Clear all of this session's attributes.
*/
public void clearAttributes() {
for (Iterator<Map.Entry<String, Object>> it = this.attributes.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Object> entry = it.next();
String name = entry.getKey();
Object value = entry.getValue();
it.remove();
if (value instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
}
}
}
/**
* Invalidates this session then unbinds any objects bound to it.
* @throws IllegalStateException if this method is called on an already invalidated session
*/
@Override
public void invalidate() {
assertIsValid();
this.invalid = true;
clearAttributes();
}
public boolean isInvalid() {
return this.invalid;
}
/**
* Convenience method for asserting that this session has not been
* {@linkplain #invalidate() invalidated}.
* @throws IllegalStateException if this session has been invalidated
*/
private void assertIsValid() {
Assert.state(!isInvalid(), "The session has already been invalidated");
}
public void setNew(boolean value) {
this.isNew = value;
}
@Override
public boolean isNew() {
assertIsValid();
return this.isNew;
}
/**
* Serialize the attributes of this session into an object that can be
* turned into a byte array with standard Java serialization.
* @return a representation of this session's serialized state
*/
public Serializable serializeState() {
HashMap<String, Serializable> state = new HashMap<>();
for (Iterator<Map.Entry<String, Object>> it = this.attributes.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Object> entry = it.next();
String name = entry.getKey();
Object value = entry.getValue();
it.remove();
if (value instanceof Serializable) {
state.put(name, (Serializable) value);
}
else {
// Not serializable... Servlet containers usually automatically
// unbind the attribute in this case.
if (value instanceof HttpSessionBindingListener) {
((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
}
}
}
return state;
}
/**
* Deserialize the attributes of this session from a state object created by
* {@link #serializeState()}.
* @param state a representation of this session's serialized state
*/
@SuppressWarnings("unchecked")
public void deserializeState(Serializable state) {
Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]");
this.attributes.putAll((Map<String, Object>) state);
}
}

View File

@@ -1,219 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;
import org.springframework.lang.Nullable;
/**
* Mock implementation of the {@link javax.servlet.jsp.JspWriter} class.
* Only necessary for testing applications when testing custom JSP tags.
*
* @author Juergen Hoeller
* @since 2.5
*/
public class MockJspWriter extends JspWriter {
private final HttpServletResponse response;
@Nullable
private PrintWriter targetWriter;
/**
* Create a MockJspWriter for the given response,
* using the response's default Writer.
* @param response the servlet response to wrap
*/
public MockJspWriter(HttpServletResponse response) {
this(response, null);
}
/**
* Create a MockJspWriter for the given plain Writer.
* @param targetWriter the target Writer to wrap
*/
public MockJspWriter(Writer targetWriter) {
this(null, targetWriter);
}
/**
* Create a MockJspWriter for the given response.
* @param response the servlet response to wrap
* @param targetWriter the target Writer to wrap
*/
public MockJspWriter(@Nullable HttpServletResponse response, @Nullable Writer targetWriter) {
super(DEFAULT_BUFFER, true);
this.response = (response != null ? response : new MockHttpServletResponse());
if (targetWriter instanceof PrintWriter) {
this.targetWriter = (PrintWriter) targetWriter;
}
else if (targetWriter != null) {
this.targetWriter = new PrintWriter(targetWriter);
}
}
/**
* Lazily initialize the target Writer.
*/
protected PrintWriter getTargetWriter() throws IOException {
if (this.targetWriter == null) {
this.targetWriter = this.response.getWriter();
}
return this.targetWriter;
}
@Override
public void clear() throws IOException {
if (this.response.isCommitted()) {
throw new IOException("Response already committed");
}
this.response.resetBuffer();
}
@Override
public void clearBuffer() throws IOException {
}
@Override
public void flush() throws IOException {
this.response.flushBuffer();
}
@Override
public void close() throws IOException {
flush();
}
@Override
public int getRemaining() {
return Integer.MAX_VALUE;
}
@Override
public void newLine() throws IOException {
getTargetWriter().println();
}
@Override
public void write(char[] value, int offset, int length) throws IOException {
getTargetWriter().write(value, offset, length);
}
@Override
public void print(boolean value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(char value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(char[] value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(double value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(float value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(int value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(long value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(Object value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void print(String value) throws IOException {
getTargetWriter().print(value);
}
@Override
public void println() throws IOException {
getTargetWriter().println();
}
@Override
public void println(boolean value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(char value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(char[] value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(double value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(float value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(int value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(long value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(Object value) throws IOException {
getTargetWriter().println(value);
}
@Override
public void println(String value) throws IOException {
getTargetWriter().println(value);
}
}

View File

@@ -1,146 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
/**
* Mock implementation of the {@link org.springframework.web.multipart.MultipartFile}
* interface.
*
* <p>Useful in conjunction with a {@link MockMultipartHttpServletRequest}
* for testing application controllers that access multipart uploads.
*
* @author Juergen Hoeller
* @author Eric Crampton
* @since 2.0
* @see MockMultipartHttpServletRequest
*/
public class MockMultipartFile implements MultipartFile {
private final String name;
private String originalFilename;
@Nullable
private String contentType;
private final byte[] content;
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param content the content of the file
*/
public MockMultipartFile(String name, @Nullable byte[] content) {
this(name, "", null, content);
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MockMultipartFile(String name, InputStream contentStream) throws IOException {
this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param content the content of the file
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {
Assert.hasLength(name, "Name must not be null");
this.name = name;
this.originalFilename = (originalFilename != null ? originalFilename : "");
this.contentType = contentType;
this.content = (content != null ? content : new byte[0]);
}
/**
* Create a new MockMultipartFile with the given content.
* @param name the name of the file
* @param originalFilename the original filename (as on the client's machine)
* @param contentType the content type (if known)
* @param contentStream the content of the file as stream
* @throws IOException if reading from the stream failed
*/
public MockMultipartFile(
String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
throws IOException {
this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
}
@Override
public String getName() {
return this.name;
}
@Override
public String getOriginalFilename() {
return this.originalFilename;
}
@Override
@Nullable
public String getContentType() {
return this.contentType;
}
@Override
public boolean isEmpty() {
return (this.content.length == 0);
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public byte[] getBytes() throws IOException {
return this.content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(this.content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.content, dest);
}
}

View File

@@ -1,169 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Part;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
/**
* Mock implementation of the
* {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface.
*
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* <p>Useful for testing application controllers that access multipart uploads.
* {@link MockMultipartFile} can be used to populate these mock requests with files.
*
* @author Juergen Hoeller
* @author Eric Crampton
* @author Arjen Poutsma
* @since 2.0
* @see MockMultipartFile
*/
public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest {
private final MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<>();
/**
* Create a new {@code MockMultipartHttpServletRequest} with a default
* {@link MockServletContext}.
* @see #MockMultipartHttpServletRequest(ServletContext)
*/
public MockMultipartHttpServletRequest() {
this(null);
}
/**
* Create a new {@code MockMultipartHttpServletRequest} with the supplied {@link ServletContext}.
* @param servletContext the ServletContext that the request runs in
* (may be {@code null} to use a default {@link MockServletContext})
*/
public MockMultipartHttpServletRequest(@Nullable ServletContext servletContext) {
super(servletContext);
setMethod("POST");
setContentType("multipart/form-data");
}
/**
* Add a file to this request. The parameter name from the multipart
* form is taken from the {@link MultipartFile#getName()}.
* @param file multipart file to be added
*/
public void addFile(MultipartFile file) {
Assert.notNull(file, "MultipartFile must not be null");
this.multipartFiles.add(file.getName(), file);
}
@Override
public Iterator<String> getFileNames() {
return this.multipartFiles.keySet().iterator();
}
@Override
public MultipartFile getFile(String name) {
return this.multipartFiles.getFirst(name);
}
@Override
public List<MultipartFile> getFiles(String name) {
List<MultipartFile> multipartFiles = this.multipartFiles.get(name);
if (multipartFiles != null) {
return multipartFiles;
}
else {
return Collections.emptyList();
}
}
@Override
public Map<String, MultipartFile> getFileMap() {
return this.multipartFiles.toSingleValueMap();
}
@Override
public MultiValueMap<String, MultipartFile> getMultiFileMap() {
return new LinkedMultiValueMap<>(this.multipartFiles);
}
@Override
public String getMultipartContentType(String paramOrFileName) {
MultipartFile file = getFile(paramOrFileName);
if (file != null) {
return file.getContentType();
}
try {
Part part = getPart(paramOrFileName);
if (part != null) {
return part.getContentType();
}
}
catch (ServletException | IOException ex) {
// Should never happen (we're not actually parsing)
throw new IllegalStateException(ex);
}
return null;
}
@Override
public HttpMethod getRequestMethod() {
return HttpMethod.resolve(getMethod());
}
@Override
public HttpHeaders getRequestHeaders() {
HttpHeaders headers = new HttpHeaders();
Enumeration<String> headerNames = getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.put(headerName, Collections.list(getHeaders(headerName)));
}
return headers;
}
@Override
public HttpHeaders getMultipartHeaders(String paramOrFileName) {
String contentType = getMultipartContentType(paramOrFileName);
if (contentType != null) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", contentType);
return headers;
}
else {
return null;
}
}
}

View File

@@ -1,387 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import javax.el.ELContext;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.jsp.PageContext} interface.
* Only necessary for testing applications when testing custom JSP tags.
*
* <p>Note: Expects initialization via the constructor rather than via the
* {@code PageContext.initialize} method. Does not support writing to a
* JspWriter, request dispatching, or {@code handlePageException} calls.
*
* @author Juergen Hoeller
* @since 1.0.2
*/
public class MockPageContext extends PageContext {
private final ServletContext servletContext;
private final HttpServletRequest request;
private final HttpServletResponse response;
private final ServletConfig servletConfig;
private final Map<String, Object> attributes = new LinkedHashMap<>();
@Nullable
private JspWriter out;
/**
* Create new MockPageContext with a default {@link MockServletContext},
* {@link MockHttpServletRequest}, {@link MockHttpServletResponse},
* {@link MockServletConfig}.
*/
public MockPageContext() {
this(null, null, null, null);
}
/**
* Create new MockPageContext with a default {@link MockHttpServletRequest},
* {@link MockHttpServletResponse}, {@link MockServletConfig}.
* @param servletContext the ServletContext that the JSP page runs in
* (only necessary when actually accessing the ServletContext)
*/
public MockPageContext(@Nullable ServletContext servletContext) {
this(servletContext, null, null, null);
}
/**
* Create new MockPageContext with a MockHttpServletResponse,
* MockServletConfig.
* @param servletContext the ServletContext that the JSP page runs in
* @param request the current HttpServletRequest
* (only necessary when actually accessing the request)
*/
public MockPageContext(@Nullable ServletContext servletContext, @Nullable HttpServletRequest request) {
this(servletContext, request, null, null);
}
/**
* Create new MockPageContext with a MockServletConfig.
* @param servletContext the ServletContext that the JSP page runs in
* @param request the current HttpServletRequest
* @param response the current HttpServletResponse
* (only necessary when actually writing to the response)
*/
public MockPageContext(@Nullable ServletContext servletContext, @Nullable HttpServletRequest request,
@Nullable HttpServletResponse response) {
this(servletContext, request, response, null);
}
/**
* Create new MockServletConfig.
* @param servletContext the ServletContext that the JSP page runs in
* @param request the current HttpServletRequest
* @param response the current HttpServletResponse
* @param servletConfig the ServletConfig (hardly ever accessed from within a tag)
*/
public MockPageContext(@Nullable ServletContext servletContext, @Nullable HttpServletRequest request,
@Nullable HttpServletResponse response, @Nullable ServletConfig servletConfig) {
this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
this.request = (request != null ? request : new MockHttpServletRequest(servletContext));
this.response = (response != null ? response : new MockHttpServletResponse());
this.servletConfig = (servletConfig != null ? servletConfig : new MockServletConfig(servletContext));
}
@Override
public void initialize(
Servlet servlet, ServletRequest request, ServletResponse response,
String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) {
throw new UnsupportedOperationException("Use appropriate constructor");
}
@Override
public void release() {
}
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Attribute name must not be null");
if (value != null) {
this.attributes.put(name, value);
}
else {
this.attributes.remove(name);
}
}
@Override
public void setAttribute(String name, @Nullable Object value, int scope) {
Assert.notNull(name, "Attribute name must not be null");
switch (scope) {
case PAGE_SCOPE:
setAttribute(name, value);
break;
case REQUEST_SCOPE:
this.request.setAttribute(name, value);
break;
case SESSION_SCOPE:
this.request.getSession().setAttribute(name, value);
break;
case APPLICATION_SCOPE:
this.servletContext.setAttribute(name, value);
break;
default:
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
@Override
@Nullable
public Object getAttribute(String name) {
Assert.notNull(name, "Attribute name must not be null");
return this.attributes.get(name);
}
@Override
@Nullable
public Object getAttribute(String name, int scope) {
Assert.notNull(name, "Attribute name must not be null");
switch (scope) {
case PAGE_SCOPE:
return getAttribute(name);
case REQUEST_SCOPE:
return this.request.getAttribute(name);
case SESSION_SCOPE:
HttpSession session = this.request.getSession(false);
return (session != null ? session.getAttribute(name) : null);
case APPLICATION_SCOPE:
return this.servletContext.getAttribute(name);
default:
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
@Override
@Nullable
public Object findAttribute(String name) {
Object value = getAttribute(name);
if (value == null) {
value = getAttribute(name, REQUEST_SCOPE);
if (value == null) {
value = getAttribute(name, SESSION_SCOPE);
if (value == null) {
value = getAttribute(name, APPLICATION_SCOPE);
}
}
}
return value;
}
@Override
public void removeAttribute(String name) {
Assert.notNull(name, "Attribute name must not be null");
this.removeAttribute(name, PageContext.PAGE_SCOPE);
this.removeAttribute(name, PageContext.REQUEST_SCOPE);
this.removeAttribute(name, PageContext.SESSION_SCOPE);
this.removeAttribute(name, PageContext.APPLICATION_SCOPE);
}
@Override
public void removeAttribute(String name, int scope) {
Assert.notNull(name, "Attribute name must not be null");
switch (scope) {
case PAGE_SCOPE:
this.attributes.remove(name);
break;
case REQUEST_SCOPE:
this.request.removeAttribute(name);
break;
case SESSION_SCOPE:
this.request.getSession().removeAttribute(name);
break;
case APPLICATION_SCOPE:
this.servletContext.removeAttribute(name);
break;
default:
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
@Override
public int getAttributesScope(String name) {
if (getAttribute(name) != null) {
return PAGE_SCOPE;
}
else if (getAttribute(name, REQUEST_SCOPE) != null) {
return REQUEST_SCOPE;
}
else if (getAttribute(name, SESSION_SCOPE) != null) {
return SESSION_SCOPE;
}
else if (getAttribute(name, APPLICATION_SCOPE) != null) {
return APPLICATION_SCOPE;
}
else {
return 0;
}
}
public Enumeration<String> getAttributeNames() {
return Collections.enumeration(new LinkedHashSet<>(this.attributes.keySet()));
}
@Override
public Enumeration<String> getAttributeNamesInScope(int scope) {
switch (scope) {
case PAGE_SCOPE:
return getAttributeNames();
case REQUEST_SCOPE:
return this.request.getAttributeNames();
case SESSION_SCOPE:
HttpSession session = this.request.getSession(false);
return (session != null ? session.getAttributeNames() : Collections.emptyEnumeration());
case APPLICATION_SCOPE:
return this.servletContext.getAttributeNames();
default:
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
@Override
public JspWriter getOut() {
if (this.out == null) {
this.out = new MockJspWriter(this.response);
}
return this.out;
}
@Override
@Deprecated
public javax.servlet.jsp.el.ExpressionEvaluator getExpressionEvaluator() {
return new MockExpressionEvaluator(this);
}
@Override
@Nullable
public ELContext getELContext() {
return null;
}
@Override
@Deprecated
@Nullable
public javax.servlet.jsp.el.VariableResolver getVariableResolver() {
return null;
}
@Override
public HttpSession getSession() {
return this.request.getSession();
}
@Override
public Object getPage() {
return this;
}
@Override
public ServletRequest getRequest() {
return this.request;
}
@Override
public ServletResponse getResponse() {
return this.response;
}
@Override
@Nullable
public Exception getException() {
return null;
}
@Override
public ServletConfig getServletConfig() {
return this.servletConfig;
}
@Override
public ServletContext getServletContext() {
return this.servletContext;
}
@Override
public void forward(String path) throws ServletException, IOException {
this.request.getRequestDispatcher(path).forward(this.request, this.response);
}
@Override
public void include(String path) throws ServletException, IOException {
this.request.getRequestDispatcher(path).include(this.request, this.response);
}
@Override
public void include(String path, boolean flush) throws ServletException, IOException {
this.request.getRequestDispatcher(path).include(this.request, this.response);
if (flush) {
this.response.flushBuffer();
}
}
public byte[] getContentAsByteArray() {
Assert.state(this.response instanceof MockHttpServletResponse, "MockHttpServletResponse required");
return ((MockHttpServletResponse) this.response).getContentAsByteArray();
}
public String getContentAsString() throws UnsupportedEncodingException {
Assert.state(this.response instanceof MockHttpServletResponse, "MockHttpServletResponse required");
return ((MockHttpServletResponse) this.response).getContentAsString();
}
@Override
public void handlePageException(Exception ex) throws ServletException, IOException {
throw new ServletException("Page exception", ex);
}
@Override
public void handlePageException(Throwable ex) throws ServletException, IOException {
throw new ServletException("Page exception", ex);
}
}

View File

@@ -1,137 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import javax.servlet.http.Part;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Mock implementation of {@code javax.servlet.http.Part}.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
* @see MockHttpServletRequest#addPart
* @see MockMultipartFile
*/
public class MockPart implements Part {
private final String name;
@Nullable
private final String filename;
private final byte[] content;
private final HttpHeaders headers = new HttpHeaders();
/**
* Constructor for a part with byte[] content only.
* @see #getHeaders()
*/
public MockPart(String name, @Nullable byte[] content) {
this(name, null, content);
}
/**
* Constructor for a part with a filename and byte[] content.
* @see #getHeaders()
*/
public MockPart(String name, @Nullable String filename, @Nullable byte[] content) {
Assert.hasLength(name, "'name' must not be empty");
this.name = name;
this.filename = filename;
this.content = (content != null ? content : new byte[0]);
this.headers.setContentDispositionFormData(name, filename);
}
@Override
public String getName() {
return this.name;
}
@Override
@Nullable
public String getSubmittedFileName() {
return this.filename;
}
@Override
@Nullable
public String getContentType() {
MediaType contentType = this.headers.getContentType();
return (contentType != null ? contentType.toString() : null);
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(this.content);
}
@Override
public void write(String fileName) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void delete() throws IOException {
throw new UnsupportedOperationException();
}
@Override
@Nullable
public String getHeader(String name) {
return this.headers.getFirst(name);
}
@Override
public Collection<String> getHeaders(String name) {
Collection<String> headerValues = this.headers.get(name);
return (headerValues != null ? headerValues : Collections.emptyList());
}
@Override
public Collection<String> getHeaderNames() {
return this.headers.keySet();
}
/**
* Return the {@link HttpHeaders} backing header related accessor methods,
* allowing for populating selected header entries.
*/
public final HttpHeaders getHeaders() {
return this.headers;
}
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.RequestDispatcher} interface.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since 1.0.2
* @see MockHttpServletRequest#getRequestDispatcher(String)
*/
public class MockRequestDispatcher implements RequestDispatcher {
private final Log logger = LogFactory.getLog(getClass());
private final String resource;
/**
* Create a new MockRequestDispatcher for the given resource.
* @param resource the server resource to dispatch to, located at a
* particular path or given by a particular name
*/
public MockRequestDispatcher(String resource) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
}
@Override
public void forward(ServletRequest request, ServletResponse response) {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
Assert.state(!response.isCommitted(), "Cannot perform forward - response is already committed");
getMockHttpServletResponse(response).setForwardedUrl(this.resource);
if (logger.isDebugEnabled()) {
logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]");
}
}
@Override
public void include(ServletRequest request, ServletResponse response) {
Assert.notNull(request, "Request must not be null");
Assert.notNull(response, "Response must not be null");
getMockHttpServletResponse(response).addIncludedUrl(this.resource);
if (logger.isDebugEnabled()) {
logger.debug("MockRequestDispatcher: including [" + this.resource + "]");
}
}
/**
* Obtain the underlying {@link MockHttpServletResponse}, unwrapping
* {@link HttpServletResponseWrapper} decorators if necessary.
*/
protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) {
if (response instanceof MockHttpServletResponse) {
return (MockHttpServletResponse) response;
}
if (response instanceof HttpServletResponseWrapper) {
return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse());
}
throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse");
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.ServletConfig} interface.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 1.0.2
*/
public class MockServletConfig implements ServletConfig {
private final ServletContext servletContext;
private final String servletName;
private final Map<String, String> initParameters = new LinkedHashMap<>();
/**
* Create a new MockServletConfig with a default {@link MockServletContext}.
*/
public MockServletConfig() {
this(null, "");
}
/**
* Create a new MockServletConfig with a default {@link MockServletContext}.
* @param servletName the name of the servlet
*/
public MockServletConfig(String servletName) {
this(null, servletName);
}
/**
* Create a new MockServletConfig.
* @param servletContext the ServletContext that the servlet runs in
*/
public MockServletConfig(@Nullable ServletContext servletContext) {
this(servletContext, "");
}
/**
* Create a new MockServletConfig.
* @param servletContext the ServletContext that the servlet runs in
* @param servletName the name of the servlet
*/
public MockServletConfig(@Nullable ServletContext servletContext, String servletName) {
this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
this.servletName = servletName;
}
@Override
public String getServletName() {
return this.servletName;
}
@Override
public ServletContext getServletContext() {
return this.servletContext;
}
public void addInitParameter(String name, String value) {
Assert.notNull(name, "Parameter name must not be null");
this.initParameters.put(name, value);
}
@Override
public String getInitParameter(String name) {
Assert.notNull(name, "Parameter name must not be null");
return this.initParameters.get(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(this.initParameters.keySet());
}
}

View File

@@ -1,747 +0,0 @@
/*
* Copyright 2002-2019 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
*
* https://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.mock.web.test;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.InvalidPathException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeType;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.ServletContext} interface.
*
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* <p>Compatible with Servlet 3.1 but can be configured to expose a specific version
* through {@link #setMajorVersion}/{@link #setMinorVersion}; default is 3.1.
* Note that Servlet 3.1 support is limited: servlet, filter and listener
* registration methods are not supported; neither is JSP configuration.
* We generally do not recommend to unit test your ServletContainerInitializers and
* WebApplicationInitializers which is where those registration methods would be used.
*
* <p>For setting up a full {@code WebApplicationContext} in a test environment, you can
* use {@code AnnotationConfigWebApplicationContext}, {@code XmlWebApplicationContext},
* or {@code GenericWebApplicationContext}, passing in a corresponding
* {@code MockServletContext} instance. Consider configuring your
* {@code MockServletContext} with a {@code FileSystemResourceLoader} in order to
* interpret resource paths as relative filesystem locations.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since 1.0.2
* @see #MockServletContext(org.springframework.core.io.ResourceLoader)
* @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext
* @see org.springframework.web.context.support.XmlWebApplicationContext
* @see org.springframework.web.context.support.GenericWebApplicationContext
*/
public class MockServletContext implements ServletContext {
/** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */
private static final String COMMON_DEFAULT_SERVLET_NAME = "default";
private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir";
private static final Set<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES = new LinkedHashSet<>(4);
static {
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.COOKIE);
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.URL);
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.SSL);
}
private final Log logger = LogFactory.getLog(getClass());
private final ResourceLoader resourceLoader;
private final String resourceBasePath;
private String contextPath = "";
private final Map<String, ServletContext> contexts = new HashMap<>();
private int majorVersion = 3;
private int minorVersion = 1;
private int effectiveMajorVersion = 3;
private int effectiveMinorVersion = 1;
private final Map<String, RequestDispatcher> namedRequestDispatchers = new HashMap<>();
private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
private final Map<String, String> initParameters = new LinkedHashMap<>();
private final Map<String, Object> attributes = new LinkedHashMap<>();
private String servletContextName = "MockServletContext";
private final Set<String> declaredRoles = new LinkedHashSet<>();
@Nullable
private Set<SessionTrackingMode> sessionTrackingModes;
private final SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig();
private int sessionTimeout;
@Nullable
private String requestCharacterEncoding;
@Nullable
private String responseCharacterEncoding;
private final Map<String, MediaType> mimeTypes = new LinkedHashMap<>();
/**
* Create a new {@code MockServletContext}, using no base path and a
* {@link DefaultResourceLoader} (i.e. the classpath root as WAR root).
* @see org.springframework.core.io.DefaultResourceLoader
*/
public MockServletContext() {
this("", null);
}
/**
* Create a new {@code MockServletContext}, using a {@link DefaultResourceLoader}.
* @param resourceBasePath the root directory of the WAR (should not end with a slash)
* @see org.springframework.core.io.DefaultResourceLoader
*/
public MockServletContext(String resourceBasePath) {
this(resourceBasePath, null);
}
/**
* Create a new {@code MockServletContext}, using the specified {@link ResourceLoader}
* and no base path.
* @param resourceLoader the ResourceLoader to use (or null for the default)
*/
public MockServletContext(@Nullable ResourceLoader resourceLoader) {
this("", resourceLoader);
}
/**
* Create a new {@code MockServletContext} using the supplied resource base
* path and resource loader.
* <p>Registers a {@link MockRequestDispatcher} for the Servlet named
* {@literal 'default'}.
* @param resourceBasePath the root directory of the WAR (should not end with a slash)
* @param resourceLoader the ResourceLoader to use (or null for the default)
* @see #registerNamedDispatcher
*/
public MockServletContext(String resourceBasePath, @Nullable ResourceLoader resourceLoader) {
this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
this.resourceBasePath = resourceBasePath;
// Use JVM temp dir as ServletContext temp dir.
String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY);
if (tempDir != null) {
this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir));
}
registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName));
}
/**
* Build a full resource location for the given path, prepending the resource
* base path of this {@code MockServletContext}.
* @param path the path as specified
* @return the full resource path
*/
protected String getResourceLocation(String path) {
if (!path.startsWith("/")) {
path = "/" + path;
}
return this.resourceBasePath + path;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
@Override
public String getContextPath() {
return this.contextPath;
}
public void registerContext(String contextPath, ServletContext context) {
this.contexts.put(contextPath, context);
}
@Override
public ServletContext getContext(String contextPath) {
if (this.contextPath.equals(contextPath)) {
return this;
}
return this.contexts.get(contextPath);
}
public void setMajorVersion(int majorVersion) {
this.majorVersion = majorVersion;
}
@Override
public int getMajorVersion() {
return this.majorVersion;
}
public void setMinorVersion(int minorVersion) {
this.minorVersion = minorVersion;
}
@Override
public int getMinorVersion() {
return this.minorVersion;
}
public void setEffectiveMajorVersion(int effectiveMajorVersion) {
this.effectiveMajorVersion = effectiveMajorVersion;
}
@Override
public int getEffectiveMajorVersion() {
return this.effectiveMajorVersion;
}
public void setEffectiveMinorVersion(int effectiveMinorVersion) {
this.effectiveMinorVersion = effectiveMinorVersion;
}
@Override
public int getEffectiveMinorVersion() {
return this.effectiveMinorVersion;
}
@Override
@Nullable
public String getMimeType(String filePath) {
String extension = StringUtils.getFilenameExtension(filePath);
if (this.mimeTypes.containsKey(extension)) {
return this.mimeTypes.get(extension).toString();
}
else {
return MediaTypeFactory.getMediaType(filePath).
map(MimeType::toString)
.orElse(null);
}
}
/**
* Adds a mime type mapping for use by {@link #getMimeType(String)}.
* @param fileExtension a file extension, such as {@code txt}, {@code gif}
* @param mimeType the mime type
*/
public void addMimeType(String fileExtension, MediaType mimeType) {
Assert.notNull(fileExtension, "'fileExtension' must not be null");
this.mimeTypes.put(fileExtension, mimeType);
}
@Override
@Nullable
public Set<String> getResourcePaths(String path) {
String actualPath = (path.endsWith("/") ? path : path + "/");
String resourceLocation = getResourceLocation(actualPath);
Resource resource = null;
try {
resource = this.resourceLoader.getResource(resourceLocation);
File file = resource.getFile();
String[] fileList = file.list();
if (ObjectUtils.isEmpty(fileList)) {
return null;
}
Set<String> resourcePaths = new LinkedHashSet<>(fileList.length);
for (String fileEntry : fileList) {
String resultPath = actualPath + fileEntry;
if (resource.createRelative(fileEntry).getFile().isDirectory()) {
resultPath += "/";
}
resourcePaths.add(resultPath);
}
return resourcePaths;
}
catch (InvalidPathException | IOException ex ) {
if (logger.isWarnEnabled()) {
logger.warn("Could not get resource paths for " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
}
}
@Override
@Nullable
public URL getResource(String path) throws MalformedURLException {
String resourceLocation = getResourceLocation(path);
Resource resource = null;
try {
resource = this.resourceLoader.getResource(resourceLocation);
if (!resource.exists()) {
return null;
}
return resource.getURL();
}
catch (MalformedURLException ex) {
throw ex;
}
catch (InvalidPathException | IOException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not get URL for resource " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
}
}
@Override
@Nullable
public InputStream getResourceAsStream(String path) {
String resourceLocation = getResourceLocation(path);
Resource resource = null;
try {
resource = this.resourceLoader.getResource(resourceLocation);
if (!resource.exists()) {
return null;
}
return resource.getInputStream();
}
catch (InvalidPathException | IOException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not open InputStream for resource " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
}
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
Assert.isTrue(path.startsWith("/"),
() -> "RequestDispatcher path [" + path + "] at ServletContext level must start with '/'");
return new MockRequestDispatcher(path);
}
@Override
public RequestDispatcher getNamedDispatcher(String path) {
return this.namedRequestDispatchers.get(path);
}
/**
* Register a {@link RequestDispatcher} (typically a {@link MockRequestDispatcher})
* that acts as a wrapper for the named Servlet.
* @param name the name of the wrapped Servlet
* @param requestDispatcher the dispatcher that wraps the named Servlet
* @see #getNamedDispatcher
* @see #unregisterNamedDispatcher
*/
public void registerNamedDispatcher(String name, RequestDispatcher requestDispatcher) {
Assert.notNull(name, "RequestDispatcher name must not be null");
Assert.notNull(requestDispatcher, "RequestDispatcher must not be null");
this.namedRequestDispatchers.put(name, requestDispatcher);
}
/**
* Unregister the {@link RequestDispatcher} with the given name.
* @param name the name of the dispatcher to unregister
* @see #getNamedDispatcher
* @see #registerNamedDispatcher
*/
public void unregisterNamedDispatcher(String name) {
Assert.notNull(name, "RequestDispatcher name must not be null");
this.namedRequestDispatchers.remove(name);
}
/**
* Get the name of the <em>default</em> {@code Servlet}.
* <p>Defaults to {@literal 'default'}.
* @see #setDefaultServletName
*/
public String getDefaultServletName() {
return this.defaultServletName;
}
/**
* Set the name of the <em>default</em> {@code Servlet}.
* <p>Also {@link #unregisterNamedDispatcher unregisters} the current default
* {@link RequestDispatcher} and {@link #registerNamedDispatcher replaces}
* it with a {@link MockRequestDispatcher} for the provided
* {@code defaultServletName}.
* @param defaultServletName the name of the <em>default</em> {@code Servlet};
* never {@code null} or empty
* @see #getDefaultServletName
*/
public void setDefaultServletName(String defaultServletName) {
Assert.hasText(defaultServletName, "defaultServletName must not be null or empty");
unregisterNamedDispatcher(this.defaultServletName);
this.defaultServletName = defaultServletName;
registerNamedDispatcher(this.defaultServletName, new MockRequestDispatcher(this.defaultServletName));
}
@Deprecated
@Override
@Nullable
public Servlet getServlet(String name) {
return null;
}
@Override
@Deprecated
public Enumeration<Servlet> getServlets() {
return Collections.enumeration(Collections.emptySet());
}
@Override
@Deprecated
public Enumeration<String> getServletNames() {
return Collections.enumeration(Collections.emptySet());
}
@Override
public void log(String message) {
logger.info(message);
}
@Override
@Deprecated
public void log(Exception ex, String message) {
logger.info(message, ex);
}
@Override
public void log(String message, Throwable ex) {
logger.info(message, ex);
}
@Override
@Nullable
public String getRealPath(String path) {
String resourceLocation = getResourceLocation(path);
Resource resource = null;
try {
resource = this.resourceLoader.getResource(resourceLocation);
return resource.getFile().getAbsolutePath();
}
catch (InvalidPathException | IOException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Could not determine real path of resource " +
(resource != null ? resource : resourceLocation), ex);
}
return null;
}
}
@Override
public String getServerInfo() {
return "MockServletContext";
}
@Override
public String getInitParameter(String name) {
Assert.notNull(name, "Parameter name must not be null");
return this.initParameters.get(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(this.initParameters.keySet());
}
@Override
public boolean setInitParameter(String name, String value) {
Assert.notNull(name, "Parameter name must not be null");
if (this.initParameters.containsKey(name)) {
return false;
}
this.initParameters.put(name, value);
return true;
}
public void addInitParameter(String name, String value) {
Assert.notNull(name, "Parameter name must not be null");
this.initParameters.put(name, value);
}
@Override
@Nullable
public Object getAttribute(String name) {
Assert.notNull(name, "Attribute name must not be null");
return this.attributes.get(name);
}
@Override
public Enumeration<String> getAttributeNames() {
return Collections.enumeration(new LinkedHashSet<>(this.attributes.keySet()));
}
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Attribute name must not be null");
if (value != null) {
this.attributes.put(name, value);
}
else {
this.attributes.remove(name);
}
}
@Override
public void removeAttribute(String name) {
Assert.notNull(name, "Attribute name must not be null");
this.attributes.remove(name);
}
public void setServletContextName(String servletContextName) {
this.servletContextName = servletContextName;
}
@Override
public String getServletContextName() {
return this.servletContextName;
}
@Override
@Nullable
public ClassLoader getClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
@Override
public void declareRoles(String... roleNames) {
Assert.notNull(roleNames, "Role names array must not be null");
for (String roleName : roleNames) {
Assert.hasLength(roleName, "Role name must not be empty");
this.declaredRoles.add(roleName);
}
}
public Set<String> getDeclaredRoles() {
return Collections.unmodifiableSet(this.declaredRoles);
}
@Override
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
throws IllegalStateException, IllegalArgumentException {
this.sessionTrackingModes = sessionTrackingModes;
}
@Override
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
return DEFAULT_SESSION_TRACKING_MODES;
}
@Override
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
return (this.sessionTrackingModes != null ?
Collections.unmodifiableSet(this.sessionTrackingModes) : DEFAULT_SESSION_TRACKING_MODES);
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
return this.sessionCookieConfig;
}
@Override // on Servlet 4.0
public void setSessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
@Override // on Servlet 4.0
public int getSessionTimeout() {
return this.sessionTimeout;
}
@Override // on Servlet 4.0
public void setRequestCharacterEncoding(@Nullable String requestCharacterEncoding) {
this.requestCharacterEncoding = requestCharacterEncoding;
}
@Override // on Servlet 4.0
@Nullable
public String getRequestCharacterEncoding() {
return this.requestCharacterEncoding;
}
@Override // on Servlet 4.0
public void setResponseCharacterEncoding(@Nullable String responseCharacterEncoding) {
this.responseCharacterEncoding = responseCharacterEncoding;
}
@Override // on Servlet 4.0
@Nullable
public String getResponseCharacterEncoding() {
return this.responseCharacterEncoding;
}
//---------------------------------------------------------------------
// Unsupported Servlet 3.0 registration methods
//---------------------------------------------------------------------
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
throw new UnsupportedOperationException();
}
@Override // on Servlet 4.0
public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
throw new UnsupportedOperationException();
}
@Override
public <T extends Servlet> T createServlet(Class<T> c) throws ServletException {
throw new UnsupportedOperationException();
}
/**
* This method always returns {@code null}.
* @see javax.servlet.ServletContext#getServletRegistration(java.lang.String)
*/
@Override
@Nullable
public ServletRegistration getServletRegistration(String servletName) {
return null;
}
/**
* This method always returns an {@linkplain Collections#emptyMap empty map}.
* @see javax.servlet.ServletContext#getServletRegistrations()
*/
@Override
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
return Collections.emptyMap();
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
throw new UnsupportedOperationException();
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
throw new UnsupportedOperationException();
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
throw new UnsupportedOperationException();
}
@Override
public <T extends Filter> T createFilter(Class<T> c) throws ServletException {
throw new UnsupportedOperationException();
}
/**
* This method always returns {@code null}.
* @see javax.servlet.ServletContext#getFilterRegistration(java.lang.String)
*/
@Override
@Nullable
public FilterRegistration getFilterRegistration(String filterName) {
return null;
}
/**
* This method always returns an {@linkplain Collections#emptyMap empty map}.
* @see javax.servlet.ServletContext#getFilterRegistrations()
*/
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
return Collections.emptyMap();
}
@Override
public void addListener(Class<? extends EventListener> listenerClass) {
throw new UnsupportedOperationException();
}
@Override
public void addListener(String className) {
throw new UnsupportedOperationException();
}
@Override
public <T extends EventListener> void addListener(T t) {
throw new UnsupportedOperationException();
}
@Override
public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public String getVirtualServerName() {
throw new UnsupportedOperationException();
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import javax.servlet.SessionCookieConfig;
import org.springframework.lang.Nullable;
/**
* Mock implementation of the {@link javax.servlet.SessionCookieConfig} interface.
*
* @author Juergen Hoeller
* @since 4.0
* @see javax.servlet.ServletContext#getSessionCookieConfig()
*/
public class MockSessionCookieConfig implements SessionCookieConfig {
@Nullable
private String name;
@Nullable
private String domain;
@Nullable
private String path;
@Nullable
private String comment;
private boolean httpOnly;
private boolean secure;
private int maxAge = -1;
@Override
public void setName(@Nullable String name) {
this.name = name;
}
@Override
@Nullable
public String getName() {
return this.name;
}
@Override
public void setDomain(@Nullable String domain) {
this.domain = domain;
}
@Override
@Nullable
public String getDomain() {
return this.domain;
}
@Override
public void setPath(@Nullable String path) {
this.path = path;
}
@Override
@Nullable
public String getPath() {
return this.path;
}
@Override
public void setComment(@Nullable String comment) {
this.comment = comment;
}
@Override
@Nullable
public String getComment() {
return this.comment;
}
@Override
public void setHttpOnly(boolean httpOnly) {
this.httpOnly = httpOnly;
}
@Override
public boolean isHttpOnly() {
return this.httpOnly;
}
@Override
public void setSecure(boolean secure) {
this.secure = secure;
}
@Override
public boolean isSecure() {
return this.secure;
}
@Override
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
@Override
public int getMaxAge() {
return this.maxAge;
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Implementation of the {@link javax.servlet.FilterConfig} interface which
* simply passes the call through to a given Filter/FilterChain combination
* (indicating the next Filter in the chain along with the FilterChain that it is
* supposed to work on) or to a given Servlet (indicating the end of the chain).
*
* @author Juergen Hoeller
* @since 2.0.3
* @see javax.servlet.Filter
* @see javax.servlet.Servlet
* @see MockFilterChain
*/
public class PassThroughFilterChain implements FilterChain {
@Nullable
private Filter filter;
@Nullable
private FilterChain nextFilterChain;
@Nullable
private Servlet servlet;
/**
* Create a new PassThroughFilterChain that delegates to the given Filter,
* calling it with the given FilterChain.
* @param filter the Filter to delegate to
* @param nextFilterChain the FilterChain to use for that next Filter
*/
public PassThroughFilterChain(Filter filter, FilterChain nextFilterChain) {
Assert.notNull(filter, "Filter must not be null");
Assert.notNull(nextFilterChain, "'FilterChain must not be null");
this.filter = filter;
this.nextFilterChain = nextFilterChain;
}
/**
* Create a new PassThroughFilterChain that delegates to the given Servlet.
* @param servlet the Servlet to delegate to
*/
public PassThroughFilterChain(Servlet servlet) {
Assert.notNull(servlet, "Servlet must not be null");
this.servlet = servlet;
}
/**
* Pass the call on to the Filter/Servlet.
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws ServletException, IOException {
if (this.filter != null) {
this.filter.doFilter(request, response, this.nextFilterChain);
}
else {
Assert.state(this.servlet != null, "Neither a Filter not a Servlet set");
this.servlet.service(request, response);
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test.server;
import reactor.core.publisher.Mono;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.server.WebSession;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;
import org.springframework.web.server.session.DefaultWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
/**
* Extension of {@link DefaultServerWebExchange} for use in tests, along with
* {@link MockServerHttpRequest} and {@link MockServerHttpResponse}.
*
* <p>See static factory methods to create an instance.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public final class MockServerWebExchange extends DefaultServerWebExchange {
private MockServerWebExchange(MockServerHttpRequest request, WebSessionManager sessionManager) {
super(request, new MockServerHttpResponse(), sessionManager,
ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
}
@Override
public MockServerHttpResponse getResponse() {
return (MockServerHttpResponse) super.getResponse();
}
/**
* Create a {@link MockServerWebExchange} from the given mock request.
* @param request the request to use.
* @return the exchange
*/
public static MockServerWebExchange from(MockServerHttpRequest request) {
return builder(request).build();
}
/**
* Variant of {@link #from(MockServerHttpRequest)} with a mock request builder.
* @param requestBuilder the builder for the mock request.
* @return the exchange
*/
public static MockServerWebExchange from(MockServerHttpRequest.BaseBuilder<?> requestBuilder) {
return builder(requestBuilder).build();
}
/**
* Create a {@link Builder} starting with the given mock request.
* @param request the request to use.
* @return the exchange builder
* @since 5.1
*/
public static MockServerWebExchange.Builder builder(MockServerHttpRequest request) {
return new MockServerWebExchange.Builder(request);
}
/**
* Variant of {@link #builder(MockServerHttpRequest)} with a mock request builder.
* @param requestBuilder the builder for the mock request.
* @return the exchange builder
* @since 5.1
*/
public static MockServerWebExchange.Builder builder(MockServerHttpRequest.BaseBuilder<?> requestBuilder) {
return new MockServerWebExchange.Builder(requestBuilder.build());
}
/**
* Builder for a {@link MockServerWebExchange}.
* @since 5.1
*/
public static class Builder {
private final MockServerHttpRequest request;
@Nullable
private WebSessionManager sessionManager;
public Builder(MockServerHttpRequest request) {
this.request = request;
}
/**
* Set the session to use for the exchange.
* <p>This is mutually exclusive with {@link #sessionManager(WebSessionManager)}.
* @param session the session to use
*/
public Builder session(WebSession session) {
this.sessionManager = exchange -> Mono.just(session);
return this;
}
/**
* Provide a {@code WebSessionManager} instance to use with the exchange.
* <p>This is mutually exclusive with {@link #session(WebSession)}.
* @param sessionManager the session manager to use
*/
public Builder sessionManager(WebSessionManager sessionManager) {
this.sessionManager = sessionManager;
return this;
}
/**
* Build the {@code MockServerWebExchange} instance.
*/
public MockServerWebExchange build() {
return new MockServerWebExchange(this.request,
this.sessionManager != null ? this.sessionManager : new DefaultWebSessionManager());
}
}
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright 2002-2018 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
*
* https://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.mock.web.test.server;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import reactor.core.publisher.Mono;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.server.WebSession;
import org.springframework.web.server.session.InMemoryWebSessionStore;
/**
* Implementation of {@code WebSession} that delegates to a session instance
* obtained via {@link InMemoryWebSessionStore}.
*
* <p>This is intended for use with the
* {@link MockServerWebExchange.Builder#session(WebSession) session(WebSession)}
* method of the {@code MockServerWebExchange} builder, eliminating the need
* to use {@code WebSessionManager} or {@code WebSessionStore} altogether.
*
* @author Rossen Stoyanchev
* @since 5.1
*/
public class MockWebSession implements WebSession {
private final WebSession delegate;
public MockWebSession() {
this(null);
}
public MockWebSession(@Nullable Clock clock) {
InMemoryWebSessionStore sessionStore = new InMemoryWebSessionStore();
if (clock != null) {
sessionStore.setClock(clock);
}
WebSession session = sessionStore.createWebSession().block();
Assert.state(session != null, "WebSession must not be null");
this.delegate = session;
}
@Override
public String getId() {
return this.delegate.getId();
}
@Override
public Map<String, Object> getAttributes() {
return this.delegate.getAttributes();
}
@Override
public void start() {
this.delegate.start();
}
@Override
public boolean isStarted() {
return this.delegate.isStarted();
}
@Override
public Mono<Void> changeSessionId() {
return this.delegate.changeSessionId();
}
@Override
public Mono<Void> invalidate() {
return this.delegate.invalidate();
}
@Override
public Mono<Void> save() {
return this.delegate.save();
}
@Override
public boolean isExpired() {
return this.delegate.isExpired();
}
@Override
public Instant getCreationTime() {
return this.delegate.getCreationTime();
}
@Override
public Instant getLastAccessTime() {
return this.delegate.getLastAccessTime();
}
@Override
public void setMaxIdleTime(Duration maxIdleTime) {
this.delegate.setMaxIdleTime(maxIdleTime);
}
@Override
public Duration getMaxIdleTime() {
return this.delegate.getMaxIdleTime();
}
}

View File

@@ -1,9 +0,0 @@
/**
* For @NonNull annotations on implementation classes
*/
@NonNullApi
@NonNullFields
package org.springframework.mock.web.test.server;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -39,13 +39,13 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.support.DefaultRemoteInvocationExecutor;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationFactory;
import org.springframework.remoting.support.RemoteInvocationResult;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -26,12 +26,12 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -21,10 +21,10 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -24,10 +24,10 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -27,7 +27,7 @@ import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -19,8 +19,8 @@ package org.springframework.web.bind;
import org.junit.jupiter.api.Test;
import org.springframework.core.testfixture.EnabledForTestGroups;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.util.StopWatch;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -34,12 +34,12 @@ import org.springframework.http.MediaType;
import org.springframework.http.codec.FormHttpMessageWriter;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.codec.multipart.MultipartHttpMessageWriter;
import org.springframework.mock.http.client.reactive.test.MockClientHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.testfixture.http.client.reactive.MockClientHttpRequest;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.server.MockServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.ResolvableType.forClass;
@@ -198,7 +198,7 @@ public class WebExchangeDataBinderTests {
data.add("someArray", "456");
data.add("part", new ClassPathResource("org/springframework/http/codec/multipart/foo.txt"));
data.add("somePartList", new ClassPathResource("org/springframework/http/codec/multipart/foo.txt"));
data.add("somePartList", new ClassPathResource("org/springframework/http/server/reactive/spring.png"));
data.add("somePartList", new ClassPathResource("/org/springframework/web/spring.png"));
binder.bind(exchangeMultipart(data)).block(Duration.ofMillis(5000));
assertThat(bean.getName()).isEqualTo("bar");

View File

@@ -29,12 +29,12 @@ import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockMultipartFile;
import org.springframework.mock.web.test.MockMultipartHttpServletRequest;
import org.springframework.web.bind.ServletRequestParameterPropertyValues;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.multipart.support.StringMultipartFileEditor;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockMultipartFile;
import org.springframework.web.testfixture.servlet.MockMultipartHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -24,9 +24,9 @@ import javax.servlet.ServletException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -23,9 +23,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -21,8 +21,8 @@ import javax.servlet.ServletRequestEvent;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.MockRunnable;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -29,7 +29,7 @@ import org.springframework.beans.testfixture.beans.DerivedTestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -29,7 +29,7 @@ import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.beans.testfixture.beans.factory.DummyFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -24,8 +24,8 @@ import javax.servlet.http.HttpSession;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpSession;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

View File

@@ -26,8 +26,8 @@ import java.util.Date;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -29,9 +29,9 @@ import javax.servlet.http.HttpServletResponseWrapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -32,8 +32,8 @@ import org.springframework.beans.testfixture.beans.DerivedTestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.testfixture.io.SerializationTestUtils;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpSession;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpSession;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -22,11 +22,11 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.testfixture.beans.DerivedTestBean;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.web.context.ContextCleanupListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -23,9 +23,9 @@ import javax.servlet.AsyncEvent;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.test.MockAsyncContext;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockAsyncContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

View File

@@ -25,10 +25,10 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.mock.web.test.MockAsyncContext;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.testfixture.servlet.MockAsyncContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;

View File

@@ -26,7 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -25,10 +25,10 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.mock.web.test.MockAsyncContext;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.testfixture.servlet.MockAsyncContext;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;

View File

@@ -21,7 +21,7 @@ import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.Resource;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -21,9 +21,9 @@ import javax.servlet.ServletContextEvent;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

View File

@@ -24,8 +24,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.testfixture.beans.ITestBean;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.mock.web.test.MockServletContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.testfixture.servlet.MockServletContext;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -20,7 +20,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import static org.assertj.core.api.Assertions.assertThat;

View File

@@ -23,8 +23,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThat;

Some files were not shown because too many files have changed in this diff Show More