Merge remote-tracking branch 'origin/master'

# Conflicts:
#	spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy
#	spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/ContentUtilsSpec.groovy
This commit is contained in:
Olga Maciaszek-Sharma
2019-02-13 13:27:55 +01:00
1272 changed files with 31933 additions and 20845 deletions

View File

@@ -1,32 +1,33 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.util.logging.Commons
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.util.logging.Commons
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast
import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize
import static org.springframework.cloud.contract.verifier.util.NamesUtil.packageToDirectory
@@ -48,16 +49,20 @@ class FileSaver {
void saveClassFile(Path classPath, byte[] classBytes) {
log.info("Creating new class file [$classPath]")
Files.write(classPath, classBytes, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)
Files.
write(classPath, classBytes, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)
}
protected Path pathToClass(Path testBaseDir, String fileName) {
return Paths.get(testBaseDir.toString(), capitalize(fileName) + generator.fileExtension(this.properties)).toAbsolutePath()
return Paths.get(testBaseDir.toString(),
capitalize(fileName) + generator.fileExtension(this.properties)).
toAbsolutePath()
}
protected Path generateTestBaseDir(String basePackageClass, String includedDirectoryRelativePath) {
Path testBaseDir = Paths.get(targetDirectory.absolutePath, packageToDirectory(basePackageClass),
beforeLast(includedDirectoryRelativePath, File.separator))
Path testBaseDir = Paths.
get(targetDirectory.absolutePath, packageToDirectory(basePackageClass),
beforeLast(includedDirectoryRelativePath, File.separator))
Files.createDirectories(testBaseDir)
return testBaseDir
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -42,6 +42,7 @@ import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeL
import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars
import static org.springframework.cloud.contract.verifier.util.NamesUtil.directoryToPackage
import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot
/**
* @author Jakub Kubrynski, codearte.io
*/
@@ -60,11 +61,13 @@ class TestGenerator {
TestGenerator(ContractVerifierConfigProperties configProperties) {
this(configProperties, singleTestGenerator(),
new FileSaver(configProperties.generatedTestSourcesDir, singleTestGenerator(), configProperties))
new FileSaver(configProperties.generatedTestSourcesDir,
singleTestGenerator(), configProperties))
}
private static SingleTestGenerator singleTestGenerator() {
List<SingleTestGenerator> factories = SpringFactoriesLoader.loadFactories(SingleTestGenerator, null)
List<SingleTestGenerator> factories = SpringFactoriesLoader.
loadFactories(SingleTestGenerator, null)
if (factories.empty) {
return new JavaTestGenerator()
}
@@ -97,9 +100,11 @@ class TestGenerator {
private String basePackageName() {
if (configProperties.basePackageForTests) {
return configProperties.basePackageForTests
} else if (configProperties.baseClassForTests) {
}
else if (configProperties.baseClassForTests) {
return toLastDot(configProperties.baseClassForTests)
} else if (configProperties.packageWithBaseClasses) {
}
else if (configProperties.packageWithBaseClasses) {
return configProperties.packageWithBaseClasses
}
return DEFAULT_TEST_PACKAGE
@@ -107,14 +112,19 @@ class TestGenerator {
@PackageScope
void generateTestClasses(final String basePackageName) {
ListMultimap<Path, ContractMetadata> contracts = contractFileScanner.findContracts()
ListMultimap<Path, ContractMetadata> contracts = contractFileScanner.
findContracts()
contracts.asMap().entrySet().each {
Map.Entry<Path, Collection<ContractMetadata>> entry -> processIncludedDirectory(relativizeContractPath(entry), (Collection<ContractMetadata>) entry.getValue(), basePackageName)
Map.Entry<Path, Collection<ContractMetadata>> entry ->
processIncludedDirectory(
relativizeContractPath(entry), (Collection<ContractMetadata>) entry.
getValue(), basePackageName)
}
}
private String relativizeContractPath(Map.Entry<Path, Collection<ContractMetadata>> entry) {
Path relativePath = configProperties.contractsDslDir.toPath().relativize(entry.getKey())
Path relativePath = configProperties.contractsDslDir.toPath().
relativize(entry.getKey())
if (StringUtils.isEmpty(relativePath.toString())) {
return DEFAULT_CLASS_PREFIX
}
@@ -129,11 +139,15 @@ class TestGenerator {
if (contracts.size()) {
def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix()
def convertedClassName = convertIllegalPackageChars(className)
def packageName = buildPackage(basePackageNameForClass, includedDirectoryRelativePath)
Path dir = saver.generateTestBaseDir(basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString()))
def packageName =
buildPackage(basePackageNameForClass, includedDirectoryRelativePath)
Path dir = saver.generateTestBaseDir(basePackageNameForClass,
convertIllegalPackageChars(includedDirectoryRelativePath.toString()))
Path classPath = saver.pathToClass(dir, convertedClassName)
def classBytes = generator.buildClass(configProperties, contracts, includedDirectoryRelativePath,
new SingleTestGenerator.GeneratedClassData(convertedClassName, packageName, classPath)).getBytes(StandardCharsets.UTF_8)
def classBytes = generator.
buildClass(configProperties, contracts, includedDirectoryRelativePath,
new SingleTestGenerator.GeneratedClassData(convertedClassName, packageName, classPath)).
getBytes(StandardCharsets.UTF_8)
saver.saveClassFile(classPath, classBytes)
counter.incrementAndGet()
}
@@ -149,4 +163,4 @@ class TestGenerator {
return !directory.empty ? convertedPackage : packageNameForClass
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -108,13 +108,16 @@ class BlockBuilder {
*/
BlockBuilder addAtTheEnd(String toAdd) {
String lastChar = builder.charAt(builder.length() - 1) as String
String secondLastChar = builder.length() >= 2 ? builder.charAt(builder.length() - 2) as String : ""
String secondLastChar = builder.length() >= 2 ? builder.
charAt(builder.length() - 2) as String : ""
if (endsWithNewLine(lastChar) && aSpecialSign(secondLastChar, toAdd)) {
return this
} else if (endsWithNewLine(lastChar) && !aSpecialSign(secondLastChar, toAdd)) {
}
else if (endsWithNewLine(lastChar) && !aSpecialSign(secondLastChar, toAdd)) {
builder.replace(builder.length() - 1, builder.length(), toAdd)
builder << '\n'
} else {
}
else {
builder << toAdd
}
return this

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -51,7 +51,7 @@ trait BodyMethodGeneration {
}
void addBodyMatchingBlock(List<BodyMatcher> matchers, BlockBuilder blockBuilder,
Object responseBody, boolean shouldCommentOutBDDBlocks) {
Object responseBody, boolean shouldCommentOutBDDBlocks) {
blockBuilder.endBlock()
blockBuilder.addLine(getAssertionJoiner(shouldCommentOutBDDBlocks))
blockBuilder.startBlock()
@@ -59,8 +59,10 @@ trait BodyMethodGeneration {
if (it.matchingType() == MatchingType.NULL) {
methodForNullCheck(it, blockBuilder)
}
else if (MatchingType.regexRelated(it.matchingType()) || it
.matchingType() == MatchingType.EQUALITY) {
else if (MatchingType.regexRelated(it.matchingType())
|| it
.matchingType()
== MatchingType.EQUALITY) {
methodForEqualityCheck(it, blockBuilder, responseBody)
}
else if (it.matchingType() == MatchingType.COMMAND) {

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -21,9 +21,9 @@ import groovy.transform.PackageScope
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.config.TestFramework
import org.springframework.cloud.contract.verifier.util.NamesUtil
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
/**
* Builds a class. Adds all the imports, static imports etc.
@@ -62,28 +62,34 @@ class ClassBuilder {
}
/**
* Returns a {@link ClassBuilder} for the given parameters
* @return a{@link ClassBuilder} for the given parameters
*/
static ClassBuilder createClass(String className, String classPackage, ContractVerifierConfigProperties properties,
String includedDirectoryRelativePath) {
String includedDirectoryRelativePath) {
String baseClassForTests
if (properties.testFramework == TestFramework.SPOCK && !properties.baseClassForTests
&& !properties.packageWithBaseClasses && !properties.baseClassMappings) {
&& !properties.packageWithBaseClasses
&& !properties.baseClassMappings) {
baseClassForTests = 'spock.lang.Specification'
} else {
baseClassForTests = retrieveBaseClass(properties, includedDirectoryRelativePath)
}
else {
baseClassForTests =
retrieveBaseClass(properties, includedDirectoryRelativePath)
}
return new ClassBuilder(className, classPackage, baseClassForTests, properties.testFramework)
}
protected static String retrieveBaseClass(ContractVerifierConfigProperties properties, String includedDirectoryRelativePath) {
String contractPathAsPackage = includedDirectoryRelativePath.replace(File.separator, ".")
String contractPackage = includedDirectoryRelativePath.replace(File.separator, SEPARATOR)
String contractPathAsPackage = includedDirectoryRelativePath.
replace(File.separator, ".")
String contractPackage = includedDirectoryRelativePath.
replace(File.separator, SEPARATOR)
// package mapping takes super precedence
if (properties.baseClassMappings) {
Map.Entry<String, String> mapping = properties.baseClassMappings.find { String pattern, String fqn ->
return contractPathAsPackage.matches(pattern)
}
Map.Entry<String, String> mapping = properties.baseClassMappings.
find { String pattern, String fqn ->
return contractPathAsPackage.matches(pattern)
}
if (log.isDebugEnabled()) {
log.debug("Matching pattern for contract package [${contractPathAsPackage}] with setup ${properties.baseClassMappings} is [${mapping}]")
}
@@ -94,12 +100,14 @@ class ClassBuilder {
if (!properties.packageWithBaseClasses) {
return properties.baseClassForTests
}
String generatedClassName = generateDefaultBaseClassName(contractPackage, properties)
String generatedClassName =
generateDefaultBaseClassName(contractPackage, properties)
return "${generatedClassName}Base"
}
private static String generateDefaultBaseClassName(String classPackage, ContractVerifierConfigProperties properties) {
String[] splitPackage = NamesUtil.convertIllegalPackageChars(classPackage).split(SEPARATOR)
String[] splitPackage = NamesUtil.convertIllegalPackageChars(classPackage).
split(SEPARATOR)
if (splitPackage.size() > 1) {
String last = NamesUtil.capitalize(splitPackage[-1])
String butLast = NamesUtil.capitalize(splitPackage[-2])
@@ -182,7 +190,8 @@ class ClassBuilder {
clazz.startBlock()
rules.sort().each {
clazz.addLine("@Rule")
clazz.addLine("public $it ${NamesUtil.camelCase(it)} = new $it()$lang.lineSuffix")
clazz.
addLine("public $it ${NamesUtil.camelCase(it)} = new $it()$lang.lineSuffix")
}
clazz.endBlock()
if (!rules.empty) {

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -28,14 +28,14 @@ trait ClassVerifier {
Class classToCheck(Object elementFromBody) {
switch (elementFromBody.getClass()) {
case List:
return List
case Set:
return Set
case Map:
return Map
default:
return elementFromBody.class
case List:
return List
case Set:
return Set
case Map:
return Map
default:
return elementFromBody.class
}
}
}

View File

@@ -1,18 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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
@@ -28,4 +27,4 @@ import groovy.transform.CompileStatic
@CompileStatic
enum CommunicationType {
REQUEST, RESPONSE, INPUT, OUTPUT
}
}

View File

@@ -1,23 +1,24 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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 groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
@@ -33,8 +34,8 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig
class ExplicitJUnitMethodBodyBuilder extends RestAssuredJUnitMethodBodyBuilder {
ExplicitJUnitMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}

View File

@@ -1,23 +1,26 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.regex.Pattern
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.Cookie
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
@@ -26,7 +29,6 @@ import org.springframework.cloud.contract.spec.internal.NotToEscapePattern
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
/**
* A {@link SpockMethodRequestProcessingBodyBuilder} implementation that uses MockMvc to send requests.
*
@@ -37,8 +39,8 @@ import java.util.regex.Pattern
class HttpSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProcessingBodyBuilder {
HttpSpockMethodRequestProcessingBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -73,9 +75,11 @@ class HttpSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProc
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Object value) {
if (value instanceof NotToEscapePattern) {
blockBuilder.addLine("response.header('$property') " +
blockBuilder.addLine("response.header('$property') "
+
"${patternComparison(((NotToEscapePattern) value).serverValue.pattern().replace("\\", "\\\\"))}")
} else {
}
else {
// fallback
processHeaderElement(blockBuilder, property, value.toString())
}
@@ -84,9 +88,11 @@ class HttpSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProc
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, Object value) {
if (value instanceof NotToEscapePattern) {
blockBuilder.addLine("response.cookie('$key') " +
blockBuilder.addLine("response.cookie('$key') "
+
"${patternComparison(((NotToEscapePattern) value).serverValue.pattern().replace("\\", "\\\\"))}")
} else {
}
else {
processCookieElement(blockBuilder, key, value.toString())
}
}
@@ -103,18 +109,21 @@ class HttpSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProc
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
blockBuilder.addLine("response.header('$property') ${convertHeaderComparison(value)}")
blockBuilder.
addLine("response.header('$property') ${convertHeaderComparison(value)}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Pattern value) {
blockBuilder.addLine("response.header('$property') ${convertHeaderComparison(value)}")
blockBuilder.
addLine("response.header('$property') ${convertHeaderComparison(value)}")
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, Pattern pattern) {
blockBuilder.addLine("response.cookie('$key') != null")
blockBuilder.addLine("response.cookie('$key') ${convertCookieComparison(pattern)}")
blockBuilder.
addLine("response.cookie('$key') ${convertCookieComparison(pattern)}")
}
@Override
@@ -131,4 +140,4 @@ class HttpSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProc
}
return jsonPath.replace('$', '\\$')
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -53,8 +53,8 @@ import static org.springframework.cloud.contract.verifier.config.TestFramework.J
class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
JUnitMessagingMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -108,25 +108,29 @@ class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
blockBuilder.addLine("assertThat(response.getHeader(\"$property\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getHeader(\"$property\").toString()).${createHeaderComparison(value)}")
blockBuilder.
addLine("assertThat(response.getHeader(\"$property\").toString()).${createHeaderComparison(value)}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Number value) {
blockBuilder.addLine("assertThat(response.getHeader(\"$property\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getHeader(\"$property\")).isEqualTo(${value});")
blockBuilder.
addLine("assertThat(response.getHeader(\"$property\")).isEqualTo(${value});")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Pattern pattern) {
blockBuilder.addLine("assertThat(response.getHeader(\"$property\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getHeader(\"$property\").toString()).${createHeaderComparison(pattern)}")
blockBuilder.
addLine("assertThat(response.getHeader(\"$property\").toString()).${createHeaderComparison(pattern)}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) {
blockBuilder.addLine("assertThat(response.getHeader(\"$property\")).isNotNull();")
blockBuilder.addLine("${exec.insertValue("response.getHeader(\"$property\").toString()")};")
blockBuilder.
addLine("${exec.insertValue("response.getHeader(\"$property\").toString()")};")
}
@Override
@@ -149,7 +153,9 @@ class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
@Override
protected void validateResponseHeadersBlock(BlockBuilder bb) {
bb.addLine("""ContractVerifierMessage response = contractVerifierMessaging.receive(${sentToValue(outputMessage.sentTo.serverValue)});""")
bb.addLine("""ContractVerifierMessage response = contractVerifierMessaging.receive(${
sentToValue(outputMessage.sentTo.serverValue)
});""")
bb.addLine("""assertThat(response).isNotNull();""")
outputMessage.headers?.executeForEachHeader { Header header ->
processHeaderElement(bb, header.name, header.serverValue instanceof NotToEscapePattern ?

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -37,6 +37,7 @@ import static groovy.json.StringEscapeUtils.escapeJava
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.util.ContentUtils.getJavaMultipartFileParameterContent
/**
* Root class for JUnit method building
*
@@ -52,7 +53,7 @@ import static org.springframework.cloud.contract.verifier.util.ContentUtils.getJ
abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder {
JUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -120,7 +121,8 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
@Override
protected void processBodyElement(BlockBuilder blockBuilder, String property, Map.Entry entry) {
processBodyElement(blockBuilder, property, getMapKeyReferenceString(property, entry), entry.value)
processBodyElement(blockBuilder, property,
getMapKeyReferenceString(property, entry), entry.value)
}
private String getMapKeyReferenceString(String property, Map.Entry entry) {
@@ -178,12 +180,14 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
String value
if (body instanceof ExecutionProperty) {
value = body.toString()
} else if (body instanceof FromFileProperty) {
}
else if (body instanceof FromFileProperty) {
FromFileProperty fileProperty = (FromFileProperty) body
value = fileProperty.isByte() ?
readBytesFromFileString(fileProperty, CommunicationType.REQUEST) :
readStringFromFileString(fileProperty, CommunicationType.REQUEST)
} else {
}
else {
String escaped = escapeRequestSpecialChars(body.toString())
value = "\"$escaped\""
}
@@ -192,12 +196,16 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
@Override
protected String getMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) {
return getJavaMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty fileProp -> readBytesFromFileString(fileProp, CommunicationType.REQUEST) })
return getJavaMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty fileProp ->
readBytesFromFileString(fileProp, CommunicationType.REQUEST)
})
}
@Override
protected String getParameterString(Map.Entry<String, Object> parameter) {
return """.param("${escapeJava(parameter.key)}", "${escapeJava(parameter.value as String)}")"""
return """.param("${escapeJava(parameter.key)}", "${
escapeJava(parameter.value as String)
}")"""
}
protected String createHeaderComparison(Object headerValue) {
@@ -211,11 +219,12 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
protected String createBodyComparison(Pattern bodyValue) {
String patternAsString = bodyValue.pattern()
return createMatchesMethod(RegexpBuilders.buildGStringRegexpForTestSide(patternAsString)) + ";"
return createMatchesMethod(RegexpBuilders.
buildGStringRegexpForTestSide(patternAsString)) + ";"
}
protected String createCookieComparison(Object cookieValue) {
String escapedCookie = convertUnicodeEscapesIfRequired("$cookieValue")
String escapedCookie = convertUnicodeEscapesIfRequired("$cookieValue")
return "isEqualTo(\"$escapedCookie\");"
}

View File

@@ -1,26 +1,25 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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 groovy.transform.CompileStatic
import java.lang.invoke.MethodHandles
import groovy.transform.Canonical
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.transform.PackageScope
import org.apache.commons.logging.Log
@@ -53,13 +52,15 @@ class JavaTestGenerator implements SingleTestGenerator {
// TODO: Remove in next major
private static final String REST_ASSURED_2_0_CLASS = 'com.jayway.restassured.RestAssured'
@PackageScope ClassPresenceChecker checker = new ClassPresenceChecker()
@PackageScope
ClassPresenceChecker checker = new ClassPresenceChecker()
@Override
String buildClass(ContractVerifierConfigProperties configProperties, Collection<ContractMetadata> listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) {
String className = generatedClassData.className
String classPackage = generatedClassData.classPackage
ClassBuilder clazz = ClassBuilder.createClass(capitalize(className), classPackage, configProperties, includedDirectoryRelativePath)
ClassBuilder clazz = ClassBuilder.createClass(
capitalize(className), classPackage, configProperties, includedDirectoryRelativePath)
if (configProperties.imports) {
configProperties.imports.each { String it ->
clazz.addImport(it)
@@ -72,7 +73,8 @@ class JavaTestGenerator implements SingleTestGenerator {
}
if (isScenarioClass(listOfFiles)) {
clazz.addImports(configProperties.testFramework.getOrderAnnotationImports())
clazz.addClassLevelAnnotation(configProperties.testFramework.getOrderAnnotation())
clazz.addClassLevelAnnotation(configProperties.testFramework.
getOrderAnnotation())
}
// FIXME: change during Hoxton refactoring: we should only add either Json or Xml imports and not both
addJsonPathRelatedImports(clazz)
@@ -90,7 +92,7 @@ class JavaTestGenerator implements SingleTestGenerator {
Map<ParsedDsl, TestType> contracts = mapContractsToTheirTestTypes(listOfFiles)
boolean conditionalImportsAdded = false
boolean toIgnore = listOfFiles.find { it.ignored }
contracts.each {ParsedDsl key, TestType value ->
contracts.each { ParsedDsl key, TestType value ->
if (!conditionalImportsAdded) {
clazz.addImports(getImports(configProperties.testFramework))
clazz.addStaticImports(getStaticImports(configProperties.testFramework))
@@ -119,16 +121,20 @@ class JavaTestGenerator implements SingleTestGenerator {
clazz.addImport(getRuleImport(configProperties.testFramework))
if (configProperties.testFramework.annotationLevelRules()) {
clazz.addClassLevelAnnotation(configProperties.testFramework
.getRuleAnnotation(configProperties.ruleClassForTests))
} else {
.getRuleAnnotation(configProperties.ruleClassForTests))
}
else {
clazz.addRule(configProperties.ruleClassForTests)
}
}
private void addHttpRelatedEntries(ClassBuilder clazz, ContractVerifierConfigProperties configProperties) {
HttpImportProvider httpImportProvider = new HttpImportProvider(getRestAssuredPackage())
clazz.addImports(httpImportProvider.getImports(configProperties.testFramework, configProperties.testMode))
clazz.addStaticImports(httpImportProvider.getStaticImports(configProperties.testFramework, configProperties.testMode))
HttpImportProvider httpImportProvider = new HttpImportProvider(
getRestAssuredPackage())
clazz.addImports(httpImportProvider.
getImports(configProperties.testFramework, configProperties.testMode))
clazz.addStaticImports(httpImportProvider.
getStaticImports(configProperties.testFramework, configProperties.testMode))
}
// TODO for 2.2: leave only RestAssured 3
@@ -154,10 +160,11 @@ class JavaTestGenerator implements SingleTestGenerator {
log.debug("Stub content from file [${stubsFile.text}]")
}
Collection<Contract> stubContents = metadata.convertedContract
Map<ParsedDsl, TestType> entries = stubContents.collectEntries { Contract stubContent ->
TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP
return [(new ParsedDsl(metadata, stubContent, stubsFile)): testType]
}
Map<ParsedDsl, TestType> entries = stubContents.
collectEntries { Contract stubContent ->
TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP
return [(new ParsedDsl(metadata, stubContent, stubsFile)): testType]
}
dsls.putAll(entries)
}
return dsls
@@ -182,7 +189,7 @@ class JavaTestGenerator implements SingleTestGenerator {
private void addJsonPathRelatedImports(ClassBuilder clazz) {
clazz.addImports(['com.jayway.jsonpath.DocumentContext',
'com.jayway.jsonpath.JsonPath',
'com.jayway.jsonpath.JsonPath',
])
if (this.checker.isClassPresent(JSON_ASSERT_CLASS)) {
clazz.addStaticImport(JSON_ASSERT_STATIC_IMPORT)
@@ -191,15 +198,15 @@ class JavaTestGenerator implements SingleTestGenerator {
private void addXPathRelatedImports(ClassBuilder clazz) {
clazz.addImports(['javax.xml.parsers.DocumentBuilder',
'javax.xml.parsers.DocumentBuilderFactory',
'org.w3c.dom.Document',
'org.xml.sax.InputSource',
'java.io.StringReader'])
'javax.xml.parsers.DocumentBuilderFactory',
'org.w3c.dom.Document',
'org.xml.sax.InputSource',
'java.io.StringReader'])
}
private void addMessagingRelatedEntries(ClassBuilder clazz) {
clazz.addField(['@Inject ContractVerifierMessaging contractVerifierMessaging',
'@Inject ContractVerifierObjectMapper contractVerifierObjectMapper'
'@Inject ContractVerifierObjectMapper contractVerifierObjectMapper'
])
clazz.addImports(MessagingImportProvider.getImports())
clazz.addStaticImports(MessagingImportProvider.getStaticImports())
@@ -214,7 +221,8 @@ class ClassPresenceChecker {
try {
Class.forName(className)
return true
} catch (ClassNotFoundException ex) {
}
catch (ClassNotFoundException ex) {
if (log.isDebugEnabled()) {
log.debug("[${className}] is not present on classpath. Will not add a static import.")
}

View File

@@ -1,37 +1,38 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.regex.Pattern
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.Cookie
import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.spec.internal.FromFileProperty
import org.springframework.cloud.contract.spec.internal.Header
import org.springframework.cloud.contract.spec.internal.NotToEscapePattern
import org.springframework.cloud.contract.spec.internal.QueryParameter
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.spec.internal.QueryParameters
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT
/**
@@ -49,8 +50,8 @@ import static org.springframework.cloud.contract.verifier.config.TestFramework.J
class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
JaxRsClientJUnitMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -85,7 +86,8 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
if (request.url) {
bb.addLine(".path(${concreteUrl(request.url)})")
appendQueryParams(request.url.queryParameters, bb)
} else if (request.urlPath) {
}
else if (request.urlPath) {
bb.addLine(".path(${concreteUrl(request.urlPath)})")
appendQueryParams(request.urlPath.queryParameters, bb)
}
@@ -103,9 +105,10 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
if (!queryParameters?.parameters) {
return
}
queryParameters.parameters.findAll(this.&allowedQueryParameter).each { QueryParameter param ->
bb.addLine(".queryParam(\"$param.name\", \"${resolveParamValue(param).toString()}\")")
}
queryParameters.parameters.findAll(this.&allowedQueryParameter).
each { QueryParameter param ->
bb.addLine(".queryParam(\"$param.name\", \"${resolveParamValue(param).toString()}\")")
}
}
@Override
@@ -120,21 +123,25 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
protected void appendMethodAndBody(BlockBuilder bb) {
String method = request.method.serverValue.toString().toLowerCase()
if (request.body) {
String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType
String contentType =
getHeader('Content-Type') ?: getRequestContentType().mimeType
Object body = request.body.serverValue
String value
if (body instanceof ExecutionProperty) {
value = body.toString()
} else if (body instanceof FromFileProperty) {
}
else if (body instanceof FromFileProperty) {
FromFileProperty fileProperty = (FromFileProperty) body
value = fileProperty.isByte() ?
readBytesFromFileString(fileProperty, CommunicationType.REQUEST) :
readStringFromFileString(fileProperty, CommunicationType.REQUEST)
} else {
}
else {
value = "\"${getBodyAsString()}\""
}
bb.addLine(".method(\"${method.toUpperCase()}\", entity(${value}, \"$contentType\"))")
} else {
}
else {
bb.addLine(".method(\"${method.toUpperCase()}\")")
}
}
@@ -144,7 +151,9 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
if (headerOfAbsentType(header)) {
return
}
if (header.name == 'Content-Type' || header.name == 'Accept') return
if (header.name == 'Content-Type' || header.name == 'Accept') {
return
}
bb.addLine(".header(\"${header.name}\", \"${header.serverValue}\")")
}
}
@@ -163,7 +172,8 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
String acceptHeader = getHeader("Accept")
if (acceptHeader) {
bb.addLine(".request(\"$acceptHeader\")")
} else {
}
else {
bb.addLine(".request()")
}
}
@@ -203,8 +213,10 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Object value) {
if (value instanceof NotToEscapePattern) {
blockBuilder.addLine("assertThat(response.getHeaderString(\"$property\")).${createHeaderComparison(((NotToEscapePattern) value).serverValue)}")
} else {
blockBuilder.
addLine("assertThat(response.getHeaderString(\"$property\")).${createHeaderComparison(((NotToEscapePattern) value).serverValue)}")
}
else {
// fallback
processHeaderElement(blockBuilder, property, value.toString())
}
@@ -212,34 +224,42 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
blockBuilder.addLine("assertThat(response.getHeaderString(\"$property\")).${createHeaderComparison(value)}")
blockBuilder.
addLine("assertThat(response.getHeaderString(\"$property\")).${createHeaderComparison(value)}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Number value) {
blockBuilder.addLine("assertThat(response.getHeaderString(\"$property\")).isEqualTo(${value});")
blockBuilder.
addLine("assertThat(response.getHeaderString(\"$property\")).isEqualTo(${value});")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Pattern pattern) {
blockBuilder.addLine("assertThat(response.getHeaderString(\"$property\")).${createHeaderComparison(pattern)}")
blockBuilder.
addLine("assertThat(response.getHeaderString(\"$property\")).${createHeaderComparison(pattern)}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) {
blockBuilder.addLine("${exec.insertValue("response.getHeaderString(\"$property\")")};")
blockBuilder.
addLine("${exec.insertValue("response.getHeaderString(\"$property\")")};")
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, Pattern pattern) {
blockBuilder.addLine("assertThat(response.getCookies().get(\"$key\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getCookies().get(\"$key\").getValue()).${createCookieComparison(pattern)}")
blockBuilder.
addLine("assertThat(response.getCookies().get(\"$key\")).isNotNull();")
blockBuilder.
addLine("assertThat(response.getCookies().get(\"$key\").getValue()).${createCookieComparison(pattern)}")
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, String value) {
blockBuilder.addLine("assertThat(response.getCookies().get(\"$key\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getCookies().get(\"$key\").getValue()).${createCookieComparison(value)}")
blockBuilder.
addLine("assertThat(response.getCookies().get(\"$key\")).isNotNull();")
blockBuilder.
addLine("assertThat(response.getCookies().get(\"$key\").getValue()).${createCookieComparison(value)}")
}
}

View File

@@ -1,37 +1,38 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.regex.Pattern
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.Cookie
import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.spec.internal.FromFileProperty
import org.springframework.cloud.contract.spec.internal.Header
import org.springframework.cloud.contract.spec.internal.NotToEscapePattern
import org.springframework.cloud.contract.spec.internal.QueryParameter
import org.springframework.cloud.contract.spec.internal.QueryParameters
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
/**
* Knows how to build a Spock test method for JaxRs.
*
@@ -46,8 +47,8 @@ import java.util.regex.Pattern
class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProcessingBodyBuilder {
JaxRsClientSpockMethodRequestProcessingBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -81,7 +82,8 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
String acceptHeader = getHeader("Accept")
if (acceptHeader) {
bb.addLine(".request('$acceptHeader')")
} else {
}
else {
bb.addLine(".request()")
}
}
@@ -90,7 +92,8 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
if (request.url) {
bb.addLine(".path(${concreteUrl(request.url)})")
appendQueryParams(request.url.queryParameters, bb)
} else if (request.urlPath) {
}
else if (request.urlPath) {
bb.addLine(".path(${concreteUrl(request.urlPath)})")
appendQueryParams(request.urlPath.queryParameters, bb)
}
@@ -108,9 +111,10 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
if (!queryParameters?.parameters) {
return
}
queryParameters.parameters.findAll(this.&allowedQueryParameter).each { QueryParameter param ->
bb.addLine(".queryParam('$param.name', '${resolveParamValue(param).toString()}')")
}
queryParameters.parameters.findAll(this.&allowedQueryParameter).
each { QueryParameter param ->
bb.addLine(".queryParam('$param.name', '${resolveParamValue(param).toString()}')")
}
}
@Override
@@ -125,21 +129,25 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
protected void appendMethodAndBody(BlockBuilder bb) {
String method = request.method.serverValue.toString().toLowerCase()
if (request.body) {
String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType
String contentType =
getHeader('Content-Type') ?: getRequestContentType().mimeType
Object body = request.body.serverValue
String value
if (body instanceof ExecutionProperty) {
value = body.toString()
} else if (body instanceof FromFileProperty) {
}
else if (body instanceof FromFileProperty) {
FromFileProperty fileProperty = (FromFileProperty) body
value = fileProperty.isByte() ?
readBytesFromFileString(fileProperty, CommunicationType.REQUEST) :
readStringFromFileString(fileProperty, CommunicationType.REQUEST)
} else {
}
else {
value = "'${bodyAsString}'"
}
bb.addLine(".method('${method.toUpperCase()}', entity(${value}, '$contentType'))")
} else {
}
else {
bb.addLine(".method('${method.toUpperCase()}')")
}
}
@@ -149,7 +157,9 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
if (headerOfAbsentType(header)) {
return
}
if (header.name == 'Content-Type' || header.name == 'Accept') return // Particular headers are set via 'request' / 'entity' methods
if (header.name == 'Content-Type' || header.name == 'Accept') {
return
} // Particular headers are set via 'request' / 'entity' methods
bb.addLine(".header('${header.name}', '${header.serverValue}')")
}
}
@@ -199,8 +209,10 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Object value) {
if (value instanceof NotToEscapePattern) {
blockBuilder.addLine("response.getHeaderString('$property') ${convertHeaderComparison(((NotToEscapePattern) value).serverValue)}")
} else {
blockBuilder.
addLine("response.getHeaderString('$property') ${convertHeaderComparison(((NotToEscapePattern) value).serverValue)}")
}
else {
// fallback
processHeaderElement(blockBuilder, property, value.toString())
}
@@ -208,12 +220,14 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) {
blockBuilder.addLine("${exec.insertValue("response.getHeaderString(\'$property\')")}")
blockBuilder.
addLine("${exec.insertValue("response.getHeaderString(\'$property\')")}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
blockBuilder.addLine("response.getHeaderString('$property') ${convertHeaderComparison(value)}")
blockBuilder.
addLine("response.getHeaderString('$property') ${convertHeaderComparison(value)}")
}
@Override
@@ -223,19 +237,22 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Pattern value) {
blockBuilder.addLine("response.getHeaderString('$property') ${convertHeaderComparison(value)}")
blockBuilder.
addLine("response.getHeaderString('$property') ${convertHeaderComparison(value)}")
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, Pattern pattern) {
blockBuilder.addLine("response.getCookies().get('$key') != null")
blockBuilder.addLine("response.getCookies().get('$key').getValue() ${convertCookieComparison(pattern)}")
blockBuilder.
addLine("response.getCookies().get('$key').getValue() ${convertCookieComparison(pattern)}")
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, String value) {
blockBuilder.addLine("response.getCookies().get('$key') != null")
blockBuilder.addLine("response.getCookies().get('$key').getValue() ${convertCookieComparison(value)}")
blockBuilder.
addLine("response.getCookies().get('$key').getValue() ${convertCookieComparison(value)}")
}
@Override

View File

@@ -1,18 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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
@@ -38,12 +37,12 @@ import org.springframework.cloud.contract.verifier.template.TemplateProcessor
import org.springframework.cloud.contract.verifier.util.JsonPaths
import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter
import org.springframework.cloud.contract.verifier.util.MapConverter
/**
* @author Marcin Grzejszczak
* @author Olga Maciaszek-Sharma
* @since 2.1.0
*/
@PackageScope
@CompileStatic
class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier {
@@ -63,11 +62,11 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
// Passing way more arguments here than I would like to, but since we are planning a major
// refactoring of this module for Hoxton release, leaving it this way for now
JsonBodyVerificationBuilder(ContractVerifierConfigProperties configProperties,
TemplateProcessor templateProcessor,
ContractTemplate contractTemplate,
Contract contract,
Optional<String> lineSuffix,
Closure postProcessJsonPathCall) {
TemplateProcessor templateProcessor,
ContractTemplate contractTemplate,
Contract contract,
Optional<String> lineSuffix,
Closure postProcessJsonPathCall) {
this.configProperties = configProperties
this.templateProcessor = templateProcessor
this.contractTemplate = contractTemplate
@@ -77,9 +76,9 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
}
Object addJsonResponseBodyCheck(BlockBuilder bb, Object convertedResponseBody,
BodyMatchers bodyMatchers,
String responseString,
boolean shouldCommentOutBDDBlocks) {
BodyMatchers bodyMatchers,
String responseString,
boolean shouldCommentOutBDDBlocks) {
appendJsonPath(bb, responseString)
DocumentContext parsedRequestBody
boolean dontParseStrings = convertedResponseBody instanceof Map
@@ -252,7 +251,8 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
return entry
}
String entryAsString = (String) entry
if (templateProcessor.containsTemplateEntry(entryAsString) &&
if (templateProcessor.containsTemplateEntry(entryAsString)
&&
!templateProcessor.containsJsonPathTemplateEntry(entryAsString)) {
// TODO: HANDLEBARS LEAKING VIA request.
String justEntry = entryAsString - contractTemplate.
@@ -306,8 +306,7 @@ class JsonBodyVerificationBuilder implements BodyMethodGeneration, ClassVerifier
}
private void doBodyMatchingIfPresent(BodyMatchers bodyMatchers, BlockBuilder bb,
Object responseBody,
boolean shouldCommentOutBDDBlocks) {
Object responseBody, boolean shouldCommentOutBDDBlocks) {
if (bodyMatchers?.hasMatchers()) {
addBodyMatchingBlock(bodyMatchers.
matchers(), bb, responseBody, shouldCommentOutBDDBlocks)

View File

@@ -1,18 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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
@@ -50,8 +49,8 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder {
protected final OutputMessage outputMessage
MessagingMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(configProperties, stubDefinition, classDataForMethod)
this.inputMessage = stubDefinition.input
this.outputMessage = stubDefinition.outputMessage
@@ -88,7 +87,8 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder {
bb.endBlock()
if (outputMessage.headers) {
bb.addLine(addCommentSignIfRequired('and:')).startBlock()
} else {
}
else {
bb.startBlock()
}
validateResponseBodyBlock(bb, outputMessage.bodyMatchers, outputMessage.body.serverValue)
@@ -102,7 +102,8 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, GString value) {
String gstringValue = ContentUtils.extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
String gstringValue = ContentUtils.
extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
processHeaderElement(blockBuilder, property, gstringValue)
}
@@ -118,12 +119,15 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder {
protected String getBodyAsString() {
ContentType contentType = contentType()
Object bodyValue = extractServerValueFromBody(contentType, inputMessage.messageBody.serverValue)
Object bodyValue =
extractServerValueFromBody(contentType, inputMessage.messageBody.serverValue)
if (bodyValue instanceof FromFileProperty) {
FromFileProperty fileProperty = (FromFileProperty) bodyValue
return fileProperty.isByte() ?
indentBody(readBytesFromFileString(fileProperty, CommunicationType.REQUEST)) :
indentStringBody(readStringFromFileString(fileProperty, CommunicationType.REQUEST))
indentBody(
readBytesFromFileString(fileProperty, CommunicationType.REQUEST)) :
indentStringBody(
readStringFromFileString(fileProperty, CommunicationType.REQUEST))
}
String json = new JsonOutput().toJson(bodyValue)
json = convertUnicodeEscapesIfRequired(json)

View File

@@ -5,14 +5,13 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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
@@ -50,6 +49,7 @@ import static org.springframework.cloud.contract.verifier.util.ContentType.JSON
import static org.springframework.cloud.contract.verifier.util.ContentType.TEXT
import static org.springframework.cloud.contract.verifier.util.ContentType.XML
import static org.springframework.cloud.contract.verifier.util.ContentUtils.extractValue
/**
* Main class for building method body.
*
@@ -64,7 +64,9 @@ import static org.springframework.cloud.contract.verifier.util.ContentUtils.extr
@PackageScope
abstract class MethodBodyBuilder implements ClassVerifier {
private static final Closure GET_SERVER_VALUE = { it instanceof DslProperty ? it.serverValue : it }
private static final Closure GET_SERVER_VALUE = {
it instanceof DslProperty ? it.serverValue : it
}
protected final ContractVerifierConfigProperties configProperties
protected final TemplateProcessor templateProcessor
@@ -75,8 +77,8 @@ abstract class MethodBodyBuilder implements ClassVerifier {
private final XmlBodyVerificationBuilder xmlBodyVerificationBuilder
protected MethodBodyBuilder(ContractVerifierConfigProperties configProperties,
Contract contract,
GeneratedClassDataForMethod classDataForMethod) {
Contract contract,
GeneratedClassDataForMethod classDataForMethod) {
this.configProperties = configProperties
this.templateProcessor = processor()
this.contractTemplate = template()
@@ -86,7 +88,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
templateProcessor, contractTemplate, this.contract,
lineSuffix(), { String jsonPath ->
postProcessJsonPathCall(jsonPath)
})
})
this.xmlBodyVerificationBuilder = new XmlBodyVerificationBuilder(contract,
lineSuffix())
}
@@ -152,12 +154,12 @@ abstract class MethodBodyBuilder implements ClassVerifier {
protected abstract String getResponseAsString()
/**
* Returns the given string with comment sign if required by the given implementation
* @return the given string with comment sign if required by the given implementation
*/
protected abstract String addCommentSignIfRequired(String baseString)
/**
* Returns true if the BDD-syntax blocks should be commented out for a given framework
* @return true if the BDD-syntax blocks should be commented out for a given framework
*/
protected abstract boolean shouldCommentOutBDDBlocks()
@@ -167,7 +169,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
protected abstract BlockBuilder addColonIfRequired(BlockBuilder blockBuilder)
/**
* Returns line suffix appropriate for test builder if required
* @return line suffix appropriate for test builder if required
*/
protected abstract Optional<String> lineSuffix()
@@ -232,7 +234,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
* Appends to the {@link BlockBuilder} the assertion for the given header path
*/
protected abstract void processHeaderElement(BlockBuilder blockBuilder, String property, String value)
/**
* Appends to the {@link BlockBuilder} the assertion for the given header path
*/
@@ -320,7 +322,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
protected abstract void then(BlockBuilder bb)
/**
* Returns a {@link org.springframework.cloud.contract.verifier.util.ContentType} for the given request
* @return a{@link org.springframework.cloud.contract.verifier.util.ContentType} for the given request
*/
protected abstract ContentType getResponseContentType()
@@ -330,7 +332,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
protected abstract String getBodyAsString()
/**
* Returns {@code true} if given section should be created
* @return {@code true} if given section should be created
*/
protected abstract boolean hasGivenSection()
@@ -412,14 +414,18 @@ abstract class MethodBodyBuilder implements ClassVerifier {
convertedResponseBody = convertedResponseBody.asString()
}
if (convertedResponseBody instanceof GString) {
convertedResponseBody = extractValue(convertedResponseBody as GString, contentType, { Object o -> o instanceof DslProperty ? o.serverValue : o })
convertedResponseBody =
extractValue(convertedResponseBody as GString, contentType, { Object o -> o instanceof DslProperty ? o.serverValue : o })
}
if (TEXT != contentType && FORM != contentType) {
boolean dontParseStrings = contentType == JSON && convertedResponseBody instanceof Map
Closure parsingClosure = dontParseStrings ? Closure.IDENTITY : MapConverter.JSON_PARSING_CLOSURE
convertedResponseBody = MapConverter.getTestSideValues(convertedResponseBody, parsingClosure)
} else {
convertedResponseBody = StringEscapeUtils.escapeJava(convertedResponseBody.toString())
convertedResponseBody = MapConverter.
getTestSideValues(convertedResponseBody, parsingClosure)
}
else {
convertedResponseBody = StringEscapeUtils.
escapeJava(convertedResponseBody.toString())
}
if (JSON == contentType) {
addJsonBodyVerification(bb, convertedResponseBody, bodyMatchers)
@@ -427,7 +433,8 @@ abstract class MethodBodyBuilder implements ClassVerifier {
else if (XML == contentType) {
xmlBodyVerificationBuilder.addXmlResponseBodyCheck(bb, convertedResponseBody,
bodyMatchers, getResponseAsString(), shouldCommentOutBDDBlocks())
} else {
}
else {
simpleTextResponseBodyCheck(bb, convertedResponseBody)
}
}
@@ -499,7 +506,8 @@ abstract class MethodBodyBuilder implements ClassVerifier {
if (toTrim.startsWith('"')) {
return toTrim.replaceAll('"', '')
//#261
} else if (toTrim.startsWith('\\"') && toTrim.endsWith('\\"')) {
}
else if (toTrim.startsWith('\\"') && toTrim.endsWith('\\"')) {
return toTrim.substring(2, toTrim.length() - 2)
}
return toTrim
@@ -562,7 +570,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
/**
* Extracts the executable test side values and
* returns the code of the executable
* @return the code of the executable
*/
protected String getTestSideValue(ExecutionProperty executionProperty) {
return executionProperty.toString()
@@ -604,7 +612,7 @@ abstract class MethodBodyBuilder implements ClassVerifier {
}
private void byteResponseBodyCheck(BlockBuilder bb,
FromFileProperty convertedResponseBody) {
FromFileProperty convertedResponseBody) {
processText(bb, "", convertedResponseBody)
addColonIfRequired(bb)
}
@@ -613,4 +621,4 @@ abstract class MethodBodyBuilder implements ClassVerifier {
return s.substring(1)
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -49,7 +49,7 @@ class MethodBuilder {
private final boolean ignored
private MethodBuilder(String methodName, Contract stubContent, ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod generatedClassDataForMethod, boolean ignored) {
GeneratedClassDataForMethod generatedClassDataForMethod, boolean ignored) {
this.ignored = ignored
this.stubContent = stubContent
this.methodName = methodName
@@ -71,15 +71,17 @@ class MethodBuilder {
static String methodName(ContractMetadata contract, File stubsFile, Contract stubContent) {
if (stubContent.name) {
String name = NamesUtil.camelCase(NamesUtil.convertIllegalPackageChars(stubContent.name))
String name = NamesUtil.
camelCase(NamesUtil.convertIllegalPackageChars(stubContent.name))
if (log.isDebugEnabled()) {
log.debug("Overriding the default test name with [" + name + "]")
}
return name
} else if (contract.convertedContract.size() > 1) {
int index = contract.convertedContract.findIndexOf { it == stubContent}
}
else if (contract.convertedContract.size() > 1) {
int index = contract.convertedContract.findIndexOf { it == stubContent }
String name = "${camelCasedMethodFromFileName(stubsFile)}_${index}"
if (log.isDebugEnabled()) {
if (log.isDebugEnabled()) {
log.debug("Scenario found. The method name will be [" + name + "]")
}
return name
@@ -92,7 +94,8 @@ class MethodBuilder {
}
private static String camelCasedMethodFromFileName(File stubsFile) {
return NamesUtil.camelCase(NamesUtil.convertIllegalMethodNameChars(NamesUtil.toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator))))
return NamesUtil.camelCase(NamesUtil.convertIllegalMethodNameChars(NamesUtil.
toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator))))
}
/**
@@ -105,7 +108,8 @@ class MethodBuilder {
if (ignored) {
blockBuilder.addLine(configProperties.testFramework.ignoreAnnotation)
}
blockBuilder.addLine(configProperties.testFramework.methodModifier + "validate_$methodName() throws Exception {")
blockBuilder.
addLine(configProperties.testFramework.methodModifier + "validate_$methodName() throws Exception {")
getMethodBodyBuilder().appendTo(blockBuilder)
blockBuilder.addLine('}')
}
@@ -122,18 +126,21 @@ class MethodBuilder {
return new JaxRsClientJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
}
return new JaxRsClientSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
} else if (configProperties.testMode == TestMode.WEBTESTCLIENT) {
}
else if (configProperties.testMode == TestMode.WEBTESTCLIENT) {
if (isJUnitType()) {
return new WebTestClientJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
}
return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
} else if (configProperties.testMode == TestMode.EXPLICIT) {
}
else if (configProperties.testMode == TestMode.EXPLICIT) {
if (isJUnitType()) {
return new ExplicitJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
}
// in Groovy we're using def so we don't have to update the imports
return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
} else if (configProperties.testFramework == SPOCK) {
}
else if (configProperties.testFramework == SPOCK) {
return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)
}
return new MockMvcJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod)

View File

@@ -1,23 +1,24 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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 groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
@@ -33,7 +34,7 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig
class MockMvcJUnitMethodBodyBuilder extends RestAssuredJUnitMethodBodyBuilder {
MockMvcJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}

View File

@@ -1,18 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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
@@ -75,7 +74,7 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
}
/**
* Returns code used to retrieve a response for the given {@link Request}
* @return code used to retrieve a response for the given {@link Request}
*/
protected abstract String getInputString(Request request)
@@ -85,28 +84,28 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
}
/**
* Returns {@code true} if a response body is expected
* @return {@code true} if a response body is expected
*/
protected boolean expectsResponseBody() {
return response.body != null
}
/**
* Returns {@code true} if the query parameter is allowed
* @return {@code true} if the query parameter is allowed
*/
protected boolean allowedQueryParameter(QueryParameter param) {
return allowedQueryParameter(param.serverValue)
}
/**
* Returns {@code true} if the query parameter is allowed
* @return {@code true} if the query parameter is allowed
*/
protected boolean allowedQueryParameter(MatchingStrategy matchingStrategy) {
return matchingStrategy.type != MatchingStrategy.Type.ABSENT
}
/**
* Returns {@code true} if the query parameter is allowed
* @return {@code true} if the query parameter is allowed
*/
protected boolean allowedQueryParameter(Object o) {
return true
@@ -131,17 +130,20 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
if (request.body) {
Object body = null
switch (request.body.serverValue) {
case ExecutionProperty:
case FromFileProperty:
body = request.body?.serverValue
break
default:
body = getBodyAsString()
case ExecutionProperty:
case FromFileProperty:
body = request.body?.serverValue
break
default:
body = getBodyAsString()
}
bb.addLine(getBodyString(body))
}
if (request.multipart) {
multipartParameters?.each { Map.Entry<String, Object> entry -> bb.addLine(getMultipartParameterLine(entry)) }
multipartParameters?.each { Map.Entry<String, Object> entry ->
bb.
addLine(getMultipartParameterLine(entry))
}
}
}
@@ -179,8 +181,9 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
@TypeChecked(TypeCheckingMode.SKIP)
protected addQueryParameters(Url buildUrl, BlockBuilder bb) {
if(hasQueryParams(buildUrl)){
List<QueryParameter> queryParameters = buildUrl.queryParameters.parameters.findAll(this.&allowedQueryParameter)
if (hasQueryParams(buildUrl)) {
List<QueryParameter> queryParameters = buildUrl.queryParameters.parameters.
findAll(this.&allowedQueryParameter)
for (queryParam in queryParameters) {
addQueryParameter(queryParam, bb)
}
@@ -189,10 +192,12 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
@TypeChecked(TypeCheckingMode.SKIP)
protected addQueryParameter(QueryParameter queryParam, BlockBuilder bb) {
bb.addLine(/.${QUERY_PARAM_METHOD}(${DOUBLE_QUOTE}${queryParam.name}${DOUBLE_QUOTE},${DOUBLE_QUOTE}${resolveParamValue(queryParam).toString()}${DOUBLE_QUOTE})/)
bb.addLine(".${QUERY_PARAM_METHOD}(${DOUBLE_QUOTE}${queryParam.name}"
+
"${DOUBLE_QUOTE},${DOUBLE_QUOTE}${resolveParamValue(queryParam).toString()}${DOUBLE_QUOTE})")
}
protected addUrl(Url buildUrl, BlockBuilder bb){
protected addUrl(Url buildUrl, BlockBuilder bb) {
Object testSideUrl = MapConverter.getTestSideValues(buildUrl)
String method = request.method.serverValue.toString().toLowerCase()
String url = testSideUrl.toString()
@@ -227,13 +232,15 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, GString value) {
String gstringValue = ContentUtils.extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
String gstringValue = ContentUtils.
extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
processHeaderElement(blockBuilder, property, gstringValue)
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, GString value) {
String gStringValue = ContentUtils.extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
String gStringValue = ContentUtils.
extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
processCookieElement(blockBuilder, key, gStringValue)
}
@@ -245,20 +252,23 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
@Override
protected String getBodyAsString() {
ContentType contentType = contentType()
Object bodyValue = extractServerValueFromBody(contentType, request.body.serverValue)
Object bodyValue =
extractServerValueFromBody(contentType, request.body.serverValue)
if (contentType == ContentType.FORM) {
if (bodyValue instanceof Map) {
// [a:3, b:4] == "a=3&b=4"
return ((Map) bodyValue).collect {
convertUnicodeEscapesIfRequired(it.key.toString() + "=" + it.value)
}.join("&")
} else if (bodyValue instanceof List) {
}
else if (bodyValue instanceof List) {
// ["a=3", "b=4"] == "a=3&b=4"
return ((List) bodyValue).collect {
convertUnicodeEscapesIfRequired(it.toString())
}.join("&")
}
} else {
}
else {
String json = new JsonOutput().toJson(bodyValue)
json = convertUnicodeEscapesIfRequired(json)
return trimRepeatedQuotes(json)
@@ -266,7 +276,7 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
}
/**
* Returns a map of server side multipart parameters
* @return a map of server side multipart parameters
*/
protected Map<String, Object> getMultipartParameters() {
return (Map<String, Object>) request?.multipart?.serverValue
@@ -280,19 +290,21 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
}
/**
* Returns a String URL from {@link Request}'s test side values. It can be
* @return a String URL from {@link Request}'s test side values. It can be
* a concrete value of the URL or a path.
*/
protected Url getUrl(Request request) {
if (request.url)
if (request.url) {
return request.url
if (request.urlPath)
}
if (request.urlPath) {
return request.urlPath
}
throw new IllegalStateException("URL is not set!")
}
/**
* Returns a line of code to send a multi part parameter in the request
* @return a line of code to send a multi part parameter in the request
*/
protected String getMultipartParameterLine(Map.Entry<String, Object> parameter) {
if (parameter.value instanceof NamedProperty) {
@@ -304,4 +316,4 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder {
private boolean hasQueryParams(Url url) {
return url.queryParameters
}
}
}

View File

@@ -1,23 +1,26 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.regex.Pattern
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.Cookie
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
@@ -26,7 +29,6 @@ import org.springframework.cloud.contract.spec.internal.NotToEscapePattern
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
/**
* A {@link JUnitMethodBodyBuilder} implementation that uses Rest Assured.
*
@@ -39,7 +41,7 @@ import java.util.regex.Pattern
class RestAssuredJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
RestAssuredJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -79,9 +81,11 @@ class RestAssuredJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Object value) {
if (value instanceof NotToEscapePattern) {
blockBuilder.addLine("assertThat(response.header(\"$property\"))." +
blockBuilder.addLine("assertThat(response.header(\"$property\"))."
+
"${createMatchesMethod((value as NotToEscapePattern).serverValue.pattern().replace("\\", "\\\\"))};")
} else {
}
else {
// fallback
processHeaderElement(blockBuilder, property, value.toString())
}
@@ -89,17 +93,20 @@ class RestAssuredJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
blockBuilder.addLine("assertThat(response.header(\"$property\")).${createHeaderComparison(value)}")
blockBuilder.
addLine("assertThat(response.header(\"$property\")).${createHeaderComparison(value)}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Number value) {
blockBuilder.addLine("assertThat(response.header(\"$property\")).isEqualTo(${value});")
blockBuilder.
addLine("assertThat(response.header(\"$property\")).isEqualTo(${value});")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Pattern pattern) {
blockBuilder.addLine("assertThat(response.header(\"$property\")).${createHeaderComparison(pattern)}")
blockBuilder.
addLine("assertThat(response.header(\"$property\")).${createHeaderComparison(pattern)}")
}
@Override
@@ -110,12 +117,14 @@ class RestAssuredJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, Pattern pattern) {
blockBuilder.addLine("assertThat(response.getCookie(\"$key\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getCookie(\"$key\")).${createCookieComparison(pattern)}")
blockBuilder.
addLine("assertThat(response.getCookie(\"$key\")).${createCookieComparison(pattern)}")
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, String value) {
blockBuilder.addLine("assertThat(response.getCookie(\"$key\")).isNotNull();")
blockBuilder.addLine("assertThat(response.getCookie(\"$key\")).${createCookieComparison(value)}")
blockBuilder.
addLine("assertThat(response.getCookie(\"$key\")).${createCookieComparison(value)}")
}
}

View File

@@ -1,8 +1,24 @@
/*
* Copyright 2013-2019 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
*
* http://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.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.cloud.contract.verifier.file.ContractMetadata
/**
* Builds a single test.
@@ -15,13 +31,13 @@ trait SingleTestGenerator {
* Creates contents of a single test class in which all test scenarios from
* the contract metadata should be placed.
*
* @param properties - properties passed to the plugin
* @param listOfFiles - list of parsed contracts with additional metadata
* @param className - the name of the generated test class
* @param classPackage - the name of the package in which the test class should be stored
* @param properties - properties passed to the plugin
* @param listOfFiles - list of parsed contracts with additional metadata
* @param className - the name of the generated test class
* @param classPackage - the name of the package in which the test class should be stored
* @param includedDirectoryRelativePath - relative path to the included directory
* @return contents of a single test class
* @deprecated use {@link SingleTestGenerator#buildClass(ContractVerifierConfigProperties, Collection, String, GeneratedClassData)}
* @deprecated use{@link SingleTestGenerator#buildClass(ContractVerifierConfigProperties, Collection, String, GeneratedClassData)}
*/
@Deprecated
abstract String buildClass(ContractVerifierConfigProperties properties,
@@ -31,15 +47,18 @@ trait SingleTestGenerator {
* Creates contents of a single test class in which all test scenarios from
* the contract metadata should be placed.
*
* @param properties - properties passed to the plugin
* @param listOfFiles - list of parsed contracts with additional metadata
* @param generatedClassData - information about the generated class
* @param properties - properties passed to the plugin
* @param listOfFiles - list of parsed contracts with additional metadata
* @param generatedClassData - information about the generated class
* @param includedDirectoryRelativePath - relative path to the included directory
* @return contents of a single test class
*/
String buildClass(ContractVerifierConfigProperties properties,
Collection<ContractMetadata> listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) {
return buildClass(properties, listOfFiles, generatedClassData.className, generatedClassData.classPackage, includedDirectoryRelativePath)
String className = generatedClassData.className
String classPackage = generatedClassData.classPackage
String path = includedDirectoryRelativePath
return buildClass(properties, listOfFiles, className, classPackage, path)
}
/**

View File

@@ -1,24 +1,27 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.regex.Pattern
import groovy.json.StringEscapeUtils
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.Cookie
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
@@ -31,8 +34,6 @@ import org.springframework.cloud.contract.spec.internal.RegexProperty
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.util.MapConverter
import java.util.regex.Pattern
import static org.apache.commons.text.StringEscapeUtils.escapeJava
/**
@@ -44,8 +45,8 @@ import static org.apache.commons.text.StringEscapeUtils.escapeJava
class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
SpockMessagingMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -84,12 +85,14 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) {
blockBuilder.addLine("${exec.insertValue("response.getHeader(\'$property\')?.toString()")}")
blockBuilder.
addLine("${exec.insertValue("response.getHeader(\'$property\')?.toString()")}")
}
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
blockBuilder.addLine("response.getHeader('$property')?.toString() ${convertHeaderComparison(value)}")
blockBuilder.
addLine("response.getHeader('$property')?.toString() ${convertHeaderComparison(value)}")
}
@Override
@@ -99,7 +102,8 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Pattern value) {
blockBuilder.addLine("response.getHeader('$property')?.toString() ${convertHeaderComparison(value)}")
blockBuilder.
addLine("response.getHeader('$property')?.toString() ${convertHeaderComparison(value)}")
}
@Override
@@ -117,9 +121,12 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
@Override
protected void validateResponseCodeBlock(BlockBuilder bb) {
if (outputMessage) {
bb.addLine("""ContractVerifierMessage response = contractVerifierMessaging.receive(${sentToValue(outputMessage.sentTo.serverValue)})""")
bb.addLine("""ContractVerifierMessage response = contractVerifierMessaging.receive(${
sentToValue(outputMessage.sentTo.serverValue)
})""")
bb.addLine("""assert response != null""")
} else {
}
else {
bb.addLine('noExceptionThrown()')
}
}
@@ -262,7 +269,8 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder {
}
protected String convertHeaderComparison(Pattern headerValue) {
String converted = escapeJava(convertUnicodeEscapesIfRequired(headerValue.pattern()))
String converted =
escapeJava(convertUnicodeEscapesIfRequired(headerValue.pattern()))
return "==~ java.util.regex.Pattern.compile('${converted}')"
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -49,8 +49,8 @@ import static org.springframework.cloud.contract.verifier.util.ContentUtils.getG
abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessingMethodBodyBuilder {
SpockMethodRequestProcessingBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@@ -153,12 +153,14 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
String value
if (body instanceof ExecutionProperty) {
value = body.toString()
} else if (body instanceof FromFileProperty) {
}
else if (body instanceof FromFileProperty) {
FromFileProperty fileProperty = (FromFileProperty) body
value = fileProperty.isByte() ?
readBytesFromFileString(fileProperty, CommunicationType.REQUEST) :
readStringFromFileString(fileProperty, CommunicationType.REQUEST)
} else {
}
else {
String escaped = escapeRequestSpecialChars(body.toString())
value = "'''$escaped'''"
}
@@ -167,7 +169,9 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
@Override
protected String getMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) {
return getGroovyMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty fileProp -> readBytesFromFileString(fileProp, CommunicationType.REQUEST) })
return getGroovyMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty fileProp ->
readBytesFromFileString(fileProp, CommunicationType.REQUEST)
})
}
@Override
@@ -177,13 +181,15 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
@Override
protected void processHeaderElement(BlockBuilder blockBuilder, String property, GString value) {
String gstringValue = ContentUtils.extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
String gstringValue = ContentUtils.
extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
processHeaderElement(blockBuilder, property, gstringValue)
}
@Override
protected void processCookieElement(BlockBuilder blockBuilder, String key, GString value) {
String gStringValue = ContentUtils.extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
String gStringValue = ContentUtils.
extractValueForGString(value, ContentUtils.GET_TEST_SIDE).toString()
processCookieElement(blockBuilder, key, gStringValue)
}
@@ -209,7 +215,8 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
protected String createBodyComparison(Pattern bodyValue) {
String patternAsString = bodyValue.pattern()
return patternComparison(RegexpBuilders.buildGStringRegexpForTestSide(patternAsString)) + ";"
return patternComparison(RegexpBuilders.
buildGStringRegexpForTestSide(patternAsString)) + ";"
}
protected String convertCookieComparison(Pattern cookieValue) {

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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 groovy.json.JsonOutput
@@ -9,6 +25,7 @@ import org.springframework.cloud.contract.spec.internal.FromFileProperty
import org.springframework.cloud.contract.spec.internal.Request
import org.springframework.cloud.contract.verifier.util.ContentUtils
import org.springframework.cloud.contract.verifier.util.MapConverter
/**
* Representation of the request side to be used for response templating in
* the generated tests.
@@ -61,7 +78,7 @@ class TestSideRequestTemplateModel {
String url = MapConverter.getTestSideValues(request.url ?: request.urlPath)
Path paths = new Path(buildPathsFromUrl(url))
Map<String, List<String>> query = (Map<String, List<String>>) (request.url ?: request.urlPath)
.queryParameters?.parameters?.groupBy { it.name }?.collectEntries {
.queryParameters?.parameters?.groupBy { it.name }?.collectEntries {
[(it.key): it.value.collect { MapConverter.getTestSideValues(it) }]
}
String fullUrl = (query == null || query.isEmpty()) ? url :
@@ -99,7 +116,8 @@ class TestSideRequestTemplateModel {
Object bodyValue = extractServerValueFromBody(body)
if (bodyValue instanceof GString || bodyValue instanceof String) {
return bodyValue.toString()
} else if (bodyValue instanceof FromFileProperty) {
}
else if (bodyValue instanceof FromFileProperty) {
return null
}
return bodyValue != null ? new JsonOutput().toJson(bodyValue) : bodyValue
@@ -107,8 +125,10 @@ class TestSideRequestTemplateModel {
protected static Object extractServerValueFromBody(bodyValue) {
if (bodyValue instanceof GString) {
bodyValue = ContentUtils.extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue } as Closure)
} else {
bodyValue = ContentUtils.
extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue } as Closure)
}
else {
bodyValue = MapConverter.transformValues(bodyValue, {
it instanceof DslProperty ? it.serverValue : it
})

View File

@@ -1,7 +1,24 @@
/*
* Copyright 2013-2019 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
*
* http://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 groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.internal.Url
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
@@ -17,31 +34,31 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig
@PackageScope
class WebTestClientJUnitMethodBodyBuilder extends RestAssuredJUnitMethodBodyBuilder {
WebTestClientJUnitMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
WebTestClientJUnitMethodBodyBuilder(Contract stubDefinition,
ContractVerifierConfigProperties configProperties,
GeneratedClassDataForMethod classDataForMethod) {
super(stubDefinition, configProperties, classDataForMethod)
}
@Override
protected String returnedResponseType() {
return 'WebTestClientResponse'
}
@Override
protected String returnedResponseType() {
return 'WebTestClientResponse'
}
@Override
protected String returnedRequestType() {
return 'WebTestClientRequestSpecification'
}
@Override
protected String returnedRequestType() {
return 'WebTestClientRequestSpecification'
}
@Override
protected void when(BlockBuilder bb) {
bb.addLine(getInputString(request))
bb.indent()
@Override
protected void when(BlockBuilder bb) {
bb.addLine(getInputString(request))
bb.indent()
Url url = getUrl(request)
addQueryParameters(url, bb)
addUrl(url, bb)
addColonIfRequired(bb)
bb.unindent()
}
Url url = getUrl(request)
addQueryParameters(url, bb)
addUrl(url, bb)
addColonIfRequired(bb)
bb.unindent()
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2018-2019 the original author or authors.
* Copyright 2018-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -43,8 +43,8 @@ class XmlBodyVerificationBuilder implements BodyMethodGeneration {
}
void addXmlResponseBodyCheck(BlockBuilder blockBuilder, Object responseBody,
BodyMatchers bodyMatchers, String responseString,
boolean shouldCommentOutBDDBlocks) {
BodyMatchers bodyMatchers, String responseString,
boolean shouldCommentOutBDDBlocks) {
addXmlProcessingLines(blockBuilder, responseString)
Object processedBody = XmlToXPathsConverter
.removeMatchingXPaths(responseBody, bodyMatchers)
@@ -62,7 +62,7 @@ class XmlBodyVerificationBuilder implements BodyMethodGeneration {
.each {
blockBuilder.addLine(it as String)
addColonIfRequired(lineSuffix, blockBuilder)
}
}
}
@Override

View File

@@ -1,11 +1,29 @@
/*
* Copyright 2013-2019 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
*
* http://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.handlebars
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel
import groovy.transform.CompileStatic
import org.apache.commons.text.StringEscapeUtils
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel
/**
* A Handlebars helper for the {@code escapejsonbody} helper function.
*
@@ -23,7 +41,8 @@ class HandlebarsEscapeHelper implements Helper<Map<String, Object>> {
Object model = context.get(REQUEST_MODEL_NAME)
if (model instanceof TestSideRequestTemplateModel) {
return StringEscapeUtils.escapeJson(returnObjectForTest(model).toString())
} else if (model instanceof RequestTemplateModel) {
}
else if (model instanceof RequestTemplateModel) {
return StringEscapeUtils.escapeJson(returnObjectForStub(model).toString())
}
throw new IllegalArgumentException("Unsupported model")

View File

@@ -1,15 +1,31 @@
/*
* Copyright 2013-2019 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
*
* http://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.handlebars
import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers
import org.apache.commons.text.StringEscapeUtils
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel
import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers
import com.jayway.jsonpath.DocumentContext
import com.jayway.jsonpath.JsonPath
import groovy.transform.CompileStatic
import wiremock.com.github.jknack.handlebars.Helper
import wiremock.com.github.jknack.handlebars.Options
import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel
/**
* A Handlebars helper for the {@code jsonpath} helper function.
*
@@ -31,11 +47,13 @@ class HandlebarsJsonPathHelper implements Helper<Object> {
Object model = oldContext.get(REQUEST_MODEL_NAME)
if (model instanceof TestSideRequestTemplateModel) {
return returnObjectForTest(model, jsonPath)
} else if (model instanceof RequestTemplateModel) {
}
else if (model instanceof RequestTemplateModel) {
return returnObjectForStub(model, jsonPath)
}
throw new IllegalArgumentException("Unsupported model")
} else if (context instanceof String) {
}
else if (context instanceof String) {
Object value = WireMockHelpers.jsonPath.apply(context, options)
if (testSideModel(options)) {
return processTestResponseValue(value)
@@ -55,7 +73,8 @@ class HandlebarsJsonPathHelper implements Helper<Object> {
}
private Object returnObjectForStub(Object model, String jsonPath) {
DocumentContext documentContext = JsonPath.parse(((RequestTemplateModel) model).body)
DocumentContext documentContext = JsonPath.
parse(((RequestTemplateModel) model).body)
return documentContext.read(jsonPath)
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -60,16 +60,17 @@ class BaseImportProvider {
* @return list of imports
*/
static List<String> getImports(TestFramework testFramework) {
return GENERAL_IMPORTS.imports + TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).imports
return GENERAL_IMPORTS.imports +
TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).imports
}
/**
* Returns list of static imports for provided test framework.
* @param testFramework
* @return
* @param testFramework test framework to pick the static imports for
* @return list of static imports for provided test framework.
*/
static List<String> getStaticImports(TestFramework testFramework) {
return GENERAL_IMPORTS.staticImports + TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).staticImports
return GENERAL_IMPORTS.staticImports +
TEST_FRAMEWORK_SPECIFIC_IMPORTS.get(testFramework).staticImports
}
static String getRuleImport(TestFramework testFramework) {

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -59,7 +59,7 @@ class HttpImportProvider {
'io.restassured.module.webtestclient.specification.WebTestClientRequestSpecification',
'io.restassured.module.webtestclient.response.WebTestClientResponse']),
(new Tuple2(JUNIT, EXPLICIT)) : new ImportDefinitions(["${restAssuredPackage}.specification.RequestSpecification",
"${restAssuredPackage}.response.Response"]),
"${restAssuredPackage}.response.Response"]),
(new Tuple2(JUNIT5, EXPLICIT)) : new ImportDefinitions(["${restAssuredPackage}.specification.RequestSpecification",
"${restAssuredPackage}.response.Response"]),
(new Tuple2(SPOCK, JAXRSCLIENT)) : new ImportDefinitions([]),

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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 groovy.transform.CompileStatic
@@ -19,4 +35,4 @@ class ImportDefinitions {
this.imports = imports
this.staticImports = staticImports
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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 groovy.transform.CompileStatic
@@ -17,9 +33,9 @@ class MessagingImportProvider {
*/
static List<String> getImports() {
return ['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',
'org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper',
'org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage',
'org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging',
]
}
@@ -27,6 +43,6 @@ class MessagingImportProvider {
* @return list of static imports for messaging test contracts.
*/
static List<String> getStaticImports() {
return ['org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers','org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes']
return ['org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers', 'org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes']
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.config
@@ -83,10 +83,10 @@ class ContractVerifierConfigProperties {
*/
List<String> excludedFiles = []
/**
* Patterns that should be taken into account for processing
*/
List<String> includedFiles = []
/**
* Patterns that should be taken into account for processing
*/
List<String> includedFiles = []
/**
* Patterns for which generated tests should be @Ignored

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.config
@@ -46,7 +46,7 @@ enum TestFramework {
}
/**
* @deprecated use {@link #TestFramework(TestFrameworkDefinition)}
* @deprecated use{@link #TestFramework(TestFrameworkDefinition)}
* @param classModifier
* @param methodModifier
* @param lineSuffix
@@ -58,7 +58,7 @@ enum TestFramework {
*/
@Deprecated
TestFramework(String classModifier, String methodModifier, String lineSuffix, String classExtension, String classNameSuffix,
String ignoreClass, List<String> orderAnnotationImports, String orderAnnotation) {
String ignoreClass, List<String> orderAnnotationImports, String orderAnnotation) {
testFrameworkDefinition = new TestFrameworkDefinition() {
@Override
@@ -117,4 +117,4 @@ enum TestFramework {
}
}
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.config
@@ -43,4 +43,4 @@ enum TestMode {
* Uses Spring's reactive WebTestClient
*/
WEBTESTCLIENT
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.config.framework
import groovy.transform.CompileStatic

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.config.framework
import groovy.transform.CompileStatic

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.config.framework
import groovy.transform.CompileStatic

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.config.framework
import groovy.transform.CompileStatic

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.config.framework
import groovy.transform.CompileStatic
@@ -13,63 +29,63 @@ import groovy.transform.CompileStatic
interface TestFrameworkDefinition {
/**
* Returns the class access level modifier. E.g. for Java tests that would mean {@code public}
**/
* @return the class access level modifier. E.g. for Java tests that would mean {@code public}
* */
String getClassModifier()
/**
* Returns the method access level modifier along with the return type.
* @return the method access level modifier along with the return type.
* E.g. for Java tests that would mean {@code public void}
**/
* */
String getMethodModifier()
/**
* Returns the characters that should end each line. E.g. for Java tests that would mean {@code ;}
**/
* @return the characters that should end each line. E.g. for Java tests that would mean {@code ;}
* */
String getLineSuffix()
/**
* Returns the file extension. E.g. for Java tests that would be {@code .java}
**/
* @return the file extension. E.g. for Java tests that would be {@code .java}
* */
String getClassExtension()
/**
* Returns the test class name suffix. E.g. for JUnit tests that would be {@code Test}
**/
* @return the test class name suffix. E.g. for JUnit tests that would be {@code Test}
* */
String getClassNameSuffix()
/**
* Returns the qualified name of the class used to ignore or disable tests. E.g. for JUnit 4 tests that would
* @return the qualified name of the class used to ignore or disable tests. E.g. for JUnit 4 tests that would
* be {@code org.junit.Ignore}
**/
* */
String getIgnoreClass()
/**
* Returns the qualified names of the classes that are used for arranging tests into scenarios.
* @return the qualified names of the classes that are used for arranging tests into scenarios.
* E.g. for JUnit 4 tests that would be {@code 'org.junit.FixMethodOrder'}, {@code 'org.junit.runners.MethodSorters'}
**/
* */
List<String> getOrderAnnotationImports()
/**
* Returns the annotation used for arranging tests into scenarios.
* @return the annotation used for arranging tests into scenarios.
* E.g. for JUnit test that would be {@code @FixMethodOrder(MethodSorters.NAME_ASCENDING)}
**/
* */
String getOrderAnnotation()
/**
* Returns the annotation used for ignoring or disabling tests. E.g. for JUnit tests that would mean {@code @Ignore}
**/
* @return the annotation used for ignoring or disabling tests. E.g. for JUnit tests that would mean {@code @Ignore}
* */
String getIgnoreAnnotation()
/**
* Returns a boolean indicating whether an annotation-type rule or extension is being used or not.
* @return a boolean indicating whether an annotation-type rule or extension is being used or not.
* E.g. for JUnit 5 tests that would return {@code true}
**/
* */
boolean annotationLevelRules()
/**
* Returns the test rule or extension annotation with the {@annotationValue} passed as an argument.
* @return the test rule or extension annotation with the {@annotationValue} passed as an argument.
* E.g. for JUnit 5 tests that could be {@code @ExtendWith(Example.class)}
**/
* */
String getRuleAnnotation(String annotationValue)
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.converter
@@ -75,8 +75,10 @@ class ContractsToYaml {
ContentType contentType = evaluateContentType(contract.response?.headers,
contract.response?.body)
yamlContract.outputMessage = new YamlContract.OutputMessage()
yamlContract.outputMessage.sentTo = MapConverter.getStubSideValues(contract.outputMessage.sentTo)
yamlContract.outputMessage.headers = (contract.outputMessage?.headers as Headers)?.asStubSideMap()
yamlContract.outputMessage.sentTo = MapConverter.
getStubSideValues(contract.outputMessage.sentTo)
yamlContract.outputMessage.headers = (contract.outputMessage?.headers as Headers)?.
asStubSideMap()
yamlContract.outputMessage.body = MapConverter.getStubSideValues(
contract.outputMessage?.body)
contract.outputMessage?.bodyMatchers?.matchers()?.each { BodyMatcher matcher ->
@@ -103,11 +105,16 @@ class ContractsToYaml {
ContentType contentType = evaluateContentType(contract.input?.messageHeaders,
contract.input?.messageBody)
yamlContract.input = new YamlContract.Input()
yamlContract.input.assertThat = MapConverter.getTestSideValues(contract.input?.assertThat?.toString())
yamlContract.input.triggeredBy = MapConverter.getTestSideValues(contract.input?.triggeredBy?.toString())
yamlContract.input.messageHeaders = (contract.input?.messageHeaders as Headers)?.asTestSideMap()
yamlContract.input.messageBody = MapConverter.getTestSideValues(contract.input?.messageBody)
yamlContract.input.messageFrom = MapConverter.getTestSideValues(contract.input?.messageFrom)
yamlContract.input.assertThat = MapConverter.
getTestSideValues(contract.input?.assertThat?.toString())
yamlContract.input.triggeredBy = MapConverter.
getTestSideValues(contract.input?.triggeredBy?.toString())
yamlContract.input.messageHeaders = (contract.input?.messageHeaders as Headers)?.
asTestSideMap()
yamlContract.input.messageBody = MapConverter.
getTestSideValues(contract.input?.messageBody)
yamlContract.input.messageFrom = MapConverter.
getTestSideValues(contract.input?.messageFrom)
contract.input?.bodyMatchers?.matchers()?.each { BodyMatcher matcher ->
yamlContract.input.matchers.body << new YamlContract.BodyStubMatcher(
path: matcher.path(),
@@ -139,15 +146,21 @@ class ContractsToYaml {
request.cookies = (contract.request?.cookies as Cookies)?.asTestSideMap()
Object body = contract.request?.body?.serverValue
if (body instanceof FromFileProperty) {
if (body.isByte()) request.bodyFromFileAsBytes = body.fileName()
if (body.isString()) request.bodyFromFile = body.fileName()
} else {
if (body.isByte()) {
request.bodyFromFileAsBytes = body.fileName()
}
if (body.isString()) {
request.bodyFromFile = body.fileName()
}
}
else {
request.body = MapConverter.getTestSideValues(contract.request?.body)
}
Multipart multipart = contract.request.multipart
if (multipart) {
request.multipart = new YamlContract.Multipart()
Map<String, Object> map = (Map<String, Object>) MapConverter.getTestSideValues(multipart)
Map<String, Object> map = (Map<String, Object>) MapConverter.
getTestSideValues(multipart)
map.each { String key, Object value ->
if (value instanceof NamedProperty) {
Object fileName = value.name?.serverValue
@@ -162,7 +175,8 @@ class ContractsToYaml {
fileNameCommand: fileName instanceof ExecutionProperty ? fileName.toString() : null,
fileContentCommand: fileContent instanceof ExecutionProperty ? fileContent.toString() : null,
contentTypeCommand: contentType instanceof ExecutionProperty ? contentType.toString() : null)
} else {
}
else {
request.multipart.params.put(key, value != null ? value.toString() : null)
}
}
@@ -178,18 +192,19 @@ class ContractsToYaml {
)
}
Object url = contract.request.url?.clientValue
request.matchers.url = url instanceof RegexProperty ?
request.matchers.url = url instanceof RegexProperty ?
new YamlContract.KeyValueMatcher(regex: url.pattern()) :
url instanceof ExecutionProperty ?
new YamlContract.KeyValueMatcher(command: url.toString()) : null
Object urlPath = contract.request.urlPath?.clientValue
request.matchers.url = urlPath instanceof RegexProperty ?
request.matchers.url = urlPath instanceof RegexProperty ?
new YamlContract.KeyValueMatcher(regex: urlPath.pattern()) :
urlPath instanceof ExecutionProperty ?
new YamlContract.KeyValueMatcher(command: urlPath.toString()) : null
if (multipart) {
request.matchers.multipart = new YamlContract.MultipartStubMatcher()
Map<String, Object> map = (Map<String, Object>) MapConverter.getStubSideValues(multipart)
Map<String, Object> map = (Map<String, Object>) MapConverter.
getStubSideValues(multipart)
map.each { String key, Object value ->
if (value instanceof NamedProperty) {
Object fileName = value.name?.clientValue
@@ -205,13 +220,15 @@ class ContractsToYaml {
contentType: valueMatcher(contentType),
)
}
} else if (value instanceof RegexProperty || value instanceof Pattern) {
}
else if (value instanceof RegexProperty || value instanceof Pattern) {
RegexProperty property = new RegexProperty(value)
request.matchers.multipart.params.add(new YamlContract.KeyValueMatcher(
key: key,
regex: property.pattern(),
regexType: regexType(property.clazz())
))
request.matchers.multipart.params.
add(new YamlContract.KeyValueMatcher(
key: key,
regex: property.pattern(),
regexType: regexType(property.clazz())
))
}
}
}
@@ -232,12 +249,14 @@ class ContractsToYaml {
}
protected YamlContract.ValueMatcher valueMatcher(Object o) {
return o instanceof RegexProperty ? new YamlContract.ValueMatcher(regex: o.pattern()) : null
return o instanceof RegexProperty ? new YamlContract.ValueMatcher(regex: o.
pattern()) : null
}
protected void setInputBodyMatchers(DslProperty body, List<YamlContract.BodyStubMatcher> bodyMatchers) {
def testSideValues = MapConverter.getTestSideValues(body)
JsonPaths paths = new JsonToJsonPathsConverter().transformToJsonPathWithStubsSideValues(body)
JsonPaths paths = new JsonToJsonPathsConverter().
transformToJsonPathWithStubsSideValues(body)
paths?.findAll { it.valueBeforeChecking() instanceof Pattern }?.each {
Object element = JsonToJsonPathsConverter.readElement(testSideValues, it.keyBeforeChecking())
bodyMatchers << new YamlContract.BodyStubMatcher(
@@ -254,28 +273,29 @@ class ContractsToYaml {
}
protected RegexType regexType(Class clazz) {
switch(clazz) {
case Boolean:
return RegexType.as_boolean
case Long:
return RegexType.as_long
case Short:
return RegexType.as_short
case Integer:
return RegexType.as_integer
case Float:
return RegexType.as_float
case Double:
return RegexType.as_double
default:
return RegexType.as_string
switch (clazz) {
case Boolean:
return RegexType.as_boolean
case Long:
return RegexType.as_long
case Short:
return RegexType.as_short
case Integer:
return RegexType.as_integer
case Float:
return RegexType.as_float
case Double:
return RegexType.as_double
default:
return RegexType.as_string
}
}
protected void setOutputBodyMatchers(DslProperty body,
List<YamlContract.BodyTestMatcher> bodyMatchers) {
List<YamlContract.BodyTestMatcher> bodyMatchers) {
def testSideValues = MapConverter.getTestSideValues(body)
JsonPaths paths = new JsonToJsonPathsConverter().transformToJsonPathWithTestsSideValues(body)
JsonPaths paths = new JsonToJsonPathsConverter().
transformToJsonPathWithTestsSideValues(body)
paths?.findAll { it.valueBeforeChecking() instanceof Pattern }?.each {
Object element = JsonToJsonPathsConverter.readElement(testSideValues, it.keyBeforeChecking())
bodyMatchers << new YamlContract.BodyTestMatcher(
@@ -311,9 +331,14 @@ class ContractsToYaml {
response.cookies = (contract.response?.cookies as Cookies)?.asStubSideMap()
Object body = contract.response?.body?.clientValue
if (body instanceof FromFileProperty) {
if (body.isByte()) response.bodyFromFileAsBytes = body.fileName()
if (body.isString()) response.bodyFromFile = body.fileName()
} else {
if (body.isByte()) {
response.bodyFromFileAsBytes = body.fileName()
}
if (body.isString()) {
response.bodyFromFile = body.fileName()
}
}
else {
response.body = MapConverter.getStubSideValues(contract.response?.body)
}
contract.response?.bodyMatchers?.matchers()?.each { BodyMatcher matcher ->
@@ -356,12 +381,14 @@ class ContractsToYaml {
regex: property.pattern(),
regexType: regexType(property.clazz())
)
} else if (value instanceof ExecutionProperty) {
}
else if (value instanceof ExecutionProperty) {
headerMatchers << new YamlContract.TestHeaderMatcher(
key: key,
command: value.executionCommand,
)
} else if (value instanceof NotToEscapePattern) {
}
else if (value instanceof NotToEscapePattern) {
headerMatchers << new YamlContract.TestHeaderMatcher(
key: key,
regex: ((Pattern) value.serverValue).pattern(),
@@ -372,39 +399,39 @@ class ContractsToYaml {
protected YamlContract.TestMatcherType testMatcherType(MatchingType matchingType) {
switch (matchingType) {
case MatchingType.EQUALITY:
return YamlContract.TestMatcherType.by_equality
case MatchingType.TYPE:
return YamlContract.TestMatcherType.by_type
case MatchingType.COMMAND:
return YamlContract.TestMatcherType.by_command
case MatchingType.DATE:
return YamlContract.TestMatcherType.by_date
case MatchingType.TIME:
return YamlContract.TestMatcherType.by_time
case MatchingType.TIMESTAMP:
return YamlContract.TestMatcherType.by_timestamp
case MatchingType.REGEX:
return YamlContract.TestMatcherType.by_regex
case MatchingType.EQUALITY:
return YamlContract.TestMatcherType.by_equality
case MatchingType.TYPE:
return YamlContract.TestMatcherType.by_type
case MatchingType.COMMAND:
return YamlContract.TestMatcherType.by_command
case MatchingType.DATE:
return YamlContract.TestMatcherType.by_date
case MatchingType.TIME:
return YamlContract.TestMatcherType.by_time
case MatchingType.TIMESTAMP:
return YamlContract.TestMatcherType.by_timestamp
case MatchingType.REGEX:
return YamlContract.TestMatcherType.by_regex
}
return null
}
protected YamlContract.StubMatcherType stubMatcherType(MatchingType matchingType) {
switch (matchingType) {
case MatchingType.EQUALITY:
return YamlContract.StubMatcherType.by_equality
case MatchingType.TYPE:
case MatchingType.COMMAND:
throw new UnsupportedOperationException("No type for client side")
case MatchingType.DATE:
return YamlContract.StubMatcherType.by_date
case MatchingType.TIME:
return YamlContract.StubMatcherType.by_time
case MatchingType.TIMESTAMP:
return YamlContract.StubMatcherType.by_timestamp
case MatchingType.REGEX:
return YamlContract.StubMatcherType.by_regex
case MatchingType.EQUALITY:
return YamlContract.StubMatcherType.by_equality
case MatchingType.TYPE:
case MatchingType.COMMAND:
throw new UnsupportedOperationException("No type for client side")
case MatchingType.DATE:
return YamlContract.StubMatcherType.by_date
case MatchingType.TIME:
return YamlContract.StubMatcherType.by_time
case MatchingType.TIMESTAMP:
return YamlContract.StubMatcherType.by_timestamp
case MatchingType.REGEX:
return YamlContract.StubMatcherType.by_regex
}
return null
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.converter
import java.nio.file.Files
@@ -9,6 +25,7 @@ import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.ContractConverter
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter
import org.springframework.core.io.support.SpringFactoriesLoader
/**
* Converts contracts to YAML for the given folder
*
@@ -31,11 +48,19 @@ class ToYamlConverter {
// target/copied_contracts/contracts/foo/baz/bar.groovy
Collection<Contract> collection = converter.convertFrom(file)
if (log.isDebugEnabled()) {
log.debug("Converted file [" + file + "] to collection of [" + collection.size() + "] contracts")
log.debug("Converted file [" + file + "] to collection of ["
+ collection.
size()
+ "] contracts")
}
List<YamlContract> yamls = yamlContractConverter.convertTo(collection)
if (log.isDebugEnabled()) {
log.debug("Converted collection of [" + collection.size() + "] contracts to [" + yamls.size() + "] YAML contracts")
log.debug("Converted collection of ["
+ collection.
size()
+ "] contracts to ["
+ yamls.size()
+ "] YAML contracts")
}
// rm target/copied_contracts/contracts/foo/baz/bar.groovy
file.delete()
@@ -103,4 +128,4 @@ class GroovyContractConverter implements ContractConverter<Collection<Contract>>
Collection<Contract> convertTo(Collection<Contract> contract) {
return contract
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.converter
@@ -22,9 +22,8 @@ import groovy.transform.ToString
/**
* YAML representation of a {@link org.springframework.cloud.contract.spec.Contract}
*
* @since 1.2.1
* @author Marcin Grzejszczak
*
* @since 1.2.1* @author Marcin Grzejszczak
* @author Tim Ysewyn
*/
@CompileStatic
@@ -270,4 +269,4 @@ class YamlContract {
public String assertThat
public TestMatchers matchers = new TestMatchers()
}
}
}

View File

@@ -1,30 +1,31 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.converter
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.spec.ContractConverter
/**
* Simple converter from and to a {@link YamlContract} to a collection of {@link Contract}
*
* @since 1.2.1
* @author Marcin Grzejszczak
* @since 1.2.1* @author Marcin Grzejszczak
* @author Tim Ysewyn
*/
@CompileStatic
@@ -54,7 +55,7 @@ class YamlContractConverter implements ContractConverter<List<YamlContract>> {
@Override
Map<String, byte[]> store(List<YamlContract> contracts) {
return contracts.collectEntries {
return [(name(it)) :
return [(name(it)):
this.mapper.writeValueAsString(it).bytes]
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.converter
@@ -54,11 +54,13 @@ class YamlToContracts {
ClassLoader classLoader = YamlContractConverter.getClassLoader()
YAMLMapper mapper = new YAMLMapper()
try {
Iterable<Object> iterables = new Yaml().loadAll(Files.newInputStream(contractFile.toPath()))
Iterable<Object> iterables = new Yaml().
loadAll(Files.newInputStream(contractFile.toPath()))
Collection<Contract> contracts = []
int counter = 0
for (Object document : iterables) {
List<Contract> processedYaml = processYaml(counter, document, mapper, classLoader, contractFile)
List<Contract> processedYaml =
processYaml(counter, document, mapper, classLoader, contractFile)
contracts.addAll(processedYaml)
counter = counter + 1
}
@@ -72,23 +74,33 @@ class YamlToContracts {
}
catch (Exception e1) {
throw new IllegalStateException("Exception occurred while processing the file [" + contractFile + "]", e1)
} finally {
}
finally {
Thread.currentThread().setContextClassLoader(classLoader)
}
}
protected List<Contract> processYaml(int counter, Object document, ObjectMapper mapper, ClassLoader classLoader, File contractFile) {
List<YamlContract> yamlContracts = convert(mapper, document)
Thread.currentThread().setContextClassLoader(updatedClassLoader(contractFile.getParentFile(), classLoader))
Thread.currentThread().setContextClassLoader(
updatedClassLoader(contractFile.getParentFile(), classLoader))
List<Contract> contracts = []
for (YamlContract yamlContract : yamlContracts) {
Contract contract = Contract.make {
if (yamlContract.description) description(yamlContract.description)
if (yamlContract.label) label(yamlContract.label)
if (yamlContract.description) {
description(yamlContract.description)
}
if (yamlContract.label) {
label(yamlContract.label)
}
name(StringUtils.hasText(yamlContract.name) ? yamlContract.name
: NamesUtil.defaultContractName(contractFile, yamlContracts, counter))
if (yamlContract.priority) priority(yamlContract.priority)
if (yamlContract.ignored) ignored()
: NamesUtil.defaultContractName(contractFile, yamlContracts, counter))
if (yamlContract.priority) {
priority(yamlContract.priority)
}
if (yamlContract.ignored) {
ignored()
}
if (yamlContract.request?.method) {
request {
method(yamlContract.request?.method)
@@ -96,125 +108,156 @@ class YamlToContracts {
url(urlValue(yamlContract.request?.url, yamlContract.request?.matchers?.url)) {
if (yamlContract.request.queryParameters) {
queryParameters {
yamlContract.request.queryParameters.each { String key, Object value ->
if (value instanceof List) {
((List) value).each {
parameter(key, it)
yamlContract.request.queryParameters.
each { String key, Object value ->
if (value instanceof List) {
((List) value).each {
parameter(key, it)
}
}
else {
parameter(key, value)
}
} else {
parameter(key, value)
}
}
}
}
}
}
if (yamlContract.request?.urlPath) {
urlPath(urlValue(yamlContract.request?.urlPath, yamlContract.request?.matchers?.url)) {
urlPath(
urlValue(yamlContract.request?.urlPath, yamlContract.request?.matchers?.url)) {
if (yamlContract.request.queryParameters) {
queryParameters {
yamlContract.request.queryParameters.each { String key, Object value ->
if (value instanceof List) {
((List) value).each {
parameter(key, queryParamValue(yamlContract, key, it))
yamlContract.request.queryParameters.
each { String key, Object value ->
if (value instanceof List) {
((List) value).each {
parameter(key,
queryParamValue(yamlContract, key, it))
}
}
else {
parameter(key,
queryParamValue(yamlContract, key, value))
}
} else {
parameter(key, queryParamValue(yamlContract, key, value))
}
}
}
}
}
}
if (yamlContract.request?.headers) {
headers {
yamlContract.request.headers.each { String key, Object value ->
List<YamlContract.KeyValueMatcher> matchers =
yamlContract.request.matchers.headers.findAll { it.key == key }
matchers.each { YamlContract.KeyValueMatcher matcher ->
if (value instanceof List) {
((List) value).each {
header(key, clientValue(it, matcher, key).clientValue)
yamlContract.request.headers.
each { String key, Object value ->
List<YamlContract.KeyValueMatcher> matchers =
yamlContract.request.matchers.headers.
findAll { it.key == key }
matchers.
each { YamlContract.KeyValueMatcher matcher ->
if (value instanceof List) {
((List) value).each {
header(key,
clientValue(it, matcher, key).clientValue)
}
}
else {
header(key, new DslProperty(
clientValue(value, matcher, key).clientValue,
serverValue(value, matcher)))
}
}
} else {
header(key, new DslProperty(clientValue(value, matcher, key).clientValue,
serverValue(value, matcher)))
if (!matchers) {
header(key, value)
}
}
if (!matchers) {
header(key, value)
}
}
}
}
if (yamlContract.request?.cookies) {
cookies {
yamlContract.request?.cookies?.each { String key, Object value ->
YamlContract.KeyValueMatcher matcher = yamlContract.request.matchers.cookies.find { it.key == key }
cookie(key, clientValue(value, matcher, key))
}
yamlContract.request?.cookies?.
each { String key, Object value ->
YamlContract.KeyValueMatcher matcher = yamlContract.request.matchers.cookies.
find { it.key == key }
cookie(key, clientValue(value, matcher, key))
}
}
}
if (yamlContract.request.body != null) body(yamlContract.request.body)
if (yamlContract.request.bodyFromFile != null) body(file(yamlContract.request.bodyFromFile))
if (yamlContract.request.bodyFromFileAsBytes != null) body(fileAsBytes(yamlContract.request.bodyFromFileAsBytes))
if (yamlContract.request.body != null) {
body(yamlContract.request.body)
}
if (yamlContract.request.bodyFromFile != null) {
body(file(yamlContract.request.bodyFromFile))
}
if (yamlContract.request.bodyFromFileAsBytes != null) {
body(fileAsBytes(yamlContract.request.bodyFromFileAsBytes))
}
if (yamlContract.request.multipart) {
Map multipartMap = [:]
Map<String, DslProperty> multiPartParams = yamlContract.request
.multipart.params.collectEntries { String paramKey, String paramValue ->
YamlContract.KeyValueMatcher matcher = yamlContract.request.matchers
.multipart.params.
collectEntries { String paramKey, String paramValue ->
YamlContract.KeyValueMatcher matcher = yamlContract.request.matchers
.multipart.params.find {
it.key == paramKey
}
Object value = paramValue
if (matcher) {
value = matcher.regex ? Pattern.compile(matcher.regex) :
it.key == paramKey
}
Object value = paramValue
if (matcher) {
value = matcher.regex ? Pattern.
compile(matcher.regex) :
predefinedToPattern(matcher.predefined)
}
return [(paramKey), new DslProperty<>(value, paramValue)]
} as Map<String, DslProperty>
}
return [(paramKey), new DslProperty<>(value, paramValue)]
} as Map<String, DslProperty>
multipartMap.putAll(multiPartParams)
yamlContract.request.multipart.named.each { YamlContract.Named namedParam ->
YamlContract.MultipartNamedStubMatcher matcher = yamlContract.request.matchers.multipart.named.find {
it.paramName == namedParam.paramName
}
Object fileNameValue = namedParam.fileName
Object fileContentValue = namedParam.fileContent
String fileContentAsBytes = namedParam.fileContentAsBytes
String fileContentFromFileAsBytes = namedParam.fileContentFromFileAsBytes
String contentTypeCommand = namedParam.contentTypeCommand
String fileContentCommand = namedParam.fileContentCommand
String fileNameCommand = namedParam.fileNameCommand
Object contentTypeValue = namedParam.contentType
if (matcher && matcher.fileName) {
fileNameValue = matcher.fileName.regex ? Pattern.compile(matcher.fileName.regex) :
yamlContract.request.multipart.named.
each { YamlContract.Named namedParam ->
YamlContract.MultipartNamedStubMatcher matcher = yamlContract.request.matchers.multipart.named.
find {
it.paramName == namedParam.paramName
}
Object fileNameValue = namedParam.fileName
Object fileContentValue = namedParam.fileContent
String fileContentAsBytes = namedParam.fileContentAsBytes
String fileContentFromFileAsBytes = namedParam.fileContentFromFileAsBytes
String contentTypeCommand = namedParam.contentTypeCommand
String fileContentCommand = namedParam.fileContentCommand
String fileNameCommand = namedParam.fileNameCommand
Object contentTypeValue = namedParam.contentType
if (matcher && matcher.fileName) {
fileNameValue = matcher.fileName.regex ? Pattern.
compile(matcher.fileName.regex) :
predefinedToPattern(matcher.fileName.predefined)
}
if (matcher && matcher.fileContent) {
fileContentValue = matcher.fileContent.regex ? Pattern.compile(matcher.fileContent.regex) :
}
if (matcher && matcher.fileContent) {
fileContentValue = matcher.fileContent.regex ? Pattern.
compile(matcher.fileContent.regex) :
predefinedToPattern(matcher.fileContent.predefined)
}
if (matcher && matcher.contentType) {
contentTypeValue = matcher.contentType.regex ? Pattern.compile(matcher.contentType.regex) :
}
if (matcher && matcher.contentType) {
contentTypeValue = matcher.contentType.regex ? Pattern.
compile(matcher.contentType.regex) :
predefinedToPattern(matcher.contentType.predefined)
}
multipartMap.put(namedParam.paramName, new NamedProperty(
new DslProperty<>(fileNameValue, fileNameCommand ? new ExecutionProperty(fileNameCommand)
}
multipartMap.
put(namedParam.paramName, new NamedProperty(
new DslProperty<>(fileNameValue, fileNameCommand ? new ExecutionProperty(fileNameCommand)
: namedParam.fileName),
new DslProperty<>(fileContentValue, namedParam.fileContent ? namedParam.fileContent : fileContentFromFileAsBytes ? fileAsBytes(namedParam.fileContentFromFileAsBytes) : fileContentAsBytes ? fileContentAsBytes.bytes : new ExecutionProperty(fileContentCommand)),
new DslProperty(contentTypeValue, contentTypeCommand ? new ExecutionProperty(contentTypeCommand)
new DslProperty<>(fileContentValue, namedParam.fileContent ? namedParam.fileContent : fileContentFromFileAsBytes ?
fileAsBytes(namedParam.fileContentFromFileAsBytes) : fileContentAsBytes ? fileContentAsBytes.bytes : new ExecutionProperty(fileContentCommand)),
new DslProperty(contentTypeValue, contentTypeCommand ? new ExecutionProperty(contentTypeCommand)
: namedParam.contentType)))
}
}
multipart(multipartMap)
}
bodyMatchers {
yamlContract.request.matchers?.body?.each { YamlContract.BodyStubMatcher matcher ->
ContentType contentType =
yamlContract.request.matchers?.body?.
each { YamlContract.BodyStubMatcher matcher ->
ContentType contentType =
evaluateContentType(
yamlHeadersToContractHeaders(yamlContract.request?.headers),
yamlContract.request?.body)
MatchingTypeValue value = null
switch (matcher.type) {
yamlHeadersToContractHeaders(yamlContract.request?.headers),
yamlContract.request?.body)
MatchingTypeValue value = null
switch (matcher.type) {
case YamlContract.StubMatcherType.by_date:
value = byDate()
break
@@ -227,7 +270,9 @@ class YamlToContracts {
case YamlContract.StubMatcherType.by_regex:
String regex = matcher.value
if (matcher.predefined) {
regex = predefinedToPattern(matcher.predefined).pattern()
regex =
predefinedToPattern(matcher.predefined).
pattern()
}
value = byRegex(regex)
break
@@ -236,8 +281,12 @@ class YamlToContracts {
break
case YamlContract.StubMatcherType.by_type:
value = byType {
if (matcher.minOccurrence != null) minOccurrence(matcher.minOccurrence)
if (matcher.maxOccurrence != null) maxOccurrence(matcher.maxOccurrence)
if (matcher.minOccurrence != null) {
minOccurrence(matcher.minOccurrence)
}
if (matcher.maxOccurrence != null) {
maxOccurrence(matcher.maxOccurrence)
}
}
break
case YamlContract.StubMatcherType.by_null:
@@ -245,68 +294,87 @@ class YamlToContracts {
break
default:
throw new UnsupportedOperationException("The type [" + matcher.type + "] is unsupported. Hint: If you're using <predefined> remember to pass <type: by_regex>")
}
if (value) {
if (XML == contentType) {
xPath(matcher.path, value)
}
else {
jsonPath(matcher.path, value)
if (value) {
if (XML == contentType) {
xPath(matcher.path, value)
}
else {
jsonPath(matcher.path, value)
}
}
}
}
}
}
response {
status(yamlContract.response.status)
headers {
yamlContract.response?.headers?.each { String key, Object value ->
YamlContract.TestHeaderMatcher matcher = yamlContract.response.matchers.headers.find { it.key == key }
if (value instanceof List) {
((List) value).each {
Object serverValue = serverValue(it, matcher, key)
header(key, new DslProperty(it, serverValue))
yamlContract.response?.headers?.
each { String key, Object value ->
YamlContract.TestHeaderMatcher matcher = yamlContract.response.matchers.headers.
find { it.key == key }
if (value instanceof List) {
((List) value).each {
Object serverValue =
serverValue(it, matcher, key)
header(key, new DslProperty(it, serverValue))
}
}
else {
Object serverValue =
serverValue(value, matcher, key)
header(key, new DslProperty(value, serverValue))
}
} else {
Object serverValue = serverValue(value, matcher, key)
header(key, new DslProperty(value, serverValue))
}
}
}
if (yamlContract.response?.cookies) {
cookies {
yamlContract.response?.cookies?.each { String key, Object value ->
YamlContract.TestCookieMatcher matcher = yamlContract.response.matchers.cookies.find { it.key == key }
DslProperty cookieValue = serverCookieValue(value, matcher, key)
cookie(key, cookieValue)
}
yamlContract.response?.cookies?.
each { String key, Object value ->
YamlContract.TestCookieMatcher matcher = yamlContract.response.matchers.cookies.
find { it.key == key }
DslProperty cookieValue =
serverCookieValue(value, matcher, key)
cookie(key, cookieValue)
}
}
}
if (yamlContract.response.body != null) {
YamlContract.BodyTestMatcher bodyTestMatcher = yamlContract.response?.matchers?.body?.find {
it.path == null && (it.type == YamlContract.TestMatcherType.by_regex ||
it.type == YamlContract.TestMatcherType.by_command)
}
}
if (bodyTestMatcher) {
body(new DslProperty(yamlContract.response.body,
bodyTestMatcher.type == YamlContract.TestMatcherType.by_regex ?
Pattern.compile(bodyTestMatcher.value) : new ExecutionProperty(bodyTestMatcher.value)))
} else {
bodyTestMatcher.type == YamlContract.TestMatcherType.by_regex ?
Pattern.
compile(bodyTestMatcher.value) : new ExecutionProperty(bodyTestMatcher.value)))
}
else {
body(yamlContract.response.body)
}
}
if (yamlContract.response.bodyFromFile) body(file(yamlContract.response.bodyFromFile))
if (yamlContract.response.bodyFromFileAsBytes) body(fileAsBytes(yamlContract.response.bodyFromFileAsBytes))
if (yamlContract.response.async) async()
if (yamlContract.response.fixedDelayMilliseconds) fixedDelayMilliseconds(yamlContract.response.fixedDelayMilliseconds)
if (yamlContract.response.bodyFromFile) {
body(file(yamlContract.response.bodyFromFile))
}
if (yamlContract.response.bodyFromFileAsBytes) {
body(fileAsBytes(yamlContract.response.bodyFromFileAsBytes))
}
if (yamlContract.response.async) {
async()
}
if (yamlContract.response.fixedDelayMilliseconds) {
fixedDelayMilliseconds(yamlContract.response.fixedDelayMilliseconds)
}
bodyMatchers {
yamlContract.response?.matchers?.body?.each { YamlContract.BodyTestMatcher testMatcher ->
ContentType contentType =
yamlContract.response?.matchers?.body?.
each { YamlContract.BodyTestMatcher testMatcher ->
ContentType contentType =
evaluateContentType(
yamlHeadersToContractHeaders(yamlContract.response?.headers),
yamlContract.response?.body)
MatchingTypeValue value = null
switch (testMatcher.type) {
yamlHeadersToContractHeaders(yamlContract.response?.headers),
yamlContract.response?.body)
MatchingTypeValue value = null
switch (testMatcher.type) {
case YamlContract.TestMatcherType.by_date:
value = byDate()
break
@@ -319,7 +387,9 @@ class YamlToContracts {
case YamlContract.TestMatcherType.by_regex:
String regex = testMatcher.value
if (testMatcher.predefined) {
regex = predefinedToPattern(testMatcher.predefined).pattern()
regex =
predefinedToPattern(testMatcher.predefined).
pattern()
}
value = byRegex(regex)
break
@@ -328,8 +398,12 @@ class YamlToContracts {
break
case YamlContract.TestMatcherType.by_type:
value = byType() {
if (testMatcher.minOccurrence != null) minOccurrence(testMatcher.minOccurrence)
if (testMatcher.maxOccurrence != null) maxOccurrence(testMatcher.maxOccurrence)
if (testMatcher.minOccurrence != null) {
minOccurrence(testMatcher.minOccurrence)
}
if (testMatcher.maxOccurrence != null) {
maxOccurrence(testMatcher.maxOccurrence)
}
}
break
case YamlContract.TestMatcherType.by_command:
@@ -340,41 +414,57 @@ class YamlToContracts {
break
default:
throw new UnsupportedOperationException("The type [" + testMatcher.type + "] is unsupported. Hint: If you're using <predefined> remember to pass <type: by_regex>")
}
if (testMatcher.path) {
if (XML == contentType) {
xPath(testMatcher.path, value)
}
else {
jsonPath(testMatcher.path, value)
if (testMatcher.path) {
if (XML == contentType) {
xPath(testMatcher.path, value)
}
else {
jsonPath(testMatcher.path, value)
}
}
}
}
}
}
}
if (yamlContract.input) {
input {
if (yamlContract.input.messageFrom) messageFrom(yamlContract.input.messageFrom)
if (yamlContract.input.assertThat) assertThat(yamlContract.input.assertThat)
if (yamlContract.input.triggeredBy) triggeredBy(yamlContract.input.triggeredBy)
messageHeaders {
yamlContract.input?.messageHeaders?.each { String key, Object value ->
YamlContract.KeyValueMatcher matcher = yamlContract.input.matchers?.headers?.find { it.key == key }
header(key, clientValue(value, matcher, key))
}
if (yamlContract.input.messageFrom) {
messageFrom(yamlContract.input.messageFrom)
}
if (yamlContract.input.assertThat) {
assertThat(yamlContract.input.assertThat)
}
if (yamlContract.input.triggeredBy) {
triggeredBy(yamlContract.input.triggeredBy)
}
messageHeaders {
yamlContract.input?.messageHeaders?.
each { String key, Object value ->
YamlContract.KeyValueMatcher matcher = yamlContract.input.matchers?.headers?.
find { it.key == key }
header(key, clientValue(value, matcher, key))
}
}
if (yamlContract.input.messageBody) {
messageBody(yamlContract.input.messageBody)
}
if (yamlContract.input.messageBodyFromFile) {
messageBody(file(yamlContract.input.messageBodyFromFile))
}
if (yamlContract.input.messageBodyFromFileAsBytes) {
messageBody(
fileAsBytes(yamlContract.input.messageBodyFromFileAsBytes))
}
if (yamlContract.input.messageBody) messageBody(yamlContract.input.messageBody)
if (yamlContract.input.messageBodyFromFile) messageBody(file(yamlContract.input.messageBodyFromFile))
if (yamlContract.input.messageBodyFromFileAsBytes) messageBody(fileAsBytes(yamlContract.input.messageBodyFromFileAsBytes))
bodyMatchers {
yamlContract.input.matchers.body?.each { YamlContract.BodyStubMatcher matcher ->
ContentType contentType =
yamlContract.input.matchers.body?.
each { YamlContract.BodyStubMatcher matcher ->
ContentType contentType =
evaluateContentType(
yamlHeadersToContractHeaders(yamlContract.input?.messageHeaders),
yamlContract.input?.messageBody)
MatchingTypeValue value = null
switch (matcher.type) {
yamlHeadersToContractHeaders(yamlContract.input?.messageHeaders),
yamlContract.input?.messageBody)
MatchingTypeValue value = null
switch (matcher.type) {
case YamlContract.StubMatcherType.by_date:
value = byDate()
break
@@ -387,7 +477,9 @@ class YamlToContracts {
case YamlContract.StubMatcherType.by_regex:
String regex = matcher.value
if (matcher.predefined) {
regex = predefinedToPattern(matcher.predefined).pattern()
regex =
predefinedToPattern(matcher.predefined).
pattern()
}
value = byRegex(regex)
break
@@ -396,41 +488,53 @@ class YamlToContracts {
break
default:
throw new UnsupportedOperationException("The type [" + matcher.type + "] is unsupported. Hint: If you're using <predefined> remember to pass <type: by_regex>")
}
if (XML == contentType) {
xPath(matcher.path, value)
}
else {
jsonPath(matcher.path, value)
}
}
if (XML == contentType) {
xPath(matcher.path, value)
}
else {
jsonPath(matcher.path, value)
}
}
}
}
}
YamlContract.OutputMessage outputMsg = yamlContract.outputMessage
if (outputMsg) {
outputMessage {
if (outputMsg.assertThat) assertThat(outputMsg.assertThat)
if (outputMsg.sentTo) sentTo(outputMsg.sentTo)
if (outputMsg.assertThat) {
assertThat(outputMsg.assertThat)
}
if (outputMsg.sentTo) {
sentTo(outputMsg.sentTo)
}
headers {
outputMsg.headers?.each { String key, Object value ->
YamlContract.TestHeaderMatcher matcher = outputMsg.matchers?.headers?.find { it.key == key }
YamlContract.TestHeaderMatcher matcher = outputMsg.matchers?.headers?.
find { it.key == key }
Object serverValue = serverValue(value, matcher, key)
header(key, new DslProperty(value, serverValue))
}
}
if (outputMsg.body) body(outputMsg.body)
if (outputMsg.bodyFromFile) body(file(outputMsg.bodyFromFile))
if (outputMsg.bodyFromFileAsBytes) body(fileAsBytes(outputMsg.bodyFromFileAsBytes))
if (outputMsg.body) {
body(outputMsg.body)
}
if (outputMsg.bodyFromFile) {
body(file(outputMsg.bodyFromFile))
}
if (outputMsg.bodyFromFileAsBytes) {
body(fileAsBytes(outputMsg.bodyFromFileAsBytes))
}
if (outputMsg.matchers) {
bodyMatchers {
yamlContract.outputMessage?.matchers?.body?.each { YamlContract.BodyTestMatcher testMatcher ->
ContentType contentType =
yamlContract.outputMessage?.matchers?.body?.
each { YamlContract.BodyTestMatcher testMatcher ->
ContentType contentType =
evaluateContentType(
yamlHeadersToContractHeaders(yamlContract.outputMessage?.headers),
yamlContract.outputMessage?.body)
MatchingTypeValue value = null
switch (testMatcher.type) {
yamlHeadersToContractHeaders(yamlContract.outputMessage?.headers),
yamlContract.outputMessage?.body)
MatchingTypeValue value = null
switch (testMatcher.type) {
case YamlContract.TestMatcherType.by_date:
value = byDate()
break
@@ -443,7 +547,9 @@ class YamlToContracts {
case YamlContract.TestMatcherType.by_regex:
String regex = testMatcher.value
if (testMatcher.predefined) {
regex = predefinedToPattern(testMatcher.predefined).pattern()
regex =
predefinedToPattern(testMatcher.predefined).
pattern()
}
value = byRegex(regex)
break
@@ -452,8 +558,12 @@ class YamlToContracts {
break
case YamlContract.TestMatcherType.by_type:
value = byType() {
if (testMatcher.minOccurrence != null) minOccurrence(testMatcher.minOccurrence)
if (testMatcher.maxOccurrence != null) maxOccurrence(testMatcher.maxOccurrence)
if (testMatcher.minOccurrence != null) {
minOccurrence(testMatcher.minOccurrence)
}
if (testMatcher.maxOccurrence != null) {
maxOccurrence(testMatcher.maxOccurrence)
}
}
break
case YamlContract.TestMatcherType.by_command:
@@ -464,14 +574,14 @@ class YamlToContracts {
break
default:
throw new UnsupportedOperationException("The type [" + testMatcher.type + "] is unsupported. Hint: If you're using <predefined> remember to pass <type: by_regex>")
}
if (XML == contentType) {
xPath(testMatcher.path, value)
}
else {
jsonPath(testMatcher.path, value)
}
}
if (XML == contentType) {
xPath(testMatcher.path, value)
}
else {
jsonPath(testMatcher.path, value)
}
}
}
}
}
@@ -484,8 +594,8 @@ class YamlToContracts {
private Headers yamlHeadersToContractHeaders(Map<String, Object> headers) {
Set<Header> convertedHeaders = headers.keySet().stream()
.map({ new Header(it, headers.get(it)) })
.collect(toSet())
.map({ new Header(it, headers.get(it)) })
.collect(toSet())
Headers contractHeaders = new Headers()
contractHeaders.headers(convertedHeaders)
return contractHeaders
@@ -497,7 +607,8 @@ class YamlToContracts {
return new DslProperty<Object>(url, new ExecutionProperty(urlMatcher.command))
}
return new DslProperty(urlMatcher.regex ? Pattern.compile(urlMatcher.regex) :
urlMatcher.predefined ? predefinedToPattern(urlMatcher.predefined) : url, url)
urlMatcher.predefined ?
predefinedToPattern(urlMatcher.predefined) : url, url)
}
return new DslProperty(url)
}
@@ -505,7 +616,8 @@ class YamlToContracts {
protected List<YamlContract> convert(ObjectMapper mapper, Object o) {
try {
return Arrays.asList(mapper.convertValue(o, YamlContract[].class))
} catch(IllegalArgumentException e) {
}
catch (IllegalArgumentException e) {
return Collections.singletonList(mapper.convertValue(o, YamlContract.class))
}
}
@@ -516,11 +628,13 @@ class YamlToContracts {
serverValue = Pattern.compile(matcher.regex)
Pattern pattern = (Pattern) serverValue
assertPatternMatched(pattern, value, key)
} else if (matcher?.predefined) {
}
else if (matcher?.predefined) {
Pattern pattern = predefinedToPattern(matcher.predefined)
serverValue = pattern
assertPatternMatched(pattern, value, key)
} else if (matcher?.command) {
}
else if (matcher?.command) {
serverValue = new ExecutionProperty(matcher.command)
}
return serverValue
@@ -532,11 +646,13 @@ class YamlToContracts {
serverValue = Pattern.compile(matcher.regex)
Pattern pattern = (Pattern) serverValue
assertPatternMatched(pattern, value, key)
} else if (matcher?.predefined) {
}
else if (matcher?.predefined) {
Pattern pattern = predefinedToPattern(matcher.predefined)
serverValue = pattern
assertPatternMatched(pattern, value, key)
} else if (matcher?.command) {
}
else if (matcher?.command) {
return new DslProperty(new ExecutionProperty(matcher.command), value)
}
return new DslProperty(value, serverValue)
@@ -548,11 +664,13 @@ class YamlToContracts {
clientValue = Pattern.compile(matcher.regex)
Pattern pattern = (Pattern) clientValue
assertPatternMatched(pattern, value, key)
} else if (matcher?.predefined) {
}
else if (matcher?.predefined) {
Pattern pattern = predefinedToPattern(matcher.predefined)
clientValue = pattern
assertPatternMatched(pattern, value, key)
} else if (matcher?.command) {
}
else if (matcher?.command) {
return new DslProperty(value, new ExecutionProperty(matcher.command))
}
return new DslProperty(clientValue, value)
@@ -561,27 +679,29 @@ class YamlToContracts {
protected Object queryParamValue(YamlContract yamlContract, String key, Object value) {
Request request = new Request()
YamlContract.QueryParameterMatcher matcher = yamlContract.request.
matchers.queryParameters.find { it.key == key}
matchers.queryParameters.find { it.key == key }
if (!matcher) {
return value
}
switch (matcher.type) {
case YamlContract.MatchingType.equal_to:
return new DslProperty(request.equalTo(matcher.value), value)
case YamlContract.MatchingType.containing:
return new DslProperty(request.containing(matcher.value), value)
case YamlContract.MatchingType.matching:
return new DslProperty(request.matching(matcher.value), value)
case YamlContract.MatchingType.not_matching:
return new DslProperty(request.notMatching(matcher.value), value)
case YamlContract.MatchingType.equal_to_json:
return new DslProperty(request.equalToJson(matcher.value), value)
case YamlContract.MatchingType.equal_to_xml:
return new DslProperty(request.equalToXml(matcher.value), value)
case YamlContract.MatchingType.absent:
return new DslProperty(request.absent(), null)
default:
throw new UnsupportedOperationException("The provided matching type [" + matcher + "] is unsupported. Use on of " + YamlContract.MatchingType.values())
case YamlContract.MatchingType.equal_to:
return new DslProperty(request.equalTo(matcher.value), value)
case YamlContract.MatchingType.containing:
return new DslProperty(request.containing(matcher.value), value)
case YamlContract.MatchingType.matching:
return new DslProperty(request.matching(matcher.value), value)
case YamlContract.MatchingType.not_matching:
return new DslProperty(request.notMatching(matcher.value), value)
case YamlContract.MatchingType.equal_to_json:
return new DslProperty(request.equalToJson(matcher.value), value)
case YamlContract.MatchingType.equal_to_xml:
return new DslProperty(request.equalToXml(matcher.value), value)
case YamlContract.MatchingType.absent:
return new DslProperty(request.absent(), null)
default:
throw new UnsupportedOperationException("The provided matching type [" + matcher + "] is unsupported. Use on of "
+ YamlContract.MatchingType.
values())
}
}
@@ -591,55 +711,61 @@ class YamlToContracts {
return new ExecutionProperty(matcher.command)
}
return serverValue instanceof DslProperty ?
((DslProperty) serverValue).serverValue : serverValue
((DslProperty) serverValue).serverValue : serverValue
}
private void assertPatternMatched(Pattern pattern, value, String key) {
boolean matches = pattern.matcher(value.toString()).matches()
if (!matches) throw new IllegalStateException("Broken headers! A header with " +
if (!matches) {
throw new IllegalStateException("Broken headers! A header with "
+
"key [${key}] with value [${value}] is not matched by regex [${pattern.pattern()}]")
}
}
protected Pattern predefinedToPattern(YamlContract.PredefinedRegex predefinedRegex) {
RegexPatterns patterns = new RegexPatterns()
switch (predefinedRegex) {
case YamlContract.PredefinedRegex.only_alpha_unicode:
return patterns.onlyAlphaUnicode().pattern
case YamlContract.PredefinedRegex.number:
return patterns.number().pattern
case YamlContract.PredefinedRegex.any_double:
return patterns.aDouble().pattern
case YamlContract.PredefinedRegex.any_boolean:
return patterns.anyBoolean().pattern
case YamlContract.PredefinedRegex.ip_address:
return patterns.ipAddress().pattern
case YamlContract.PredefinedRegex.hostname:
return patterns.hostname().pattern
case YamlContract.PredefinedRegex.email:
return patterns.email().pattern
case YamlContract.PredefinedRegex.url:
return patterns.url().pattern
case YamlContract.PredefinedRegex.uuid:
return patterns.uuid().pattern
case YamlContract.PredefinedRegex.iso_date:
return patterns.isoDate().pattern
case YamlContract.PredefinedRegex.iso_date_time:
return patterns.isoDateTime().pattern
case YamlContract.PredefinedRegex.iso_time:
return patterns.isoTime().pattern
case YamlContract.PredefinedRegex.iso_8601_with_offset:
return patterns.iso8601WithOffset().pattern
case YamlContract.PredefinedRegex.non_empty:
return patterns.nonEmpty().pattern
case YamlContract.PredefinedRegex.non_blank:
return patterns.nonBlank().pattern
default:
throw new UnsupportedOperationException("The predefined regex [" + predefinedRegex + "] is unsupported. Use on of " + YamlContract.PredefinedRegex.values())
case YamlContract.PredefinedRegex.only_alpha_unicode:
return patterns.onlyAlphaUnicode().pattern
case YamlContract.PredefinedRegex.number:
return patterns.number().pattern
case YamlContract.PredefinedRegex.any_double:
return patterns.aDouble().pattern
case YamlContract.PredefinedRegex.any_boolean:
return patterns.anyBoolean().pattern
case YamlContract.PredefinedRegex.ip_address:
return patterns.ipAddress().pattern
case YamlContract.PredefinedRegex.hostname:
return patterns.hostname().pattern
case YamlContract.PredefinedRegex.email:
return patterns.email().pattern
case YamlContract.PredefinedRegex.url:
return patterns.url().pattern
case YamlContract.PredefinedRegex.uuid:
return patterns.uuid().pattern
case YamlContract.PredefinedRegex.iso_date:
return patterns.isoDate().pattern
case YamlContract.PredefinedRegex.iso_date_time:
return patterns.isoDateTime().pattern
case YamlContract.PredefinedRegex.iso_time:
return patterns.isoTime().pattern
case YamlContract.PredefinedRegex.iso_8601_with_offset:
return patterns.iso8601WithOffset().pattern
case YamlContract.PredefinedRegex.non_empty:
return patterns.nonEmpty().pattern
case YamlContract.PredefinedRegex.non_blank:
return patterns.nonBlank().pattern
default:
throw new UnsupportedOperationException("The predefined regex [" + predefinedRegex + "] is unsupported. Use on of "
+ YamlContract.PredefinedRegex.
values())
}
}
protected String file(String relativePath) {
URL resource = Thread.currentThread().getContextClassLoader().getResource(relativePath)
URL resource = Thread.currentThread().getContextClassLoader().
getResource(relativePath)
if (resource == null) {
throw new IllegalStateException("File [${relativePath}] is not present")
}
@@ -648,7 +774,7 @@ class YamlToContracts {
protected static ClassLoader updatedClassLoader(File rootFolder, ClassLoader classLoader) {
ClassLoader urlCl = URLClassLoader
.newInstance([rootFolder.toURI().toURL()] as URL[], classLoader)
.newInstance([rootFolder.toURI().toURL()] as URL[], classLoader)
Thread.currentThread().setContextClassLoader(urlCl)
return urlCl
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -71,9 +71,9 @@ abstract class BaseWireMockStubStrategy {
}
/**
* Returns the stub side values from the object
* @return the stub side values from the object
*/
protected getStubSideValue(Object object) {
protected Object getStubSideValue(Object object) {
return MapConverter.getStubSideValues(object)
}
@@ -139,7 +139,9 @@ abstract class BaseWireMockStubStrategy {
return it
}
return "${WRAPPER}${it}${WRAPPER}"
} else if (it instanceof String && processor.containsTemplateEntry(it) &&
}
else if (it instanceof String && processor.containsTemplateEntry(it)
&&
template.escapedBody() == it) {
return template.escapedBody()
}
@@ -155,7 +157,8 @@ abstract class BaseWireMockStubStrategy {
list.each {
if (it instanceof Map) {
result += MapConverter.getStubSideValues(it)
} else {
}
else {
result += parseBody(it, contentType)
}
}
@@ -166,7 +169,8 @@ abstract class BaseWireMockStubStrategy {
* For the given {@link ContentType} returns the String version of the body
*/
String parseBody(GString value, ContentType contentType) {
Object processedValue = extractValue(value, contentType, { Object o -> o instanceof DslProperty ? o.clientValue : o })
Object processedValue =
extractValue(value, contentType, { Object o -> o instanceof DslProperty ? o.clientValue : o })
if (processedValue instanceof GString) {
return parseBody(processedValue.toString(), contentType)
}
@@ -185,7 +189,8 @@ abstract class BaseWireMockStubStrategy {
Map convertedMap = MapConverter.transformValues(value) {
it instanceof GString ? it.toString() : it
} as Map
String jsonOutput = new JSONObject(new JsonBuilder(convertedMap).toString()).toString()
String jsonOutput = new JSONObject(new JsonBuilder(convertedMap).toString()).
toString()
return jsonOutput.replaceAll("\\\\\\\\\\\\", "\\\\")
}
return new JsonBuilder(value).toString()
@@ -205,4 +210,4 @@ abstract class BaseWireMockStubStrategy {
}
return contentType
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.extension.responsetemplating.ResponseTemplateTransformer

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.List;
@@ -5,12 +21,14 @@ import java.util.List;
import com.github.tomakehurst.wiremock.extension.Extension;
/**
* Contract that describes a list of {@link Extension} extensions
* that should be applied to the response
* Contract that describes a list of {@link Extension} extensions that should be applied
* to the response.
*
* @author Marcin Grzejszczak
* @since 1.2.0
*/
public interface WireMockExtensions {
List<Extension> extensions();
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -89,7 +89,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
@PackageScope
RequestPattern buildClientRequestContent() {
if(!request) {
if (!request) {
return null
}
RequestPatternBuilder requestPatternBuilder = appendMethodAndUrl()
@@ -102,10 +102,11 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
private RequestPatternBuilder appendMethodAndUrl() {
if(!request.method) {
if (!request.method) {
return null
}
RequestMethod requestMethod = RequestMethod.fromString(request.method.clientValue?.toString())
RequestMethod requestMethod = RequestMethod.
fromString(request.method.clientValue?.toString())
UrlPattern urlPattern = urlPattern()
return RequestPatternBuilder.newRequestPattern(requestMethod, urlPattern)
}
@@ -117,20 +118,28 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
MatchingStrategy matchingStrategy = getMatchingStrategyFromBody(request.body)
if (contentType == ContentType.JSON) {
def originalBody = matchingStrategy?.clientValue
def body = JsonToJsonPathsConverter.removeMatchingJsonPaths(originalBody, request.bodyMatchers)
JsonPaths values = JsonToJsonPathsConverter.transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(body)
if ((values.empty && !request.bodyMatchers?.hasMatchers()) || onlySizeAssertionsArePresent(values)) {
def body = JsonToJsonPathsConverter.
removeMatchingJsonPaths(originalBody, request.bodyMatchers)
JsonPaths values = JsonToJsonPathsConverter.
transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(body)
if ((values.empty && !request.bodyMatchers?.hasMatchers())
||
onlySizeAssertionsArePresent(values)) {
requestPattern.withRequestBody(WireMock.equalToJson(JsonOutput.toJson(
getMatchingStrategy(request.body.clientValue).clientValue),
false, false))
} else {
values.findAll{ !it.assertsSize() }.each {
requestPattern.withRequestBody(WireMock.matchingJsonPath(it.jsonPath().replace("\\\\", "\\")))
}
else {
values.findAll { !it.assertsSize() }.each {
requestPattern.withRequestBody(WireMock.
matchingJsonPath(it.jsonPath().replace("\\\\", "\\")))
}
}
request.bodyMatchers?.matchers()?.each {
String newPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(it, originalBody)
requestPattern.withRequestBody(WireMock.matchingJsonPath(newPath.replace("\\\\", "\\")))
String newPath = JsonToJsonPathsConverter.
convertJsonPathAndRegexToAJsonPath(it, originalBody)
requestPattern.withRequestBody(WireMock.
matchingJsonPath(newPath.replace("\\\\", "\\")))
}
}
else if (contentType == ContentType.XML) {
@@ -145,10 +154,12 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
request.bodyMatchers?.matchers()?.each {
addWireMockStubMatchingSection(it, requestPattern, originalBody)
}
} else if (containsPattern(request?.body)) {
}
else if (containsPattern(request?.body)) {
requestPattern.withRequestBody(
convertToValuePattern(appendBodyRegexpMatchPattern(request.body)))
} else {
}
else {
requestBodyGuessedFromMatchingStrategy(requestPattern)
}
}
@@ -159,8 +170,8 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
private static void addWireMockStubMatchingSection(BodyMatcher matcher,
RequestPatternBuilder requestPattern,
Object body) {
RequestPatternBuilder requestPattern,
Object body) {
Set<MatchingType> matchingTypesUnsupportedForRequest = [NULL, COMMAND, TYPE] as Set
if (!matcher instanceof PathBodyMatcher) {
throw new IllegalArgumentException("Only jsonPath and XPath matchers can be processed.")
@@ -184,7 +195,8 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
private boolean onlySizeAssertionsArePresent(JsonPaths values) {
return !values.empty && !request.bodyMatchers?.hasMatchers() && values.every { it.assertsSize() }
return !values.empty && !request.bodyMatchers?.hasMatchers() && values.
every { it.assertsSize() }
}
private void appendMultipart(RequestPatternBuilder requestPattern) {
@@ -192,13 +204,16 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
return
}
if (request.multipart.clientValue instanceof Map) {
List<StringValuePattern> multipartPatterns = (request.multipart.clientValue as Map).collect {
(it.value instanceof NamedProperty
? WireMock.matching(RegexPatterns.multipartFile(it.key, (it.value as NamedProperty).name.clientValue,
(it.value as NamedProperty).value.clientValue,
(it.value as NamedProperty).contentType?.clientValue))
: WireMock.matching(RegexPatterns.multipartParam(it.key, it.value)) )
}
List<StringValuePattern> multipartPatterns = (request.multipart.clientValue as Map).
collect {
(it.value instanceof NamedProperty
? WireMock.matching(RegexPatterns.
multipartFile(it.key, (it.value as NamedProperty).name.clientValue,
(it.value as NamedProperty).value.clientValue,
(it.value as NamedProperty).contentType?.clientValue))
: WireMock.
matching(RegexPatterns.multipartParam(it.key, it.value)))
}
multipartPatterns.each {
requestPattern.withRequestBody(it)
}
@@ -206,7 +221,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
private void appendHeaders(RequestPatternBuilder requestPattern) {
if(!request.headers) {
if (!request.headers) {
return
}
request.headers.entries.each {
@@ -216,7 +231,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
private void appendCookies(RequestPatternBuilder requestPattern) {
if(!request.cookies) {
if (!request.cookies) {
return
}
request.cookies.entries.each {
@@ -228,13 +243,16 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
private UrlPattern urlPattern() {
Object urlPath = urlPathOrUrlIfQueryPresent()
if (urlPath) {
if(urlPath instanceof Pattern || urlPath instanceof RegexProperty) {
return WireMock.urlPathMatching(getStubSideValue(new RegexProperty(urlPath).pattern()) as String)
} else {
return WireMock.urlPathEqualTo(getStubSideValue(urlPath.toString()) as String)
if (urlPath instanceof Pattern || urlPath instanceof RegexProperty) {
return WireMock.urlPathMatching(
getStubSideValue(new RegexProperty(urlPath).pattern()) as String)
}
else {
return WireMock.
urlPathEqualTo(getStubSideValue(urlPath.toString()) as String)
}
}
if(!request.url) {
if (!request.url) {
throw new IllegalStateException("URL is required!")
}
Object url = getUrlIfGstring(request?.url?.clientValue)
@@ -264,7 +282,8 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}) {
String string = getStubSideValue(clientSide).toString()
return new RegexProperty(Pattern.compile(string))
} else {
}
else {
return getStubSideValue(clientSide).toString()
}
}
@@ -282,29 +301,31 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
@TypeChecked(TypeCheckingMode.SKIP)
private ContentPattern convertToValuePattern(Object object) {
switch (object) {
case Pattern:
case RegexProperty:
return WireMock.matching(new RegexProperty(object).pattern())
case OptionalProperty:
OptionalProperty value = object as OptionalProperty
return WireMock.matching(value.optionalPattern())
case MatchingStrategy:
MatchingStrategy value = object as MatchingStrategy
switch (value.type) {
case MatchingStrategy.Type.NOT_MATCHING:
return WireMock.notMatching(value.clientValue.toString())
case MatchingStrategy.Type.ABSENT:
return WireMock.absent()
default:
try {
return WireMock."${value.type.name}"(clientBody(value.clientValue, contentType))
} catch (Throwable t) {
log.error("Exception occurred while trying to call WireMock.${value.type.name}(${value.clientValue})", t)
throw t
}
}
case Pattern:
case RegexProperty:
return WireMock.matching(new RegexProperty(object).pattern())
case OptionalProperty:
OptionalProperty value = object as OptionalProperty
return WireMock.matching(value.optionalPattern())
case MatchingStrategy:
MatchingStrategy value = object as MatchingStrategy
switch (value.type) {
case MatchingStrategy.Type.NOT_MATCHING:
return WireMock.notMatching(value.clientValue.toString())
case MatchingStrategy.Type.ABSENT:
return WireMock.absent()
default:
return WireMock.equalTo(object.toString())
try {
return WireMock."${value.type.name}"(
clientBody(value.clientValue, contentType))
}
catch (Throwable t) {
log.error("Exception occurred while trying to call WireMock.${value.type.name}(${value.clientValue})", t)
throw t
}
}
default:
return WireMock.equalTo(object.toString())
}
}
@@ -313,9 +334,11 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
if (bodyValue instanceof Map) {
// [a:3, b:4] == "a=3&b=4"
return ((Map) bodyValue).collect {
StringEscapeUtils.unescapeJavaScript(it.key.toString() + "=" + it.value)
StringEscapeUtils.
unescapeJavaScript(it.key.toString() + "=" + it.value)
}.join("&")
} else if (bodyValue instanceof List) {
}
else if (bodyValue instanceof List) {
// ["a=3", "b=4"] == "a=3&b=4"
return ((List) bodyValue).collect {
StringEscapeUtils.unescapeJavaScript(it.toString())
@@ -329,7 +352,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
}
private MatchingStrategy getMatchingStrategyFromBody(Body body) {
if(!body) {
if (!body) {
return null
}
return getMatchingStrategy(body.clientValue)
@@ -338,6 +361,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
private MatchingStrategy getMatchingStrategy(MatchingStrategy matchingStrategy) {
return getMatchingStrategyIncludingContentType(matchingStrategy)
}
private MatchingStrategy getMatchingStrategy(GString gString) {
if (!gString) {
return new MatchingStrategy("", MatchingStrategy.Type.EQUAL_TO)
@@ -369,7 +393,8 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
private MatchingStrategy getMatchingStrategyIncludingContentType(MatchingStrategy matchingStrategy) {
MatchingStrategy.Type type = matchingStrategy.type
Object value = matchingStrategy.clientValue
ContentType contentType = ContentUtils.recognizeContentTypeFromMatchingStrategy(type)
ContentType contentType = ContentUtils.
recognizeContentTypeFromMatchingStrategy(type)
if (contentType == ContentType.UNKNOWN && type == MatchingStrategy.Type.EQUAL_TO) {
contentType = ContentUtils.recognizeContentTypeFromContent(value)
type = getEqualsTypeFromContentType(contentType)
@@ -379,12 +404,14 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
private MatchingStrategy appendBodyRegexpMatchPattern(Object value, ContentType contentType) {
switch (contentType) {
case ContentType.JSON:
return new MatchingStrategy(buildJSONRegexpMatch(value), MatchingStrategy.Type.MATCHING)
case ContentType.UNKNOWN:
return new MatchingStrategy(buildGStringRegexpForStubSide(value), MatchingStrategy.Type.MATCHING)
case ContentType.XML:
throw new IllegalStateException("XML pattern matching is not implemented yet")
case ContentType.JSON:
return new MatchingStrategy(
buildJSONRegexpMatch(value), MatchingStrategy.Type.MATCHING)
case ContentType.UNKNOWN:
return new MatchingStrategy(
buildGStringRegexpForStubSide(value), MatchingStrategy.Type.MATCHING)
case ContentType.XML:
throw new IllegalStateException("XML pattern matching is not implemented yet")
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -55,7 +55,7 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
@PackageScope
ResponseDefinition buildClientResponseContent() {
if(!response) {
if (!response) {
return null
}
ResponseDefinitionBuilder builder = new ResponseDefinitionBuilder()
@@ -68,12 +68,13 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
}
private String[] responseTransformerNames() {
List<WireMockExtensions> wireMockExtensions = SpringFactoriesLoader.loadFactories(WireMockExtensions, null)
List<WireMockExtensions> wireMockExtensions = SpringFactoriesLoader.
loadFactories(WireMockExtensions, null)
if (wireMockExtensions) {
return ((List<Extension>) wireMockExtensions
.collect { WireMockExtensions extension -> extension.extensions() }
.collect { WireMockExtensions extension -> extension.extensions() }
.flatten())
.collect { Extension e -> e.getName()} as String[]
.collect { Extension e -> e.getName() } as String[]
}
return [new DefaultResponseTransformer().getName()] as String[]
}
@@ -81,7 +82,8 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
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())
new HttpHeader(it.name, MapConverter.getStubSideValues(it.clientValue).
toString())
}))
}
}
@@ -92,9 +94,11 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
ContentType contentType = evaluateContentType(response.headers, body)
if (body instanceof byte[]) {
builder.withBody(body)
} else if (body instanceof FromFileProperty && body.isByte()) {
}
else if (body instanceof FromFileProperty && body.isByte()) {
builder.withBody(body.asBytes())
} else {
}
else {
builder.withBody(parseBody(body, contentType))
}
}
@@ -107,5 +111,4 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy {
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.stubbing.StubMapping;
@@ -5,8 +21,14 @@ import com.github.tomakehurst.wiremock.stubbing.StubMapping;
/**
* @author Marcin Grzejszczak
*/
public class WireMockStubMapping {
public final class WireMockStubMapping {
private WireMockStubMapping() {
throw new IllegalStateException("Can't instantiate a utility class");
}
public static StubMapping buildFrom(String mappingDefinition) {
return StubMapping.buildFrom(mappingDefinition);
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -22,6 +22,7 @@ import com.github.tomakehurst.wiremock.stubbing.StubMapping
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.file.ContractMetadata
/**
* Converts a {@link ContractMetadata} into a WireMock stub
*
@@ -54,7 +55,8 @@ class WireMockStubStrategy {
StubMapping stubMapping = new StubMapping()
RequestPattern request = wireMockRequestStubStrategy.buildClientRequestContent()
ResponseDefinition response = wireMockResponseStubStrategy.buildClientResponseContent()
ResponseDefinition response = wireMockResponseStubStrategy.
buildClientResponseContent()
if (priority) {
stubMapping.priority = priority
}
@@ -79,4 +81,4 @@ class WireMockStubStrategy {
}
return StubMapping.buildJsonStringFor(stubMapping)
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2018-2019 the original author or authors.
* Copyright 2018-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -35,8 +35,8 @@ class XPathBodyMatcherToWireMockValuePatternConverter {
static StringValuePattern mapToPattern(MatchingType type, String value) {
switch (type) {
case EQUALITY: return WireMock.equalTo(value)
default: return WireMock.matching(value)
case EQUALITY: return WireMock.equalTo(value)
default: return WireMock.matching(value)
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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
@@ -32,6 +32,7 @@ import org.springframework.cloud.contract.spec.ContractConverter
import org.springframework.cloud.contract.verifier.converter.YamlContractConverter
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter
import org.springframework.core.io.support.SpringFactoriesLoader
/**
* Scans the provided file path for the DSLs. There's a possibility to provide
* inclusion and exclusion filters.
@@ -46,10 +47,12 @@ class ContractFileScanner {
private static final String OS_NAME = System.getProperty("os.name")
private static final String OS_NAME_WINDOWS_PREFIX = "Windows"
protected static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX)
protected static final boolean IS_OS_WINDOWS =
getOSMatchesName(OS_NAME_WINDOWS_PREFIX)
private static final String MATCH_PREFIX = "glob:"
private static final Pattern SCENARIO_STEP_FILENAME_PATTERN = Pattern.compile("[0-9]+_.*")
private static final Pattern SCENARIO_STEP_FILENAME_PATTERN = Pattern.
compile("[0-9]+_.*")
private final File baseDir
private final Set<PathMatcher> excludeMatchers
private final Set<PathMatcher> ignoreMatchers
@@ -57,8 +60,8 @@ class ContractFileScanner {
private final String includeMatcher
ContractFileScanner(File baseDir, Set<String> excluded, Set<String> ignored,
Set<String> included = [],
String includeMatcher = "") {
Set<String> included = [],
String includeMatcher = "") {
this.baseDir = baseDir
this.excludeMatchers = processPatterns(excluded ?: [] as Set<String>)
this.ignoreMatchers = processPatterns(ignored ?: [] as Set<String>)
@@ -81,7 +84,7 @@ class ContractFileScanner {
}
/**
* Returns for a map of paths for which a list of matching contracts has been found
* @return for a map of paths for which a list of matching contracts has been found
*/
ListMultimap<Path, ContractMetadata> findContracts() {
ListMultimap<Path, ContractMetadata> result = ArrayListMultimap.create()
@@ -108,20 +111,25 @@ class ContractFileScanner {
boolean excluded = matchesPattern(file, excludeMatchers)
if (!excluded) {
boolean contractFile = isContractFile(file)
boolean included = includeMatcher ? file.absolutePath.matches(includeMatcher) : true
included = includeMatchers ? matchesPattern(file, includeMatchers) : included
boolean included = includeMatcher ? file.absolutePath.
matches(includeMatcher) : true
included = includeMatchers ?
matchesPattern(file, includeMatchers) : included
if (contractFile && included) {
addContractToTestGeneration(result, files, file, i, ContractVerifierDslConverter.convertAsCollection(baseDir, file))
addContractToTestGeneration(result, files, file, i, ContractVerifierDslConverter.
convertAsCollection(baseDir, file))
}
if (!contractFile && included) {
addContractToTestGeneration(converters, result, files, file, i)
} else {
}
else {
appendRecursively(file, result)
if (log.isDebugEnabled()) {
log.debug("File [$file] is ignored. Is a contract file? [$contractFile]. Should be included by pattern? [$included]")
}
}
} else {
}
else {
if (log.isDebugEnabled()) {
log.debug("File [$file] is ignored. Should be excluded? [$excluded]")
}
@@ -140,7 +148,7 @@ class ContractFileScanner {
}
private void addContractToTestGeneration(List<ContractConverter> converters, ListMultimap<Path, ContractMetadata> result,
File[] files, File file, int index) {
File[] files, File file, int index) {
boolean converted = false
if (!file.isDirectory()) {
for (ContractConverter converter : converters) {
@@ -167,20 +175,22 @@ class ContractFileScanner {
}
try {
return converter.convertFrom(file)
} catch (Exception e) {
}
catch (Exception e) {
throw new IllegalStateException("Failed to convert file [" + file + "]", e)
}
}
private void addContractToTestGeneration(ListMultimap<Path, ContractMetadata> result, File[] files, File file,
int index, Collection<Contract> convertedContract) {
int index, Collection<Contract> convertedContract) {
Path path = file.toPath()
Integer order = null
if (hasScenarioFilenamePattern(path)) {
order = index
}
Path parent = file.parentFile.toPath()
ContractMetadata metadata = new ContractMetadata(path, matchesPattern(file, ignoreMatchers),
ContractMetadata metadata = new ContractMetadata(path,
matchesPattern(file, ignoreMatchers),
files.size(), order, convertedContract)
if (log.isDebugEnabled()) {
log.debug("Creating a contract entry for path [" + path + "] and metadata [" + metadata + "]")

View File

@@ -1,23 +1,24 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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 groovy.transform.CompileStatic
/**
* Scans the provided file path for the DSLs. There's a possibility to provide
* inclusion and exclusion filters.
@@ -62,10 +63,10 @@ class ContractFileScannerBuilder {
ContractFileScanner build() {
return new ContractFileScanner(this.baseDir,
this.excluded,
this.ignored,
this.included,
this.includeMatcher)
this.excluded,
this.ignored,
this.included,
this.includeMatcher)
}
}

View File

@@ -1,28 +1,29 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter
import java.nio.file.Path
import org.springframework.cloud.contract.spec.Contract
/**
* Contains metadata for a particular file with a DSL
*

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.template
import java.util.regex.Matcher
@@ -23,12 +39,16 @@ import org.springframework.cloud.contract.verifier.builder.handlebars.Handlebars
@CompileStatic
class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate {
private static final Pattern ESCAPED_LEGACY_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{\\{jsonpath this '(.*)'}}}.*\$")
private static final Pattern ESCAPED_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{\\{jsonPath request.body '(.*)'}}}.*\$")
private static final Pattern LEGACY_JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{jsonpath this '(.*)'}}.*\$")
private static final Pattern JSON_PATH_PATTERN = Pattern.compile("^.*\\{\\{jsonPath request.body '(.*)'}}.*\$")
private static final Pattern ESCAPED_LEGACY_JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{\\{jsonpath this '(.*)'}}}.*\$")
private static final Pattern ESCAPED_JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{\\{jsonPath request.body '(.*)'}}}.*\$")
private static final Pattern LEGACY_JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{jsonpath this '(.*)'}}.*\$")
private static final Pattern JSON_PATH_PATTERN = Pattern.
compile("^.*\\{\\{jsonPath request.body '(.*)'}}.*\$")
private static final List<Pattern> PATTERNS = [ESCAPED_LEGACY_JSON_PATH_PATTERN,
ESCAPED_JSON_PATH_PATTERN, LEGACY_JSON_PATH_PATTERN, JSON_PATH_PATTERN]
ESCAPED_JSON_PATH_PATTERN, LEGACY_JSON_PATH_PATTERN, JSON_PATH_PATTERN]
private static final String LEGACY_JSON_PATH_TEMPLATE_NAME = HandlebarsJsonPathHelper.NAME
private static final String JSON_PATH_TEMPLATE_NAME = WireMockHelpers.jsonPath.name()
@@ -36,7 +56,8 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
@Override
String transform(Request request, String testContents) {
TestSideRequestTemplateModel templateModel = TestSideRequestTemplateModel.from(request)
TestSideRequestTemplateModel templateModel = TestSideRequestTemplateModel.
from(request)
Map<String, TestSideRequestTemplateModel> model = [(HandlebarsJsonPathHelper.REQUEST_MODEL_NAME): templateModel]
Template bodyTemplate = uncheckedCompileTemplate(testContents)
return templatedResponseBody(model, bodyTemplate)
@@ -44,16 +65,18 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
@Override
boolean containsTemplateEntry(String line) {
return (line.contains(contractTemplate.openingTemplate()) && line.contains(contractTemplate.closingTemplate())) ||
(line.contains(contractTemplate.escapedOpeningTemplate()) && line.contains(contractTemplate.escapedClosingTemplate()))
return (line.contains(contractTemplate.openingTemplate())
&& line.contains(contractTemplate.closingTemplate())) ||
(line.contains(contractTemplate.escapedOpeningTemplate()) &&
line.contains(contractTemplate.escapedClosingTemplate()))
}
@Override
boolean containsJsonPathTemplateEntry(String line) {
return line.contains(openingTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
line.contains(openingTemplate() + JSON_PATH_TEMPLATE_NAME) ||
line.contains(escapedOpeningTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
line.contains(escapedOpeningTemplate() + JSON_PATH_TEMPLATE_NAME)
line.contains(openingTemplate() + JSON_PATH_TEMPLATE_NAME) ||
line.contains(escapedOpeningTemplate() + LEGACY_JSON_PATH_TEMPLATE_NAME) ||
line.contains(escapedOpeningTemplate() + JSON_PATH_TEMPLATE_NAME)
}
@Override
@@ -70,14 +93,15 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
return ""
}
private String templatedResponseBody(Map< String, TestSideRequestTemplateModel> model, Template bodyTemplate) {
private String templatedResponseBody(Map<String, TestSideRequestTemplateModel> model, Template bodyTemplate) {
return uncheckedApplyTemplate(bodyTemplate, model)
}
private String uncheckedApplyTemplate(Template template, Object context) {
try {
return template.apply(context)
} catch (IOException e) {
}
catch (IOException e) {
throw new RuntimeException(e)
}
}
@@ -85,15 +109,18 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate
private Template uncheckedCompileTemplate(String content) {
try {
Handlebars handlebars = new Handlebars()
handlebars.registerHelper(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper())
handlebars.registerHelper(WireMockHelpers.jsonPath.name(), new HandlebarsJsonPathHelper())
handlebars.
registerHelper(HandlebarsJsonPathHelper.NAME, new HandlebarsJsonPathHelper())
handlebars.registerHelper(WireMockHelpers.jsonPath.
name(), new HandlebarsJsonPathHelper())
WireMockHelpers.values()
.findAll { it != WireMockHelpers.jsonPath}
.each { WireMockHelpers helper ->
.findAll { it != WireMockHelpers.jsonPath }
.each { WireMockHelpers helper ->
handlebars.registerHelper(helper.name(), helper)
}
return handlebars.compileInline(content)
} catch (IOException e) {
}
catch (IOException e) {
throw new RuntimeException(e)
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.template
import org.springframework.cloud.contract.spec.internal.Request
@@ -19,24 +35,24 @@ interface TemplateProcessor {
String transform(Request request, String testContents)
/**
* Returns {@code true} if the current line contains template related entry. E.g. for Handlebars
* @return {@code true} if the current line contains template related entry. E.g. for Handlebars
* if a line contains {{{...}}} then it's considered to contain template related entry
*/
boolean containsTemplateEntry(String line)
/**
* Returns {@code true} if the current line contains template related entry for json path processing.
* @return {@code true} if the current line contains template related entry for json path processing.
* E.g. for Handlebars if a line contains {{{jsonpath ...}}} or {{{jsonPath ...}}} then
* it's considered to contain template related entry for json path processing
*/
boolean containsJsonPathTemplateEntry(String line)
/**
* Returns the json path entry from the current line that contains template related entry for json path processing.
* @return the json path entry from the current line that contains template related entry for json path processing.
* E.g. for Handlebars if a line contains {{{jsonpath this '$.a.b.c'}}} or {{{jsonPath request.body ...}}} then
* the te method would return {@code $.a.b.c}. Returns empty string if there's no matching
* json path entry
*/
String jsonPathFromTemplateEntry(String line)
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
@@ -27,6 +27,7 @@ import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.internal.RegexProperty
import static ContentUtils.extractValue
/**
* Class that constructs a String from a body. The body can be a GString
* or a map.
@@ -41,7 +42,7 @@ class BodyExtractor {
private BodyExtractor() {}
/**
* Returns the string representation of the body for the server side.
* @return the string representation of the body for the server side.
* That means that all the interpolations etc. will be resolved for the
* server side.
*/
@@ -53,7 +54,7 @@ class BodyExtractor {
}
/**
* Returns the string representation of the body for the client side.
* @return the string representation of the body for the client side.
* That means that all the interpolations etc. will be resolved for the
* client side.
*/
@@ -70,9 +71,13 @@ class BodyExtractor {
static Object extractServerValueFromBody(bodyValue) {
if (bodyValue instanceof GString) {
bodyValue = extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue })
} else {
bodyValue = MapConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.serverValue : it })
bodyValue =
extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue })
}
else {
bodyValue = MapConverter.transformValues(bodyValue, {
it instanceof DslProperty ? it.serverValue : it
})
}
return bodyValue
}
@@ -80,9 +85,11 @@ class BodyExtractor {
static Object extractClientValueFromBody(bodyValue) {
if (bodyValue instanceof GString) {
return extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.clientValue })
} else if (bodyValue instanceof DslProperty) {
}
else if (bodyValue instanceof DslProperty) {
return extractClientValueFromBody(bodyValue.clientValue)
} else {
}
else {
return MapConverter.transformValues(bodyValue, {
Object prop = it instanceof DslProperty ? it.clientValue : it
if (prop instanceof CanBeDynamic || prop instanceof Pattern) {

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
@@ -33,4 +33,4 @@ enum ContentType {
ContentType(String mimeType) {
this.mimeType = mimeType
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
@@ -50,8 +50,8 @@ import static org.springframework.cloud.contract.verifier.util.ContentType.UNKNO
* @author Marcin Grzejszczak
* @author Olga Maciaszek-Sharma
* @author Konstantin Shevchuk
* @since 1.0.0
*
* @since 1.0.0
*/
@CompileStatic
class ContentUtils {
@@ -66,9 +66,12 @@ class ContentUtils {
it instanceof DslProperty ? it.serverValue : it
}
private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('.*REGEXP>>(.*)<<.*')
private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern.compile('["]?EXECUTION>>(.*)<<["]?')
private static final Pattern TEMPORARY_OPTIONAL_PATTERN_HOLDER = Pattern.compile('OPTIONAL>>(.*)<<')
private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.
compile('.*REGEXP>>(.*)<<.*')
private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern.
compile('["]?EXECUTION>>(.*)<<["]?')
private static final Pattern TEMPORARY_OPTIONAL_PATTERN_HOLDER = Pattern.
compile('OPTIONAL>>(.*)<<')
private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<'
private static final String JSON_VALUE_PATTERN_FOR_OPTIONAL = 'OPTIONAL>>%s<<'
private static final String JSON_VALUE_PATTERN_FOR_EXECUTION = '"EXECUTION>>%s<<"'
@@ -86,7 +89,7 @@ class ContentUtils {
* @return JSON structure with replaced client / server side parts
*/
static Object extractValue(GString bodyAsValue, ContentType contentType, Closure valueProvider) {
if (bodyAsValue.isEmpty()){
if (bodyAsValue.isEmpty()) {
return bodyAsValue
}
if (contentType == ContentType.TEXT || contentType == ContentType.FORM) {
@@ -102,12 +105,14 @@ class ContentUtils {
try {
log.trace("No content type provided so trying to parse as JSON")
return extractValueForJSON(bodyAsValue, valueProvider)
} catch(JsonException e) {
}
catch (JsonException e) {
// Not a JSON format
log.trace("Failed to parse as JSON - trying to parse as XML", e)
try {
return extractValueForXML(bodyAsValue, valueProvider)
} catch (Exception exception) {
}
catch (Exception exception) {
log.trace("No content type provided and failed to parse as XML - returning the value back to the user", exception)
return extractValueForGString(bodyAsValue, valueProvider)
}
@@ -118,11 +123,14 @@ class ContentUtils {
try {
extractValueForJSON(bodyAsValue, GET_STUB_SIDE)
return JSON
} catch(JsonException e) {
}
catch (JsonException e) {
try {
getXmlSlurperWithDefaultErrorHandler().parseText(extractValueForXML(bodyAsValue, GET_STUB_SIDE).toString())
getXmlSlurperWithDefaultErrorHandler()
.parseText(extractValueForXML(bodyAsValue, GET_STUB_SIDE).toString())
return ContentType.XML
} catch (Exception ignored) {
}
catch (Exception ignored) {
extractValueForGString(bodyAsValue, GET_STUB_SIDE)
return UNKNOWN
}
@@ -133,11 +141,14 @@ class ContentUtils {
try {
new JsonSlurper().parseText(bodyAsValue)
return JSON
} catch(JsonException e) {
}
catch (JsonException e) {
try {
getXmlSlurperWithDefaultErrorHandler().parseText(bodyAsValue)
getXmlSlurperWithDefaultErrorHandler()
.parseText(bodyAsValue)
return ContentType.XML
} catch (Exception ignored) {
}
catch (Exception ignored) {
return UNKNOWN
}
}
@@ -146,15 +157,20 @@ class ContentUtils {
static ContentType getClientContentType(Object bodyAsValue) {
if (bodyAsValue instanceof GString) {
return getClientContentType((GString) bodyAsValue)
} else if (bodyAsValue instanceof String) {
}
else if (bodyAsValue instanceof String) {
return getClientContentType((String) bodyAsValue)
} else if (bodyAsValue instanceof Map) {
}
else if (bodyAsValue instanceof Map) {
return getClientContentType((Map) bodyAsValue)
} else if (bodyAsValue instanceof List) {
}
else if (bodyAsValue instanceof List) {
return getClientContentType((List) bodyAsValue)
} else if (bodyAsValue instanceof MatchingStrategy) {
}
else if (bodyAsValue instanceof MatchingStrategy) {
return UNKNOWN
} else if (bodyAsValue instanceof FromFileProperty) {
}
else if (bodyAsValue instanceof FromFileProperty) {
return UNKNOWN
}
return tryToGuessContentType(bodyAsValue)
@@ -187,7 +203,8 @@ class ContentUtils {
try {
JsonOutput.toJson(bodyAsValue)
return JSON
} catch (Exception ignore) {
}
catch (Exception ignore) {
return UNKNOWN
}
}
@@ -196,14 +213,17 @@ class ContentUtils {
try {
JsonOutput.toJson(bodyAsValue)
return JSON
} catch (Exception ignore) {
}
catch (Exception ignore) {
return UNKNOWN
}
}
static GStringImpl extractValueForGString(GString bodyAsValue, Closure valueProvider) {
return new GStringImpl(
bodyAsValue.values.collect { it instanceof DslProperty ? valueProvider(it) : it } as String[],
bodyAsValue.values.collect {
it instanceof DslProperty ? valueProvider(it) : it
} as String[],
bodyAsValue.strings.clone() as String[]
)
}
@@ -222,31 +242,38 @@ class ContentUtils {
private static Object extractValueForJSON(GString bodyAsValue, Closure valueProvider) {
GString transformedString = new GStringImpl(
bodyAsValue.values.collect { transformJSONStringValue(it, valueProvider) } as String[],
bodyAsValue.values.
collect { transformJSONStringValue(it, valueProvider) } as String[],
bodyAsValue.strings.clone() as String[]
)
def parsedJson = new JsonSlurper().parseText(transformedString.toString().replace('\\', '\\\\'))
def parsedJson = new JsonSlurper().
parseText(transformedString.toString().replace('\\', '\\\\'))
return convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson)
}
private static GStringImpl extractValueForXML(GString bodyAsValue, Closure valueProvider) {
GStringImpl impl = new GStringImpl(
bodyAsValue.values.collect { transformXMLStringValue(it, valueProvider) } as String[],
bodyAsValue.values.
collect { transformXMLStringValue(it, valueProvider) } as String[],
bodyAsValue.strings.clone() as String[]
)
// try to convert it to XML
getXmlSlurperWithDefaultErrorHandler().parseText(impl.toString())
getXmlSlurperWithDefaultErrorHandler()
.parseText(impl.toString())
return impl
}
protected static Object transformJSONStringValue(Object obj, Closure valueProvider) {
if (obj instanceof DslProperty) {
return transformJSONStringValue((DslProperty) obj, valueProvider)
} else if (obj instanceof Pattern) {
}
else if (obj instanceof Pattern) {
return transformJSONStringValue((Pattern) obj, valueProvider)
} else if (obj instanceof OptionalProperty) {
}
else if (obj instanceof OptionalProperty) {
return transformJSONStringValue((OptionalProperty) obj, valueProvider)
} else if (obj instanceof ExecutionProperty) {
}
else if (obj instanceof ExecutionProperty) {
return transformJSONStringValue((ExecutionProperty) obj, valueProvider)
}
return obj
@@ -329,7 +356,8 @@ class ContentUtils {
if (matcher.matches()) {
return Pattern.compile(patternFromMatchingGroup(matcher))
}
Matcher executionMatcher = TEMPORARY_EXECUTION_PATTERN_HOLDER.matcher(string.trim())
Matcher executionMatcher = TEMPORARY_EXECUTION_PATTERN_HOLDER.
matcher(string.trim())
if (executionMatcher.matches()) {
return new ExecutionProperty(patternFromMatchingGroup(executionMatcher))
}
@@ -347,8 +375,10 @@ class ContentUtils {
}
static ContentType recognizeContentTypeFromHeader(Headers headers, Closure<Object> closure) {
Header header = headers?.entries?.find { it.name == "Content-Type" ||
it.name == "contentType" }
Header header = headers?.entries?.find {
it.name == "Content-Type" ||
it.name == "contentType"
}
String content = closure(header)?.toString()
if (content?.contains("json")) {
return JSON
@@ -375,10 +405,10 @@ class ContentUtils {
static MatchingStrategy.Type getEqualsTypeFromContentType(ContentType contentType) {
switch (contentType) {
case JSON:
return MatchingStrategy.Type.EQUAL_TO_JSON
case ContentType.XML:
return MatchingStrategy.Type.EQUAL_TO_XML
case JSON:
return MatchingStrategy.Type.EQUAL_TO_JSON
case ContentType.XML:
return MatchingStrategy.Type.EQUAL_TO_XML
}
return MatchingStrategy.Type.EQUAL_TO
}
@@ -409,7 +439,8 @@ class ContentUtils {
try {
new JsonSlurper().parseText(string)
return JSON
} catch (Exception ignored){
}
catch (Exception ignored) {
if (isXmlType("$string")) {
return ContentType.XML
}
@@ -424,15 +455,20 @@ class ContentUtils {
static ContentType recognizeContentTypeFromContent(Object object) {
if (object instanceof GString) {
return recognizeContentTypeFromContent((GString) object)
} else if (object instanceof Map) {
}
else if (object instanceof Map) {
return recognizeContentTypeFromContent((Map) object)
} else if (object instanceof byte[]) {
}
else if (object instanceof byte[]) {
return recognizeContentTypeFromContent((byte[]) object)
} else if (object instanceof List) {
}
else if (object instanceof List) {
return recognizeContentTypeFromContent((List) object)
} else if (object instanceof String) {
}
else if (object instanceof String) {
return recognizeContentTypeFromContent((String) object)
} else if (object instanceof Number) {
}
else if (object instanceof Number) {
return recognizeContentTypeFromContent((Number) object)
}
return UNKNOWN
@@ -444,14 +480,16 @@ class ContentUtils {
}
GString stringWithoutValues = new GStringImpl(
gstring.values.collect({
it instanceof String || it instanceof GString ? it.toString() : escapeJson(it.toString())
it instanceof String || it instanceof GString ? it.toString() :
escapeJson(it.toString())
}) as Object[],
gstring.strings.clone() as String[]
)
try {
new JsonSlurper().parseText(stringWithoutValues.toString())
return true
} catch (JsonException e) {
}
catch (JsonException e) {
// Not JSON
}
return false
@@ -460,14 +498,17 @@ class ContentUtils {
static boolean isXmlType(GString gString) {
GString stringWithoutValues = new GStringImpl(
gString.values.collect({
it instanceof String || it instanceof GString ? it.toString() : escapeXml11(it.toString())
it instanceof String || it instanceof GString ? it.toString() :
escapeXml11(it.toString())
}) as Object[],
gString.strings.clone() as String[]
)
try {
getXmlSlurperWithDefaultErrorHandler().parseText(stringWithoutValues.toString())
getXmlSlurperWithDefaultErrorHandler()
.parseText(stringWithoutValues.toString())
return true
} catch (Exception ignored) {
}
catch (Exception ignored) {
// Not XML
}
return false
@@ -475,10 +516,10 @@ class ContentUtils {
static ContentType recognizeContentTypeFromMatchingStrategy(MatchingStrategy.Type type) {
switch (type) {
case MatchingStrategy.Type.EQUAL_TO_XML:
return ContentType.XML
case MatchingStrategy.Type.EQUAL_TO_JSON:
return JSON
case MatchingStrategy.Type.EQUAL_TO_XML:
return ContentType.XML
case MatchingStrategy.Type.EQUAL_TO_JSON:
return JSON
}
return UNKNOWN
}
@@ -486,18 +527,26 @@ class ContentUtils {
static String getGroovyMultipartFileParameterContent(String propertyName, NamedProperty propertyValue,
Closure<String> bytesFromFile) {
return "'$propertyName', ${namedPropertyName(propertyValue, "'")}, " +
"${groovyNamedPropertyValue(propertyValue, "'", bytesFromFile)}" + namedContentTypeNameIfPresent(propertyValue, "'")
"${groovyNamedPropertyValue(propertyValue, "'", bytesFromFile)}" +
namedContentTypeNameIfPresent(propertyValue, "'")
}
static String getJavaMultipartFileParameterContent(String propertyName, NamedProperty propertyValue,
Closure<String> bytesFromFile) {
return """"${escapeJava(propertyName)}", ${namedPropertyName(propertyValue, '"')}, """ +
"""${javaNamedPropertyValue(propertyValue, '"', bytesFromFile)}${namedContentTypeNameIfPresent(propertyValue, '"')}"""
return """"${escapeJava(propertyName)}", ${
namedPropertyName(propertyValue, '"')
}, """ +
"""${
javaNamedPropertyValue(propertyValue, '"', bytesFromFile)
}${
namedContentTypeNameIfPresent(propertyValue, '"')
}"""
}
static String namedPropertyName(NamedProperty property, String quote) {
return property.name.serverValue instanceof ExecutionProperty ?
property.name.serverValue.toString() : quote + escapeJava(property.name.serverValue.toString()) + quote
property.name.serverValue.toString() : quote +
escapeJava(property.name.serverValue.toString()) + quote
}
static String namedContentTypeNameIfPresent(NamedProperty property, String quote) {
@@ -505,40 +554,46 @@ class ContentUtils {
return ""
}
String contentType = property.contentType.serverValue instanceof ExecutionProperty ?
property.contentType.serverValue.toString() : quote + escapeJava(property.contentType.serverValue.toString()) + quote
property.contentType.serverValue.toString() : quote +
escapeJava(property.contentType.serverValue.toString()) + quote
return ", " + contentType
}
static String groovyNamedPropertyValue(NamedProperty property, String quote, Closure<String> bytesFromFile) {
if (property.value.serverValue instanceof ExecutionProperty) {
return property.value.serverValue.toString()
} else if (property.value.serverValue instanceof byte[]) {
}
else if (property.value.serverValue instanceof byte[]) {
byte[] bytes = (byte[]) property.value.serverValue
return "[" + bytes.collect { it }.join(", ") + "] as byte[]"
} else if (property.value.serverValue instanceof FromFileProperty) {
}
else if (property.value.serverValue instanceof FromFileProperty) {
FromFileProperty fromFileProperty = (FromFileProperty) property.value.serverValue
if (fromFileProperty.isByte()) {
return bytesFromFile(fromFileProperty)
}
return "[" + fromFileProperty.asBytes().collect { it }.join(", ") + "] as byte[]"
}
return quote + escapeJava(property.value.serverValue.toString()) + quote + ".bytes"
return quote +
escapeJava(property.value.serverValue.toString()) + quote + ".bytes"
}
static String javaNamedPropertyValue(NamedProperty property, String quote, Closure<String> bytesFromFile) {
if (property.value.serverValue instanceof ExecutionProperty) {
return property.value.serverValue.toString()
} else if (property.value.serverValue instanceof byte[]) {
}
else if (property.value.serverValue instanceof byte[]) {
byte[] bytes = (byte[]) property.value.serverValue
return "new byte[] {" + bytes.collect { it }.join(", ") + "}"
} else if (property.value.serverValue instanceof FromFileProperty) {
}
else if (property.value.serverValue instanceof FromFileProperty) {
FromFileProperty fromFileProperty = (FromFileProperty) property.value.serverValue
if (fromFileProperty.isByte()) {
return bytesFromFile(fromFileProperty)
}
return "new byte[] {" + fromFileProperty.asBytes().collect { it }.join(", ") + "}"
}
return quote + escapeJava(property.value.serverValue.toString()) + quote + ".getBytes()"
return quote + escapeJava(property.value.serverValue.toString()) + quote + ".getBytes()"
}
static ContentType evaluateContentType(Headers contractHeaders, Object body) {
@@ -548,6 +603,7 @@ class ContentUtils {
}
return contentType
}
/**
* Creates new {@link XmlSlurper} with default error handler.
*

View File

@@ -1,27 +1,20 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
import groovy.transform.CompileStatic
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.ContractConverter
import org.springframework.cloud.contract.verifier.converter.YamlContractConverter
import org.springframework.core.io.support.SpringFactoriesLoader
package org.springframework.cloud.contract.verifier.util
import java.nio.file.FileVisitResult
import java.nio.file.Files
@@ -31,6 +24,15 @@ import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import java.util.function.Predicate
import groovy.transform.CompileStatic
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.ContractConverter
import org.springframework.cloud.contract.verifier.converter.YamlContractConverter
import org.springframework.core.io.support.SpringFactoriesLoader
/**
* Scans through the given directory and converts all files for
* contract definitions.
@@ -82,8 +84,8 @@ final class ContractScanner {
if (isContractDescriptor(file)) {
contractDescriptors
.addAll(ContractVerifierDslConverter
.convertAsCollection(
file.getParentFile(), file))
.convertAsCollection(
file.getParentFile(), file))
}
else if (converter != null
&& converter.isAccepted(file)) {
@@ -91,10 +93,10 @@ final class ContractScanner {
.addAll(converter.convertFrom(file))
}
else if (YamlContractConverter.INSTANCE
.isAccepted(file)) {
.isAccepted(file)) {
contractDescriptors
.addAll(YamlContractConverter.INSTANCE
.convertFrom(file))
.convertFrom(file))
}
}
return super.visitFile(path, attrs)
@@ -120,4 +122,4 @@ final class ContractScanner {
private static boolean isContractDescriptor(File file) {
return file.isFile() && file.getName().endsWith(".groovy")
}
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
@@ -19,6 +19,7 @@ package org.springframework.cloud.contract.verifier.util
import groovy.transform.CompileStatic
import groovy.util.logging.Commons
import org.codehaus.groovy.control.CompilerConfiguration
import org.springframework.cloud.contract.spec.Contract
import org.springframework.util.StringUtils
@@ -43,9 +44,11 @@ class ContractVerifierDslConverter {
try {
Object object = groovyShell().evaluate(dsl)
return listOfContracts(object)
} catch (DslParseException e) {
}
catch (DslParseException e) {
throw e
} catch (Exception e) {
}
catch (Exception e) {
log.error("Exception occurred while trying to evaluate the contract", e)
throw new DslParseException(e)
}
@@ -57,12 +60,15 @@ class ContractVerifierDslConverter {
ClassLoader urlCl = updatedClassLoader(rootFolder, classLoader)
Object object = groovyShell(urlCl, rootFolder).evaluate(dsl)
return listOfContracts(object)
} catch (DslParseException e) {
}
catch (DslParseException e) {
throw e
} catch (Exception e) {
}
catch (Exception e) {
log.error("Exception occurred while trying to evaluate the contract", e)
throw new DslParseException(e)
} finally {
}
finally {
Thread.currentThread().setContextClassLoader(classLoader)
}
}
@@ -77,12 +83,15 @@ class ContractVerifierDslConverter {
ClassLoader urlCl = updatedClassLoader(rootFolder, classLoader)
Object object = groovyShell(urlCl, rootFolder).evaluate(dsl)
return listOfContracts(dsl, object)
} catch (DslParseException e) {
}
catch (DslParseException e) {
throw e
} catch (Exception e) {
}
catch (Exception e) {
log.error("Exception occurred while trying to evaluate the contract at path [${dsl.path}]", e)
throw new DslParseException(e)
} finally {
}
finally {
Thread.currentThread().setContextClassLoader(classLoader)
}
}
@@ -107,7 +116,8 @@ class ContractVerifierDslConverter {
private static Collection<Contract> listOfContracts(object) {
if (object instanceof Collection) {
return object as Collection<Contract>
} else if (!object instanceof Contract) {
}
else if (!object instanceof Contract) {
throw new DslParseException("Contract is not returning a Contract or list of Contracts")
}
return [object] as Collection<Contract>
@@ -116,7 +126,8 @@ class ContractVerifierDslConverter {
private static Collection<Contract> listOfContracts(File file, Object object) {
if (object instanceof Collection) {
return withName(file, object as Collection<Contract>)
} else if (!object instanceof Contract) {
}
else if (!object instanceof Contract) {
throw new DslParseException("Contract is not returning a Contract or list of Contracts")
}
return withName(file, [object] as Collection<Contract>)
@@ -138,7 +149,6 @@ class ContractVerifierDslConverter {
}
private static boolean relatedToScenarios(File file, Contract contract) {
return contract.name?.matches(SCENARIO_MATCHER) ||
file.name.matches(SCENARIO_MATCHER)
return contract.name?.matches(SCENARIO_MATCHER) || file.name.matches(SCENARIO_MATCHER)
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util;
@@ -25,33 +25,36 @@ import org.apache.commons.logging.LogFactory;
import org.apache.commons.text.StringEscapeUtils;
/**
* Implementation of the {@link MethodBufferingJsonVerifiable} that contains a list
* of String method commands that need to be executed to assert JSONs.
* Implementation of the {@link MethodBufferingJsonVerifiable} that contains a list of
* String method commands that need to be executed to assert JSONs.
*
* @author Marcin Grzejszczak
*
* @since 1.0.0
*/
class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
private static final Log log = LogFactory.getLog(DelegatingJsonVerifiable.class);
private static final Pattern FIELD_PATTERN = Pattern.compile("\\.field\\((\")?(.)+(\")?\\)");
private static final Pattern ARRAY_PATTERN = Pattern.compile("\\.array\\((\")?(.)+(\")?\\)");
private static final Pattern FIELD_PATTERN = Pattern
.compile("\\.field\\((\")?(.)+(\")?\\)");
private static final Pattern ARRAY_PATTERN = Pattern
.compile("\\.array\\((\")?(.)+(\")?\\)");
final JsonVerifiable delegate;
final LinkedList<String> methodsBuffer;
final Object valueToCheck;
DelegatingJsonVerifiable(JsonVerifiable delegate,
LinkedList<String> methodsBuffer, Object valueToCheck) {
DelegatingJsonVerifiable(JsonVerifiable delegate, LinkedList<String> methodsBuffer,
Object valueToCheck) {
this.delegate = delegate;
this.methodsBuffer = new LinkedList<>(methodsBuffer);
this.valueToCheck = valueToCheck;
}
DelegatingJsonVerifiable(JsonVerifiable delegate,
LinkedList<String> methodsBuffer) {
DelegatingJsonVerifiable(JsonVerifiable delegate, LinkedList<String> methodsBuffer) {
this.delegate = delegate;
this.methodsBuffer = new LinkedList<>(methodsBuffer);
this.valueToCheck = null;
@@ -69,13 +72,12 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
}
private static String wrapValueWithQuotes(Object value) {
return value instanceof String ?
"\"" + stringWithEscapedQuotes(value) + "\"" :
value.toString();
return value instanceof String ? "\"" + stringWithEscapedQuotes(value) + "\""
: value.toString();
}
private void appendMethodWithValue(String methodName, Object value) {
this.methodsBuffer.offer("." + methodName + "(" + value + ")");
this.methodsBuffer.offer("." + methodName + "(" + value + ")");
}
private void appendMethodWithQuotedValue(String methodName, Object value) {
@@ -84,8 +86,9 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable contains(Object value) {
DelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(),
this.delegate.contains(value), this.methodsBuffer);
DelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.contains(value),
this.methodsBuffer);
verifiable.appendMethodWithQuotedValue("contains", value);
if (isAssertingAValueInArray()) {
verifiable.methodsBuffer.offer(".value()");
@@ -95,12 +98,15 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable field(Object value) {
Object valueToPut = value instanceof ShouldTraverse ? ((ShouldTraverse) value).value : value;
Object valueToPut = value instanceof ShouldTraverse
? ((ShouldTraverse) value).value : value;
Object wrappedValue = wrapInBrackets(valueToPut);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.field(wrappedValue), this.methodsBuffer, value);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(
this.delegate.field(wrappedValue), this.methodsBuffer, value);
if (this.delegate.isIteratingOverArray() && !(value instanceof ShouldTraverse)) {
verifiable.appendMethodWithQuotedValue("contains", wrappedValue);
} else {
}
else {
verifiable.appendMethodWithQuotedValue("field", wrappedValue);
}
return verifiable;
@@ -118,7 +124,8 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable array(Object value) {
Object valueToPut = wrapInBrackets(value);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.array(valueToPut), this.methodsBuffer, value);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(
this.delegate.array(valueToPut), this.methodsBuffer, value);
verifiable.appendMethodWithQuotedValue("array", valueToPut);
return verifiable;
}
@@ -126,28 +133,32 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable arrayField(Object value) {
Object valueToPut = wrapInBrackets(value);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.field(valueToPut).arrayField(), this.methodsBuffer, value);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(
this.delegate.field(valueToPut).arrayField(), this.methodsBuffer, value);
verifiable.appendMethodWithQuotedValue("array", valueToPut);
return verifiable;
}
@Override
public MethodBufferingJsonVerifiable arrayField() {
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.arrayField(), this.methodsBuffer);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(
this.delegate.arrayField(), this.methodsBuffer);
verifiable.methodsBuffer.offer(".arrayField()");
return verifiable;
}
@Override
public MethodBufferingJsonVerifiable array() {
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.array(), this.methodsBuffer);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(
this.delegate.array(), this.methodsBuffer);
verifiable.methodsBuffer.offer(".array()");
return verifiable;
}
@Override
public JsonVerifiable elementWithIndex(int i) {
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.elementWithIndex(i), this.methodsBuffer);
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(
this.delegate.elementWithIndex(i), this.methodsBuffer);
this.methodsBuffer.offer(".elementWithIndex(" + i + ")");
return verifiable;
}
@@ -159,15 +170,22 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable isEqualTo(String value) {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(),
this.delegate.isEqualTo(value), this.methodsBuffer, value);
if (this.delegate.isAssertingAValueInArray() && readyToCheck.methodsBuffer.peekLast().equals(".arrayField()")) {
readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapedHackedJavaText(value));
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.isEqualTo(value),
this.methodsBuffer, value);
if (this.delegate.isAssertingAValueInArray()
&& readyToCheck.methodsBuffer.peekLast().equals(".arrayField()")) {
readyToCheck.appendMethodWithQuotedValue("isEqualTo",
escapedHackedJavaText(value));
readyToCheck.methodsBuffer.offer(".value()");
} else if (this.delegate.isAssertingAValueInArray() && !readyToCheck.methodsBuffer.peekLast().contains("array")) {
}
else if (this.delegate.isAssertingAValueInArray()
&& !readyToCheck.methodsBuffer.peekLast().contains("array")) {
readyToCheck.methodsBuffer.offer(".value()");
} else {
readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapedHackedJavaText(value));
}
else {
readyToCheck.appendMethodWithQuotedValue("isEqualTo",
escapedHackedJavaText(value));
}
return readyToCheck;
}
@@ -182,21 +200,26 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable isEqualTo(Number value) {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.jsonPath(),
this.delegate.isEqualTo(value), this.methodsBuffer, value);
// related to #271 - the problem is with asserting arrays of maps vs arrays of primitives
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.isEqualTo(value),
this.methodsBuffer, value);
// related to #271 - the problem is with asserting arrays of maps vs arrays of
// primitives
String last = readyToCheck.methodsBuffer.peekLast();
boolean containsAMatcher = containsAnyMatcher(last);
if (this.delegate.isAssertingAValueInArray() && containsAMatcher) {
readyToCheck.methodsBuffer.offer(".value()");
} else {
readyToCheck.appendMethodWithValue("isEqualTo", value instanceof Long ? String.valueOf(value).concat("L") : String.valueOf(value));
}
else {
readyToCheck.appendMethodWithValue("isEqualTo", value instanceof Long
? String.valueOf(value).concat("L") : String.valueOf(value));
}
return readyToCheck;
}
private boolean containsAnyMatcher(String string) {
return string.contains("isEqualTo") || string.contains("matches") || string.contains("isNull");
return string.contains("isEqualTo") || string.contains("matches")
|| string.contains("isNull");
}
@Override
@@ -207,17 +230,20 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
return readyToCheck;
}
@Override public MethodBufferingJsonVerifiable isEmpty() {
@Override
public MethodBufferingJsonVerifiable isEmpty() {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.isEmpty(), this.methodsBuffer);
readyToCheck.methodsBuffer.offer(".isEmpty()");
return readyToCheck;
}
@Override public MethodBufferingJsonVerifiable isInstanceOf(Class clazz)
@Override
public MethodBufferingJsonVerifiable isInstanceOf(Class clazz)
throws IllegalStateException {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.isInstanceOf(clazz), this.methodsBuffer);
this.delegate.jsonPath(), this.delegate.isInstanceOf(clazz),
this.methodsBuffer);
readyToCheck.methodsBuffer.offer(".isInstanceOf(" + clazz.getName() + ")");
return readyToCheck;
}
@@ -225,13 +251,16 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public MethodBufferingJsonVerifiable matches(String value) {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.matches(value), this.methodsBuffer,
compilePattern(value));
this.delegate.jsonPath(), this.delegate.matches(value),
this.methodsBuffer, compilePattern(value));
if (this.delegate.isAssertingAValueInArray()) {
readyToCheck.appendMethodWithQuotedValue("matches", escapedHackedJavaText(value));
readyToCheck.appendMethodWithQuotedValue("matches",
escapedHackedJavaText(value));
readyToCheck.methodsBuffer.offer(".value()");
} else {
readyToCheck.appendMethodWithQuotedValue("matches", escapedHackedJavaText(value));
}
else {
readyToCheck.appendMethodWithQuotedValue("matches",
escapedHackedJavaText(value));
}
return readyToCheck;
}
@@ -239,30 +268,36 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
private Object compilePattern(String value) {
try {
return Pattern.compile(value);
} catch (Exception e) {
log.warn("Exception occurred while trying to compile the pattern [" + value + "]. Will return the value explicitly. Hopefully, you know what you're doing...");
}
catch (Exception e) {
log.warn("Exception occurred while trying to compile the pattern [" + value
+ "]. Will return the value explicitly. Hopefully, you know what you're doing...");
return value;
}
}
/**
* We need to escape the pattern in order for the produced text to be compilable.
* The problem is that sometimes we get quotes that already escaped. If we escape them
* we get code that doesn't compile. That's why we're doing this hack to unescape
* an double escaped text. Related to https://github.com/spring-cloud/spring-cloud-contract/issues/169
* We need to escape the pattern in order for the produced text to be compilable. The
* problem is that sometimes we get quotes that already escaped. If we escape them we
* get code that doesn't compile. That's why we're doing this hack to unescape an
* double escaped text. Related to
* https://github.com/spring-cloud/spring-cloud-contract/issues/169
* @param value text to escape
* @return escaped text with lower number of escaped backslashes
*/
private String escapedHackedJavaText(String value) {
return StringEscapeUtils.escapeJava(value)
.replace("\\\"", "\"");
return StringEscapeUtils.escapeJava(value).replace("\\\"", "\"");
}
@Override
public MethodBufferingJsonVerifiable isEqualTo(Boolean value) {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.isEqualTo(value), this.methodsBuffer, value);
this.delegate.jsonPath(), this.delegate.isEqualTo(value),
this.methodsBuffer, value);
if (this.delegate.isAssertingAValueInArray()) {
readyToCheck.methodsBuffer.offer(".value()");
} else {
}
else {
readyToCheck.appendMethodWithValue("isEqualTo", String.valueOf(value));
}
return readyToCheck;
@@ -273,11 +308,13 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
return new FinishedDelegatingJsonVerifiable(this.delegate, this.methodsBuffer);
}
@Override public String keyBeforeChecking() {
@Override
public String keyBeforeChecking() {
return this.delegate.jsonPath();
}
@Override public Object valueBeforeChecking() {
@Override
public Object valueBeforeChecking() {
return this.valueToCheck;
}
@@ -294,7 +331,8 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public boolean assertsConcreteValue() {
for (String s : this.methodsBuffer) {
if (FIELD_PATTERN.matcher(s).matches()|| ARRAY_PATTERN.matcher(s).matches()) {
if (FIELD_PATTERN.matcher(s).matches()
|| ARRAY_PATTERN.matcher(s).matches()) {
return true;
}
}
@@ -319,7 +357,8 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public JsonVerifiable hasSize(int size) {
FinishedDelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(
this.delegate.jsonPath(), this.delegate.hasSize(size), this.methodsBuffer);
this.delegate.jsonPath(), this.delegate.hasSize(size),
this.methodsBuffer);
verifiable.methodsBuffer.offer(".hasSize(" + size + ")");
return verifiable;
}
@@ -363,10 +402,12 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DelegatingJsonVerifiable that = (DelegatingJsonVerifiable) o;
return this.methodsBuffer.toString().equals(that.methodsBuffer.toString());
}
@@ -379,14 +420,13 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
@Override
public String toString() {
return "DelegatingJsonVerifiable{" +
"delegate=\n" + this.delegate +
", methodsBuffer=" + this.methodsBuffer +
'}';
return "DelegatingJsonVerifiable{" + "delegate=\n" + this.delegate
+ ", methodsBuffer=" + this.methodsBuffer + '}';
}
@Override
public <T> T read(Class<T> aClass) {
return this.delegate.read(aClass);
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util;
@@ -21,11 +21,10 @@ import java.util.LinkedList;
import com.toomuchcoding.jsonassert.JsonVerifiable;
/**
* Helper class that represents a finished assertion of a JSON.
* Contains a list of all necessary method calls to assert the JSON.
* Helper class that represents a finished assertion of a JSON. Contains a list of all
* necessary method calls to assert the JSON.
*
* @author Marcin Grzejszczak
*
* @since 1.0.0
*/
class FinishedDelegatingJsonVerifiable extends DelegatingJsonVerifiable {
@@ -50,7 +49,9 @@ class FinishedDelegatingJsonVerifiable extends DelegatingJsonVerifiable {
this.keyBeforeChecking = delegate.jsonPath();
}
@Override public String keyBeforeChecking() {
@Override
public String keyBeforeChecking() {
return this.keyBeforeChecking;
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util

View File

@@ -1,18 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.util
@@ -35,6 +34,7 @@ import org.springframework.cloud.contract.spec.internal.OptionalProperty
import org.springframework.cloud.contract.spec.internal.RegexProperty
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.util.SerializationUtils
/**
* I would like to apologize to anyone who is reading this class. Since JSON is a hectic structure
* this class is also hectic. The idea is to traverse the JSON structure and build a set of
@@ -55,6 +55,7 @@ class JsonToJsonPathsConverter {
private static final Boolean SERVER_SIDE = false
private static final Boolean CLIENT_SIDE = true
private static final String ANY_ARRAY_NOTATION_IN_JSONPATH = "[*]"
private static final String DESCENDANT_OPERATOR = ".."
private final ContractVerifierConfigProperties configProperties
@@ -87,9 +88,10 @@ class JsonToJsonPathsConverter {
def entry = entry(context, matcher.path())
if (entry != null) {
context.delete(matcher.path())
removeTrailingContainers(matcher, context)
removeTrailingContainers(matcher.path(), context)
}
} catch (RuntimeException e) {
}
catch (RuntimeException e) {
if (log.isDebugEnabled()) {
log.debug("Exception occurred while trying to delete path [${matcher.path()}]", e)
}
@@ -102,7 +104,8 @@ class JsonToJsonPathsConverter {
private static def entry(DocumentContext context, String path) {
try {
return context.read(path)
} catch (Exception ex) {
}
catch (Exception ex) {
if (log.isDebugEnabled()) {
log.debug("Exception occurred while trying to retrieve element via path [${path}]", ex)
}
@@ -131,21 +134,34 @@ class JsonToJsonPathsConverter {
* remove that trailing collection. All in all it's better to use the Groovy based notation for
* defining body...
*/
private static void removeTrailingContainers(BodyMatcher matcher, DocumentContext context) {
String pathWithoutAnyArray = matcher.path().contains(ANY_ARRAY_NOTATION_IN_JSONPATH) ? matcher.path().substring(0, matcher.path().lastIndexOf(ANY_ARRAY_NOTATION_IN_JSONPATH)) : matcher.path()
private static boolean removeTrailingContainers(String matcherPath, DocumentContext context) {
boolean containsArray = matcherPath.contains(ANY_ARRAY_NOTATION_IN_JSONPATH)
String pathWithoutAnyArray = containsArray ? matcherPath.substring(0, matcherPath.
lastIndexOf(ANY_ARRAY_NOTATION_IN_JSONPATH)) : matcherPath
def object = entry(context, pathWithoutAnyArray)
// object got removed and it was the only element
// let's get its parent and see if it contains an empty element
if (isIterable(object) && containsOnlyEmptyElements(object)) {
if (isIterable(object)
&&
containsOnlyEmptyElements(object)
&& isNotRootArray(matcherPath)) {
String pathToDelete = pathToDelete(pathWithoutAnyArray)
context.delete(pathToDelete)
} else {
String lastParent = matcher.path().substring(0, matcher.path().lastIndexOf("."))
return pathToDelete.contains(DESCENDANT_OPERATOR) ? false :
removeTrailingContainers(pathToDelete, context)
}
else {
String lastParent = matcherPath.substring(0, matcherPath.lastIndexOf("."))
def lastParentObject = context.read(lastParent)
if (isIterable(lastParentObject) && containsOnlyEmptyElements(lastParentObject)) {
if (isIterable(lastParentObject)
&&
containsOnlyEmptyElements(lastParentObject)
&& isNotRoot(lastParent)) {
context.delete(lastParent)
return removeTrailingContainers(lastParent, context)
}
}
return false
}
private static boolean isIterable(Object object) {
@@ -157,11 +173,22 @@ class JsonToJsonPathsConverter {
return pathWithoutAnyArray == '$' ? '$[*]' : pathWithoutAnyArray
}
private static boolean isNotRoot(String path) {
// we can't remove root
return path != '$'
}
private static boolean isNotRootArray(String path) {
// we can't remove root
return path != '$[*]'
}
private static boolean containsOnlyEmptyElements(Object object) {
return object.every {
if (it instanceof Map) {
return it.isEmpty()
} else if (it instanceof List) {
}
else if (it instanceof List) {
return it.isEmpty()
}
return false
@@ -184,7 +211,8 @@ class JsonToJsonPathsConverter {
static String convertJsonPathAndRegexToAJsonPath(BodyMatcher bodyMatcher, def body = null) {
String path = bodyMatcher.path()
Object value = bodyMatcher.value()
if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY &&
if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY
&&
bodyMatcher.matchingType() != MatchingType.TYPE) {
return path
}
@@ -227,13 +255,16 @@ class JsonToJsonPathsConverter {
convertedBody = MapConverter.transformValues(body) {
return generatedValueIfNeeded(it)
}
Object retrievedValue = JsonPath.parse(convertedBody).read(bodyMatcher.path())
Object retrievedValue = JsonPath.parse(convertedBody).
read(bodyMatcher.path())
String wrappedValue = retrievedValue instanceof Number ? retrievedValue : "'${retrievedValue.toString()}'"
return "${propertyName} == ${wrappedValue}"
} catch (PathNotFoundException e) {
}
catch (PathNotFoundException e) {
throw new IllegalStateException("Value [${bodyMatcher.path()}] not found in JSON [${JsonOutput.toJson(convertedBody)}]", e)
}
} else if (bodyMatcher.matchingType() == MatchingType.TYPE) {
}
else if (bodyMatcher.matchingType() == MatchingType.TYPE) {
Integer min = bodyMatcher.minTypeOccurrence()
Integer max = bodyMatcher.maxTypeOccurrence()
String result = ""
@@ -245,7 +276,8 @@ class JsonToJsonPathsConverter {
result = result ? "${result} && ${maxResult}" : maxResult
}
return result
} else {
}
else {
String convertedValue = value.toString().replace('/', '\\\\/')
return "${propertyName} =~ /(${convertedValue})/"
}
@@ -269,23 +301,25 @@ class JsonToJsonPathsConverter {
private JsonPaths transformToJsonPathWithValues(def json, boolean clientSide,
Closure parsingClosure = MapConverter.JSON_PARSING_CLOSURE) {
if(!json) {
if (!json) {
return new JsonPaths()
}
JsonPaths pathsAndValues = [] as Set
Object convertedJson = MapConverter.getClientOrServerSideValues(json, clientSide, parsingClosure)
Object convertedJson = MapConverter.
getClientOrServerSideValues(json, clientSide, parsingClosure)
Object jsonWithPatterns = ContentUtils.
convertDslPropsToTemporaryRegexPatterns(convertedJson, parsingClosure)
MethodBufferingJsonVerifiable methodBufferingJsonPathVerifiable =
new DelegatingJsonVerifiable(JsonAssertion.assertThat(JsonOutput.toJson(jsonWithPatterns))
.withoutThrowingException())
new DelegatingJsonVerifiable(JsonAssertion.
assertThat(JsonOutput.toJson(jsonWithPatterns))
.withoutThrowingException())
traverseRecursivelyForKey(jsonWithPatterns, methodBufferingJsonPathVerifiable,
{ MethodBufferingJsonVerifiable key, Object value ->
if (value instanceof ExecutionProperty || !(key instanceof FinishedDelegatingJsonVerifiable)) {
return
}
pathsAndValues.add(key)
}, parsingClosure)
{ MethodBufferingJsonVerifiable key, Object value ->
if (value instanceof ExecutionProperty || !(key instanceof FinishedDelegatingJsonVerifiable)) {
return
}
pathsAndValues.add(key)
}, parsingClosure)
return pathsAndValues
}
@@ -298,48 +332,68 @@ class JsonToJsonPathsConverter {
if (json instanceof Map) {
return convertWithKey(parentType, key, json, closure, parsingClosure)
}
} catch (Exception ignore) {
}
catch (Exception ignore) {
return runClosure(closure, key, value)
}
} else if (isAnEntryWithNonCollectionLikeValue(value)) {
}
else if (isAnEntryWithNonCollectionLikeValue(value)) {
return convertWithKey(List, key, value as Map, closure, parsingClosure)
} else if (isAnEntryWithoutNestedStructures(value)) {
}
else if (isAnEntryWithoutNestedStructures(value)) {
return convertWithKey(List, key, value as Map, closure, parsingClosure)
} else if (value instanceof Map && !value.isEmpty()) {
}
else if (value instanceof Map && !value.isEmpty()) {
return convertWithKey(Map, key, value as Map, closure, parsingClosure)
} else if (value instanceof Map && value.isEmpty()) {
}
else if (value instanceof Map && value.isEmpty()) {
return runClosure(closure, key.isEmpty(), value)
// JSON with a list of primitives ["a", "b", "c"] in root issue #266
} else if (key.isIteratingOverNamelessArray() && value instanceof List && listContainsOnlyPrimitives(value)) {
}
else if (key.isIteratingOverNamelessArray() && value instanceof List
&&
listContainsOnlyPrimitives(value)) {
addSizeVerificationForListWithPrimitives(key, closure, value)
value.each {
traverseRecursively(Object, key.arrayField().contains(ContentUtils.returnParsedObject(it)),
traverseRecursively(Object, key.arrayField().
contains(ContentUtils.returnParsedObject(it)),
ContentUtils.returnParsedObject(it), closure, parsingClosure)
}
// JSON containing list of primitives { "partners":[ { "role":"AGENT", "payment_methods":[ "BANK", "CASH" ] } ]
} else if (value instanceof List && listContainsOnlyPrimitives(value)) {
// JSON containing list of primitives { "partners":[ { "role":"AGENT", "payment_methods":[ "BANK", "CASH" ] } ]
}
else if (value instanceof List && listContainsOnlyPrimitives(value)) {
addSizeVerificationForListWithPrimitives(key, closure, value)
value.each {
traverseRecursively(Object, valueToAsserter(key.arrayField(), ContentUtils.returnParsedObject(it)),
traverseRecursively(Object,
valueToAsserter(key.arrayField(), ContentUtils.
returnParsedObject(it)),
ContentUtils.returnParsedObject(it), closure, parsingClosure)
}
} else if (value instanceof List && !value.empty) {
MethodBufferingJsonVerifiable jsonPathVerifiable = createAsserterFromList(key, value)
}
else if (value instanceof List && !value.empty) {
MethodBufferingJsonVerifiable jsonPathVerifiable =
createAsserterFromList(key, value)
addSizeVerificationForListWithPrimitives(key, closure, value)
value.each { def element ->
traverseRecursively(List, createAsserterFromListElement(jsonPathVerifiable, ContentUtils.returnParsedObject(element)),
traverseRecursively(List,
createAsserterFromListElement(jsonPathVerifiable, ContentUtils.
returnParsedObject(element)),
ContentUtils.returnParsedObject(element), closure, parsingClosure)
}
return value
} else if (value instanceof List && value.empty) {
}
else if (value instanceof List && value.empty) {
return runClosure(closure, key, value)
} else if (key.isIteratingOverArray()) {
traverseRecursively(Object, key.arrayField().contains(ContentUtils.returnParsedObject(value)),
}
else if (key.isIteratingOverArray()) {
traverseRecursively(Object, key.arrayField().
contains(ContentUtils.returnParsedObject(value)),
ContentUtils.returnParsedObject(value), closure, parsingClosure)
}
try {
return runClosure(closure, key, value)
} catch (Exception ignore) {
}
catch (Exception ignore) {
return value
}
}
@@ -348,12 +402,15 @@ class JsonToJsonPathsConverter {
private void addSizeVerificationForListWithPrimitives(MethodBufferingJsonVerifiable key, Closure closure, List value) {
String systemPropValue = System.getProperty(SIZE_ASSERTION_SYSTEM_PROP)
Boolean configPropValue = configProperties.assertJsonSize
if ((systemPropValue != null && Boolean.parseBoolean(systemPropValue)) ||
if ((systemPropValue != null && Boolean.parseBoolean(systemPropValue))
||
configPropValue && listContainsOnlyPrimitives(value)) {
addArraySizeCheck(key, value, closure)
} else {
}
else {
if (log.isDebugEnabled()) {
log.debug("Turning off the incubating feature of JSON array check. " +
log.debug("Turning off the incubating feature of JSON array check. "
+
"System property [$systemPropValue]. Config property [$configPropValue]")
}
return
@@ -379,13 +436,16 @@ class JsonToJsonPathsConverter {
private MethodBufferingJsonVerifiable createAsserterFromList(MethodBufferingJsonVerifiable key, List value) {
if (key.isIteratingOverNamelessArray()) {
return key.array()
} else if (key.isIteratingOverArray() && isAnEntryWithLists(value)) {
if (!value.every { listContainsOnlyPrimitives(it as List)} ) {
}
else if (key.isIteratingOverArray() && isAnEntryWithLists(value)) {
if (!value.every { listContainsOnlyPrimitives(it as List) }) {
return key.array()
} else {
}
else {
return key.iterationPassingArray()
}
} else if (key.isIteratingOverArray()) {
}
else if (key.isIteratingOverArray()) {
return key.iterationPassingArray()
}
return key
@@ -398,7 +458,8 @@ class JsonToJsonPathsConverter {
return jsonPathVerifiable.matches((object as Pattern).pattern())
}
return jsonPathVerifiable.contains(object)
} else if (element instanceof List) {
}
else if (element instanceof List) {
if (listContainsOnlyPrimitives(element)) {
return jsonPathVerifiable.array()
}
@@ -407,7 +468,9 @@ class JsonToJsonPathsConverter {
}
private def runClosure(Closure closure, MethodBufferingJsonVerifiable key, def value) {
if (key.isAssertingAValueInArray() && !(value instanceof List || value instanceof Map)) {
if (key.
isAssertingAValueInArray()
&& !(value instanceof List || value instanceof Map)) {
return closure(valueToAsserter(key, value), value)
}
return closure(key, value)
@@ -465,10 +528,12 @@ class JsonToJsonPathsConverter {
Object entrykey, value ->
def convertedValue = ContentUtils.returnParsedObject(value)
[entrykey, traverseRecursively(parentType,
convertedValue instanceof List ? list(convertedValue, entrykey, parentKey) :
convertedValue instanceof Map ? parentKey.field(new ShouldTraverse(entrykey)) :
valueToAsserter(parentKey.field(entrykey), convertedValue)
, convertedValue, closureToExecute, parsingClosure)]
convertedValue instanceof List ?
list(convertedValue, entrykey, parentKey) :
convertedValue instanceof Map ? parentKey.
field(new ShouldTraverse(entrykey)) :
valueToAsserter(parentKey.field(entrykey), convertedValue)
, convertedValue, closureToExecute, parsingClosure)]
}
}
@@ -493,11 +558,15 @@ class JsonToJsonPathsConverter {
}
if (convertedValue instanceof Pattern) {
return key.matches((convertedValue as Pattern).pattern())
} else if (convertedValue instanceof OptionalProperty) {
}
else if (convertedValue instanceof OptionalProperty) {
return key.matches((convertedValue as OptionalProperty).optionalPattern())
} else if (convertedValue instanceof GString) {
return key.matches(RegexpBuilders.buildGStringRegexpForTestSide(convertedValue))
} else if (convertedValue instanceof ExecutionProperty) {
}
else if (convertedValue instanceof GString) {
return key.
matches(RegexpBuilders.buildGStringRegexpForTestSide(convertedValue))
}
else if (convertedValue instanceof ExecutionProperty) {
return key
}
return key.isEqualTo(convertedValue)

View File

@@ -1,18 +1,17 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.util
@@ -53,7 +52,7 @@ class MapConverter {
}
/**
* Returns the object with client side values of {@link org.springframework.cloud.contract.spec.internal.DslProperty}
* @return the object with client side values of {@link org.springframework.cloud.contract.spec.internal.DslProperty}
*/
static def transformToClientValues(def value) {
return transformValues(value) {
@@ -65,7 +64,7 @@ class MapConverter {
* Iterates over the structure of the object and executes the closure
* on each element of that structure.
*
* Returns the transformed structure
* @return the transformed structure
*/
static def transformValues(def value, Closure closure,
Closure parsingClosure = JSON_PARSING_CLOSURE) {
@@ -74,15 +73,19 @@ class MapConverter {
def json = parsingClosure(value)
if (json instanceof Map) {
return convert(json, closure, parsingClosure)
} else if (json instanceof List) {
}
else if (json instanceof List) {
return transformValues(json, closure, parsingClosure)
}
} catch (Exception ignore) {
}
catch (Exception ignore) {
}
return extractValue(value, closure)
} else if (value instanceof Map) {
}
else if (value instanceof Map) {
return convert(value as Map, closure, parsingClosure)
} else if (value instanceof List) {
}
else if (value instanceof List) {
return value.collect({ transformValues(it, closure, parsingClosure) })
}
return transformValue(closure, value, parsingClosure)
@@ -93,7 +96,7 @@ class MapConverter {
* method access exception will occur at runtime.
*/
protected static Object transformValue(Closure closure, Object value, Closure parsingClosure) {
return extractValue(value, { Object val->
return extractValue(value, { Object val ->
Object newValue = closure(val)
if (newValue instanceof Map || newValue instanceof List || newValue instanceof String && value) {
return transformValues(newValue, closure, parsingClosure)
@@ -105,7 +108,8 @@ class MapConverter {
private static extractValue(Object value, Closure closure) {
try {
return closure(value)
} catch (Exception ignore) {
}
catch (Exception ignore) {
return value
}
}
@@ -129,11 +133,15 @@ class MapConverter {
return clientSide ?
getClientOrServerSideValues(dslProperty.clientValue, clientSide, parsingClosure) :
getClientOrServerSideValues(dslProperty.serverValue, clientSide, parsingClosure)
} else if (it instanceof GString) {
ContentType type = new MapConverter().templateProcessor.containsJsonPathTemplateEntry(
ContentUtils.extractValueForGString(it, ContentUtils.GET_TEST_SIDE).toString()
) ? ContentType.TEXT : null
return ContentUtils.extractValue(it , type, {
}
else if (it instanceof GString) {
ContentType type = new MapConverter().templateProcessor.
containsJsonPathTemplateEntry(
ContentUtils.
extractValueForGString(it, ContentUtils.GET_TEST_SIDE).
toString()
) ? ContentType.TEXT : null
return ContentUtils.extractValue(it, type, {
if (it instanceof DslProperty) {
return clientSide ?
getClientOrServerSideValues((it as DslProperty).clientValue, clientSide, parsingClosure) :
@@ -141,7 +149,8 @@ class MapConverter {
}
return it
})
} else if (it instanceof FromFileProperty) {
}
else if (it instanceof FromFileProperty) {
return it.isByte() ? it.asBytes() : it.asString()
}
return it

View File

@@ -1,29 +1,29 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util;
/**
* Contract for classes that buffer method executions
* Contract for classes that buffer method executions.
*
* @author Marcin Grzejszczak
*
* @since 1.0.0
*/
public interface MethodBuffering {
String method();
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util;
@@ -19,15 +19,14 @@ package org.springframework.cloud.contract.verifier.util;
import com.toomuchcoding.jsonassert.JsonVerifiable;
/**
* A wrapper over {@link JsonVerifiable} that allows to store the method
* name in order to print it out in the generated test
* A wrapper over {@link JsonVerifiable} that allows to store the method name in order to
* print it out in the generated test.
*
* @author Marcin Grzejszczak
*
* @since 1.0.0
*/
public interface MethodBufferingJsonVerifiable
extends JsonVerifiable, MethodBuffering {
public interface MethodBufferingJsonVerifiable extends JsonVerifiable, MethodBuffering {
@Override
MethodBufferingJsonVerifiable contains(Object value);
@@ -81,4 +80,5 @@ public interface MethodBufferingJsonVerifiable
boolean assertsSize();
boolean assertsConcreteValue();
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
@@ -33,7 +33,7 @@ class NamesUtil {
/**
* Returns the first element before the last separator presence.
* Returns empty string if separator is not found.
* @return empty string if separator is not found.
*/
static String beforeLast(String string, String separator) {
if (string?.indexOf(separator) > -1) {
@@ -44,7 +44,7 @@ class NamesUtil {
/**
* Returns the first element after the last separator presence
* Returns the provided string if separator is not found.
* @return the provided string if separator is not found.
*/
static String afterLast(String string, String separator) {
if (hasSeparator(string, separator)) {
@@ -62,28 +62,26 @@ class NamesUtil {
/**
* Returns the first element after the last dot presence
* Returns the provided string if separator is not found.
* @return the provided string if separator is not found.
*/
static String afterLastDot(String string) {
return afterLast(string, '.')
}
/**
* Returns {@code true} if has a dot
* @return {@code true} if has a dot
*/
static boolean hasDot(String string) {
return hasSeparator(string, '.')
}
/**
* Returns the default contract name, resolved from file name, taking
* into consideration also the index of contract (for multiple contracts
* stored in a single file).
*
* @param file - file with contracts
* @param contracts - collection of contracts
* @param counter - given contract index
* @return
* @return the default contract name, resolved from file name, taking
* * into consideration also the index of contract (for multiple contracts
* * stored in a single file).
*/
static String defaultContractName(File file, Collection contracts, int counter) {
String tillExtension = file.name.substring(0, file.name.lastIndexOf("."))
@@ -114,7 +112,7 @@ class NamesUtil {
/**
* Returns the whole string to the last present dot.
* Returns input string if there is no dot
* @return input string if there is no dot
*/
static String toLastDot(String string) {
if (string?.indexOf('.') > -1) {
@@ -170,7 +168,8 @@ class NamesUtil {
String name = dir.toFile().getName()
String convertedName = directoryToPackage(name)
if (name != convertedName) {
this.filesToRename.addFirst(new FileAndNewName(dir.toFile(), convertedName))
this.filesToRename.
addFirst(new FileAndNewName(dir.toFile(), convertedName))
}
return FileVisitResult.CONTINUE
}
@@ -203,7 +202,7 @@ class NamesUtil {
* Converts illegal characters in method names to underscores
*/
static String convertIllegalMethodNameChars(String methodName) {
String result = methodName.replaceAll('^[^a-zA-Z_$0-9]', '_')
String result = methodName.replaceAll('^[^a-zA-Z_$0-9]', '_')
return result.replaceAll('[^a-zA-Z_$0-9]', '_')
}
}

View File

@@ -1,31 +1,32 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
import java.util.regex.Pattern
import groovy.transform.TypeChecked
import org.codehaus.groovy.runtime.GStringImpl
import org.springframework.cloud.contract.spec.internal.DslProperty
import org.springframework.cloud.contract.spec.util.RegexpUtils
import java.util.regex.Pattern
import static org.apache.commons.text.StringEscapeUtils.escapeJson
import static ContentType.*
import static ContentUtils.extractValue
import static org.apache.commons.text.StringEscapeUtils.escapeJson
import static org.springframework.cloud.contract.verifier.util.ContentType.JSON
/**
* Useful utility methods to work with regular expressions
@@ -106,7 +107,8 @@ class RegexpBuilders {
private final static String WS = /\s*/
static String buildJSONRegexpMatch(GString gString) {
return buildJSONRegexpMatch(extractValue(gString, JSON, { DslProperty dslProperty -> dslProperty.clientValue }))
return buildJSONRegexpMatch(
extractValue(gString, JSON, { DslProperty dslProperty -> dslProperty.clientValue }))
}
static String buildJSONRegexpMatch(Map jsonMap) {
@@ -121,7 +123,8 @@ class RegexpBuilders {
* Converts the map into String representation of regular expressions
*/
static String buildJSONRegexpMatch(Map.Entry<String, Object> entry) {
return buildJSONRegexpMatchString(escapeJson(entry.key)) + ":" + buildJSONRegexpMatch(entry.value)
return buildJSONRegexpMatchString(escapeJson(entry.key)) + ":" +
buildJSONRegexpMatch(entry.value)
}
/**

View File

@@ -1,33 +1,34 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util;
/**
* Utility class that wraps an object that should be traversed
* when building a list of methods to execute in the generated test.
* Utility class that wraps an object that should be traversed when building a list of
* methods to execute in the generated test.
*
* @author Marcin Grzejszczak
*
* @since 1.0.0
*/
class ShouldTraverse {
final Object value;
ShouldTraverse(Object value) {
this.value = value;
}
}

View File

@@ -1,28 +1,30 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util
import java.nio.file.Files
import groovy.transform.CompileStatic
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.ContractConverter
import java.nio.file.Files
/**
* Allows conversion of Contract files to files.
*
@@ -69,10 +71,12 @@ final class ToFileContractsTransformer {
log.info("Input path [" + path + "]")
log.info("FQN of the converter [" + fqn + "]")
log.info("Output path [" + outputPath + "]")
Collection<Contract> contracts = ContractScanner.collectContractDescriptors(new File(path))
Collection<Contract> contracts = ContractScanner.
collectContractDescriptors(new File(path))
log.info("Found [" + contracts.size() + "] contract definition")
Class<?> name = Class.forName(fqn)
ContractConverter<Collection> contractConverter = (ContractConverter) name.newInstance()
ContractConverter<Collection> contractConverter = (ContractConverter) name.
newInstance()
Collection converted = contractConverter.convertTo(contracts)
log.info("Successfully converted contracts definitions")
Map<String, byte[]> stored = contractConverter.store(converted)
@@ -85,11 +89,17 @@ final class ToFileContractsTransformer {
for (Map.Entry<String, byte[]> entry : entries) {
File outputFile = new File(outputFolder, entry.getKey())
Files.write(outputFile.toPath(), entry.getValue())
log.info("[" + i + "/" + entries.size() + "] Successfully stored [" + outputFile.getName() + "]")
log.info("[" + i + "/"
+ entries.
size()
+ "] Successfully stored ["
+ outputFile.getName()
+ "]")
files.add(outputFile)
}
return files
} catch (Exception ex) {
}
catch (Exception ex) {
throw new IllegalStateException(ex)
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2018-2019 the original author or authors.
* Copyright 2018-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.util.xml
@@ -63,9 +63,9 @@ class XmlToXPathsConverter {
static Object removeMatchingXPaths(Object body, BodyMatchers bodyMatchers) {
XPath xPath = XPathFactory.newInstance().newXPath()
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.newDocumentBuilder()
Document parsedXml = documentBuilder
.parse(new InputSource(new StringReader(body as String)))
.parse(new InputSource(new StringReader(body as String)))
bodyMatchers?.matchers()?.each({
Node node = xPath.evaluate(it.path(), parsedXml.documentElement, NODE) as Node
removeNode(node)
@@ -88,9 +88,9 @@ class XmlToXPathsConverter {
private static String getNodeValue(String path, Object body) {
XPath xPath = XPathFactory.newInstance().newXPath()
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.newDocumentBuilder()
Document parsedXml = documentBuilder.
parse(new InputSource(new StringReader(body as String)))
parse(new InputSource(new StringReader(body as String)))
return xPath.evaluate(path, parsedXml.documentElement)
}
@@ -99,7 +99,9 @@ class XmlToXPathsConverter {
if (isValueNode(node as Node)) {
node.getParentNode().removeChild(node)
}
else removeNode(node.getParentNode())
else {
removeNode(node.getParentNode())
}
}
}
@@ -126,10 +128,10 @@ class XmlToXPathsConverter {
static List<BodyMatcher> mapToMatchers(Object xml) {
DocumentBuilder documentBuilder = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.newInstance()
.newDocumentBuilder()
Document parsedXml = documentBuilder
.parse(new InputSource(new StringReader(xml as String)))
.parse(new InputSource(new StringReader(xml as String)))
List<List<Node>> valueNodes = getValueNodesWithParents(parsedXml)
List<BodyMatcher> matchers = []
List<NodePath> valueNodePaths = transformListEntries(valueNodes)
@@ -148,12 +150,12 @@ class XmlToXPathsConverter {
nodeLists.each { nodeList ->
List<Node> parentNodesList = nodeList.subList(1, nodeList.size())
int elementIndex = pathOccurrenceCounters.stream()
.map({ it })
.filter({
.map({ it })
.filter({
nodeNames(it.path) == nodeNames(parentNodesList)
}).findFirst()
.map({ ++it.counter })
.orElseGet({
.map({ ++it.counter })
.orElseGet({
PathOccurrenceCounter pathCounter = new PathOccurrenceCounter(parentNodesList)
pathOccurrenceCounters << pathCounter
return pathCounter.counter
@@ -165,8 +167,8 @@ class XmlToXPathsConverter {
private static List<String> nodeNames(List<Node> nodes) {
return nodes.stream()
.map({ it.getNodeName() })
.collect(toList())
.map({ it.getNodeName() })
.collect(toList())
}
static String buildXPath(List<Node> nodes, int index = 1) {
@@ -237,8 +239,8 @@ class XmlToXPathsConverter {
@CompileDynamic
private static List<Node> getNodeCollectionElements(def nodeCollection) {
return IntStream.range(0, nodeCollection.getLength())
.mapToObj({ nodeCollection.item(it) as Node })
.collect(toList())
.mapToObj({ nodeCollection.item(it) as Node })
.collect(toList())
}
private static List<Node> withParents(Node node) {

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.assertion;
import java.util.Collection;
@@ -7,8 +23,9 @@ import java.util.Map;
import org.assertj.core.api.IterableAssert;
/**
* Extension to {@link Iterable} assertions
* Extension to {@link Iterable} assertions.
*
* @param <ELEMENT> type to assert
* @author Marcin Grzejszczak
* @since 1.1.0
*/
@@ -23,7 +40,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
}
/**
* Asserts all elements of the collection whether they match a regular expression
* Asserts all elements of the collection whether they match a regular expression.
* @param regex - regular expression to check against
* @return this
*/
@@ -48,7 +65,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
/**
* Flattens the collection and checks whether size is greater than or equal to the
* provided value
* provided value.
* @param size - the flattened collection should have size greater than or equal to
* this value
* @return this
@@ -65,7 +82,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
/**
* Flattens the collection and checks whether size is less than or equal to the
* provided value
* provided value.
* @param size - the flattened collection should have size less than or equal to this
* value
* @return this
@@ -81,7 +98,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
}
/**
* Flattens the collection and checks whether size is between the provided value
* Flattens the collection and checks whether size is between the provided value.
* @param lowerBound - the flattened collection should have size greater than or equal
* to this value
* @param higherBound - the flattened collection should have size less than or equal
@@ -99,7 +116,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
}
/**
* Checks whether size is greater than or equal to the provided value
* Checks whether size is greater than or equal to the provided value.
* @param size - the collection should have size greater than or equal to this value
* @return this
*/
@@ -114,7 +131,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
}
/**
* Checks whether size is less than or equal to the provided value
* Checks whether size is less than or equal to the provided value.
* @param size - the collection should have size less than or equal to this value
* @return this
*/
@@ -129,7 +146,7 @@ public class CollectionAssert<ELEMENT> extends IterableAssert<ELEMENT> {
}
/**
* Checks whether size is between the provided value
* Checks whether size is between the provided value.
* @param lowerBound - the collection should have size greater than or equal to this
* value
* @param higherBound - the collection should have size less than or equal to this

View File

@@ -1,9 +1,25 @@
/*
* Copyright 2013-2019 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
*
* http://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.assertion;
import org.assertj.core.api.Assertions;
/**
* Assertions used by the generated tests
* Assertions used by the generated tests.
*
* @author Marcin Grzejszczak
* @since 1.1.0
@@ -12,6 +28,7 @@ public class SpringCloudContractAssertions extends Assertions {
/**
* Creates a new instance of <code>{@link CollectionAssert}</code>.
* @param <ELEMENT> type to assert
* @param actual the actual value.
* @return the created assertion object.
*/

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging;
@@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
* Destination is relevant to the underlying implementation. Might be a channel, queue,
* topic etc.
*
* @param <M> message type
* @author Marcin Grzejszczak
* @since 1.0.0
*/
@@ -32,24 +33,35 @@ public interface MessageVerifier<M> {
/**
* Sends the message to the given destination.
* @param message to send
* @param destination destination to which the message will be sent
*/
void send(M message, String destination);
/**
* Sends the given payload with headers, to the given destination.
* @param <T> payload type
* @param payload payload to send
* @param headers headers to send
* @param destination destination to which the message will be sent
*/
<T> void send(T payload, Map<String, Object> headers, String destination);
/**
* Receives the message from the given destination. You can provide the timeout for
* receiving that message.
* @param destination destination from which the message will be received
* @param timeout timeout to wait for the message
* @param timeUnit param to define the unit of timeout
* @return received message
*/
M receive(String destination, long timeout, TimeUnit timeUnit);
/**
* Receives the message from the given destination. A default timeout will be applied.
* @param destination destination from which the message will be received
* @return received message
*/
M receive(String destination);
}

View File

@@ -1,23 +1,21 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.amqp;
import static java.util.Collections.emptyList;
import java.util.List;
import org.springframework.amqp.core.Binding;
@@ -43,9 +41,11 @@ import org.springframework.cloud.contract.verifier.messaging.stream.ContractVeri
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static java.util.Collections.emptyList;
/**
* Configuration setting up {@link MessageVerifier} for use with plain
* spring-rabbit/spring-amqp
* spring-rabbit/spring-amqp.
*
* @author Mathias Düsterhöft
* @since 1.0.2
@@ -91,7 +91,7 @@ class ContractVerifierHelper extends ContractVerifierMessaging<Message> {
private final MessageConverter messageConverter;
public ContractVerifierHelper(MessageVerifier<Message> exchange,
ContractVerifierHelper(MessageVerifier<Message> exchange,
MessageConverter messageConverter) {
super(exchange);
this.messageConverter = messageConverter;
@@ -101,7 +101,8 @@ class ContractVerifierHelper extends ContractVerifierMessaging<Message> {
protected ContractVerifierMessage convert(Message message) {
MessagingMessageConverter messageConverter = new MessagingMessageConverter(
this.messageConverter, new SimpleAmqpHeaderMapper());
org.springframework.messaging.Message<?> messagingMessage = (org.springframework.messaging.Message<?>) messageConverter
org.springframework.messaging.Message<?> messagingMessage;
messagingMessage = (org.springframework.messaging.Message<?>) messageConverter
.fromMessage(message);
return new ContractVerifierMessage(messagingMessage.getPayload(),
messagingMessage.getHeaders());

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2013-2019 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
*
* http://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.messaging.amqp;
import java.util.ArrayList;
@@ -12,13 +28,13 @@ import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
/**
* Abstraction hiding details of the different sources of message listeners
* Abstraction hiding details of the different sources of message listeners.
*
* Needed because
* {@link org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor}
* adds the listeners to the {@link RabbitListenerEndpointRegistry} so that the registry
* is empty when wired into an auto configuration class so we wrap it in the accessor to
* access the listeners late at runtime
* access the listeners late at runtime.
*
* @author Mathias Düsterhöft
* @since 1.0.2

View File

@@ -1,12 +1,28 @@
/*
* Copyright 2013-2019 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
*
* http://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.messaging.amqp;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.amqp;
@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessagePropertiesBuilder;
@@ -86,18 +87,17 @@ public class SpringAmqpStubMessages implements MessageVerifier<Message> {
public <T> void send(T payload, Map<String, Object> headers, String destination) {
Message message = org.springframework.amqp.core.MessageBuilder
.withBody(((String) payload).getBytes())
.andProperties(
MessagePropertiesBuilder.newInstance()
.setContentType(header(headers, "contentType"))
.copyHeaders(headers).build())
.andProperties(MessagePropertiesBuilder.newInstance()
.setContentType(header(headers, "contentType"))
.copyHeaders(headers).build())
.build();
if (headers != null && headers.containsKey(DEFAULT_CLASSID_FIELD_NAME)) {
message.getMessageProperties().setHeader(DEFAULT_CLASSID_FIELD_NAME,
headers.get(DEFAULT_CLASSID_FIELD_NAME));
}
if (headers != null && headers.containsKey(AmqpHeaders.RECEIVED_ROUTING_KEY)) {
message.getMessageProperties()
.setReceivedRoutingKey(header(headers, AmqpHeaders.RECEIVED_ROUTING_KEY));
message.getMessageProperties().setReceivedRoutingKey(
header(headers, AmqpHeaders.RECEIVED_ROUTING_KEY));
}
send(message, destination);
}
@@ -109,7 +109,8 @@ public class SpringAmqpStubMessages implements MessageVerifier<Message> {
Object value = headers.get(headerName);
if (value instanceof String) {
return (String) value;
} else if (value instanceof Iterable) {
}
else if (value instanceof Iterable) {
Iterable values = ((Iterable) value);
return values.iterator().hasNext() ? (String) values.iterator().next() : "";
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.camel;
@@ -27,6 +27,7 @@ import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.DefaultExchange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.stereotype.Component;
@@ -37,10 +38,10 @@ import org.springframework.stereotype.Component;
@Component
public class CamelStubMessages implements MessageVerifier<Message> {
private static final Logger log = LoggerFactory.getLogger(
CamelStubMessages.class);
private static final Logger log = LoggerFactory.getLogger(CamelStubMessages.class);
private final CamelContext context;
private final ContractVerifierCamelMessageBuilder builder;
@Autowired
@@ -56,9 +57,10 @@ public class CamelStubMessages implements MessageVerifier<Message> {
Exchange exchange = new DefaultExchange(this.context);
exchange.setIn(message);
producerTemplate.send(destination, exchange);
} catch (Exception e) {
log.error("Exception occurred while trying to send a message [" + message + "] " +
"to a channel with name [" + destination + "]", e);
}
catch (Exception e) {
log.error("Exception occurred while trying to send a message [" + message
+ "] " + "to a channel with name [" + destination + "]", e);
throw e;
}
}
@@ -72,11 +74,13 @@ public class CamelStubMessages implements MessageVerifier<Message> {
public Message receive(String destination, long timeout, TimeUnit timeUnit) {
try {
ConsumerTemplate consumerTemplate = this.context.createConsumerTemplate();
Exchange exchange = consumerTemplate.receive(destination, timeUnit.toMillis(timeout));
Exchange exchange = consumerTemplate.receive(destination,
timeUnit.toMillis(timeout));
return exchange.getIn();
} catch (Exception e) {
log.error("Exception occurred while trying to read a message from " +
" a channel with name [" + destination + "]", e);
}
catch (Exception e) {
log.error("Exception occurred while trying to read a message from "
+ " a channel with name [" + destination + "]", e);
throw new IllegalStateException(e);
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.camel;
@@ -19,13 +19,18 @@ package org.springframework.cloud.contract.verifier.messaging.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.Message;
import org.apache.camel.spring.boot.CamelAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author Marcin Grzejszczak
@@ -33,14 +38,13 @@ import org.springframework.context.annotation.*;
@Configuration
@ConditionalOnClass(Message.class)
@Import(CamelAutoConfiguration.class)
@ConditionalOnProperty(name="stubrunner.camel.enabled", havingValue="true", matchIfMissing = true)
@ConditionalOnProperty(name = "stubrunner.camel.enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class)
public class ContractVerifierCamelConfiguration {
@Bean
@ConditionalOnMissingBean
MessageVerifier<Message> contractVerifierMessageExchange(
CamelContext camelContext) {
MessageVerifier<Message> contractVerifierMessageExchange(CamelContext camelContext) {
return new CamelStubMessages(camelContext);
}
@@ -50,12 +54,12 @@ public class ContractVerifierCamelConfiguration {
MessageVerifier<Message> exchange) {
return new ContractVerifierCamelHelper(exchange);
}
}
class ContractVerifierCamelHelper extends ContractVerifierMessaging<Message> {
public ContractVerifierCamelHelper(
MessageVerifier<Message> exchange) {
ContractVerifierCamelHelper(MessageVerifier<Message> exchange) {
super(exchange);
}
@@ -63,4 +67,5 @@ class ContractVerifierCamelHelper extends ContractVerifierMessaging<Message> {
protected ContractVerifierMessage convert(Message receive) {
return new ContractVerifierMessage(receive.getBody(), receive.getHeaders());
}
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.camel;

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.integration;
@@ -57,7 +57,7 @@ public class ContractVerifierIntegrationConfiguration {
class ContractVerifierHelper extends ContractVerifierMessaging<Message<?>> {
public ContractVerifierHelper(MessageVerifier<Message<?>> exchange) {
ContractVerifierHelper(MessageVerifier<Message<?>> exchange) {
super(exchange);
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.integration;

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.integration;
@@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.context.ApplicationContext;

View File

@@ -54,19 +54,20 @@ public class ContractVerifierMessage {
if (this.payload instanceof byte[]) {
return (byte[]) this.payload;
}
throw new IllegalStateException("Payload [" + this.payload.getClass() + "]" + "is not instance of byte[]");
throw new IllegalStateException("Payload [" + this.payload.getClass() + "]"
+ "is not instance of byte[]");
}
public Map<String, Object> getHeaders() {
return this.headers;
}
public Object getHeader(String name) {
return this.headers.get(name);
}
public void setHeaders(Map<String, Object> headers) {
this.headers = headers;
}
public Object getHeader(String name) {
return this.headers.get(name);
}
}

View File

@@ -21,8 +21,12 @@ import java.util.Map;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
/**
* @author Dave Syer
* Wrapper around messaging. Abstracts all message related operations like sending,
* converting and receiving. Delegates the actual work to an implementation of a
* {@link MessageVerifier}.
*
* @param <M> message type
* @author Dave Syer
*/
public class ContractVerifierMessaging<M> {

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.internal;
@@ -50,9 +50,11 @@ public class ContractVerifierObjectMapper {
public byte[] writeValueAsBytes(Object payload) throws JsonProcessingException {
if (payload instanceof String) {
return payload.toString().getBytes();
} else if (payload instanceof byte[]) {
}
else if (payload instanceof byte[]) {
return (byte[]) payload;
}
return this.objectMapper.writeValueAsBytes(payload);
}
}

View File

@@ -1,21 +1,23 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.noop;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -26,10 +28,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Verifier auto configuration containing default beans for messaging
* Verifier auto configuration containing default beans for messaging.
*
* @author Marcin Grzejszczak
*/

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.noop;

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.stream;
@@ -59,7 +59,7 @@ public class ContractVerifierStreamAutoConfiguration {
class ContractVerifierHelper extends ContractVerifierMessaging<Message<?>> {
public ContractVerifierHelper(MessageVerifier<Message<?>> exchange) {
ContractVerifierHelper(MessageVerifier<Message<?>> exchange) {
super(exchange);
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.stream;

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.stream;
@@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.BindingServiceProperties;
@@ -31,6 +32,12 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.util.StringUtils;
enum DefaultChannels {
INPUT, OUTPUT
}
/**
* @author Marcin Grzejszczak
*/
@@ -140,9 +147,3 @@ public class StreamStubMessages implements MessageVerifier<Message<?>> {
}
}
enum DefaultChannels {
INPUT, OUTPUT
}

View File

@@ -1,17 +1,17 @@
/*
* Copyright 2013-2019 the original author or authors.
* Copyright 2013-2019 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
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://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.
* 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.messaging.util;
@@ -22,16 +22,26 @@ import java.util.Map;
import java.util.Set;
/**
* Helper class that allows to build headers in a nice way
* Helper class that allows to build headers in a nice way.
*
* @author Marcin Grzejszczak
*/
public class ContractVerifierMessagingUtil {
public final class ContractVerifierMessagingUtil {
private ContractVerifierMessagingUtil() {
throw new IllegalStateException("Can't instantiate a utility class");
}
/**
* @return a builder for headers
*/
public static ContractVerifierHeaders headers() {
return new ContractVerifierHeaders();
}
/**
* A map with a fluent interface. Thanks to this, the generated tests look much nicer.
*/
public static class ContractVerifierHeaders implements Map<String, Object> {
private final Map<String, Object> delegate = new HashMap<>();

Some files were not shown because too many files have changed in this diff Show More