Skip to content
Open
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
Expand Up @@ -134,6 +134,8 @@ private void insertRequestModel(Operation operation, Map<String, Object> model)
filterHeaders(headers);
model.put("request_headers_present", !headers.isEmpty());
model.put("request_headers", headers.entrySet());
model.put("request_cookies_present", !request.getCookies().isEmpty());
model.put("request_cookies", request.getCookies());
@SuppressWarnings("unchecked")
Set<String> jsonPaths = (Set<String>) operation.getAttributes().get("contract.jsonPaths");
model.put("request_json_paths_present", jsonPaths != null && !jsonPaths.isEmpty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.springframework.http.MediaType;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.restdocs.operation.Operation;
import org.springframework.restdocs.operation.RequestCookie;
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolverFactory;
import org.springframework.restdocs.snippet.Snippet;
import org.springframework.restdocs.snippet.StandardWriterResolver;
Expand Down Expand Up @@ -150,7 +151,7 @@ private ResponseDefinitionBuilder response(Operation operation) {
}

private MappingBuilder request(Operation operation) {
return queryParams(requestHeaders(requestBuilder(operation), operation), operation);
return queryParams(requestCookies(requestHeaders(requestBuilder(operation), operation), operation), operation);
}

private MappingBuilder queryParams(MappingBuilder request, Operation operation) {
Expand All @@ -166,6 +167,13 @@ private MappingBuilder queryParams(MappingBuilder request, Operation operation)
return request;
}

private MappingBuilder requestCookies(MappingBuilder request, Operation operation) {
for (RequestCookie cookie : operation.getRequest().getCookies()) {
request = request.withCookie(cookie.getName(), equalTo(cookie.getValue()));
}
return request;
}

private MappingBuilder requestHeaders(MappingBuilder request, Operation operation) {
org.springframework.http.HttpHeaders headers = operation.getRequest().getHeaders();
// TODO: whitelist headers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ Contract.make {
{{/request_headers}}
}
{{/request_headers_present}}
{{#request_cookies_present}}
cookies {
{{#request_cookies}}
cookie('''{{name}}''', '''{{value}}''')
{{/request_cookies}}
}
{{/request_cookies_present}}
{{#request_json_paths_present}}
bodyMatchers {
{{#request_json_paths}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@
package org.springframework.cloud.contract.wiremock;

import java.io.File;
import java.nio.file.Files;

import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import jakarta.servlet.http.Cookie;
import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
Expand All @@ -29,6 +33,7 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.cloud.contract.wiremock.WiremockServerRestDocsMatcherApplicationTests.TestConfiguration;
import org.springframework.cloud.contract.wiremock.restdocs.SpringCloudContractRestDocs;
import org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
Expand All @@ -52,6 +57,9 @@
@AutoConfigureMockMvc
public class WiremockServerRestDocsMatcherApplicationTests {

/**
* Expected exception rule for WireMock mismatch assertions.
*/
@Rule
public ExpectedException expected = ExpectedException.none();

Expand All @@ -71,6 +79,25 @@ public void matchesRequest() throws Exception {
assertThat(new File("target/snippets/stubs/posted.json")).exists();
}

@Test
public void stubsRenderRequestCookies() throws Exception {
File stub = new File("target/snippets/stubs/cookie.json");
File contract = new File("target/snippets/contracts/cookie.groovy");
FileSystemUtils.deleteRecursively(stub);
FileSystemUtils.deleteRecursively(contract);
this.mockMvc.perform(MockMvcRequestBuilders.get("/cookie").cookie(new Cookie("test_user", "free")))
.andExpect(MockMvcResultMatchers.content().string("Hello Cookie"))
.andDo(WireMockRestDocs.verify())
.andDo(document("cookie", SpringCloudContractRestDocs.dslContract()));

assertThat(stub).exists();
StubMapping stubMapping = WireMockStubMapping.buildFrom(Files.readString(stub.toPath()));
assertThat(stubMapping.getRequest().getCookies())
.containsOnly(Assertions.entry("test_user", WireMock.equalTo("free")));
assertThat(contract).exists();
assertThat(Files.readString(contract.toPath())).contains("cookie('''test_user''', '''free''')");
}

@Test
public void doesNotMatch() throws Exception {
this.expected.expect(AssertionError.class);
Expand All @@ -94,6 +121,12 @@ public String resource(@RequestBody String body) {
return "Hello World";
}

@ResponseBody
@RequestMapping(value = "/cookie", method = RequestMethod.GET)
public String cookie() {
return "Hello Cookie";
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.RequestCookie;
import org.springframework.restdocs.operation.ResponseCookie;
import org.springframework.restdocs.snippet.RestDocumentationContextPlaceholderResolverFactory;
import org.springframework.restdocs.snippet.StandardWriterResolver;
import org.springframework.restdocs.snippet.WriterResolver;
import org.springframework.restdocs.templates.StandardTemplateResourceResolver;
import org.springframework.restdocs.templates.TemplateEngine;
import org.springframework.restdocs.templates.TemplateFormats;
import org.springframework.restdocs.templates.mustache.MustacheTemplateEngine;

import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -58,12 +65,15 @@
*/
public class WireMockSnippetTests {

/**
* Temporary output folder for generated snippets.
*/
@Rule
public TemporaryFolder tmp = new TemporaryFolder();

Operation operation;
private Operation operation;

RestDocumentationContext context;
private RestDocumentationContext context;

private File outputFolder;

Expand Down Expand Up @@ -172,6 +182,38 @@ public void should_accept_query_params() throws IOException {
.containsOnly(Assertions.entry("myParam", MultiValuePattern.of(equalTo(("myValue")))));
}

@Test
public void should_accept_request_cookies() throws IOException {
this.operation = operation(requestGetWithCookie(), response(), this.context);
WireMockSnippet snippet = new WireMockSnippet();

snippet.document(this.operation);

File stub = new File(this.outputFolder, "stubs/foo.json");
assertThat(stub).exists();
StubMapping stubMapping = WireMockStubMapping.buildFrom(new String(Files.readAllBytes(stub.toPath())));
assertThat(stubMapping.getRequest().getCookies()).containsOnly(Assertions.entry("test_user", equalTo("free")));
}

@Test
public void should_include_request_cookies_in_contract() throws IOException {
this.operation = operation(requestGetWithCookie(), response(), this.context);
this.operation.getAttributes()
.put(TemplateEngine.class.getName(),
new MustacheTemplateEngine(new StandardTemplateResourceResolver(TemplateFormats.asciidoctor())));
this.operation.getAttributes()
.put(WriterResolver.class.getName(), new StandardWriterResolver(
new RestDocumentationContextPlaceholderResolverFactory(), "UTF-8", TemplateFormats.asciidoctor()));
ContractDslSnippet snippet = new ContractDslSnippet();

snippet.document(this.operation);

File contract = new File(this.outputFolder, "contracts/foo.groovy");
assertThat(contract).exists();
String contractText = new String(Files.readAllBytes(contract.toPath()));
assertThat(contractText).contains("cookies {").contains("cookie('''test_user''', '''free''')");
}

private Operation operation(OperationRequest request, OperationResponse response,
RestDocumentationContext context) {
return operation("foo", request, response, context);
Expand Down Expand Up @@ -486,4 +528,43 @@ public Collection<RequestCookie> getCookies() {
};
}

private OperationRequest requestGetWithCookie() {
return new OperationRequest() {
@Override
public byte[] getContent() {
return new byte[0];
}

@Override
public String getContentAsString() {
return "";
}

@Override
public HttpHeaders getHeaders() {
return new HttpHeaders();
}

@Override
public HttpMethod getMethod() {
return HttpMethod.GET;
}

@Override
public Collection<OperationRequestPart> getParts() {
return null;
}

@Override
public URI getUri() {
return URI.create("https://foo/bar");
}

@Override
public Collection<RequestCookie> getCookies() {
return Collections.singleton(new RequestCookie("test_user", "free"));
}
};
}

}