Isolate and reduce Spring Test dependencies
This commit splits Spring REST Docs into two projects – spring-restdocs-core and spring-restdocs-mockmvc. spring-restdocs-core contains the vast majority of the code but does not depend on a specific test framework other than JUnit. The use of a Spring Test TestExecutionListener has been replaced with a JUnit test rule. The rule is declared once per test class and configured with the output directory to which the generated snippets should be written. This simplifies the implementation as thread local storage is no longer required to transfer information about the test that’s running into Spring REST Docs. Instead, this transfer is now handled by the new test rule. It has also simplified the configuration as it’s no longer necessary for users to provide a system property that configures the output directory. spring-restdocs-mockmvc contains code that’s specific to using Spring REST Docs with Spring MVC Test’s MockMvc. This is currently the only testing framework that’s supported, but it paves the way for adding support for additional frameworks. REST Assured is one that users seem particularly interested in (see gh-80 and gh-102). Closes gh-107
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
/**
|
||||
* Abstract configurer that declares methods that are internal to the documentation
|
||||
* configuration implementation.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class AbstractConfigurer {
|
||||
|
||||
/**
|
||||
* Applies the configuration, possibly by modifying the given {@code request}
|
||||
* @param request the request that may be modified
|
||||
*/
|
||||
abstract void apply(MockHttpServletRequest request);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Base class for {@link NestedConfigurer} implementations.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @param <PARENT> The type of the configurer's parent
|
||||
*/
|
||||
abstract class AbstractNestedConfigurer<PARENT extends MockMvcConfigurer> extends
|
||||
AbstractConfigurer implements NestedConfigurer<PARENT>, MockMvcConfigurer {
|
||||
|
||||
private final PARENT parent;
|
||||
|
||||
protected AbstractNestedConfigurer(PARENT parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PARENT and() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConfigurerAdded(ConfigurableMockMvcBuilder<?> builder) {
|
||||
this.parent.afterConfigurerAdded(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPostProcessor beforeMockMvcCreated(
|
||||
ConfigurableMockMvcBuilder<?> builder, WebApplicationContext context) {
|
||||
return this.parent.beforeMockMvcCreated(builder, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import static org.springframework.restdocs.mockmvc.util.IterableEnumeration.iterable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockMultipartHttpServletRequest;
|
||||
import org.springframework.restdocs.operation.OperationRequest;
|
||||
import org.springframework.restdocs.operation.OperationRequestPart;
|
||||
import org.springframework.restdocs.operation.Parameters;
|
||||
import org.springframework.restdocs.operation.StandardOperationRequest;
|
||||
import org.springframework.restdocs.operation.StandardOperationRequestPart;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* A factory for creating an {@link OperationRequest} from a
|
||||
* {@link MockHttpServletRequest}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
*/
|
||||
class MockMvcOperationRequestFactory {
|
||||
|
||||
private static final String SCHEME_HTTP = "http";
|
||||
|
||||
private static final String SCHEME_HTTPS = "https";
|
||||
|
||||
private static final int STANDARD_PORT_HTTP = 80;
|
||||
|
||||
private static final int STANDARD_PORT_HTTPS = 443;
|
||||
|
||||
/**
|
||||
* Creates a new {@code OperationRequest} derived from the given {@code mockRequest}.
|
||||
*
|
||||
* @param mockRequest the request
|
||||
* @return the {@code OperationRequest}
|
||||
* @throws Exception if the request could not be created
|
||||
*/
|
||||
public OperationRequest createOperationRequest(MockHttpServletRequest mockRequest)
|
||||
throws Exception {
|
||||
HttpHeaders headers = extractHeaders(mockRequest);
|
||||
Parameters parameters = extractParameters(mockRequest);
|
||||
List<OperationRequestPart> parts = extractParts(mockRequest);
|
||||
String queryString = mockRequest.getQueryString();
|
||||
if (!StringUtils.hasText(queryString) && "GET".equals(mockRequest.getMethod())) {
|
||||
queryString = parameters.toQueryString();
|
||||
}
|
||||
return new StandardOperationRequest(URI.create(getRequestUri(mockRequest)
|
||||
+ (StringUtils.hasText(queryString) ? "?" + queryString : "")),
|
||||
HttpMethod.valueOf(mockRequest.getMethod()),
|
||||
FileCopyUtils.copyToByteArray(mockRequest.getInputStream()), headers,
|
||||
parameters, parts);
|
||||
}
|
||||
|
||||
private List<OperationRequestPart> extractParts(MockHttpServletRequest servletRequest)
|
||||
throws IOException, ServletException {
|
||||
List<OperationRequestPart> parts = new ArrayList<>();
|
||||
for (Part part : servletRequest.getParts()) {
|
||||
HttpHeaders partHeaders = extractHeaders(part);
|
||||
List<String> contentTypeHeader = partHeaders.get(HttpHeaders.CONTENT_TYPE);
|
||||
if (part.getContentType() != null && contentTypeHeader == null) {
|
||||
partHeaders
|
||||
.setContentType(MediaType.parseMediaType(part.getContentType()));
|
||||
}
|
||||
parts.add(new StandardOperationRequestPart(part.getName(), StringUtils
|
||||
.hasText(part.getSubmittedFileName()) ? part.getSubmittedFileName()
|
||||
: null, FileCopyUtils.copyToByteArray(part.getInputStream()),
|
||||
partHeaders));
|
||||
}
|
||||
if (servletRequest instanceof MockMultipartHttpServletRequest) {
|
||||
for (Entry<String, List<MultipartFile>> entry : ((MockMultipartHttpServletRequest) servletRequest)
|
||||
.getMultiFileMap().entrySet()) {
|
||||
for (MultipartFile file : entry.getValue()) {
|
||||
HttpHeaders partHeaders = new HttpHeaders();
|
||||
if (StringUtils.hasText(file.getContentType())) {
|
||||
partHeaders.setContentType(MediaType.parseMediaType(file
|
||||
.getContentType()));
|
||||
}
|
||||
parts.add(new StandardOperationRequestPart(file.getName(),
|
||||
StringUtils.hasText(file.getOriginalFilename()) ? file
|
||||
.getOriginalFilename() : null, file.getBytes(),
|
||||
partHeaders));
|
||||
}
|
||||
}
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
private HttpHeaders extractHeaders(Part part) {
|
||||
HttpHeaders partHeaders = new HttpHeaders();
|
||||
for (String headerName : part.getHeaderNames()) {
|
||||
for (String value : part.getHeaders(headerName)) {
|
||||
partHeaders.add(headerName, value);
|
||||
}
|
||||
}
|
||||
return partHeaders;
|
||||
}
|
||||
|
||||
private Parameters extractParameters(MockHttpServletRequest servletRequest) {
|
||||
Parameters parameters = new Parameters();
|
||||
for (String name : iterable(servletRequest.getParameterNames())) {
|
||||
for (String value : servletRequest.getParameterValues(name)) {
|
||||
parameters.add(name, value);
|
||||
}
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private HttpHeaders extractHeaders(MockHttpServletRequest servletRequest) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
for (String headerName : iterable(servletRequest.getHeaderNames())) {
|
||||
for (String value : iterable(servletRequest.getHeaders(headerName))) {
|
||||
headers.add(headerName, value);
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
private boolean isNonStandardPort(MockHttpServletRequest request) {
|
||||
return (SCHEME_HTTP.equals(request.getScheme()) && request.getServerPort() != STANDARD_PORT_HTTP)
|
||||
|| (SCHEME_HTTPS.equals(request.getScheme()) && request.getServerPort() != STANDARD_PORT_HTTPS);
|
||||
}
|
||||
|
||||
private String getRequestUri(MockHttpServletRequest request) {
|
||||
StringWriter uriWriter = new StringWriter();
|
||||
PrintWriter printer = new PrintWriter(uriWriter);
|
||||
|
||||
printer.printf("%s://%s", request.getScheme(), request.getServerName());
|
||||
if (isNonStandardPort(request)) {
|
||||
printer.printf(":%d", request.getServerPort());
|
||||
}
|
||||
printer.print(request.getRequestURI());
|
||||
return uriWriter.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.restdocs.operation.OperationResponse;
|
||||
import org.springframework.restdocs.operation.StandardOperationResponse;
|
||||
|
||||
/**
|
||||
* A factory for creating an {@link OperationResponse} derived from a
|
||||
* {@link MockHttpServletResponse}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class MockMvcOperationResponseFactory {
|
||||
|
||||
/**
|
||||
* Create a new {@code OperationResponse} derived from the given {@code mockResponse}.
|
||||
*
|
||||
* @param mockResponse the response
|
||||
* @return the {@code OperationResponse}
|
||||
*/
|
||||
public OperationResponse createOperationResponse(MockHttpServletResponse mockResponse) {
|
||||
return new StandardOperationResponse(
|
||||
HttpStatus.valueOf(mockResponse.getStatus()),
|
||||
extractHeaders(mockResponse), mockResponse.getContentAsByteArray());
|
||||
}
|
||||
|
||||
private HttpHeaders extractHeaders(MockHttpServletResponse response) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
for (String headerName : response.getHeaderNames()) {
|
||||
for (String value : response.getHeaders(headerName)) {
|
||||
headers.add(headerName, value);
|
||||
}
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentation;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Static factory methods for documenting RESTful APIs using Spring MVC Test
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public abstract class MockMvcRestDocumentation {
|
||||
|
||||
private MockMvcRestDocumentation() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to a {@link MockMvcConfigurer} that can be used to configure a
|
||||
* {@link MockMvc} instance using the given {@code restDocumentation}.
|
||||
*
|
||||
* @param restDocumentation the REST documentation
|
||||
* @return the configurer
|
||||
* @see ConfigurableMockMvcBuilder#apply(MockMvcConfigurer)
|
||||
*/
|
||||
public static RestDocumentationMockMvcConfigurer documentationConfiguration(
|
||||
RestDocumentation restDocumentation) {
|
||||
return new RestDocumentationMockMvcConfigurer(restDocumentation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets}.
|
||||
*
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param snippets the snippets that will document the API call
|
||||
* @return a Mock MVC {@code ResultHandler} that will produce the documentation
|
||||
* @see MockMvc#perform(org.springframework.test.web.servlet.RequestBuilder)
|
||||
* @see ResultActions#andDo(org.springframework.test.web.servlet.ResultHandler)
|
||||
*/
|
||||
public static RestDocumentationResultHandler document(String identifier,
|
||||
Snippet... snippets) {
|
||||
return new RestDocumentationResultHandler(identifier, snippets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets}. The given {@code requestPreprocessor} is applied to the request
|
||||
* before it is documented.
|
||||
*
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param requestPreprocessor the request preprocessor
|
||||
* @param snippets the snippets that will document the API call
|
||||
* @return a Mock MVC {@code ResultHandler} that will produce the documentation
|
||||
* @see MockMvc#perform(org.springframework.test.web.servlet.RequestBuilder)
|
||||
* @see ResultActions#andDo(org.springframework.test.web.servlet.ResultHandler)
|
||||
*/
|
||||
public static RestDocumentationResultHandler document(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationResultHandler(identifier, requestPreprocessor,
|
||||
snippets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets}. The given {@code responsePreprocessor} is applied to the request
|
||||
* before it is documented.
|
||||
*
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param responsePreprocessor the response preprocessor
|
||||
* @param snippets the snippets that will document the API call
|
||||
* @return a Mock MVC {@code ResultHandler} that will produce the documentation
|
||||
* @see MockMvc#perform(org.springframework.test.web.servlet.RequestBuilder)
|
||||
* @see ResultActions#andDo(org.springframework.test.web.servlet.ResultHandler)
|
||||
*/
|
||||
public static RestDocumentationResultHandler document(String identifier,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationResultHandler(identifier, responsePreprocessor,
|
||||
snippets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents the API call with the given {@code identifier} using the given
|
||||
* {@code snippets}. The given {@code requestPreprocessor} and
|
||||
* {@code responsePreprocessor} are applied to the request and response respectively
|
||||
* before they are documented.
|
||||
*
|
||||
* @param identifier an identifier for the API call that is being documented
|
||||
* @param requestPreprocessor the request preprocessor
|
||||
* @param responsePreprocessor the response preprocessor
|
||||
* @param snippets the snippets that will document the API call
|
||||
* @return a Mock MVC {@code ResultHandler} that will produce the documentation
|
||||
* @see MockMvc#perform(org.springframework.test.web.servlet.RequestBuilder)
|
||||
* @see ResultActions#andDo(org.springframework.test.web.servlet.ResultHandler)
|
||||
*/
|
||||
public static RestDocumentationResultHandler document(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
return new RestDocumentationResultHandler(identifier, requestPreprocessor,
|
||||
responsePreprocessor, snippets);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||
|
||||
/**
|
||||
* A configurer that is nested and, therefore, has a parent.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @param <PARENT> The parent's type
|
||||
*/
|
||||
interface NestedConfigurer<PARENT extends MockMvcConfigurer> {
|
||||
|
||||
/**
|
||||
* Returns the configurer's parent
|
||||
*
|
||||
* @return the parent
|
||||
*/
|
||||
PARENT and();
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.RestDocumentation;
|
||||
import org.springframework.restdocs.RestDocumentationContext;
|
||||
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver;
|
||||
import org.springframework.restdocs.snippet.StandardWriterResolver;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
|
||||
import org.springframework.restdocs.templates.TemplateEngine;
|
||||
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurerAdapter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* A {@link MockMvcConfigurer} that can be used to configure the documentation
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Dmitriy Mayboroda
|
||||
* @see ConfigurableMockMvcBuilder#apply(MockMvcConfigurer)
|
||||
* @see MockMvcRestDocumentation#documentationConfiguration(RestDocumentation)
|
||||
*/
|
||||
public class RestDocumentationMockMvcConfigurer extends MockMvcConfigurerAdapter {
|
||||
|
||||
private final UriConfigurer uriConfigurer = new UriConfigurer(this);
|
||||
|
||||
private final SnippetConfigurer snippetConfigurer = new SnippetConfigurer(this);
|
||||
|
||||
private final RequestPostProcessor requestPostProcessor;
|
||||
|
||||
private final TemplateEngineConfigurer templateEngineConfigurer = new TemplateEngineConfigurer();
|
||||
|
||||
private final WriterResolverConfigurer writerResolverConfigurer = new WriterResolverConfigurer();
|
||||
|
||||
/**
|
||||
* Creates a new {code RestDocumentationMockMvcConfigurer} that will use the given
|
||||
* {@code restDocumentation} when configuring MockMvc.
|
||||
*
|
||||
* @param restDocumentation the rest documentation
|
||||
* @see MockMvcRestDocumentation#documentationConfiguration(RestDocumentation)
|
||||
*/
|
||||
RestDocumentationMockMvcConfigurer(RestDocumentation restDocumentation) {
|
||||
this.requestPostProcessor = new ConfigurerApplyingRequestPostProcessor(
|
||||
restDocumentation, this.uriConfigurer, this.writerResolverConfigurer,
|
||||
this.snippetConfigurer, new ContentLengthHeaderConfigurer(),
|
||||
this.templateEngineConfigurer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link UriConfigurer} that can be used to configure the request URIs that
|
||||
* will be documented.
|
||||
*
|
||||
* @return the URI configurer
|
||||
*/
|
||||
public UriConfigurer uris() {
|
||||
return this.uriConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SnippetConfigurer} that can be used to configure the snippets that
|
||||
* will be generated.
|
||||
*
|
||||
* @return the snippet configurer
|
||||
*/
|
||||
public SnippetConfigurer snippets() {
|
||||
return this.snippetConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link TemplateEngine} that will be used for snippet rendering.
|
||||
*
|
||||
* @param templateEngine the template engine to use
|
||||
* @return {@code this}
|
||||
*/
|
||||
public RestDocumentationMockMvcConfigurer templateEngine(TemplateEngine templateEngine) {
|
||||
this.templateEngineConfigurer.setTemplateEngine(templateEngine);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the {@link WriterResolver} that will be used to resolve a writer for a
|
||||
* snippet.
|
||||
*
|
||||
* @param writerResolver The writer resolver to use
|
||||
* @return {@code this}
|
||||
*/
|
||||
public RestDocumentationMockMvcConfigurer writerResolver(WriterResolver writerResolver) {
|
||||
this.writerResolverConfigurer.setWriterResolver(writerResolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestPostProcessor beforeMockMvcCreated(
|
||||
ConfigurableMockMvcBuilder<?> builder, WebApplicationContext context) {
|
||||
return this.requestPostProcessor;
|
||||
}
|
||||
|
||||
private static class ContentLengthHeaderConfigurer extends AbstractConfigurer {
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
long contentLength = request.getContentLengthLong();
|
||||
if (contentLength > 0
|
||||
&& !StringUtils.hasText(request.getHeader("Content-Length"))) {
|
||||
request.addHeader("Content-Length", request.getContentLengthLong());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TemplateEngineConfigurer extends AbstractConfigurer {
|
||||
|
||||
private TemplateEngine templateEngine = new MustacheTemplateEngine(
|
||||
new StandardTemplateResourceResolver());
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
request.setAttribute(TemplateEngine.class.getName(), this.templateEngine);
|
||||
}
|
||||
|
||||
void setTemplateEngine(TemplateEngine templateEngine) {
|
||||
this.templateEngine = templateEngine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class WriterResolverConfigurer extends AbstractConfigurer {
|
||||
|
||||
private WriterResolver writerResolver;
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
WriterResolver resolverToUse = this.writerResolver;
|
||||
if (resolverToUse == null) {
|
||||
resolverToUse = new StandardWriterResolver(
|
||||
new RestDocumentationContextPlaceholderResolver(
|
||||
(RestDocumentationContext) request
|
||||
.getAttribute(RestDocumentationContext.class
|
||||
.getName())));
|
||||
}
|
||||
request.setAttribute(WriterResolver.class.getName(), resolverToUse);
|
||||
}
|
||||
|
||||
void setWriterResolver(WriterResolver writerResolver) {
|
||||
this.writerResolver = writerResolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ConfigurerApplyingRequestPostProcessor implements
|
||||
RequestPostProcessor {
|
||||
|
||||
private final RestDocumentation restDocumentation;
|
||||
|
||||
private final AbstractConfigurer[] configurers;
|
||||
|
||||
private ConfigurerApplyingRequestPostProcessor(
|
||||
RestDocumentation restDocumentation, AbstractConfigurer... configurers) {
|
||||
this.restDocumentation = restDocumentation;
|
||||
this.configurers = configurers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
|
||||
request.setAttribute(RestDocumentationContext.class.getName(),
|
||||
this.restDocumentation.beforeOperation());
|
||||
for (AbstractConfigurer configurer : this.configurers) {
|
||||
configurer.apply(request);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.restdocs.request.RequestDocumentation;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
/**
|
||||
* A drop-in replacement for {@link MockMvcRequestBuilders} that captures a request's URL
|
||||
* template and makes it available for documentation. Required when
|
||||
* {@link RequestDocumentation#pathParameters(org.springframework.restdocs.request.ParameterDescriptor...)
|
||||
* ) documenting path parameters} and recommended for general usage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @see MockMvcRequestBuilders
|
||||
* @see RequestDocumentation#pathParameters(org.springframework.restdocs.request.ParameterDescriptor...)
|
||||
* @see RequestDocumentation#pathParameters(java.util.Map,
|
||||
* org.springframework.restdocs.request.ParameterDescriptor...)
|
||||
*/
|
||||
public abstract class RestDocumentationRequestBuilders {
|
||||
|
||||
private static final String ATTRIBUTE_NAME_URL_TEMPLATE = "org.springframework.restdocs.urlTemplate";
|
||||
|
||||
private RestDocumentationRequestBuilders() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a GET request. The url template
|
||||
* will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the GET request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder get(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.get(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a GET request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the GET request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder get(URI uri) {
|
||||
return MockMvcRequestBuilders.get(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a POST request. The url template
|
||||
* will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the POST request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder post(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.post(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a POST request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the POST request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder post(URI uri) {
|
||||
return MockMvcRequestBuilders.post(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a PUT request. The url template
|
||||
* will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the PUT request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder put(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.put(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a PUT request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the PUT request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder put(URI uri) {
|
||||
return MockMvcRequestBuilders.put(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a PATCH request. The url
|
||||
* template will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the PATCH request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder patch(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.patch(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a PATCH request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the PATCH request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder patch(URI uri) {
|
||||
return MockMvcRequestBuilders.patch(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a DELETE request. The url
|
||||
* template will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the DELETE request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder delete(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.delete(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a DELETE request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the DELETE request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder delete(URI uri) {
|
||||
return MockMvcRequestBuilders.delete(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for an OPTIONS request. The url
|
||||
* template will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the OPTIONS request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder options(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.options(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for an OPTIONS request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the OPTIONS request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder options(URI uri) {
|
||||
return MockMvcRequestBuilders.options(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a HEAD request. The url template
|
||||
* will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the HEAD request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder head(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.head(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a HEAD request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the HEAD request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder head(URI uri) {
|
||||
return MockMvcRequestBuilders.head(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP
|
||||
* method. The url template will be captured and made available for documentation.
|
||||
*
|
||||
* @param httpMethod the HTTP method
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder request(HttpMethod httpMethod,
|
||||
String urlTemplate, Object... urlVariables) {
|
||||
return MockMvcRequestBuilders.request(httpMethod, urlTemplate, urlVariables)
|
||||
.requestAttr(ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a request with the given HTTP
|
||||
* method.
|
||||
* @param httpMethod the HTTP method (GET, POST, etc)
|
||||
* @param uri the URL
|
||||
* @return the builder for the request
|
||||
*/
|
||||
public static MockHttpServletRequestBuilder request(HttpMethod httpMethod, URI uri) {
|
||||
return MockMvcRequestBuilders.request(httpMethod, uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a multipart request. The url
|
||||
* template will be captured and made available for documentation.
|
||||
*
|
||||
* @param urlTemplate a URL template; the resulting URL will be encoded
|
||||
* @param urlVariables zero or more URL variables
|
||||
* @return the builder for the file upload request
|
||||
*/
|
||||
public static MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return (MockMultipartHttpServletRequestBuilder) MockMvcRequestBuilders
|
||||
.fileUpload(urlTemplate, urlVariables).requestAttr(
|
||||
ATTRIBUTE_NAME_URL_TEMPLATE, urlTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MockHttpServletRequestBuilder} for a multipart request.
|
||||
*
|
||||
* @param uri the URL
|
||||
* @return the builder for the file upload request
|
||||
*/
|
||||
public static MockMultipartHttpServletRequestBuilder fileUpload(URI uri) {
|
||||
return MockMvcRequestBuilders.fileUpload(uri);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import static org.springframework.restdocs.mockmvc.util.IterableEnumeration.iterable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.restdocs.operation.Operation;
|
||||
import org.springframework.restdocs.operation.OperationRequest;
|
||||
import org.springframework.restdocs.operation.OperationResponse;
|
||||
import org.springframework.restdocs.operation.StandardOperation;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
|
||||
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultHandler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Spring MVC Test {@code ResultHandler} for documenting RESTful APIs.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Andreas Evers
|
||||
* @see MockMvcRestDocumentation#document(String, Snippet...)
|
||||
*/
|
||||
public class RestDocumentationResultHandler implements ResultHandler {
|
||||
|
||||
private final String identifier;
|
||||
|
||||
private final OperationRequestPreprocessor requestPreprocessor;
|
||||
|
||||
private final OperationResponsePreprocessor responsePreprocessor;
|
||||
|
||||
private final List<Snippet> snippets;
|
||||
|
||||
RestDocumentationResultHandler(String identifier, Snippet... snippets) {
|
||||
this(identifier, new IdentityOperationRequestPreprocessor(),
|
||||
new IdentityOperationResponsePreprocessor(), snippets);
|
||||
}
|
||||
|
||||
RestDocumentationResultHandler(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) {
|
||||
this(identifier, requestPreprocessor,
|
||||
new IdentityOperationResponsePreprocessor(), snippets);
|
||||
}
|
||||
|
||||
RestDocumentationResultHandler(String identifier,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
this(identifier, new IdentityOperationRequestPreprocessor(),
|
||||
responsePreprocessor, snippets);
|
||||
}
|
||||
|
||||
RestDocumentationResultHandler(String identifier,
|
||||
OperationRequestPreprocessor requestPreprocessor,
|
||||
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
|
||||
Assert.notNull(identifier, "identifier must be non-null");
|
||||
Assert.notNull(requestPreprocessor, "requestPreprocessor must be non-null");
|
||||
Assert.notNull(responsePreprocessor, "responsePreprocessor must be non-null");
|
||||
Assert.notNull(snippets, "snippets must be non-null");
|
||||
this.identifier = identifier;
|
||||
this.requestPreprocessor = requestPreprocessor;
|
||||
this.responsePreprocessor = responsePreprocessor;
|
||||
this.snippets = Arrays.asList(snippets);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result) throws Exception {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
for (String name : iterable(result.getRequest().getAttributeNames())) {
|
||||
attributes.put(name, result.getRequest().getAttribute(name));
|
||||
}
|
||||
OperationRequest request = this.requestPreprocessor
|
||||
.preprocess(new MockMvcOperationRequestFactory()
|
||||
.createOperationRequest(result.getRequest()));
|
||||
|
||||
OperationResponse response = this.responsePreprocessor
|
||||
.preprocess(new MockMvcOperationResponseFactory()
|
||||
.createOperationResponse(result.getResponse()));
|
||||
Operation operation = new StandardOperation(this.identifier, request, response,
|
||||
attributes);
|
||||
for (Snippet snippet : getSnippets(result)) {
|
||||
snippet.document(operation);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Snippet> getSnippets(MvcResult result) {
|
||||
List<Snippet> combinedSnippets = new ArrayList<>((List<Snippet>) result
|
||||
.getRequest()
|
||||
.getAttribute("org.springframework.restdocs.defaultSnippets"));
|
||||
combinedSnippets.addAll(this.snippets);
|
||||
return combinedSnippets;
|
||||
}
|
||||
|
||||
static final class IdentityOperationRequestPreprocessor implements
|
||||
OperationRequestPreprocessor {
|
||||
|
||||
@Override
|
||||
public OperationRequest preprocess(OperationRequest request) {
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class IdentityOperationResponsePreprocessor implements
|
||||
OperationResponsePreprocessor {
|
||||
|
||||
@Override
|
||||
public OperationResponse preprocess(OperationResponse response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.curl.CurlDocumentation;
|
||||
import org.springframework.restdocs.http.HttpDocumentation;
|
||||
import org.springframework.restdocs.snippet.Snippet;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
|
||||
/**
|
||||
* A configurer that can be used to configure the generated documentation snippets.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class SnippetConfigurer extends
|
||||
AbstractNestedConfigurer<RestDocumentationMockMvcConfigurer> {
|
||||
|
||||
private List<Snippet> defaultSnippets = Arrays.asList(
|
||||
CurlDocumentation.curlRequest(), HttpDocumentation.httpRequest(),
|
||||
HttpDocumentation.httpResponse());
|
||||
|
||||
/**
|
||||
* The default encoding for documentation snippets
|
||||
* @see #withEncoding(String)
|
||||
*/
|
||||
public static final String DEFAULT_SNIPPET_ENCODING = "UTF-8";
|
||||
|
||||
private String snippetEncoding = DEFAULT_SNIPPET_ENCODING;
|
||||
|
||||
SnippetConfigurer(RestDocumentationMockMvcConfigurer parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures any documentation snippets to be written using the given
|
||||
* {@code encoding}. The default is UTF-8.
|
||||
* @param encoding the encoding
|
||||
* @return {@code this}
|
||||
*/
|
||||
public SnippetConfigurer withEncoding(String encoding) {
|
||||
this.snippetEncoding = encoding;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
((WriterResolver) request.getAttribute(WriterResolver.class.getName()))
|
||||
.setEncoding(this.snippetEncoding);
|
||||
request.setAttribute("org.springframework.restdocs.defaultSnippets",
|
||||
this.defaultSnippets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the documentation snippets that will be produced by default.
|
||||
*
|
||||
* @param defaultSnippets the default snippets
|
||||
* @return {@code this}
|
||||
*/
|
||||
public SnippetConfigurer withDefaults(Snippet... defaultSnippets) {
|
||||
this.defaultSnippets = Arrays.asList(defaultSnippets);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
/**
|
||||
* A configurer that can be used to configure the documented URIs
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class UriConfigurer extends AbstractNestedConfigurer<RestDocumentationMockMvcConfigurer> {
|
||||
|
||||
/**
|
||||
* The default scheme for documented URIs
|
||||
* @see #withScheme(String)
|
||||
*/
|
||||
public static final String DEFAULT_SCHEME = "http";
|
||||
|
||||
/**
|
||||
* The defalt host for documented URIs
|
||||
* @see #withHost(String)
|
||||
*/
|
||||
public static final String DEFAULT_HOST = "localhost";
|
||||
|
||||
/**
|
||||
* The default port for documented URIs
|
||||
* @see #withPort(int)
|
||||
*/
|
||||
public static final int DEFAULT_PORT = 8080;
|
||||
|
||||
private String scheme = DEFAULT_SCHEME;
|
||||
|
||||
private String host = DEFAULT_HOST;
|
||||
|
||||
private int port = DEFAULT_PORT;
|
||||
|
||||
protected UriConfigurer(RestDocumentationMockMvcConfigurer parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures any documented URIs to use the given {@code scheme}. The default is
|
||||
* {@code http}.
|
||||
*
|
||||
* @param scheme The URI scheme
|
||||
* @return {@code this}
|
||||
*/
|
||||
public UriConfigurer withScheme(String scheme) {
|
||||
this.scheme = scheme;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures any documented URIs to use the given {@code host}. The default is
|
||||
* {@code localhost}.
|
||||
*
|
||||
* @param host The URI host
|
||||
* @return {@code this}
|
||||
*/
|
||||
public UriConfigurer withHost(String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures any documented URIs to use the given {@code port}. The default is
|
||||
* {@code 8080}.
|
||||
*
|
||||
* @param port The URI port
|
||||
* @return {@code this}
|
||||
*/
|
||||
public UriConfigurer withPort(int port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
void apply(MockHttpServletRequest request) {
|
||||
request.setScheme(this.scheme);
|
||||
request.setServerPort(this.port);
|
||||
request.setServerName(this.host);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* An adapter to expose an {@link Enumeration} as an {@link Iterable}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
* @param <T> the type of the Enumeration's contents
|
||||
*/
|
||||
public final class IterableEnumeration<T> implements Iterable<T> {
|
||||
|
||||
private final Enumeration<T> enumeration;
|
||||
|
||||
private IterableEnumeration(Enumeration<T> enumeration) {
|
||||
this.enumeration = enumeration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return IterableEnumeration.this.enumeration.hasMoreElements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return IterableEnumeration.this.enumeration.nextElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Iterable} that will iterate over the given {@code enumeration}
|
||||
*
|
||||
* @param <T> the type of the enumeration's elements
|
||||
* @param enumeration The enumeration to expose as an {@code Iterable}
|
||||
* @return the iterable
|
||||
*/
|
||||
public static <T> Iterable<T> iterable(Enumeration<T> enumeration) {
|
||||
return new IterableEnumeration<T>(enumeration);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcOperationRequestFactory;
|
||||
import org.springframework.restdocs.operation.OperationRequest;
|
||||
import org.springframework.restdocs.operation.OperationRequestPart;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
/**
|
||||
* Tests for {@link MockMvcOperationRequestFactory}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MockMvcOperationRequestFactoryTests {
|
||||
|
||||
private final MockMvcOperationRequestFactory factory = new MockMvcOperationRequestFactory();
|
||||
|
||||
@Test
|
||||
public void httpRequest() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.get("/foo"));
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpRequestWithCustomPort() throws Exception {
|
||||
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
|
||||
.buildRequest(new MockServletContext());
|
||||
mockRequest.setServerPort(8080);
|
||||
OperationRequest request = this.factory.createOperationRequest(mockRequest);
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost:8080/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithContextPath() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders.get(
|
||||
"/foo/bar").contextPath("/foo"));
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost/foo/bar")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithHeaders() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.get("/foo").header("a", "alpha", "apple").header("b", "bravo"));
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
assertThat(request.getHeaders(), hasEntry("a", Arrays.asList("alpha", "apple")));
|
||||
assertThat(request.getHeaders(), hasEntry("b", Arrays.asList("bravo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsRequest() throws Exception {
|
||||
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
|
||||
.buildRequest(new MockServletContext());
|
||||
mockRequest.setScheme("https");
|
||||
mockRequest.setServerPort(443);
|
||||
OperationRequest request = this.factory.createOperationRequest(mockRequest);
|
||||
assertThat(request.getUri(), is(URI.create("https://localhost/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpsRequestWithCustomPort() throws Exception {
|
||||
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
|
||||
.buildRequest(new MockServletContext());
|
||||
mockRequest.setScheme("https");
|
||||
mockRequest.setServerPort(8443);
|
||||
OperationRequest request = this.factory.createOperationRequest(mockRequest);
|
||||
assertThat(request.getUri(), is(URI.create("https://localhost:8443/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestWithParametersProducesUriWithQueryString() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.get("/foo").param("a", "alpha", "apple").param("b", "br&vo"));
|
||||
assertThat(request.getUri(),
|
||||
is(URI.create("http://localhost/foo?a=alpha&a=apple&b=br%26vo")));
|
||||
assertThat(request.getParameters().size(), is(2));
|
||||
assertThat(request.getParameters(),
|
||||
hasEntry("a", Arrays.asList("alpha", "apple")));
|
||||
assertThat(request.getParameters(), hasEntry("b", Arrays.asList("br&vo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestWithQueryStringPopulatesParameters() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.get("/foo?a=alpha&b=bravo"));
|
||||
assertThat(request.getUri(),
|
||||
is(URI.create("http://localhost/foo?a=alpha&b=bravo")));
|
||||
assertThat(request.getParameters().size(), is(2));
|
||||
assertThat(request.getParameters(), hasEntry("a", Arrays.asList("alpha")));
|
||||
assertThat(request.getParameters(), hasEntry("b", Arrays.asList("bravo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.GET));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithParameters() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.post("/foo").param("a", "alpha", "apple").param("b", "br&vo"));
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.POST));
|
||||
assertThat(request.getParameters().size(), is(2));
|
||||
assertThat(request.getParameters(),
|
||||
hasEntry("a", Arrays.asList("alpha", "apple")));
|
||||
assertThat(request.getParameters(), hasEntry("b", Arrays.asList("br&vo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockMultipartFileUpload() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.fileUpload("/foo").file(
|
||||
new MockMultipartFile("file", new byte[] { 1, 2, 3, 4 })));
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.POST));
|
||||
assertThat(request.getParts().size(), is(1));
|
||||
OperationRequestPart part = request.getParts().iterator().next();
|
||||
assertThat(part.getName(), is(equalTo("file")));
|
||||
assertThat(part.getSubmittedFileName(), is(nullValue()));
|
||||
assertThat(part.getHeaders().isEmpty(), is(true));
|
||||
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mockMultipartFileUploadWithContentType() throws Exception {
|
||||
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
|
||||
.fileUpload("/foo").file(
|
||||
new MockMultipartFile("file", "original", "image/png",
|
||||
new byte[] { 1, 2, 3, 4 })));
|
||||
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
|
||||
assertThat(request.getMethod(), is(HttpMethod.POST));
|
||||
assertThat(request.getParts().size(), is(1));
|
||||
OperationRequestPart part = request.getParts().iterator().next();
|
||||
assertThat(part.getName(), is(equalTo("file")));
|
||||
assertThat(part.getSubmittedFileName(), is(equalTo("original")));
|
||||
assertThat(part.getHeaders().getContentType(), is(MediaType.IMAGE_PNG));
|
||||
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithPart() throws Exception {
|
||||
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
|
||||
.buildRequest(new MockServletContext());
|
||||
Part mockPart = mock(Part.class);
|
||||
when(mockPart.getHeaderNames()).thenReturn(Arrays.asList("a", "b"));
|
||||
when(mockPart.getHeaders("a")).thenReturn(Arrays.asList("alpha"));
|
||||
when(mockPart.getHeaders("b")).thenReturn(Arrays.asList("bravo", "banana"));
|
||||
when(mockPart.getInputStream()).thenReturn(
|
||||
new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
|
||||
when(mockPart.getName()).thenReturn("part-name");
|
||||
when(mockPart.getSubmittedFileName()).thenReturn("submitted.txt");
|
||||
mockRequest.addPart(mockPart);
|
||||
OperationRequest request = this.factory.createOperationRequest(mockRequest);
|
||||
assertThat(request.getParts().size(), is(1));
|
||||
OperationRequestPart part = request.getParts().iterator().next();
|
||||
assertThat(part.getName(), is(equalTo("part-name")));
|
||||
assertThat(part.getSubmittedFileName(), is(equalTo("submitted.txt")));
|
||||
assertThat(part.getHeaders().getContentType(), is(nullValue()));
|
||||
assertThat(part.getHeaders().get("a"), contains("alpha"));
|
||||
assertThat(part.getHeaders().get("b"), contains("bravo", "banana"));
|
||||
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithPartWithContentType() throws Exception {
|
||||
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")
|
||||
.buildRequest(new MockServletContext());
|
||||
Part mockPart = mock(Part.class);
|
||||
when(mockPart.getHeaderNames()).thenReturn(Arrays.asList("a", "b"));
|
||||
when(mockPart.getHeaders("a")).thenReturn(Arrays.asList("alpha"));
|
||||
when(mockPart.getHeaders("b")).thenReturn(Arrays.asList("bravo", "banana"));
|
||||
when(mockPart.getInputStream()).thenReturn(
|
||||
new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }));
|
||||
when(mockPart.getName()).thenReturn("part-name");
|
||||
when(mockPart.getSubmittedFileName()).thenReturn("submitted.png");
|
||||
when(mockPart.getContentType()).thenReturn("image/png");
|
||||
mockRequest.addPart(mockPart);
|
||||
OperationRequest request = this.factory.createOperationRequest(mockRequest);
|
||||
assertThat(request.getParts().size(), is(1));
|
||||
OperationRequestPart part = request.getParts().iterator().next();
|
||||
assertThat(part.getName(), is(equalTo("part-name")));
|
||||
assertThat(part.getSubmittedFileName(), is(equalTo("submitted.png")));
|
||||
assertThat(part.getHeaders().getContentType(), is(MediaType.IMAGE_PNG));
|
||||
assertThat(part.getHeaders().get("a"), contains("alpha"));
|
||||
assertThat(part.getHeaders().get("b"), contains("bravo", "banana"));
|
||||
assertThat(part.getContent(), is(equalTo(new byte[] { 1, 2, 3, 4 })));
|
||||
}
|
||||
|
||||
private OperationRequest createOperationRequest(MockHttpServletRequestBuilder builder)
|
||||
throws Exception {
|
||||
return this.factory.createOperationRequest(builder
|
||||
.buildRequest(new MockServletContext()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.curlRequest;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.maskLinks;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
|
||||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||
import static org.springframework.restdocs.snippet.Attributes.attributes;
|
||||
import static org.springframework.restdocs.snippet.Attributes.key;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.httpRequest;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.httpResponse;
|
||||
import static org.springframework.restdocs.test.SnippetMatchers.snippet;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.restdocs.RestDocumentation;
|
||||
import org.springframework.restdocs.hypermedia.Link;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationIntegrationTests.TestConfiguration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Integration tests for Spring REST Docs
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Dewet Diener
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration(classes = TestConfiguration.class)
|
||||
public class MockMvcRestDocumentationIntegrationTests {
|
||||
|
||||
@Rule
|
||||
public RestDocumentation restDocumentation = new RestDocumentation(
|
||||
"build/generated-snippets");
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void deleteSnippets() {
|
||||
FileSystemUtils.deleteRecursively(new File("build/generated-snippets"));
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearOutputDirSystemProperty() {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicSnippetGeneration() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk()).andDo(document("basic"));
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/basic"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linksSnippet() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("links",
|
||||
links(linkWithRel("rel").description("The description"))));
|
||||
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
|
||||
"links.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathParametersSnippet() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(get("{foo}", "/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("links", pathParameters(parameterWithName("foo")
|
||||
.description("The description"))));
|
||||
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
|
||||
"path-parameters.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestParametersSnippet() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(get("/").param("foo", "bar").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("links", requestParameters(parameterWithName("foo")
|
||||
.description("The description"))));
|
||||
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
|
||||
"request-parameters.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestFieldsSnippet() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(
|
||||
get("/").param("foo", "bar").content("{\"a\":\"alpha\"}")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("links",
|
||||
requestFields(fieldWithPath("a").description("The description"))));
|
||||
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
|
||||
"request-fields.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseFieldsSnippet() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(get("/").param("foo", "bar").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document(
|
||||
"links",
|
||||
responseFields(
|
||||
fieldWithPath("a").description("The description"),
|
||||
fieldWithPath("links").description(
|
||||
"Links to other resources"))));
|
||||
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc",
|
||||
"response-fields.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterizedOutputDirectory() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk()).andDo(document("{method-name}"));
|
||||
assertExpectedSnippetFilesExist(new File(
|
||||
"build/generated-snippets/parameterized-output-directory"),
|
||||
"http-request.adoc", "http-response.adoc", "curl-request.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiStep() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation))
|
||||
.alwaysDo(document("{method-name}-{step}")).build();
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
|
||||
status().isOk());
|
||||
assertExpectedSnippetFilesExist(
|
||||
new File("build/generated-snippets/multi-step-1/"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
|
||||
status().isOk());
|
||||
assertExpectedSnippetFilesExist(
|
||||
new File("build/generated-snippets/multi-step-2/"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
|
||||
status().isOk());
|
||||
assertExpectedSnippetFilesExist(
|
||||
new File("build/generated-snippets/multi-step-3/"), "http-request.adoc",
|
||||
"http-response.adoc", "curl-request.adoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preprocessedRequest() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
Pattern pattern = Pattern.compile("(\"alpha\")");
|
||||
|
||||
mockMvc.perform(
|
||||
get("/").header("a", "alpha").header("b", "bravo")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON).content("{\"a\":\"alpha\"}"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("original-request"))
|
||||
.andDo(document(
|
||||
"preprocessed-request",
|
||||
preprocessRequest(prettyPrint(), removeHeaders("a"),
|
||||
replacePattern(pattern, "\"<<beta>>\""))));
|
||||
|
||||
assertThat(
|
||||
new File("build/generated-snippets/original-request/http-request.adoc"),
|
||||
is(snippet().withContents(
|
||||
httpRequest(RequestMethod.GET, "/").header("Host", "localhost")
|
||||
.header("a", "alpha").header("b", "bravo")
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
|
||||
.header("Content-Length", "13")
|
||||
.content("{\"a\":\"alpha\"}"))));
|
||||
assertThat(
|
||||
new File(
|
||||
"build/generated-snippets/preprocessed-request/http-request.adoc"),
|
||||
is(snippet().withContents(
|
||||
httpRequest(RequestMethod.GET, "/").header("Host", "localhost")
|
||||
.header("b", "bravo")
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Accept", MediaType.APPLICATION_JSON_VALUE)
|
||||
.header("Content-Length", "22")
|
||||
.content(String.format("{%n \"a\" : \"<<beta>>\"%n}")))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preprocessedResponse() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
Pattern pattern = Pattern.compile("(\"alpha\")");
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("original-response"))
|
||||
.andDo(document(
|
||||
"preprocessed-response",
|
||||
preprocessResponse(prettyPrint(), maskLinks(),
|
||||
removeHeaders("a"),
|
||||
replacePattern(pattern, "\"<<beta>>\""))));
|
||||
|
||||
assertThat(
|
||||
new File("build/generated-snippets/original-response/http-response.adoc"),
|
||||
is(snippet().withContents(
|
||||
httpResponse(HttpStatus.OK)
|
||||
.header("a", "alpha")
|
||||
.header("Content-Type", "application/json")
|
||||
.content(
|
||||
"{\"a\":\"alpha\",\"links\":[{\"rel\":\"rel\","
|
||||
+ "\"href\":\"href\"}]}"))));
|
||||
assertThat(
|
||||
new File(
|
||||
"build/generated-snippets/preprocessed-response/http-response.adoc"),
|
||||
is(snippet().withContents(
|
||||
httpResponse(HttpStatus.OK).header("Content-Type",
|
||||
"application/json").content(
|
||||
String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" :"
|
||||
+ " [ {%n \"rel\" : \"rel\",%n \"href\" :"
|
||||
+ " \"...\"%n } ]%n}")))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customSnippetTemplate() throws Exception {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(this.restDocumentation)).build();
|
||||
|
||||
ClassLoader classLoader = new URLClassLoader(new URL[] { new File(
|
||||
"src/test/resources/custom-snippet-templates").toURI().toURL() },
|
||||
getClass().getClassLoader());
|
||||
ClassLoader previous = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
try {
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("custom-snippet-template"));
|
||||
}
|
||||
finally {
|
||||
Thread.currentThread().setContextClassLoader(previous);
|
||||
}
|
||||
assertThat(new File(
|
||||
"build/generated-snippets/custom-snippet-template/curl-request.adoc"),
|
||||
is(snippet().withContents(equalTo("Custom curl request"))));
|
||||
|
||||
mockMvc.perform(get("/")).andDo(
|
||||
document(
|
||||
"index",
|
||||
curlRequest(attributes(key("title").value(
|
||||
"Access the index using curl")))));
|
||||
}
|
||||
|
||||
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
|
||||
for (String snippet : snippets) {
|
||||
assertTrue(new File(directory, snippet).isFile());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
static class TestConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Bean
|
||||
public TestController testController() {
|
||||
return new TestController();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@RequestMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<Map<String, Object>> foo() {
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("a", "alpha");
|
||||
response.put("links", Arrays.asList(new Link("rel", "href")));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("a", "alpha");
|
||||
return new ResponseEntity<Map<String, Object>>(response, headers,
|
||||
HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.mvc.BasicLinkBuilder;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.RestDocumentation;
|
||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestDocumentationMockMvcConfigurer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Dmitriy Mayboroda
|
||||
*/
|
||||
public class RestDocumentationConfigurerTests {
|
||||
|
||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
@Rule
|
||||
public RestDocumentation restDocumentation = new RestDocumentation("test");
|
||||
|
||||
@Test
|
||||
public void defaultConfiguration() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
|
||||
this.restDocumentation).beforeMockMvcCreated(null, null);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
|
||||
assertUriConfiguration("http", "localhost", 8080);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customScheme() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
|
||||
this.restDocumentation).uris().withScheme("https")
|
||||
.beforeMockMvcCreated(null, null);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
|
||||
assertUriConfiguration("https", "localhost", 8080);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customHost() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
|
||||
this.restDocumentation).uris().withHost("api.example.com")
|
||||
.beforeMockMvcCreated(null, null);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
|
||||
assertUriConfiguration("http", "api.example.com", 8080);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customPort() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
|
||||
this.restDocumentation).uris().withPort(8081)
|
||||
.beforeMockMvcCreated(null, null);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
|
||||
assertUriConfiguration("http", "localhost", 8081);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noContentLengthHeaderWhenRequestHasNotContent() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
|
||||
this.restDocumentation).uris().withPort(8081)
|
||||
.beforeMockMvcCreated(null, null);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
assertThat(this.request.getHeader("Content-Length"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentLengthHeaderIsSetWhenRequestHasContent() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationMockMvcConfigurer(
|
||||
this.restDocumentation).beforeMockMvcCreated(null, null);
|
||||
byte[] content = "Hello, world".getBytes();
|
||||
this.request.setContent(content);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
assertThat(this.request.getHeader("Content-Length"),
|
||||
is(equalTo(Integer.toString(content.length))));
|
||||
}
|
||||
|
||||
private void assertUriConfiguration(String scheme, String host, int port) {
|
||||
assertEquals(scheme, this.request.getScheme());
|
||||
assertEquals(host, this.request.getServerName());
|
||||
assertEquals(port, this.request.getServerPort());
|
||||
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(
|
||||
this.request));
|
||||
try {
|
||||
URI uri = BasicLinkBuilder.linkToCurrentMapping().toUri();
|
||||
assertEquals(scheme, uri.getScheme());
|
||||
assertEquals(host, uri.getHost());
|
||||
assertEquals(port, uri.getPort());
|
||||
}
|
||||
finally {
|
||||
RequestContextHolder.resetRequestAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.fileUpload;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.head;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.options;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.request;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestDocumentationRequestBuilders}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
*/
|
||||
public class RestDocumentationRequestBuildersTests {
|
||||
|
||||
private final ServletContext servletContext = new MockServletContext();
|
||||
|
||||
@Test
|
||||
public void getTemplate() {
|
||||
assertTemplate(get("{template}", "t"), HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getUri() {
|
||||
assertUri(get(URI.create("/uri")), HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postTemplate() {
|
||||
assertTemplate(post("{template}", "t"), HttpMethod.POST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postUri() {
|
||||
assertUri(post(URI.create("/uri")), HttpMethod.POST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putTemplate() {
|
||||
assertTemplate(put("{template}", "t"), HttpMethod.PUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putUri() {
|
||||
assertUri(put(URI.create("/uri")), HttpMethod.PUT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patchTemplate() {
|
||||
assertTemplate(patch("{template}", "t"), HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patchUri() {
|
||||
assertUri(patch(URI.create("/uri")), HttpMethod.PATCH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteTemplate() {
|
||||
assertTemplate(delete("{template}", "t"), HttpMethod.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteUri() {
|
||||
assertUri(delete(URI.create("/uri")), HttpMethod.DELETE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsTemplate() {
|
||||
assertTemplate(options("{template}", "t"), HttpMethod.OPTIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionsUri() {
|
||||
assertUri(options(URI.create("/uri")), HttpMethod.OPTIONS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headTemplate() {
|
||||
assertTemplate(head("{template}", "t"), HttpMethod.HEAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headUri() {
|
||||
assertUri(head(URI.create("/uri")), HttpMethod.HEAD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestTemplate() {
|
||||
assertTemplate(request(HttpMethod.GET, "{template}", "t"), HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestUri() {
|
||||
assertUri(request(HttpMethod.GET, URI.create("/uri")), HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileUploadTemplate() {
|
||||
assertTemplate(fileUpload("{template}", "t"), HttpMethod.POST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fileUploadUri() {
|
||||
assertUri(fileUpload(URI.create("/uri")), HttpMethod.POST);
|
||||
}
|
||||
|
||||
private void assertTemplate(MockHttpServletRequestBuilder builder,
|
||||
HttpMethod httpMethod) {
|
||||
MockHttpServletRequest request = builder.buildRequest(this.servletContext);
|
||||
assertThat(
|
||||
(String) request.getAttribute("org.springframework.restdocs.urlTemplate"),
|
||||
is(equalTo("{template}")));
|
||||
assertThat(request.getRequestURI(), is(equalTo("t")));
|
||||
assertThat(request.getMethod(), is(equalTo(httpMethod.name())));
|
||||
}
|
||||
|
||||
private void assertUri(MockHttpServletRequestBuilder builder, HttpMethod httpMethod) {
|
||||
MockHttpServletRequest request = builder.buildRequest(this.servletContext);
|
||||
assertThat(request.getRequestURI(), is(equalTo("/uri")));
|
||||
assertThat(request.getMethod(), is(equalTo(httpMethod.name())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc.test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.restdocs.RestDocumentationContext;
|
||||
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolver;
|
||||
import org.springframework.restdocs.snippet.StandardWriterResolver;
|
||||
import org.springframework.restdocs.snippet.WriterResolver;
|
||||
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
|
||||
import org.springframework.restdocs.templates.TemplateEngine;
|
||||
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.RequestBuilder;
|
||||
import org.springframework.web.servlet.FlashMap;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* A minimal stub implementation of {@link MvcResult}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
*/
|
||||
public class StubMvcResult implements MvcResult {
|
||||
|
||||
private final MockHttpServletRequest request;
|
||||
|
||||
private final MockHttpServletResponse response;
|
||||
|
||||
public static StubMvcResult result() {
|
||||
return new StubMvcResult();
|
||||
}
|
||||
|
||||
public static StubMvcResult result(RequestBuilder requestBuilder) {
|
||||
return new StubMvcResult(requestBuilder);
|
||||
}
|
||||
|
||||
public static StubMvcResult result(RequestBuilder requestBuilder,
|
||||
MockHttpServletResponse response) {
|
||||
return new StubMvcResult(requestBuilder, response);
|
||||
}
|
||||
|
||||
public static StubMvcResult result(MockHttpServletRequest request) {
|
||||
return new StubMvcResult(request);
|
||||
}
|
||||
|
||||
public static StubMvcResult result(MockHttpServletResponse response) {
|
||||
return new StubMvcResult(response);
|
||||
}
|
||||
|
||||
public static StubMvcResult result(MockHttpServletRequest request,
|
||||
MockHttpServletResponse response) {
|
||||
return new StubMvcResult(request, response);
|
||||
}
|
||||
|
||||
private StubMvcResult() {
|
||||
this(new MockHttpServletRequest(), new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
private StubMvcResult(MockHttpServletRequest request) {
|
||||
this(request, new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
private StubMvcResult(MockHttpServletResponse response) {
|
||||
this(new MockHttpServletRequest(), response);
|
||||
}
|
||||
|
||||
private StubMvcResult(RequestBuilder requestBuilder, MockHttpServletResponse response) {
|
||||
this(requestBuilder.buildRequest(new MockServletContext()), response);
|
||||
}
|
||||
|
||||
private StubMvcResult(MockHttpServletRequest request, MockHttpServletResponse response) {
|
||||
this.request = request;
|
||||
if (this.request.getAttribute(TemplateEngine.class.getName()) == null) {
|
||||
this.request.setAttribute(TemplateEngine.class.getName(),
|
||||
new MustacheTemplateEngine(new StandardTemplateResourceResolver()));
|
||||
}
|
||||
RestDocumentationContext context = new RestDocumentationContext(null, null, null);
|
||||
this.request.setAttribute(RestDocumentationContext.class.getName(), context);
|
||||
if (this.request.getAttribute(WriterResolver.class.getName()) == null) {
|
||||
this.request.setAttribute(WriterResolver.class.getName(),
|
||||
new StandardWriterResolver(
|
||||
new RestDocumentationContextPlaceholderResolver(context)));
|
||||
}
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
private StubMvcResult(RequestBuilder requestBuilder) {
|
||||
this(requestBuilder.buildRequest(new MockServletContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockHttpServletRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockHttpServletResponse getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerInterceptor[] getInterceptors() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelAndView getModelAndView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getResolvedException() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlashMap getFlashMap() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAsyncResult() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAsyncResult(long timeToWait) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.mockmvc.test;
|
||||
|
||||
import org.springframework.restdocs.RestDocumentationContext;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
|
||||
public class TestRequestBuilders {
|
||||
|
||||
private TestRequestBuilders() {
|
||||
|
||||
}
|
||||
|
||||
public static MockHttpServletRequestBuilder get(String urlTemplate,
|
||||
Object... urlVariables) {
|
||||
return org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get(
|
||||
urlTemplate, urlVariables).requestAttr(
|
||||
RestDocumentationContext.class.getName(),
|
||||
new RestDocumentationContext(null, null, null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Custom curl request
|
||||
Reference in New Issue
Block a user