diff --git a/docs/src/docs/asciidoc/configuration.adoc b/docs/src/docs/asciidoc/configuration.adoc index af45dad3..1e6fca5e 100644 --- a/docs/src/docs/asciidoc/configuration.adoc +++ b/docs/src/docs/asciidoc/configuration.adoc @@ -114,3 +114,27 @@ 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]] +=== Default operation preprocessors + +You can configure default request and 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-operation-preprocessors] +---- +<1> Apply a request preprocessor that will remove the header named `Foo`. +<2> Apply a response preprocessor that will pretty print its content. + +[source,java,indent=0,role="secondary"] +.REST Assured +---- +include::{examples-dir}/com/example/restassured/CustomDefaultOperationPreprocessors.java[tags=custom-default-operation-preprocessors] +---- +<1> Apply a request preprocessor that will remove the header named `Foo`. +<2> Apply a response preprocessor that will pretty print its content. + diff --git a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc index 28d6d754..4cc2625b 100644 --- a/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc +++ b/docs/src/docs/asciidoc/customizing-requests-and-responses.adoc @@ -27,29 +27,25 @@ 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 in your +`@Before` method. 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. +<1> Apply a request preprocessor that will remove the header named `Foo`. +<2> Apply a response preprocessor that will pretty print its content. [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. +<1> Apply a request preprocessor that will remove the header named `Foo`. +<2> Apply a response preprocessor that will pretty print its content. Then, in each test, any configuration specific to that test can be performed. For example: @@ -58,17 +54,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..c6cd2fa0 --- /dev/null +++ b/docs/src/test/java/com/example/mockmvc/CustomDefaultOperationPreprocessors.java @@ -0,0 +1,53 @@ +/* + * 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; + + @SuppressWarnings("unused") + private MockMvc mockMvc; + + @Before + public void setup() { + // tag::custom-default-operation-preprocessors[] + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) + .apply(documentationConfiguration(this.restDocumentation) + .operationPreprocessors() + .withRequestDefaults(removeHeaders("Foo")) // <1> + .withResponseDefaults(prettyPrint())) // <2> + .build(); + // end::custom-default-operation-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..3b46bb21 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,26 +42,21 @@ 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> - .build(); + .apply(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withRequestDefaults(removeHeaders("Foo")) // <1> + .withResponseDefaults(prettyPrint())) // <2> + .build(); } - // end::setup[] public void use() throws Exception { // tag::use[] - this.mockMvc.perform(get("/")) // <1> + this.mockMvc.perform(get("/")) .andExpect(status().isOk()) - .andDo(this.documentationHandler.document( // <2> + .andDo(document("index", 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..262f9680 --- /dev/null +++ b/docs/src/test/java/com/example/restassured/CustomDefaultOperationPreprocessors.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 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-operation-preprocessors[] + this.spec = new RequestSpecBuilder() + .addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withRequestDefaults(removeHeaders("Foo")) // <1> + .withResponseDefaults(prettyPrint())) // <2> + .build(); + // end::custom-default-operation-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..05bc3a61 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,26 +40,21 @@ 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> - .build(); + .addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors() + .withRequestDefaults(removeHeaders("Foo")) // <1> + .withResponseDefaults(prettyPrint())) // <2> + .build(); } - // end::setup[] public void use() throws Exception { // tag::use[] - RestAssured.given(this.spec) // <1> - .filter(this.documentationFilter.document( // <2> - links(linkWithRel("self").description("Canonical self link")))) + RestAssured.given(this.spec) + .filter(document("index", + links(linkWithRel("self").description("Canonical self link")))) .when().get("/") .then().assertThat().statusCode(is(200)); // end::use[] 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..a0126dee --- /dev/null +++ b/spring-restdocs-core/src/main/java/org/springframework/restdocs/config/OperationPreprocessorsConfigurer.java @@ -0,0 +1,91 @@ +/* + * 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. + * + * @param The type of the configurer's parent + * @param The concrete type of the configurer to be returned from chained methods + * @author Filip Hrisafov + * @author Andy Wilkinson + * @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 operation request preprocessors. + * + * @param preprocessors the preprocessors + * @return {@code this} + */ + @SuppressWarnings("unchecked") + public TYPE withRequestDefaults(OperationPreprocessor... preprocessors) { + this.defaultOperationRequestPreprocessor = Preprocessors + .preprocessRequest(preprocessors); + return (TYPE) this; + } + + /** + * Configures the default operation response preprocessors. + * + * @param preprocessors the preprocessors + * @return {@code this} + */ + @SuppressWarnings("unchecked") + public TYPE withResponseDefaults(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..0f9c67d2 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 @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * 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. @@ -35,13 +35,15 @@ 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 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(), - this.templateEngineConfigurer, this.writerResolverConfigurer); + 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..b69bae2f 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,18 @@ 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 +196,11 @@ 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( + this.requestConverter.convert(request), attributes); + OperationResponse operationResponse = preprocessResponse( + this.responseConverter.convert(response), attributes); Operation operation = new StandardOperation(this.identifier, operationRequest, operationResponse, attributes); try { @@ -228,6 +240,51 @@ public final class RestDocumentationGenerator { return combinedSnippets; } + private OperationRequest preprocessRequest(OperationRequest request, + Map configuration) { + List requestPreprocessors = getRequestPreprocessors( + configuration); + for (OperationRequestPreprocessor preprocessor : requestPreprocessors) { + request = preprocessor.preprocess(request); + } + return request; + } + + private List getRequestPreprocessors( + Map configuration) { + return getPreprocessors(this.requestPreprocessor, + RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR, + configuration); + } + + private OperationResponse preprocessResponse(OperationResponse response, + Map configuration) { + for (OperationResponsePreprocessor preprocessor : getResponsePreprocessors( + configuration)) { + response = preprocessor.preprocess(response); + } + return response; + } + + private List getResponsePreprocessors( + Map configuration) { + return getPreprocessors(this.responsePreprocessor, + RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR, + configuration); + } + + @SuppressWarnings("unchecked") + private List getPreprocessors(T preprocessor, String preprocessorAttribute, + Map configuration) { + List preprocessors = new ArrayList<>(2); + preprocessors.add(preprocessor); + T defaultResponsePreprocessor = (T) configuration.get(preprocessorAttribute); + 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..103a7960 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,12 @@ 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 +116,63 @@ 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 newGeneratorOnlyCallsItsSnippets() throws IOException { OperationRequestPreprocessor requestPreprocessor = mock( @@ -141,12 +207,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..f8f6880c 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 @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 the original author or authors. + * 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. @@ -16,6 +16,8 @@ package org.springframework.restdocs.config; +import java.net.URI; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -23,6 +25,9 @@ import java.util.Map; import org.hamcrest.Matchers; import org.junit.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; import org.springframework.restdocs.ManualRestDocumentation; import org.springframework.restdocs.RestDocumentationContext; import org.springframework.restdocs.cli.CliDocumentation; @@ -31,6 +36,13 @@ 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.OperationRequest; +import org.springframework.restdocs.operation.OperationRequestFactory; +import org.springframework.restdocs.operation.OperationResponse; +import org.springframework.restdocs.operation.OperationResponseFactory; +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 +57,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 +67,7 @@ import static org.mockito.Mockito.mock; * Tests for {@link RestDocumentationConfigurer}. * * @author Andy Wilkinson + * @author Filip Hrisafov */ public class RestDocumentationConfigurerTests { @@ -88,6 +102,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 +222,41 @@ public class RestDocumentationConfigurerTests { assertThat(templateContext.size(), equalTo(0)); } + @Test + public void customDefaultOperationRequestPreprocessor() { + Map configuration = new HashMap<>(); + this.configurer.operationPreprocessors() + .withRequestDefaults(Preprocessors.prettyPrint(), + Preprocessors.removeHeaders("Foo")) + .apply(configuration, createContext()); + OperationRequestPreprocessor preprocessor = (OperationRequestPreprocessor) configuration + .get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR); + HttpHeaders headers = new HttpHeaders(); + headers.add("Foo", "value"); + OperationRequest request = new OperationRequestFactory().create( + URI.create("http://localhost:8080"), HttpMethod.GET, null, headers, null, + Collections.emptyList()); + assertThat(preprocessor.preprocess(request).getHeaders().get("Foo"), + is(nullValue())); + } + + @Test + public void customDefaultOperationResponsePreprocessor() { + Map configuration = new HashMap<>(); + this.configurer.operationPreprocessors() + .withResponseDefaults(Preprocessors.prettyPrint(), + Preprocessors.removeHeaders("Foo")) + .apply(configuration, createContext()); + OperationResponsePreprocessor preprocessor = (OperationResponsePreprocessor) configuration + .get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR); + HttpHeaders headers = new HttpHeaders(); + headers.add("Foo", "value"); + OperationResponse response = new OperationResponseFactory().create(HttpStatus.OK, + headers, null); + assertThat(preprocessor.preprocess(response).getHeaders().get("Foo"), + is(nullValue())); + } + private RestDocumentationContext createContext() { ManualRestDocumentation manualRestDocumentation = new ManualRestDocumentation( "build"); @@ -209,16 +266,23 @@ 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 +294,13 @@ 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..0e5662f7 --- /dev/null +++ b/spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/MockMvcOperationPreprocessorsConfigurer.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 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..52f0231e 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,11 @@ 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 +45,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 +80,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/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java b/spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java index 3b6ed629..f76911ff 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,42 @@ 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() + .withRequestDefaults(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 +566,33 @@ 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().withResponseDefaults( + 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..af8850a5 --- /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..807b7057 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,19 @@ 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 +58,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..250da411 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,10 @@ public class RestAssuredRestDocumentationConfigurerTests { @Test public void configurationIsAddedToTheContext() { - this.configurer.filter(this.requestSpec, this.responseSpec, this.filterContext); + this.configurer.operationPreprocessors() + .withRequestDefaults(Preprocessors.prettyPrint()) + .withResponseDefaults(Preprocessors.removeHeaders("Foo")) + .filter(this.requestSpec, this.responseSpec, this.filterContext); @SuppressWarnings("rawtypes") ArgumentCaptor configurationCaptor = ArgumentCaptor.forClass(Map.class); verify(this.filterContext).setValue( @@ -84,6 +91,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..0b108bad 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,33 @@ 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().withRequestDefaults( + 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 +381,33 @@ 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() + .withResponseDefaults(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[] {