Added documentation to the new features

This commit is contained in:
Marcin Grzejszczak
2016-12-05 18:24:13 +01:00
parent 01460f6d9f
commit 148dc4effc
12 changed files with 353 additions and 186 deletions

View File

@@ -42,7 +42,6 @@ class FileSaver {
}
void saveClassFile(String fileName, String basePackageClass, String includedDirectoryRelativePath, byte[] classBytes) {
Path testBaseDir = Paths.get(targetDirectory.absolutePath, packageToDirectory(basePackageClass),
beforeLast(includedDirectoryRelativePath, File.separator))
Files.createDirectories(testBaseDir)

View File

@@ -20,10 +20,12 @@ import com.google.common.collect.ListMultimap
import groovy.transform.PackageScope
import org.apache.commons.lang3.StringUtils
import org.springframework.cloud.contract.spec.ContractVerifierException
import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.file.ContractFileScanner
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.core.io.support.SpringFactoriesLoader
import java.nio.charset.StandardCharsets
import java.nio.file.Path
@@ -45,10 +47,18 @@ class TestGenerator {
private ContractFileScanner contractFileScanner
TestGenerator(ContractVerifierConfigProperties configProperties) {
this(configProperties, new SingleTestGenerator(configProperties),
this(configProperties, singleTestGenerator(),
new FileSaver(configProperties.generatedTestSourcesDir, configProperties.targetFramework))
}
private static SingleTestGenerator singleTestGenerator() {
List<SingleTestGenerator> factories = SpringFactoriesLoader.loadFactories(SingleTestGenerator, null)
if (factories.empty) {
return new JavaTestGenerator()
}
return factories.first()
}
TestGenerator(ContractVerifierConfigProperties configProperties, SingleTestGenerator generator, FileSaver saver) {
this.configProperties = configProperties
if (configProperties.contractsDslDir == null) {
@@ -88,7 +98,7 @@ class TestGenerator {
if (contracts.size()) {
def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix()
def packageName = buildPackage(basePackageNameForClass, includedDirectoryRelativePath)
def classBytes = generator.buildClass(contracts, className, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8)
def classBytes = generator.buildClass(configProperties, contracts, className, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8)
saver.saveClassFile(className, basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString()), classBytes)
counter.incrementAndGet()
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright 2013-2016 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.Canonical
import groovy.transform.EqualsAndHashCode
import groovy.util.logging.Slf4j
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.config.TestFramework
import org.springframework.cloud.contract.verifier.config.TestMode
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize
/**
* Builds a single test for the given {@link ContractVerifierConfigProperties properties}
*
* @since 1.0.0
*/
@Slf4j
class JavaTestGenerator implements SingleTestGenerator {
private static final String JSON_ASSERT_STATIC_IMPORT = 'com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson'
private static final String JSON_ASSERT_CLASS = 'com.toomuchcoding.jsonassert.JsonAssertion'
@Override
String buildClass(ContractVerifierConfigProperties configProperties, Collection<ContractMetadata> listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) {
ClassBuilder clazz = ClassBuilder.createClass(capitalize(className), classPackage, configProperties, includedDirectoryRelativePath)
if (configProperties.imports) {
configProperties.imports.each {
clazz.addImport(it)
}
}
if (configProperties.staticImports) {
configProperties.staticImports.each {
clazz.addStaticImport(it)
}
}
if (isScenarioClass(listOfFiles)) {
clazz.addImport(configProperties.targetFramework.getOrderAnnotationImport())
clazz.addClassLevelAnnotation(configProperties.targetFramework.getOrderAnnotation())
}
addJsonPathRelatedImports(clazz)
Map<ParsedDsl, TestType> contracts = mapContractsToTheirTestTypes(listOfFiles)
boolean conditionalImportsAdded = false
boolean toIgnore = listOfFiles.ignored.find { it }
contracts.each { ParsedDsl key, TestType value ->
if (!conditionalImportsAdded) {
if (contracts.values().contains(TestType.HTTP)) {
if (configProperties.testMode == TestMode.JAXRSCLIENT) {
clazz.addStaticImport('javax.ws.rs.client.Entity.*')
if (configProperties.targetFramework == TestFramework.JUNIT) {
clazz.addImport('javax.ws.rs.core.Response')
}
} else if (configProperties.testMode == TestMode.MOCKMVC) {
clazz.addStaticImport('com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*')
} else {
clazz.addStaticImport('com.jayway.restassured.RestAssured.*')
}
}
if (configProperties.targetFramework == TestFramework.JUNIT) {
if (contracts.values().contains(TestType.HTTP) && configProperties.testMode == TestMode.MOCKMVC) {
clazz.addImport('com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification')
clazz.addImport('com.jayway.restassured.response.ResponseOptions')
}
clazz.addImport('org.junit.Test')
clazz.addStaticImport('org.assertj.core.api.Assertions.assertThat')
}
if (configProperties.ruleClassForTests) {
clazz.addImport('org.junit.Rule').addRule(configProperties.ruleClassForTests)
}
if (contracts.values().contains(TestType.MESSAGING)) {
addMessagingRelatedEntries(clazz)
}
conditionalImportsAdded = true
toIgnore = toIgnore ? true: key.groovyDsl.ignored
}
clazz.addMethod(MethodBuilder.createTestMethod(key.contract, key.stubsFile, key.groovyDsl, configProperties))
}
if (toIgnore) {
clazz.addImport(configProperties.targetFramework.getIgnoreClass())
}
return clazz.build()
}
private Map<ParsedDsl, TestType> mapContractsToTheirTestTypes(Collection<ContractMetadata> listOfFiles) {
return listOfFiles.collectEntries {
File stubsFile = it.path.toFile()
if (log.isDebugEnabled()) {
log.debug("Stub content from file [${stubsFile.text}]")
}
Contract stubContent = it.convertedContract
TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP
return [(new ParsedDsl(it, stubContent, stubsFile)): testType]
}
}
@Canonical
@EqualsAndHashCode
private static class ParsedDsl {
ContractMetadata contract
Contract groovyDsl
File stubsFile
}
private static enum TestType {
MESSAGING, HTTP
}
private boolean isScenarioClass(Collection<ContractMetadata> listOfFiles) {
return listOfFiles.find({ it.order != null }) != null
}
private void addJsonPathRelatedImports(ClassBuilder clazz) {
clazz.addImport(['com.jayway.jsonpath.DocumentContext',
'com.jayway.jsonpath.JsonPath',
])
if (jsonAssertPresent()) {
clazz.addStaticImport(JSON_ASSERT_STATIC_IMPORT)
}
}
private void addMessagingRelatedEntries(ClassBuilder clazz) {
clazz.addField(['@Inject ContractVerifierMessaging contractVerifierMessaging',
'@Inject ContractVerifierObjectMapper contractVerifierObjectMapper'
])
clazz.addImport([ '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',
])
clazz.addStaticImport('org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers')
}
private static boolean jsonAssertPresent() {
try {
Class.forName(JSON_ASSERT_CLASS)
return true
} catch (ClassNotFoundException e) {
if (log.isDebugEnabled()) {
log.debug("JsonAssert is not present on classpath. Will not add a static import.")
}
return false
}
}
}

View File

@@ -16,166 +16,29 @@
package org.springframework.cloud.contract.verifier.builder
import groovy.transform.Canonical
import groovy.transform.EqualsAndHashCode
import groovy.transform.PackageScope
import groovy.util.logging.Slf4j
import org.springframework.cloud.contract.spec.Contract
import groovy.transform.CompileStatic
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.config.TestFramework
import org.springframework.cloud.contract.verifier.config.TestMode
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter
import static org.springframework.cloud.contract.verifier.util.NamesUtil.capitalize
/**
* Builds a single test for the given {@link ContractVerifierConfigProperties properties}
* Builds a single test.
*
* @since 1.0.0
* @since 1.0.3
*/
@Slf4j
class SingleTestGenerator {
private static final String JSON_ASSERT_STATIC_IMPORT = 'com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson'
private static final String JSON_ASSERT_CLASS = 'com.toomuchcoding.jsonassert.JsonAssertion'
private final ContractVerifierConfigProperties configProperties
SingleTestGenerator(ContractVerifierConfigProperties configProperties) {
this.configProperties = configProperties
}
@CompileStatic
interface SingleTestGenerator {
/**
* Returns String code representing a test class with test methods for
* each {@link ContractMetadata}
* 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 includedDirectoryRelativePath - relative path to the included directory
* @return contents of a single test class
*/
@PackageScope
String buildClass(Collection<ContractMetadata> listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) {
ClassBuilder clazz = ClassBuilder.createClass(capitalize(className), classPackage, configProperties, includedDirectoryRelativePath)
if (configProperties.imports) {
configProperties.imports.each {
clazz.addImport(it)
}
}
if (configProperties.staticImports) {
configProperties.staticImports.each {
clazz.addStaticImport(it)
}
}
if (isScenarioClass(listOfFiles)) {
clazz.addImport(configProperties.targetFramework.getOrderAnnotationImport())
clazz.addClassLevelAnnotation(configProperties.targetFramework.getOrderAnnotation())
}
addJsonPathRelatedImports(clazz)
Map<ParsedDsl, TestType> contracts = mapContractsToTheirTestTypes(listOfFiles)
boolean conditionalImportsAdded = false
boolean toIgnore = listOfFiles.ignored.find { it }
contracts.each { ParsedDsl key, TestType value ->
if (!conditionalImportsAdded) {
if (contracts.values().contains(TestType.HTTP)) {
if (configProperties.testMode == TestMode.JAXRSCLIENT) {
clazz.addStaticImport('javax.ws.rs.client.Entity.*')
if (configProperties.targetFramework == TestFramework.JUNIT) {
clazz.addImport('javax.ws.rs.core.Response')
}
} else if (configProperties.testMode == TestMode.MOCKMVC) {
clazz.addStaticImport('com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*')
} else {
clazz.addStaticImport('com.jayway.restassured.RestAssured.*')
}
}
if (configProperties.targetFramework == TestFramework.JUNIT) {
if (contracts.values().contains(TestType.HTTP) && configProperties.testMode == TestMode.MOCKMVC) {
clazz.addImport('com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification')
clazz.addImport('com.jayway.restassured.response.ResponseOptions')
}
clazz.addImport('org.junit.Test')
clazz.addStaticImport('org.assertj.core.api.Assertions.assertThat')
}
if (configProperties.ruleClassForTests) {
clazz.addImport('org.junit.Rule').addRule(configProperties.ruleClassForTests)
}
if (contracts.values().contains(TestType.MESSAGING)) {
addMessagingRelatedEntries(clazz)
}
conditionalImportsAdded = true
toIgnore = toIgnore ? true: key.groovyDsl.ignored
}
clazz.addMethod(MethodBuilder.createTestMethod(key.contract, key.stubsFile, key.groovyDsl, configProperties))
}
if (toIgnore) {
clazz.addImport(configProperties.targetFramework.getIgnoreClass())
}
return clazz.build()
}
private Map<ParsedDsl, TestType> mapContractsToTheirTestTypes(Collection<ContractMetadata> listOfFiles) {
return listOfFiles.collectEntries {
File stubsFile = it.path.toFile()
if (log.isDebugEnabled()) {
log.debug("Stub content from file [${stubsFile.text}]")
}
Contract stubContent = it.convertedContract ?: ContractVerifierDslConverter.convert(stubsFile)
TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP
return [(new ParsedDsl(it, stubContent, stubsFile)): testType]
}
}
@Canonical
@EqualsAndHashCode
private static class ParsedDsl {
ContractMetadata contract
Contract groovyDsl
File stubsFile
}
private static enum TestType {
MESSAGING, HTTP
}
private boolean isScenarioClass(Collection<ContractMetadata> listOfFiles) {
return listOfFiles.find({ it.order != null }) != null
}
private void addJsonPathRelatedImports(ClassBuilder clazz) {
clazz.addImport(['com.jayway.jsonpath.DocumentContext',
'com.jayway.jsonpath.JsonPath',
])
if (jsonAssertPresent()) {
clazz.addStaticImport(JSON_ASSERT_STATIC_IMPORT)
}
}
private void addMessagingRelatedEntries(ClassBuilder clazz) {
clazz.addField(['@Inject ContractVerifierMessaging contractVerifierMessaging',
'@Inject ContractVerifierObjectMapper contractVerifierObjectMapper'
])
clazz.addImport([ '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',
])
clazz.addStaticImport('org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers')
}
private static boolean jsonAssertPresent() {
try {
Class.forName(JSON_ASSERT_CLASS)
return true
} catch (ClassNotFoundException e) {
if (log.isDebugEnabled()) {
log.debug("JsonAssert is not present on classpath. Will not add a static import.")
}
return false
}
}
String buildClass(ContractVerifierConfigProperties properties, Collection<ContractMetadata> listOfFiles,
String className, String classPackage, String includedDirectoryRelativePath)
}

View File

@@ -7,7 +7,8 @@ import org.springframework.cloud.contract.spec.internal.Headers
import org.yaml.snakeyaml.Yaml
/**
* Converter from and to a {@link YamlContract} to a
* Converter from and to a {@link YamlContract} to a {@link Contract}
*
* @author Marcin Grzejszczak
* @since 1.0.3
*/

View File

@@ -23,6 +23,7 @@ import groovy.util.logging.Slf4j
import org.apache.commons.lang3.SystemUtils
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
import java.nio.file.FileSystem
@@ -93,7 +94,7 @@ class ContractFileScanner {
boolean contractFile = isContractFile(file)
boolean included = includeMatcher ? file.absolutePath.matches(includeMatcher) : true
if (contractFile && included) {
addContractToTestGeneration(result, files, file, index)
addContractToTestGeneration(result, files, file, index, ContractVerifierDslConverter.convert(file))
} else if (!contractFile && included) {
addContractToTestGeneration(converters, result, files, file, index)
} else {
@@ -129,7 +130,7 @@ class ContractFileScanner {
}
private void addContractToTestGeneration(ListMultimap<Path, ContractMetadata> result, File[] files, File file,
int index, Contract convertedContract = null) {
int index, Contract convertedContract) {
Path path = file.toPath()
Integer order = null
if (hasScenarioFilenamePattern(path)) {

View File

@@ -16,14 +16,14 @@
package org.springframework.cloud.contract.verifier
import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator
import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.config.TestFramework
import spock.lang.Specification
class GeneratorScannerSpec extends Specification {
private SingleTestGenerator classGenerator = Mock(SingleTestGenerator)
private JavaTestGenerator classGenerator = Mock(JavaTestGenerator)
def "should find all .json files and generate 6 classes for them"() {
given:
@@ -34,7 +34,7 @@ class GeneratorScannerSpec extends Specification {
when:
testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier")
then:
6 * classGenerator.buildClass(_, _, _, _) >> "qwerty"
6 * classGenerator.buildClass(_, _, _, _, _) >> "qwerty"
}
def "should create class with full package"() {
@@ -45,9 +45,9 @@ class GeneratorScannerSpec extends Specification {
when:
testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier")
then:
1 * classGenerator.buildClass(_, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier', _) >> "spec"
1 * classGenerator.buildClass(_, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v1', _) >> "spec1"
1 * classGenerator.buildClass(_, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v2', _) >> "spec2"
1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier', _) >> "spec"
1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v1', _) >> "spec1"
1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v2', _) >> "spec2"
}
}

View File

@@ -26,6 +26,7 @@ import spock.lang.Specification
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT
import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK
import static org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter.convert
class SingleTestGeneratorSpec extends Specification {
@@ -63,13 +64,13 @@ class SingleTestGeneratorSpec extends Specification {
given:
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties();
properties.targetFramework = testFramework
ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2)
ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file))
contract.ignored >> true
contract.order >> 2
SingleTestGenerator testGenerator = new SingleTestGenerator(properties)
JavaTestGenerator testGenerator = new JavaTestGenerator()
when:
String clazz = testGenerator.buildClass([contract], "test", "test", 'com/foo')
String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo')
then:
classStrings.each { clazz.contains(it) }
@@ -85,13 +86,13 @@ class SingleTestGeneratorSpec extends Specification {
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties();
properties.testMode = TestMode.JAXRSCLIENT
properties.targetFramework = testFramework
ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2)
ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file))
contract.ignored >> true
contract.order >> 2
SingleTestGenerator testGenerator = new SingleTestGenerator(properties)
JavaTestGenerator testGenerator = new JavaTestGenerator()
when:
String clazz = testGenerator.buildClass([contract], "test", "test", 'com/foo')
String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo')
then:
classStrings.each { clazz.contains(it) }
@@ -123,18 +124,18 @@ class SingleTestGeneratorSpec extends Specification {
and:
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties();
properties.targetFramework = testFramework
ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2)
ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file))
contract.ignored >> true
contract.order >> 2
and:
ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2)
ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convert(secondFile))
contract2.ignored >> true
contract2.order >> 2
and:
SingleTestGenerator testGenerator = new SingleTestGenerator(properties)
JavaTestGenerator testGenerator = new JavaTestGenerator()
when:
String clazz = testGenerator.buildClass([contract, contract2], "test", "test", 'com/foo')
String clazz = testGenerator.buildClass(properties, [contract, contract2], "test", "test", 'com/foo')
then:
classStrings.each { clazz.contains(it) }
@@ -166,14 +167,14 @@ class SingleTestGeneratorSpec extends Specification {
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties();
properties.targetFramework = testFramework
and:
ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2)
ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convert(file))
contract2.ignored >> false
contract2.order >> 2
and:
SingleTestGenerator testGenerator = new SingleTestGenerator(properties)
JavaTestGenerator testGenerator = new JavaTestGenerator()
when:
String clazz = testGenerator.buildClass([contract2], "test", "test", 'com/foo')
String clazz = testGenerator.buildClass(properties, [contract2], "test", "test", 'com/foo')
then:
classStrings.each { clazz.contains(it) }

View File

@@ -82,7 +82,7 @@ class ContractFileScannerSpec extends Specification {
ListMultimap<Path, ContractMetadata> result = scanner.findContracts()
then:
result.keySet().size() == 1
result.entries().find { it.value.convertedContract && it.value.convertedContract.request.method.clientValue == "PUT" }
result.entries().find { !it.value.convertedContract && !it.value.ignored }
result.entries().every { it.value.convertedContract }
result.entries().find { it.value.convertedContract.request.method.clientValue == "PUT" }
}
}

View File

@@ -1,3 +1,5 @@
import org.springframework.cloud.contract.spec.Contract
/*
* Copyright 2013-2016 the original author or authors.
*
@@ -14,3 +16,33 @@
* limitations under the License.
*/
Contract.make {
request {
method('PUT')
headers {
contentType(applicationJson())
}
body("""\
{
"name": "Jan",
"id": "${value(consumer('abc'), producer('def'))}",
}
"""
)
url $(consumer('/[0-9]{2}'), producer('/12'))
}
response {
status 200
body("""\
{
"name": "Jan",
"id": "${value(consumer('123'), producer('321'))}",
"surname": "${value(consumer('Kowalsky'), producer('$checkIfSurnameValid($value)'))}"
}
"""
)
headers {
contentType(textPlain())
}
}
}