From b5f2454c005f08497cc55be345afb17ac016a851 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Mon, 18 Feb 2019 16:08:53 +0200 Subject: [PATCH] Improve diagnostics for null configuration See gh-583 --- .../RestDocumentationResultHandler.java | 21 ++++++++++------ ...kMvcRestDocumentationIntegrationTests.java | 24 +++++++++++++++++++ .../restassured3/RestDocumentationFilter.java | 13 ++++++++-- ...uredRestDocumentationIntegrationTests.java | 22 +++++++++++++++++ .../WebTestClientRestDocumentation.java | 20 ++++++++++------ ...ientRestDocumentationIntegrationTests.java | 16 +++++++++++++ 6 files changed, 100 insertions(+), 16 deletions(-) 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 a5c12334..944940b3 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 @@ -49,10 +49,7 @@ public class RestDocumentationResultHandler implements ResultHandler { @Override public void handle(MvcResult result) throws Exception { - @SuppressWarnings("unchecked") - Map configuration = (Map) result.getRequest() - .getAttribute(ATTRIBUTE_NAME_CONFIGURATION); - this.delegate.handle(result.getRequest(), result.getResponse(), configuration); + this.delegate.handle(result.getRequest(), result.getResponse(), getRequiredConfiguration(result)); } /** @@ -75,9 +72,7 @@ public class RestDocumentationResultHandler implements ResultHandler { @Override public void handle(MvcResult result) throws Exception { - @SuppressWarnings("unchecked") - Map configuration = new HashMap<>( - (Map) result.getRequest().getAttribute(ATTRIBUTE_NAME_CONFIGURATION)); + Map configuration = new HashMap<>(getRequiredConfiguration(result)); configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS); getDelegate().handle(result.getRequest(), result.getResponse(), configuration); } @@ -93,4 +88,16 @@ public class RestDocumentationResultHandler implements ResultHandler { return this.delegate; } + private static Map getRequiredConfiguration(MvcResult result) { + @SuppressWarnings("unchecked") + Map configuration = (Map) result.getRequest() + .getAttribute(ATTRIBUTE_NAME_CONFIGURATION); + Assert.state(configuration != null, + () -> String.format( + "There is no REST Docs configuration. Looks like " + + "'%s' was not invoked. Please check your configuration.", + MockMvcRestDocumentationConfigurer.class.getName())); + return 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 ed8872e8..38ebdfa4 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 @@ -69,6 +69,7 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.fail; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; @@ -491,6 +492,29 @@ public class MockMvcRestDocumentationIntegrationTests { + " -H 'Accept: application/json'")))); } + @Test + public void exceptionShouldBeThrownWhenCallDocumentMockMvcNotConfigured() { + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + assertThatThrownBy(() -> mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andDo(document("basic"))) + .isInstanceOf(IllegalStateException.class).hasMessageContaining(missingConfigurationMessage()); + + } + + @Test + public void exceptionShouldBeThrownWhenCallDocumentSnippetsMockMvcNotConfigured() { + RestDocumentationResultHandler documentation = document("{method-name}-{step}"); + MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + assertThatThrownBy(() -> mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)) + .andDo(documentation.document(responseHeaders(headerWithName("a").description("one"))))) + .isInstanceOf(IllegalStateException.class).hasMessageContaining(missingConfigurationMessage()); + } + + private String missingConfigurationMessage() { + return "There is no REST Docs configuration. Looks like " + + "'org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer' " + + "was not invoked. Please check your configuration."; + } + @Test public void multiPart() throws Exception { MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) 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 b3e730e2..eb629917 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 @@ -67,8 +67,7 @@ public class RestDocumentationFilter implements Filter { * @return the configuration */ protected Map getConfiguration(FilterableRequestSpecification requestSpec, FilterContext context) { - Map configuration = new HashMap<>( - context.>getValue(CONTEXT_KEY_CONFIGURATION)); + Map configuration = new HashMap<>(getRequiredConfiguration(context)); configuration.put(RestDocumentationContext.class.getName(), context.getValue(RestDocumentationContext.class.getName())); configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, requestSpec.getUserDefinedPath()); @@ -97,4 +96,14 @@ public class RestDocumentationFilter implements Filter { }; } + private static Map getRequiredConfiguration(FilterContext context) { + Map configuration = context.getValue(CONTEXT_KEY_CONFIGURATION); + Assert.state(configuration != null, + () -> String.format( + "There is no REST Docs configuration. Looks like " + + "'%s' was not invoked. Please check your configuration.", + RestDocumentationFilter.class.getName())); + return configuration; + } + } 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 a5206105..c3b91f6b 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 @@ -47,6 +47,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import static io.restassured.RestAssured.given; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.fail; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; @@ -339,6 +340,27 @@ public class RestAssuredRestDocumentationIntegrationTests { .hasContent("Custom curl request"); } + @Test + public void exceptionShouldBeThrownWhenCallDocumentRequestSpecificationNotConfigured() { + assertThatThrownBy(() -> given().port(tomcat.getPort()).filter(document("default")).get("/")) + .isInstanceOf(IllegalStateException.class).hasMessageContaining(messingConfigurationMessage()); + } + + @Test + public void exceptionShouldBeThrownWhenCallDocumentSnippetsRequestSpecificationNotConfigured() { + RestDocumentationFilter documentation = document("{method-name}-{step}"); + assertThatThrownBy(() -> given().port(tomcat.getPort()) + .filter(documentation.document(responseHeaders(headerWithName("a").description("one")))).get("/")) + .isInstanceOf(IllegalStateException.class).hasMessageContaining(messingConfigurationMessage()); + } + + private String messingConfigurationMessage() { + return "There is no REST Docs configuration. Looks like 'org.springframework." + + "restdocs.restassured3.RestDocumentationFilter' was not invoked." + + " Please check your configuration."; + + } + private void assertExpectedSnippetFilesExist(File directory, String... snippets) { for (String snippet : snippets) { assertThat(new File(directory, snippet)).isFile(); diff --git a/spring-restdocs-webtestclient/src/main/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentation.java b/spring-restdocs-webtestclient/src/main/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentation.java index 1dd60c17..8ed49c24 100644 --- a/spring-restdocs-webtestclient/src/main/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentation.java +++ b/spring-restdocs-webtestclient/src/main/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentation.java @@ -30,6 +30,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec; import org.springframework.test.web.reactive.server.WebTestClient.BodySpec; import org.springframework.test.web.reactive.server.WebTestClient.Builder; +import org.springframework.util.Assert; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; /** @@ -75,7 +76,7 @@ public abstract class WebTestClientRestDocumentation { */ public static Consumer document(String identifier, Snippet... snippets) { return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets) - .handle(result, result, retrieveConfiguration(result)); + .handle(result, result, getRequiredConfiguration(result)); } /** @@ -92,7 +93,7 @@ public abstract class WebTestClientRestDocumentation { public static Consumer document(String identifier, OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) { return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, - requestPreprocessor, snippets).handle(result, result, retrieveConfiguration(result)); + requestPreprocessor, snippets).handle(result, result, getRequiredConfiguration(result)); } /** @@ -109,7 +110,7 @@ public abstract class WebTestClientRestDocumentation { public static Consumer document(String identifier, OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) { return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, - responsePreprocessor, snippets).handle(result, result, retrieveConfiguration(result)); + responsePreprocessor, snippets).handle(result, result, getRequiredConfiguration(result)); } /** @@ -130,12 +131,17 @@ public abstract class WebTestClientRestDocumentation { Snippet... snippets) { return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, requestPreprocessor, responsePreprocessor, snippets).handle(result, result, - retrieveConfiguration(result)); + getRequiredConfiguration(result)); } - private static Map retrieveConfiguration(ExchangeResult result) { - Map configuration = new HashMap<>( - WebTestClientRestDocumentationConfigurer.retrieveConfiguration(result.getRequestHeaders())); + private static Map getRequiredConfiguration(ExchangeResult result) { + Map config = WebTestClientRestDocumentationConfigurer + .retrieveConfiguration(result.getRequestHeaders()); + Assert.state(config != null, + () -> String.format("There is no REST Docs configuration. Looks like '%s' " + + "was not invoked or configuration has already been removed. Please check your configuration.", + WebTestClientRestDocumentationConfigurer.class.getName())); + Map configuration = new HashMap<>(config); configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, result.getUriTemplate()); return configuration; } diff --git a/spring-restdocs-webtestclient/src/test/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentationIntegrationTests.java b/spring-restdocs-webtestclient/src/test/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentationIntegrationTests.java index ae3766c8..e09633fe 100644 --- a/spring-restdocs-webtestclient/src/test/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentationIntegrationTests.java +++ b/spring-restdocs-webtestclient/src/test/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentationIntegrationTests.java @@ -23,6 +23,7 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -58,6 +59,7 @@ import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.fail; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.partWithName; @@ -173,6 +175,20 @@ public class WebTestClientRestDocumentationIntegrationTests { + " 'Accept:application/json' \\%n" + " 'Cookie:cookieName=cookieVal'")))); } + @Test + public void illegalStateExceptionShouldBeThrownWhenCallDocumentWebClientNotConfigured() { + assertThatThrownBy(() -> this.webTestClient + .mutateWith((builder, httpHandlerBuilder, connector) -> builder.filters(List::clear).build()).get() + .uri("/").exchange().expectBody().consumeWith(document("default-snippets"))) + .isInstanceOf(IllegalStateException.class).hasMessageContaining(missingConfiguration()); + } + + private String missingConfiguration() { + return "There is no REST Docs configuration. Looks like " + + "'org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer' " + + "was not invoked or configuration has already been removed. Please check your configuration."; + } + private void assertExpectedSnippetFilesExist(File directory, String... snippets) { Set actual = new HashSet<>(Arrays.asList(directory.listFiles())); Set expected = Stream.of(snippets).map((snippet) -> new File(directory, snippet))