Removed Camel support (#387)

until https://issues.apache.org/jira/browse/CAMEL-11430 gets fixed

fixes #386
This commit is contained in:
Marcin Grzejszczak
2017-09-05 15:14:31 +02:00
committed by GitHub
parent d06af6544f
commit f4ec52d4ac
46 changed files with 17 additions and 1812 deletions

View File

@@ -29,7 +29,7 @@ with __Contract Definition Language__ (DSL). Contract definitions are used to pr
* JSON stub definitions to be used by WireMock when doing integration testing on the client code (__client tests__).
Test code must still be written by hand, test data is produced by Spring Cloud Contract Verifier.
* Messaging routes if you're using one. We're integrating with Spring Integration, Spring Cloud Stream, Spring AMQP and Apache Camel. You can however set your own integrations if you want to
* Messaging routes if you're using one. We're integrating with Spring Integration, Spring Cloud Stream, Spring AMQP. You can however set your own integrations if you want to
* Acceptance tests (in JUnit or Spock) used to verify if server-side implementation of the API is compliant with the contract (__server tests__).
Full test is generated by Spring Cloud Contract Verifier.

View File

@@ -139,4 +139,11 @@ In order to add support for `fromRequest.path` some methods had to be added to t
`TemplateProcessor` interface.
Related to
https://github.com/spring-cloud/spring-cloud-contract/issues/388[issue 388].
https://github.com/spring-cloud/spring-cloud-contract/issues/388[issue 388].
=== 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

View File

@@ -4,7 +4,6 @@ Stub Runner has the functionality to run the published stubs in memory. It can i
- Spring Integration
- Spring Cloud Stream
- Apache Camel
- Spring AMQP
It also provides points of entry to integrate with any other solution on the market.
@@ -31,32 +30,30 @@ For convenience the `StubFinder` interface extends `StubTrigger` so it's enough
[source,groovy]
----
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=client_trigger,indent=0]
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=client_trigger,indent=0]
----
==== Trigger by group and artifact ids
[source,groovy]
----
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=trigger_group_artifact,indent=0]
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_group_artifact,indent=0]
----
==== Trigger by artifact ids
[source,groovy]
----
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=trigger_artifact,indent=0]
include::{tests_path}/spring-cloud-contract-stub-runner-stream/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StreamStubRunnerSpec.groovy[tags=trigger_artifact,indent=0]
----
==== Trigger all messages
[source,groovy]
----
include::{tests_path}/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy[tags=trigger_all,indent=0]
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[]

32
pom.xml
View File

@@ -23,8 +23,6 @@
<inceptionYear>2016</inceptionYear>
<properties>
<activemq.version>5.12.1</activemq.version>
<camel.version>2.18.3</camel.version>
<spring-boot.version>2.0.0.M2</spring-boot.version>
<checkstyle.version>2.17</checkstyle.version>
<spring-cloud-build.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-build.version>
@@ -58,36 +56,6 @@
<type>pom</type>
<scope>import</scope>
</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-starter</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>

View File

@@ -60,17 +60,6 @@
<artifactId>jopt-simple</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot</artifactId>
<version>${camel.version}</version>
<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>

View File

@@ -1,65 +0,0 @@
/*
* 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.Collection;
import java.util.Map;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.spring.SpringRouteBuilder;
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.Bean;
/**
* Camel configuration that iterates over the downloaded Groovy DSLs and registers a route
* for each DSL.
*
* @author Marcin Grzejszczak
*/
//TODO: Set it back once https://issues.apache.org/jira/browse/CAMEL-11430 is done
//@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());
}
}
}
}
};
}
}

View File

@@ -1,109 +0,0 @@
/*
* 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)) {
return false;
}
Object inputMessage = exchange.getIn().getBody();
BodyMatchers matchers = this.groovyDsl.getInput().getMatchers();
Object dslBody = MapConverter.getStubSideValues(this.groovyDsl.getInput().getMessageBody());
Object matchingInputMessage = JsonToJsonPathsConverter
.removeMatchingJsonPaths(dslBody, matchers);
JsonPaths jsonPaths = JsonToJsonPathsConverter
.transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(
matchingInputMessage);
DocumentContext parsedJson;
try {
parsedJson = JsonPath
.parse(this.objectMapper.writeValueAsString(inputMessage));
}
catch (JsonProcessingException e) {
throw new IllegalStateException("Cannot serialize to JSON", e);
}
boolean matches = true;
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 boolean matchesJsonPath(DocumentContext parsedJson, String jsonPath) {
try {
JsonAssertion.assertThat(parsedJson).matchesJsonPath(jsonPath);
return true;
} catch (Exception e) {
return false;
}
}
private boolean headersMatch(Exchange exchange) {
Map<String, Object> headers = exchange.getIn().getHeaders();
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 &= value instanceof Pattern ?
((Pattern) value).matcher(valueInHeader.toString()).matches() :
valueInHeader!=null && valueInHeader.equals(value);
}
return matches;
}
}

View File

@@ -1,59 +0,0 @@
/*
* 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());
}
}
}
}

View File

@@ -1,137 +0,0 @@
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)
}
}

View File

@@ -43,7 +43,6 @@ 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

View File

@@ -56,7 +56,6 @@ 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

View File

@@ -43,7 +43,6 @@ public class StubRunnerBootZookeeperExample {
-Dstubrunner.cloud.stubbed.discovery.enabled=false
-Dstubrunner.cloud.zookeepr.enabled=true
-Dstubrunner.repositoryRoot=classpath:m2repo/repository/
-Dstubrunner.camel.enabled=false
-Deureka.client.enabled=false
-Ddebug=true

View File

@@ -39,7 +39,6 @@ import spock.lang.Specification
// tag::test[]
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
@SpringBootTest(properties = [" stubrunner.cloud.enabled=false",
"stubrunner.camel.enabled=false",
'foo=${stubrunner.runningstubs.fraudDetectionServer.port}'])
@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/")
@DirtiesContext

View File

@@ -18,11 +18,11 @@ package org.springframework.cloud.contract.stubrunner.spring.cloud.consul
import com.ecwid.consul.v1.ConsulClient
import com.ecwid.consul.v1.agent.model.NewService
import org.hamcrest.Description
import org.hamcrest.TypeSafeMatcher
import org.junit.AfterClass
import org.junit.BeforeClass
import org.mockito.ArgumentMatcher
import spock.lang.Specification
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.test.context.SpringBootContextLoader
@@ -33,7 +33,6 @@ import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
import static org.mockito.BDDMockito.then
import static org.mockito.Matchers.argThat
@@ -43,8 +42,7 @@ import static org.mockito.Mockito.mock
*/
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = ["stubrunner.camel.enabled=false",
"eureka.client.enabled=false",
properties = ["eureka.client.enabled=false",
"spring.cloud.zookeeper.enabled=false",
"stubrunner.cloud.stubbed.discovery.enabled=false",
"stubrunner.cloud.eureka.enabled=false",

View File

@@ -1,5 +1,4 @@
stubrunner:
camel.enabled: false
cloud.stubbed.discovery.enabled: true
spring.cloud:
zookeeper:

View File

@@ -6,8 +6,6 @@ stubrunner:
- org.springframework.cloud.contract.verifier.stubs:bootService
cloud:
enabled: false
camel:
enabled: false
spring.cloud:
consul.enabled: false

View File

@@ -3,7 +3,6 @@ spring.cloud:
consul.enabled: false
eureka.client.enabled: false
stubrunner:
camel.enabled: false
idsToServiceIds:
ivyNotation: someValueInsideYourCode
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer

View File

@@ -26,11 +26,6 @@
<artifactId>spring-messaging</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>

View File

@@ -1,88 +0,0 @@
/*
* 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 = new ContractVerifierCamelMessageBuilder();
@Autowired
public CamelStubMessages(CamelContext context) {
this.context = 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);
}
}

View File

@@ -1,65 +0,0 @@
/*
* 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.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Marcin Grzejszczak
*/
@Configuration
@ConditionalOnClass(Message.class)
@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class)
public class ContractVerifierCamelConfiguration {
@Bean
@ConditionalOnMissingBean
MessageVerifier<Message> contractVerifierMessageExchange(
CamelContext context) {
return new CamelStubMessages(context);
}
@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());
}
}

View File

@@ -1,36 +0,0 @@
/*
* 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.Message;
import org.apache.camel.impl.DefaultMessage;
/**
* @author Marcin Grzejszczak
*/
class ContractVerifierCamelMessageBuilder {
public <T> Message create(T payload, Map<String, Object> headers) {
DefaultMessage message = new DefaultMessage();
message.setBody(payload);
message.setHeaders(headers);
return message;
}
}

View File

@@ -4,5 +4,4 @@ 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

View File

@@ -18,15 +18,12 @@
<description>Spring Cloud Contract Tests</description>
<modules>
<!-- TODO: Add support for Camel back -->
<!--<module>samples-messaging-camel</module>-->
<module>samples-messaging-spring</module>
<module>samples-messaging-stream</module>
<module>samples-messaging-integration</module>
<module>samples-messaging-amqp</module>
<module>spring-cloud-contract-stub-runner-boot-eureka</module>
<module>spring-cloud-contract-stub-runner-boot-zookeeper</module>
<!--<module>spring-cloud-contract-stub-runner-camel</module>-->
<module>spring-cloud-contract-stub-runner-context-path</module>
<module>spring-cloud-contract-stub-runner-moco-contract-jar</module>
<module>spring-cloud-contract-stub-runner-moco</module>

View File

@@ -1,16 +0,0 @@
<?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>

View File

@@ -1,52 +0,0 @@
<?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.0.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>

View File

@@ -1,31 +0,0 @@
/*
* 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;
@SuppressWarnings("serial")
public class BookDeleted implements Serializable {
public final String bookName;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public BookDeleted(String bookName) {
this.bookName = bookName;
}
}

View File

@@ -1,45 +0,0 @@
/*
* 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);
}

View File

@@ -1,31 +0,0 @@
/*
* 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;
@SuppressWarnings("serial")
public class BookReturned implements Serializable {
public final String bookName;
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
BookReturned(String bookName) {
this.bookName = bookName;
}
}

View File

@@ -1,56 +0,0 @@
/*
* 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);
}
};
}
}

View File

@@ -1,43 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,28 +0,0 @@
/*
* 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);
}
}

View File

@@ -1,159 +0,0 @@
/*
* 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.annotation.DirtiesContext
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)
@DirtiesContext
@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()
}
}
}

View File

@@ -1,5 +1,4 @@
stubrunner:
camel.enabled: false
idsToServiceIds:
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
server:

View File

@@ -42,8 +42,7 @@ import spock.lang.Specification
*/
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = ["stubrunner.camel.enabled=false",
"stubrunner.cloud.stubbed.discovery.enabled=false",
properties = ["stubrunner.cloud.stubbed.discovery.enabled=false",
"debug=true"])
@AutoConfigureStubRunner( ids =
["org.springframework.cloud.contract.verifier.stubs:loanIssuance",

View File

@@ -1,5 +1,4 @@
stubrunner:
camel.enabled: false
idsToServiceIds:
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
server:

View File

@@ -1,123 +0,0 @@
: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]
----

View File

@@ -1,93 +0,0 @@
<?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.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>spring-cloud-contract-stub-runner-camel</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Contract Stub Runner Camel</name>
<description>Spring Cloud Contract Stub Runner Camel</description>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-stub-runner</artifactId>
</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>

View File

@@ -1,32 +0,0 @@
/*
* 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
}
}

View File

@@ -1,254 +0,0 @@
/*
* 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[]
}

View File

@@ -1,98 +0,0 @@
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"}'''
}
}

View File

@@ -1,5 +0,0 @@
stubrunner.repositoryRoot: classpath:m2repo/repository/
stubrunner.ids: org.springframework.cloud.contract.verifier.stubs:camelService
server:
port: 0
debug: true

View File

@@ -1,25 +0,0 @@
<?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>

View File

@@ -1,28 +0,0 @@
<?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>

View File

@@ -1,28 +0,0 @@
<?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>

View File

@@ -1,28 +0,0 @@
<?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>