Bumped up version and polished

This commit is contained in:
Marcin Grzejszczak
2016-12-06 23:06:39 +01:00
committed by Marcin Grzejszczak
parent 96525b2ad5
commit d69670db68
22 changed files with 310 additions and 71 deletions

View File

@@ -43,7 +43,7 @@ interface SingleFileConverter {
* Returns the collection of converted contracts into stubs. One contract can
* result in multiple stubs.
*/
Collection<String> convertContents(String rootName, ContractMetadata content)
Map<Contract, String> convertContents(String rootName, ContractMetadata content)
/**
* Returns the name of the converted stub file. If you have multiple contracts

View File

@@ -23,7 +23,6 @@ import org.springframework.cloud.contract.verifier.file.ContractMetadata
import org.springframework.cloud.contract.verifier.util.NamesUtil
import java.nio.charset.StandardCharsets
/**
* Converts DSLs to WireMock stubs
*
@@ -44,15 +43,19 @@ class DslToWireMockClientConverter extends DslToWireMockConverter {
}
@Override
Collection<String> convertContents(String rootName, ContractMetadata contract) {
if (contract.convertedContract.size() == 1) {
return [convertASingleContract(rootName, contract, contract.convertedContract.first())]
Map<Contract, String> convertContents(String rootName, ContractMetadata contract) {
if (!(contract.convertedContract.any { it.request })) {
return [:]
}
List<String> convertedContracts = []
contract.convertedContract.eachWithIndex { Contract dsl, int index ->
if (contract.convertedContract.size() == 1) {
return [(contract.convertedContract.first()): convertASingleContract(rootName, contract, contract.convertedContract.first())]
}
Map<Contract, String> convertedContracts = [:]
contract.convertedContract.findAll { it.request }.eachWithIndex { Contract dsl, int index ->
String name = dsl.name ? NamesUtil.convertIllegalPackageChars(dsl.name) : "${rootName}_${index}"
convertedContracts << convertASingleContract(name, contract, dsl)
convertedContracts << [(dsl) : convertASingleContract(name, contract, dsl)]
}
return convertedContracts
}
}

View File

@@ -88,15 +88,17 @@ class RecursiveFilesConverter {
return
}
int contractsSize = contract.convertedContract.size()
contract.convertedContract.eachWithIndex { Contract dsl, int index ->
String convertedContent = singleFileConverter.convertContent(entry.key.last().toString(), contract)
if (!convertedContent) {
return
}
Map<Contract, String> convertedContent = singleFileConverter.convertContents(entry.key.last().toString(), contract)
if (!convertedContent) {
return
}
convertedContent.entrySet().eachWithIndex { Map.Entry<Contract, String> content, int index ->
Contract dsl = content.key
String converted = content.value
Path absoluteTargetPath = createAndReturnTargetDirectory(sourceFile)
File newJsonFile = createTargetFileWithProperName(singleFileConverter, absoluteTargetPath,
sourceFile, contractsSize, index, dsl)
newJsonFile.setText(convertedContent, StandardCharsets.UTF_8.toString())
newJsonFile.setText(converted, StandardCharsets.UTF_8.toString())
}
} catch (Exception e) {
throw new ConversionContractVerifierException("Unable to make conversion of ${sourceFile.name}", e)

View File

@@ -20,6 +20,7 @@ import com.github.tomakehurst.wiremock.stubbing.StubMapping
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import org.skyscreamer.jsonassert.JSONAssert
import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.file.ContractMetadata
import spock.lang.Issue
import spock.lang.Specification
@@ -46,7 +47,7 @@ class DslToWireMockClientConverterSpec extends Specification {
}
""")
when:
String json = converter.convertContent("Test", new ContractMetadata(file.toPath(), false, 0, null))
String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null)).values().first()
then:
JSONAssert.assertEquals('''
{"request":{"method":"PUT","urlPattern":"/[0-9]{2}"},"response":{"status":200}}
@@ -75,17 +76,37 @@ class DslToWireMockClientConverterSpec extends Specification {
}
''')
when:
List<String> json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null))
Map<Contract, String> convertedContents = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null))
then:
json.size() == 2
JSONAssert.assertEquals(jsonResponse(1), json.first(), false)
JSONAssert.assertEquals(jsonResponse(2), json.last(), false)
convertedContents.size() == 2
JSONAssert.assertEquals(jsonResponse(1), convertedContents.values().first(), false)
JSONAssert.assertEquals(jsonResponse(2), convertedContents.values().last(), false)
}
private String jsonResponse(int index) {
return """{"request":{"method":"PUT","url":"/${index}"},"response":{"status":200}}"""
}
def "should not convert if contract is messaging related"() {
given:
def converter = new DslToWireMockClientConverter()
and:
File file = tmpFolder.newFile("dsl1_list.groovy")
file.write('''
(1..2).collect { int index ->
org.springframework.cloud.contract.spec.Contract.make {
input {
}
}
}
''')
when:
Map<Contract, String> convertedContents = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null))
then:
convertedContents.isEmpty()
}
@Issue("196")
def "should creation of delayed stub responses be possible"() {
given:
@@ -105,7 +126,7 @@ class DslToWireMockClientConverterSpec extends Specification {
}
""")
when:
String json = converter.convertContent("test", new ContractMetadata(file.toPath(), false, 0, null))
String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null)).values().first()
then:
JSONAssert.assertEquals('''
{"request":{
@@ -168,7 +189,7 @@ class DslToWireMockClientConverterSpec extends Specification {
}
""")
when:
String json = converter.convertContent("Test", new ContractMetadata(file.toPath(), false, 0, null))
String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null)).values().first()
then:
JSONAssert.assertEquals('''
{
@@ -250,7 +271,7 @@ class DslToWireMockClientConverterSpec extends Specification {
}
""")
when:
String json = converter.convertContent("test", new ContractMetadata(file.toPath(), false, 0, null))
String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null)).values().first()
then:
JSONAssert.assertEquals('''
{"request":{"urlPath":"/foos","method":"GET"},"response":{"body":"[{\\"id\\":\\"123\\"},{\\"id\\":\\"567\\"}]"}}
@@ -280,7 +301,7 @@ class DslToWireMockClientConverterSpec extends Specification {
}
""")
when:
String json = converter.convertContent("test", new ContractMetadata(file.toPath(), false, 0, null))
String json = converter.convertContents("test", new ContractMetadata(file.toPath(), false, 0, null)).values().first()
StubMapping.buildFrom(json)
then:
noExceptionThrown()
@@ -320,7 +341,7 @@ class DslToWireMockClientConverterSpec extends Specification {
}
''')
when:
String json = converter.convertContent("Test", new ContractMetadata(file.toPath(), false, 0, null))
String json = converter.convertContents("Test", new ContractMetadata(file.toPath(), false, 0, null)).values().first()
then:
JSONAssert.assertEquals( // tag::wiremock[]
'''

View File

@@ -17,19 +17,17 @@
package org.springframework.cloud.contract.verifier.wiremock
import groovy.io.FileType
import org.springframework.cloud.contract.verifier.converter.SingleFileConvertersHolder
import java.nio.file.Path
import java.nio.file.Paths
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
import org.springframework.cloud.contract.verifier.converter.SingleFileConverter
import org.springframework.cloud.contract.verifier.converter.SingleFileConvertersHolder
import org.springframework.util.FileSystemUtils
import spock.lang.Specification
import java.nio.file.Path
import java.nio.file.Paths
class RecursiveFilesConverterSpec extends Specification {
private static
@@ -49,12 +47,7 @@ class RecursiveFilesConverterSpec extends Specification {
properties.stubsOutputDir = tmpFolder.newFolder("target")
FileSystemUtils.copyRecursively(originalSourceRootDirectory, properties.contractsDslDir)
and:
def singleFileConverterStub = Stub(SingleFileConverter)
singleFileConverterStub.canHandleFileName(_) >> { String fileName -> fileName.endsWith(".groovy") }
singleFileConverterStub.convertContent(_, _) >> { "converted" }
singleFileConverterStub.generateOutputFileNameForInput(_) >> { String inputFileName -> inputFileName.replaceAll('.groovy', '.json') }
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(singleFileConverterStub, properties)
RecursiveFilesConverter recursiveFilesConverter = new RecursiveFilesConverter(properties)
when:
recursiveFilesConverter.processFiles()
then:
@@ -63,7 +56,7 @@ class RecursiveFilesConverterSpec extends Specification {
Set<String> relativizedCreatedFiles = getRelativePathsForFilesInDirectory(createdFiles, properties.stubsOutputDir)
EXPECTED_TARGET_FILES == relativizedCreatedFiles
and:
createdFiles.each { it.text == "converted" }
createdFiles.each { assert it.text.contains("uuid") }
}
def "should recursively convert matching files with exlusions"() {
@@ -98,7 +91,7 @@ class RecursiveFilesConverterSpec extends Specification {
and:
def singleFileConverterStub = Stub(SingleFileConverter)
singleFileConverterStub.canHandleFileName(_) >> { true }
singleFileConverterStub.convertContent(_, _) >> { throw new NullPointerException("Test conversion error") }
singleFileConverterStub.convertContents(_, _) >> { throw new NullPointerException("Test conversion error") }
singleFileConverterStub.generateOutputFileNameForInput(_) >> { String inputFileName -> "${inputFileName}2" }
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
properties.contractsDslDir = tmpFolder.root

View File

@@ -70,7 +70,7 @@ class ContractVerifierExtension {
File generatedTestSourcesDir
/**
* Dir where the generated WireMock stubs from Groovy DSL should be placed.
* Dir where the generated stubs from Groovy DSL should be placed.
* You can then mention them in your packaging task to create jar with stubs
*/
File stubsOutputDir

View File

@@ -26,7 +26,8 @@ import org.springframework.cloud.contract.verifier.wiremock.RecursiveFilesConver
import static org.springframework.cloud.contract.verifier.plugin.SpringCloudContractVerifierGradlePlugin.COPY_CONTRACTS_TASK_NAME
//TODO: Implement as an incremental task: https://gradle.org/docs/current/userguide/custom_tasks.html#incremental_tasks ?
/**
* Generates WireMock stubs from the contracts
* Generates stubs from the contracts. The name is WireMock related but the implementation
* can differ
*
* @since 1.0.0
*/
@@ -45,7 +46,7 @@ class GenerateWireMockClientStubsFromDslTask extends ConventionTask {
Task copyContractsTask = project.getTasksByName(COPY_CONTRACTS_TASK_NAME, false).first()
ContractVerifierConfigProperties props = props(copyContractsTask)
File contractsDslDir = contractsDslDir(copyContractsTask, props)
logger.info("Spring Cloud Contract Verifier Plugin: Invoking DSL to WireMock client stubs conversion")
logger.info("Spring Cloud Contract Verifier Plugin: Invoking DSL to client stubs conversion")
props.contractsDslDir = contractsDslDir
props.includedContracts = ".*"
File outMappingsDir = getStubsOutputDir() != null ? new File(getStubsOutputDir(), DEFAULT_MAPPINGS_FOLDER)
@@ -71,7 +72,7 @@ class GenerateWireMockClientStubsFromDslTask extends ConventionTask {
try {
return task.ext.contractsDslDir
} catch (Exception e) {
project.logger.error("Couldn't retrieve the contractdsl property set by the copy contracts task", e)
project.logger.error("Couldn't retrieve the contract dsl property set by the copy contracts task", e)
return props.contractsDslDir
}
}

View File

@@ -47,7 +47,8 @@ import org.gradle.jvm.tasks.Jar
class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
private static final String GENERATE_SERVER_TESTS_TASK_NAME = 'generateContractTests'
private static final String DSL_TO_WIREMOCK_CLIENT_TASK_NAME = 'generateWireMockClientStubs'
private static final String DEPRECATED_DSL_TO_WIREMOCK_CLIENT_TASK_NAME = 'generateWireMockClientStubs'
private static final String DSL_TO_CLIENT_TASK_NAME = 'generateClientStubs'
@PackageScope static final String COPY_CONTRACTS_TASK_NAME = 'copyContracts'
private static final String VERIFIER_STUBS_JAR_TASK_NAME = 'verifierStubsJar'
@@ -69,7 +70,8 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
Task copyContracts = createAndConfigureCopyContractsTask(stubsJar, downloader, extension)
createAndConfigureMavenPublishPlugin(stubsJar)
createGenerateTestsTask(extension, copyContracts)
createAndConfigureGenerateWireMockClientStubsFromDslTask(extension, copyContracts)
Task clientTask = createAndConfigureGenerateClientStubsFromDslTask(extension, copyContracts)
createAndConfigureGenerateWireMockClientStubsFromDslTask(extension, clientTask)
addProjectDependencies(project)
addIdeaTestSources(project, extension)
}
@@ -89,6 +91,7 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
}
private void addProjectDependencies(Project project) {
//TODO: Consider removing this at some point
project.dependencies.add("testCompile", "com.github.tomakehurst:wiremock:2.1.7")
project.dependencies.add("testCompile", "com.toomuchcoding.jsonassert:jsonassert:0.4.7")
project.dependencies.add("testCompile", "org.assertj:assertj-core:2.3.0")
@@ -119,10 +122,19 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
task.dependsOn copyContracts
}
// TODO: Remove this task at some point
private void createAndConfigureGenerateWireMockClientStubsFromDslTask(ContractVerifierExtension extension,
Task mainTask) {
Task task = project.tasks.create(DEPRECATED_DSL_TO_WIREMOCK_CLIENT_TASK_NAME)
task.description = "DEPRECATED: Generate WireMock client stubs from the contracts. Use ${DSL_TO_CLIENT_TASK_NAME} task."
task.group = GROUP_NAME
task.dependsOn mainTask
}
private Task createAndConfigureGenerateClientStubsFromDslTask(ContractVerifierExtension extension,
Task copyContracts) {
Task task = project.tasks.create(DSL_TO_WIREMOCK_CLIENT_TASK_NAME, GenerateWireMockClientStubsFromDslTask)
task.description = "Generate WireMock client stubs from the contracts"
Task task = project.tasks.create(DSL_TO_CLIENT_TASK_NAME, GenerateWireMockClientStubsFromDslTask)
task.description = "Generate client stubs from the contracts"
task.group = GROUP_NAME
task.conventionMapping.with {
downloader = { gradleContractsDownloader }
@@ -130,6 +142,7 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
configProperties = { extension }
}
task.dependsOn copyContracts
return task
}
private Task createAndConfigureStubsJarTasks(ContractVerifierExtension extension) {
@@ -139,7 +152,7 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin<Project> {
return task
} else {
task = project.tasks.create(type: Jar, name: VERIFIER_STUBS_JAR_TASK_NAME,
dependsOn: DSL_TO_WIREMOCK_CLIENT_TASK_NAME) {
dependsOn: DSL_TO_CLIENT_TASK_NAME) {
baseName = project.name
classifier = extension.stubsSuffix
from { extension.stubsOutputDir ?: project.file("${project.buildDir}/stubs") }

View File

@@ -43,6 +43,7 @@ class BasicFunctionalSpec extends ContractVerifierIntegrationSpec {
BuildResult result = run(checkAndPublishToMavenLocal())
then:
result.task(":generateWireMockClientStubs").outcome == SUCCESS
result.task(":generateClientStubs").outcome == SUCCESS
result.task(":generateContractTests").outcome == SUCCESS
and: "tests generated"

View File

@@ -55,7 +55,7 @@ class ContractVerifierSpec extends Specification {
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
expect:
project.tasks.findByName("generateWireMockClientStubs") != null
project.tasks.findByName("generateClientStubs") != null
}
def "should create verifierStubsJar task"() {
@@ -71,7 +71,7 @@ class ContractVerifierSpec extends Specification {
project.plugins.apply(SpringCloudContractVerifierGradlePlugin)
expect:
project.tasks.verifierStubsJar.getDependsOn().contains("generateWireMockClientStubs")
project.tasks.verifierStubsJar.getDependsOn().contains("generateClientStubs")
}
def "should create copyContracts task"() {

View File

@@ -16,6 +16,11 @@
*/
package org.springframework.cloud.contract.maven.verifier;
import static io.takari.maven.testing.TestMavenRuntime.newParameter;
import static io.takari.maven.testing.TestResources.assertFilesNotPresent;
import static io.takari.maven.testing.TestResources.assertFilesPresent;
import static org.assertj.core.api.BDDAssertions.then;
import java.io.File;
import org.apache.commons.io.FileUtils;
@@ -25,11 +30,6 @@ import org.junit.Test;
import io.takari.maven.testing.TestMavenRuntime;
import io.takari.maven.testing.TestResources;
import static io.takari.maven.testing.TestMavenRuntime.newParameter;
import static io.takari.maven.testing.TestResources.assertFilesNotPresent;
import static io.takari.maven.testing.TestResources.assertFilesPresent;
import static org.assertj.core.api.BDDAssertions.then;
public class PluginUnitTest {
@Rule
@@ -213,4 +213,34 @@ public class PluginUnitTest {
File test = new File(basedir, path);
then(FileUtils.readFileToString(test)).contains("extends TestBase").contains("import com.example.TestBase");
}
@Test
public void shouldGenerateContractTestsWithAFileContainingAListOfContracts() throws Exception {
File basedir = this.resources.getBasedir("multiple-contracts");
this.maven.executeMojo(basedir, "generateTests", newParameter("testFramework", "JUNIT"));
String path = "target/generated-test-sources/contracts/org/springframework/cloud/contract/verifier/tests/com/hello/V1Test.java";
assertFilesPresent(basedir, path);
File test = new File(basedir, path);
then(FileUtils.readFileToString(test))
.contains("public void validate_should_post_a_user() throws Exception {")
.contains("public void validate_withList_1() throws Exception {");
}
@Test
public void shouldGenerateStubsWithAFileContainingAListOfContracts() throws Exception {
File basedir = this.resources.getBasedir("multiple-contracts");
this.maven.executeMojo(basedir, "convert", newParameter("stubsDirectory", "target/foo"));
String firstFile = "target/foo/mappings/com/hello/v1/should post a user.json";
File test = new File(basedir, firstFile);
assertFilesPresent(basedir, "target/foo/mappings/com/hello/v1/1_WithList.json");
then(FileUtils.readFileToString(test)).contains("/users/1");
String secondFile = "target/foo/mappings/com/hello/v1/1_WithList.json";
File test2 = new File(basedir, secondFile);
assertFilesPresent(basedir, "target/foo/mappings/com/hello/v1/should post a user.json");
then(FileUtils.readFileToString(test2)).contains("/users/2");
}
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud.verifier.sample</groupId>
<artifactId>sample-project</artifactId>
<version>0.1</version>
<build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<configuration>
<baseClassForTests>com.example.FooBase</baseClassForTests>
<baseClassMappings>
<baseClassMapping>
<contractPackageRegex>.*com.*</contractPackageRegex>
<baseClassFQN>com.example.TestBase</baseClassFQN>
</baseClassMapping >
</baseClassMappings>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,40 @@
/**
*
* 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.
*/
import org.springframework.cloud.contract.spec.Contract
[
Contract.make {
name("should post a user")
request {
method 'POST'
url('/users/1')
}
response {
status 200
}
},
Contract.make {
request {
method 'POST'
url('/users/2')
}
response {
status 200
}
}
]