Add support for modifying a request prior to it being documented

Prior to this commit it was not possible to modify a request prior to
it being documented, only a response. This commit builds on the new
Operation abstraction to simplify the existing response modification
support and to add support for request modification.

Closes gh-84
This commit is contained in:
Andy Wilkinson
2015-09-02 12:40:59 +01:00
parent 3579b34a77
commit 9d8bbf0558
34 changed files with 992 additions and 885 deletions

View File

@@ -0,0 +1,56 @@
[[customizing-requests-and-responses]]
== Customizing requests and responses
There may be situations where you do not want to document a request exactly as it was sent
or a response exactly as it was received. Spring REST Docs provides a number of
preprocessors that can be used to modify a request or response before it's documented.
Preprocessing is configured by calling `document` with an `OperationRequestPreprocessor`,
and/or an `OperationResponsePreprocessor`. Instances can be obtained using the
static `preprocessRequest` and `preprocessResponse` methods on `Preprocessors`:
[source,java,indent=0]
----
include::{examples-dir}/com/example/Preprocessing.java[tags=general]
----
<1> Apply a request preprocessor that will remove the header named `Foo`.
<2> Apply a response preprocessor that will pretty print its content.
Various built in preprocessors, including those illustrated above, are available via the
static methods on `Preprocessors`. See below for further details.
[[customizing-requests-and-responses-pretty-printing]]
=== Pretty printing
`prettyPrint` on `Preprocessors` formats the content of the request or response
to make it easier to read.
[[customizing-requests-and-responses-masking-links]]
=== Masking links
If you're documenting a Hypermedia-based API, you may want to encourage clients to
navigate the API using links rather than through the use of hard coded URIs. One way to do
this is to limit the use of URIs in the documentation. `maskLinks` on
`Preprocessors` replaces the `href` of any links in the response with `...`. A
different replacement can also be specified if you wish.
[[customizing-requests-and-responses-removing-headers]]
=== Removing headers
`removeHeaders` on `Preprocessors` removes any occurrences of the named headers
from the request or response.
[[customizing-requests-and-responses-replacing-patterns]]
=== Replacing patterns
`replacePattern` on `Preprocessors` provides a general purpose mechanism for
replacing content in a request or response. Any occurrences of a regular expression are
replaced.

View File

@@ -1,45 +0,0 @@
[[customizing-responses]]
== Customizing responses
There may be situations where you do not want to document a response exactly as received.
Spring REST Docs provides a number of response post processors that can be used to modify
a response after it is received but before it's documented.
Response modification is configured using a `ResponseModifier`. An instance can be
obtained using the static `modifyResponseTo` method on `RestDocumentation`. Once the
response modifications have been provided, documentation can be configured as usual
via the `andDocument` method:
[source,java,indent=0]
----
include::{examples-dir}/com/example/ResponsePostProcessing.java[tags=general]
----
<1> Call `modifyResponseTo` to configure response modifications, passing in one or more
`ResponsePostProcessor` implementations.
<2> Proceed with documenting the call.
[[customizing-responses-pretty-printing]]
=== Pretty printing
`prettyPrintContent` on `ResponsePostProcessors` formats the body of the response to
make it easier to read.
[[customizing-responses-masking-links]]
=== Masking links
If you're documenting a Hypermedia-based API, you may want to encourage clients to
navigate the API using links rather than through the use of hard coded URIs. One way to do
this is to limit the use of URIs in the documentation. `maskLinks` on
`ResponsePostProcessors` replaces the `href` of any links in the response with `...`. A
different replacement can also be specified if you wish.
=== Removing headers
`removeHeaders` on `ResponsePostProcessors` removes any occurrences of the named headers
from the response.
=== Replacing patterns
`replacePattern` on `ResponsePostProcessors` provides a general purpose mechanism for
replacing content in a response. Any occurrences of a regular expression are replaced.

View File

@@ -23,7 +23,7 @@ snippets produced with Spring MVC Test.
include::introduction.adoc[]
include::getting-started.adoc[]
include::documenting-your-api.adoc[]
include::customizing-responses.adoc[]
include::customizing-requests-and-responses.adoc[]
include::configuration.adoc[]
include::working-with-asciidoctor.adoc[]
include::contributing.adoc[]

View File

@@ -16,13 +16,17 @@
package com.example;
import static org.springframework.restdocs.RestDocumentation.modifyResponseTo;
import static org.springframework.restdocs.RestDocumentationRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
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.removeHeaders;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.RestDocumentation.document;
import org.springframework.test.web.servlet.MockMvc;
public class ResponsePostProcessing {
public class Preprocessing {
private MockMvc mockMvc;
@@ -30,8 +34,9 @@ public class ResponsePostProcessing {
// tag::general[]
this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andDo(modifyResponseTo(/* ... */) // <1>
.andDocument("index")); // <2>
.andDo(document("index",
preprocessRequest(removeHeaders("Foo")), // <1>
preprocessResponse(prettyPrint()))); // <2>
// end::general[]
}

View File

@@ -1,123 +0,0 @@
/*
* 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;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.restdocs.response.ResponsePostProcessor;
import org.springframework.restdocs.snippet.Snippet;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.ReflectionUtils;
/**
* Modifies the response in an {@link MvcResult} by applying {@link ResponsePostProcessor
* ResponsePostProcessors} to it.
*
* @see RestDocumentation#modifyResponseTo(ResponsePostProcessor...)
* @author Andy Wilkinson
*/
public final class ResponseModifier {
private final List<ResponsePostProcessor> postProcessors;
ResponseModifier(ResponsePostProcessor... postProcessors) {
this.postProcessors = Arrays.asList(postProcessors);
}
/**
* Provides a {@link RestDocumentationResultHandler} that can be used to document the
* request and modified response.
* @param identifier an identifier for the API call that is being documented
* @param snippets the snippets to use to document the call
* @return the result handler that will produce the documentation
*/
public RestDocumentationResultHandler andDocument(String identifier,
Snippet... snippets) {
return new ResponseModifyingRestDocumentationResultHandler(identifier, snippets);
}
class ResponseModifyingRestDocumentationResultHandler extends
RestDocumentationResultHandler {
private ResponseModifyingRestDocumentationResultHandler(String identifier,
Snippet... snippets) {
super(identifier, snippets);
}
@Override
public void handle(MvcResult result) throws Exception {
super.handle(postProcessResponse(result));
}
MvcResult postProcessResponse(MvcResult result) throws Exception {
MockHttpServletResponse response = result.getResponse();
for (ResponsePostProcessor postProcessor : ResponseModifier.this.postProcessors) {
response = postProcessor.postProcess(response);
}
return decorateResult(result, response);
}
private MvcResult decorateResult(MvcResult result,
MockHttpServletResponse response) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MvcResult.class);
enhancer.setCallback(new GetResponseMethodInterceptor(response, result));
return (MvcResult) enhancer.create();
}
private class GetResponseMethodInterceptor implements MethodInterceptor {
private final MvcResult delegate;
private final MockHttpServletResponse response;
private final Method getResponseMethod = findMethod("getResponse");
private GetResponseMethodInterceptor(MockHttpServletResponse response,
MvcResult delegate) {
this.delegate = delegate;
this.response = response;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws IllegalAccessException,
InvocationTargetException {
if (this.getResponseMethod.equals(method)) {
return this.response;
}
return method.invoke(this.delegate, args);
}
private Method findMethod(String methodName) {
return BridgeMethodResolver.findBridgedMethod(ReflectionUtils.findMethod(
MvcResult.class, methodName));
}
}
}
}

View File

@@ -17,11 +17,10 @@
package org.springframework.restdocs;
import org.springframework.restdocs.config.RestDocumentationConfigurer;
import org.springframework.restdocs.response.ResponsePostProcessor;
import org.springframework.restdocs.response.ResponsePostProcessors;
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.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
@@ -50,7 +49,7 @@ public abstract class RestDocumentation {
/**
* Documents the API call with the given {@code identifier} using the given
* {@code handlers}.
* {@code snippets}.
*
* @param identifier an identifier for the API call that is being documented
* @param snippets the snippets that will document the API call
@@ -64,17 +63,60 @@ public abstract class RestDocumentation {
}
/**
* Enables the modification of the response in a {@link MvcResult} prior to it being
* documented. The modification is performed using the given
* {@code responsePostProcessors}.
* 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 responsePostProcessors the post-processors to use to modify the response
* @return the response modifier
* @see ResponsePostProcessors
* @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 ResponseModifier modifyResponseTo(
ResponsePostProcessor... responsePostProcessors) {
return new ResponseModifier(responsePostProcessors);
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);
}
}

View File

@@ -26,10 +26,16 @@ import java.util.Map;
import org.springframework.restdocs.operation.MockMvcOperationRequestFactory;
import org.springframework.restdocs.operation.MockMvcOperationResponseFactory;
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.
@@ -42,10 +48,39 @@ 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);
}
@@ -55,11 +90,15 @@ public class RestDocumentationResultHandler implements ResultHandler {
for (String name : iterable(result.getRequest().getAttributeNames())) {
attributes.put(name, result.getRequest().getAttribute(name));
}
StandardOperation operation = new StandardOperation(this.identifier,
new MockMvcOperationRequestFactory().createOperationRequest(result
.getRequest()),
new MockMvcOperationResponseFactory().createOperationResponse(result
.getResponse()), attributes);
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);
}
@@ -74,4 +113,24 @@ public class RestDocumentationResultHandler implements ResultHandler {
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;
}
}
}

View File

@@ -59,7 +59,7 @@ public class StandardOperationRequest implements OperationRequest {
Collection<OperationRequestPart> parts) {
this.uri = uri;
this.method = method;
this.content = content == null ? new byte[0] : content;
this.content = content;
this.headers = headers;
this.parameters = parameters;
this.parts = parts;

View File

@@ -44,7 +44,7 @@ public class StandardOperationResponse implements OperationResponse {
byte[] content) {
this.status = status;
this.headers = headers;
this.content = content == null ? new byte[0] : content;
this.content = content;
}
@Override

View File

@@ -14,26 +14,27 @@
* limitations under the License.
*/
package org.springframework.restdocs.response;
package org.springframework.restdocs.operation.preprocess;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationResponse;
/**
* A {@code ResponsePostProcessor} is used to modify the response received from a MockMvc
* call prior to the response being documented.
* A {@code ContentModifier} modifies the content of an {@link OperationRequest} or
* {@link OperationResponse} during the preprocessing that is performed prior to
* documentation generation.
*
* @author Andy Wilkinson
* @see ContentModifyingOperationPreprocessor
*/
public interface ResponsePostProcessor {
interface ContentModifier {
/**
* Post-processes the given {@code response}, returning a, possibly new,
* {@link MockHttpServletResponse} that should now be used.
* Returns modified content based on the given {@code originalContent}
*
* @param response The response to post-process
* @return The result of the post-processing
* @throws Exception if a failure occurs during the post-processing
* @param originalContent the original content
* @return the modified content
*/
MockHttpServletResponse postProcess(MockHttpServletResponse response)
throws Exception;
byte[] modifyContent(byte[] originalContent);
}

View File

@@ -0,0 +1,65 @@
/*
* 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.operation.preprocess;
import org.springframework.http.HttpHeaders;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.StandardOperationRequest;
import org.springframework.restdocs.operation.StandardOperationResponse;
/**
* An {@link OperationPreprocessor} that applies a {@link ContentModifier} to the content
* of the request or response.
*
* @author Andy Wilkinson
*/
class ContentModifyingOperationPreprocessor implements OperationPreprocessor {
private final ContentModifier contentModifier;
ContentModifyingOperationPreprocessor(ContentModifier contentModifier) {
this.contentModifier = contentModifier;
}
@Override
public OperationRequest preprocess(OperationRequest request) {
byte[] modifiedContent = this.contentModifier.modifyContent(request.getContent());
return new StandardOperationRequest(request.getUri(), request.getMethod(),
modifiedContent,
getUpdatedHeaders(request.getHeaders(), modifiedContent),
request.getParameters(), request.getParts());
}
@Override
public OperationResponse preprocess(OperationResponse response) {
byte[] modifiedContent = this.contentModifier
.modifyContent(response.getContent());
return new StandardOperationResponse(response.getStatus(), getUpdatedHeaders(
response.getHeaders(), modifiedContent), modifiedContent);
}
private HttpHeaders getUpdatedHeaders(HttpHeaders headers, byte[] updatedContent) {
HttpHeaders updatedHeaders = new HttpHeaders();
updatedHeaders.putAll(headers);
if (updatedHeaders.getContentLength() > -1) {
updatedHeaders.setContentLength(updatedContent.length);
}
return updatedHeaders;
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.operation.preprocess;
import java.util.List;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.util.Assert;
/**
* An {@link OperationRequestPreprocessor} that delgates to one or more
* {@link OperationPreprocessor OperationPreprocessors} to preprocess an
* {@link OperationRequest}.
*
* @author Andy Wilkinson
*
*/
class DelegatingOperationRequestPreprocessor implements OperationRequestPreprocessor {
private final List<OperationPreprocessor> delegates;
/**
* Creates a new {@code DelegatingOperationRequestPreprocessor} that will delegate to
* the given {@code delegates} by calling
* {@link OperationPreprocessor#preprocess(OperationRequest)}.
*
* @param delegates the delegates
*/
DelegatingOperationRequestPreprocessor(List<OperationPreprocessor> delegates) {
Assert.notNull(delegates, "delegates must be non-null");
this.delegates = delegates;
}
@Override
public OperationRequest preprocess(OperationRequest operationRequest) {
OperationRequest preprocessedRequest = operationRequest;
for (OperationPreprocessor delegate : this.delegates) {
preprocessedRequest = delegate.preprocess(preprocessedRequest);
}
return preprocessedRequest;
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.operation.preprocess;
import java.util.List;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.util.Assert;
/**
* An {@link OperationResponsePreprocessor} that delgates to one or more
* {@link OperationPreprocessor OperationPreprocessors} to preprocess an
* {@link OperationResponse}.
*
* @author Andy Wilkinson
*/
class DelegatingOperationResponsePreprocessor implements OperationResponsePreprocessor {
private final List<OperationPreprocessor> delegates;
/**
* Creates a new {@code DelegatingOperationResponsePreprocessor} that will delegate to
* the given {@code delegates} by calling
* {@link OperationPreprocessor#preprocess(OperationResponse)}.
*
* @param delegates the delegates
*/
DelegatingOperationResponsePreprocessor(List<OperationPreprocessor> delegates) {
Assert.notNull(delegates, "delegates must be non-null");
this.delegates = delegates;
}
@Override
public OperationResponse preprocess(OperationResponse response) {
OperationResponse preprocessedResponse = response;
for (OperationPreprocessor delegate : this.delegates) {
preprocessedResponse = delegate.preprocess(preprocessedResponse);
}
return preprocessedResponse;
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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.operation.preprocess;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.springframework.http.HttpHeaders;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.StandardOperationRequest;
import org.springframework.restdocs.operation.StandardOperationResponse;
/**
* An {@link OperationPreprocessor} that removes headers
*
* @author Andy Wilkinson
*/
class HeaderRemovingOperationPreprocessor implements OperationPreprocessor {
private final Set<String> headersToRemove;
HeaderRemovingOperationPreprocessor(String... headersToRemove) {
this.headersToRemove = new HashSet<>(Arrays.asList(headersToRemove));
}
@Override
public OperationResponse preprocess(OperationResponse response) {
return new StandardOperationResponse(response.getStatus(),
removeHeaders(response.getHeaders()), response.getContent());
}
@Override
public OperationRequest preprocess(OperationRequest request) {
return new StandardOperationRequest(request.getUri(), request.getMethod(),
request.getContent(), removeHeaders(request.getHeaders()),
request.getParameters(), request.getParts());
}
private HttpHeaders removeHeaders(HttpHeaders originalHeaders) {
HttpHeaders processedHeaders = new HttpHeaders();
processedHeaders.putAll(originalHeaders);
for (String headerToRemove : this.headersToRemove) {
processedHeaders.remove(headerToRemove);
}
return processedHeaders;
}
}

View File

@@ -14,30 +14,35 @@
* limitations under the License.
*/
package org.springframework.restdocs.response;
package org.springframework.restdocs.operation.preprocess;
import java.util.regex.Pattern;
/**
* A {@link ResponsePostProcessor} that modifies the content of a hypermedia response to
* mask the hrefs of any links.
* A content modifier the masks the {@code href} of any hypermedia links
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
class LinkMaskingResponsePostProcessor extends PatternReplacingResponsePostProcessor {
class LinkMaskingContentModifier implements ContentModifier {
private static final String DEFAULT_MASK = "...";
private static final Pattern LINK_HREF = Pattern.compile(
"\"href\"\\s*:\\s*\"(.*?)\"", Pattern.DOTALL);
LinkMaskingResponsePostProcessor() {
super(LINK_HREF, DEFAULT_MASK);
private final ContentModifier contentModifier;
LinkMaskingContentModifier() {
this(DEFAULT_MASK);
}
LinkMaskingResponsePostProcessor(String mask) {
super(LINK_HREF, mask);
LinkMaskingContentModifier(String mask) {
this.contentModifier = new PatternReplacingContentModifier(LINK_HREF, mask);
}
@Override
public byte[] modifyContent(byte[] originalContent) {
return this.contentModifier.modifyContent(originalContent);
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.operation.preprocess;
import org.springframework.restdocs.operation.Operation;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationResponse;
/**
* An {@code OperationPreprocessor} processes the {@link OperationRequest} and
* {@link OperationResponse} of an {@link Operation} prior to it being documented.
*
* @author Andy Wilkinson
*/
public interface OperationPreprocessor {
/**
* Processes the given {@code request}
*
* @param request the request to process
* @return the processed request
*/
OperationRequest preprocess(OperationRequest request);
/**
* Processes the given {@code response}
*
* @param response the response to process
* @return the processed response
*/
OperationResponse preprocess(OperationResponse response);
}

View File

@@ -0,0 +1,38 @@
/*
* 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.operation.preprocess;
import org.springframework.restdocs.operation.OperationRequest;
/**
* An {@code OperationRequestPreprocessor} is used to modify an {@code OperationRequest}
* prior to it being documented.
*
* @author Andy Wilkinson
*/
public interface OperationRequestPreprocessor {
/**
* Processes and potentially modifies the given {@code request} before it is
* documented.
*
* @param request the request
* @return the modified request
*/
OperationRequest preprocess(OperationRequest request);
}

View File

@@ -0,0 +1,22 @@
package org.springframework.restdocs.operation.preprocess;
import org.springframework.restdocs.operation.OperationResponse;
/**
* An {@code OperationRequestPreprocessor} is used to modify an {@code OperationRequest}
* prior to it being documented.
*
* @author Andy Wilkinson
*/
public interface OperationResponsePreprocessor {
/**
* Processes and potentially modifies the given {@code response} before it is
* documented.
*
* @param response the response
* @return the modified response
*/
OperationResponse preprocess(OperationResponse response);
}

View File

@@ -14,43 +14,51 @@
* limitations under the License.
*/
package org.springframework.restdocs.response;
package org.springframework.restdocs.operation.preprocess;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A {@link ResponsePostProcessor} that modifies the content of the response by replacing
* occurrences of a regular expression {@link Pattern}.
* A {@link ContentModifier} that modifies the content by replacing occurrences of a
* regular expression {@link Pattern}.
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
class PatternReplacingResponsePostProcessor extends ContentModifyingReponsePostProcessor {
class PatternReplacingContentModifier implements ContentModifier {
private final Pattern pattern;
private final String replacement;
PatternReplacingResponsePostProcessor(Pattern pattern, String replacement) {
/**
* Creates a new {@link PatternReplacingContentModifier} that will replace occurences
* the given {@code pattern} with the given {@code replacement}.
*
* @param pattern the pattern
* @param replacement the replacement
*/
PatternReplacingContentModifier(Pattern pattern, String replacement) {
this.pattern = pattern;
this.replacement = replacement;
}
@Override
protected String modifyContent(String originalContent) {
Matcher matcher = this.pattern.matcher(originalContent);
public byte[] modifyContent(byte[] content) {
String original = new String(content);
Matcher matcher = this.pattern.matcher(original);
StringBuilder buffer = new StringBuilder();
int previous = 0;
while (matcher.find()) {
buffer.append(originalContent.substring(previous, matcher.start(1)));
buffer.append(original.substring(previous, matcher.start(1)));
buffer.append(this.replacement);
previous = matcher.end(1);
}
if (previous < originalContent.length()) {
buffer.append(originalContent.substring(previous));
if (previous < original.length()) {
buffer.append(original.substring(previous));
}
return buffer.toString();
return buffer.toString().getBytes();
}
}

View File

@@ -0,0 +1,122 @@
/*
* 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.operation.preprocess;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.springframework.restdocs.operation.Operation;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationResponse;
/**
* Static factory methods for creating {@link OperationPreprocessor
* OperationPreprocessors} that can be applied to an {@link Operation Operation's}
* {@link OperationRequest request} or {@link OperationResponse response} before it is
* documented.
*
* @author Andy Wilkinson
*/
public class Preprocessors {
private Preprocessors() {
}
/**
* Returns an {@link OperationRequestPreprocessor} that will preprocess the request by
* applying the given {@code preprocessors} to it.
*
* @param preprocessors the preprocessors
* @return the request preprocessor
*/
public static OperationRequestPreprocessor preprocessRequest(
OperationPreprocessor... preprocessors) {
return new DelegatingOperationRequestPreprocessor(Arrays.asList(preprocessors));
}
/**
* Returns an {@link OperationResponsePreprocessor} that will preprocess the response
* by applying the given {@code preprocessors} to it.
*
* @param preprocessors the preprocessors
* @return the response preprocessor
*/
public static OperationResponsePreprocessor preprocessResponse(
OperationPreprocessor... preprocessors) {
return new DelegatingOperationResponsePreprocessor(Arrays.asList(preprocessors));
}
/**
* Returns an {@code OperationPreprocessor} that will pretty print the content of the
* request or response.
*
* @return the preprocessor
*/
public static OperationPreprocessor prettyPrint() {
return new ContentModifyingOperationPreprocessor(
new PrettyPrintingContentModifier());
}
/**
* Returns an {@code OperationPreprocessor} that will remove headers from the request
* or response.
*
* @param headersToRemove the names of the headers to remove
* @return the preprocessor
*/
public static OperationPreprocessor removeHeaders(String... headersToRemove) {
return new HeaderRemovingOperationPreprocessor(headersToRemove);
}
/**
* Returns an {@code OperationPreprocessor} that will mask the href of hypermedia
* links in the request or response.
*
* @return the preprocessor
*/
public static OperationPreprocessor maskLinks() {
return new ContentModifyingOperationPreprocessor(new LinkMaskingContentModifier());
}
/**
* Returns an {@code OperationPreprocessor} that will mask the href of hypermedia
* links in the request or response.
*
* @param mask the link mask
* @return the preprocessor
*/
public static OperationPreprocessor maskLinks(String mask) {
return new ContentModifyingOperationPreprocessor(new LinkMaskingContentModifier(
mask));
}
/**
* Returns an {@code OperationPreprocessor} that will modify the content of the
* request or response by replacing occurences of the given {@code pattern} with the
* given {@code replacement}
*
* @param pattern the pattern
* @param replacement the replacement
* @return the preprocessor
*/
public static OperationPreprocessor replacePattern(Pattern pattern, String replacement) {
return new ContentModifyingOperationPreprocessor(
new PatternReplacingContentModifier(pattern, replacement));
}
}

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
package org.springframework.restdocs.response;
package org.springframework.restdocs.operation.preprocess;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
@@ -29,27 +29,28 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
class PrettyPrintingResponsePostProcessor extends ContentModifyingReponsePostProcessor {
/**
* A {@link ContentModifier} that modifies the content by pretty printing it.
*
* @author Andy Wilkinson
*/
public class PrettyPrintingContentModifier implements ContentModifier {
private static final List<PrettyPrinter> PRETTY_PRINTERS = Collections
.unmodifiableList(Arrays.asList(new JsonPrettyPrinter(),
new XmlPrettyPrinter()));
@Override
protected String modifyContent(String originalContent) {
if (StringUtils.hasText(originalContent)) {
for (PrettyPrinter prettyPrinter : PRETTY_PRINTERS) {
try {
return prettyPrinter.prettyPrint(originalContent);
}
catch (Exception ex) {
// Continue
}
public byte[] modifyContent(byte[] originalContent) {
for (PrettyPrinter prettyPrinter : PRETTY_PRINTERS) {
try {
return prettyPrinter.prettyPrint(originalContent).getBytes();
}
catch (Exception ex) {
// Continue
}
}
return originalContent;
@@ -57,21 +58,21 @@ class PrettyPrintingResponsePostProcessor extends ContentModifyingReponsePostPro
private interface PrettyPrinter {
String prettyPrint(String string) throws Exception;
String prettyPrint(byte[] content) throws Exception;
}
private static final class XmlPrettyPrinter implements PrettyPrinter {
@Override
public String prettyPrint(String original) throws Exception {
public String prettyPrint(byte[] original) throws Exception {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
"4");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
StringWriter transformed = new StringWriter();
transformer.transform(new StreamSource(new StringReader(original)),
transformer.transform(new StreamSource(new ByteArrayInputStream(original)),
new StreamResult(transformed));
return transformed.toString();
}
@@ -80,7 +81,7 @@ class PrettyPrintingResponsePostProcessor extends ContentModifyingReponsePostPro
private static final class JsonPrettyPrinter implements PrettyPrinter {
@Override
public String prettyPrint(String original) throws IOException {
public String prettyPrint(byte[] original) throws IOException {
ObjectMapper objectMapper = new ObjectMapper().configure(
SerializationFeature.INDENT_OUTPUT, true);
return objectMapper.writeValueAsString(objectMapper.readTree(original));

View File

@@ -1,96 +0,0 @@
/*
* 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.response;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.ReflectionUtils;
/**
* A base class for {@link ResponsePostProcessor ResponsePostProcessors} that modify the
* content of the response.
*
* @author Andy Wilkinson
*/
public abstract class ContentModifyingReponsePostProcessor implements
ResponsePostProcessor {
@Override
public MockHttpServletResponse postProcess(MockHttpServletResponse response)
throws Exception {
String modifiedContent = modifyContent(response.getContentAsString());
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MockHttpServletResponse.class);
enhancer.setCallback(new ContentModifyingMethodInterceptor(modifiedContent,
response));
return (MockHttpServletResponse) enhancer.create();
}
/**
* Returns a modified version of the given {@code originalContent}
*
* @param originalContent the content to modify
* @return the modified content
* @throws Exception if a failure occurs while modifying the content
*/
protected abstract String modifyContent(String originalContent) throws Exception;
private static class ContentModifyingMethodInterceptor implements MethodInterceptor {
private final Method getContentAsStringMethod = findMethod("getContentAsString");
private final Method getContentAsByteArray = findMethod("getContentAsByteArray");
private final String modifiedContent;
private final MockHttpServletResponse delegate;
private ContentModifyingMethodInterceptor(String modifiedContent,
MockHttpServletResponse delegate) {
this.modifiedContent = modifiedContent;
this.delegate = delegate;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws IllegalAccessException,
InvocationTargetException {
if (this.getContentAsStringMethod.equals(method)) {
return this.modifiedContent;
}
if (this.getContentAsByteArray.equals(method)) {
return this.modifiedContent.getBytes();
}
return method.invoke(this.delegate, args);
}
private static Method findMethod(String methodName) {
return BridgeMethodResolver.findBridgedMethod(ReflectionUtils.findMethod(
MockHttpServletResponse.class, methodName));
}
}
}

View File

@@ -1,134 +0,0 @@
/*
* 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.response;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.ReflectionUtils;
/**
* A {@link ResponsePostProcessor} that removes headers from the response
*
* @author Andy Wilkinson
*/
class HeaderRemovingResponsePostProcessor implements ResponsePostProcessor {
private final Set<String> headersToRemove;
HeaderRemovingResponsePostProcessor(String... headersToRemove) {
this.headersToRemove = new HashSet<>(Arrays.asList(headersToRemove));
}
@Override
public MockHttpServletResponse postProcess(final MockHttpServletResponse response) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MockHttpServletResponse.class);
enhancer.setCallback(new HeaderHidingMethodInterceptor(this.headersToRemove,
response));
return (MockHttpServletResponse) enhancer.create();
}
private static final class HeaderHidingMethodInterceptor implements MethodInterceptor {
private final MockHttpServletResponse response;
private final List<Method> interceptedMethods = Arrays.asList(
findHeaderMethod("containsHeader", String.class),
findHeaderMethod("getHeader", String.class),
findHeaderMethod("getHeaderValue", String.class),
findHeaderMethod("getHeaders", String.class),
findHeaderMethod("getHeaderValues", String.class));
private final Method getHeaderNamesMethod = findHeaderMethod("getHeaderNames");
private final Set<String> hiddenHeaders;
private HeaderHidingMethodInterceptor(Set<String> hiddenHeaders,
MockHttpServletResponse response) {
this.hiddenHeaders = hiddenHeaders;
this.response = response;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws IllegalAccessException,
InvocationTargetException {
if (this.getHeaderNamesMethod.equals(method)) {
List<String> headerNames = new ArrayList<>();
for (String candidate : this.response.getHeaderNames()) {
if (!isHiddenHeader(candidate)) {
headerNames.add(candidate);
}
}
return headerNames;
}
if (this.interceptedMethods.contains(method) && isHiddenHeader(args)) {
if (method.getReturnType().equals(boolean.class)) {
return false;
}
else if (Collection.class.isAssignableFrom(method.getReturnType())) {
return Collections.emptyList();
}
else {
return null;
}
}
return method.invoke(this.response, args);
}
private boolean isHiddenHeader(Object[] args) {
if (args.length == 1 && args[0] instanceof String) {
return isHiddenHeader((String) args[0]);
}
return false;
}
private boolean isHiddenHeader(String headerName) {
for (String hiddenHeader : this.hiddenHeaders) {
if (hiddenHeader.equalsIgnoreCase(headerName)) {
return true;
}
}
return false;
}
private static Method findHeaderMethod(String methodName, Class<?>... args) {
Method candidate = ReflectionUtils.findMethod(MockHttpServletResponse.class,
methodName, args);
if (candidate.isBridge()) {
return BridgeMethodResolver.findBridgedMethod(candidate);
}
return candidate;
}
}
}

View File

@@ -1,91 +0,0 @@
/*
* 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.response;
import java.util.regex.Pattern;
/**
* Static factory methods for accessing various {@link ResponsePostProcessor
* ResponsePostProcessors}.
*
* @author Andy Wilkinson
* @author Dewet Diener
*/
public abstract class ResponsePostProcessors {
private ResponsePostProcessors() {
}
/**
* Returns a {@link ResponsePostProcessor} that will pretty print the content of the
* response.
*
* @return the response post-processor
*/
public static ResponsePostProcessor prettyPrintContent() {
return new PrettyPrintingResponsePostProcessor();
}
/**
* Returns a {@link ResponsePostProcessor} that will remove the headers with the given
* {@code headerNames} from the response.
*
* @param headerNames the name of the headers to remove
* @return the response post-processor
*/
public static ResponsePostProcessor removeHeaders(String... headerNames) {
return new HeaderRemovingResponsePostProcessor(headerNames);
}
/**
* Returns a {@link ResponsePostProcessor} that will update the content of the
* response to mask any links that it contains. Each link is masked my replacing its
* {@code href} with {@code ...}.
*
* @return the response post-processor
*/
public static ResponsePostProcessor maskLinks() {
return new LinkMaskingResponsePostProcessor();
}
/**
* Returns a {@link ResponsePostProcessor} that will update the content of the
* response to mask any links that it contains. Each link is masked my replacing its
* {@code href} with the given {@code mask}.
*
* @param mask the mask to apply
* @return the response post-processor
*/
public static ResponsePostProcessor maskLinksWith(String mask) {
return new LinkMaskingResponsePostProcessor(mask);
}
/**
* Returns a {@link ResponsePostProcessor} that will update the content of the
* response by replacing any occurrences of the given {@code pattern} with the given
* {@code replacement}.
*
* @param pattern the pattern to match
* @param replacement the replacement to apply
* @return the response post-processor
*/
public static ResponsePostProcessor replacePattern(Pattern pattern, String replacement) {
return new PatternReplacingResponsePostProcessor(pattern, replacement);
}
}

View File

@@ -1,59 +0,0 @@
/*
* 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;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.springframework.restdocs.test.StubMvcResult.result;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.restdocs.ResponseModifier.ResponseModifyingRestDocumentationResultHandler;
import org.springframework.restdocs.response.ResponsePostProcessor;
/**
* Tests for {@link ResponseModifier}
*
* @author Andy Wilkinson
*
*/
public class ResponseModifierTests {
@Test
public void postProcessorsAreApplied() throws Exception {
ResponsePostProcessor first = mock(ResponsePostProcessor.class);
ResponsePostProcessor second = mock(ResponsePostProcessor.class);
MockHttpServletResponse original = new MockHttpServletResponse();
MockHttpServletResponse afterFirst = new MockHttpServletResponse();
MockHttpServletResponse afterSecond = new MockHttpServletResponse();
given(first.postProcess(original)).willReturn(afterFirst);
given(second.postProcess(afterFirst)).willReturn(afterSecond);
RestDocumentationResultHandler resultHandler = new ResponseModifier(first, second)
.andDocument("test");
assertThat(
afterSecond,
is(equalTo(((ResponseModifyingRestDocumentationResultHandler) resultHandler)
.postProcessResponse(result(original)).getResponse())));
}
}

View File

@@ -21,23 +21,25 @@ import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.springframework.restdocs.RestDocumentation.document;
import static org.springframework.restdocs.RestDocumentation.modifyResponseTo;
import static org.springframework.restdocs.RestDocumentationRequestBuilders.get;
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.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.response.ResponsePostProcessors.maskLinks;
import static org.springframework.restdocs.response.ResponsePostProcessors.prettyPrintContent;
import static org.springframework.restdocs.response.ResponsePostProcessors.removeHeaders;
import static org.springframework.restdocs.response.ResponsePostProcessors.replacePattern;
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;
@@ -71,6 +73,7 @@ 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;
@@ -236,15 +239,62 @@ public class RestDocumentationIntegrationTests {
}
@Test
public void postProcessedResponse() throws Exception {
public void preprocessedRequest() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(new RestDocumentationConfigurer()).build();
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document("original"));
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/http-response.adoc"),
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(new RestDocumentationConfigurer()).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")
@@ -252,16 +302,9 @@ public class RestDocumentationIntegrationTests {
.content(
"{\"a\":\"alpha\",\"links\":[{\"rel\":\"rel\","
+ "\"href\":\"href\"}]}"))));
Pattern pattern = Pattern.compile("(\"alpha\")");
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(modifyResponseTo(prettyPrintContent(), removeHeaders("a"),
replacePattern(pattern, "\"<<beta>>\""), maskLinks())
.andDocument("post-processed"));
assertThat(
new File("build/generated-snippets/post-processed/http-response.adoc"),
new File(
"build/generated-snippets/preprocessed-response/http-response.adoc"),
is(snippet().withContents(
httpResponse(HttpStatus.OK).header("Content-Type",
"application/json").content(

View File

@@ -0,0 +1,79 @@
package org.springframework.restdocs.operation.preprocess;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.Collections;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.Parameters;
import org.springframework.restdocs.operation.StandardOperationRequest;
import org.springframework.restdocs.operation.StandardOperationResponse;
/**
* Tests for {@link ContentModifyingOperationPreprocessor}
*
* @author Andy Wilkinson
*
*/
public class ContentModifyingOperationPreprocessorTests {
private final ContentModifyingOperationPreprocessor preprocessor = new ContentModifyingOperationPreprocessor(
new ContentModifier() {
@Override
public byte[] modifyContent(byte[] originalContent) {
return "modified".getBytes();
}
});
@Test
public void modifyRequestContent() {
StandardOperationRequest request = new StandardOperationRequest(
URI.create("http://localhost"), HttpMethod.GET, "content".getBytes(),
new HttpHeaders(), new Parameters(),
Collections.<OperationRequestPart> emptyList());
OperationRequest preprocessed = this.preprocessor.preprocess(request);
assertThat(preprocessed.getContent(), is(equalTo("modified".getBytes())));
}
@Test
public void modifyResponseContent() {
StandardOperationResponse response = new StandardOperationResponse(HttpStatus.OK,
new HttpHeaders(), "content".getBytes());
OperationResponse preprocessed = this.preprocessor.preprocess(response);
assertThat(preprocessed.getContent(), is(equalTo("modified".getBytes())));
}
@Test
public void unknownContentLengthIsUnchanged() {
StandardOperationRequest request = new StandardOperationRequest(
URI.create("http://localhost"), HttpMethod.GET, "content".getBytes(),
new HttpHeaders(), new Parameters(),
Collections.<OperationRequestPart> emptyList());
OperationRequest preprocessed = this.preprocessor.preprocess(request);
assertThat(preprocessed.getHeaders().getContentLength(), is(equalTo(-1L)));
}
@Test
public void contentLengthIsUpdated() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentLength(7);
StandardOperationRequest request = new StandardOperationRequest(
URI.create("http://localhost"), HttpMethod.GET, "content".getBytes(),
httpHeaders, new Parameters(),
Collections.<OperationRequestPart> emptyList());
OperationRequest preprocessed = this.preprocessor.preprocess(request);
assertThat(preprocessed.getHeaders().getContentLength(), is(equalTo(8L)));
}
}

View File

@@ -0,0 +1,62 @@
package org.springframework.restdocs.operation.preprocess;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasEntry;
import static org.junit.Assert.assertThat;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.Parameters;
import org.springframework.restdocs.operation.StandardOperationRequest;
import org.springframework.restdocs.operation.StandardOperationResponse;
/**
* Tests for {@link HeaderRemovingOperationPreprocessorTests}
*
* @author Andy Wilkinson
*
*/
public class HeaderRemovingOperationPreprocessorTests {
private final HeaderRemovingOperationPreprocessor preprocessor = new HeaderRemovingOperationPreprocessor(
"b");
@Test
public void modifyRequestHeaders() {
StandardOperationRequest request = new StandardOperationRequest(
URI.create("http://localhost"), HttpMethod.GET, new byte[0],
getHttpHeaders(), new Parameters(),
Collections.<OperationRequestPart> emptyList());
OperationRequest preprocessed = this.preprocessor.preprocess(request);
assertThat(preprocessed.getHeaders().size(), is(equalTo(1)));
assertThat(preprocessed.getHeaders(), hasEntry("a", Arrays.asList("alpha")));
}
@Test
public void modifyResponseHeaders() {
StandardOperationResponse response = new StandardOperationResponse(HttpStatus.OK,
getHttpHeaders(), new byte[0]);
OperationResponse preprocessed = this.preprocessor.preprocess(response);
assertThat(preprocessed.getHeaders().size(), is(equalTo(1)));
assertThat(preprocessed.getHeaders(), hasEntry("a", Arrays.asList("alpha")));
}
private HttpHeaders getHttpHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("a", "alpha");
httpHeaders.add("b", "bravo");
httpHeaders.add("b", "banana");
return httpHeaders;
}
}

View File

@@ -1,20 +1,4 @@
/*
* 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.response;
package org.springframework.restdocs.operation.preprocess;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
@@ -34,9 +18,15 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class LinkMaskingResponsePostProcessorTests {
/**
* Tests for {@link LinkMaskingContentModifier}
*
* @author Andy Wilkinson
*
*/
public class LinkMaskingContentModifierTests {
private final LinkMaskingResponsePostProcessor postProcessor = new LinkMaskingResponsePostProcessor();
private final ContentModifier contentModifier = new LinkMaskingContentModifier();
private final Link[] links = new Link[] { new Link("a", "alpha"),
new Link("b", "bravo") };
@@ -46,28 +36,28 @@ public class LinkMaskingResponsePostProcessorTests {
@Test
public void halLinksAreMasked() throws Exception {
assertThat(this.postProcessor.modifyContent(halPayloadWithLinks(this.links)),
assertThat(this.contentModifier.modifyContent(halPayloadWithLinks(this.links)),
is(equalTo(halPayloadWithLinks(this.maskedLinks))));
}
@Test
public void formattedHalLinksAreMasked() throws Exception {
assertThat(
this.postProcessor
this.contentModifier
.modifyContent(formattedHalPayloadWithLinks(this.links)),
is(equalTo(formattedHalPayloadWithLinks(this.maskedLinks))));
}
@Test
public void atomLinksAreMasked() throws Exception {
assertThat(this.postProcessor.modifyContent(atomPayloadWithLinks(this.links)),
assertThat(this.contentModifier.modifyContent(atomPayloadWithLinks(this.links)),
is(equalTo(atomPayloadWithLinks(this.maskedLinks))));
}
@Test
public void formattedAtomLinksAreMasked() throws Exception {
assertThat(
this.postProcessor
this.contentModifier
.modifyContent(formattedAtomPayloadWithLinks(this.links)),
is(equalTo(formattedAtomPayloadWithLinks(this.maskedLinks))));
}
@@ -75,20 +65,20 @@ public class LinkMaskingResponsePostProcessorTests {
@Test
public void maskCanBeCustomized() throws Exception {
assertThat(
new LinkMaskingResponsePostProcessor("custom")
new LinkMaskingContentModifier("custom")
.modifyContent(formattedAtomPayloadWithLinks(this.links)),
is(equalTo(formattedAtomPayloadWithLinks(new Link("a", "custom"),
new Link("b", "custom")))));
}
private String atomPayloadWithLinks(Link... links) throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(createAtomPayload(links));
private byte[] atomPayloadWithLinks(Link... links) throws JsonProcessingException {
return new ObjectMapper().writeValueAsBytes(createAtomPayload(links));
}
private String formattedAtomPayloadWithLinks(Link... links)
private byte[] formattedAtomPayloadWithLinks(Link... links)
throws JsonProcessingException {
return new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true)
.writeValueAsString(createAtomPayload(links));
.writeValueAsBytes(createAtomPayload(links));
}
private AtomPayload createAtomPayload(Link... links) {
@@ -97,14 +87,14 @@ public class LinkMaskingResponsePostProcessorTests {
return payload;
}
private String halPayloadWithLinks(Link... links) throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(createHalPayload(links));
private byte[] halPayloadWithLinks(Link... links) throws JsonProcessingException {
return new ObjectMapper().writeValueAsBytes(createHalPayload(links));
}
private String formattedHalPayloadWithLinks(Link... links)
private byte[] formattedHalPayloadWithLinks(Link... links)
throws JsonProcessingException {
return new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true)
.writeValueAsString(createHalPayload(links));
.writeValueAsBytes(createHalPayload(links));
}
private HalPayload createHalPayload(Link... links) {

View File

@@ -0,0 +1,31 @@
package org.springframework.restdocs.operation.preprocess;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.regex.Pattern;
import org.junit.Test;
/**
* Tests for {@link PatternReplacingContentModifier}
*
* @author Andy Wilkinson
*
*/
public class PatternReplacingContentModifierTests {
@Test
public void patternsAreReplaced() throws Exception {
Pattern pattern = Pattern.compile(
"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})",
Pattern.CASE_INSENSITIVE);
PatternReplacingContentModifier contentModifier = new PatternReplacingContentModifier(
pattern, "<<uuid>>");
assertThat(
contentModifier.modifyContent("{\"id\" : \"CA761232-ED42-11CE-BACD-00AA0057B223\"}"
.getBytes()), is(equalTo("{\"id\" : \"<<uuid>>\"}".getBytes())));
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.restdocs.response;
package org.springframework.restdocs.operation.preprocess;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
@@ -22,38 +22,40 @@ import static org.junit.Assert.assertThat;
import org.junit.Test;
/**
* Tests for {@link PrettyPrintingResponsePostProcessor}
* Tests for {@link PrettyPrintingContentModifier}
*
* @author Andy Wilkinson
*
*/
public class PrettyPrintingResponsePostProcessorTests {
public class PrettyPrintingContentModifierTests {
@Test
public void prettyPrintJson() throws Exception {
assertThat(new PrettyPrintingResponsePostProcessor().modifyContent("{\"a\":5}"),
equalTo(String.format("{%n \"a\" : 5%n}")));
assertThat(
new PrettyPrintingContentModifier().modifyContent("{\"a\":5}".getBytes()),
equalTo(String.format("{%n \"a\" : 5%n}").getBytes()));
}
@Test
public void prettyPrintXml() throws Exception {
assertThat(
new PrettyPrintingResponsePostProcessor()
.modifyContent("<one a=\"alpha\"><two b=\"bravo\"/></one>"),
equalTo(String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n"
+ "<one a=\"alpha\">%n <two b=\"bravo\"/>%n</one>%n")));
new PrettyPrintingContentModifier().modifyContent("<one a=\"alpha\"><two b=\"bravo\"/></one>"
.getBytes()), equalTo(String.format(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n"
+ "<one a=\"alpha\">%n <two b=\"bravo\"/>%n</one>%n")
.getBytes()));
}
@Test
public void empytContentIsHandledGracefully() throws Exception {
assertThat(new PrettyPrintingResponsePostProcessor().modifyContent(""),
equalTo(""));
assertThat(new PrettyPrintingContentModifier().modifyContent("".getBytes()),
equalTo("".getBytes()));
}
@Test
public void nonJsonAndNonXmlContentIsHandledGracefully() throws Exception {
String content = "abcdefg";
assertThat(new PrettyPrintingResponsePostProcessor().modifyContent(content),
equalTo(content));
assertThat(new PrettyPrintingContentModifier().modifyContent(content.getBytes()),
equalTo(content.getBytes()));
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.response;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.mock.web.MockHttpServletResponse;
public class ContentModifyingResponsePostProcessorTests {
private final MockHttpServletResponse original = new MockHttpServletResponse();
private final ContentModifyingReponsePostProcessor postProcessor = new TestContentModifyingResponsePostProcessor();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void contentCanBeModified() throws Exception {
MockHttpServletResponse modified = this.postProcessor.postProcess(this.original);
assertThat(modified.getContentAsString(), is(equalTo("modified")));
assertThat(modified.getContentAsByteArray(), is(equalTo("modified".getBytes())));
}
@Test
public void nonContentMethodsAreDelegated() throws Exception {
this.original.addHeader("a", "alpha");
MockHttpServletResponse modified = this.postProcessor.postProcess(this.original);
assertThat(modified.getHeader("a"), is(equalTo("alpha")));
}
private static final class TestContentModifyingResponsePostProcessor extends
ContentModifyingReponsePostProcessor {
@Override
protected String modifyContent(String originalContent) throws Exception {
return "modified";
}
}
}

View File

@@ -1,91 +0,0 @@
/*
* 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.response;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Tests for {@link HeaderRemovingResponsePostProcessor}.
*
* @author Andy Wilkinson
*
*/
public class HeaderRemovingResponsePostProcessorTests {
private final MockHttpServletResponse response = new MockHttpServletResponse();
@Before
public void configureResponse() {
this.response.addHeader("a", "alpha");
this.response.addHeader("b", "bravo");
}
@Test
public void containsHeaderHonoursRemovedHeaders() {
MockHttpServletResponse response = removeHeaders("a");
assertThat(response.containsHeader("a"), is(false));
assertThat(response.containsHeader("b"), is(true));
}
@Test
public void getHeaderNamesHonoursRemovedHeaders() {
MockHttpServletResponse response = removeHeaders("a");
assertThat(response.getHeaderNames(), contains("b"));
}
@Test
public void getHeaderHonoursRemovedHeaders() {
MockHttpServletResponse response = removeHeaders("a");
assertThat(response.getHeader("a"), is(nullValue()));
assertThat(response.getHeader("b"), is("bravo"));
}
@Test
public void getHeadersHonoursRemovedHeaders() {
MockHttpServletResponse response = removeHeaders("a");
assertThat(response.getHeaders("a"), is(empty()));
assertThat(response.getHeaders("b"), contains("bravo"));
}
@Test
public void getHeaderValueHonoursRemovedHeaders() {
MockHttpServletResponse response = removeHeaders("a");
assertThat(response.getHeaderValue("a"), is(nullValue()));
assertThat(response.getHeaderValue("b"), is((Object) "bravo"));
}
@Test
public void getHeaderValuesHonoursRemovedHeaders() {
MockHttpServletResponse response = removeHeaders("a");
assertThat(response.getHeaderValues("a"), is(empty()));
assertThat(response.getHeaderValues("b"), contains((Object) "bravo"));
}
private MockHttpServletResponse removeHeaders(String... headerNames) {
return new HeaderRemovingResponsePostProcessor(headerNames)
.postProcess(this.response);
}
}

View File

@@ -1,47 +0,0 @@
/*
* 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.response;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.regex.Pattern;
import org.junit.Test;
/**
* Tests for {@link PatternReplacingResponsePostProcessor}.
*
* @author Dewet Diener
*/
public class PatternReplacingResponsePostProcessorTests {
@Test
public void patternsAreReplaced() throws Exception {
Pattern pattern = Pattern.compile(
"([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})",
Pattern.CASE_INSENSITIVE);
PatternReplacingResponsePostProcessor postProcessor = new PatternReplacingResponsePostProcessor(
pattern, "<<uuid>>");
assertThat(
postProcessor
.modifyContent("{\"id\" : \"CA761232-ED42-11CE-BACD-00AA0057B223\"}"),
is(equalTo("{\"id\" : \"<<uuid>>\"}")));
}
}