diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml
index b9b880936d..fcb3dc3d79 100644
--- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml
+++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml
@@ -265,6 +265,10 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.springframework
+ spring-jcl
+
org.apache.maven.resolver
diff --git a/spring-cloud-contract-verifier/pom.xml b/spring-cloud-contract-verifier/pom.xml
index 1d30c776b8..cfa99d5d05 100644
--- a/spring-cloud-contract-verifier/pom.xml
+++ b/spring-cloud-contract-verifier/pom.xml
@@ -33,6 +33,11 @@
com.fasterxml.jackson.core
jackson-databind
+
+ com.squareup.okhttp3
+ okhttp
+ true
+
org.springframework
spring-messaging
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java
new file mode 100644
index 0000000000..66f3b7e663
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeAcceptor.java
@@ -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();
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java
new file mode 100644
index 0000000000..af1b53a628
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyGiven.java
@@ -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 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java
new file mode 100644
index 0000000000..621a6d03b2
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeBodyParser.java
@@ -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()";
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java
new file mode 100644
index 0000000000..12ef6734ec
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesGiven.java
@@ -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 apply(SingleContractMetadata metadata) {
+ processInput(metadata.getContract().getRequest());
+ return this;
+ }
+
+ private void processInput(Request request) {
+ Iterator 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java
new file mode 100644
index 0000000000..e6c4a47ba0
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeCookiesThen.java
@@ -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 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java
new file mode 100644
index 0000000000..cd16ebb3e3
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeFields.java
@@ -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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java
new file mode 100644
index 0000000000..ee6bf48658
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeGiven.java
@@ -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 requestGivens = new LinkedList<>();
+
+ private final List 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 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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java
new file mode 100644
index 0000000000..2e3f40841f
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersGiven.java
@@ -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 apply(SingleContractMetadata metadata) {
+ processInput(this.blockBuilder, metadata.getContract().getRequest().getHeaders());
+ return this;
+ }
+
+ private void processInput(BlockBuilder bb, Headers headers) {
+ Iterator 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java
new file mode 100644
index 0000000000..8785876388
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeHeadersThen.java
@@ -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 apply(SingleContractMetadata metadata) {
+ Response response = metadata.getContract().getResponse();
+ Headers headers = response.getHeaders();
+ Iterator 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java
new file mode 100644
index 0000000000..f61f9d4bb4
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeImports.java
@@ -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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java
new file mode 100644
index 0000000000..0a02fbafef
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeMethodWithUrlGiven.java
@@ -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 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java
new file mode 100644
index 0000000000..6118d01e45
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestBuildGiven.java
@@ -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 apply(SingleContractMetadata metadata) {
+ this.blockBuilder.addLineWithEnding(".build()");
+ return this;
+ }
+
+ @Override
+ public boolean accept(SingleContractMetadata metadata) {
+ Request request = metadata.getContract().getRequest();
+ return request != null;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java
new file mode 100644
index 0000000000..d3e899d82c
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeRequestGiven.java
@@ -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 apply(SingleContractMetadata metadata) {
+ this.blockBuilder.addIndented("Request request = given()");
+ return this;
+ }
+
+ @Override
+ public boolean accept(SingleContractMetadata metadata) {
+ return acceptType(this.generatedClassMetaData);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java
new file mode 100644
index 0000000000..533ba64b22
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeResponseWhen.java
@@ -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 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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java
new file mode 100644
index 0000000000..d1621006b6
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStaticImports.java
@@ -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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java
new file mode 100644
index 0000000000..01100378ee
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeStatusCodeThen.java
@@ -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 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java
new file mode 100644
index 0000000000..5270e54355
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeThen.java
@@ -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 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 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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java
new file mode 100644
index 0000000000..4ffa7670ca
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomModeWhen.java
@@ -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 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 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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java
new file mode 100644
index 0000000000..79289da7ca
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomMultipartGiven.java
@@ -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 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);
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomQueryParamsGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomQueryParamsGiven.java
new file mode 100644
index 0000000000..baa39ff651
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomQueryParamsGiven.java
@@ -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 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;
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java
index 19d3a34b6d..d597e8f136 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/FieldBuilder.java
@@ -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;
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java
index 2e5c529306..9a9b405008 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/ImportsBuilder.java
@@ -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;
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java
similarity index 74%
rename from spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcMultipartGiven.java
rename to spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java
index 0bd899c547..95ebeebd67 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/MockMvcMultipartGiven.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaMultipartGiven.java
@@ -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 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 parameter) {
+ private String getMultipartParameterLine(SingleContractMetadata metadata,
+ Map.Entry 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 getMultipartParameters(SingleContractMetadata metadata) {
- return (Map) metadata.getContract().getRequest().getMultipart().getServerValue();
+ return (Map) 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 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;
}
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java
index e1f2241de0..175ef46959 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.java
@@ -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
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java
new file mode 100644
index 0000000000..c2b822fdcf
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredAcceptor.java
@@ -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();
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java
index b9aec10638..8c38aba630 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredCookiesThen.java
@@ -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;
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java
index 3d6d19de8a..ef9982909b 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredGiven.java
@@ -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 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);
}
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java
index 6485ad8ac5..659ac65d77 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredHeadersThen.java
@@ -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;
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java
index e0ecf8e7cb..f51095f98f 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredThen.java
@@ -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 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);
}
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java
index 2699cc00e2..77b19ec439 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/RestAssuredWhen.java
@@ -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 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);
}
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java
index 0bd7e13258..c9321feb89 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SingleMethodBuilder.java
@@ -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))
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java
index 48f69c30ad..42a40ca4cf 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/SpockMockMvcMultipartGiven.java
@@ -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 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 parameter) {
+ private String getMultipartParameterLine(SingleContractMetadata metadata,
+ Map.Entry 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 getMultipartParameters(SingleContractMetadata metadata) {
- return (Map) metadata.getContract().getRequest().getMultipart().getServerValue();
+ return (Map) 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 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;
}
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java
similarity index 90%
rename from spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomImports.java
rename to spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java
index 00b6cf51b9..4ecea6f427 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomImports.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserImports.java
@@ -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;
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomStaticImports.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java
similarity index 84%
rename from spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomStaticImports.java
rename to spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java
index 380346d421..be09b2fd11 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/CustomStaticImports.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/UserStaticImports.java
@@ -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;
}
}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/BaseImportProvider.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/BaseImportProvider.java
deleted file mode 100644
index caa5edd83b..0000000000
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/BaseImportProvider.java
+++ /dev/null
@@ -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 RULE_IMPORT;
-
- private static final Map 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 getImports(TestFramework testFramework) {
- List 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 getStaticImports(TestFramework testFramework) {
- List 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);
- }
-
-}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.java
deleted file mode 100644
index 7a22ef3714..0000000000
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.java
+++ /dev/null
@@ -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, ImportDefinitions> FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS;
-
- private final Map 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 getImports(TestFramework testFramework, TestMode testMode) {
- List 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 getStaticImports(TestFramework testFramework, TestMode testMode) {
- List 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;
- }
-
-}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/ImportDefinitions.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/ImportDefinitions.java
deleted file mode 100644
index 6f5c202190..0000000000
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/ImportDefinitions.java
+++ /dev/null
@@ -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 imports;
-
- private final List staticImports;
-
- public ImportDefinitions(List imports, List staticImports) {
- this.imports = imports;
- this.staticImports = staticImports;
- }
-
- public ImportDefinitions(List imports) {
- this(imports, new ArrayList<>());
- }
-
- public final List getImports() {
- return imports;
- }
-
- public final List getStaticImports() {
- return staticImports;
- }
-
-}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.java
deleted file mode 100644
index c13ff3df23..0000000000
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.java
+++ /dev/null
@@ -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 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 getStaticImports() {
- return Arrays.asList(
- "org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers",
- "org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes");
- }
-
-}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java
index 073869c4e2..6cb03a421f 100644
--- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/config/TestMode.java
@@ -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.
*/
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java
new file mode 100644
index 0000000000..f4c6a3fde1
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Body.java
@@ -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();
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetadata.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetadata.java
new file mode 100644
index 0000000000..57e37e813d
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/ContractVerifierHttpMetadata.java
@@ -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 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);
+ }
+
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java
new file mode 100644
index 0000000000..391f5bb8d5
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/HttpVerifier.java
@@ -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);
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java
new file mode 100644
index 0000000000..2ff34ec0ae
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/OkHttpHttpVerifier.java
@@ -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 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 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 stringTyped(Map headers) {
+ return headers.entrySet().stream().collect(
+ Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString()));
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java
new file mode 100644
index 0000000000..560bb46145
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Request.java
@@ -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 headers;
+
+ private final Map cookies;
+
+ Request(HttpMethods.HttpMethod method, String path, Body body,
+ Map headers, Map 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 headers() {
+ return this.headers;
+ }
+
+ /**
+ * @return request cookies
+ */
+ public Map 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 headers = new HashMap<>();
+
+ Map 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 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 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);
+ }
+
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java
new file mode 100644
index 0000000000..d368b45497
--- /dev/null
+++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/http/Response.java
@@ -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 headers;
+
+ private final Map cookies;
+
+ Response(int statusCode, Body body, Map headers,
+ Map 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 headers() {
+ return this.headers;
+ }
+
+ /**
+ * @return cookies
+ */
+ public Map cookies() {
+ return this.cookies;
+ }
+
+ /**
+ * Response builder.
+ */
+ public static class Builder {
+
+ int statusCode;
+
+ Body body;
+
+ Map headers = new HashMap<>();
+
+ Map 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 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 cookies) {
+ this.cookies = cookies;
+ return this;
+ }
+
+ /**
+ * @return response
+ */
+ public Response build() {
+ return new Response(this.statusCode, this.body, this.headers, this.cookies);
+ }
+
+ }
+
+}
diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy
index 7007324aee..61a42632c4 100644
--- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy
+++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy
@@ -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");') }
}
}
diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java
index 3151fd723b..d9837add2a 100644
--- a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java
+++ b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/dsl/wiremock/SpringCloudContractRequestMatcherTests.java
@@ -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 contracts, Request request, Parameters parameters) {
+ public MatchResult match(List contracts, Request request,
+ Parameters parameters) {
return MatchResult.of(true);
}