Re-instate integration tests for stub runner messaging
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -38,6 +38,7 @@
|
||||
<module>spring-cloud-contract-stub-runner</module>
|
||||
<module>spring-cloud-contract-starters</module>
|
||||
<module>spring-cloud-contract-tools</module>
|
||||
<module>tests</module>
|
||||
<module>samples</module>
|
||||
</modules>
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import org.apache.camel.RoutesBuilder;
|
||||
import org.apache.camel.spring.SpringRouteBuilder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.contract.spec.Contract;
|
||||
import org.springframework.cloud.contract.stubrunner.BatchStubRunner;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(RoutesBuilder.class)
|
||||
@ConditionalOnProperty(name="stubrunner.camel.enabled", havingValue="true", matchIfMissing=true)
|
||||
public class StubRunnerCamelConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.Map.Entry;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
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.spec.Contract;
|
||||
import org.springframework.cloud.contract.stubrunner.BatchStubRunner;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.messaging.Message;
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(IntegrationFlowBuilder.class)
|
||||
@ConditionalOnProperty(name="stubrunner.integration.enabled", havingValue="true", matchIfMissing=true)
|
||||
public class StubRunnerIntegrationConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -23,11 +23,15 @@ import java.util.Map.Entry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
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.spec.Contract;
|
||||
import org.springframework.cloud.contract.stubrunner.BatchStubRunner;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.messaging.integration.StubRunnerIntegrationConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.messaging.stream.StubRunnerStreamConfiguration.FlowRegistrar;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.config.BindingProperties;
|
||||
@@ -52,6 +56,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({FlowRegistrar.class, EnableBinding.class})
|
||||
@ConditionalOnProperty(name="stubrunner.stream.enabled", havingValue="true", matchIfMissing=true)
|
||||
@AutoConfigureBefore(StubRunnerIntegrationConfiguration.class)
|
||||
public class StubRunnerStreamConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
@@ -59,6 +65,7 @@ public class StubRunnerStreamConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name="stubFlowRegistrar")
|
||||
@ConditionalOnBean(ChannelBindingServiceProperties.class)
|
||||
public FlowRegistrar stubFlowRegistrar(AutowireCapableBeanFactory beanFactory,
|
||||
BatchStubRunner batchStubRunner) {
|
||||
Map<StubConfiguration, Collection<Contract>> contracts = batchStubRunner
|
||||
|
||||
@@ -35,7 +35,7 @@ import spock.lang.Specification
|
||||
// tag::test[]
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
// Not necessary if Spring Cloud is used. TODO: make it work without this.
|
||||
@IntegrationTest("stubrunner.cloud.enabled=false")
|
||||
@IntegrationTest(["stubrunner.cloud.enabled=false", "stubrunner.camel.enabled=false"])
|
||||
@AutoConfigureStubRunner
|
||||
@DirtiesContext
|
||||
class StubRunnerConfigurationSpec extends Specification {
|
||||
|
||||
@@ -45,7 +45,7 @@ import spock.lang.Specification
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@WebIntegrationTest(randomPort = true)
|
||||
@IntegrationTest
|
||||
@IntegrationTest("stubrunner.camel.enabled=false")
|
||||
@AutoConfigureStubRunner
|
||||
@DirtiesContext
|
||||
class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
|
||||
@@ -77,7 +77,7 @@ class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
zookeeperServiceDiscovery.serviceDiscovery.close()
|
||||
zookeeperServiceDiscovery?.serviceDiscovery?.close()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
37
tests/pom.xml
Normal file
37
tests/pom.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-parent</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-cloud-contract-tests</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Spring Cloud Contract Tests</name>
|
||||
<description>Spring Cloud Contract Tests</description>
|
||||
|
||||
<modules>
|
||||
<module>spring-cloud-contract-stub-runner-camel</module>
|
||||
<module>spring-cloud-contract-stub-runner-integration</module>
|
||||
<module>spring-cloud-contract-stub-runner-stream</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
123
tests/spring-cloud-contract-stub-runner-camel/README.adoc
Normal file
123
tests/spring-cloud-contract-stub-runner-camel/README.adoc
Normal file
@@ -0,0 +1,123 @@
|
||||
:input_name: jms:input
|
||||
:output_name: jms:output
|
||||
|
||||
=== Stub Runner Camel
|
||||
|
||||
Spring Cloud Contract Verifier Stub Runner's messaging module gives you an easy way to integrate with Apache Camel.
|
||||
For the provided artifacts it will automatically download the stubs and register the required
|
||||
routes.
|
||||
|
||||
==== Adding it to the project
|
||||
|
||||
To use it you have to add the following dependency to your project (example for Gradle):
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
testCompile "org.springframework.cloud:stub-runner-camel:${verifierVersion}"
|
||||
----
|
||||
|
||||
==== Examples
|
||||
|
||||
===== Stubs structure
|
||||
|
||||
Let us assume that we have the following Maven repository with a deployed stubs for the
|
||||
`camelService` application.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── camelService
|
||||
├── 0.0.1-SNAPSHOT
|
||||
│ ├── camelService-0.0.1-SNAPSHOT.pom
|
||||
│ ├── camelService-0.0.1-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
|
||||
And the stubs contain the following structure:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ ├── bookDeleted.groovy
|
||||
│ ├── bookReturned1.groovy
|
||||
│ └── bookReturned2.groovy
|
||||
└── mappings
|
||||
----
|
||||
|
||||
Let's consider the following contracts (let' number it with *1*):
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
|
||||
and number *2*
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=sample_dsl_2,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 1 (no input message)
|
||||
|
||||
So as to trigger a message via the `return_book_1` label we'll use the `StubTigger` interface as follows
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
|
||||
Next we'll want to listen to the output of the message sent to `{output_name}`
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_trigger_receive,indent=0]
|
||||
----
|
||||
|
||||
And the received message would pass the following assertions
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_trigger_message,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 2 (output triggered by input)
|
||||
|
||||
Since the route is set for you it's enough to just send a message to the `{output_name}` destination.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_send,indent=0]
|
||||
----
|
||||
|
||||
Next we'll want to listen to the output of the message sent to `{output_name}`
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_receive,indent=0]
|
||||
----
|
||||
|
||||
And the received message would pass the following assertions
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_receive_message,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 3 (input with no output)
|
||||
|
||||
Since the route is set for you it's enough to just send a message to the `{output_name}` destination.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=trigger_no_output,indent=0]
|
||||
----
|
||||
94
tests/spring-cloud-contract-stub-runner-camel/pom.xml
Normal file
94
tests/spring-cloud-contract-stub-runner-camel/pom.xml
Normal file
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner-build</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-stub-runner-camel</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Stub Runner Camel</name>
|
||||
<description>Spring Cloud Contract Stub Runner Camel</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner-jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-camel</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-pool</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.solidsoft.spock</groupId>
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.stubrunner.messaging.camel
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
@CompileStatic
|
||||
@EqualsAndHashCode
|
||||
class BookReturned implements Serializable {
|
||||
final String bookName
|
||||
|
||||
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
|
||||
BookReturned(String bookName) {
|
||||
this.bookName = bookName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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.stubrunner.messaging.camel
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
import org.apache.activemq.camel.component.ActiveMQComponent
|
||||
import org.apache.activemq.spring.ActiveMQConnectionFactory
|
||||
import org.apache.camel.CamelContext
|
||||
import org.apache.camel.Exchange
|
||||
import org.apache.camel.component.jms.JmsConfiguration
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.IntegrationTest
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@IntegrationTest("debug=true")
|
||||
@AutoConfigureStubRunner
|
||||
class CamelStubRunnerSpec extends Specification {
|
||||
|
||||
@Autowired StubFinder stubFinder
|
||||
@Autowired CamelContext camelContext
|
||||
|
||||
def setup() {
|
||||
// ensure that message were taken from the queue
|
||||
camelContext.createConsumerTemplate().receive('jms:output', 100)
|
||||
}
|
||||
|
||||
def 'should download the stub and register a route for it'() {
|
||||
when:
|
||||
// tag::client_send[]
|
||||
camelContext.createProducerTemplate().sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header'])
|
||||
// end::client_send[]
|
||||
then:
|
||||
// tag::client_receive[]
|
||||
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
|
||||
// end::client_receive[]
|
||||
and:
|
||||
// tag::client_receive_message[]
|
||||
receivedMessage != null
|
||||
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
|
||||
receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
|
||||
// end::client_receive_message[]
|
||||
}
|
||||
|
||||
def 'should trigger a message by label'() {
|
||||
when:
|
||||
// tag::client_trigger[]
|
||||
stubFinder.trigger('return_book_1')
|
||||
// end::client_trigger[]
|
||||
then:
|
||||
// tag::client_trigger_receive[]
|
||||
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
|
||||
// end::client_trigger_receive[]
|
||||
and:
|
||||
// tag::client_trigger_message[]
|
||||
receivedMessage != null
|
||||
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
|
||||
receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
|
||||
// end::client_trigger_message[]
|
||||
}
|
||||
|
||||
def 'should trigger a label for the existing groupId:artifactId'() {
|
||||
when:
|
||||
// tag::trigger_group_artifact[]
|
||||
stubFinder.trigger('org.springframework.cloud.contract.verifier.stubs:camelService', 'return_book_1')
|
||||
// end::trigger_group_artifact[]
|
||||
then:
|
||||
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
|
||||
receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should trigger a label for the existing artifactId'() {
|
||||
when:
|
||||
// tag::trigger_artifact[]
|
||||
stubFinder.trigger('camelService', 'return_book_1')
|
||||
// end::trigger_artifact[]
|
||||
then:
|
||||
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
|
||||
receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should throw an exception when missing label is passed'() {
|
||||
when:
|
||||
stubFinder.trigger('missing label')
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def 'should throw an exception when missing label and artifactid is passed'() {
|
||||
when:
|
||||
stubFinder.trigger('some:service', 'return_book_1')
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def 'should trigger messages by running all triggers'() {
|
||||
when:
|
||||
// tag::trigger_all[]
|
||||
stubFinder.trigger()
|
||||
// end::trigger_all[]
|
||||
then:
|
||||
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000)
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertThatBodyContainsBookNameFoo(receivedMessage.in.body)
|
||||
receivedMessage.in.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should trigger a label with no output message'() {
|
||||
when:
|
||||
// tag::trigger_no_output[]
|
||||
camelContext.createProducerTemplate().sendBodyAndHeaders('jms:delete', new BookReturned('foo'), [sample: 'header'])
|
||||
// end::trigger_no_output[]
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def 'should not trigger a message that does not match input'() {
|
||||
when:
|
||||
camelContext.createProducerTemplate().sendBodyAndHeaders('jms:input', new BookReturned('notmatching'), [wrong: 'header_value'])
|
||||
then:
|
||||
Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 100)
|
||||
and:
|
||||
receivedMessage == null
|
||||
}
|
||||
|
||||
private boolean assertThatBodyContainsBookNameFoo(Object payload) {
|
||||
String objectAsString = payload instanceof String ? payload :
|
||||
JsonOutput.toJson(payload)
|
||||
def json = new JsonSlurper().parseText(objectAsString)
|
||||
return json.bookName == 'foo'
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ActiveMQConnectionFactory activeMQConnectionFactory(@Value('${activemq.url:vm://localhost?broker.persistent=false}') String url) {
|
||||
return new ActiveMQConnectionFactory(brokerURL: url, trustAllPackages: true)
|
||||
}
|
||||
|
||||
@Bean
|
||||
JmsConfiguration jmsConfiguration(ActiveMQConnectionFactory activeMQConnectionFactory) {
|
||||
return new JmsConfiguration(connectionFactory: activeMQConnectionFactory)
|
||||
}
|
||||
|
||||
@Bean
|
||||
ActiveMQComponent activeMQComponent(JmsConfiguration jmsConfiguration) {
|
||||
return new ActiveMQComponent(configuration: jmsConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Contract dsl =
|
||||
// tag::sample_dsl[]
|
||||
Contract.make {
|
||||
label 'return_book_1'
|
||||
input {
|
||||
triggeredBy('bookReturnedTriggered()')
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('jms:output')
|
||||
body('''{ "bookName" : "foo" }''')
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
// end::sample_dsl[]
|
||||
|
||||
Contract dsl2 =
|
||||
// tag::sample_dsl_2[]
|
||||
Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('jms:input')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('jms:output')
|
||||
body([
|
||||
bookName: 'foo'
|
||||
])
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
// end::sample_dsl_2[]
|
||||
|
||||
Contract dsl3 =
|
||||
// tag::sample_dsl_3[]
|
||||
Contract.make {
|
||||
label 'delete_book'
|
||||
input {
|
||||
messageFrom('jms:delete')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
assertThat('bookWasDeleted()')
|
||||
}
|
||||
}
|
||||
// end::sample_dsl_3[]
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.camel
|
||||
|
||||
import org.apache.camel.CamelContext
|
||||
import org.apache.camel.Exchange
|
||||
import org.apache.camel.builder.ExchangeBuilder
|
||||
import org.apache.camel.spring.SpringCamelContext
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import spock.lang.Specification
|
||||
|
||||
class StubRunnerCamelProcessorSpec extends Specification {
|
||||
|
||||
CamelContext camelContext = new SpringCamelContext()
|
||||
Exchange message = ExchangeBuilder.anExchange(camelContext).build()
|
||||
|
||||
def noOutputMessageContract = Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookId: $(consumer(regex('[0-9]+')), producer('123'))
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def 'should not process the message if there is no output message'() {
|
||||
given:
|
||||
StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor(noOutputMessageContract)
|
||||
when:
|
||||
processor.process(message)
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def dsl = Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookId: $(consumer(regex('[0-9]+')), producer('123'))
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('returnBook')
|
||||
body([
|
||||
responseId: $(producer(regex('[0-9]+')), consumer('123'))
|
||||
])
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def 'should process message when it has an output message section'() {
|
||||
given:
|
||||
StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor(dsl)
|
||||
when:
|
||||
processor.process(message)
|
||||
then:
|
||||
message.getIn().getBody(String) == '{"responseId":"123"}'
|
||||
}
|
||||
|
||||
def dslWithRegexInGString = Contract.make {
|
||||
// Human readable description
|
||||
description 'Should produce valid sensor data'
|
||||
// Label by means of which the output message can be triggered
|
||||
label 'sensor1'
|
||||
// input to the contract
|
||||
input {
|
||||
// the contract will be triggered by a method
|
||||
triggeredBy('createSensorData()')
|
||||
}
|
||||
// output message of the contract
|
||||
outputMessage {
|
||||
// destination to which the output message will be sent
|
||||
sentTo 'sensor-data'
|
||||
headers {
|
||||
header('contentType': 'application/json')
|
||||
}
|
||||
// the body of the output message
|
||||
body("""{"id":"${value(producer(regex('[0-9]+')), consumer('99'))}","temperature":"123.45"}""")
|
||||
}
|
||||
}
|
||||
|
||||
def 'should convert dsl into message with regex in GString'() {
|
||||
given:
|
||||
StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor(dslWithRegexInGString)
|
||||
when:
|
||||
processor.process(message)
|
||||
then:
|
||||
message.getIn().getBody(String) == '''{"id":"99","temperature":"123.45"}'''
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
stubrunner.stubs.repositoryRoot: classpath:m2repo/repository/
|
||||
stubrunner.stubs.ids: org.springframework.cloud.contract.verifier.stubs:camelService
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>camelService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>camelService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<snapshot>
|
||||
<localCopy>true</localCopy>
|
||||
</snapshot>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>camelService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>camelService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
131
tests/spring-cloud-contract-stub-runner-integration/README.adoc
Normal file
131
tests/spring-cloud-contract-stub-runner-integration/README.adoc
Normal file
@@ -0,0 +1,131 @@
|
||||
:input_name: input
|
||||
:output_name: output
|
||||
|
||||
=== Stub Runner Integration
|
||||
|
||||
Spring Cloud Contract Verifier Stub Runner's messaging module gives you an easy way to integrate with Spring Integration.
|
||||
For the provided artifacts it will automatically download the stubs and register the required
|
||||
routes.
|
||||
|
||||
==== Adding it to the project
|
||||
|
||||
To use it you have to add the following dependency to your project (example for Gradle):
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
testCompile "org.springframework.cloud:stub-runner-integration:${verifierVersion}"
|
||||
----
|
||||
|
||||
==== Examples
|
||||
|
||||
===== Stubs structure
|
||||
|
||||
Let us assume that we have the following Maven repository with a deployed stubs for the
|
||||
`integrationService` application.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── integrationService
|
||||
├── 0.0.1-SNAPSHOT
|
||||
│ ├── integrationService-0.0.1-SNAPSHOT.pom
|
||||
│ ├── integrationService-0.0.1-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
|
||||
And the stubs contain the following structure:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ ├── bookDeleted.groovy
|
||||
│ ├── bookReturned1.groovy
|
||||
│ └── bookReturned2.groovy
|
||||
└── mappings
|
||||
----
|
||||
|
||||
Let's consider the following contracts (let' number it with *1*):
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
|
||||
and number *2*
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=sample_dsl_2,indent=0]
|
||||
----
|
||||
|
||||
and the following Spring Integration Route:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
include::src/test/resources/integration-context.xml[]
|
||||
----
|
||||
|
||||
|
||||
===== Scenario 1 (no input message)
|
||||
|
||||
So as to trigger a message via the `return_book_1` label we'll use the `StubTigger` interface as follows
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
|
||||
Next we'll want to listen to the output of the message sent to `{output_name}`
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_trigger_receive,indent=0]
|
||||
----
|
||||
|
||||
And the received message would pass the following assertions
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_trigger_message,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 2 (output triggered by input)
|
||||
|
||||
Since the route is set for you it's enough to just send a message to the `{output_name}` destination.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_send,indent=0]
|
||||
----
|
||||
|
||||
Next we'll want to listen to the output of the message sent to `{output_name}`
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_receive,indent=0]
|
||||
----
|
||||
|
||||
And the received message would pass the following assertions
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=client_receive_message,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 3 (input with no output)
|
||||
|
||||
Since the route is set for you it's enough to just send a message to the `{input_name}` destination.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy[tags=trigger_no_output,indent=0]
|
||||
----
|
||||
82
tests/spring-cloud-contract-stub-runner-integration/pom.xml
Normal file
82
tests/spring-cloud-contract-stub-runner-integration/pom.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner-build</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-stub-runner-integration</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Stub Runner Integration</name>
|
||||
<description>Spring Cloud Contract Stub Runner Integration</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner-jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-verifier</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-java-dsl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.solidsoft.spock</groupId>
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.stubrunner.messaging.integration
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
@CompileStatic
|
||||
@EqualsAndHashCode
|
||||
class BookReturned implements Serializable {
|
||||
final String bookName
|
||||
|
||||
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
|
||||
BookReturned(String bookName) {
|
||||
this.bookName = bookName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.stubrunner.messaging.integration
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.cloud.contract.verifier.messaging.integration.SpringIntegrationStubMessages
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.ImportResource
|
||||
import org.springframework.messaging.Message
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableAutoConfiguration
|
||||
@ContextConfiguration(classes = IntegrationStubRunnerSpec, loader = SpringBootContextLoader)
|
||||
@ImportResource("classpath*:integration-context.xml")
|
||||
@AutoConfigureStubRunner
|
||||
class IntegrationStubRunnerSpec extends Specification {
|
||||
|
||||
@Autowired StubFinder stubFinder
|
||||
@Autowired SpringIntegrationStubMessages messaging
|
||||
|
||||
def setup() {
|
||||
// ensure that message were taken from the queue
|
||||
messaging.receive('outputTest', 100, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
def 'should download the stub and register a route for it'() {
|
||||
when:
|
||||
// tag::client_send[]
|
||||
messaging.send(new BookReturned('foo'), [sample: 'header'], 'input')
|
||||
// end::client_send[]
|
||||
then:
|
||||
// tag::client_receive[]
|
||||
Message<?> receivedMessage = messaging.receive('outputTest')
|
||||
// end::client_receive[]
|
||||
and:
|
||||
// tag::client_receive_message[]
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
// end::client_receive_message[]
|
||||
}
|
||||
|
||||
def 'should trigger a message by label'() {
|
||||
when:
|
||||
// tag::client_trigger[]
|
||||
stubFinder.trigger('return_book_1')
|
||||
// end::client_trigger[]
|
||||
then:
|
||||
// tag::client_trigger_receive[]
|
||||
Message<?> receivedMessage = messaging.receive('outputTest')
|
||||
// end::client_trigger_receive[]
|
||||
and:
|
||||
// tag::client_trigger_message[]
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
// end::client_trigger_message[]
|
||||
}
|
||||
|
||||
def 'should trigger a label for the existing groupId:artifactId'() {
|
||||
when:
|
||||
// tag::trigger_group_artifact[]
|
||||
stubFinder.trigger('org.springframework.cloud.contract.verifier.stubs:integrationService', 'return_book_1')
|
||||
// end::trigger_group_artifact[]
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('outputTest')
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should trigger a label for the existing artifactId'() {
|
||||
when:
|
||||
// tag::trigger_artifact[]
|
||||
stubFinder.trigger('integrationService', 'return_book_1')
|
||||
// end::trigger_artifact[]
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('outputTest')
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should throw exception when missing label is passed'() {
|
||||
when:
|
||||
stubFinder.trigger('missing label')
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def 'should throw exception when missing label and artifactid is passed'() {
|
||||
when:
|
||||
stubFinder.trigger('some:service', 'return_book_1')
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def 'should trigger messages by running all triggers'() {
|
||||
when:
|
||||
// tag::trigger_all[]
|
||||
stubFinder.trigger()
|
||||
// end::trigger_all[]
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('outputTest')
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should trigger a label with no output message'() {
|
||||
when:
|
||||
// tag::trigger_no_output[]
|
||||
messaging.send(new BookReturned('foo'), [sample: 'header'], 'delete')
|
||||
// end::trigger_no_output[]
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def 'should not trigger a message that does not match input'() {
|
||||
when:
|
||||
messaging.send(new BookReturned('not_matching'), [wrong: 'header_value'], 'input')
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('outputTest', 100, TimeUnit.MILLISECONDS)
|
||||
and:
|
||||
receivedMessage == null
|
||||
}
|
||||
|
||||
private boolean assertJsons(Object payload) {
|
||||
String objectAsString = payload instanceof String ? payload :
|
||||
JsonOutput.toJson(payload)
|
||||
def json = new JsonSlurper().parseText(objectAsString)
|
||||
return json.bookName == 'foo'
|
||||
}
|
||||
|
||||
Contract dsl =
|
||||
// tag::sample_dsl[]
|
||||
Contract.make {
|
||||
label 'return_book_1'
|
||||
input {
|
||||
triggeredBy('bookReturnedTriggered()')
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('output')
|
||||
body('''{ "bookName" : "foo" }''')
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
// end::sample_dsl[]
|
||||
|
||||
Contract dsl2 =
|
||||
// tag::sample_dsl_2[]
|
||||
Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('input')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('output')
|
||||
body([
|
||||
bookName: 'foo'
|
||||
])
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
// end::sample_dsl_2[]
|
||||
|
||||
Contract dsl3 =
|
||||
// tag::sample_dsl_3[]
|
||||
Contract.make {
|
||||
label 'delete_book'
|
||||
input {
|
||||
messageFrom('delete')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
assertThat('bookWasDeleted()')
|
||||
}
|
||||
}
|
||||
// end::sample_dsl_3[]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.integration
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.messaging.Message
|
||||
import org.springframework.messaging.support.MessageBuilder
|
||||
import spock.lang.Specification
|
||||
|
||||
class StubRunnerIntegrationTransformerSpec extends Specification {
|
||||
|
||||
Message message = MessageBuilder.withPayload("hello").build()
|
||||
|
||||
def noOutputMessageContract = Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookId: $(consumer(regex('[0-9]+')), producer('123'))
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def 'should not transform the message if there is no output message'() {
|
||||
given:
|
||||
StubRunnerIntegrationTransformer transformer = new StubRunnerIntegrationTransformer(noOutputMessageContract)
|
||||
when:
|
||||
def result = transformer.transform(message)
|
||||
then:
|
||||
result.is(message)
|
||||
}
|
||||
|
||||
def dsl = Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookId: $(consumer(regex('[0-9]+')), producer('123'))
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('returnBook')
|
||||
body([
|
||||
responseId: $(producer(regex('[0-9]+')), consumer('123'))
|
||||
])
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def 'should convert dsl into message'() {
|
||||
given:
|
||||
StubRunnerIntegrationTransformer transformer = new StubRunnerIntegrationTransformer(dsl)
|
||||
when:
|
||||
def result = transformer.transform(message)
|
||||
then:
|
||||
result.payload == '{"responseId":"123"}'
|
||||
}
|
||||
|
||||
def dslWithRegexInGString = Contract.make {
|
||||
// Human readable description
|
||||
description 'Should produce valid sensor data'
|
||||
// Label by means of which the output message can be triggered
|
||||
label 'sensor1'
|
||||
// input to the contract
|
||||
input {
|
||||
// the contract will be triggered by a method
|
||||
triggeredBy('createSensorData()')
|
||||
}
|
||||
// output message of the contract
|
||||
outputMessage {
|
||||
// destination to which the output message will be sent
|
||||
sentTo 'sensor-data'
|
||||
headers {
|
||||
header('contentType': 'application/json')
|
||||
}
|
||||
// the body of the output message
|
||||
body("""{"id":"${value(producer(regex('[0-9]+')), consumer('99'))}","temperature":"123.45"}""")
|
||||
}
|
||||
}
|
||||
|
||||
def 'should convert dsl into message with regex in GString'() {
|
||||
given:
|
||||
StubRunnerIntegrationTransformer transformer = new StubRunnerIntegrationTransformer(dslWithRegexInGString)
|
||||
when:
|
||||
def result = transformer.transform(message)
|
||||
then:
|
||||
result.payload == '''{"id":"99","temperature":"123.45"}'''
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
stubrunner.stubs.repositoryRoot: classpath:m2repo/repository/
|
||||
stubrunner.stubs.ids: org.springframework.cloud.contract.verifier.stubs:integrationService:0.0.1-SNAPSHOT
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
|
||||
<!-- REQUIRED FOR TESTING -->
|
||||
<bridge input-channel="output"
|
||||
output-channel="outputTest"/>
|
||||
|
||||
<channel id="outputTest">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
</beans:beans>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>integrationService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>integrationService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<snapshot>
|
||||
<localCopy>true</localCopy>
|
||||
</snapshot>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>integrationService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>integrationService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
132
tests/spring-cloud-contract-stub-runner-stream/README.adoc
Normal file
132
tests/spring-cloud-contract-stub-runner-stream/README.adoc
Normal file
@@ -0,0 +1,132 @@
|
||||
=== Stub Runner Stream
|
||||
|
||||
Spring Cloud Contract Verifier Stub Runner's messaging module gives you an easy way to integrate with Spring Stream.
|
||||
For the provided artifacts it will automatically download the stubs and register the required
|
||||
routes.
|
||||
|
||||
WARNING: In Stub Runner's integration with Stream the `messageFrom` or `sentTo` Strings are resolved
|
||||
first as a `destination` of a channel, and then if there is no such `destination` it's resolved as a
|
||||
channel name.
|
||||
|
||||
==== Adding it to the project
|
||||
|
||||
To use it you have to add the following dependency to your project (example for Gradle):
|
||||
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
testCompile "org.springframework.cloud:stub-runner-stream:${verifierVersion}"
|
||||
----
|
||||
|
||||
==== Examples
|
||||
|
||||
===== Stubs structure
|
||||
|
||||
Let us assume that we have the following Maven repository with a deployed stubs for the
|
||||
`streamService` application.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── io
|
||||
└── codearte
|
||||
└── accurest
|
||||
└── stubs
|
||||
└── streamService
|
||||
├── 0.0.1-SNAPSHOT
|
||||
│ ├── streamService-0.0.1-SNAPSHOT.pom
|
||||
│ ├── streamService-0.0.1-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
|
||||
And the stubs contain the following structure:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── repository
|
||||
├── accurest
|
||||
│ ├── bookDeleted.groovy
|
||||
│ ├── bookReturned1.groovy
|
||||
│ └── bookReturned2.groovy
|
||||
└── mappings
|
||||
----
|
||||
|
||||
Let's consider the following contracts (let' number it with *1*):
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=sample_dsl,indent=0]
|
||||
----
|
||||
|
||||
and number *2*
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=sample_dsl_2,indent=0]
|
||||
----
|
||||
|
||||
and the following Spring configuration:
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
include::src/test/resources/application.yml[]
|
||||
----
|
||||
|
||||
|
||||
===== Scenario 1 (no input message)
|
||||
|
||||
So as to trigger a message via the `return_book_1` label we'll use the `StubTrigger` interface as follows
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
|
||||
Next we'll want to listen to the output of the message sent to a channel whose `destination` is `returnBook`
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger_receive,indent=0]
|
||||
----
|
||||
|
||||
And the received message would pass the following assertions
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger_message,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 2 (output triggered by input)
|
||||
|
||||
Since the route is set for you it's enough to just send a message to the `bookStorage` `destination`.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_send,indent=0]
|
||||
----
|
||||
|
||||
Next we'll want to listen to the output of the message sent to `returnBook`
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_receive,indent=0]
|
||||
----
|
||||
|
||||
And the received message would pass the following assertions
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_receive_message,indent=0]
|
||||
----
|
||||
|
||||
===== Scenario 3 (input with no output)
|
||||
|
||||
Since the route is set for you it's enough to just send a message to the `{output_name}` destination.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_no_output,indent=0]
|
||||
----
|
||||
85
tests/spring-cloud-contract-stub-runner-stream/pom.xml
Normal file
85
tests/spring-cloud-contract-stub-runner-stream/pom.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner-build</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-stub-runner-stream</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Stub Runner Stream</name>
|
||||
<description>Spring Cloud Contract Stub Runner Stream</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner-jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-verifier</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-java-dsl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.solidsoft.spock</groupId>
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.stubrunner.messaging.stream
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator
|
||||
import groovy.transform.CompileStatic
|
||||
import groovy.transform.EqualsAndHashCode
|
||||
|
||||
@CompileStatic
|
||||
@EqualsAndHashCode
|
||||
class BookReturned implements Serializable {
|
||||
final String bookName
|
||||
|
||||
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
|
||||
BookReturned(String bookName) {
|
||||
this.bookName = bookName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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.stubrunner.messaging.stream
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier
|
||||
import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding
|
||||
import org.springframework.cloud.stream.messaging.Sink
|
||||
import org.springframework.cloud.stream.messaging.Source
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.messaging.Message
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@IntegrationTest("debug=true")
|
||||
@AutoConfigureStubRunner
|
||||
@AutoConfigureMessageVerifier
|
||||
class StreamStubRunnerSpec extends Specification {
|
||||
|
||||
@Autowired StubFinder stubFinder
|
||||
@Autowired MessageVerifier<Message<?>> messaging
|
||||
|
||||
def setup() {
|
||||
// ensure that message were taken from the queue
|
||||
messaging.receive('returnBook', 100, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
def 'should download the stub and register a route for it'() {
|
||||
when:
|
||||
// tag::client_send[]
|
||||
messaging.send(new BookReturned('foo'), [sample: 'header'], 'bookStorage')
|
||||
// end::client_send[]
|
||||
then:
|
||||
// tag::client_receive[]
|
||||
Message<?> receivedMessage = messaging.receive('returnBook')
|
||||
// end::client_receive[]
|
||||
and:
|
||||
// tag::client_receive_message[]
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
// end::client_receive_message[]
|
||||
}
|
||||
|
||||
def 'should trigger a message by label'() {
|
||||
when:
|
||||
// tag::client_trigger[]
|
||||
stubFinder.trigger('return_book_1')
|
||||
// end::client_trigger[]
|
||||
then:
|
||||
// tag::client_trigger_receive[]
|
||||
Message<?> receivedMessage = messaging.receive('returnBook')
|
||||
// end::client_trigger_receive[]
|
||||
and:
|
||||
// tag::client_trigger_message[]
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
// end::client_trigger_message[]
|
||||
}
|
||||
|
||||
def 'should trigger a label for the existing groupId:artifactId'() {
|
||||
when:
|
||||
// tag::trigger_group_artifact[]
|
||||
stubFinder.trigger('org.springframework.cloud.contract.verifier.stubs:streamService', 'return_book_1')
|
||||
// end::trigger_group_artifact[]
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('returnBook')
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should trigger a label for the existing artifactId'() {
|
||||
when:
|
||||
// tag::trigger_artifact[]
|
||||
stubFinder.trigger('streamService', 'return_book_1')
|
||||
// end::trigger_artifact[]
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('returnBook')
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should throw exception when missing label is passed'() {
|
||||
when:
|
||||
stubFinder.trigger('missing label')
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def 'should throw exception when missing label and artifactid is passed'() {
|
||||
when:
|
||||
stubFinder.trigger('some:service', 'return_book_1')
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def 'should trigger messages by running all triggers'() {
|
||||
when:
|
||||
// tag::trigger_all[]
|
||||
stubFinder.trigger()
|
||||
// end::trigger_all[]
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('returnBook')
|
||||
and:
|
||||
receivedMessage != null
|
||||
assertJsons(receivedMessage.payload)
|
||||
receivedMessage.headers.get('BOOK-NAME') == 'foo'
|
||||
}
|
||||
|
||||
def 'should trigger a label with no output message'() {
|
||||
when:
|
||||
// tag::trigger_no_output[]
|
||||
messaging.send(new BookReturned('foo'), [sample: 'header'], 'delete')
|
||||
// end::trigger_no_output[]
|
||||
then:
|
||||
noExceptionThrown()
|
||||
}
|
||||
|
||||
def 'should not trigger a message that does not match input'() {
|
||||
when:
|
||||
messaging.send(new BookReturned('not_matching'), [wrong: 'header_value'], 'bookStorage')
|
||||
then:
|
||||
Message<?> receivedMessage = messaging.receive('returnBook', 100, TimeUnit.MILLISECONDS)
|
||||
and:
|
||||
receivedMessage == null
|
||||
}
|
||||
|
||||
private boolean assertJsons(Object payload) {
|
||||
String objectAsString = payload instanceof String ? payload :
|
||||
JsonOutput.toJson(payload)
|
||||
def json = new JsonSlurper().parseText(objectAsString)
|
||||
return json.bookName == 'foo'
|
||||
}
|
||||
|
||||
Contract dsl =
|
||||
// tag::sample_dsl[]
|
||||
Contract.make {
|
||||
label 'return_book_1'
|
||||
input { triggeredBy('bookReturnedTriggered()') }
|
||||
outputMessage {
|
||||
sentTo('returnBook')
|
||||
body('''{ "bookName" : "foo" }''')
|
||||
headers { header('BOOK-NAME', 'foo') }
|
||||
}
|
||||
}
|
||||
// end::sample_dsl[]
|
||||
|
||||
Contract dsl2 =
|
||||
// tag::sample_dsl_2[]
|
||||
Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders { header('sample', 'header') }
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('returnBook')
|
||||
body([
|
||||
bookName: 'foo'
|
||||
])
|
||||
headers { header('BOOK-NAME', 'foo') }
|
||||
}
|
||||
}
|
||||
// end::sample_dsl_2[]
|
||||
|
||||
Contract dsl3 =
|
||||
// tag::sample_dsl_3[]
|
||||
Contract.make {
|
||||
label 'delete_book'
|
||||
input {
|
||||
messageFrom('delete')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders { header('sample', 'header') }
|
||||
assertThat('bookWasDeleted()')
|
||||
}
|
||||
}
|
||||
// end::sample_dsl_3[]
|
||||
|
||||
|
||||
@EnableBinding([Sink, Source])
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class Config {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.stream
|
||||
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.messaging.Message
|
||||
import org.springframework.messaging.support.MessageBuilder
|
||||
import spock.lang.Specification
|
||||
|
||||
class StubRunnerStreamTransformerSpec extends Specification {
|
||||
|
||||
Message message = MessageBuilder.withPayload("hello").build()
|
||||
|
||||
def noOutputMessageContract = Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookId: $(consumer(regex('[0-9]+')), producer('123'))
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def 'should not transform the message if there is no output message'() {
|
||||
given:
|
||||
StubRunnerStreamTransformer streamTransformer = new StubRunnerStreamTransformer(noOutputMessageContract)
|
||||
when:
|
||||
def result = streamTransformer.transform(message)
|
||||
then:
|
||||
result.is(message)
|
||||
}
|
||||
|
||||
def dsl = Contract.make {
|
||||
label 'return_book_2'
|
||||
input {
|
||||
messageFrom('bookStorage')
|
||||
messageBody([
|
||||
bookId: $(consumer(regex('[0-9]+')), producer('123'))
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('returnBook')
|
||||
body([
|
||||
responseId: $(producer(regex('[0-9]+')), consumer('123'))
|
||||
])
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def 'should convert dsl into message'() {
|
||||
given:
|
||||
StubRunnerStreamTransformer streamTransformer = new StubRunnerStreamTransformer(dsl)
|
||||
when:
|
||||
def result = streamTransformer.transform(message)
|
||||
then:
|
||||
result.payload == '{"responseId":"123"}'
|
||||
}
|
||||
|
||||
def dslWithRegexInGString = Contract.make {
|
||||
// Human readable description
|
||||
description 'Should produce valid sensor data'
|
||||
// Label by means of which the output message can be triggered
|
||||
label 'sensor1'
|
||||
// input to the contract
|
||||
input {
|
||||
// the contract will be triggered by a method
|
||||
triggeredBy('createSensorData()')
|
||||
}
|
||||
// output message of the contract
|
||||
outputMessage {
|
||||
// destination to which the output message will be sent
|
||||
sentTo 'sensor-data'
|
||||
headers {
|
||||
header('contentType': 'application/json')
|
||||
}
|
||||
// the body of the output message
|
||||
body("""{"id":"${value(producer(regex('[0-9]+')), consumer('99'))}","temperature":"123.45"}""")
|
||||
}
|
||||
}
|
||||
|
||||
def 'should convert dsl into message with regex in GString'() {
|
||||
given:
|
||||
StubRunnerStreamTransformer streamTransformer = new StubRunnerStreamTransformer(dslWithRegexInGString)
|
||||
when:
|
||||
def result = streamTransformer.transform(message)
|
||||
then:
|
||||
result.payload == '''{"id":"99","temperature":"123.45"}'''
|
||||
}
|
||||
|
||||
def 'should parse dsl without DslProperty'() {
|
||||
given:
|
||||
Contract contract = Contract.make {
|
||||
// Human readable description
|
||||
description 'Sends an order message'
|
||||
// Label by means of which the output message can be triggered
|
||||
label 'send_order'
|
||||
// input to the contract
|
||||
input {
|
||||
// the contract will be triggered by a method
|
||||
triggeredBy('orderTrigger()')
|
||||
}
|
||||
// output message of the contract
|
||||
outputMessage {
|
||||
// destination to which the output message will be sent
|
||||
sentTo('orders')
|
||||
// any headers for the output message
|
||||
headers {
|
||||
header('contentType': 'application/json')
|
||||
}
|
||||
// the body of the output message
|
||||
body(
|
||||
orderId: value(
|
||||
consumer('40058c70-891c-4176-a033-f70bad0c5f77'),
|
||||
producer(regex('([0-9|a-f]*-*)*'))),
|
||||
description: "This is the order description"
|
||||
)
|
||||
}
|
||||
}
|
||||
StubRunnerStreamTransformer streamTransformer = new StubRunnerStreamTransformer(contract)
|
||||
when:
|
||||
def result = streamTransformer.transform(message)
|
||||
then:
|
||||
result.payload == '''{"orderId":"40058c70-891c-4176-a033-f70bad0c5f77","description":"This is the order description"}'''
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
stubrunner.stubs.repositoryRoot: classpath:m2repo/repository/
|
||||
stubrunner.stubs.ids: org.springframework.cloud.contract.verifier.stubs:streamService:0.0.1-SNAPSHOT:stubs
|
||||
|
||||
spring:
|
||||
cloud:
|
||||
stream:
|
||||
bindings:
|
||||
output:
|
||||
destination: returnBook
|
||||
input:
|
||||
destination: bookStorage
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>streamService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<snapshot>
|
||||
<localCopy>true</localCopy>
|
||||
</snapshot>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>streamService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>streamService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>streamService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Reference in New Issue
Block a user