Skip to content

Diagnostics are poor when misconfiguration leads to operation-specific configuration being null #583

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 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.
Expand Down Expand Up @@ -49,10 +49,8 @@ public class RestDocumentationResultHandler implements ResultHandler {

@Override
public void handle(MvcResult result) throws Exception {
@SuppressWarnings("unchecked")
Map<String, Object> configuration = (Map<String, Object>) result.getRequest()
.getAttribute(ATTRIBUTE_NAME_CONFIGURATION);
this.delegate.handle(result.getRequest(), result.getResponse(), configuration);
this.delegate.handle(result.getRequest(), result.getResponse(),
getRequiredConfiguration(result));
}

/**
Expand All @@ -75,10 +73,8 @@ public RestDocumentationResultHandler document(Snippet... snippets) {

@Override
public void handle(MvcResult result) throws Exception {
@SuppressWarnings("unchecked")
Map<String, Object> configuration = new HashMap<>(
(Map<String, Object>) result.getRequest()
.getAttribute(ATTRIBUTE_NAME_CONFIGURATION));
getRequiredConfiguration(result));
configuration.remove(
RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS);
getDelegate().handle(result.getRequest(), result.getResponse(),
Expand All @@ -96,4 +92,15 @@ protected final RestDocumentationGenerator<MockHttpServletRequest, MockHttpServl
return this.delegate;
}

private static Map<String, Object> getRequiredConfiguration(MvcResult result) {
@SuppressWarnings("unchecked")
Map<String, Object> configuration = (Map<String, Object>) 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;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 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.
Expand Down Expand Up @@ -69,6 +69,7 @@
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;
Expand Down Expand Up @@ -594,6 +595,36 @@ public void customContextPath() throws Exception {
+ " -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 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.
Expand Down Expand Up @@ -70,7 +70,7 @@ public final Response filter(FilterableRequestSpecification requestSpec,
protected Map<String, Object> getConfiguration(
FilterableRequestSpecification requestSpec, FilterContext context) {
Map<String, Object> configuration = new HashMap<>(
context.<Map<String, Object>>getValue(CONTEXT_KEY_CONFIGURATION));
getRequiredConfiguration(context));
configuration.put(RestDocumentationContext.class.getName(),
context.<RestDocumentationContext>getValue(
RestDocumentationContext.class.getName()));
Expand Down Expand Up @@ -105,4 +105,13 @@ protected Map<String, Object> getConfiguration(
};
}

private static Map<String, Object> getRequiredConfiguration(FilterContext context) {
Map<String, Object> 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;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 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.
Expand Down Expand Up @@ -47,6 +47,7 @@

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;
Expand Down Expand Up @@ -432,6 +433,31 @@ public void customSnippetTemplate() throws Exception {
.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();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 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.
Expand Down Expand Up @@ -30,6 +30,7 @@
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;

/**
Expand Down Expand Up @@ -77,7 +78,7 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
Snippet... snippets) {
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, snippets).handle(result, result,
retrieveConfiguration(result));
getRequiredConfiguration(result));
}

/**
Expand All @@ -95,7 +96,7 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
OperationRequestPreprocessor requestPreprocessor, Snippet... snippets) {
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, requestPreprocessor, snippets).handle(result, result,
retrieveConfiguration(result));
getRequiredConfiguration(result));
}

/**
Expand All @@ -113,7 +114,7 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, responsePreprocessor, snippets).handle(result, result,
retrieveConfiguration(result));
getRequiredConfiguration(result));
}

/**
Expand All @@ -134,13 +135,17 @@ public static <T extends ExchangeResult> Consumer<T> document(String identifier,
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
return (result) -> new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, requestPreprocessor, responsePreprocessor, snippets)
.handle(result, result, retrieveConfiguration(result));
.handle(result, result, getRequiredConfiguration(result));
}

private static Map<String, Object> retrieveConfiguration(ExchangeResult result) {
Map<String, Object> configuration = new HashMap<>(
WebTestClientRestDocumentationConfigurer
.retrieveConfiguration(result.getRequestHeaders()));
private static Map<String, Object> getRequiredConfiguration(ExchangeResult result) {
Map<String, Object> 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<String, Object> configuration = new HashMap<>(config);
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE,
result.getUriTemplate());
return configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2018 the original author or authors.
* Copyright 2014-2019 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.
Expand All @@ -23,6 +23,7 @@
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;
Expand Down Expand Up @@ -58,6 +59,7 @@
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;
Expand Down Expand Up @@ -199,6 +201,23 @@ public void httpieSnippetWithCookies() throws Exception {
+ " '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<File> actual = new HashSet<>(Arrays.asList(directory.listFiles()));
Set<File> expected = Stream.of(snippets)
Expand Down