committed by
Marcin Grzejszczak
parent
4c3d0d2c3c
commit
5abf2d7c17
@@ -177,9 +177,4 @@ version of the release train (and vice versa).
|
||||
Done via https://github.com/spring-cloud/spring-cloud-contract/issues/267[issue 267]
|
||||
|
||||
[[cloud-verifier-1.2-2.0]]
|
||||
=== 1.2.x -> 2.0.x
|
||||
|
||||
==== No Camel support
|
||||
|
||||
We will add back Apache Camel support only after this https://issues.apache.org/jira/browse/CAMEL-11430[issue]
|
||||
gets fixed
|
||||
=== 1.2.x -> 2.0.x
|
||||
@@ -6,6 +6,7 @@ frameworks:
|
||||
|
||||
* Spring Integration
|
||||
* Spring Cloud Stream
|
||||
* Apache Camel
|
||||
* Spring AMQP
|
||||
|
||||
It also provides entry points to integrate with any other solution on the market.
|
||||
@@ -65,6 +66,8 @@ include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/o
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_all,indent=0]
|
||||
----
|
||||
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-camel/README.adoc[]
|
||||
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-integration/README.adoc[]
|
||||
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/README.adoc[]
|
||||
|
||||
48
pom.xml
48
pom.xml
@@ -23,6 +23,9 @@
|
||||
<inceptionYear>2016</inceptionYear>
|
||||
|
||||
<properties>
|
||||
<activemq.version>5.12.1</activemq.version>
|
||||
<camel.version>2.22.1</camel.version>
|
||||
<checkstyle.version>2.17</checkstyle.version>
|
||||
<pact.version>3.5.13</pact.version>
|
||||
<jsch-agent.version>0.0.9</jsch-agent.version>
|
||||
<spring-cloud-build.version>2.1.0.BUILD-SNAPSHOT</spring-cloud-build.version>
|
||||
@@ -71,6 +74,51 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot-starter</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-core</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-kafka</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-jackson</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-jms</artifactId>
|
||||
<version>${camel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-camel</artifactId>
|
||||
<version>${activemq.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-pool</artifactId>
|
||||
<version>${activemq.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.jopt-simple</groupId>
|
||||
<artifactId>jopt-simple</artifactId>
|
||||
|
||||
@@ -60,6 +60,21 @@
|
||||
<artifactId>jopt-simple</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-jackson</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 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;
|
||||
import org.springframework.context.annotation.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Camel configuration that iterates over the downloaded Groovy DSLs and registers a route
|
||||
* for each DSL.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(RoutesBuilder.class)
|
||||
@ConditionalOnProperty(name = "stubrunner.camel.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class StubRunnerCamelConfiguration {
|
||||
|
||||
@Bean
|
||||
public RoutesBuilder myRouter(final BatchStubRunner batchStubRunner) {
|
||||
return new SpringRouteBuilder() {
|
||||
@Override
|
||||
public void configure() throws Exception {
|
||||
Map<StubConfiguration, Collection<Contract>> contracts = batchStubRunner
|
||||
.getContracts();
|
||||
for (Collection<Contract> list : contracts.values()) {
|
||||
for (Contract it : list) {
|
||||
if (it.getInput() != null
|
||||
&& it.getInput().getMessageFrom() != null
|
||||
&& it.getOutputMessage() != null
|
||||
&& it.getOutputMessage().getSentTo() != null) {
|
||||
from(it.getInput().getMessageFrom().getClientValue())
|
||||
.filter(new StubRunnerCamelPredicate(it))
|
||||
.process(new StubRunnerCamelProcessor(it))
|
||||
.to(it.getOutputMessage().getSentTo()
|
||||
.getClientValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.camel.Exchange;
|
||||
import org.apache.camel.Predicate;
|
||||
import org.springframework.cloud.contract.spec.Contract;
|
||||
import org.springframework.cloud.contract.spec.internal.BodyMatcher;
|
||||
import org.springframework.cloud.contract.spec.internal.BodyMatchers;
|
||||
import org.springframework.cloud.contract.spec.internal.Header;
|
||||
import org.springframework.cloud.contract.verifier.util.MapConverter;
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper;
|
||||
import org.springframework.cloud.contract.verifier.util.JsonPaths;
|
||||
import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter;
|
||||
import org.springframework.cloud.contract.verifier.util.MethodBufferingJsonVerifiable;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import com.toomuchcoding.jsonassert.JsonAssertion;
|
||||
|
||||
/**
|
||||
* Passes through a message that matches the one defined in the DSL
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubRunnerCamelPredicate implements Predicate {
|
||||
|
||||
private final Contract groovyDsl;
|
||||
private final ContractVerifierObjectMapper objectMapper = new ContractVerifierObjectMapper();
|
||||
|
||||
public StubRunnerCamelPredicate(Contract groovyDsl) {
|
||||
this.groovyDsl = groovyDsl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Exchange exchange) {
|
||||
if (!headersMatch(exchange.getIn().getHeaders())) {
|
||||
return false;
|
||||
}
|
||||
Object inputMessage = exchange.getIn().getBody();
|
||||
BodyMatchers matchers = this.groovyDsl.getInput().getBodyMatchers();
|
||||
Object dslBody = MapConverter.getStubSideValues(this.groovyDsl.getInput().getMessageBody());
|
||||
|
||||
DocumentContext parsedJson = deserialize(inputMessage);
|
||||
return matchMessage(matchers, dslBody, parsedJson);
|
||||
}
|
||||
|
||||
private boolean matchMessage(BodyMatchers matchers, Object dslBody, DocumentContext parsedJson) {
|
||||
boolean matches = true;
|
||||
JsonPaths jsonPaths = getJsonPaths(matchers, dslBody);
|
||||
for (MethodBufferingJsonVerifiable path : jsonPaths) {
|
||||
matches &= matchesJsonPath(parsedJson, path.jsonPath());
|
||||
}
|
||||
if (matchers != null && matchers.hasMatchers()) {
|
||||
for (BodyMatcher matcher : matchers.jsonPathMatchers()) {
|
||||
String jsonPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher, dslBody);
|
||||
matches &= matchesJsonPath(parsedJson, jsonPath);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private JsonPaths getJsonPaths(BodyMatchers matchers, Object dslBody) {
|
||||
Object matchingInputMessage = JsonToJsonPathsConverter
|
||||
.removeMatchingJsonPaths(dslBody, matchers);
|
||||
return JsonToJsonPathsConverter
|
||||
.transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(
|
||||
matchingInputMessage);
|
||||
}
|
||||
|
||||
private DocumentContext deserialize(Object inputMessage) {
|
||||
DocumentContext parsedJson;
|
||||
try {
|
||||
parsedJson = JsonPath
|
||||
.parse(this.objectMapper.writeValueAsString(inputMessage));
|
||||
}
|
||||
catch (JsonProcessingException e) {
|
||||
throw new IllegalStateException("Cannot serialize to JSON", e);
|
||||
}
|
||||
return parsedJson;
|
||||
}
|
||||
|
||||
private boolean matchesJsonPath(DocumentContext parsedJson, String jsonPath) {
|
||||
try {
|
||||
JsonAssertion.assertThat(parsedJson).matchesJsonPath(jsonPath);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean headersMatch(Map<String, Object> headers) {
|
||||
boolean matches = true;
|
||||
for (Header it : this.groovyDsl.getInput().getMessageHeaders().getEntries()) {
|
||||
String name = it.getName();
|
||||
Object value = it.getClientValue();
|
||||
Object valueInHeader = headers.get(name);
|
||||
matches &= matchValue(value, valueInHeader);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private boolean matchValue(Object value, Object valueInHeader) {
|
||||
return value instanceof Pattern ?
|
||||
((Pattern) value).matcher(valueInHeader.toString()).matches() :
|
||||
valueInHeader!=null && valueInHeader.equals(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 org.springframework.cloud.contract.verifier.util.BodyExtractor;
|
||||
import org.apache.camel.Exchange;
|
||||
import org.apache.camel.Message;
|
||||
import org.apache.camel.Processor;
|
||||
import org.springframework.cloud.contract.spec.Contract;
|
||||
import org.springframework.cloud.contract.spec.internal.Header;
|
||||
|
||||
/**
|
||||
* Sends forward a message defined in the DSL. Also removes headers from the input message
|
||||
* and provides the headers from the DSL.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubRunnerCamelProcessor implements Processor {
|
||||
|
||||
private final Contract groovyDsl;
|
||||
|
||||
StubRunnerCamelProcessor(Contract groovyDsl) {
|
||||
this.groovyDsl = groovyDsl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Exchange exchange) throws Exception {
|
||||
Message input = exchange.getIn();
|
||||
if (this.groovyDsl.getInput().getMessageHeaders() != null) {
|
||||
for (Header entry : this.groovyDsl.getInput().getMessageHeaders().getEntries()) {
|
||||
input.removeHeader(entry.getName());
|
||||
}
|
||||
}
|
||||
if (this.groovyDsl.getOutputMessage() == null) {
|
||||
return;
|
||||
}
|
||||
input.setBody(BodyExtractor
|
||||
.extractStubValueFrom(this.groovyDsl.getOutputMessage().getBody()));
|
||||
if (this.groovyDsl.getOutputMessage().getHeaders() != null) {
|
||||
for (Header entry : this.groovyDsl.getOutputMessage().getHeaders().getEntries()) {
|
||||
input.setHeader(entry.getName(), entry.getClientValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@ org.springframework.cloud.contract.stubrunner.messaging.stream.StubRunnerStreamC
|
||||
org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper.StubRunnerSpringCloudZookeeperAutoConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.spring.cloud.eureka.StubRunnerSpringCloudEurekaAutoConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.spring.cloud.consul.StubRunnerSpringCloudConsulAutoConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.messaging.StubRunnerStreamsIntegrationAutoConfiguration
|
||||
org.springframework.cloud.contract.stubrunner.messaging.StubRunnerStreamsIntegrationAutoConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.messaging.camel.StubRunnerCamelConfiguration
|
||||
|
||||
# Test Execution Listeners
|
||||
org.springframework.test.context.TestExecutionListener=\
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.camel
|
||||
|
||||
import org.apache.camel.Exchange
|
||||
import org.apache.camel.Message
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubRunnerCamelPredicateSpec extends Specification {
|
||||
Exchange exchange = Stub(Exchange)
|
||||
Message message = Stub(Message)
|
||||
|
||||
def "should return false if headers don't match"() {
|
||||
given:
|
||||
Contract dsl = Contract.make {
|
||||
input {
|
||||
messageFrom "foo"
|
||||
messageBody(foo: "bar")
|
||||
messageHeaders {
|
||||
header("foo", $(c(regex("[0-9]{3}")), p(123)))
|
||||
}
|
||||
}
|
||||
}
|
||||
and:
|
||||
StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl)
|
||||
exchange.in >> message
|
||||
message.headers >> [
|
||||
foo: "non matching stuff"
|
||||
]
|
||||
expect:
|
||||
!predicate.matches(exchange)
|
||||
}
|
||||
|
||||
def "should return false if headers match and body doesn't"() {
|
||||
given:
|
||||
Contract dsl = Contract.make {
|
||||
input {
|
||||
messageFrom "foo"
|
||||
messageHeaders {
|
||||
header("foo", 123)
|
||||
}
|
||||
messageBody(foo: $(c(regex("[0-9]{3}")), p(123)))
|
||||
}
|
||||
}
|
||||
and:
|
||||
StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl)
|
||||
exchange.in >> message
|
||||
message.headers >> [
|
||||
foo: 123
|
||||
]
|
||||
message.body >> [
|
||||
foo: "non matching stuff"
|
||||
]
|
||||
expect:
|
||||
!predicate.matches(exchange)
|
||||
}
|
||||
|
||||
def "should return false if headers match and body doesn't when it's using matchers"() {
|
||||
given:
|
||||
Contract dsl = Contract.make {
|
||||
input {
|
||||
messageFrom "foo"
|
||||
messageHeaders {
|
||||
header("foo", 123)
|
||||
}
|
||||
messageBody(foo: "non matching stuff")
|
||||
stubMatchers {
|
||||
jsonPath('$.foo', byRegex("[0-9]{3}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
and:
|
||||
StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl)
|
||||
exchange.in >> message
|
||||
message.headers >> [
|
||||
foo: 123
|
||||
]
|
||||
message.body >> [
|
||||
foo: "non matching stuff"
|
||||
]
|
||||
expect:
|
||||
!predicate.matches(exchange)
|
||||
}
|
||||
def "should return true if headers and body match"() {
|
||||
given:
|
||||
Contract dsl = Contract.make {
|
||||
input {
|
||||
messageFrom "foo"
|
||||
messageHeaders {
|
||||
header("foo", 123)
|
||||
}
|
||||
messageBody(foo: $(c(regex("[0-9]{3}")), p(123)))
|
||||
|
||||
}
|
||||
}
|
||||
and:
|
||||
StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl)
|
||||
exchange.in >> message
|
||||
message.headers >> [
|
||||
foo: 123
|
||||
]
|
||||
message.body >> [
|
||||
foo: 123
|
||||
]
|
||||
expect:
|
||||
predicate.matches(exchange)
|
||||
|
||||
}
|
||||
def "should return true if headers and body using matchers match"() {
|
||||
given:
|
||||
Contract dsl = Contract.make {
|
||||
input {
|
||||
messageFrom "foo"
|
||||
messageHeaders {
|
||||
header("foo", 123)
|
||||
}
|
||||
messageBody(foo: 123)
|
||||
stubMatchers {
|
||||
jsonPath('$.foo', byRegex("[0-9]{3}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
and:
|
||||
StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl)
|
||||
exchange.in >> message
|
||||
message.headers >> [
|
||||
foo: 123
|
||||
]
|
||||
message.body >> [
|
||||
foo: 123
|
||||
]
|
||||
expect:
|
||||
predicate.matches(exchange)
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ public class StubRunnerBootConsulExample {
|
||||
-Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.cloud.contract.verifier.stubs:bootService
|
||||
-Dstubrunner.idsToServiceIds.fraudDetectionServer=someNameThatShouldMapFraudDetectionServer
|
||||
-Dstubrunner.cloud.consul.enabled=true
|
||||
-Dstubrunner.camel.enabled=false
|
||||
-Dspring.cloud.zookeeper.enabled=false
|
||||
-Deureka.client.enabled=false
|
||||
-Dspring.cloud.zookeeper.discovery.enabled=false
|
||||
|
||||
@@ -56,6 +56,7 @@ public class StubRunnerBootEurekaExample {
|
||||
|
||||
-Dstubrunner.cloud.eureka.enabled=true
|
||||
-Dstubrunner.repositoryRoot=classpath:m2repo/repository/
|
||||
-Dstubrunner.camel.enabled=false
|
||||
-Dspring.cloud.zookeeper.enabled=false
|
||||
-Dspring.cloud.zookeeper.discovery.enabled=false
|
||||
-Ddebug=true
|
||||
|
||||
@@ -42,6 +42,7 @@ public class StubRunnerBootZookeeperExample {
|
||||
-Dstubrunner.idsToServiceIds.fraudDetectionServer=someNameThatShouldMapFraudDetectionServer
|
||||
-Dstubrunner.cloud.stubbed.discovery.enabled=false
|
||||
-Dstubrunner.cloud.zookeepr.enabled=true
|
||||
-Dstubrunner.camel.enabled=false
|
||||
-Dstubrunner.repositoryRoot=classpath:m2repo/repository/
|
||||
-Deureka.client.enabled=false
|
||||
-Ddebug=true
|
||||
|
||||
@@ -30,6 +30,26 @@
|
||||
<artifactId>spring-messaging</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-kafka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-test-support</artifactId>
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.messaging.camel;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.camel.CamelContext;
|
||||
import org.apache.camel.ConsumerTemplate;
|
||||
import org.apache.camel.Exchange;
|
||||
import org.apache.camel.Message;
|
||||
import org.apache.camel.ProducerTemplate;
|
||||
import org.apache.camel.impl.DefaultExchange;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Component
|
||||
public class CamelStubMessages implements MessageVerifier<Message> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(
|
||||
CamelStubMessages.class);
|
||||
|
||||
private final CamelContext context;
|
||||
private final ContractVerifierCamelMessageBuilder builder;
|
||||
|
||||
@Autowired
|
||||
public CamelStubMessages(CamelContext context) {
|
||||
this.context = context;
|
||||
this.builder = new ContractVerifierCamelMessageBuilder(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Message message, String destination) {
|
||||
try {
|
||||
ProducerTemplate producerTemplate = this.context.createProducerTemplate();
|
||||
Exchange exchange = new DefaultExchange(this.context);
|
||||
exchange.setIn(message);
|
||||
producerTemplate.send(destination, exchange);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception occurred while trying to send a message [" + message + "] " +
|
||||
"to a channel with name [" + destination + "]", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void send(T payload, Map<String, Object> headers, String destination) {
|
||||
send(this.builder.create(payload, headers), destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
try {
|
||||
ConsumerTemplate consumerTemplate = this.context.createConsumerTemplate();
|
||||
Exchange exchange = consumerTemplate.receive(destination, timeUnit.toMillis(timeout));
|
||||
return exchange.getIn();
|
||||
} catch (Exception e) {
|
||||
log.error("Exception occurred while trying to read a message from " +
|
||||
" a channel with name [" + destination + "]", e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message receive(String destination) {
|
||||
return receive(destination, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.messaging.camel;
|
||||
|
||||
import org.apache.camel.CamelContext;
|
||||
import org.apache.camel.Message;
|
||||
import org.apache.camel.spring.boot.CamelAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.*;
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
|
||||
import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration;
|
||||
import org.springframework.context.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Message.class)
|
||||
@Import(CamelAutoConfiguration.class)
|
||||
@ConditionalOnProperty(name="stubrunner.camel.enabled", havingValue="true", matchIfMissing = true)
|
||||
@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class)
|
||||
public class ContractVerifierCamelConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
MessageVerifier<Message> contractVerifierMessageExchange(
|
||||
CamelContext camelContext) {
|
||||
return new CamelStubMessages(camelContext);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ContractVerifierMessaging<Message> contractVerifierMessaging(
|
||||
MessageVerifier<Message> exchange) {
|
||||
return new ContractVerifierCamelHelper(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
class ContractVerifierCamelHelper extends ContractVerifierMessaging<Message> {
|
||||
|
||||
public ContractVerifierCamelHelper(
|
||||
MessageVerifier<Message> exchange) {
|
||||
super(exchange);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractVerifierMessage convert(Message receive) {
|
||||
return new ContractVerifierMessage(receive.getBody(), receive.getHeaders());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.messaging.camel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.camel.CamelContext;
|
||||
import org.apache.camel.Message;
|
||||
import org.apache.camel.impl.DefaultMessage;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class ContractVerifierCamelMessageBuilder {
|
||||
|
||||
private final CamelContext context;
|
||||
|
||||
ContractVerifierCamelMessageBuilder(CamelContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public <T> Message create(T payload, Map<String, Object> headers) {
|
||||
DefaultMessage message = new DefaultMessage(this.context);
|
||||
message.setBody(payload);
|
||||
message.setHeaders(headers);
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,4 +4,5 @@ org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStr
|
||||
org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.amqp.ContractVerifierAmqpAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.amqp.RabbitMockConnectionFactoryAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.camel.ContractVerifierCamelConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration
|
||||
@@ -18,6 +18,7 @@
|
||||
<description>Spring Cloud Contract Tests</description>
|
||||
|
||||
<modules>
|
||||
<module>samples-messaging-camel</module>
|
||||
<module>samples-messaging-stream</module>
|
||||
<module>samples-messaging-integration</module>
|
||||
<module>samples-messaging-amqp</module>
|
||||
|
||||
16
tests/samples-messaging-camel/.springBeans
Normal file
16
tests/samples-messaging-camel/.springBeans
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[3.8.0.201606301005-RELEASE]]></pluginVersion>
|
||||
<configSuffixes>
|
||||
<configSuffix><![CDATA[xml]]></configSuffix>
|
||||
</configSuffixes>
|
||||
<enableImports><![CDATA[false]]></enableImports>
|
||||
<configs>
|
||||
<config>java:com.example.fraud.CamelMessagingApplication</config>
|
||||
</configs>
|
||||
<autoconfigs>
|
||||
</autoconfigs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
</beansProjectDescription>
|
||||
52
tests/samples-messaging-camel/pom.xml
Normal file
52
tests/samples-messaging-camel/pom.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?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-tests</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-sample-camel</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Sample Camel</name>
|
||||
<description>Spring Cloud Contract Sample Camel</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-camel</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-pool</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.camel</groupId>
|
||||
<artifactId>camel-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-verifier</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>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BookDeleted implements Serializable {
|
||||
public final String bookName;
|
||||
|
||||
@JsonCreator
|
||||
public BookDeleted(@JsonProperty("bookName") String bookName) {
|
||||
this.bookName = bookName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.camel.Exchange;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BookDeleter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BookDeleter.class);
|
||||
|
||||
/**
|
||||
* Scenario for "should generate tests triggered by a message": client side: if sends
|
||||
* a message to input.messageFrom then message will be sent to output.messageFrom
|
||||
* server side: will send a message to input, verify the message contents and await
|
||||
* upon receiving message on the output messageFrom
|
||||
*/
|
||||
public void bookDeleted(Exchange exchange) {
|
||||
BookDeleted bookDeleted = exchange.getIn().getBody(BookDeleted.class);
|
||||
log.info("Deleting book " + bookDeleted);
|
||||
this.bookSuccessfulyDeleted.set(true);
|
||||
log.info("Book successfuly deleted [" + this.bookSuccessfulyDeleted + "]");
|
||||
}
|
||||
|
||||
private AtomicBoolean bookSuccessfulyDeleted = new AtomicBoolean(false);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class BookReturned implements Serializable {
|
||||
public final String bookName;
|
||||
|
||||
@JsonCreator
|
||||
BookReturned(@JsonProperty("bookName") String bookName) {
|
||||
this.bookName = bookName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example;
|
||||
|
||||
import org.apache.activemq.camel.component.ActiveMQComponent;
|
||||
import org.apache.camel.RoutesBuilder;
|
||||
import org.apache.camel.model.dataformat.JsonLibrary;
|
||||
import org.apache.camel.spring.SpringRouteBuilder;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration
|
||||
public class BookRouteConfiguration {
|
||||
|
||||
@Bean
|
||||
ActiveMQComponent activeMQComponent(@Value("${activemq.url:vm://localhost?broker.persistent=false}") String url) {
|
||||
ActiveMQComponent component = new ActiveMQComponent();
|
||||
component.setBrokerURL(url);
|
||||
return component;
|
||||
}
|
||||
|
||||
@Bean
|
||||
RoutesBuilder myRouter(final BookService bookService, final BookDeleter bookDeleter) {
|
||||
return new SpringRouteBuilder() {
|
||||
|
||||
@Override
|
||||
public void configure() throws Exception {
|
||||
// scenario 1 - from bean to output
|
||||
from("direct:start").unmarshal().json(JsonLibrary.Jackson, BookReturned.class).bean(bookService).to("jms:output");
|
||||
// scenario 2 - from input to output
|
||||
from("jms:input").unmarshal().json(JsonLibrary.Jackson, BookReturned.class).bean(bookService).to("jms:output");
|
||||
// scenario 3 - from input to no output
|
||||
from("jms:delete").unmarshal().json(JsonLibrary.Jackson, BookDeleted.class).bean(bookDeleter);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example;
|
||||
|
||||
import org.apache.camel.Exchange;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class BookService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BookService.class);
|
||||
|
||||
/**
|
||||
* Scenario for "should generate tests triggered by a method": client side: must have
|
||||
* a possibility to "trigger" sending of a message to the given messageFrom server
|
||||
* side: will run the method and await upon receiving message on the output
|
||||
* messageFrom
|
||||
*
|
||||
* Method triggers sending a message to a source
|
||||
*/
|
||||
public void returnBook(Exchange exchange) {
|
||||
BookReturned bookReturned = exchange.getIn().getBody(BookReturned.class);
|
||||
log.info("Returning book [$bookReturned]");
|
||||
exchange.getOut().setBody(bookReturned);
|
||||
exchange.getOut().setHeader("BOOK-NAME", bookReturned.bookName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class CamelMessagingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CamelMessagingApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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 com.example
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
import org.apache.camel.Message
|
||||
import org.apache.camel.model.ModelCamelContext
|
||||
import org.junit.BeforeClass
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier
|
||||
import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper;
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
|
||||
import spock.lang.Specification
|
||||
import spock.util.concurrent.PollingConditions
|
||||
|
||||
import com.jayway.jsonpath.DocumentContext
|
||||
import com.jayway.jsonpath.JsonPath
|
||||
import com.toomuchcoding.jsonassert.JsonAssertion
|
||||
/**
|
||||
* SPIKE ON TESTS FROM NOTES IN MessagingSpec
|
||||
*/
|
||||
// Context configuration would end up in base class
|
||||
@ContextConfiguration(classes = [CamelMessagingApplication], loader = SpringBootContextLoader)
|
||||
@AutoConfigureMessageVerifier
|
||||
class CamelMessagingApplicationSpec extends Specification {
|
||||
|
||||
// ALL CASES
|
||||
@Autowired ModelCamelContext camelContext
|
||||
@Autowired BookDeleter bookDeleter
|
||||
@Inject MessageVerifier<Message> contractVerifierMessaging
|
||||
|
||||
ContractVerifierObjectMapper contractVerifierObjectMapper = new ContractVerifierObjectMapper()
|
||||
|
||||
@BeforeClass
|
||||
static void init() {
|
||||
System.setProperty("org.apache.activemq.SERIALIZABLE_PACKAGES", "*")
|
||||
}
|
||||
|
||||
def "should work for triggered based messaging"() {
|
||||
given:
|
||||
Contract.make {
|
||||
label 'some_label'
|
||||
input {
|
||||
triggeredBy('bookReturnedTriggered()')
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('activemq:output')
|
||||
body('''{ "bookName" : "foo" }''')
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
// generated test should look like this:
|
||||
when:
|
||||
bookReturnedTriggered()
|
||||
then:
|
||||
def response = contractVerifierMessaging.receive('activemq:output')
|
||||
response.headers.get('BOOK-NAME') == 'foo'
|
||||
and:
|
||||
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.body))
|
||||
JsonAssertion.assertThat(parsedJson).field('bookName').isEqualTo('foo')
|
||||
}
|
||||
|
||||
def "should generate tests triggered by a message"() {
|
||||
given:
|
||||
Contract.make {
|
||||
label 'some_label'
|
||||
input {
|
||||
messageFrom('jms:input')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
|
||||
}
|
||||
}
|
||||
outputMessage {
|
||||
sentTo('jms:output')
|
||||
body([
|
||||
bookName: 'foo'
|
||||
])
|
||||
headers {
|
||||
header('BOOK-NAME', 'foo')
|
||||
}
|
||||
}
|
||||
}
|
||||
// generated test should look like this:
|
||||
when:
|
||||
contractVerifierMessaging.send(
|
||||
contractVerifierObjectMapper.writeValueAsString([bookName: 'foo']),
|
||||
[sample: 'header'], 'jms:input')
|
||||
then:
|
||||
def response = contractVerifierMessaging.receive('jms:output')
|
||||
response.headers.get('BOOK-NAME') == 'foo'
|
||||
and:
|
||||
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.body))
|
||||
JsonAssertion.assertThat(parsedJson).field('bookName').isEqualTo('foo')
|
||||
}
|
||||
|
||||
def "should generate tests without destination, triggered by a message"() {
|
||||
given:
|
||||
Contract.make {
|
||||
label 'some_label'
|
||||
input {
|
||||
messageFrom('jms:delete')
|
||||
messageBody([
|
||||
bookName: 'foo'
|
||||
])
|
||||
messageHeaders {
|
||||
header('sample', 'header')
|
||||
}
|
||||
assertThat('bookWasDeleted()')
|
||||
}
|
||||
}
|
||||
// generated test should look like this:
|
||||
when:
|
||||
contractVerifierMessaging.send(contractVerifierObjectMapper.writeValueAsString([bookName: 'foo']),
|
||||
[sample: 'header'], 'jms:delete')
|
||||
then:
|
||||
noExceptionThrown()
|
||||
bookWasDeleted()
|
||||
}
|
||||
|
||||
void bookReturnedTriggered() {
|
||||
camelContext.createProducerTemplate().sendBody('direct:start', '''{"bookName" : "foo" }''')
|
||||
}
|
||||
|
||||
PollingConditions pollingConditions = new PollingConditions()
|
||||
|
||||
void bookWasDeleted() {
|
||||
pollingConditions.eventually {
|
||||
assert bookDeleter.bookSuccessfulyDeleted.get()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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
|
||||
|
||||
It's enough to have both Apache Camel and Spring Cloud Contract Stub Runner on classpath.
|
||||
Remember to annotate your test class with `@AutoConfigureStubRunner`.
|
||||
|
||||
==== Disabling the functionality
|
||||
|
||||
If you need to disable this functionality just pass `stubrunner.camel.enabled=false` property.
|
||||
|
||||
==== 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]
|
||||
----
|
||||
93
tests/spring-cloud-contract-stub-runner-camel/pom.xml
Normal file
93
tests/spring-cloud-contract-stub-runner-camel/pom.xml
Normal file
@@ -0,0 +1,93 @@
|
||||
<?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-tests</artifactId>
|
||||
<version>2.1.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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-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-2017 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,254 @@
|
||||
/*
|
||||
* Copyright 2013-2017 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.context.SpringBootContextLoader
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
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.IgnoreIf
|
||||
import spock.lang.Specification
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@SpringBootTest(properties = "debug=true")
|
||||
@AutoConfigureStubRunner
|
||||
@IgnoreIf({ os.windows })
|
||||
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) {
|
||||
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL: url)
|
||||
try {
|
||||
factory.trustAllPackages = true
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
return factory
|
||||
}
|
||||
|
||||
@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,7 @@
|
||||
stubrunner:
|
||||
repositoryRoot: classpath:m2repo/repository/
|
||||
ids: org.springframework.cloud.contract.verifier.stubs:camelService:0.0.1-SNAPSHOT:stubs
|
||||
stubs-mode: remote
|
||||
server:
|
||||
port: 0
|
||||
debug: true
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2017 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-2017 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-2017 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-2017 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>
|
||||
Reference in New Issue
Block a user