Skip to content

Commit b5f2454

Browse files
nosanwilkinsona
authored andcommitted
Improve diagnostics for null configuration
See gh-583
1 parent c4d664c commit b5f2454

File tree

6 files changed

+100
-16
lines changed

6 files changed

+100
-16
lines changed

spring-restdocs-mockmvc/src/main/java/org/springframework/restdocs/mockmvc/RestDocumentationResultHandler.java

+14-7
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ public class RestDocumentationResultHandler implements ResultHandler {
4949

5050
@Override
5151
public void handle(MvcResult result) throws Exception {
52-
@SuppressWarnings("unchecked")
53-
Map<String, Object> configuration = (Map<String, Object>) result.getRequest()
54-
.getAttribute(ATTRIBUTE_NAME_CONFIGURATION);
55-
this.delegate.handle(result.getRequest(), result.getResponse(), configuration);
52+
this.delegate.handle(result.getRequest(), result.getResponse(), getRequiredConfiguration(result));
5653
}
5754

5855
/**
@@ -75,9 +72,7 @@ public RestDocumentationResultHandler document(Snippet... snippets) {
7572

7673
@Override
7774
public void handle(MvcResult result) throws Exception {
78-
@SuppressWarnings("unchecked")
79-
Map<String, Object> configuration = new HashMap<>(
80-
(Map<String, Object>) result.getRequest().getAttribute(ATTRIBUTE_NAME_CONFIGURATION));
75+
Map<String, Object> configuration = new HashMap<>(getRequiredConfiguration(result));
8176
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS);
8277
getDelegate().handle(result.getRequest(), result.getResponse(), configuration);
8378
}
@@ -93,4 +88,16 @@ protected final RestDocumentationGenerator<MockHttpServletRequest, MockHttpServl
9388
return this.delegate;
9489
}
9590

91+
private static Map<String, Object> getRequiredConfiguration(MvcResult result) {
92+
@SuppressWarnings("unchecked")
93+
Map<String, Object> configuration = (Map<String, Object>) result.getRequest()
94+
.getAttribute(ATTRIBUTE_NAME_CONFIGURATION);
95+
Assert.state(configuration != null,
96+
() -> String.format(
97+
"There is no REST Docs configuration. Looks like "
98+
+ "'%s' was not invoked. Please check your configuration.",
99+
MockMvcRestDocumentationConfigurer.class.getName()));
100+
return configuration;
101+
}
102+
96103
}

spring-restdocs-mockmvc/src/test/java/org/springframework/restdocs/mockmvc/MockMvcRestDocumentationIntegrationTests.java

+24
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
7070

7171
import static org.assertj.core.api.Assertions.assertThat;
72+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
7273
import static org.assertj.core.api.Assertions.fail;
7374
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
7475
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
@@ -491,6 +492,29 @@ public void customContextPath() throws Exception {
491492
+ " -H 'Accept: application/json'"))));
492493
}
493494

495+
@Test
496+
public void exceptionShouldBeThrownWhenCallDocumentMockMvcNotConfigured() {
497+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
498+
assertThatThrownBy(() -> mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andDo(document("basic")))
499+
.isInstanceOf(IllegalStateException.class).hasMessageContaining(missingConfigurationMessage());
500+
501+
}
502+
503+
@Test
504+
public void exceptionShouldBeThrownWhenCallDocumentSnippetsMockMvcNotConfigured() {
505+
RestDocumentationResultHandler documentation = document("{method-name}-{step}");
506+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
507+
assertThatThrownBy(() -> mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
508+
.andDo(documentation.document(responseHeaders(headerWithName("a").description("one")))))
509+
.isInstanceOf(IllegalStateException.class).hasMessageContaining(missingConfigurationMessage());
510+
}
511+
512+
private String missingConfigurationMessage() {
513+
return "There is no REST Docs configuration. Looks like "
514+
+ "'org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer' "
515+
+ "was not invoked. Please check your configuration.";
516+
}
517+
494518
@Test
495519
public void multiPart() throws Exception {
496520
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)

spring-restdocs-restassured/src/main/java/org/springframework/restdocs/restassured3/RestDocumentationFilter.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ public final Response filter(FilterableRequestSpecification requestSpec,
6767
* @return the configuration
6868
*/
6969
protected Map<String, Object> getConfiguration(FilterableRequestSpecification requestSpec, FilterContext context) {
70-
Map<String, Object> configuration = new HashMap<>(
71-
context.<Map<String, Object>>getValue(CONTEXT_KEY_CONFIGURATION));
70+
Map<String, Object> configuration = new HashMap<>(getRequiredConfiguration(context));
7271
configuration.put(RestDocumentationContext.class.getName(),
7372
context.<RestDocumentationContext>getValue(RestDocumentationContext.class.getName()));
7473
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, requestSpec.getUserDefinedPath());
@@ -97,4 +96,14 @@ protected Map<String, Object> getConfiguration(FilterableRequestSpecification re
9796
};
9897
}
9998

99+
private static Map<String, Object> getRequiredConfiguration(FilterContext context) {
100+
Map<String, Object> configuration = context.getValue(CONTEXT_KEY_CONFIGURATION);
101+
Assert.state(configuration != null,
102+
() -> String.format(
103+
"There is no REST Docs configuration. Looks like "
104+
+ "'%s' was not invoked. Please check your configuration.",
105+
RestDocumentationFilter.class.getName()));
106+
return configuration;
107+
}
108+
100109
}

spring-restdocs-restassured/src/test/java/org/springframework/restdocs/restassured3/RestAssuredRestDocumentationIntegrationTests.java

+22
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
import static io.restassured.RestAssured.given;
4949
import static org.assertj.core.api.Assertions.assertThat;
50+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5051
import static org.assertj.core.api.Assertions.fail;
5152
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
5253
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
@@ -339,6 +340,27 @@ public void customSnippetTemplate() throws Exception {
339340
.hasContent("Custom curl request");
340341
}
341342

343+
@Test
344+
public void exceptionShouldBeThrownWhenCallDocumentRequestSpecificationNotConfigured() {
345+
assertThatThrownBy(() -> given().port(tomcat.getPort()).filter(document("default")).get("/"))
346+
.isInstanceOf(IllegalStateException.class).hasMessageContaining(messingConfigurationMessage());
347+
}
348+
349+
@Test
350+
public void exceptionShouldBeThrownWhenCallDocumentSnippetsRequestSpecificationNotConfigured() {
351+
RestDocumentationFilter documentation = document("{method-name}-{step}");
352+
assertThatThrownBy(() -> given().port(tomcat.getPort())
353+
.filter(documentation.document(responseHeaders(headerWithName("a").description("one")))).get("/"))
354+
.isInstanceOf(IllegalStateException.class).hasMessageContaining(messingConfigurationMessage());
355+
}
356+
357+
private String messingConfigurationMessage() {
358+
return "There is no REST Docs configuration. Looks like 'org.springframework."
359+
+ "restdocs.restassured3.RestDocumentationFilter' was not invoked."
360+
+ " Please check your configuration.";
361+
362+
}
363+
342364
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
343365
for (String snippet : snippets) {
344366
assertThat(new File(directory, snippet)).isFile();

spring-restdocs-webtestclient/src/main/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentation.java

+13-7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.springframework.test.web.reactive.server.WebTestClient.BodyContentSpec;
3131
import org.springframework.test.web.reactive.server.WebTestClient.BodySpec;
3232
import org.springframework.test.web.reactive.server.WebTestClient.Builder;
33+
import org.springframework.util.Assert;
3334
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
3435

3536
/**
@@ -75,7 +76,7 @@ public static WebTestClientRestDocumentationConfigurer documentationConfiguratio
7576
*/
7677
public static <T extends ExchangeResult> Consumer<T> document(String identifier, Snippet... snippets) {
7778
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets)
78-
.handle(result, result, retrieveConfiguration(result));
79+
.handle(result, result, getRequiredConfiguration(result));
7980
}
8081

8182
/**
@@ -92,7 +93,7 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
9293
public static <T extends ExchangeResult> Consumer<T> document(String identifier,
9394
OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) {
9495
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER,
95-
requestPreprocessor, snippets).handle(result, result, retrieveConfiguration(result));
96+
requestPreprocessor, snippets).handle(result, result, getRequiredConfiguration(result));
9697
}
9798

9899
/**
@@ -109,7 +110,7 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
109110
public static <T extends ExchangeResult> Consumer<T> document(String identifier,
110111
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
111112
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER,
112-
responsePreprocessor, snippets).handle(result, result, retrieveConfiguration(result));
113+
responsePreprocessor, snippets).handle(result, result, getRequiredConfiguration(result));
113114
}
114115

115116
/**
@@ -130,12 +131,17 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
130131
Snippet... snippets) {
131132
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER,
132133
requestPreprocessor, responsePreprocessor, snippets).handle(result, result,
133-
retrieveConfiguration(result));
134+
getRequiredConfiguration(result));
134135
}
135136

136-
private static Map<String, Object> retrieveConfiguration(ExchangeResult result) {
137-
Map<String, Object> configuration = new HashMap<>(
138-
WebTestClientRestDocumentationConfigurer.retrieveConfiguration(result.getRequestHeaders()));
137+
private static Map<String, Object> getRequiredConfiguration(ExchangeResult result) {
138+
Map<String, Object> config = WebTestClientRestDocumentationConfigurer
139+
.retrieveConfiguration(result.getRequestHeaders());
140+
Assert.state(config != null,
141+
() -> String.format("There is no REST Docs configuration. Looks like '%s' "
142+
+ "was not invoked or configuration has already been removed. Please check your configuration.",
143+
WebTestClientRestDocumentationConfigurer.class.getName()));
144+
Map<String, Object> configuration = new HashMap<>(config);
139145
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, result.getUriTemplate());
140146
return configuration;
141147
}

spring-restdocs-webtestclient/src/test/java/org/springframework/restdocs/webtestclient/WebTestClientRestDocumentationIntegrationTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.nio.charset.StandardCharsets;
2424
import java.util.Arrays;
2525
import java.util.HashSet;
26+
import java.util.List;
2627
import java.util.Set;
2728
import java.util.function.Consumer;
2829
import java.util.stream.Collectors;
@@ -58,6 +59,7 @@
5859
import org.springframework.web.reactive.function.server.ServerResponse;
5960

6061
import static org.assertj.core.api.Assertions.assertThat;
62+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
6163
import static org.assertj.core.api.Assertions.fail;
6264
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
6365
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
@@ -173,6 +175,20 @@ public void httpieSnippetWithCookies() throws Exception {
173175
+ " 'Accept:application/json' \\%n" + " 'Cookie:cookieName=cookieVal'"))));
174176
}
175177

178+
@Test
179+
public void illegalStateExceptionShouldBeThrownWhenCallDocumentWebClientNotConfigured() {
180+
assertThatThrownBy(() -> this.webTestClient
181+
.mutateWith((builder, httpHandlerBuilder, connector) -> builder.filters(List::clear).build()).get()
182+
.uri("/").exchange().expectBody().consumeWith(document("default-snippets")))
183+
.isInstanceOf(IllegalStateException.class).hasMessageContaining(missingConfiguration());
184+
}
185+
186+
private String missingConfiguration() {
187+
return "There is no REST Docs configuration. Looks like "
188+
+ "'org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer' "
189+
+ "was not invoked or configuration has already been removed. Please check your configuration.";
190+
}
191+
176192
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
177193
Set<File> actual = new HashSet<>(Arrays.asList(directory.listFiles()));
178194
Set<File> expected = Stream.of(snippets).map((snippet) -> new File(directory, snippet))

0 commit comments

Comments
 (0)