Include cookies in request snippets

Closes gh-336
See gh-302, gh-303, gh-304
This commit is contained in:
Tomasz Kopczynski
2016-12-18 15:43:58 +01:00
committed by Andy Wilkinson
parent 0337160e80
commit 25bc6c37da
18 changed files with 271 additions and 11 deletions

View File

@@ -25,6 +25,8 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.restdocs.operation.OperationRequest;
@@ -125,6 +127,11 @@ final class CliOperationRequest implements OperationRequest {
return this.delegate.getUri();
}
@Override
public Collection<Cookie> getCookies() {
return this.delegate.getCookies();
}
private interface HeaderFilter {
boolean allow(String name, List<String> value);

View File

@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpMethod;
import org.springframework.restdocs.operation.Operation;
import org.springframework.restdocs.operation.OperationRequest;
@@ -92,12 +94,28 @@ public class CurlRequestSnippet extends TemplatedSnippet {
writeUserOptionIfNecessary(request, printer);
writeHttpMethodIfNecessary(request, printer);
writeHeaders(request, printer);
writeCookies(request, printer);
writePartsIfNecessary(request, printer);
writeContent(request, printer);
return command.toString();
}
private void writeCookies(CliOperationRequest request, PrintWriter printer) {
if (request.getCookies() != null && request.getCookies().size() > 0) {
printer.print(" --cookie ");
StringBuilder cookiesBuilder = new StringBuilder();
for (Cookie cookie : request.getCookies()) {
cookiesBuilder.append(String.format("%s=%s;", cookie.getName(), cookie.getValue()));
}
String cookiesHeader = cookiesBuilder.substring(0, cookiesBuilder.length() - 1); // remove trailing semicolon
printer.print(String.format("'%s'", cookiesHeader)); // add single quotes
}
}
private void writeIncludeHeadersInOutputOption(PrintWriter writer) {
writer.print("-i");
}

View File

@@ -23,6 +23,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
@@ -160,6 +162,10 @@ public class HttpieRequestSnippet extends TemplatedSnippet {
writer.print(String.format(" '%s:%s'", entry.getKey(), header));
}
}
for (Cookie cookie : request.getCookies()) {
writer.print(String.format(" 'Cookie:%s=%s'", cookie.getName(), cookie.getValue()));
}
}
private void writeParametersIfNecessary(CliOperationRequest request,

View File

@@ -24,6 +24,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
@@ -35,6 +37,7 @@ import org.springframework.restdocs.snippet.Snippet;
import org.springframework.restdocs.snippet.TemplatedSnippet;
import org.springframework.util.StringUtils;
/**
* A {@link Snippet} that documents an HTTP request.
*
@@ -112,6 +115,11 @@ public class HttpRequestSnippet extends TemplatedSnippet {
}
}
for (Cookie cookie : request.getCookies()) {
headers.add(header(HttpHeaders.COOKIE, String.format("%s=%s", cookie.getName(), cookie.getValue())));
}
if (requiresFormEncodingContentTypeHeader(request)) {
headers.add(header(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_FORM_URLENCODED_VALUE));

View File

@@ -19,6 +19,8 @@ package org.springframework.restdocs.operation;
import java.net.URI;
import java.util.Collection;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -86,4 +88,11 @@ public interface OperationRequest {
*/
URI getUri();
/**
* Returns cookies sent with the request.
*
* @return the cookies
*/
Collection<Cookie> getCookies();
}

View File

@@ -18,6 +18,9 @@ package org.springframework.restdocs.operation;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -29,6 +32,28 @@ import org.springframework.http.HttpMethod;
*/
public class OperationRequestFactory {
/**
* Creates a new {@link OperationRequest}. The given {@code headers} will be augmented
* to ensure that they always include a {@code Content-Length} header if the request
* has any content and a {@code Host} header.
*
* @param uri the request's uri
* @param method the request method
* @param content the content of the request
* @param headers the request's headers
* @param parameters the request's parameters
* @param parts the request's parts
* @param cookies the request's cookies
* @return the {@code OperationRequest}
*/
public OperationRequest create(URI uri, HttpMethod method, byte[] content,
HttpHeaders headers, Parameters parameters,
Collection<OperationRequestPart> parts,
Collection<Cookie> cookies) {
return new StandardOperationRequest(uri, method, content,
augmentHeaders(headers, uri, content), parameters, parts, cookies);
}
/**
* Creates a new {@link OperationRequest}. The given {@code headers} will be augmented
* to ensure that they always include a {@code Content-Length} header if the request
@@ -45,8 +70,7 @@ public class OperationRequestFactory {
public OperationRequest create(URI uri, HttpMethod method, byte[] content,
HttpHeaders headers, Parameters parameters,
Collection<OperationRequestPart> parts) {
return new StandardOperationRequest(uri, method, content,
augmentHeaders(headers, uri, content), parameters, parts);
return create(uri, method, content, headers, parameters, parts, Collections.<Cookie>emptyList());
}
/**
@@ -62,7 +86,7 @@ public class OperationRequestFactory {
public OperationRequest createFrom(OperationRequest original, byte[] newContent) {
return new StandardOperationRequest(original.getUri(), original.getMethod(),
newContent, getUpdatedHeaders(original.getHeaders(), newContent),
original.getParameters(), original.getParts());
original.getParameters(), original.getParts(), original.getCookies());
}
/**
@@ -78,7 +102,7 @@ public class OperationRequestFactory {
HttpHeaders newHeaders) {
return new StandardOperationRequest(original.getUri(), original.getMethod(),
original.getContent(), newHeaders, original.getParameters(),
original.getParts());
original.getParts(), original.getCookies());
}
/**
@@ -94,7 +118,7 @@ public class OperationRequestFactory {
Parameters newParameters) {
return new StandardOperationRequest(original.getUri(), original.getMethod(),
original.getContent(), original.getHeaders(), newParameters,
original.getParts());
original.getParts(), original.getCookies());
}
private HttpHeaders augmentHeaders(HttpHeaders originalHeaders, URI uri,

View File

@@ -20,6 +20,8 @@ import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import javax.servlet.http.Cookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -39,6 +41,8 @@ class StandardOperationRequest extends AbstractOperationMessage
private URI uri;
private Collection<Cookie> cookies;
/**
* Creates a new request with the given {@code uri} and {@code method}. The request
* will have the given {@code headers}, {@code parameters}, and {@code parts}.
@@ -52,12 +56,14 @@ class StandardOperationRequest extends AbstractOperationMessage
*/
StandardOperationRequest(URI uri, HttpMethod method, byte[] content,
HttpHeaders headers, Parameters parameters,
Collection<OperationRequestPart> parts) {
Collection<OperationRequestPart> parts,
Collection<Cookie> cookies) {
super(content, headers);
this.uri = uri;
this.method = method;
this.parameters = parameters;
this.parts = parts;
this.cookies = cookies;
}
@Override
@@ -80,4 +86,9 @@ class StandardOperationRequest extends AbstractOperationMessage
return this.uri;
}
@Override
public Collection<Cookie> getCookies() {
return this.cookies;
}
}

View File

@@ -251,6 +251,17 @@ public class CurlRequestSnippetTests extends AbstractSnippetTests {
.header("a", "alpha").build());
}
@Test
public void requestWithCookies() throws IOException {
this.snippets.expectCurlRequest()
.withContents(codeBlock("bash").content("$ curl 'http://localhost/foo' -i" +
" --cookie 'name1=value1;name2=value2'"));
new CurlRequestSnippet()
.document(this.operationBuilder.request("http://localhost/foo")
.cookie("name1", "value1")
.cookie("name2", "value2").build());
}
@Test
public void multipartPostWithNoSubmittedFileName() throws IOException {
String expectedContent = "$ curl 'http://localhost/upload' -i -X POST -H "

View File

@@ -252,6 +252,17 @@ public class HttpieRequestSnippetTests extends AbstractSnippetTests {
.header("a", "alpha").build());
}
@Test
public void requestWithCookies() throws IOException {
this.snippets.expectHttpieRequest().withContents(
codeBlock("bash").content("$ http GET 'http://localhost/foo'" +
" 'Cookie:name1=value1' 'Cookie:name2=value2'"));
new HttpieRequestSnippet()
.document(this.operationBuilder.request("http://localhost/foo")
.cookie("name1", "value1")
.cookie("name2", "value2").build());
}
@Test
public void multipartPostWithNoSubmittedFileName() throws IOException {
String expectedContent = String

View File

@@ -54,7 +54,7 @@ public class RequestHeadersSnippetTests extends AbstractSnippetTests {
.row("`X-Test`", "one").row("`Accept`", "two")
.row("`Accept-Encoding`", "three")
.row("`Accept-Language`", "four").row("`Cache-Control`", "five")
.row("`Connection`", "six"));
.row("`Connection`", "six").row("`Cookie`", "seven"));
new RequestHeadersSnippet(
Arrays.asList(headerWithName("X-Test").description("one"),
headerWithName("Accept").description("two"),
@@ -63,7 +63,8 @@ public class RequestHeadersSnippetTests extends AbstractSnippetTests {
headerWithName("Cache-Control").description("five"),
headerWithName(
"Connection")
.description("six")))
.description("six"),
headerWithName("Cookie").description("seven")))
.document(
this.operationBuilder
.request(
@@ -78,6 +79,8 @@ public class RequestHeadersSnippetTests extends AbstractSnippetTests {
"max-age=0")
.header("Connection",
"keep-alive")
.header("Cookie",
"cookie1=cookieVal1; cookie2=cookieVal2")
.build());
}

View File

@@ -80,6 +80,21 @@ public class HttpRequestSnippetTests extends AbstractSnippetTests {
.request("http://localhost:8080/foo").header("Alpha", "a").build());
}
@Test
public void getRequestWithCookies() throws IOException {
this.snippets.expectHttpRequest()
.withContents(httpRequest(RequestMethod.GET, "/foo")
.header(HttpHeaders.HOST, "localhost")
.header(HttpHeaders.COOKIE, "name1=value1")
.header(HttpHeaders.COOKIE, "name2=value2"));
new HttpRequestSnippet()
.document(this.operationBuilder.request("http://localhost/foo")
.cookie("name1", "value1")
.cookie("name2", "value2")
.build());
}
@Test
public void getRequestWithQueryString() throws IOException {
this.snippets.expectHttpRequest()

View File

@@ -19,11 +19,14 @@ package org.springframework.restdocs.test;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import org.junit.runners.model.Statement;
import org.springframework.http.HttpHeaders;
@@ -153,6 +156,8 @@ public class OperationBuilder extends OperationTestRule {
private List<OperationRequestPartBuilder> partBuilders = new ArrayList<>();
private Collection<Cookie> cookies = new ArrayList<>();
private OperationRequestBuilder(String uri) {
this.requestUri = URI.create(uri);
}
@@ -163,7 +168,7 @@ public class OperationBuilder extends OperationTestRule {
parts.add(builder.buildPart());
}
return new OperationRequestFactory().create(this.requestUri, this.method,
this.content, this.headers, this.parameters, parts);
this.content, this.headers, this.parameters, parts, this.cookies);
}
public Operation build() {
@@ -209,6 +214,11 @@ public class OperationBuilder extends OperationTestRule {
return partBuilder;
}
public OperationRequestBuilder cookie(String name, String value) {
this.cookies.add(new Cookie(name, value));
return this;
}
/**
* Basic builder API for creating an {@link OperationRequestPart}.
*/

View File

@@ -21,10 +21,14 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.Part;
import org.springframework.http.HttpHeaders;
@@ -67,6 +71,7 @@ class MockMvcRequestConverter implements RequestConverter<MockHttpServletRequest
HttpHeaders headers = extractHeaders(mockRequest);
Parameters parameters = extractParameters(mockRequest);
List<OperationRequestPart> parts = extractParts(mockRequest);
Collection<Cookie> cookies = extractCookies(mockRequest);
String queryString = mockRequest.getQueryString();
if (!StringUtils.hasText(queryString)
&& "GET".equals(mockRequest.getMethod())) {
@@ -78,13 +83,21 @@ class MockMvcRequestConverter implements RequestConverter<MockHttpServletRequest
? "?" + queryString : "")),
HttpMethod.valueOf(mockRequest.getMethod()),
FileCopyUtils.copyToByteArray(mockRequest.getInputStream()), headers,
parameters, parts);
parameters, parts, cookies);
}
catch (Exception ex) {
throw new ConversionException(ex);
}
}
private Collection<Cookie> extractCookies(MockHttpServletRequest mockRequest) {
if (mockRequest.getCookies() != null) {
return Arrays.asList(mockRequest.getCookies());
}
return Collections.emptyList();
}
private List<OperationRequestPart> extractParts(MockHttpServletRequest servletRequest)
throws IOException, ServletException {
List<OperationRequestPart> parts = new ArrayList<>();

View File

@@ -19,7 +19,9 @@ package org.springframework.restdocs.mockmvc;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.util.Arrays;
import java.util.Iterator;
import javax.servlet.http.Cookie;
import javax.servlet.http.Part;
import org.junit.Test;
@@ -88,6 +90,27 @@ public class MockMvcRequestConverterTests {
assertThat(request.getHeaders(), hasEntry("b", Arrays.asList("bravo")));
}
@Test
public void requestWithCookies() throws Exception {
OperationRequest request = createOperationRequest(MockMvcRequestBuilders
.get("/foo")
.cookie(new Cookie("cookieName1", "cookieVal1"),
new Cookie("cookieName2", "cookieVal2")));
assertThat(request.getUri(), is(URI.create("http://localhost/foo")));
assertThat(request.getMethod(), is(HttpMethod.GET));
assertThat(request.getCookies().size(), is(equalTo(2)));
Iterator<Cookie> cookieIterator = request.getCookies().iterator();
Cookie cookie1 = cookieIterator.next();
assertThat(cookie1.getName(), is(equalTo("cookieName1")));
assertThat(cookie1.getValue(), is(equalTo("cookieVal1")));
Cookie cookie2 = cookieIterator.next();
assertThat(cookie2.getName(), is(equalTo("cookieName2")));
assertThat(cookie2.getValue(), is(equalTo("cookieVal2")));
}
@Test
public void httpsRequest() throws Exception {
MockHttpServletRequest mockRequest = MockMvcRequestBuilders.get("/foo")

View File

@@ -24,6 +24,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import javax.servlet.http.Cookie;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -159,6 +161,23 @@ public class MockMvcRestDocumentationIntegrationTests {
+ "-H 'Accept: application/json' -d 'content'"))));
}
@Test
public void curlSnippetWithCookies() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/")
.accept(MediaType.APPLICATION_JSON)
.cookie(new Cookie("cookieName", "cookieVal")))
.andExpect(status().isOk()).andDo(document("curl-snippet-with-cookies"));
assertThat(
new File(
"build/generated-snippets/curl-snippet-with-cookies/curl-request.adoc"),
is(snippet(asciidoctor()).withContents(codeBlock(asciidoctor(), "bash")
.content("$ curl " + "'http://localhost:8080/' -i "
+ "-H 'Accept: application/json' --cookie 'cookieName=cookieVal'"))));
}
@Test
public void curlSnippetWithQueryStringOnPost() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
@@ -207,6 +226,24 @@ public class MockMvcRestDocumentationIntegrationTests {
+ " 'Accept:application/json'"))));
}
@Test
public void httpieSnippetWithCookies() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation)).build();
mockMvc.perform(get("/")
.accept(MediaType.APPLICATION_JSON)
.cookie(new Cookie("cookieName", "cookieVal")))
.andExpect(status().isOk())
.andDo(document("httpie-snippet-with-cookies"));
assertThat(
new File(
"build/generated-snippets/httpie-snippet-with-cookies/httpie-request.adoc"),
is(snippet(asciidoctor()).withContents(codeBlock(asciidoctor(), "bash")
.content("$ http GET 'http://localhost:8080/'"
+ " 'Accept:application/json' 'Cookie:cookieName=cookieVal'"))));
}
@Test
public void httpieSnippetWithQueryStringOnPost() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context)

View File

@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import com.jayway.restassured.response.Cookie;
import com.jayway.restassured.response.Header;
import com.jayway.restassured.specification.FilterableRequestSpecification;
import com.jayway.restassured.specification.MultiPartSpecification;
@@ -55,7 +56,18 @@ class RestAssuredRequestConverter
return new OperationRequestFactory().create(URI.create(requestSpec.getURI()),
HttpMethod.valueOf(requestSpec.getMethod().name()),
extractContent(requestSpec), extractHeaders(requestSpec),
extractParameters(requestSpec), extractParts(requestSpec));
extractParameters(requestSpec), extractParts(requestSpec),
extractCookies(requestSpec));
}
private Collection<javax.servlet.http.Cookie> extractCookies(FilterableRequestSpecification requestSpec) {
Collection<javax.servlet.http.Cookie> cookies = new ArrayList<>();
for (Cookie cookie : requestSpec.getCookies()) {
cookies.add(new javax.servlet.http.Cookie(cookie.getName(), cookie.getValue()));
}
return cookies;
}
private byte[] extractContent(FilterableRequestSpecification requestSpec) {

View File

@@ -25,6 +25,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import javax.servlet.http.Cookie;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.specification.FilterableRequestSpecification;
import com.jayway.restassured.specification.RequestSpecification;
@@ -143,6 +145,27 @@ public class RestAssuredRequestConverterTests {
is(equalTo(Arrays.asList("localhost:" + this.port))));
}
@Test
public void cookies() {
RequestSpecification requestSpec = RestAssured.given().port(this.port)
.cookie("cookie1", "cookieVal1")
.cookie("cookie2", "cookieVal2");
requestSpec.get("/");
OperationRequest request = this.factory
.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getCookies().size(), is(equalTo(2)));
Iterator<Cookie> cookieIterator = request.getCookies().iterator();
Cookie cookie1 = cookieIterator.next();
assertThat(cookie1.getName(), is(equalTo("cookie1")));
assertThat(cookie1.getValue(), is(equalTo("cookieVal1")));
Cookie cookie2 = cookieIterator.next();
assertThat(cookie2.getName(), is(equalTo("cookie2")));
assertThat(cookie2.getValue(), is(equalTo("cookieVal2")));
}
@Test
public void multipart() {
RequestSpecification requestSpec = RestAssured.given().port(this.port)

View File

@@ -119,6 +119,25 @@ public class RestAssuredRestDocumentationIntegrationTests {
+ "-d 'content'"))));
}
@Test
public void curlSnippetWithCookies() throws Exception {
String contentType = "text/plain; charset=UTF-8";
given().port(this.port).filter(documentationConfiguration(this.restDocumentation))
.filter(document("curl-snippet-with-cookies")).accept("application/json")
.contentType(contentType)
.cookie("cookieName", "cookieVal").get("/")
.then()
.statusCode(200);
assertThat(
new File(
"build/generated-snippets/curl-snippet-with-cookies/curl-request.adoc"),
is(snippet(asciidoctor()).withContents(codeBlock(asciidoctor(), "bash")
.content("$ curl 'http://localhost:" + this.port + "/' -i "
+ "-H 'Accept: application/json' "
+ "-H 'Content-Type: " + contentType + "' "
+ "--cookie 'cookieName=cookieVal'"))));
}
@Test
public void curlSnippetWithQueryStringOnPost() throws Exception {
given().port(this.port).filter(documentationConfiguration(this.restDocumentation))