From 62c1886cc0bc4f793decf0b822c6a3e6a4b5fd91 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 13 Nov 2018 18:36:49 +0100 Subject: [PATCH] Merged camel routes into a single one for multiple contracts for the same exchange; fixes gh-791 --- .../camel/StubRunnerCamelConfiguration.java | 76 ++++++--- .../camel/StubRunnerCamelPayload.java | 16 ++ .../camel/StubRunnerCamelPredicate.java | 150 ++++++++++++------ .../camel/StubRunnerCamelProcessor.java | 43 +++-- .../camel/StubRunnerCamelPredicateSpec.groovy | 45 +++--- .../camel/CamelStubRunnerSpec.groovy | 43 +++-- .../camel/StubRunnerCamelProcessorSpec.groovy | 9 +- .../src/test/resources/application.yml | 5 +- 8 files changed, 269 insertions(+), 118 deletions(-) create mode 100644 spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPayload.java diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java index f5488d4eeb..da9c05dec4 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelConfiguration.java @@ -16,17 +16,27 @@ package org.springframework.cloud.contract.stubrunner.messaging.camel; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; import org.apache.camel.RoutesBuilder; import org.apache.camel.spring.SpringRouteBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + 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; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; /** * Camel configuration that iterates over the downloaded Groovy DSLs and registers a route @@ -39,6 +49,8 @@ import java.util.Map; @ConditionalOnProperty(name = "stubrunner.camel.enabled", havingValue = "true", matchIfMissing = true) public class StubRunnerCamelConfiguration { + static final String STUBRUNNER_DESTINATION_URL_HEADER_NAME = "STUBRUNNER_DESTINATION_URL"; + @Bean public RoutesBuilder myRouter(final BatchStubRunner batchStubRunner) { return new SpringRouteBuilder() { @@ -46,21 +58,49 @@ public class StubRunnerCamelConfiguration { public void configure() throws Exception { Map> contracts = batchStubRunner .getContracts(); - for (Collection 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()); + for (Map.Entry> entry : contracts + .entrySet()) { + Collection value = entry.getValue(); + MultiValueMap map = new LinkedMultiValueMap<>(); + for (Contract dsl : value) { + if (dsl == null) { + continue; + } + if (dsl.getInput() != null && dsl.getInput() + .getMessageFrom() != null + && StringUtils.hasText( + dsl.getInput().getMessageFrom().getClientValue())) { + String from = dsl.getInput().getMessageFrom() + .getClientValue(); + map.add(from, dsl); + } + } + for (Map.Entry> entries : map.entrySet()) { + from(entries.getKey()) + .filter(new StubRunnerCamelPredicate(entries.getValue())) + .process(new StubRunnerCamelProcessor()) + .dynamicRouter(header(StubRunnerCamelConfiguration.STUBRUNNER_DESTINATION_URL_HEADER_NAME)); } } } - } - }; + }; + } + + + @Bean DummyProcessor dummyStubRunnerProcessor() { + return new DummyProcessor(); } -} + + private static class DummyProcessor implements Processor { + + private static final Log log = LogFactory.getLog(DummyProcessor.class); + + @Override + public void process(Exchange exchange) { + if (log.isDebugEnabled()) { + log.debug("Got exchange [" + exchange + "]"); + } + } + } + +} \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPayload.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPayload.java new file mode 100644 index 0000000000..e50e59d536 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPayload.java @@ -0,0 +1,16 @@ +package org.springframework.cloud.contract.stubrunner.messaging.camel; + +import org.springframework.cloud.contract.spec.Contract; + +/** + * @author Marcin Grzejszczak + */ +class StubRunnerCamelPayload { + final Object payload; + final Contract contract; + + StubRunnerCamelPayload(Contract contract) { + this.contract = contract; + this.payload = null; + } +} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java index f62a75e4ae..a49bfcf935 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java @@ -16,25 +16,30 @@ package org.springframework.cloud.contract.stubrunner.messaging.camel; +import java.util.ArrayList; +import java.util.List; 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; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Predicate; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +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.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.MapConverter; +import org.springframework.cloud.contract.verifier.util.MethodBufferingJsonVerifiable; /** * Passes through a message that matches the one defined in the DSL @@ -43,50 +48,55 @@ import com.toomuchcoding.jsonassert.JsonAssertion; */ class StubRunnerCamelPredicate implements Predicate { - private final Contract groovyDsl; + private static final Log log = LogFactory.getLog(StubRunnerCamelPredicate.class); + + private final List groovyDsls; private final ContractVerifierObjectMapper objectMapper = new ContractVerifierObjectMapper(); - public StubRunnerCamelPredicate(Contract groovyDsl) { - this.groovyDsl = groovyDsl; + public StubRunnerCamelPredicate(List groovyDsls) { + this.groovyDsls = groovyDsls; } @Override public boolean matches(Exchange exchange) { - if (!headersMatch(exchange.getIn().getHeaders())) { + Contract contract = getContract(exchange.getMessage()); + if (log.isDebugEnabled()) { + log.debug("For exchange [" + exchange + "] found contract [" + contract + "]"); + } + if (contract == null) { 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); + exchange.getIn().setBody(new StubRunnerCamelPayload(contract)); + return true; } - 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); + private Contract getContract(Message message) { + for (Contract groovyDsl : this.groovyDsls) { + Contract contract = matchContract(message, groovyDsl); + if (contract != null) { + return contract; } } - return matches; + return null; } - private JsonPaths getJsonPaths(BodyMatchers matchers, Object dslBody) { + private Contract matchContract(Message message, Contract groovyDsl) { + List unmatchedHeaders = headersMatch(message, groovyDsl); + if (!unmatchedHeaders.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("Contract [" + groovyDsl + + "] hasn't matched the following headers " + unmatchedHeaders); + } + return null; + } + Object inputMessage = message.getBody(); + BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); + Object dslBody = MapConverter.getStubSideValues(groovyDsl.getInput().getMessageBody()); Object matchingInputMessage = JsonToJsonPathsConverter .removeMatchingJsonPaths(dslBody, matchers); - return JsonToJsonPathsConverter + JsonPaths jsonPaths = JsonToJsonPathsConverter .transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck( matchingInputMessage); - } - - private DocumentContext deserialize(Object inputMessage) { DocumentContext parsedJson; try { parsedJson = JsonPath @@ -95,32 +105,72 @@ class StubRunnerCamelPredicate implements Predicate { catch (JsonProcessingException e) { throw new IllegalStateException("Cannot serialize to JSON", e); } - return parsedJson; + List unmatchedJsonPath = new ArrayList<>(); + boolean matches = true; + for (MethodBufferingJsonVerifiable path : jsonPaths) { + matches &= matchesJsonPath(unmatchedJsonPath, parsedJson, path.jsonPath()); + } + if (matchers != null && matchers.hasMatchers()) { + for (BodyMatcher matcher : matchers.jsonPathMatchers()) { + String jsonPath = JsonToJsonPathsConverter + .convertJsonPathAndRegexToAJsonPath(matcher, dslBody); + matches &= matchesJsonPath(unmatchedJsonPath, parsedJson, jsonPath); + } + } + if (!unmatchedJsonPath.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("Contract [" + groovyDsl + "] didn't much the body due to " + + unmatchedJsonPath); + } + } + if (matches) { + return groovyDsl; + } + return null; } - private boolean matchesJsonPath(DocumentContext parsedJson, String jsonPath) { + private boolean matchesJsonPath(List unmatchedJsonPath, + DocumentContext parsedJson, String jsonPath) { try { JsonAssertion.assertThat(parsedJson).matchesJsonPath(jsonPath); return true; - } catch (Exception e) { + } + catch (Exception e) { + unmatchedJsonPath.add(e.getLocalizedMessage()); return false; } } - private boolean headersMatch(Map headers) { - boolean matches = true; - for (Header it : this.groovyDsl.getInput().getMessageHeaders().getEntries()) { + private List headersMatch(Message message, Contract groovyDsl) { + List unmatchedHeaders = new ArrayList<>(); + Map headers = message.getHeaders(); + for (Header it : groovyDsl.getInput().getMessageHeaders().getEntries()) { String name = it.getName(); Object value = it.getClientValue(); Object valueInHeader = headers.get(name); - matches &= matchValue(value, valueInHeader); + boolean matches; + if (value instanceof Pattern) { + Pattern pattern = (Pattern) value; + matches = pattern.matcher(valueInHeader.toString()).matches(); + } + else { + matches = valueInHeader != null + && valueInHeader.toString().equals(value.toString()); + } + if (!matches) { + unmatchedHeaders.add("Header with name [" + name + "] was supposed to " + + unmatchedText(value) + " but the value is [" + + (valueInHeader != null ? valueInHeader.toString() : "null") + + "]"); + } } - return matches; + return unmatchedHeaders; } - private boolean matchValue(Object value, Object valueInHeader) { - return value instanceof Pattern ? - ((Pattern) value).matcher(valueInHeader.toString()).matches() : - valueInHeader!=null && valueInHeader.equals(value); + private String unmatchedText(Object expectedValue) { + return expectedValue instanceof Pattern + ? "match pattern [" + ((Pattern) expectedValue).pattern() + "]" + : "be equal to [" + expectedValue + "]"; } + } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java index e733c5a817..3c92811e83 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java @@ -16,12 +16,15 @@ 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.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.cloud.contract.spec.Contract; import org.springframework.cloud.contract.spec.internal.Header; +import org.springframework.cloud.contract.verifier.util.BodyExtractor; /** * Sends forward a message defined in the DSL. Also removes headers from the input message @@ -31,29 +34,45 @@ import org.springframework.cloud.contract.spec.internal.Header; */ class StubRunnerCamelProcessor implements Processor { - private final Contract groovyDsl; + private static final Log log = LogFactory.getLog(StubRunnerCamelProcessor.class); - StubRunnerCamelProcessor(Contract groovyDsl) { - this.groovyDsl = groovyDsl; - } + private static final String DUMMY_BEAN_URL = "bean:dummyStubRunnerProcessor"; @Override - public void process(Exchange exchange) throws Exception { + public void process(Exchange exchange) { Message input = exchange.getIn(); - if (this.groovyDsl.getInput().getMessageHeaders() != null) { - for (Header entry : this.groovyDsl.getInput().getMessageHeaders().getEntries()) { + StubRunnerCamelPayload body = input.getBody(StubRunnerCamelPayload.class); + Contract groovyDsl = body.contract; + setStubRunnerDestinationHeader(exchange, body); + if (groovyDsl.getInput().getMessageHeaders() != null) { + for (Header entry : groovyDsl.getInput().getMessageHeaders().getEntries()) { input.removeHeader(entry.getName()); } } - if (this.groovyDsl.getOutputMessage() == null) { + if (groovyDsl.getOutputMessage() == null) { + if (log.isDebugEnabled()) { + log.debug("No output message provided, will not modify the body"); + } return; } input.setBody(BodyExtractor - .extractStubValueFrom(this.groovyDsl.getOutputMessage().getBody())); - if (this.groovyDsl.getOutputMessage().getHeaders() != null) { - for (Header entry : this.groovyDsl.getOutputMessage().getHeaders().getEntries()) { + .extractStubValueFrom(groovyDsl.getOutputMessage().getBody())); + if (groovyDsl.getOutputMessage().getHeaders() != null) { + for (Header entry : groovyDsl.getOutputMessage().getHeaders().getEntries()) { input.setHeader(entry.getName(), entry.getClientValue()); } } } + + private void setStubRunnerDestinationHeader(Exchange exchange, StubRunnerCamelPayload body) { + boolean outputPart = body.contract.getOutputMessage() != null; + String url = DUMMY_BEAN_URL; + if (outputPart && body.contract.getOutputMessage().getSentTo() != null) { + url = body.contract.getOutputMessage().getSentTo().getClientValue(); + } + exchange.getIn().setHeader(StubRunnerCamelConfiguration.STUBRUNNER_DESTINATION_URL_HEADER_NAME, url); + if (log.isDebugEnabled()) { + log.debug("Set stub runner destination header to [" + url + "]"); + } + } } diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy index ba71c68044..c202dd93a0 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy @@ -2,6 +2,10 @@ package org.springframework.cloud.contract.stubrunner.messaging.camel import org.apache.camel.Exchange import org.apache.camel.Message +import org.apache.camel.impl.DefaultCamelContext +import org.apache.camel.impl.DefaultExchange +import org.apache.camel.impl.DefaultMessage + import org.springframework.cloud.contract.spec.Contract import spock.lang.Specification @@ -9,8 +13,8 @@ import spock.lang.Specification * @author Marcin Grzejszczak */ class StubRunnerCamelPredicateSpec extends Specification { - Exchange exchange = Stub(Exchange) - Message message = Stub(Message) + Exchange exchange = new DefaultExchange(new DefaultCamelContext()) + Message message = new DefaultMessage() def "should return false if headers don't match"() { given: @@ -24,9 +28,9 @@ class StubRunnerCamelPredicateSpec extends Specification { } } and: - StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl) - exchange.in >> message - message.headers >> [ + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) + exchange.in = message + message.headers = [ foo: "non matching stuff" ] expect: @@ -45,12 +49,12 @@ class StubRunnerCamelPredicateSpec extends Specification { } } and: - StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl) - exchange.in >> message - message.headers >> [ + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) + exchange.in = message + message.headers = [ foo: 123 ] - message.body >> [ + message.body = [ foo: "non matching stuff" ] expect: @@ -66,13 +70,13 @@ class StubRunnerCamelPredicateSpec extends Specification { header("foo", 123) } messageBody(foo: "non matching stuff") - stubMatchers { + bodyMatchers { jsonPath('$.foo', byRegex("[0-9]{3}")) } } } and: - StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl) + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) exchange.in >> message message.headers >> [ foo: 123 @@ -92,22 +96,21 @@ class StubRunnerCamelPredicateSpec extends Specification { header("foo", 123) } messageBody(foo: $(c(regex("[0-9]{3}")), p(123))) - } } and: - StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl) - exchange.in >> message - message.headers >> [ + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) + exchange.in = message + message.headers = [ foo: 123 ] - message.body >> [ + message.body = [ foo: 123 ] expect: predicate.matches(exchange) - } + def "should return true if headers and body using matchers match"() { given: Contract dsl = Contract.make { @@ -123,12 +126,12 @@ class StubRunnerCamelPredicateSpec extends Specification { } } and: - StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate(dsl) - exchange.in >> message - message.headers >> [ + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) + exchange.in = message + message.headers = [ foo: 123 ] - message.body >> [ + message.body = [ foo: 123 ] expect: diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy index 8c6c525c5b..5cc63bb229 100644 --- a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy +++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy @@ -21,8 +21,14 @@ 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.ConsumerTemplate import org.apache.camel.Exchange +import org.apache.camel.ProducerTemplate import org.apache.camel.component.jms.JmsConfiguration +import org.apache.camel.impl.DefaultShutdownStrategy +import spock.lang.IgnoreIf +import spock.lang.Specification + import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.boot.autoconfigure.EnableAutoConfiguration @@ -34,34 +40,47 @@ import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRun import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration +import org.springframework.test.annotation.DirtiesContext 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 +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @IgnoreIf({ os.windows }) class CamelStubRunnerSpec extends Specification { @Autowired StubFinder stubFinder @Autowired CamelContext camelContext + ConsumerTemplate consumerTemplate + ProducerTemplate producerTemplate def setup() { + consumerTemplate = camelContext.createConsumerTemplate() + producerTemplate = camelContext.createProducerTemplate() + } + + def cleanup() { // ensure that message were taken from the queue - camelContext.createConsumerTemplate().receive('jms:output', 100) + consumerTemplate.receive('jms:output', 100) + consumerTemplate.receive('jms:input', 100) + this.producerTemplate.stop() + this.consumerTemplate.stop() + def strategy = new DefaultShutdownStrategy(this.camelContext) + strategy.timeout = 1 + this.camelContext.shutdownStrategy = strategy } 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']) + producerTemplate.sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header']) // end::client_send[] then: // tag::client_receive[] - Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000) // end::client_receive[] and: // tag::client_receive_message[] @@ -78,7 +97,7 @@ class CamelStubRunnerSpec extends Specification { // end::client_trigger[] then: // tag::client_trigger_receive[] - Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000) // end::client_trigger_receive[] and: // tag::client_trigger_message[] @@ -94,7 +113,7 @@ class CamelStubRunnerSpec extends Specification { 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) + Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000) and: receivedMessage != null assertThatBodyContainsBookNameFoo(receivedMessage.in.body) @@ -107,7 +126,7 @@ class CamelStubRunnerSpec extends Specification { stubFinder.trigger('camelService', 'return_book_1') // end::trigger_artifact[] then: - Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000) and: receivedMessage != null assertThatBodyContainsBookNameFoo(receivedMessage.in.body) @@ -134,7 +153,7 @@ class CamelStubRunnerSpec extends Specification { stubFinder.trigger() // end::trigger_all[] then: - Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + Exchange receivedMessage = consumerTemplate.receive('jms:output', 5000) and: receivedMessage != null assertThatBodyContainsBookNameFoo(receivedMessage.in.body) @@ -144,7 +163,7 @@ class CamelStubRunnerSpec extends Specification { def 'should trigger a label with no output message'() { when: // tag::trigger_no_output[] - camelContext.createProducerTemplate().sendBodyAndHeaders('jms:delete', new BookReturned('foo'), [sample: 'header']) + producerTemplate.sendBodyAndHeaders('jms:delete', new BookReturned('foo'), [sample: 'header']) // end::trigger_no_output[] then: noExceptionThrown() @@ -152,9 +171,9 @@ class CamelStubRunnerSpec extends Specification { def 'should not trigger a message that does not match input'() { when: - camelContext.createProducerTemplate().sendBodyAndHeaders('jms:input', new BookReturned('notmatching'), [wrong: 'header_value']) + producerTemplate.sendBodyAndHeaders('jms:input', new BookReturned('notmatching'), [wrong: 'header_value']) then: - Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 100) + Exchange receivedMessage = consumerTemplate.receive('jms:output', 100) and: receivedMessage == null } diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy index 279782c65e..a6ac9cb1a6 100644 --- a/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy +++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessorSpec.groovy @@ -27,8 +27,9 @@ class StubRunnerCamelProcessorSpec extends Specification { def 'should not process the message if there is no output message'() { given: - StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor(noOutputMessageContract) + StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor() when: + message.in.body = new StubRunnerCamelPayload(noOutputMessageContract) processor.process(message) then: noExceptionThrown() @@ -58,8 +59,9 @@ class StubRunnerCamelProcessorSpec extends Specification { def 'should process message when it has an output message section'() { given: - StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor(dsl) + StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor() when: + message.in.body = new StubRunnerCamelPayload(dsl) processor.process(message) then: message.getIn().getBody(String) == '{"responseId":"123"}' @@ -89,8 +91,9 @@ class StubRunnerCamelProcessorSpec extends Specification { def 'should convert dsl into message with regex in GString'() { given: - StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor(dslWithRegexInGString) + StubRunnerCamelProcessor processor = new StubRunnerCamelProcessor() when: + message.in.body = new StubRunnerCamelPayload(dslWithRegexInGString) processor.process(message) then: message.getIn().getBody(String) == '''{"id":"99","temperature":"123.45"}''' diff --git a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml index b1b686626b..d7890d631c 100644 --- a/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml +++ b/tests/spring-cloud-contract-stub-runner-camel/src/test/resources/application.yml @@ -1,7 +1,8 @@ stubrunner: - repositoryRoot: classpath:m2repo/repository/ + repository-root: classpath:m2repo/repository/ ids: org.springframework.cloud.contract.verifier.stubs:camelService:0.0.1-SNAPSHOT:stubs stubs-mode: remote server: port: 0 -debug: true \ No newline at end of file +debug: true +logging.level.org.springframework.cloud.contract: debug \ No newline at end of file