Added a CUSTOM test mode for test generation

This commit is contained in:
Marcin Grzejszczak
2020-09-14 17:37:59 +02:00
committed by Marcin Grzejszczak
parent a629f6ba10
commit 2121b0b1b4
49 changed files with 2263 additions and 428 deletions

View File

@@ -265,6 +265,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>

View File

@@ -33,6 +33,11 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.verifier.config.TestMode;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
interface CustomModeAcceptor {
default boolean acceptType(GeneratedClassMetaData generatedClassMetaData,
SingleContractMetadata singleContractMetadata) {
return generatedClassMetaData.configProperties.getTestMode() == TestMode.CUSTOM
&& acceptType(singleContractMetadata);
}
default boolean acceptType(GeneratedClassMetaData generatedClassMetaData) {
return generatedClassMetaData.configProperties.getTestMode() == TestMode.CUSTOM
&& generatedClassMetaData.isAnyHttp();
}
default boolean acceptType(SingleContractMetadata singleContractMetadata) {
return singleContractMetadata.isHttp();
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.ExecutionProperty;
import org.springframework.cloud.contract.spec.internal.FromFileProperty;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.ContentType;
class CustomModeBodyGiven implements Given {
private final BlockBuilder blockBuilder;
private final BodyReader bodyReader;
private final BodyParser bodyParser;
CustomModeBodyGiven(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.bodyReader = new BodyReader(generatedClassMetaData);
this.bodyParser = bodyParser;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
processInput(this.blockBuilder, metadata);
return this;
}
private void processInput(BlockBuilder bb, SingleContractMetadata metadata) {
Object body;
Request request = metadata.getContract().getRequest();
Object serverValue = request.getBody().getServerValue();
if (serverValue instanceof ExecutionProperty
|| serverValue instanceof FromFileProperty) {
body = request.getBody().getServerValue();
}
else {
body = this.bodyParser.requestBodyAsString(metadata);
}
bb.addIndented(getBodyString(metadata, body));
}
private String getBodyString(SingleContractMetadata metadata, Object body) {
String value;
if (body instanceof ExecutionProperty) {
value = body.toString();
}
else if (body instanceof FromFileProperty) {
FromFileProperty fileProperty = (FromFileProperty) body;
value = fileProperty.isByte()
? this.bodyReader.readBytesFromFileString(metadata, fileProperty,
CommunicationType.REQUEST)
: this.bodyReader.readStringFromFileString(metadata, fileProperty,
CommunicationType.REQUEST);
}
else {
String escaped = escapeRequestSpecialChars(metadata, body.toString());
value = this.bodyParser.quotedEscapedLongText(escaped);
}
return ".body(" + value + ")";
}
private String escapeRequestSpecialChars(SingleContractMetadata metadata,
String string) {
if (metadata.getInputTestContentType() == ContentType.JSON) {
return string.replaceAll("\\\\n", "\\\\\\\\n");
}
return string;
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null && request.getBody() != null;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
interface CustomModeBodyParser extends BodyParser {
BodyParser INSTANCE = new CustomModeBodyParser() {
};
@Override
default String responseAsString() {
return "response.getBody().asString()";
}
@Override
default String byteArrayString() {
return "response.getBody().asByteArray()";
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Iterator;
import org.springframework.cloud.contract.spec.internal.Cookie;
import org.springframework.cloud.contract.spec.internal.MatchingStrategy;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeCookiesGiven implements Given {
private final BlockBuilder blockBuilder;
CustomModeCookiesGiven(BlockBuilder blockBuilder) {
this.blockBuilder = blockBuilder;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
processInput(metadata.getContract().getRequest());
return this;
}
private void processInput(Request request) {
Iterator<Cookie> iterator = request.getCookies().getEntries().iterator();
while (iterator.hasNext()) {
Cookie cookie = iterator.next();
if (ofAbsentType(cookie)) {
return;
}
if (iterator.hasNext()) {
this.blockBuilder.addLine(string(cookie));
}
else {
this.blockBuilder.addIndented(string(cookie));
}
}
}
private String string(Cookie cookie) {
return ".cookie(" + ContentHelper.getTestSideForNonBodyValue(cookie.getKey())
+ ", " + ContentHelper.getTestSideForNonBodyValue(cookie.getServerValue())
+ ")";
}
private boolean ofAbsentType(Cookie cookie) {
return cookie.getServerValue() instanceof MatchingStrategy
&& MatchingStrategy.Type.ABSENT
.equals(((MatchingStrategy) cookie.getServerValue()).getType());
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null && request.getCookies() != null;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeCookiesThen implements Then, CustomModeAcceptor, CookieElementProcessor {
private final BlockBuilder blockBuilder;
private final ComparisonBuilder comparisonBuilder;
CustomModeCookiesThen(BlockBuilder blockBuilder,
ComparisonBuilder comparisonBuilder) {
this.blockBuilder = blockBuilder;
this.comparisonBuilder = comparisonBuilder;
}
@Override
public MethodVisitor<Then> apply(SingleContractMetadata metadata) {
processCookies(metadata);
return this;
}
@Override
public ComparisonBuilder comparisonBuilder() {
return this.comparisonBuilder;
}
@Override
public BlockBuilder blockBuilder() {
return this.blockBuilder;
}
@Override
public String cookieKey(String key) {
return "response.cookie(\"" + key + "\")";
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Response response = metadata.getContract().getResponse();
return response.getCookies() != null;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
class CustomModeFields implements Field, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
private static final String[] FIELDS = { "@Inject HttpVerifier httpVerifier" };
CustomModeFields(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
}
@Override
public Field call() {
Arrays.stream(FIELDS).forEach(this.blockBuilder::addLineWithEnding);
return this;
}
@Override
public boolean accept() {
return acceptType(this.generatedClassMetaData);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeGiven implements Given, BodyMethodVisitor, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
private final List<Given> requestGivens = new LinkedList<>();
private final List<Given> bodyGivens = new LinkedList<>();
CustomModeGiven(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.requestGivens.addAll(Collections.singletonList(
new CustomModeRequestGiven(blockBuilder, generatedClassMetaData)));
this.bodyGivens.addAll(
Arrays.asList(new CustomModeMethodWithUrlGiven(blockBuilder, bodyParser),
new CustomModeHeadersGiven(blockBuilder),
new CustomModeCookiesGiven(blockBuilder),
new CustomModeBodyGiven(blockBuilder, generatedClassMetaData,
bodyParser),
new CustomMultipartGiven(generatedClassMetaData),
new CustomModeRequestBuildGiven(blockBuilder)));
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata singleContractMetadata) {
startBodyBlock(this.blockBuilder, "given:");
addRequestGivenLine(singleContractMetadata);
indentedBodyBlock(this.blockBuilder, this.bodyGivens, singleContractMetadata);
this.blockBuilder.addEmptyLine();
return this;
}
private void addRequestGivenLine(SingleContractMetadata singleContractMetadata) {
this.requestGivens.stream().filter(given -> given.accept(singleContractMetadata))
.findFirst()
.orElseThrow(() -> new IllegalStateException(
"No matching request building Given implementation for a custom test mode"))
.apply(singleContractMetadata);
}
@Override
public boolean accept(SingleContractMetadata singleContractMetadata) {
return acceptType(generatedClassMetaData, singleContractMetadata);
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Iterator;
import org.springframework.cloud.contract.spec.internal.Header;
import org.springframework.cloud.contract.spec.internal.Headers;
import org.springframework.cloud.contract.spec.internal.MatchingStrategy;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.MapConverter;
class CustomModeHeadersGiven implements Given {
private final BlockBuilder blockBuilder;
CustomModeHeadersGiven(BlockBuilder blockBuilder) {
this.blockBuilder = blockBuilder;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
processInput(this.blockBuilder, metadata.getContract().getRequest().getHeaders());
return this;
}
private void processInput(BlockBuilder bb, Headers headers) {
Iterator<Header> iterator = headers.getEntries().iterator();
while (iterator.hasNext()) {
Header header = iterator.next();
if (ofAbsentType(header)) {
return;
}
if (iterator.hasNext()) {
bb.addLine(string(header));
}
else {
bb.addIndented(string(header));
}
}
}
private String string(Header header) {
return ".header(" + ContentHelper.getTestSideForNonBodyValue(header.getName())
+ ", "
+ ContentHelper.getTestSideForNonBodyValue(
MapConverter.getTestSideValuesForNonBody(header.getServerValue()))
+ ")";
}
private boolean ofAbsentType(Header header) {
return header.getServerValue() instanceof MatchingStrategy
&& MatchingStrategy.Type.ABSENT
.equals(((MatchingStrategy) header.getServerValue()).getType());
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null && request.getHeaders() != null;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Iterator;
import org.springframework.cloud.contract.spec.internal.ExecutionProperty;
import org.springframework.cloud.contract.spec.internal.Header;
import org.springframework.cloud.contract.spec.internal.Headers;
import org.springframework.cloud.contract.spec.internal.NotToEscapePattern;
import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.MapConverter;
class CustomModeHeadersThen implements Then, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final ComparisonBuilder comparisonBuilder;
CustomModeHeadersThen(BlockBuilder blockBuilder,
ComparisonBuilder comparisonBuilder) {
this.blockBuilder = blockBuilder;
this.comparisonBuilder = comparisonBuilder;
}
@Override
public MethodVisitor<Then> apply(SingleContractMetadata metadata) {
Response response = metadata.getContract().getResponse();
Headers headers = response.getHeaders();
Iterator<Header> iterator = headers.getEntries().iterator();
while (iterator.hasNext()) {
Header header = iterator.next();
String text = processHeaderElement(header.getName(),
header.getServerValue() instanceof NotToEscapePattern
? header.getServerValue()
: MapConverter.getTestSideValues(header.getServerValue()));
if (iterator.hasNext()) {
this.blockBuilder.addLineWithEnding(text);
}
else {
this.blockBuilder.addIndented(text);
}
}
this.blockBuilder.addEndingIfNotPresent();
return this;
}
private String processHeaderElement(String property, Object value) {
if (value instanceof NotToEscapePattern) {
return this.comparisonBuilder
.assertThat("response.header(\"" + property + "\")")
+ matchesManuallyEscapedPattern((NotToEscapePattern) value);
}
else if (value instanceof ExecutionProperty) {
return ((ExecutionProperty) value)
.insertValue("response.header(\"" + property + "\")");
}
return this.comparisonBuilder.assertThat("response.header(\"" + property + "\")",
value);
}
private String matchesManuallyEscapedPattern(NotToEscapePattern value) {
return this.comparisonBuilder
.matchesEscaped(value.getServerValue().pattern().replace("\\", "\\\\"));
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Response response = metadata.getContract().getResponse();
return response.getHeaders() != null;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
class CustomModeImports implements Imports, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
private static final String[] IMPORTS = { "javax.inject.Inject",
"org.springframework.cloud.contract.verifier.http.HttpVerifier",
"org.springframework.cloud.contract.verifier.http.Request",
"org.springframework.cloud.contract.verifier.http.Response;" };
CustomModeImports(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
}
@Override
public Imports call() {
Arrays.stream(IMPORTS)
.forEach(s -> this.blockBuilder.addLineWithEnding("import " + s));
return this;
}
@Override
public boolean accept() {
return acceptType(this.generatedClassMetaData);
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.ExecutionProperty;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.spec.internal.Url;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.MapConverter;
class CustomModeMethodWithUrlGiven implements Given {
private final BlockBuilder blockBuilder;
private final BodyParser bodyParser;
CustomModeMethodWithUrlGiven(BlockBuilder blockBuilder, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.bodyParser = bodyParser;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
addUrl(getUrl(metadata.getContract().getRequest()),
metadata.getContract().getRequest());
return this;
}
private Url getUrl(Request request) {
if (request.getUrl() != null) {
return request.getUrl();
}
if (request.getUrlPath() != null) {
return request.getUrlPath();
}
throw new IllegalStateException("URL is not set!");
}
private void addUrl(Url buildUrl, Request request) {
Object testSideUrl = MapConverter.getTestSideValues(buildUrl);
String method = request.getMethod().getServerValue().toString().toLowerCase();
String url = testSideUrl.toString();
if (!(testSideUrl instanceof ExecutionProperty)) {
url = this.bodyParser.quotedShortText(testSideUrl.toString());
}
this.blockBuilder.addIndented("." + method + "(" + url + ")");
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeRequestBuildGiven implements Given {
private final BlockBuilder blockBuilder;
CustomModeRequestBuildGiven(BlockBuilder blockBuilder) {
this.blockBuilder = blockBuilder;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
this.blockBuilder.addLineWithEnding(".build()");
return this;
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeRequestGiven implements Given, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
CustomModeRequestGiven(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = metaData;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
this.blockBuilder.addIndented("Request request = given()");
return this;
}
@Override
public boolean accept(SingleContractMetadata metadata) {
return acceptType(this.generatedClassMetaData);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeResponseWhen implements When, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
CustomModeResponseWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = metaData;
}
@Override
public MethodVisitor<When> apply(SingleContractMetadata metadata) {
this.blockBuilder
.addLineWithEnding("Response response = httpVerifier.exchange(request)")
.endBlock();
return this;
}
@Override
public boolean accept(SingleContractMetadata metadata) {
return acceptType(this.generatedClassMetaData, metadata);
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
class CustomModeStaticImports implements Imports, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
private static final String[] IMPORTS = {
"org.springframework.cloud.contract.verifier.http.Request.given" };
CustomModeStaticImports(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
}
@Override
public Imports call() {
Arrays.stream(IMPORTS)
.forEach(s -> this.blockBuilder.addLineWithEnding("import static " + s));
return this;
}
@Override
public boolean accept() {
return acceptType(this.generatedClassMetaData);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeStatusCodeThen implements Then {
private final BlockBuilder blockBuilder;
private final ComparisonBuilder comparisonBuilder;
CustomModeStatusCodeThen(BlockBuilder blockBuilder,
ComparisonBuilder comparisonBuilder) {
this.blockBuilder = blockBuilder;
this.comparisonBuilder = comparisonBuilder;
}
@Override
public MethodVisitor<Then> apply(SingleContractMetadata metadata) {
Response response = metadata.getContract().getResponse();
this.blockBuilder
.addIndented(this.comparisonBuilder.assertThat("response.statusCode()",
response.getStatus().getServerValue()))
.addEndingIfNotPresent();
return this;
}
@Override
public boolean accept(SingleContractMetadata metadata) {
return true;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeThen implements Then, BodyMethodVisitor, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
private final List<Then> thens = new LinkedList<>();
CustomModeThen(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser,
ComparisonBuilder comparisonBuilder) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.thens.addAll(Arrays.asList(
new CustomModeStatusCodeThen(this.blockBuilder, comparisonBuilder),
new CustomModeHeadersThen(this.blockBuilder, comparisonBuilder),
new CustomModeCookiesThen(this.blockBuilder, comparisonBuilder),
new GenericHttpBodyThen(this.blockBuilder, generatedClassMetaData,
bodyParser, comparisonBuilder)));
}
@Override
public MethodVisitor<Then> apply(SingleContractMetadata singleContractMetadata) {
startBodyBlock(this.blockBuilder, "then:");
bodyBlock(this.blockBuilder, this.thens, singleContractMetadata);
return this;
}
@Override
public boolean accept(SingleContractMetadata singleContractMetadata) {
return acceptType(this.generatedClassMetaData, singleContractMetadata);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomModeWhen implements When, BodyMethodVisitor, CustomModeAcceptor {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
private final List<When> responseWhens = new LinkedList<>();
CustomModeWhen(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.responseWhens.addAll(Arrays.asList(
new CustomModeResponseWhen(blockBuilder, this.generatedClassMetaData)));
}
@Override
public MethodVisitor<When> apply(SingleContractMetadata singleContractMetadata) {
startBodyBlock(this.blockBuilder, "when:");
addResponseWhenLine(singleContractMetadata);
this.blockBuilder.addEmptyLine();
return this;
}
private void addResponseWhenLine(SingleContractMetadata singleContractMetadata) {
this.responseWhens.stream().filter(when -> when.accept(singleContractMetadata))
.findFirst()
.orElseThrow(() -> new IllegalStateException(
"No matching request building When implementation for Rest Assured"))
.apply(singleContractMetadata);
}
@Override
public boolean accept(SingleContractMetadata singleContractMetadata) {
return acceptType(this.generatedClassMetaData, singleContractMetadata);
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomMultipartGiven implements Given, CustomModeAcceptor {
private final GeneratedClassMetaData generatedClassMetaData;
CustomMultipartGiven(GeneratedClassMetaData generatedClassMetaData) {
this.generatedClassMetaData = generatedClassMetaData;
}
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
throw new UnsupportedOperationException("Multipart is not yet supported");
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null && request.getMultipart() != null
&& acceptType(this.generatedClassMetaData, metadata);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.spec.internal.Url;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class CustomQueryParamsGiven implements Given, CustomModeAcceptor, QueryParamsResolver {
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
throw new UnsupportedOperationException("Query params are not supported");
}
private Url getUrl(Request request) {
if (request.getUrl() != null) {
return request.getUrl();
}
if (request.getUrlPath() != null) {
return request.getUrlPath();
}
throw new IllegalStateException("URL is not set!");
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
Url url = getUrl(request);
return url.getQueryParameters() != null;
}
}

View File

@@ -35,6 +35,11 @@ class FieldBuilder {
return this;
}
FieldBuilder customMode() {
this.parentBuilder.field(new CustomModeFields(this.builder, this.metaData));
return this;
}
ClassBodyBuilder build() {
return this.parentBuilder;
}

View File

@@ -36,9 +36,15 @@ class ImportsBuilder {
return this;
}
ImportsBuilder custom() {
this.parentBuilder.imports(new CustomImports(builder, metaData));
this.parentBuilder.staticImports(new CustomStaticImports(builder, metaData));
ImportsBuilder userImports() {
this.parentBuilder.imports(new UserImports(builder, metaData));
this.parentBuilder.staticImports(new UserStaticImports(builder, metaData));
return this;
}
ImportsBuilder customMode() {
this.parentBuilder.imports(new CustomModeImports(builder, metaData));
this.parentBuilder.staticImports(new CustomModeStaticImports(builder, metaData));
return this;
}

View File

@@ -26,7 +26,7 @@ import org.springframework.cloud.contract.verifier.util.MapConverter;
import static org.springframework.cloud.contract.verifier.util.ContentUtils.getJavaMultipartFileParameterContent;
class MockMvcMultipartGiven implements Given {
class JavaMultipartGiven implements Given, RestAssuredAcceptor {
private final BlockBuilder blockBuilder;
@@ -36,8 +36,8 @@ class MockMvcMultipartGiven implements Given {
private final BodyParser bodyParser;
MockMvcMultipartGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData,
BodyParser bodyParser) {
JavaMultipartGiven(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.bodyReader = new BodyReader(generatedClassMetaData);
this.bodyParser = bodyParser;
@@ -46,40 +46,47 @@ class MockMvcMultipartGiven implements Given {
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
getMultipartParameters(metadata).entrySet()
.forEach(entry -> this.blockBuilder.addLine(getMultipartParameterLine(metadata, entry)));
getMultipartParameters(metadata).entrySet().forEach(entry -> this.blockBuilder
.addLine(getMultipartParameterLine(metadata, entry)));
return this;
}
private String getMultipartParameterLine(SingleContractMetadata metadata, Map.Entry<String, Object> parameter) {
private String getMultipartParameterLine(SingleContractMetadata metadata,
Map.Entry<String, Object> parameter) {
if (parameter.getValue() instanceof NamedProperty) {
return ".multiPart(" + getMultipartFileParameterContent(metadata, parameter.getKey(),
(NamedProperty) parameter.getValue()) + ")";
return ".multiPart(" + getMultipartFileParameterContent(metadata,
parameter.getKey(), (NamedProperty) parameter.getValue()) + ")";
}
return getParameterString(parameter);
}
@SuppressWarnings("unchecked")
private Map<String, Object> getMultipartParameters(SingleContractMetadata metadata) {
return (Map<String, Object>) metadata.getContract().getRequest().getMultipart().getServerValue();
return (Map<String, Object>) metadata.getContract().getRequest().getMultipart()
.getServerValue();
}
private String getMultipartFileParameterContent(SingleContractMetadata metadata, String propertyName,
NamedProperty propertyValue) {
private String getMultipartFileParameterContent(SingleContractMetadata metadata,
String propertyName, NamedProperty propertyValue) {
return getJavaMultipartFileParameterContent(propertyName, propertyValue,
fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp, CommunicationType.REQUEST));
fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp,
CommunicationType.REQUEST));
}
private String getParameterString(Map.Entry<String, Object> parameter) {
return ".param(" + this.bodyParser.quotedShortText(parameter.getKey()) + ", "
+ this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(parameter.getValue())) + ")";
+ this.bodyParser.quotedShortText(
MapConverter.getTestSideValuesForNonBody(parameter.getValue()))
+ ")";
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null && request.getMultipart() != null
&& this.generatedClassMetaData.configProperties.getTestFramework() != TestFramework.SPOCK;
&& acceptType(this.generatedClassMetaData, metadata)
&& this.generatedClassMetaData.configProperties
.getTestFramework() != TestFramework.SPOCK;
}
}

View File

@@ -66,7 +66,8 @@ public class JavaTestGenerator implements SingleTestGenerator {
.build()
.imports()
.defaultImports()
.custom()
.userImports()
.customMode()
.json()
.jUnit4()
.jUnit5()
@@ -93,6 +94,7 @@ public class JavaTestGenerator implements SingleTestGenerator {
return ClassBodyBuilder.builder(builder, metaData)
.field()
.messaging()
.customMode()
.build()
.methodBuilder(methodBuilder);
// @formatter:on
@@ -112,6 +114,7 @@ public class JavaTestGenerator implements SingleTestGenerator {
.spock()
.build()
.restAssured()
.customMode()
.jaxRs()
.messaging();
// @formatter:on

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.verifier.config.TestMode;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
interface RestAssuredAcceptor {
default boolean acceptType(GeneratedClassMetaData generatedClassMetaData,
SingleContractMetadata singleContractMetadata) {
return generatedClassMetaData.configProperties.getTestMode() != TestMode.CUSTOM
&& generatedClassMetaData.configProperties
.getTestMode() != TestMode.JAXRSCLIENT
&& singleContractMetadata.isHttp();
}
}

View File

@@ -19,7 +19,8 @@ package org.springframework.cloud.contract.verifier.builder;
import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class RestAssuredCookiesThen implements Then, MockMvcAcceptor, CookieElementProcessor {
class RestAssuredCookiesThen
implements Then, RestAssuredAcceptor, CookieElementProcessor {
private final BlockBuilder blockBuilder;

View File

@@ -20,10 +20,9 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.verifier.config.TestMode;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class RestAssuredGiven implements Given, BodyMethodVisitor {
class RestAssuredGiven implements Given, BodyMethodVisitor, RestAssuredAcceptor {
private final BlockBuilder blockBuilder;
@@ -33,18 +32,21 @@ class RestAssuredGiven implements Given, BodyMethodVisitor {
private final List<Given> bodyGivens = new LinkedList<>();
RestAssuredGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
RestAssuredGiven(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.requestGivens.addAll(Arrays.asList(new MockMvcRequestGiven(blockBuilder, generatedClassMetaData),
this.requestGivens.addAll(Arrays.asList(
new MockMvcRequestGiven(blockBuilder, generatedClassMetaData),
new SpockMockMvcRequestGiven(blockBuilder, generatedClassMetaData),
new ExplicitRequestGiven(blockBuilder, generatedClassMetaData),
new WebTestClientRequestGiven(blockBuilder, generatedClassMetaData)));
this.bodyGivens
.addAll(Arrays.asList(new MockMvcHeadersGiven(blockBuilder), new MockMvcCookiesGiven(blockBuilder),
new MockMvcBodyGiven(blockBuilder, generatedClassMetaData, bodyParser),
new MockMvcMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser),
new SpockMockMvcMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser)));
this.bodyGivens.addAll(Arrays.asList(new MockMvcHeadersGiven(blockBuilder),
new MockMvcCookiesGiven(blockBuilder),
new MockMvcBodyGiven(blockBuilder, generatedClassMetaData, bodyParser),
new JavaMultipartGiven(blockBuilder, generatedClassMetaData, bodyParser),
new SpockMockMvcMultipartGiven(blockBuilder, generatedClassMetaData,
bodyParser)));
}
@Override
@@ -57,15 +59,16 @@ class RestAssuredGiven implements Given, BodyMethodVisitor {
}
private void addRequestGivenLine(SingleContractMetadata singleContractMetadata) {
this.requestGivens.stream().filter(given -> given.accept(singleContractMetadata)).findFirst().orElseThrow(
() -> new IllegalStateException("No matching request building Given implementation for Rest Assured"))
this.requestGivens.stream().filter(given -> given.accept(singleContractMetadata))
.findFirst()
.orElseThrow(() -> new IllegalStateException(
"No matching request building Given implementation for Rest Assured"))
.apply(singleContractMetadata);
}
@Override
public boolean accept(SingleContractMetadata singleContractMetadata) {
return singleContractMetadata.isHttp()
&& this.generatedClassMetaData.configProperties.getTestMode() != TestMode.JAXRSCLIENT;
return acceptType(this.generatedClassMetaData, singleContractMetadata);
}
}

View File

@@ -26,7 +26,7 @@ import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.MapConverter;
class RestAssuredHeadersThen implements Then, MockMvcAcceptor {
class RestAssuredHeadersThen implements Then, RestAssuredAcceptor {
private final BlockBuilder blockBuilder;

View File

@@ -20,10 +20,9 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.verifier.config.TestMode;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class RestAssuredThen implements Then, BodyMethodVisitor {
class RestAssuredThen implements Then, BodyMethodVisitor, RestAssuredAcceptor {
private final BlockBuilder blockBuilder;
@@ -31,14 +30,17 @@ class RestAssuredThen implements Then, BodyMethodVisitor {
private final List<Then> thens = new LinkedList<>();
RestAssuredThen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser,
RestAssuredThen(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser,
ComparisonBuilder comparisonBuilder) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.thens.addAll(Arrays.asList(new RestAssuredStatusCodeThen(this.blockBuilder, comparisonBuilder),
this.thens.addAll(Arrays.asList(
new RestAssuredStatusCodeThen(this.blockBuilder, comparisonBuilder),
new RestAssuredHeadersThen(this.blockBuilder, comparisonBuilder),
new RestAssuredCookiesThen(this.blockBuilder, comparisonBuilder),
new GenericHttpBodyThen(this.blockBuilder, generatedClassMetaData, bodyParser, comparisonBuilder)));
new GenericHttpBodyThen(this.blockBuilder, generatedClassMetaData,
bodyParser, comparisonBuilder)));
}
@Override
@@ -50,8 +52,7 @@ class RestAssuredThen implements Then, BodyMethodVisitor {
@Override
public boolean accept(SingleContractMetadata singleContractMetadata) {
return singleContractMetadata.isHttp()
&& this.generatedClassMetaData.configProperties.getTestMode() != TestMode.JAXRSCLIENT;
return acceptType(this.generatedClassMetaData, singleContractMetadata);
}
}

View File

@@ -20,10 +20,9 @@ import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.contract.verifier.config.TestMode;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
class RestAssuredWhen implements When, BodyMethodVisitor {
class RestAssuredWhen implements When, BodyMethodVisitor, RestAssuredAcceptor {
private final BlockBuilder blockBuilder;
@@ -33,16 +32,21 @@ class RestAssuredWhen implements When, BodyMethodVisitor {
private final List<When> whens = new LinkedList<>();
RestAssuredWhen(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
RestAssuredWhen(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.responseWhens.addAll(Arrays.asList(new MockMvcResponseWhen(blockBuilder, this.generatedClassMetaData),
this.responseWhens.addAll(Arrays.asList(
new MockMvcResponseWhen(blockBuilder, this.generatedClassMetaData),
new SpockMockMvcResponseWhen(blockBuilder, this.generatedClassMetaData),
new ExplicitResponseWhen(blockBuilder, this.generatedClassMetaData),
new WebTestClientResponseWhen(blockBuilder, this.generatedClassMetaData)));
this.whens.addAll(Arrays.asList(new MockMvcQueryParamsWhen(this.blockBuilder, bodyParser),
new MockMvcAsyncWhen(this.blockBuilder, this.generatedClassMetaData),
new MockMvcUrlWhen(this.blockBuilder, bodyParser)));
new WebTestClientResponseWhen(blockBuilder,
this.generatedClassMetaData)));
this.whens.addAll(
Arrays.asList(new MockMvcQueryParamsWhen(this.blockBuilder, bodyParser),
new MockMvcAsyncWhen(this.blockBuilder,
this.generatedClassMetaData),
new MockMvcUrlWhen(this.blockBuilder, bodyParser)));
}
@Override
@@ -55,15 +59,16 @@ class RestAssuredWhen implements When, BodyMethodVisitor {
}
private void addResponseWhenLine(SingleContractMetadata singleContractMetadata) {
this.responseWhens.stream().filter(when -> when.accept(singleContractMetadata)).findFirst().orElseThrow(
() -> new IllegalStateException("No matching request building When implementation for Rest Assured"))
this.responseWhens.stream().filter(when -> when.accept(singleContractMetadata))
.findFirst()
.orElseThrow(() -> new IllegalStateException(
"No matching request building When implementation for Rest Assured"))
.apply(singleContractMetadata);
}
@Override
public boolean accept(SingleContractMetadata singleContractMetadata) {
return singleContractMetadata.isHttp()
&& this.generatedClassMetaData.configProperties.getTestMode() != TestMode.JAXRSCLIENT;
return acceptType(this.generatedClassMetaData, singleContractMetadata);
}
}

View File

@@ -99,6 +99,20 @@ class SingleMethodBuilder {
.methodPostProcessor(new TemplateUpdatingMethodPostProcessor(this.blockBuilder));
}
SingleMethodBuilder customMode() {
return given(new CustomModeGiven(this.blockBuilder, this.generatedClassMetaData,
CustomModeBodyParser.INSTANCE))
.methodPreProcessor(new InProgressContractMethodPreProcessor())
.when(new CustomModeWhen(this.blockBuilder,
this.generatedClassMetaData))
.then(new CustomModeThen(this.blockBuilder,
this.generatedClassMetaData,
CustomModeBodyParser.INSTANCE,
ComparisonBuilder.JAVA_HTTP_INSTANCE))
.methodPostProcessor(new TemplateUpdatingMethodPostProcessor(
this.blockBuilder));
}
SingleMethodBuilder jaxRs() {
return methodPreProcessor(new InProgressContractMethodPreProcessor())
.given(new JaxRsGiven(this.generatedClassMetaData))

View File

@@ -25,7 +25,7 @@ import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.ContentUtils;
import org.springframework.cloud.contract.verifier.util.MapConverter;
class SpockMockMvcMultipartGiven implements Given {
class SpockMockMvcMultipartGiven implements Given, MockMvcAcceptor {
private final BlockBuilder blockBuilder;
@@ -35,8 +35,8 @@ class SpockMockMvcMultipartGiven implements Given {
private final BodyParser bodyParser;
SpockMockMvcMultipartGiven(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData,
BodyParser bodyParser) {
SpockMockMvcMultipartGiven(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData, BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.bodyReader = new BodyReader(generatedClassMetaData);
this.bodyParser = bodyParser;
@@ -45,40 +45,48 @@ class SpockMockMvcMultipartGiven implements Given {
@Override
public MethodVisitor<Given> apply(SingleContractMetadata metadata) {
getMultipartParameters(metadata).entrySet()
.forEach(entry -> this.blockBuilder.addLine(getMultipartParameterLine(metadata, entry)));
getMultipartParameters(metadata).entrySet().forEach(entry -> this.blockBuilder
.addLine(getMultipartParameterLine(metadata, entry)));
return this;
}
private String getMultipartParameterLine(SingleContractMetadata metadata, Map.Entry<String, Object> parameter) {
private String getMultipartParameterLine(SingleContractMetadata metadata,
Map.Entry<String, Object> parameter) {
if (parameter.getValue() instanceof NamedProperty) {
return ".multiPart(" + getMultipartFileParameterContent(metadata, parameter.getKey(),
(NamedProperty) parameter.getValue()) + ")";
return ".multiPart(" + getMultipartFileParameterContent(metadata,
parameter.getKey(), (NamedProperty) parameter.getValue()) + ")";
}
return getParameterString(parameter);
}
@SuppressWarnings("unchecked")
private Map<String, Object> getMultipartParameters(SingleContractMetadata metadata) {
return (Map<String, Object>) metadata.getContract().getRequest().getMultipart().getServerValue();
return (Map<String, Object>) metadata.getContract().getRequest().getMultipart()
.getServerValue();
}
private String getMultipartFileParameterContent(SingleContractMetadata metadata, String propertyName,
NamedProperty propertyValue) {
return ContentUtils.getGroovyMultipartFileParameterContent(propertyName, propertyValue,
fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp, CommunicationType.REQUEST));
private String getMultipartFileParameterContent(SingleContractMetadata metadata,
String propertyName, NamedProperty propertyValue) {
return ContentUtils.getGroovyMultipartFileParameterContent(propertyName,
propertyValue,
fileProp -> this.bodyReader.readBytesFromFileString(metadata, fileProp,
CommunicationType.REQUEST));
}
private String getParameterString(Map.Entry<String, Object> parameter) {
return ".param(" + this.bodyParser.quotedShortText(parameter.getKey()) + ", "
+ this.bodyParser.quotedShortText(MapConverter.getTestSideValuesForNonBody(parameter.getValue())) + ")";
+ this.bodyParser.quotedShortText(
MapConverter.getTestSideValuesForNonBody(parameter.getValue()))
+ ")";
}
@Override
public boolean accept(SingleContractMetadata metadata) {
Request request = metadata.getContract().getRequest();
return request != null && request.getMultipart() != null
&& this.generatedClassMetaData.configProperties.getTestFramework() == TestFramework.SPOCK;
&& acceptType(this.generatedClassMetaData, metadata)
&& this.generatedClassMetaData.configProperties
.getTestFramework() == TestFramework.SPOCK;
}
}

View File

@@ -18,13 +18,14 @@ package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
class CustomImports implements Imports {
class UserImports implements Imports {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
CustomImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) {
UserImports(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
}

View File

@@ -18,13 +18,14 @@ package org.springframework.cloud.contract.verifier.builder;
import java.util.Arrays;
class CustomStaticImports implements Imports {
class UserStaticImports implements Imports {
private final BlockBuilder blockBuilder;
private final GeneratedClassMetaData generatedClassMetaData;
CustomStaticImports(BlockBuilder blockBuilder, GeneratedClassMetaData generatedClassMetaData) {
UserStaticImports(BlockBuilder blockBuilder,
GeneratedClassMetaData generatedClassMetaData) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
}
@@ -39,7 +40,8 @@ class CustomStaticImports implements Imports {
@Override
public boolean accept() {
return this.generatedClassMetaData.configProperties.getStaticImports() != null
&& this.generatedClassMetaData.configProperties.getStaticImports().length > 0;
&& this.generatedClassMetaData.configProperties
.getStaticImports().length > 0;
}
}

View File

@@ -1,96 +0,0 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder.imports;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.springframework.cloud.contract.verifier.config.TestFramework.CUSTOM;
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT;
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5;
import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK;
import static org.springframework.cloud.contract.verifier.config.TestFramework.TESTNG;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.contract.verifier.config.TestFramework;
/**
* Provides imports based on test framework.
*
* @author Olga Maciaszek-Sharma
* @since 2.1.0
* @deprecated
*/
@Deprecated
public class BaseImportProvider {
private static final ImportDefinitions GENERAL_IMPORTS = new ImportDefinitions(emptyList(),
Arrays.asList(
"org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat",
"org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*"));
private static final Map<TestFramework, String> RULE_IMPORT;
private static final Map<TestFramework, ImportDefinitions> TEST_FRAMEWORK_SPECIFIC_IMPORTS;
static {
TEST_FRAMEWORK_SPECIFIC_IMPORTS = new HashMap<>(5);
TEST_FRAMEWORK_SPECIFIC_IMPORTS.put(JUNIT, new ImportDefinitions(singletonList("org.junit.Test")));
TEST_FRAMEWORK_SPECIFIC_IMPORTS.put(JUNIT5, new ImportDefinitions(singletonList("org.junit.jupiter.api.Test")));
TEST_FRAMEWORK_SPECIFIC_IMPORTS.put(SPOCK, new ImportDefinitions(emptyList()));
TEST_FRAMEWORK_SPECIFIC_IMPORTS.put(TESTNG,
new ImportDefinitions(singletonList("org.testng.annotations.Test")));
TEST_FRAMEWORK_SPECIFIC_IMPORTS.put(CUSTOM, new ImportDefinitions(emptyList()));
RULE_IMPORT = new HashMap<>(5);
RULE_IMPORT.put(JUNIT, "org.junit.Rule");
RULE_IMPORT.put(JUNIT5, "org.junit.jupiter.api.extension.ExtendWith");
RULE_IMPORT.put(SPOCK, "org.junit.Rule");
RULE_IMPORT.put(TESTNG, "org.junit.Rule");
RULE_IMPORT.put(CUSTOM, "org.junit.Rule");
}
/**
* Returns list of imports for provided test framework.
* @param testFramework
* @return list of imports
*/
public static List<String> getImports(TestFramework testFramework) {
List<String> result = new ArrayList<>(GENERAL_IMPORTS.getImports());
result.addAll(TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).getImports());
return result;
}
/**
* @param testFramework test framework to pick the static imports for
* @return list of static imports for provided test framework.
*/
public static List<String> getStaticImports(TestFramework testFramework) {
List<String> result = new ArrayList<>(GENERAL_IMPORTS.getStaticImports());
result.addAll(TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).getStaticImports());
return result;
}
public static String getRuleImport(TestFramework testFramework) {
return RULE_IMPORT.get(testFramework);
}
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder.imports;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.springframework.cloud.contract.verifier.config.TestFramework.CUSTOM;
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT;
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT5;
import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK;
import static org.springframework.cloud.contract.verifier.config.TestFramework.TESTNG;
import static org.springframework.cloud.contract.verifier.config.TestMode.EXPLICIT;
import static org.springframework.cloud.contract.verifier.config.TestMode.JAXRSCLIENT;
import static org.springframework.cloud.contract.verifier.config.TestMode.MOCKMVC;
import static org.springframework.cloud.contract.verifier.config.TestMode.WEBTESTCLIENT;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.cloud.contract.verifier.config.TestFramework;
import org.springframework.cloud.contract.verifier.config.TestMode;
/**
* Provides imports based on test framework and test mode.
*
* @author Olga Maciaszek-Sharma
* @since 2.1.0
*/
@Deprecated
public class HttpImportProvider {
private final Map<Pair<TestFramework, TestMode>, ImportDefinitions> FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS;
private final Map<TestMode, ImportDefinitions> TEST_MODE_SPECIFIC_IMPORTS;
public HttpImportProvider(String restAssuredPackage) {
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS = new HashMap<>(20);
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT, JAXRSCLIENT),
new ImportDefinitions(singletonList("javax.ws.rs.core.Response")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT5, JAXRSCLIENT),
new ImportDefinitions(singletonList("javax.ws.rs.core.Response")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(TESTNG, JAXRSCLIENT),
new ImportDefinitions(singletonList("javax.ws.rs.core.Response")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT, MOCKMVC),
new ImportDefinitions(
Arrays.asList(restAssuredPackage + ".module.mockmvc.specification.MockMvcRequestSpecification",
restAssuredPackage + ".response.ResponseOptions")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT, WEBTESTCLIENT),
new ImportDefinitions(Arrays.asList(
"io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification",
"io.restassured.module.webtestclient.response.WebTestClientResponse")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT5, MOCKMVC),
new ImportDefinitions(
Arrays.asList(restAssuredPackage + ".module.mockmvc.specification.MockMvcRequestSpecification",
restAssuredPackage + ".response.ResponseOptions")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT5, WEBTESTCLIENT),
new ImportDefinitions(Arrays.asList(
"io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification",
"io.restassured.module.webtestclient.response.WebTestClientResponse")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(TESTNG, MOCKMVC),
new ImportDefinitions(
Arrays.asList(restAssuredPackage + ".module.mockmvc.specification.MockMvcRequestSpecification",
restAssuredPackage + ".response.ResponseOptions")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(TESTNG, WEBTESTCLIENT),
new ImportDefinitions(Arrays.asList(
"io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification",
"io.restassured.module.webtestclient.response.WebTestClientResponse")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT, EXPLICIT),
new ImportDefinitions(Arrays.asList(restAssuredPackage + ".specification.RequestSpecification",
restAssuredPackage + ".response.Response")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(JUNIT5, EXPLICIT),
new ImportDefinitions(Arrays.asList(restAssuredPackage + ".specification.RequestSpecification",
restAssuredPackage + ".response.Response")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(TESTNG, EXPLICIT),
new ImportDefinitions(Arrays.asList(restAssuredPackage + ".specification.RequestSpecification",
restAssuredPackage + ".response.Response")));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(SPOCK, JAXRSCLIENT), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(CUSTOM, JAXRSCLIENT), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(SPOCK, MOCKMVC), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(CUSTOM, MOCKMVC), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(SPOCK, EXPLICIT), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(CUSTOM, EXPLICIT), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(SPOCK, WEBTESTCLIENT), new ImportDefinitions(emptyList()));
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.put(Pair.of(CUSTOM, WEBTESTCLIENT),
new ImportDefinitions(emptyList()));
TEST_MODE_SPECIFIC_IMPORTS = new HashMap<>(4);
TEST_MODE_SPECIFIC_IMPORTS.put(JAXRSCLIENT,
new ImportDefinitions(emptyList(), singletonList("javax.ws.rs.client.Entity.*")));
TEST_MODE_SPECIFIC_IMPORTS.put(MOCKMVC, new ImportDefinitions(emptyList(),
singletonList(restAssuredPackage + ".module.mockmvc.RestAssuredMockMvc.*")));
TEST_MODE_SPECIFIC_IMPORTS.put(EXPLICIT,
new ImportDefinitions(emptyList(), singletonList(restAssuredPackage + ".RestAssured.*")));
TEST_MODE_SPECIFIC_IMPORTS.put(WEBTESTCLIENT, new ImportDefinitions(emptyList(),
singletonList("io.restassured.module.webtestclient.RestAssuredWebTestClient.*")));
}
/**
* Returns list of imports for http test contracts for provided test framework and
* test mode.
* @param testFramework
* @param testMode
* @return list of imports
*/
public List<String> getImports(TestFramework testFramework, TestMode testMode) {
List<String> result = new ArrayList<>(TEST_MODE_SPECIFIC_IMPORTS.get(testMode).getImports());
result.addAll(FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.get(Pair.of(testFramework, testMode)).getImports());
return result;
}
/**
* Returns list of static imports for http test contracts for provided test framework
* and test mode.
* @param testFramework
* @param testMode
* @return list of static imports
*/
public List<String> getStaticImports(TestFramework testFramework, TestMode testMode) {
List<String> result = new ArrayList<>(TEST_MODE_SPECIFIC_IMPORTS.get(testMode).getStaticImports());
result.addAll(
FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.get(Pair.of(testFramework, testMode)).getStaticImports());
return result;
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder.imports;
import java.util.ArrayList;
import java.util.List;
/**
* @author Olga Maciaszek-Sharma
* @since 2.1.0
*/
@Deprecated
class ImportDefinitions {
private final List<String> imports;
private final List<String> staticImports;
public ImportDefinitions(List<String> imports, List<String> staticImports) {
this.imports = imports;
this.staticImports = staticImports;
}
public ImportDefinitions(List<String> imports) {
this(imports, new ArrayList<>());
}
public final List<String> getImports() {
return imports;
}
public final List<String> getStaticImports() {
return staticImports;
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2013-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.builder.imports;
import java.util.Arrays;
import java.util.List;
/**
* Provides imports based on test framework and test mode.
*
* @author Olga Maciaszek-Sharma
* @since 2.1.0
*/
@Deprecated
public class MessagingImportProvider {
/**
* @return list of imports for messaging test contracts.
*/
public static List<String> getImports() {
return Arrays.asList("javax.inject.Inject",
"org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper",
"org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage",
"org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging");
}
/**
* @return list of static imports for messaging test contracts.
*/
public static List<String> getStaticImports() {
return Arrays.asList(
"org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers",
"org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes");
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.contract.verifier.config;
import org.springframework.cloud.contract.verifier.http.HttpVerifier;
/**
* Provides different testing modes.
*
@@ -25,6 +27,10 @@ package org.springframework.cloud.contract.verifier.config;
*/
public enum TestMode {
/**
* Requires the user to provide an implementation of the {@link HttpVerifier}.
*/
CUSTOM,
/**
* Uses Spring's MockMvc mode.
*/

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2012-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.http;
import java.nio.charset.Charset;
/**
* Abstraction over an HTTP body.
*
* Warning! This API is experimental and can change in time.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class Body {
final Object body;
Body(Object body) {
this.body = body;
}
/**
* @return body as byte array
*/
public byte[] asByteArray() {
if (body instanceof byte[]) {
return (byte[]) this.body;
}
return body.toString().getBytes();
}
/**
* @return body as string
*/
public String asString() {
return asString(Charset.defaultCharset());
}
/**
* @param charset to encode the body
* @return body as string
*/
public String asString(Charset charset) {
if (body instanceof String) {
return (String) body;
}
else if (body instanceof byte[]) {
return new String((byte[]) body, charset);
}
return body.toString();
}
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright 2012-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.http;
import java.util.Arrays;
import java.util.Map;
import org.springframework.cloud.contract.verifier.util.MetadataUtil;
import org.springframework.cloud.contract.verifier.util.SpringCloudContractMetadata;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
/**
* Metadata representation of the Contract Verifier's HTTP communication.
*
* Warning! This API is experimental and can change in time.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class ContractVerifierHttpMetadata implements SpringCloudContractMetadata {
/**
* Metadata entry in the contract.
*/
public static final String METADATA_KEY = "verifierHttp";
/**
* Scheme used for HTTP communication.
*/
private Scheme scheme;
/**
* Protocol used for HTTP communication.
*/
private Protocol protocol;
@NonNull
public static ContractVerifierHttpMetadata fromMetadata(
Map<String, Object> metadata) {
return MetadataUtil.fromMetadata(metadata, METADATA_KEY,
new ContractVerifierHttpMetadata());
}
@Override
public String key() {
return METADATA_KEY;
}
@Override
public String description() {
return "Metadata entries used by the framework";
}
public Scheme getScheme() {
return scheme;
}
public void setScheme(Scheme scheme) {
this.scheme = scheme;
}
public void setScheme(String scheme) {
this.scheme = Scheme.fromString(scheme);
}
public Protocol getProtocol() {
return this.protocol;
}
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
public void setProtocol(String protocol) {
this.protocol = Protocol.fromString(protocol);
}
/**
* HTTP communication scheme.
*/
public enum Scheme {
/**
* HTTP scheme.
*/
HTTP,
/**
* HTTPS scheme.
*/
HTTPS;
/**
* Builds an enum from string.
*/
@Nullable
public static Scheme fromString(String scheme) {
return Arrays.stream(values()).filter(p -> p.name().equalsIgnoreCase(scheme))
.findFirst().orElse(null);
}
}
/**
* Taken from OKHttp's Protocol.
*/
public enum Protocol {
/**
* An obsolete plaintext framing that does not use persistent sockets by default.
*/
HTTP_1_0("http/1.0"),
/**
* A plaintext framing that includes persistent connections.
*
* This version of OkHttp implements [RFC 7230][rfc_7230], and tracks revisions to
* that spec.
*
* [rfc_7230]: https://tools.ietf.org/html/rfc7230
*/
HTTP_1_1("http/1.1"),
/**
* The IETF's binary-framed protocol that includes header compression,
* multiplexing multiple requests on the same socket, and server-push. HTTP/1.1
* semantics are layered on HTTP/2.
*
* HTTP/2 requires deployments of HTTP/2 that use TLS 1.2 support
* [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256], present in Java 8+ and
* Android 5+. Servers that enforce this may send an exception message including
* the string `INADEQUATE_SECURITY`.
*/
HTTP_2("h2"),
/**
* Cleartext HTTP/2 with no "upgrade" round trip. This option requires the client
* to have prior knowledge that the server supports cleartext HTTP/2.
*
* See also [Starting HTTP/2 with Prior Knowledge][rfc_7540_34].
*
* [rfc_7540_34]: https://tools.ietf.org/html/rfc7540.section-3.4
*/
H2_PRIOR_KNOWLEDGE("h2_prior_knowledge"),
/**
* QUIC (Quick UDP Internet Connection) is a new multiplexed and secure transport
* atop UDP, designed from the ground up and optimized for HTTP/2 semantics.
* HTTP/1.1 semantics are layered on HTTP/2.
*
* QUIC is not natively supported by OkHttp, but provided to allow a theoretical
* interceptor that provides support.
*/
QUIC("quic");
private final String protocol;
Protocol(String protocol) {
this.protocol = protocol;
}
@Override
public String toString() {
return this.protocol;
}
/**
* Builds an enum from string.
*/
@Nullable
public static Protocol fromString(String protocol) {
return Arrays.stream(values())
.filter(p -> p.protocol.equalsIgnoreCase(protocol)).findFirst()
.orElse(null);
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2012-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.http;
/**
* Abstraction over sending and receiving of http messages.
*
* Warning! This API is experimental and can change in time.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface HttpVerifier {
/**
* Sends a request and blocks for the response.
* @param request - HTTP request
* @return HTTP response
*/
Response exchange(Request request);
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright 2012-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.http;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.RequestBody;
import org.jetbrains.annotations.Nullable;
/**
* {@link HttpVerifier} implementation that uses {@link OkHttpClient}.
* Has an inbuilt support for GRPC.
*
* Warning! This API is experimental and can change in time.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OkHttpHttpVerifier implements HttpVerifier {
private final String url;
public OkHttpHttpVerifier(String url) {
this.url = url;
}
@Override
public Response exchange(Request request) {
String requestContentType = request.contentType();
// TODO: Resolve protocol and scheme from contract?
OkHttpClient client = new OkHttpClient.Builder()
.protocols(protocols(requestContentType)).build();
okhttp3.Request req = new okhttp3.Request.Builder()
.url(this.url + (request.path().startsWith("/") ? request.path()
: "/" + request.path()))
.method(request.method().name(), requestBody(request, requestContentType))
.headers(Headers.of(stringTyped(request.headers()))) // TODO: Add cookies
.build();
try (okhttp3.Response res = client.newCall(req).execute()) {
return response(res);
}
catch (IOException e) {
throw new IllegalStateException(e);
}
}
private List<Protocol> protocols(String requestContentType) {
if (this.url.startsWith("https")) {
return Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1);
}
else if (isGrpc(requestContentType)) {
return Collections.singletonList(Protocol.H2_PRIOR_KNOWLEDGE);
}
return Collections.singletonList(Protocol.HTTP_1_1);
}
private Response response(okhttp3.Response res) throws IOException {
byte[] responseBody = responseBody(res);
// String contentType = res.headers().get("Content-Type");
// TODO: Response body in the test / contract should already be properly encoded
// if (contentType != null && isGrpc(contentType) && responseBody != null) {
// responseBody = grpcResponseBody(responseBody);
// }
return Response.builder().body(responseBody).statusCode(res.code())
.headers(withSingleHeader(res))
// TODO: Add cookies
// .cookies(res.headers().values("Set-Cookie").stream().map(s ->
// s.split(";")).flatMap(Arrays::stream).collect(Collectors.toMap(o -> o.
// , e -> e.getValue().get(0), (a,b) -> a, HashMap::new))))
.build();
}
@Nullable
private RequestBody requestBody(Request request, String requestContentType) {
if (request.body() == null) {
return null;
}
byte[] bodyArray = request.body().asByteArray();
return RequestBody.create(MediaType.parse(requestContentType), bodyArray);
}
private boolean isGrpc(String contentType) {
return contentType.startsWith("application/grpc");
}
// the encoded body should already have proper byte values
// TODO: This should be removed?
private byte[] grpcRequestBody(Request request) {
byte[] bodyArray; // TODO: Add compression support
byte compressedFlag = 0;
byte[] message = request.body().asByteArray();
byte[] messageLength = ByteBuffer.allocate(4).putInt(message.length).array();
bodyArray = ByteBuffer.allocate(1 + messageLength.length + message.length)
.put(compressedFlag).put(messageLength).put(message).array();
return bodyArray;
}
// TODO: This should be removed?
private byte[] grpcResponseBody(byte[] responseBody) {
// 5 value = 4th index
// 1 for compression, 4 for message size
int actualPayloadSize = responseBody.length - 5;
byte[] destination = new byte[actualPayloadSize];
System.arraycopy(responseBody, 5, destination, 0, actualPayloadSize);
responseBody = destination;
return responseBody;
}
@Nullable
private byte[] responseBody(okhttp3.Response res) throws IOException {
return res.body() != null ? res.body().bytes() : null;
}
private Map<String, Object> withSingleHeader(okhttp3.Response res) {
return res.headers().toMultimap().entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey, e -> e.getValue().get(0), (a, b) -> a, HashMap::new));
}
private Map<String, String> stringTyped(Map<String, Object> headers) {
return headers.entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString()));
}
}

View File

@@ -0,0 +1,256 @@
/*
* Copyright 2012-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.http;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cloud.contract.spec.internal.HttpMethods;
/**
* Abstraction over a HTTP request.
*
* Warning! This API is experimental and can change in time.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class Request {
private final HttpMethods.HttpMethod method;
private final String path;
private final Body body;
private final Map<String, Object> headers;
private final Map<String, Object> cookies;
Request(HttpMethods.HttpMethod method, String path, Body body,
Map<String, Object> headers, Map<String, Object> cookies) {
this.method = method;
this.path = path;
this.body = body;
this.headers = headers == null ? new HashMap<>() : headers;
this.cookies = cookies == null ? new HashMap<>() : cookies;
}
/**
* @return content type from headers
*/
public String contentType() {
Object value = this.headers.entrySet().stream()
.filter(e -> e.getKey().toLowerCase().equals("content-type")).findFirst()
.orElse(new AbstractMap.SimpleEntry<>("", null)).getValue();
if (value == null) {
return null;
}
return value.toString();
}
/**
* @return HTTP method
*/
public HttpMethods.HttpMethod method() {
return this.method;
}
/**
* @return HTTP path
*/
public String path() {
return this.path;
}
/**
* @return request body
*/
public Body body() {
return this.body;
}
/**
* @return request headers
*/
public Map<String, Object> headers() {
return this.headers;
}
/**
* @return request cookies
*/
public Map<String, Object> cookies() {
return this.cookies;
}
/**
* Factory method to pick the HTTP method.
* @return method builder
*/
public static Request.MethodBuilder given() {
return new Request.MethodBuilder();
}
/**
* Builder over HTTP methods.
*/
public static class MethodBuilder {
/**
* Factory method for DELETE HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder delete(String path) {
return new Request.Builder(HttpMethods.HttpMethod.DELETE, path);
}
/**
* Factory method for GET HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder get(String path) {
return new Request.Builder(HttpMethods.HttpMethod.GET, path);
}
/**
* Factory method for HEAD HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder head(String path) {
return new Request.Builder(HttpMethods.HttpMethod.HEAD, path);
}
/**
* Factory method for OPTIONS HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder options(String path) {
return new Request.Builder(HttpMethods.HttpMethod.OPTIONS, path);
}
/**
* Factory method for PATCH HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder patch(String path) {
return new Request.Builder(HttpMethods.HttpMethod.PATCH, path);
}
/**
* Factory method for POST HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder post(String path) {
return new Request.Builder(HttpMethods.HttpMethod.POST, path);
}
/**
* Factory method for PUT HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder put(String path) {
return new Request.Builder(HttpMethods.HttpMethod.PUT, path);
}
/**
* Factory method for TRACE HTTP method.
* @param path to call
* @return builder
*/
public Request.Builder trace(String path) {
return new Request.Builder(HttpMethods.HttpMethod.TRACE, path);
}
}
/**
* Builder for a {@link Request}.
*/
public static class Builder {
final HttpMethods.HttpMethod method;
final String path;
Body body;
Map<String, Object> headers = new HashMap<>();
Map<String, Object> cookies = new HashMap<>();
Builder(HttpMethods.HttpMethod method, String path) {
this.method = method;
this.path = path;
}
/**
* @param body HTTP body
* @return builder
*/
public Request.Builder body(Object body) {
this.body = new Body(body);
return this;
}
/**
* @param headers HTTP headers
* @return builder
*/
public Request.Builder headers(Map<String, Object> headers) {
this.headers = headers;
return this;
}
/**
* @param key HTTP key
* @param value HTTP value
* @return builder
*/
public Request.Builder header(String key, Object value) {
this.headers.put(key, value);
return this;
}
/**
* @param cookies HTTP cookies
* @return builder
*/
public Request.Builder cookies(Map<String, Object> cookies) {
this.cookies = cookies;
return this;
}
/**
* @return built {@link Request}
*/
public Request build() {
return new Request(this.method, this.path, this.body, this.headers,
this.cookies);
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright 2012-2020 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.http;
import java.util.HashMap;
import java.util.Map;
/**
* Abstraction over a HTTP response.
*
* Warning! This API is experimental and can change in time.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class Response {
private final int statusCode;
private final Body body;
private final Map<String, Object> headers;
private final Map<String, Object> cookies;
Response(int statusCode, Body body, Map<String, Object> headers,
Map<String, Object> cookies) {
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
this.cookies = cookies;
}
/**
* @return numerical representation of a status code
*/
public int statusCode() {
return this.statusCode;
}
/**
* @param key header key
* @return header value or null if not present
*/
public String header(String key) {
return this.headers.entrySet().stream()
.filter(e -> e.getKey().equalsIgnoreCase(key)).findFirst()
.map(e -> e.getValue().toString()).orElse(null);
}
/**
* @param key cookie key
* @return header value or null if not present
*/
public String cookie(String key) {
return this.cookies.entrySet().stream()
.filter(e -> e.getKey().equalsIgnoreCase(key)).findFirst()
.map(e -> e.getValue().toString()).orElse(null);
}
/**
* @return response body
*/
public Body getBody() {
return this.body;
}
/**
* @return builder
*/
public static Response.Builder builder() {
return new Response.Builder();
}
/**
* @return headers
*/
public Map<String, Object> headers() {
return this.headers;
}
/**
* @return cookies
*/
public Map<String, Object> cookies() {
return this.cookies;
}
/**
* Response builder.
*/
public static class Builder {
int statusCode;
Body body;
Map<String, Object> headers = new HashMap<>();
Map<String, Object> cookies = new HashMap<>();
/**
* @param status as int
* @return builder
*/
public Response.Builder statusCode(int status) {
this.statusCode = status;
return this;
}
/**
* @param body - response body
* @return builder
*/
public Response.Builder body(Object body) {
this.body = new Body(body);
return this;
}
/**
* @param headers - response headers
* @return builder
*/
public Response.Builder headers(Map<String, Object> headers) {
this.headers = headers;
return this;
}
/**
* @param key header key
* @param value header value
* @return builder
*/
public Response.Builder header(String key, Object value) {
this.headers.put(key, value);
return this;
}
/**
* @param cookies - response cookies
* @return builder
*/
public Response.Builder cookies(Map<String, Object> cookies) {
this.cookies = cookies;
return this;
}
/**
* @return response
*/
public Response build() {
return new Response(this.statusCode, this.body, this.headers, this.cookies);
}
}
}

View File

@@ -122,6 +122,7 @@ response:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue("#187")
@@ -155,6 +156,7 @@ response:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('#79')
@@ -190,6 +192,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('#79')
@@ -228,6 +231,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('#82')
@@ -263,6 +267,9 @@ response:
"webclient" | {
properties.testMode = TestMode.WEBTESTCLIENT
} | '.body("{\\"items\\":[\\"HOP\\"]}")'
"custom" | {
properties.testMode = TestMode.CUSTOM
} | '.body("{\\"items\\":[\\"HOP\\"]}")'
}
@Issue('#88')
@@ -292,6 +299,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK } | """.body('''property1=VAL1''')"""
"mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '.body("property1=VAL1")'
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } | '.body("property1=VAL1")'
"custom" | { properties.testMode = TestMode.CUSTOM } | '.body("property1=VAL1")'
}
@Issue('185')
@@ -326,6 +334,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
def 'should generate assertions for array in response body with #methodBuilderName'() {
@@ -363,6 +372,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
def 'should generate assertions for array inside response body element with #methodBuilderName'() {
@@ -399,6 +409,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
def 'should generate assertions for nested objects in response body with #methodBuilderName'() {
@@ -432,6 +443,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
def 'should generate regex assertions for map objects in response body with #methodBuilderName'() {
@@ -469,6 +481,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
def "should generate a call with an url path and query parameters with #methodBuilderName"() {
@@ -642,6 +655,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK } | ".body('''''')"
"mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '.body("")'
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } | '.body("")'
"custom" | { properties.testMode = TestMode.CUSTOM } | '.body("")'
}
def 'should generate test for String in response body with #methodBuilderName'() {
@@ -678,6 +692,9 @@ response:
"webclient" | {
properties.testMode = TestMode.WEBTESTCLIENT
} | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");'
"custom" | {
properties.testMode = TestMode.CUSTOM
} | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");'
}
@Issue('113')
@@ -731,6 +748,9 @@ response:
"webclient" | {
properties.testMode = TestMode.WEBTESTCLIENT
} | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");'
"custom" | {
properties.testMode = TestMode.CUSTOM
} | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");'
}
def 'should work with more complex stuff and jsonpaths with #methodBuilderName'() {
@@ -777,6 +797,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('72')
@@ -822,6 +843,9 @@ response:
"webclient" | {
properties.testMode = TestMode.WEBTESTCLIENT
} | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))''']
"custom" | {
properties.testMode = TestMode.CUSTOM
} | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))''']
}
def "shouldn't generate unicode escape characters with #methodBuilderName"() {
@@ -871,6 +895,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('180')
@@ -1188,6 +1213,7 @@ response:
methodBuilderName | methodBuilder
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('262')
@@ -1261,6 +1287,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('266')
@@ -1298,6 +1325,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('266')
@@ -1330,6 +1358,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('47')
@@ -1420,6 +1449,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK }
"mockmvc" | { properties.testMode = TestMode.MOCKMVC }
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('#273')
@@ -1662,6 +1692,9 @@ response:
"webclient" | {
properties.testMode = TestMode.WEBTESTCLIENT
} | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" }
"custom" | {
properties.testMode = TestMode.CUSTOM
} | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" }
}
@Issue('#172')
@@ -1699,6 +1732,7 @@ response:
"spock" | { properties.testFramework = TestFramework.SPOCK } | """responseBody == '''{"a":1}\\n{"a":2}\\n'''"""
"mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}\\n'''
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}\\n'''
"custom" | { properties.testMode = TestMode.CUSTOM } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}\\n'''
}
@Issue('#443')
@@ -1747,6 +1781,9 @@ response:
"jaxrs" | {
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
} | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") }
"custom" | {
properties.testMode = TestMode.CUSTOM
} | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") }
}
@Issue('#169')
@@ -1785,6 +1822,7 @@ response:
methodBuilderName | methodBuilder | expectedAssertion
"spock" | { properties.testFramework = TestFramework.SPOCK } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"'''
"mockmvc" | { properties.testMode = TestMode.MOCKMVC } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}'''
"custom" | { properties.testMode = TestMode.CUSTOM } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}'''
}
@Issue('#169')
@@ -1825,6 +1863,9 @@ response:
"jaxrs" | {
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
}
"custom" | {
properties.testMode = TestMode.CUSTOM
}
}
@Issue('#203')
@@ -1866,6 +1907,7 @@ response:
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
}
"webclient" | { properties.testMode = TestMode.WEBTESTCLIENT }
"custom" | { properties.testMode = TestMode.CUSTOM }
}
@Issue('#226')
@@ -1909,5 +1951,8 @@ response:
"webclient" | {
properties.testMode = TestMode.WEBTESTCLIENT
} | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') }
"custom" | {
properties.testMode = TestMode.CUSTOM
} | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') }
}
}

View File

@@ -46,7 +46,8 @@ class SpringCloudContractRequestMatcherTests {
}
};
MatchResult result = matcher.match(BDDMockito.mock(Request.class), Parameters.one("tool", "foo"));
MatchResult result = matcher.match(BDDMockito.mock(Request.class),
Parameters.one("tool", "foo"));
BDDAssertions.then(result.isExactMatch()).isFalse();
}
@@ -63,7 +64,8 @@ class SpringCloudContractRequestMatcherTests {
}
};
MatchResult result = matcher.match(BDDMockito.mock(Request.class), Parameters.one("contract", "value"));
MatchResult result = matcher.match(BDDMockito.mock(Request.class),
Parameters.one("contract", "value"));
BDDAssertions.then(result.isExactMatch()).isFalse();
}
@@ -80,22 +82,28 @@ class SpringCloudContractRequestMatcherTests {
}
};
MatchResult result = matcher.match(BDDMockito.mock(Request.class), Parameters.one("contract", "value"));
MatchResult result = matcher.match(BDDMockito.mock(Request.class),
Parameters.one("contract", "value"));
BDDAssertions.then(result.isExactMatch()).isFalse();
}
private static final String PROPER_YAML = "---\n" + "request:\n" + " method: \"POST\"\n" + " url: \"/graphql\"\n"
+ " headers:\n" + " Content-Type: \"application/json\"\n" + " body:\n"
private static final String PROPER_YAML = "---\n" + "request:\n"
+ " method: \"POST\"\n" + " url: \"/graphql\"\n" + " headers:\n"
+ " Content-Type: \"application/json\"\n" + " body:\n"
+ " query: \"query queryName($personName: String!) { personToCheck(name: $personName)"
+ " { name age } }\"\n" + " variables:\n" + " personName: \"Old Enough\"\n"
+ " operationName: \"queryName\"\n" + " matchers:\n" + " headers:\n"
+ " - key: \"Content-Type\"\n" + " regex: \"application/json.*\"\n"
+ " regexType: \"as_string\"\n" + "response:\n" + " status: 200\n" + " headers:\n"
+ " Content-Type: \"application/json\"\n" + " body:\n" + " data:\n" + " personToCheck:\n"
+ " name: \"Old Enough\"\n" + " age: \"40\"\n" + " matchers:\n" + " headers:\n"
+ " - key: \"Content-Type\"\n" + " regex: \"application/json.*\"\n"
+ " regexType: \"as_string\"\n" + "name: \"shouldRetrieveOldEnoughPerson\"\n" + "metadata:\n"
+ " { name age } }\"\n" + " variables:\n"
+ " personName: \"Old Enough\"\n" + " operationName: \"queryName\"\n"
+ " matchers:\n" + " headers:\n" + " - key: \"Content-Type\"\n"
+ " regex: \"application/json.*\"\n"
+ " regexType: \"as_string\"\n" + "response:\n" + " status: 200\n"
+ " headers:\n" + " Content-Type: \"application/json\"\n" + " body:\n"
+ " data:\n" + " personToCheck:\n" + " name: \"Old Enough\"\n"
+ " age: \"40\"\n" + " matchers:\n" + " headers:\n"
+ " - key: \"Content-Type\"\n"
+ " regex: \"application/json.*\"\n"
+ " regexType: \"as_string\"\n"
+ "name: \"shouldRetrieveOldEnoughPerson\"\n" + "metadata:\n"
+ " verifier:\n" + " tool: \"graphql\"\n";
@Test
@@ -109,8 +117,8 @@ class SpringCloudContractRequestMatcherTests {
}
};
MatchResult result = matcher.match(BDDMockito.mock(Request.class),
toMap(Tuples.of("tool", "unsupported"), Tuples.of("contract", PROPER_YAML)));
MatchResult result = matcher.match(BDDMockito.mock(Request.class), toMap(
Tuples.of("tool", "unsupported"), Tuples.of("contract", PROPER_YAML)));
BDDAssertions.then(result.isExactMatch()).isFalse();
}
@@ -145,7 +153,8 @@ class SpringCloudContractRequestMatcherTests {
class ApplicableRequestMatcher implements RequestMatcher {
@Override
public MatchResult match(List<YamlContract> contracts, Request request, Parameters parameters) {
public MatchResult match(List<YamlContract> contracts, Request request,
Parameters parameters) {
return MatchResult.of(true);
}