diff --git a/docs/src/docs/asciidoc/configuration.adoc b/docs/src/docs/asciidoc/configuration.adoc index af45dad3..35490f79 100644 --- a/docs/src/docs/asciidoc/configuration.adoc +++ b/docs/src/docs/asciidoc/configuration.adoc @@ -114,3 +114,23 @@ include::{examples-dir}/com/example/mockmvc/CustomDefaultSnippets.java[tags=cust ---- include::{examples-dir}/com/example/restassured/CustomDefaultSnippets.java[tags=custom-default-snippets] ---- + +[[configuration-default-preprocessors]] +=== Operation preprocessors + +You can configure default Request / Response preprocessors during setup using the +`RestDocumentationConfigurer` API. For example, to remove the `Foo` headers from all requests +and pretty print all responses: + +[source,java,indent=0,role="primary"] +.MockMvc +---- +include::{examples-dir}/com/example/mockmvc/CustomDefaultOperationPreprocessors.java[tags=custom-default-preprocessors] +---- + +[source,java,indent=0,role="secondary"] +.REST Assured +---- +include::{examples-dir}/com/example/restassured/CustomDefaultOperationPreprocessors.java[tags=custom-default-preprocessors] +---- + diff --git a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc index 28d6d754..d68f7314 100644 --- a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc +++ b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc @@ -27,29 +27,20 @@ include::{examples-dir}/com/example/restassured/PerTestPreprocessing.java[tags=p <2> Apply a response preprocessor that will pretty print its content. Alternatively, you may want to apply the same preprocessors to every test. You can do -so by configuring the preprocessors in your `@Before` method and using the -<>: +so by configuring the preprocessors using the `RestDocumentationConfigurer` API. +For example to remove the `Foo` header from all requests and pretty print all responses: [source,java,indent=0,role="primary"] .MockMvc ---- include::{examples-dir}/com/example/mockmvc/EveryTestPreprocessing.java[tags=setup] ---- -<1> Create a `RestDocumentationResultHandler`, configured to preprocess the request - and response. -<2> Create a `MockMvc` instance, configured to always call the documentation result - handler. [source,java,indent=0,role="secondary"] .REST Assured ---- include::{examples-dir}/com/example/restassured/EveryTestPreprocessing.java[tags=setup] ---- -<1> Create a `RestDocumentationFilter`, configured to preprocess the request - and response. -<2> Create a `RequestSpecification` instance, configured to always call the documentation - filter. Then, in each test, any configuration specific to that test can be performed. For example: @@ -58,17 +49,12 @@ Then, in each test, any configuration specific to that test can be performed. Fo ---- include::{examples-dir}/com/example/mockmvc/EveryTestPreprocessing.java[tags=use] ---- -<1> The request and response will be preprocessed due to the use of `alwaysDo` above. -<2> Document the links specific to the resource that is being tested [source,java,indent=0,role="secondary"] .REST Assured ---- include::{examples-dir}/com/example/restassured/EveryTestPreprocessing.java[tags=use] ---- -<1> The request and response will be preprocessed due to the configuration of the -`RequestSpecification` in the `setUp` method. -<2> Document the links specific to the resource that is being tested Various built in preprocessors, including those illustrated above, are available via the static methods on `Preprocessors`. See <> for further details. diff --git a/docs/src/test/java/com/example/mockmvc/CustomDefaultOperationPreprocessors.java b/docs/src/test/java/com/example/mockmvc/CustomDefaultOperationPreprocessors.java new file mode 100644 index 00000000..786c050e --- /dev/null +++ b/docs/src/test/java/com/example/mockmvc/CustomDefaultOperationPreprocessors.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.mockmvc; + +import org.junit.Before; +import org.junit.Rule; + +import org.springframework.restdocs.JUnitRestDocumentation; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; + +public class CustomDefaultOperationPreprocessors { + + @Rule + public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(); + + private WebApplicationContext context; + + private MockMvc mockMvc; + + @Before + public void setup() { + // tag::custom-default-preprocessors[] + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) + .apply(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withDefaultRequestPreprocessors(removeHeaders("Foo")) + .withDefaultResponsePreprocessors(prettyPrint())) + .build(); + // end::custom-default-preprocessors[] + } +} diff --git a/docs/src/test/java/com/example/mockmvc/EveryTestPreprocessing.java b/docs/src/test/java/com/example/mockmvc/EveryTestPreprocessing.java index 934a353e..279a3310 100644 --- a/docs/src/test/java/com/example/mockmvc/EveryTestPreprocessing.java +++ b/docs/src/test/java/com/example/mockmvc/EveryTestPreprocessing.java @@ -19,7 +19,6 @@ package com.example.mockmvc; import org.junit.Before; import org.junit.Rule; import org.springframework.restdocs.JUnitRestDocumentation; -import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; @@ -29,8 +28,6 @@ import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.li 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.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.test.web.servlet.result.MockMvcResultMatchers.status; @@ -45,16 +42,12 @@ public class EveryTestPreprocessing { // tag::setup[] private MockMvc mockMvc; - private RestDocumentationResultHandler documentationHandler; - @Before public void setup() { - this.documentationHandler = document("{method-name}", // <1> - preprocessRequest(removeHeaders("Foo")), - preprocessResponse(prettyPrint())); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration(this.restDocumentation)) - .alwaysDo(this.documentationHandler) // <2> + .apply(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withDefaultRequestPreprocessors(removeHeaders("Foo")) + .withDefaultResponsePreprocessors(prettyPrint())) .build(); } @@ -64,7 +57,7 @@ public class EveryTestPreprocessing { // tag::use[] this.mockMvc.perform(get("/")) // <1> .andExpect(status().isOk()) - .andDo(this.documentationHandler.document( // <2> + .andDo(document("{method-name}", links(linkWithRel("self").description("Canonical self link")) )); // end::use[] diff --git a/docs/src/test/java/com/example/restassured/CustomDefaultOperationPreprocessors.java b/docs/src/test/java/com/example/restassured/CustomDefaultOperationPreprocessors.java new file mode 100644 index 00000000..c4ebd8ff --- /dev/null +++ b/docs/src/test/java/com/example/restassured/CustomDefaultOperationPreprocessors.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * 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 com.example.restassured; + +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.specification.RequestSpecification; + +import org.junit.Before; +import org.junit.Rule; + +import org.springframework.restdocs.JUnitRestDocumentation; + +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders; +import static org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.documentationConfiguration; + +public class CustomDefaultOperationPreprocessors { + + @Rule + public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(); + + @SuppressWarnings("unused") + private RequestSpecification spec; + + @Before + public void setup() { + // tag::custom-default-preprocessors[] + this.spec = new RequestSpecBuilder() + .addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withDefaultRequestPreprocessors(removeHeaders("Foo")) + .withDefaultResponsePreprocessors(prettyPrint())) + .build(); + // end::custom-default-preprocessors[] + } +} diff --git a/docs/src/test/java/com/example/restassured/EveryTestPreprocessing.java b/docs/src/test/java/com/example/restassured/EveryTestPreprocessing.java index e280fe45..fa14f5c2 100644 --- a/docs/src/test/java/com/example/restassured/EveryTestPreprocessing.java +++ b/docs/src/test/java/com/example/restassured/EveryTestPreprocessing.java @@ -23,13 +23,10 @@ import org.junit.Before; import org.junit.Rule; import org.springframework.restdocs.JUnitRestDocumentation; -import org.springframework.restdocs.restassured3.RestDocumentationFilter; import static org.hamcrest.CoreMatchers.is; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; -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.restassured3.RestAssuredRestDocumentation.document; @@ -43,16 +40,12 @@ public class EveryTestPreprocessing { // tag::setup[] private RequestSpecification spec; - private RestDocumentationFilter documentationFilter; - @Before public void setup() { - this.documentationFilter = document("{method-name}", - preprocessRequest(removeHeaders("Foo")), - preprocessResponse(prettyPrint())); // <1> this.spec = new RequestSpecBuilder() - .addFilter(documentationConfiguration(this.restDocumentation)) - .addFilter(this.documentationFilter)// <2> + .addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withDefaultRequestPreprocessors(removeHeaders("Foo")) + .withDefaultResponsePreprocessors(prettyPrint())) .build(); } @@ -60,8 +53,8 @@ public class EveryTestPreprocessing { public void use() throws Exception { // tag::use[] - RestAssured.given(this.spec) // <1> - .filter(this.documentationFilter.document( // <2> + RestAssured.given(this.spec) + .filter(document("{method-name]", links(linkWithRel("self").description("Canonical self link")))) .when().get("/") .then().assertThat().statusCode(is(200)); diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/OperationPreprocessorsConfigurer.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/OperationPreprocessorsConfigurer.java new file mode 100644 index 00000000..afb21cc5 --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/OperationPreprocessorsConfigurer.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.config; + +import java.util.Map; + +import org.springframework.restdocs.RestDocumentationContext; +import org.springframework.restdocs.generate.RestDocumentationGenerator; +import org.springframework.restdocs.operation.preprocess.OperationPreprocessor; +import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; +import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.restdocs.operation.preprocess.Preprocessors; + +/** + * A configurer that can be used to configure the default operation preprocessors that need to be used. + * + * @param The type of the configurer's parent + * @param The concrete type of the configurer to be returned from chained methods + * @author Filip Hrisafov + * @since 2.0.0 + */ +public abstract class OperationPreprocessorsConfigurer + extends AbstractNestedConfigurer { + + private OperationRequestPreprocessor defaultOperationRequestPreprocessor; + private OperationResponsePreprocessor defaultOperationResponsePreprocessor; + + /** + * Creates a new {@code OperationPreprocessorConfigurer} with the given {@code parent}. + * + * @param parent the parent + */ + protected OperationPreprocessorsConfigurer(PARENT parent) { + super(parent); + } + + @Override + public void apply(Map configuration, RestDocumentationContext context) { + configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR, + this.defaultOperationRequestPreprocessor); + configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR, + this.defaultOperationResponsePreprocessor); + } + + /** + * Configures the default documentation operation request preprocessors. + * + * @param preprocessors the preprocessors + * @return {@code this} + */ + @SuppressWarnings("unchecked") + public TYPE withDefaultRequestPreprocessors(OperationPreprocessor... preprocessors) { + this.defaultOperationRequestPreprocessor = Preprocessors.preprocessRequest(preprocessors); + return (TYPE) this; + } + + /** + * Configures the default documentation operation response preprocessors. + * + * @param preprocessors the preprocessors + * @return {@code this} + */ + @SuppressWarnings("unchecked") + public TYPE withDefaultResponsePreprocessors(OperationPreprocessor... preprocessors) { + this.defaultOperationResponsePreprocessor = Preprocessors.preprocessResponse(preprocessors); + return (TYPE) this; + } +} diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java index 59444e65..75b69352 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/RestDocumentationConfigurer.java @@ -36,12 +36,14 @@ import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine; * Abstract base class for the configuration of Spring REST Docs. * * @param The concrete type of the {@link SnippetConfigurer}. + * @param

The concrete type of the {@link OperationPreprocessorsConfigurer} * @param The concrete type of this configurer, to be returned from methods that * support chaining * @author Andy Wilkinson + * @author Filip Hrisafov * @since 1.1.0 */ -public abstract class RestDocumentationConfigurer { +public abstract class RestDocumentationConfigurer { private final WriterResolverConfigurer writerResolverConfigurer = new WriterResolverConfigurer(); @@ -55,6 +57,14 @@ public abstract class RestDocumentationConfigurer configuration, RestDocumentationContext context) { List configurers = Arrays.asList(snippets(), + operationPreprocessors(), this.templateEngineConfigurer, this.writerResolverConfigurer); for (AbstractConfigurer configurer : configurers) { configurer.apply(configuration, context); diff --git a/spring-restdocs-core/src/main/java/org/springframework/restdocs/generate/RestDocumentationGenerator.java b/spring-restdocs-core/src/main/java/org/springframework/restdocs/generate/RestDocumentationGenerator.java index d21b2ad7..d239ffc4 100644 --- a/spring-restdocs-core/src/main/java/org/springframework/restdocs/generate/RestDocumentationGenerator.java +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/generate/RestDocumentationGenerator.java @@ -41,6 +41,7 @@ import org.springframework.util.Assert; * @param the request type that can be handled * @param the response type that can be handled * @author Andy Wilkinson + * @author Filip Hrisafov * @since 1.1.0 */ public final class RestDocumentationGenerator { @@ -55,6 +56,19 @@ public final class RestDocumentationGenerator { */ public static final String ATTRIBUTE_NAME_DEFAULT_SNIPPETS = "org.springframework.restdocs.defaultSnippets"; + /** + * Name of the operation attribute used to hold the default operation request preprocessor. + */ + public static final String ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR = + "org.springframework.restdocs.defaultOperationRequestPreprocessor"; + + /** + * Name of the operation attribute used to hold the default operation response preprocessor. + */ + public static final String ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR = + "org.springframework.restdocs.defaultOperationResponsePreprocessor"; + + private final String identifier; private final OperationRequestPreprocessor requestPreprocessor; @@ -183,12 +197,9 @@ public final class RestDocumentationGenerator { * @throws RestDocumentationGenerationException if a failure occurs during handling */ public void handle(REQ request, RESP response, Map configuration) { - OperationRequest operationRequest = this.requestPreprocessor - .preprocess(this.requestConverter.convert(request)); - - OperationResponse operationResponse = this.responsePreprocessor - .preprocess(this.responseConverter.convert(response)); Map attributes = new HashMap<>(configuration); + OperationRequest operationRequest = preprocessRequest(request, attributes); + OperationResponse operationResponse = preprocessResponse(response, attributes); Operation operation = new StandardOperation(this.identifier, operationRequest, operationResponse, attributes); try { @@ -228,6 +239,46 @@ public final class RestDocumentationGenerator { return combinedSnippets; } + private OperationRequest preprocessRequest(REQ request, Map configuration) { + List requestPreprocessors = getRequestPreprocessors(configuration); + OperationRequest operationRequest = this.requestConverter.convert(request); + for (OperationRequestPreprocessor preprocessor : requestPreprocessors) { + operationRequest = preprocessor.preprocess(operationRequest); + } + return operationRequest; + } + + private List getRequestPreprocessors(Map configuration) { + List preprocessors = new ArrayList<>(2); + preprocessors.add(this.requestPreprocessor); + OperationRequestPreprocessor defaultRequestPreprocessor = (OperationRequestPreprocessor) configuration.get( + RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR); + if (defaultRequestPreprocessor != null) { + preprocessors.add(defaultRequestPreprocessor); + } + return preprocessors; + } + + private OperationResponse preprocessResponse(RESP response, Map configuration) { + List responsePreprocessors = getResponsePreprocessors(configuration); + OperationResponse operationResponse = this.responseConverter.convert(response); + for (OperationResponsePreprocessor preprocessor : responsePreprocessors) { + operationResponse = preprocessor.preprocess(operationResponse); + } + return operationResponse; + } + + private List getResponsePreprocessors(Map configuration) { + List preprocessors = new ArrayList<>(2); + preprocessors.add(this.responsePreprocessor); + OperationResponsePreprocessor defaultResponsePreprocessor = (OperationResponsePreprocessor) configuration.get( + RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR); + if (defaultResponsePreprocessor != null) { + preprocessors.add(defaultResponsePreprocessor); + } + return preprocessors; + } + private static final class IdentityOperationRequestPreprocessor implements OperationRequestPreprocessor { diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationGeneratorTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationGeneratorTests.java index 44fcb6e8..f06700a2 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationGeneratorTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/RestDocumentationGeneratorTests.java @@ -35,8 +35,10 @@ import org.springframework.restdocs.operation.OperationResponse; import org.springframework.restdocs.operation.OperationResponseFactory; import org.springframework.restdocs.operation.RequestConverter; import org.springframework.restdocs.operation.ResponseConverter; +import org.springframework.restdocs.operation.preprocess.OperationPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.restdocs.operation.preprocess.Preprocessors; import org.springframework.restdocs.snippet.Snippet; import static org.hamcrest.CoreMatchers.equalTo; @@ -51,6 +53,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; * Tests for {@link RestDocumentationGenerator}. * * @author Andy Wilkinson + * @author Filip Hrisafov */ public class RestDocumentationGeneratorTests { @@ -75,6 +78,9 @@ public class RestDocumentationGeneratorTests { private final Snippet snippet = mock(Snippet.class); + private final OperationPreprocessor requestPreprocessor = mock(OperationPreprocessor.class); + private final OperationPreprocessor responsePreprocessor = mock(OperationPreprocessor.class); + @Test public void basicHandling() throws IOException { given(this.requestConverter.convert(this.request)) @@ -107,6 +113,84 @@ public class RestDocumentationGeneratorTests { verifySnippetInvocation(defaultSnippet2, configuration); } + @Test + public void defaultOperationRequestPreprocessorsAreCalled() throws IOException { + given(this.requestConverter.convert(this.request)) + .willReturn(this.operationRequest); + given(this.responseConverter.convert(this.response)) + .willReturn(this.operationResponse); + HashMap configuration = new HashMap<>(); + OperationPreprocessor defaultPreprocessor1 = mock(OperationPreprocessor.class); + OperationPreprocessor defaultPreprocessor2 = mock(OperationPreprocessor.class); + configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR, + Preprocessors.preprocessRequest(defaultPreprocessor1, defaultPreprocessor2)); + OperationRequest first = createRequest(); + OperationRequest second = createRequest(); + OperationRequest third = createRequest(); + given(this.requestPreprocessor.preprocess(this.operationRequest)).willReturn(first); + given(defaultPreprocessor1.preprocess(first)).willReturn(second); + given(defaultPreprocessor2.preprocess(second)).willReturn(third); + new RestDocumentationGenerator<>("id", this.requestConverter, + this.responseConverter, Preprocessors.preprocessRequest(this.requestPreprocessor), this.snippet) + .handle(this.request, this.response, configuration); + + verifySnippetInvocation(this.snippet, third, this.operationResponse, configuration, 1); + } + + @Test + public void defaultOperationResponsePreprocessorsAreCalled() throws IOException { + given(this.requestConverter.convert(this.request)) + .willReturn(this.operationRequest); + given(this.responseConverter.convert(this.response)) + .willReturn(this.operationResponse); + HashMap configuration = new HashMap<>(); + OperationPreprocessor defaultPreprocessor1 = mock(OperationPreprocessor.class); + OperationPreprocessor defaultPreprocessor2 = mock(OperationPreprocessor.class); + configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR, + Preprocessors.preprocessResponse(defaultPreprocessor1, defaultPreprocessor2)); + OperationResponse first = createResponse(); + OperationResponse second = createResponse(); + OperationResponse third = new OperationResponseFactory().createFrom(this.operationResponse, new HttpHeaders()); + given(this.responsePreprocessor.preprocess(this.operationResponse)).willReturn(first); + given(defaultPreprocessor1.preprocess(first)).willReturn(second); + given(defaultPreprocessor2.preprocess(second)).willReturn(third); + new RestDocumentationGenerator<>("id", this.requestConverter, + this.responseConverter, Preprocessors.preprocessResponse(this.responsePreprocessor), this.snippet) + .handle(this.request, this.response, configuration); + + verifySnippetInvocation(this.snippet, this.operationRequest, third, configuration, 1); + } + + @Test + public void defaultOperationPreprocessorsAreCalled() throws IOException { + given(this.requestConverter.convert(this.request)) + .willReturn(this.operationRequest); + given(this.responseConverter.convert(this.response)) + .willReturn(this.operationResponse); + HashMap configuration = new HashMap<>(); + OperationPreprocessor requestPreprocessor1 = mock(OperationPreprocessor.class); + configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR, + Preprocessors.preprocessRequest(requestPreprocessor1)); + OperationRequest firstRequest = createRequest(); + OperationRequest secondRequest = createRequest(); + given(this.requestPreprocessor.preprocess(this.operationRequest)).willReturn(firstRequest); + given(requestPreprocessor1.preprocess(firstRequest)).willReturn(secondRequest); + + OperationPreprocessor responsePreprocessor1 = mock(OperationPreprocessor.class); + configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR, + Preprocessors.preprocessResponse(responsePreprocessor1)); + OperationResponse firstResponse = createResponse(); + OperationResponse secondResponse = createResponse(); + given(this.responsePreprocessor.preprocess(this.operationResponse)).willReturn(firstResponse); + given(responsePreprocessor1.preprocess(firstResponse)).willReturn(secondResponse); + new RestDocumentationGenerator<>("id", this.requestConverter, + this.responseConverter, Preprocessors.preprocessRequest(this.requestPreprocessor), + Preprocessors.preprocessResponse(this.responsePreprocessor), this.snippet) + .handle(this.request, this.response, configuration); + + verifySnippetInvocation(this.snippet, secondRequest, secondResponse, configuration, 1); + } + @Test public void newGeneratorOnlyCallsItsSnippets() throws IOException { OperationRequestPreprocessor requestPreprocessor = mock( @@ -141,12 +225,27 @@ public class RestDocumentationGeneratorTests { private void verifySnippetInvocation(Snippet snippet, Map attributes, int times) throws IOException { + verifySnippetInvocation(snippet, this.operationRequest, this.operationResponse, attributes, times); + } + + private void verifySnippetInvocation(Snippet snippet, OperationRequest operationRequest, + OperationResponse operationResponse, + Map attributes, int times) throws IOException { ArgumentCaptor operation = ArgumentCaptor.forClass(Operation.class); verify(snippet, Mockito.times(times)).document(operation.capture()); - assertThat(this.operationRequest, is(equalTo(operation.getValue().getRequest()))); - assertThat(this.operationResponse, - is(equalTo(operation.getValue().getResponse()))); + assertThat(operationRequest, is(equalTo(operation.getValue().getRequest()))); + assertThat(operationResponse, is(equalTo(operation.getValue().getResponse()))); assertThat(attributes, is(equalTo(operation.getValue().getAttributes()))); } + private static OperationRequest createRequest() { + return new OperationRequestFactory() + .create(URI.create("http://localhost:8080"), null, null, new HttpHeaders(), null, null); + } + + private static OperationResponse createResponse() { + return new OperationResponseFactory() + .create(null, null, null); + } + } diff --git a/spring-restdocs-core/src/test/java/org/springframework/restdocs/config/RestDocumentationConfigurerTests.java b/spring-restdocs-core/src/test/java/org/springframework/restdocs/config/RestDocumentationConfigurerTests.java index 4cc0b635..a56c5646 100644 --- a/spring-restdocs-core/src/test/java/org/springframework/restdocs/config/RestDocumentationConfigurerTests.java +++ b/spring-restdocs-core/src/test/java/org/springframework/restdocs/config/RestDocumentationConfigurerTests.java @@ -31,6 +31,9 @@ import org.springframework.restdocs.cli.HttpieRequestSnippet; import org.springframework.restdocs.generate.RestDocumentationGenerator; import org.springframework.restdocs.http.HttpRequestSnippet; import org.springframework.restdocs.http.HttpResponseSnippet; +import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; +import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.restdocs.operation.preprocess.Preprocessors; import org.springframework.restdocs.payload.RequestBodySnippet; import org.springframework.restdocs.payload.ResponseBodySnippet; import org.springframework.restdocs.snippet.Snippet; @@ -45,6 +48,7 @@ import org.springframework.test.util.ReflectionTestUtils; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; 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; @@ -54,6 +58,7 @@ import static org.mockito.Mockito.mock; * Tests for {@link RestDocumentationConfigurer}. * * @author Andy Wilkinson + * @author Filip Hrisafov */ public class RestDocumentationConfigurerTests { @@ -88,6 +93,14 @@ public class RestDocumentationConfigurerTests { assertThat(snippetConfiguration.getEncoding(), is(equalTo("UTF-8"))); assertThat(snippetConfiguration.getTemplateFormat(), is(equalTo(TemplateFormats.asciidoctor()))); + + OperationRequestPreprocessor defaultOperationRequestPreprocessor = (OperationRequestPreprocessor) + configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR); + assertThat(defaultOperationRequestPreprocessor, is(nullValue())); + + OperationResponsePreprocessor defaultOperationResponsePreprocessor = (OperationResponsePreprocessor) + configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR); + assertThat(defaultOperationResponsePreprocessor, is(nullValue())); } @Test @@ -200,6 +213,32 @@ public class RestDocumentationConfigurerTests { assertThat(templateContext.size(), equalTo(0)); } + @Test + public void customDefaultOperationRequestPreprocessor() { + Map configuration = new HashMap<>(); + this.configurer.operationPreprocessors() + .withDefaultRequestPreprocessors(Preprocessors.prettyPrint(), Preprocessors.removeHeaders("Foo")) + .apply(configuration, createContext()); + assertThat(configuration, + hasEntry( + equalTo(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR), + instanceOf(OperationRequestPreprocessor.class))); + //TODO how can we actually test that the preprocessors that we set are actually there? + } + + @Test + public void customDefaultOperationResponsePreprocessor() { + Map configuration = new HashMap<>(); + this.configurer.operationPreprocessors() + .withDefaultResponsePreprocessors(Preprocessors.prettyPrint(), Preprocessors.removeHeaders("Foo")) + .apply(configuration, createContext()); + assertThat(configuration, + hasEntry( + equalTo(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR), + instanceOf(OperationResponsePreprocessor.class))); + //TODO same as for the customDefaultOperationRequestPreprocessor + } + private RestDocumentationContext createContext() { ManualRestDocumentation manualRestDocumentation = new ManualRestDocumentation( "build"); @@ -209,16 +248,24 @@ public class RestDocumentationConfigurerTests { } private static final class TestRestDocumentationConfigurer extends - RestDocumentationConfigurer { + RestDocumentationConfigurer { private final TestSnippetConfigurer snippetConfigurer = new TestSnippetConfigurer( this); + private final TestOperationPreprocessorsConfigurer operationPreprocessorsConfigurer = + new TestOperationPreprocessorsConfigurer(this); + @Override public TestSnippetConfigurer snippets() { return this.snippetConfigurer; } + @Override + public TestOperationPreprocessorsConfigurer operationPreprocessors() { + return this.operationPreprocessorsConfigurer; + } } private static final class TestSnippetConfigurer extends @@ -230,4 +277,12 @@ public class RestDocumentationConfigurerTests { } + private static final class TestOperationPreprocessorsConfigurer extends + OperationPreprocessorsConfigurer { + + protected TestOperationPreprocessorsConfigurer(TestRestDocumentationConfigurer parent) { + super(parent); + } + } + } diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationPreprocessorsConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationPreprocessorsConfigurer.java new file mode 100644 index 00000000..d41df9ed --- /dev/null +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationPreprocessorsConfigurer.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.mockmvc; + +import org.springframework.restdocs.config.OperationPreprocessorsConfigurer; +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; + +/** + * A configurer that can be used to configure the operation preprocessors. + * + * @author Filip Hrisafov + * @since 2.0.0 + */ +public final class MockMvcOperationPreprocessorsConfigurer extends + OperationPreprocessorsConfigurer + implements MockMvcConfigurer { + + MockMvcOperationPreprocessorsConfigurer(MockMvcRestDocumentationConfigurer parent) { + super(parent); + } + + @Override + public void afterConfigurerAdded(ConfigurableMockMvcBuilder builder) { + and().afterConfigurerAdded(builder); + } + + @Override + public RequestPostProcessor beforeMockMvcCreated( + ConfigurableMockMvcBuilder builder, WebApplicationContext context) { + return and().beforeMockMvcCreated(builder, context); + } +} diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java index 5c91186d..5606ba20 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationConfigurer.java @@ -33,10 +33,12 @@ import org.springframework.web.context.WebApplicationContext; * A MockMvc-specific {@link RestDocumentationConfigurer}. * * @author Andy Wilkinson + * @author Filip Hrisafov * @since 1.1.0 */ public final class MockMvcRestDocumentationConfigurer extends - RestDocumentationConfigurer + RestDocumentationConfigurer implements MockMvcConfigurer { private final MockMvcSnippetConfigurer snippetConfigurer = new MockMvcSnippetConfigurer( @@ -44,6 +46,9 @@ public final class MockMvcRestDocumentationConfigurer extends private final UriConfigurer uriConfigurer = new UriConfigurer(this); + private final MockMvcOperationPreprocessorsConfigurer operationPreprocessorsConfigurer = + new MockMvcOperationPreprocessorsConfigurer(this); + private final RestDocumentationContextProvider contextManager; MockMvcRestDocumentationConfigurer(RestDocumentationContextProvider contextManager) { @@ -76,6 +81,11 @@ public final class MockMvcRestDocumentationConfigurer extends return this.snippetConfigurer; } + @Override + public MockMvcOperationPreprocessorsConfigurer operationPreprocessors() { + return this.operationPreprocessorsConfigurer; + } + private final class ConfigurerApplyingRequestPostProcessor implements RequestPostProcessor { diff --git a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java index 44904365..5f255440 100644 --- a/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java @@ -82,6 +82,9 @@ public class RestDocumentationResultHandler implements ResultHandler { .getAttribute(ATTRIBUTE_NAME_CONFIGURATION)); configuration.remove( RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS); + // TODO Do we need to remove the preprocessors here as well? + // I think that there is no test that evaluates this here. And the Javadoc does not reflect the + // behaviour getDelegate().handle(result.getRequest(), result.getResponse(), configuration); } diff --git a/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java b/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java index 3b6ed629..0a5979b1 100644 --- a/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java +++ b/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java @@ -103,6 +103,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * @author Andy Wilkinson * @author Dewet Diener * @author Tomasz Kopczynski + * @author Filip Hrisafov */ @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @@ -493,6 +494,44 @@ public class MockMvcRestDocumentationIntegrationTests { .withContents(preprocessedRequest.content(prettyPrinted)))); } + @Test + public void defaultPreprocessedRequest() throws Exception { + Pattern pattern = Pattern.compile("(\"alpha\")"); + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) + .apply(documentationConfiguration(this.restDocumentation) + .operationPreprocessors() + .withDefaultRequestPreprocessors(prettyPrint(), + removeHeaders("a", HttpHeaders.HOST, + HttpHeaders.CONTENT_LENGTH), + replacePattern(pattern, "\"<>\""))) + .build(); + + + MvcResult result = mockMvc + .perform(get("/").header("a", "alpha").header("b", "bravo") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON).content("{\"a\":\"alpha\"}")) + .andDo(document("default-preprocessed-request")) + .andReturn(); + + HttpRequestMatcher preprocessedRequest = httpRequest(asciidoctor(), + RequestMethod.GET, "/"); + List removedHeaders = Arrays.asList("a", HttpHeaders.HOST, + HttpHeaders.CONTENT_LENGTH); + for (String headerName : iterable(result.getRequest().getHeaderNames())) { + if (!removedHeaders.contains(headerName)) { + preprocessedRequest.header(headerName, + result.getRequest().getHeader(headerName)); + } + } + String prettyPrinted = String.format("{%n \"a\" : \"<>\"%n}"); + assertThat( + new File( + "build/generated-snippets/default-preprocessed-request/http-request.adoc"), + is(snippet(asciidoctor()) + .withContents(preprocessedRequest.content(prettyPrinted)))); + } + @Test public void preprocessedResponse() throws Exception { MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) @@ -529,6 +568,34 @@ public class MockMvcRestDocumentationIntegrationTests { .content(prettyPrinted)))); } + @Test + public void defaultPreprocessedResponse() throws Exception { + Pattern pattern = Pattern.compile("(\"alpha\")"); + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) + .apply(documentationConfiguration(this.restDocumentation) + .operationPreprocessors() + .withDefaultResponsePreprocessors(prettyPrint(), maskLinks(), removeHeaders("a"), + replacePattern(pattern, "\"<>\""))) + .build(); + + + mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(document("default-preprocessed-response")); + + String prettyPrinted = String.format("{%n \"a\" : \"<>\",%n \"links\" : " + + "[ {%n \"rel\" : \"rel\",%n \"href\" : \"...\"%n } ]%n}"); + assertThat( + new File( + "build/generated-snippets/default-preprocessed-response/http-response.adoc"), + is(snippet(asciidoctor()) + .withContents(httpResponse(asciidoctor(), HttpStatus.OK) + .header("Content-Type", "application/json;charset=UTF-8") + .header(HttpHeaders.CONTENT_LENGTH, + prettyPrinted.getBytes().length) + .content(prettyPrinted)))); + } + @Test public void customSnippetTemplate() throws Exception { MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredOperationPreprocessorsConfigurer.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredOperationPreprocessorsConfigurer.java new file mode 100644 index 00000000..db6cffcd --- /dev/null +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredOperationPreprocessorsConfigurer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.restdocs.restassured3; + +import io.restassured.filter.Filter; +import io.restassured.filter.FilterContext; +import io.restassured.response.Response; +import io.restassured.specification.FilterableRequestSpecification; +import io.restassured.specification.FilterableResponseSpecification; + +import org.springframework.restdocs.config.OperationPreprocessorsConfigurer; + +/** + * A configurer that can be used to configure the operation preprocessors when + * using REST Assured 3. + * + * @author Filip Hrisafov + * @since 2.0.0 + */ +public final class RestAssuredOperationPreprocessorsConfigurer extends + OperationPreprocessorsConfigurer + implements Filter { + + RestAssuredOperationPreprocessorsConfigurer(RestAssuredRestDocumentationConfigurer parent) { + super(parent); + } + + @Override + public Response filter(FilterableRequestSpecification requestSpec, + FilterableResponseSpecification responseSpec, FilterContext context) { + return and().filter(requestSpec, responseSpec, context); + } +} diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurer.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurer.java index b5a5b506..b8c71fbf 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurer.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurer.java @@ -33,15 +33,20 @@ import org.springframework.restdocs.config.RestDocumentationConfigurer; * A REST Assured 3-specific {@link RestDocumentationConfigurer}. * * @author Andy Wilkinson + * @author Filip Hrisafov * @since 1.2.0 */ public final class RestAssuredRestDocumentationConfigurer extends - RestDocumentationConfigurer + RestDocumentationConfigurer implements Filter { private final RestAssuredSnippetConfigurer snippetConfigurer = new RestAssuredSnippetConfigurer( this); + private final RestAssuredOperationPreprocessorsConfigurer operationPreprocessorsConfigurer = + new RestAssuredOperationPreprocessorsConfigurer(this); + private final RestDocumentationContextProvider contextProvider; RestAssuredRestDocumentationConfigurer( @@ -54,6 +59,11 @@ public final class RestAssuredRestDocumentationConfigurer extends return this.snippetConfigurer; } + @Override + public RestAssuredOperationPreprocessorsConfigurer operationPreprocessors() { + return this.operationPreprocessorsConfigurer; + } + @Override public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec, FilterContext filterContext) { diff --git a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestDocumentationFilter.java b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestDocumentationFilter.java index d1ea753d..2dc26e62 100644 --- a/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestDocumentationFilter.java +++ b/spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestDocumentationFilter.java @@ -97,6 +97,10 @@ public class RestDocumentationFilter implements Filter { context); configuration.remove( RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS); + configuration.remove( + RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR); + configuration.remove( + RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR); return configuration; } diff --git a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurerTests.java b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurerTests.java index caafafa5..0356cea3 100644 --- a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurerTests.java +++ b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationConfigurerTests.java @@ -28,6 +28,9 @@ import org.mockito.ArgumentCaptor; import org.springframework.restdocs.JUnitRestDocumentation; import org.springframework.restdocs.generate.RestDocumentationGenerator; +import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; +import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; +import org.springframework.restdocs.operation.preprocess.Preprocessors; import org.springframework.restdocs.snippet.WriterResolver; import org.springframework.restdocs.templates.TemplateEngine; @@ -43,6 +46,7 @@ import static org.mockito.Mockito.verify; * Tests for {@link RestAssuredRestDocumentationConfigurer}. * * @author Andy Wilkinson + * @author Filip Hrisafov */ public class RestAssuredRestDocumentationConfigurerTests { @@ -68,7 +72,11 @@ public class RestAssuredRestDocumentationConfigurerTests { @Test public void configurationIsAddedToTheContext() { - this.configurer.filter(this.requestSpec, this.responseSpec, this.filterContext); + this.configurer + .operationPreprocessors() + .withDefaultRequestPreprocessors(Preprocessors.prettyPrint()) + .withDefaultResponsePreprocessors(Preprocessors.removeHeaders("Foo")) + .filter(this.requestSpec, this.responseSpec, this.filterContext); @SuppressWarnings("rawtypes") ArgumentCaptor configurationCaptor = ArgumentCaptor.forClass(Map.class); verify(this.filterContext).setValue( @@ -84,6 +92,14 @@ public class RestAssuredRestDocumentationConfigurerTests { hasEntry( equalTo(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS), instanceOf(List.class))); + assertThat(configuration, + hasEntry( + equalTo(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR), + instanceOf(OperationRequestPreprocessor.class))); + assertThat(configuration, + hasEntry( + equalTo(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR), + instanceOf(OperationResponsePreprocessor.class))); } } diff --git a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java index b71a1504..e9370351 100644 --- a/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java +++ b/spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java @@ -71,6 +71,7 @@ import static org.springframework.restdocs.test.SnippetMatchers.snippet; * * @author Andy Wilkinson * @author Tomasz Kopczynski + * @author Filip Hrisafov */ public class RestAssuredRestDocumentationIntegrationTests { @@ -327,6 +328,31 @@ public class RestAssuredRestDocumentationIntegrationTests { .header("Host", "localhost").content(prettyPrinted)))); } + @Test + public void defaultPreprocessedRequest() throws Exception { + Pattern pattern = Pattern.compile("(\"alpha\")"); + given().port(tomcat.getPort()) + .filter(documentationConfiguration(this.restDocumentation) + .operationPreprocessors().withDefaultRequestPreprocessors(prettyPrint(), + replacePattern(pattern, "\"<>\""), + modifyUris().removePort(), + removeHeaders("a", HttpHeaders.CONTENT_LENGTH))) + .header("a", "alpha").header("b", "bravo").contentType("application/json") + .accept("application/json").body("{\"a\":\"alpha\"}") + .filter(document("default-preprocessed-request")) + .get("/").then().statusCode(200); + String prettyPrinted = String.format("{%n \"a\" : \"<>\"%n}"); + assertThat( + new File( + "build/generated-snippets/default-preprocessed-request/http-request.adoc"), + is(snippet(asciidoctor()) + .withContents(httpRequest(asciidoctor(), RequestMethod.GET, "/") + .header("b", "bravo") + .header("Accept", MediaType.APPLICATION_JSON_VALUE) + .header("Content-Type", "application/json; charset=UTF-8") + .header("Host", "localhost").content(prettyPrinted)))); + } + @Test public void preprocessedResponse() throws Exception { Pattern pattern = Pattern.compile("(\"alpha\")"); @@ -353,6 +379,31 @@ public class RestAssuredRestDocumentationIntegrationTests { .content(prettyPrinted)))); } + @Test + public void defaultPreprocessedResponse() throws Exception { + Pattern pattern = Pattern.compile("(\"alpha\")"); + given().port(tomcat.getPort()) + .filter(documentationConfiguration(this.restDocumentation) + .operationPreprocessors().withDefaultResponsePreprocessors(prettyPrint(), maskLinks(), + removeHeaders("a", "Transfer-Encoding", "Date", "Server"), + replacePattern(pattern, "\"<>\""), modifyUris() + .scheme("https").host("api.example.com").removePort())) + .filter(document("default-preprocessed-response")) + .get("/").then().statusCode(200); + String prettyPrinted = String.format("{%n \"a\" : \"<>\",%n \"links\" : " + + "[ {%n \"rel\" : \"rel\",%n \"href\" : \"...\"%n } ]%n}"); + assertThat( + new File( + "build/generated-snippets/default-preprocessed-response/http-response.adoc"), + is(snippet(asciidoctor()) + .withContents(httpResponse(asciidoctor(), HttpStatus.OK) + .header("Foo", "https://api.example.com/foo/bar") + .header("Content-Type", "application/json;charset=UTF-8") + .header(HttpHeaders.CONTENT_LENGTH, + prettyPrinted.getBytes().length) + .content(prettyPrinted)))); + } + @Test public void customSnippetTemplate() throws Exception { ClassLoader classLoader = new URLClassLoader(new URL[] {