diff --git a/pom.xml b/pom.xml
index 5913b04342..be51896375 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,7 @@
spring-cloud-contract-stub-runner
spring-cloud-contract-starters
spring-cloud-contract-tools
+ tests
samples
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java
index d7a5e821f3..538fec5a70 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java
@@ -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
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationConfiguration.java
index 78f74d7dc0..e16ec51b05 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationConfiguration.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationConfiguration.java
@@ -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
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamConfiguration.java
index 9c715c4bc6..e2c9f89431 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamConfiguration.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamConfiguration.java
@@ -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> contracts = batchStubRunner
diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy
index 2460562296..292411d0b8 100644
--- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy
+++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy
@@ -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 {
diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy
index 99667475c3..de4fb64f54 100644
--- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy
+++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/cloud/StubRunnerSpringCloudAutoConfigurationSpec.groovy
@@ -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
diff --git a/tests/pom.xml b/tests/pom.xml
new file mode 100644
index 0000000000..df55cadd69
--- /dev/null
+++ b/tests/pom.xml
@@ -0,0 +1,37 @@
+
+
+ 4.0.0
+
+
+ org.springframework.cloud
+ spring-cloud-contract-parent
+ 1.0.0.BUILD-SNAPSHOT
+ ..
+
+
+ spring-cloud-contract-tests
+ pom
+
+ Spring Cloud Contract Tests
+ Spring Cloud Contract Tests
+
+
+ spring-cloud-contract-stub-runner-camel
+ spring-cloud-contract-stub-runner-integration
+ spring-cloud-contract-stub-runner-stream
+
+
+
+
+
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-camel/README.adoc b/tests/spring-cloud-contract-stub-runner-camel/README.adoc
new file mode 100644
index 0000000000..0a3ef49f3a
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/README.adoc
@@ -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]
+----
diff --git a/tests/spring-cloud-contract-stub-runner-camel/pom.xml b/tests/spring-cloud-contract-stub-runner-camel/pom.xml
new file mode 100644
index 0000000000..82ded95784
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/pom.xml
@@ -0,0 +1,94 @@
+
+
+ 4.0.0
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner-build
+ 1.0.0.BUILD-SNAPSHOT
+ ..
+
+ spring-cloud-contract-stub-runner-camel
+ jar
+ Spring Cloud Contract Stub Runner Camel
+ Spring Cloud Contract Stub Runner Camel
+
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner-jetty
+ test
+
+
+ org.apache.camel
+ camel-spring-boot-starter
+
+
+ org.apache.camel
+ camel-jackson
+
+
+ junit
+ junit
+ test
+
+
+ org.codehaus.groovy
+ groovy
+
+
+ org.spockframework
+ spock-core
+ test
+
+
+ org.spockframework
+ spock-spring
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.apache.activemq
+ activemq-camel
+ test
+
+
+ org.apache.activemq
+ activemq-pool
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ test
+
+
+ info.solidsoft.spock
+ spock-global-unroll
+ test
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+
+ testCompile
+
+
+
+
+
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/BookReturned.groovy
new file mode 100644
index 0000000000..72a689a659
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/BookReturned.groovy
@@ -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
+ }
+}
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy
new file mode 100644
index 0000000000..fa6a8a5922
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy
@@ -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[]
+}
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy
new file mode 100644
index 0000000000..279782c65e
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy
@@ -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"}'''
+ }
+}
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml
new file mode 100644
index 0000000000..4eef5ea578
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml
@@ -0,0 +1,2 @@
+stubrunner.stubs.repositoryRoot: classpath:m2repo/repository/
+stubrunner.stubs.ids: org.springframework.cloud.contract.verifier.stubs:camelService
\ No newline at end of file
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT-stubs.jar
new file mode 100644
index 0000000000..b27b155a3e
Binary files /dev/null and b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT-stubs.jar differ
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT.pom
new file mode 100644
index 0000000000..0b56465de4
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT.pom
@@ -0,0 +1,25 @@
+
+
+
+
+ 4.0.0
+ org.springframework.cloud.contract.verifier.stubs
+ camelService
+ 0.0.1-SNAPSHOT
+ pom
+
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/maven-metadata-local.xml
new file mode 100644
index 0000000000..8ac2715bc8
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/0.0.1-SNAPSHOT/maven-metadata-local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ camelService
+ 0.0.1-SNAPSHOT
+
+
+ true
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/maven-metadata-local.xml
new file mode 100644
index 0000000000..237fd747a9
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/maven-metadata-local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ camelService
+ 0.0.1-SNAPSHOT
+
+
+ 0.0.1-SNAPSHOT
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/maven-metadata.xml
new file mode 100644
index 0000000000..237fd747a9
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/camelService/maven-metadata.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ camelService
+ 0.0.1-SNAPSHOT
+
+
+ 0.0.1-SNAPSHOT
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-integration/.jdk8 b/tests/spring-cloud-contract-stub-runner-integration/.jdk8
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/spring-cloud-contract-stub-runner-integration/README.adoc b/tests/spring-cloud-contract-stub-runner-integration/README.adoc
new file mode 100644
index 0000000000..ce3b3bff49
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/README.adoc
@@ -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]
+----
diff --git a/tests/spring-cloud-contract-stub-runner-integration/pom.xml b/tests/spring-cloud-contract-stub-runner-integration/pom.xml
new file mode 100644
index 0000000000..e0c5a76850
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner-build
+ 1.0.0.BUILD-SNAPSHOT
+ ..
+
+ spring-cloud-contract-stub-runner-integration
+ jar
+ Spring Cloud Contract Stub Runner Integration
+ Spring Cloud Contract Stub Runner Integration
+
+ 1.8
+
+
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner
+
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner-jetty
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-contract-verifier
+
+
+ org.springframework.integration
+ spring-integration-java-dsl
+
+
+ junit
+ junit
+ test
+
+
+ org.spockframework
+ spock-core
+ test
+
+
+ org.spockframework
+ spock-spring
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ test
+
+
+ info.solidsoft.spock
+ spock-global-unroll
+ test
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+
+ testCompile
+
+
+
+
+
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy
new file mode 100644
index 0000000000..bbb47bbb60
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/BookReturned.groovy
@@ -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
+ }
+}
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy
new file mode 100644
index 0000000000..bfa4a2c3be
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/IntegrationStubRunnerSpec.groovy
@@ -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[]
+
+}
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformerSpec.groovy b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformerSpec.groovy
new file mode 100644
index 0000000000..31b4d19ab4
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformerSpec.groovy
@@ -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"}'''
+ }
+}
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml
new file mode 100644
index 0000000000..32d7427875
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/application.yml
@@ -0,0 +1,2 @@
+stubrunner.stubs.repositoryRoot: classpath:m2repo/repository/
+stubrunner.stubs.ids: org.springframework.cloud.contract.verifier.stubs:integrationService:0.0.1-SNAPSHOT
\ No newline at end of file
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml
new file mode 100644
index 0000000000..1fdb1bb847
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/integration-context.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT-stubs.jar
new file mode 100644
index 0000000000..9cb1d97128
Binary files /dev/null and b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT-stubs.jar differ
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom
new file mode 100644
index 0000000000..0581ac022d
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/integrationService-0.0.1-SNAPSHOT.pom
@@ -0,0 +1,25 @@
+
+
+
+
+ 4.0.0
+ org.springframework.cloud.contract.verifier.stubs
+ integrationService
+ 0.0.1-SNAPSHOT
+ pom
+
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml
new file mode 100644
index 0000000000..e6c62c5897
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/0.0.1-SNAPSHOT/maven-metadata-local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ integrationService
+ 0.0.1-SNAPSHOT
+
+
+ true
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml
new file mode 100644
index 0000000000..f619bafb54
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata-local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ integrationService
+ 0.0.1-SNAPSHOT
+
+
+ 0.0.1-SNAPSHOT
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml
new file mode 100644
index 0000000000..f619bafb54
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-integration/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/integrationService/maven-metadata.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ integrationService
+ 0.0.1-SNAPSHOT
+
+
+ 0.0.1-SNAPSHOT
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-stream/README.adoc b/tests/spring-cloud-contract-stub-runner-stream/README.adoc
new file mode 100644
index 0000000000..2d6a41522c
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/README.adoc
@@ -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]
+----
diff --git a/tests/spring-cloud-contract-stub-runner-stream/pom.xml b/tests/spring-cloud-contract-stub-runner-stream/pom.xml
new file mode 100644
index 0000000000..c6b411380b
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/pom.xml
@@ -0,0 +1,85 @@
+
+
+ 4.0.0
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner-build
+ 1.0.0.BUILD-SNAPSHOT
+ ..
+
+ spring-cloud-contract-stub-runner-stream
+ jar
+ Spring Cloud Contract Stub Runner Stream
+ Spring Cloud Contract Stub Runner Stream
+
+
+ org.springframework.cloud
+ spring-cloud-starter-stream-rabbit
+
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-contract-stub-runner-jetty
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-contract-verifier
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-stream-test-support
+ test
+
+
+ org.springframework.integration
+ spring-integration-java-dsl
+
+
+ junit
+ junit
+ test
+
+
+ org.spockframework
+ spock-core
+ test
+
+
+ org.spockframework
+ spock-spring
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ info.solidsoft.spock
+ spock-global-unroll
+ test
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+
+ testCompile
+
+
+
+
+
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy
new file mode 100644
index 0000000000..49dea202eb
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/BookReturned.groovy
@@ -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
+ }
+}
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy
new file mode 100644
index 0000000000..28564fa7be
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy
@@ -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> 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 {}
+
+}
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformerSpec.groovy b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformerSpec.groovy
new file mode 100644
index 0000000000..a948936dad
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformerSpec.groovy
@@ -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"}'''
+ }
+
+}
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml
new file mode 100644
index 0000000000..baaaa1d38e
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/application.yml
@@ -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
\ No newline at end of file
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml
new file mode 100644
index 0000000000..f14e885df3
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/maven-metadata-local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ streamService
+ 0.0.1-SNAPSHOT
+
+
+ true
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT-stubs.jar b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT-stubs.jar
new file mode 100644
index 0000000000..b3daab26c4
Binary files /dev/null and b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT-stubs.jar differ
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT.pom b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT.pom
new file mode 100644
index 0000000000..8613d57be0
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/0.0.1-SNAPSHOT/streamService-0.0.1-SNAPSHOT.pom
@@ -0,0 +1,25 @@
+
+
+
+
+ 4.0.0
+ org.springframework.cloud.contract.verifier.stubs
+ streamService
+ 0.0.1-SNAPSHOT
+ pom
+
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml
new file mode 100644
index 0000000000..001cf26899
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata-local.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ streamService
+ 0.0.1-SNAPSHOT
+
+
+ 0.0.1-SNAPSHOT
+
+ 20160409062112
+
+
diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml
new file mode 100644
index 0000000000..001cf26899
--- /dev/null
+++ b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/m2repo/repository/org/springframework/cloud/contract/verifier/stubs/streamService/maven-metadata.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ org.springframework.cloud.contract.verifier.stubs
+ streamService
+ 0.0.1-SNAPSHOT
+
+
+ 0.0.1-SNAPSHOT
+
+ 20160409062112
+
+