Convert from groovy to java (#1482)

This commit is contained in:
Anatolii Zhmaiev
2020-08-26 14:43:53 +03:00
committed by GitHub
parent 00d6154c60
commit 3f90880cbb
8 changed files with 677 additions and 478 deletions

View File

@@ -1,117 +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.dsl.wiremock
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder
import com.github.tomakehurst.wiremock.extension.Extension
import com.github.tomakehurst.wiremock.http.HttpHeader
import com.github.tomakehurst.wiremock.http.HttpHeaders
import com.github.tomakehurst.wiremock.http.ResponseDefinition
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.FromFileProperty
import org.springframework.cloud.contract.spec.internal.Request
import org.springframework.cloud.contract.spec.internal.Response
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata
import org.springframework.cloud.contract.verifier.util.ContentType
import org.springframework.cloud.contract.verifier.util.MapConverter
import org.springframework.core.io.support.SpringFactoriesLoader
/**
* Converts a {@link Request} into {@link ResponseDefinition}
*
* @author Marcin Grzejszczak
* @author Olga Maciaszek-Sharma
*
* @since 1.0.0
*/
@TypeChecked
@PackageScope
class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
private final Response response
private final ContentType contentType
WireMockResponseStubStrategy(Contract groovyDsl, SingleContractMetadata singleContractMetadata) {
super(groovyDsl)
this.response = groovyDsl.response
this.contentType = contentType(singleContractMetadata)
}
protected ContentType contentType(SingleContractMetadata singleContractMetadata) {
return singleContractMetadata.evaluatedOutputStubContentType
}
@PackageScope
ResponseDefinition buildClientResponseContent() {
if (!response) {
return null
}
ResponseDefinitionBuilder builder = new ResponseDefinitionBuilder()
.withStatus(MapConverter.getStubSideValues(response.status) as Integer)
appendHeaders(builder)
appendBody(builder)
appendResponseDelayTime(builder)
builder.withTransformers(responseTransformerNames())
return builder.build()
}
private String[] responseTransformerNames() {
List<WireMockExtensions> wireMockExtensions = SpringFactoriesLoader.
loadFactories(WireMockExtensions, null)
if (wireMockExtensions) {
return ((List<Extension>) wireMockExtensions
.collect { WireMockExtensions extension -> extension.extensions() }
.flatten())
.collect { Extension e -> e.getName() } as String[]
}
return [new DefaultResponseTransformer().getName()] as String[]
}
private void appendHeaders(ResponseDefinitionBuilder builder) {
if (response.headers) {
builder.withHeaders(new HttpHeaders(response.headers.entries?.collect {
new HttpHeader(it.name, MapConverter.getStubSideValues(it.clientValue).
toString())
}))
}
}
private void appendBody(ResponseDefinitionBuilder builder) {
if (response.body) {
Object body = MapConverter.getStubSideValues(response.body)
if (body instanceof byte[]) {
builder.withBody(body)
}
else if (body instanceof FromFileProperty && body.isByte()) {
builder.withBody(body.asBytes())
}
else {
builder.withBody(parseBody(body, contentType))
}
}
}
private void appendResponseDelayTime(ResponseDefinitionBuilder builder) {
// TODO: Add a missing test for this
if (response.delay) {
builder.withFixedDelay(response.delay.clientValue as Integer)
}
}
}

View File

@@ -1,85 +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.dsl.wiremock
import com.github.tomakehurst.wiremock.http.ResponseDefinition
import com.github.tomakehurst.wiremock.matching.RequestPattern
import com.github.tomakehurst.wiremock.stubbing.StubMapping
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata
/**
* Converts a {@link ContractMetadata} into a WireMock stub
*
* @since 1.0.0
*/
class WireMockStubStrategy {
private static final String STEP_START = "Started"
private static final String STEP_PREFIX = "Step"
private final WireMockRequestStubStrategy wireMockRequestStubStrategy
private final WireMockResponseStubStrategy wireMockResponseStubStrategy
private final Integer priority
private final ContractMetadata contract
private final String rootName
private final Contract groovyDsl
WireMockStubStrategy(String rootName, ContractMetadata contract, Contract groovyDsl) {
this.rootName = rootName
this.contract = contract
SingleContractMetadata singleContractMetadata = contract.forContract(groovyDsl)
this.wireMockRequestStubStrategy = new WireMockRequestStubStrategy(groovyDsl, singleContractMetadata)
this.wireMockResponseStubStrategy = new WireMockResponseStubStrategy(groovyDsl, singleContractMetadata)
this.priority = groovyDsl.priority
this.groovyDsl = groovyDsl
}
/**
* Converts {@link ContractMetadata} to {@link StubMapping}
*/
StubMapping toWireMockClientStub() {
StubMapping stubMapping = new StubMapping()
RequestPattern request = wireMockRequestStubStrategy.buildClientRequestContent()
ResponseDefinition response = wireMockResponseStubStrategy.
buildClientResponseContent()
if (priority) {
stubMapping.priority = priority
}
stubMapping.request = request
stubMapping.response = response
if (!request || !response) {
return null
}
if (groovyDsl.ignored || contract.ignored) {
return null
}
if (contract.order != null) {
stubMapping.scenarioName = "Scenario_" + rootName
stubMapping.requiredScenarioState = contract.order == 0 ? STEP_START : STEP_PREFIX + contract.order
if (contract.order < contract.groupSize - 1) {
stubMapping.newScenarioState = STEP_PREFIX + (contract.order + 1)
}
}
return stubMapping
}
}

View File

@@ -1,260 +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.file
import java.nio.file.Path
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.internal.Header
import org.springframework.cloud.contract.spec.internal.Headers
import org.springframework.cloud.contract.verifier.util.ContentType
import org.springframework.cloud.contract.verifier.util.ContentUtils
import org.springframework.cloud.contract.verifier.util.NamesUtil
import org.springframework.util.Assert
/**
* Contains metadata for a particular file with a DSL
*
* @author Jakub Kubrynski, codearte.io
*
* @since 1.0.0
*/
@CompileStatic
class ContractMetadata {
/**
* Path to the file
*/
final Path path
/**
* Should the contract be ignored
*/
final boolean ignored
/**
* How many files are there in the folder
*/
final int groupSize
/**
* If scenario related will contain an order of execution
*/
final Integer order
/**
* The list of contracts for the given file
*/
final Collection<Contract> convertedContract = []
/**
* Converted contracts with meta data information
*/
final Collection<SingleContractMetadata> convertedContractWithMetadata = []
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Contract convertedContract) {
this(path, ignored, groupSize, order, [convertedContract])
}
ContractMetadata(Path path, boolean ignored, int groupSize, Integer order, Collection<Contract> convertedContract) {
this.groupSize = groupSize
this.path = path
this.ignored = ignored
this.order = order
this.convertedContract.addAll(convertedContract)
this.convertedContractWithMetadata.addAll(
this.convertedContract
.findAll { it != null }
.collect { new SingleContractMetadata(it, this) })
}
SingleContractMetadata forContract(Contract contract) {
return this.convertedContractWithMetadata
.find { it.contract == contract }
}
boolean anyInProgress() {
return this.convertedContract.any { it.inProgress }
}
}
@CompileStatic
@EqualsAndHashCode(excludes = ["contractMetadata"])
@ToString(excludes = ["contractMetadata"])
class SingleContractMetadata {
private static final Log log = LogFactory.getLog(SingleContractMetadata)
final ContractMetadata contractMetadata
private final File stubsFile
final Contract contract
private final Collection<Contract> allContracts
final String definedInputStubContentType
final ContentType inputStubContentType
final ContentType evaluatedInputStubContentType
final String definedOutputStubContentType
final ContentType outputStubContentType
final ContentType evaluatedOutputStubContentType
final String definedInputTestContentType
final ContentType inputTestContentType
final ContentType evaluatedInputTestContentType
final String definedOutputTestContentType
final ContentType outputTestContentType
final ContentType evaluatedOutputTestContentType
String methodName
private final boolean http
SingleContractMetadata(Contract currentContract, ContractMetadata contractMetadata) {
this.allContracts = contractMetadata.convertedContract
this.contract = currentContract
Assert.notNull(currentContract, "Contract must not be null")
Headers inputHeaders = inputHeaders(currentContract)
DslProperty inputBody = inputBody(currentContract)
Headers outputHeaders = outputHeaders(currentContract)
DslProperty outputBody = outputBody(currentContract)
Header inputContentType = contentTypeHeader(inputHeaders)
Header outputContentType = contentTypeHeader(outputHeaders)
this.definedInputTestContentType = inputContentType != null ? inputContentType.getServerValue() : ""
this.evaluatedInputTestContentType = tryToEvaluateTestContentType(inputHeaders, inputBody)
this.inputTestContentType = inputBody != null ? this.evaluatedInputTestContentType : ContentType.UNKNOWN
this.definedOutputTestContentType = outputContentType != null ? outputContentType.getServerValue() : ""
this.evaluatedOutputTestContentType = tryToEvaluateTestContentType(outputHeaders, outputBody)
this.outputTestContentType = outputBody != null ? this.evaluatedOutputTestContentType : ContentType.UNKNOWN
this.definedInputStubContentType = inputContentType != null ? inputContentType.getClientValue() : ""
this.evaluatedInputStubContentType = tryToEvaluateStubContentType(inputHeaders, inputBody)
this.inputStubContentType = inputBody != null ? this.evaluatedInputStubContentType : ContentType.UNKNOWN
this.definedOutputStubContentType = outputContentType != null ? outputContentType.getClientValue() : ""
this.evaluatedOutputStubContentType = tryToEvaluateStubContentType(outputHeaders, outputBody)
this.outputStubContentType = outputBody != null ? this.evaluatedOutputStubContentType : ContentType.UNKNOWN
this.http = currentContract.request != null
this.contractMetadata = contractMetadata
this.stubsFile = contractMetadata.getPath() != null ? contractMetadata.getPath().toFile() : null
}
private Header contentTypeHeader(Headers headers) {
return headers == null ? null : headers.getEntries().stream()
.filter({ header -> "Content-Type".equalsIgnoreCase(header.getName()) })
.findFirst().orElse(null)
}
private ContentType tryToEvaluateStubContentType(Headers mainHeaders, DslProperty body) {
ContentType contentType = ContentUtils.evaluateClientSideContentType(mainHeaders, body?.getClientValue())
if (contentType == ContentType.DEFINED || contentType == ContentType.UNKNOWN) {
// try to retrieve from the other side (e.g. stub side was a regex, but test side is concrete)
return ContentUtils.evaluateServerSideContentType(mainHeaders, body?.getServerValue())
}
return contentType
}
private ContentType tryToEvaluateTestContentType(Headers mainHeaders, DslProperty body) {
ContentType contentType = ContentUtils.evaluateClientSideContentType(mainHeaders, body?.getServerValue())
if (contentType == ContentType.DEFINED || contentType == ContentType.UNKNOWN) {
// try to retrieve from the other side (e.g. stub side was a regex, but test side is concrete)
return ContentUtils.evaluateServerSideContentType(mainHeaders, body?.getClientValue())
}
return contentType
}
boolean isJson() {
return this.inputTestContentType == ContentType.JSON ||
this.outputTestContentType == ContentType.JSON ||
this.inputStubContentType == ContentType.JSON ||
this.outputStubContentType == ContentType.JSON
}
boolean evaluatesToJson() {
return isJson() || this.evaluatedInputTestContentType == ContentType.JSON ||
this.evaluatedOutputTestContentType == ContentType.JSON ||
this.evaluatedInputStubContentType == ContentType.JSON ||
this.evaluatedOutputStubContentType == ContentType.JSON
}
boolean isIgnored() {
return this.contract.ignored || this.contractMetadata.ignored
}
boolean isXml() {
return this.inputTestContentType == ContentType.XML ||
this.outputTestContentType == ContentType.XML ||
this.inputStubContentType == ContentType.XML ||
this.outputStubContentType == ContentType.XML
}
boolean isHttp() {
return this.http
}
boolean isInProgress() {
return this.contract.isInProgress()
}
boolean isMessaging() {
return !isHttp()
}
private DslProperty inputBody(Contract contract) {
return contract.request?.body ?: contract.input?.messageBody
}
private Headers inputHeaders(Contract contract) {
return contract.request?.headers ?: contract.input?.messageHeaders
}
private DslProperty outputBody(Contract contract) {
return contract.response?.body ?: contract.outputMessage?.body
}
private Headers outputHeaders(Contract contract) {
return contract.response?.headers ?: contract.outputMessage?.headers
}
String methodName() {
if (this.methodName == null) {
this.methodName = calculateMethodName()
}
return this.methodName
}
private String calculateMethodName() {
if (contract.name) {
String name = NamesUtil.
camelCase(NamesUtil.convertIllegalPackageChars(contract.name))
if (log.isDebugEnabled()) {
log.debug("Overriding the default test name with [" + name + "]")
}
return name
}
else if (allContracts.size() > 1) {
int index = allContracts.findIndexOf { it == contract }
String name = "${camelCasedMethodFromFileName(stubsFile)}_${index}"
if (log.isDebugEnabled()) {
log.debug("Scenario found. The method name will be [" + name + "]")
}
return name
}
String name = camelCasedMethodFromFileName(stubsFile)
if (log.isDebugEnabled()) {
log.debug("The method name will be [" + name + "]")
}
return name
}
private static String camelCasedMethodFromFileName(File stubsFile) {
return NamesUtil.camelCase(NamesUtil.convertIllegalMethodNameChars(NamesUtil.
toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator))))
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.dsl.wiremock;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
import com.github.tomakehurst.wiremock.extension.Extension;
import com.github.tomakehurst.wiremock.http.HttpHeader;
import com.github.tomakehurst.wiremock.http.HttpHeaders;
import com.github.tomakehurst.wiremock.http.ResponseDefinition;
import groovy.lang.GString;
import org.springframework.cloud.contract.spec.Contract;
import org.springframework.cloud.contract.spec.internal.FromFileProperty;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
import org.springframework.cloud.contract.verifier.util.ContentType;
import org.springframework.cloud.contract.verifier.util.MapConverter;
import org.springframework.core.io.support.SpringFactoriesLoader;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
/**
* Converts a {@link Request} into {@link ResponseDefinition}.
*
* @author Marcin Grzejszczak
* @author Olga Maciaszek-Sharma
* @since 1.0.0
*/
class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
private final Response response;
private final ContentType contentType;
WireMockResponseStubStrategy(Contract groovyDsl,
SingleContractMetadata singleContractMetadata) {
super(groovyDsl);
this.response = groovyDsl.getResponse();
this.contentType = contentType(singleContractMetadata);
}
protected ContentType contentType(SingleContractMetadata singleContractMetadata) {
return singleContractMetadata.getEvaluatedOutputStubContentType();
}
ResponseDefinition buildClientResponseContent() {
if (response == null) {
return null;
}
ResponseDefinitionBuilder builder = new ResponseDefinitionBuilder().withStatus(
(Integer) MapConverter.getStubSideValues(response.getStatus()));
appendHeaders(builder);
appendBody(builder);
appendResponseDelayTime(builder);
builder.withTransformers(responseTransformerNames());
return builder.build();
}
private String[] responseTransformerNames() {
List<WireMockExtensions> wireMockExtensions = SpringFactoriesLoader
.loadFactories(WireMockExtensions.class, null);
if (!wireMockExtensions.isEmpty()) {
return wireMockExtensions.stream().map(WireMockExtensions::extensions)
.flatMap(Collection::stream).map(Extension::getName)
.toArray(String[]::new);
}
return new String[] { new DefaultResponseTransformer().getName() };
}
private void appendHeaders(ResponseDefinitionBuilder builder) {
if (response.getHeaders() != null) {
HttpHeaders headers = response.getHeaders().getEntries().stream()
.map(it -> new HttpHeader(it.getName(),
MapConverter.getStubSideValues(it.getClientValue())
.toString()))
.collect(collectingAndThen(toList(), HttpHeaders::new));
builder.withHeaders(headers);
}
}
private void appendBody(ResponseDefinitionBuilder builder) {
if (response.getBody() != null) {
Object body = MapConverter.getStubSideValues(response.getBody());
if (body instanceof byte[]) {
builder.withBody((byte[]) body);
}
else if (body instanceof FromFileProperty
&& ((FromFileProperty) body).isByte()) {
builder.withBody(((FromFileProperty) body).asBytes());
}
else if (body instanceof Map) {
builder.withBody(parseBody((Map<?, ?>) body, contentType));
}
else if (body instanceof List) {
builder.withBody(parseBody((List<?>) body, contentType));
}
else if (body instanceof GString) {
builder.withBody(parseBody((GString) body, contentType));
}
else {
builder.withBody(parseBody(body, contentType));
}
}
}
private void appendResponseDelayTime(ResponseDefinitionBuilder builder) {
// TODO: Add a missing test for this
if (response.getDelay() != null) {
builder.withFixedDelay((Integer) response.getDelay().getClientValue());
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.dsl.wiremock;
import com.github.tomakehurst.wiremock.http.ResponseDefinition;
import com.github.tomakehurst.wiremock.matching.RequestPattern;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import org.springframework.cloud.contract.spec.Contract;
import org.springframework.cloud.contract.verifier.file.ContractMetadata;
import org.springframework.cloud.contract.verifier.file.SingleContractMetadata;
/**
* Converts a {@link ContractMetadata} into a WireMock {@link StubMapping}.
*
* @since 1.0.0
*/
public class WireMockStubStrategy {
private static final String STEP_START = "Started";
private static final String STEP_PREFIX = "Step";
private final WireMockRequestStubStrategy wireMockRequestStubStrategy;
private final WireMockResponseStubStrategy wireMockResponseStubStrategy;
private final Integer priority;
private final ContractMetadata contract;
private final String rootName;
private final Contract groovyDsl;
public WireMockStubStrategy(String rootName, ContractMetadata contract,
Contract groovyDsl) {
this.rootName = rootName;
this.contract = contract;
SingleContractMetadata singleContractMetadata = contract.forContract(groovyDsl);
this.wireMockRequestStubStrategy = new WireMockRequestStubStrategy(groovyDsl,
singleContractMetadata);
this.wireMockResponseStubStrategy = new WireMockResponseStubStrategy(groovyDsl,
singleContractMetadata);
this.priority = groovyDsl.getPriority();
this.groovyDsl = groovyDsl;
}
/**
* Converts {@link ContractMetadata} to {@link StubMapping}.
*/
public StubMapping toWireMockClientStub() {
StubMapping stubMapping = new StubMapping();
RequestPattern request = wireMockRequestStubStrategy.buildClientRequestContent();
ResponseDefinition response = wireMockResponseStubStrategy
.buildClientResponseContent();
if (priority != null) {
stubMapping.setPriority(priority);
}
stubMapping.setRequest(request);
stubMapping.setResponse(response);
if (request == null || response == null) {
return null;
}
if (groovyDsl.getIgnored() || contract.getIgnored()) {
return null;
}
if (contract.getOrder() != null) {
stubMapping.setScenarioName("Scenario_" + rootName);
stubMapping.setRequiredScenarioState(contract.getOrder() == 0 ? STEP_START
: STEP_PREFIX + contract.getOrder());
if (contract.getOrder() < contract.getGroupSize() - 1) {
stubMapping.setNewScenarioState(STEP_PREFIX + (contract.getOrder() + 1));
}
}
return stubMapping;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* 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.
@@ -14,30 +14,28 @@
* limitations under the License.
*/
package org.springframework.cloud.contract.verifier.dsl.wiremock
package org.springframework.cloud.contract.verifier.dsl.wiremock;
import com.github.tomakehurst.wiremock.client.WireMock
import com.github.tomakehurst.wiremock.matching.StringValuePattern
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
import org.springframework.cloud.contract.spec.internal.MatchingType
import static org.springframework.cloud.contract.spec.internal.MatchingType.EQUALITY
import org.springframework.cloud.contract.spec.internal.MatchingType;
/**
* @author Olga Maciaszek-Sharma
* @since 2.1.0
*/
@CompileStatic
@PackageScope
class XPathBodyMatcherToWireMockValuePatternConverter {
final class XPathBodyMatcherToWireMockValuePatternConverter {
static StringValuePattern mapToPattern(MatchingType type, String value) {
switch (type) {
case EQUALITY: return WireMock.equalTo(value)
default: return WireMock.matching(value)
private XPathBodyMatcherToWireMockValuePatternConverter() {
throw new IllegalStateException("Can't instantiate an utility class");
}
public static StringValuePattern mapToPattern(MatchingType type, String value) {
if (type == MatchingType.EQUALITY) {
return WireMock.equalTo(value);
}
return WireMock.matching(value);
}
}

View File

@@ -0,0 +1,122 @@
/*
* 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.file;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import org.springframework.cloud.contract.spec.Contract;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
/**
* Contains metadata for a particular file with a DSL.
*
* @author Jakub Kubrynski, codearte.io
* @since 1.0.0
*/
public class ContractMetadata {
/**
* Path to the file.
*/
private final Path path;
/**
* Should the contract be ignored.
*/
private final boolean ignored;
/**
* How many files are there in the folder.
*/
private final int groupSize;
/**
* If scenario related will contain an order of execution.
*/
private final Integer order;
/**
* The list of contracts for the given file.
*/
private final List<Contract> convertedContract = new ArrayList<>();
/**
* Converted contracts with meta data information.
*/
private final Collection<SingleContractMetadata> convertedContractWithMetadata = new ArrayList<>();
public ContractMetadata(Path path, boolean ignored, int groupSize, Integer order,
Contract convertedContract) {
this(path, ignored, groupSize, order, singletonList(convertedContract));
}
public ContractMetadata(Path path, boolean ignored, int groupSize, Integer order,
Collection<Contract> convertedContract) {
this.groupSize = groupSize;
this.path = path;
this.ignored = ignored;
this.order = order;
this.convertedContract.addAll(convertedContract);
this.convertedContractWithMetadata.addAll(this.convertedContract.stream()
.filter(Objects::nonNull).map(it -> new SingleContractMetadata(it, this))
.collect(toList()));
}
public SingleContractMetadata forContract(Contract contract) {
return this.convertedContractWithMetadata.stream()
.filter(it -> it.getContract().equals(contract)).findFirst().orElse(null);
}
public boolean anyInProgress() {
return this.convertedContract.stream().anyMatch(Contract::getInProgress);
}
public Path getPath() {
return path;
}
public boolean getIgnored() {
return ignored;
}
public boolean isIgnored() {
return ignored;
}
public int getGroupSize() {
return groupSize;
}
public Integer getOrder() {
return order;
}
public List<Contract> getConvertedContract() {
return convertedContract;
}
public Collection<SingleContractMetadata> getConvertedContractWithMetadata() {
return convertedContractWithMetadata;
}
}

View File

@@ -0,0 +1,315 @@
/*
* 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.file;
import java.io.File;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.contract.spec.Contract;
import org.springframework.cloud.contract.spec.internal.DslProperty;
import org.springframework.cloud.contract.spec.internal.Header;
import org.springframework.cloud.contract.spec.internal.Headers;
import org.springframework.cloud.contract.spec.internal.Input;
import org.springframework.cloud.contract.spec.internal.OutputMessage;
import org.springframework.cloud.contract.spec.internal.Request;
import org.springframework.cloud.contract.spec.internal.Response;
import org.springframework.cloud.contract.verifier.util.ContentType;
import org.springframework.util.Assert;
import static org.springframework.cloud.contract.verifier.util.ContentType.DEFINED;
import static org.springframework.cloud.contract.verifier.util.ContentType.JSON;
import static org.springframework.cloud.contract.verifier.util.ContentType.UNKNOWN;
import static org.springframework.cloud.contract.verifier.util.ContentType.XML;
import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateClientSideContentType;
import static org.springframework.cloud.contract.verifier.util.ContentUtils.evaluateServerSideContentType;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.afterLast;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.camelCase;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalMethodNameChars;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.isEmpty;
import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot;
public class SingleContractMetadata {
private static final Logger log = LoggerFactory
.getLogger(SingleContractMetadata.class);
private final ContractMetadata contractMetadata;
private final Path stubsPath;
private final Contract contract;
private final List<Contract> allContracts;
private final String definedInputStubContentType;
private final ContentType inputStubContentType;
private final ContentType evaluatedInputStubContentType;
private final String definedOutputStubContentType;
private final ContentType outputStubContentType;
private final ContentType evaluatedOutputStubContentType;
private final String definedInputTestContentType;
private final ContentType inputTestContentType;
private final ContentType evaluatedInputTestContentType;
private final String definedOutputTestContentType;
private final ContentType outputTestContentType;
private final ContentType evaluatedOutputTestContentType;
private String methodName;
private final boolean http;
public SingleContractMetadata(Contract currentContract,
ContractMetadata contractMetadata) {
Assert.notNull(currentContract, "Contract must not be null");
this.allContracts = contractMetadata.getConvertedContract();
this.contract = currentContract;
this.contractMetadata = contractMetadata;
Headers inputHeaders = inputHeaders(currentContract);
DslProperty<?> inputBody = inputBody(currentContract);
Headers outputHeaders = outputHeaders(currentContract);
DslProperty<?> outputBody = outputBody(currentContract);
Header inputContentType = contentTypeHeader(inputHeaders);
Header outputContentType = contentTypeHeader(outputHeaders);
this.definedInputTestContentType = Optional.ofNullable(inputContentType)
.map(DslProperty::getServerValue).map(Object::toString).orElse("");
this.evaluatedInputTestContentType = tryToEvaluateTestContentType(inputHeaders,
inputBody);
this.inputTestContentType = inputBody != null ? this.evaluatedInputTestContentType
: UNKNOWN;
this.definedOutputTestContentType = Optional.ofNullable(outputContentType)
.map(DslProperty::getServerValue).map(Object::toString).orElse("");
this.evaluatedOutputTestContentType = tryToEvaluateTestContentType(outputHeaders,
outputBody);
this.outputTestContentType = outputBody != null
? this.evaluatedOutputTestContentType : UNKNOWN;
this.definedInputStubContentType = Optional.ofNullable(inputContentType)
.map(DslProperty::getClientValue).map(Object::toString).orElse("");
this.evaluatedInputStubContentType = tryToEvaluateStubContentType(inputHeaders,
inputBody);
this.inputStubContentType = inputBody != null ? this.evaluatedInputStubContentType
: UNKNOWN;
this.definedOutputStubContentType = Optional.ofNullable(outputContentType)
.map(DslProperty::getClientValue).map(Object::toString).orElse("");
this.evaluatedOutputStubContentType = tryToEvaluateStubContentType(outputHeaders,
outputBody);
this.outputStubContentType = outputBody != null
? this.evaluatedOutputStubContentType : UNKNOWN;
this.http = currentContract.getRequest() != null;
this.stubsPath = contractMetadata.getPath();
}
private Header contentTypeHeader(Headers headers) {
return headers == null ? null
: headers.getEntries().stream()
.filter(it -> "Content-Type".equalsIgnoreCase(it.getName()))
.findFirst().orElse(null);
}
private ContentType tryToEvaluateStubContentType(Headers mainHeaders,
DslProperty<?> body) {
Object clientValue = Optional.ofNullable(body).map(DslProperty::getClientValue)
.orElse(null);
ContentType contentType = evaluateClientSideContentType(mainHeaders, clientValue);
if (contentType == DEFINED || contentType == UNKNOWN) {
// try to retrieve from the other side (e.g. stub side was a regex, but test
// side is concrete)
Object serverValue = Optional.ofNullable(body)
.map(DslProperty::getServerValue).orElse(null);
return evaluateServerSideContentType(mainHeaders, serverValue);
}
return contentType;
}
private ContentType tryToEvaluateTestContentType(Headers mainHeaders,
DslProperty<?> body) {
Object serverValue = Optional.ofNullable(body).map(DslProperty::getServerValue)
.orElse(null);
ContentType contentType = evaluateClientSideContentType(mainHeaders, serverValue);
if (contentType == DEFINED || contentType == UNKNOWN) {
// try to retrieve from the other side (e.g. stub side was a regex, but test
// side is concrete)
Object clientValue = Optional.ofNullable(body)
.map(DslProperty::getClientValue).orElse(null);
return evaluateServerSideContentType(mainHeaders, clientValue);
}
return contentType;
}
public boolean isJson() {
return this.inputTestContentType.equals(JSON)
|| this.outputTestContentType.equals(JSON)
|| this.inputStubContentType.equals(JSON)
|| this.outputStubContentType.equals(JSON);
}
public boolean evaluatesToJson() {
return isJson() || this.evaluatedInputTestContentType.equals(JSON)
|| this.evaluatedOutputTestContentType.equals(JSON)
|| this.evaluatedInputStubContentType.equals(JSON)
|| this.evaluatedOutputStubContentType.equals(JSON);
}
public boolean isIgnored() {
return this.contract.getIgnored() || this.contractMetadata.getIgnored();
}
public boolean isXml() {
return this.inputTestContentType.equals(XML)
|| this.outputTestContentType.equals(XML)
|| this.inputStubContentType.equals(XML)
|| this.outputStubContentType.equals(XML);
}
public boolean isHttp() {
return this.http;
}
public boolean isInProgress() {
return this.contract.isInProgress();
}
public boolean isMessaging() {
return !isHttp();
}
private DslProperty<?> inputBody(Contract contract) {
return Optional.ofNullable(contract.getRequest()).map(Request::getBody)
.map(DslProperty.class::cast)
.orElseGet(() -> Optional.ofNullable(contract.getInput())
.map(Input::getMessageBody).orElse(null));
}
private Headers inputHeaders(Contract contract) {
return Optional.ofNullable(contract.getRequest()).map(Request::getHeaders)
.orElseGet(() -> Optional.ofNullable(contract.getInput())
.map(Input::getMessageHeaders).orElse(null));
}
private DslProperty<?> outputBody(Contract contract) {
return Optional.ofNullable(contract.getResponse()).map(Response::getBody)
.map(DslProperty.class::cast)
.orElseGet(() -> Optional.ofNullable(contract.getOutputMessage())
.map(OutputMessage::getBody).orElse(null));
}
private Headers outputHeaders(Contract contract) {
return Optional.ofNullable(contract.getResponse()).map(Response::getHeaders)
.orElseGet(() -> Optional.ofNullable(contract.getOutputMessage())
.map(OutputMessage::getHeaders).orElse(null));
}
public String methodName() {
if (this.methodName == null) {
this.methodName = calculateMethodName();
}
return this.methodName;
}
private String calculateMethodName() {
if (!isEmpty(contract.getName())) {
String name = camelCase(convertIllegalPackageChars(contract.getName()));
log.debug("Overriding the default test name with [{}]", name);
return name;
}
if (allContracts.size() > 1) {
int index = allContracts.indexOf(getContract());
String name = String.format("%s_%d", camelCasedMethodFromFileName(stubsPath),
index);
log.debug("Scenario found. The method name will be [{}]", name);
return name;
}
String name = camelCasedMethodFromFileName(stubsPath);
log.debug("The method name will be [{}]", name);
return name;
}
private static String camelCasedMethodFromFileName(Path stubsPath) {
return camelCase(convertIllegalMethodNameChars(
toLastDot(afterLast(stubsPath.toString(), File.separator))));
}
public ContractMetadata getContractMetadata() {
return contractMetadata;
}
public Contract getContract() {
return contract;
}
public Collection<Contract> getAllContracts() {
return allContracts;
}
public String getDefinedInputStubContentType() {
return definedInputStubContentType;
}
public ContentType getInputStubContentType() {
return inputStubContentType;
}
public ContentType getEvaluatedInputStubContentType() {
return evaluatedInputStubContentType;
}
public String getDefinedOutputStubContentType() {
return definedOutputStubContentType;
}
public ContentType getEvaluatedOutputStubContentType() {
return evaluatedOutputStubContentType;
}
public String getDefinedInputTestContentType() {
return definedInputTestContentType;
}
public ContentType getInputTestContentType() {
return inputTestContentType;
}
public String getDefinedOutputTestContentType() {
return definedOutputTestContentType;
}
public ContentType getOutputTestContentType() {
return outputTestContentType;
}
public ContentType getEvaluatedOutputTestContentType() {
return evaluatedOutputTestContentType;
}
}