diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy index f2ff1a7617..8cb84a57dc 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy @@ -58,7 +58,7 @@ class SingleTestGenerator { File stubsFile = it.path.toFile() log.debug("Stub content from file [${stubsFile.text}]") GroovyDsl stubContent = new GroovyShell(delegate.class.classLoader, new Binding(), new CompilerConfiguration(sourceEncoding:'UTF-8')).evaluate(stubsFile) - TestType testType = (stubContent.inputMessage || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP + TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP return [(new ParsedDsl(it, stubContent, stubsFile)) : testType] } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/BodyAsString.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/BodyAsString.groovy new file mode 100644 index 0000000000..7b03c5d126 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/BodyAsString.groovy @@ -0,0 +1,52 @@ +package io.codearte.accurest.builder + +import groovy.json.JsonOutput +import groovy.json.StringEscapeUtils +import io.codearte.accurest.dsl.internal.DslProperty +import io.codearte.accurest.util.MapConverter + +import static io.codearte.accurest.util.ContentUtils.extractValue + +/** + * Class that constructs a String from Body + * + * @author Marcin Grzejszczak + */ +class BodyAsString { + + static String extractServerValueFrom(Object body) { + Object bodyValue = extractServerValueFromBody(body) + String json = new JsonOutput().toJson(bodyValue) + json = StringEscapeUtils.unescapeJavaScript(json) + return trimRepeatedQuotes(json) + } + + static String extractClientValueFrom(Object body) { + Object bodyValue = extractClientValueFromBody(body); + String json = new JsonOutput().toJson(bodyValue) + json = StringEscapeUtils.unescapeJavaScript(json) + return trimRepeatedQuotes(json) + } + + private static String trimRepeatedQuotes(String toTrim) { + return toTrim.startsWith('"') ? toTrim.replaceAll('"', '') : toTrim + } + + private static Object extractServerValueFromBody(bodyValue) { + if (bodyValue instanceof GString) { + bodyValue = extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue }) + } else { + bodyValue = MapConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.serverValue : it }) + } + return bodyValue + } + + private static Object extractClientValueFromBody(bodyValue) { + if (bodyValue instanceof GString) { + bodyValue = extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.clientValue }) + } else { + bodyValue = MapConverter.transformValues(bodyValue, { it instanceof DslProperty ? it.clientValue : it }) + } + return bodyValue + } +} diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MessagingMethodBodyBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MessagingMethodBodyBuilder.groovy index e5a523e894..51d899e48b 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MessagingMethodBodyBuilder.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MessagingMethodBodyBuilder.groovy @@ -22,7 +22,7 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder { protected final OutputMessage outputMessage MessagingMethodBodyBuilder(GroovyDsl stubDefinition) { - this.inputMessage = stubDefinition.inputMessage + this.inputMessage = stubDefinition.input this.outputMessage = stubDefinition.outputMessage } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy index b53e72db3e..71c76b7f86 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy @@ -44,7 +44,7 @@ class MethodBuilder { } private MethodBodyBuilder getMethodBodyBuilder() { - if (stubContent.inputMessage || stubContent.outputMessage) { + if (stubContent.input || stubContent.outputMessage) { if (configProperties.targetFramework == TestFramework.JUNIT){ return new JUnitMessagingMethodBodyBuilder(stubContent) } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/GroovyDsl.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/GroovyDsl.groovy index b3b5a1e4e2..3cd0e993ed 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/GroovyDsl.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/GroovyDsl.groovy @@ -18,7 +18,7 @@ class GroovyDsl { Response response String label String description - Input inputMessage + Input input OutputMessage outputMessage static GroovyDsl make(Closure closure) { @@ -53,8 +53,8 @@ class GroovyDsl { } void input(@DelegatesTo(Input) Closure closure) { - this.inputMessage = new Input() - closure.delegate = inputMessage + this.input = new Input() + closure.delegate = input closure() } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Headers.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Headers.groovy index 27dd9bf192..98e7bed9bc 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Headers.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Headers.groovy @@ -26,6 +26,14 @@ class Headers { } } + Map asStubSideMap() { + def acc = [:].withDefault { [] as Collection } + return entries.inject(acc as Map) { Map map, Header header -> + map[header.name] = header.clientValue + return map + } as Map + } + boolean equals(o) { if (this.is(o)) return true if (getClass() != o.class) return false diff --git a/accurest-messaging/accurest-messaging-core/src/main/java/io/codearte/accurest/messaging/AccurestFilter.java b/accurest-messaging/accurest-messaging-core/src/main/java/io/codearte/accurest/messaging/AccurestFilter.java new file mode 100644 index 0000000000..f41e544df0 --- /dev/null +++ b/accurest-messaging/accurest-messaging-core/src/main/java/io/codearte/accurest/messaging/AccurestFilter.java @@ -0,0 +1,14 @@ +package io.codearte.accurest.messaging; + +/** + * Contract for filtering out messages that do not match the structure in the Accurest DSL + * + * @author Marcin Grzejszczak + */ +public interface AccurestFilter { + + /** + * @return @{code true} if the message should be passed through, @{code false} if the message should be filtered out, + */ + boolean matches(AccurestMessage message); +} diff --git a/settings.gradle b/settings.gradle index 54053949b1..da50942a1e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,14 +1,20 @@ include 'docs' include "accurest-core", "accurest-gradle-plugin", 'accurest-converters', 'accurest-testing-utils' -include ':stub-runner:stub-runner' -include ':stub-runner:stub-runner-spring' -include ':stub-runner:stub-runner-spring-cloud' -include ':stub-runner:stub-runner-junit' + include ':accurest-messaging:accurest-messaging-core' include ':accurest-messaging:accurest-messaging-integration' include ':accurest-messaging:accurest-messaging-stream' include ':accurest-messaging:accurest-messaging-camel' +include ':stub-runner:stub-runner' +include ':stub-runner:stub-runner-spring' +include ':stub-runner:stub-runner-spring-cloud' +include ':stub-runner:stub-runner-junit' + +include ':stub-runner:stub-runner-messaging:stub-runner-messaging-integration' +include ':stub-runner:stub-runner-messaging:stub-runner-messaging-stream' +include ':stub-runner:stub-runner-messaging:stub-runner-messaging-camel' + include ':samples:messaging-stream' include ':samples:messaging-integration' include ':samples:messaging-camel' @@ -18,4 +24,5 @@ rootProject.name = "accurest" //to prevent StackOverflow in Sonar project(":stub-runner").name = "stub-runner-root" -project(":accurest-messaging").name = "accurest-messaging-root" \ No newline at end of file +project(":accurest-messaging").name = "accurest-messaging-root" +project(":stub-runner:stub-runner-messaging").name = "stub-runner-messaging-root" diff --git a/stub-runner/stub-runner-junit/src/main/groovy/io/codearte/accurest/stubrunner/junit/AccurestRule.java b/stub-runner/stub-runner-junit/src/main/groovy/io/codearte/accurest/stubrunner/junit/AccurestRule.java index a47e4e9e8d..c4ecac01bf 100644 --- a/stub-runner/stub-runner-junit/src/main/groovy/io/codearte/accurest/stubrunner/junit/AccurestRule.java +++ b/stub-runner/stub-runner-junit/src/main/groovy/io/codearte/accurest/stubrunner/junit/AccurestRule.java @@ -6,12 +6,14 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; +import io.codearte.accurest.dsl.GroovyDsl; import io.codearte.accurest.stubrunner.BatchStubRunner; import io.codearte.accurest.stubrunner.BatchStubRunnerFactory; import io.codearte.accurest.stubrunner.RunningStubs; @@ -161,4 +163,24 @@ public class AccurestRule implements TestRule, StubFinder { public RunningStubs findAllRunningStubs() { return stubFinder.findAllRunningStubs(); } + + @Override + public Map> getAccurestContracts() { + return stubFinder.getAccurestContracts(); + } + + @Override + public void trigger(String ivyNotation, String labelName) { + throw new UnsupportedOperationException("Feature not yet supported"); + } + + @Override + public void trigger(String labelName) { + throw new UnsupportedOperationException("Feature not yet supported"); + } + + @Override + public void trigger() { + throw new UnsupportedOperationException("Feature not yet supported"); + } } diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/build.gradle b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/build.gradle new file mode 100644 index 0000000000..31a1bf7460 --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/build.gradle @@ -0,0 +1,25 @@ +repositories { + mavenLocal() + jcenter() + maven { + url "http://repo.spring.io/snapshot" + } + maven { + url "http://repo.spring.io/milestone" + } +} + +dependencies { + compile project(':stub-runner-root:stub-runner-spring') + compile project(':accurest-messaging-root:accurest-messaging-camel') + compile 'org.apache.camel:camel-spring-boot-starter:2.17.0' + compile 'org.apache.camel:camel-jackson:2.17.0' + + testCompile 'org.apache.camel:camel-jms:2.17.0' + testCompile 'org.apache.activemq:activemq-camel:5.12.1' + testCompile 'org.apache.activemq:activemq-pool:5.12.1' + testCompile 'org.springframework.boot:spring-boot-starter-test:1.3.3.RELEASE' + testCompile('org.spockframework:spock-spring:1.0-groovy-2.4') { + exclude(group: 'org.codehaus.groovy') + } +} \ No newline at end of file diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelConfiguration.groovy b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelConfiguration.groovy new file mode 100644 index 0000000000..8941d4984e --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelConfiguration.groovy @@ -0,0 +1,35 @@ +package io.codearte.accurest.stubrunner.messaging.camel + +import io.codearte.accurest.dsl.GroovyDsl +import io.codearte.accurest.stubrunner.BatchStubRunner +import io.codearte.accurest.stubrunner.StubConfiguration +import org.apache.camel.RoutesBuilder +import org.apache.camel.spring.SpringRouteBuilder +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +/** + * Camel configuration that iterates over the downloaded Groovy DSLs + * and registers a route for each DSL. + * + * @author Marcin Grzejszczak + */ +@Configuration +class StubRunnerCamelConfiguration { + + @Bean + RoutesBuilder myRouter(BatchStubRunner batchStubRunner) { + return new SpringRouteBuilder() { + @Override + public void configure() throws Exception { + Map> accurestContracts = batchStubRunner.accurestContracts + (accurestContracts.values().flatten() as Collection).findAll { it?.input?.messageFrom && it?.outputMessage?.sentTo }.each { + from(it.input.messageFrom) + .filter(new StubRunnerCamelPredicate(it)) + .process(new StubRunnerCamelProcessor(it)) + .to(it.outputMessage.sentTo) + } + } + }; + } +} diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelPredicate.groovy b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelPredicate.groovy new file mode 100644 index 0000000000..5c5834807f --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelPredicate.groovy @@ -0,0 +1,58 @@ +package io.codearte.accurest.stubrunner.messaging.camel + +import com.fasterxml.jackson.databind.ObjectMapper +import com.jayway.jsonpath.DocumentContext +import com.jayway.jsonpath.JsonPath +import com.toomuchcoding.jsonassert.JsonAssertion +import com.toomuchcoding.jsonassert.JsonVerifiable +import groovy.transform.PackageScope +import io.codearte.accurest.dsl.GroovyDsl +import io.codearte.accurest.util.JsonPaths +import io.codearte.accurest.util.JsonToJsonPathsConverter +import org.apache.camel.Exchange +import org.apache.camel.Predicate + +/** + * Passes through a message that matches the one defined in the DSL + * + * @author Marcin Grzejszczak + */ +@PackageScope +class StubRunnerCamelPredicate implements Predicate { + + private final GroovyDsl groovyDsl + private final ObjectMapper objectMapper = new ObjectMapper() + + StubRunnerCamelPredicate(GroovyDsl groovyDsl) { + this.groovyDsl = groovyDsl + } + + @Override + boolean matches(Exchange exchange) { + if(!headersMatch(exchange)){ + return false + } + Object inputMessage = exchange.in.body + JsonPaths jsonPaths = JsonToJsonPathsConverter.transformToJsonPathWithStubsSideValues(groovyDsl.input.messageBody) + DocumentContext parsedJson = JsonPath.parse(objectMapper.writeValueAsString(inputMessage)) + return jsonPaths.every { matchesJsonPath(parsedJson, it) } + } + + private boolean matchesJsonPath(DocumentContext parsedJson, JsonVerifiable jsonVerifiable) { + try { + JsonAssertion.assertThat(parsedJson).matchesJsonPath(jsonVerifiable.jsonPath()) + return true + } catch (Exception e) { + return false + } + } + + private boolean headersMatch(Exchange exchange) { + Map headers = exchange.getIn().getHeaders() + return groovyDsl.input.messageHeaders.entries.every { + String name = it.name + Object value = it.clientValue + return headers.get(name) == value + } + } +} diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelProcessor.groovy b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelProcessor.groovy new file mode 100644 index 0000000000..87b2f8590e --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/groovy/io/codearte/accurest/stubrunner/messaging/camel/StubRunnerCamelProcessor.groovy @@ -0,0 +1,36 @@ +package io.codearte.accurest.stubrunner.messaging.camel + +import groovy.transform.PackageScope +import io.codearte.accurest.builder.BodyAsString +import io.codearte.accurest.dsl.GroovyDsl +import org.apache.camel.Exchange +import org.apache.camel.Message +import org.apache.camel.Processor + +/** + * 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 + */ +@PackageScope +class StubRunnerCamelProcessor implements Processor { + + private final GroovyDsl groovyDsl + + StubRunnerCamelProcessor(GroovyDsl groovyDsl) { + this.groovyDsl = groovyDsl + } + + @Override + void process(Exchange exchange) throws Exception { + Message input = exchange.in + input.body = BodyAsString.extractClientValueFrom(groovyDsl.outputMessage.body) + groovyDsl.input.messageHeaders.entries.each { + input.removeHeader(it.name) + } + groovyDsl.outputMessage.headers.entries.each { + input.setHeader(it.name, it.clientValue) + } + } +} diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/resources/META-INF/spring.factories b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..bb95d2a818 --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configuration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.codearte.accurest.stubrunner.messaging.camel.StubRunnerCamelConfiguration diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/groovy/io/codearte/accurest/stubrunner/messaging/camel/BookReturned.groovy b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/groovy/io/codearte/accurest/stubrunner/messaging/camel/BookReturned.groovy new file mode 100644 index 0000000000..b6523d2e5c --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/groovy/io/codearte/accurest/stubrunner/messaging/camel/BookReturned.groovy @@ -0,0 +1,16 @@ +package io.codearte.accurest.stubrunner.messaging.camel + +import com.fasterxml.jackson.annotation.JsonCreator +import groovy.transform.CompileStatic +import groovy.transform.EqualsAndHashCode + +@CompileStatic +@EqualsAndHashCode +class BookReturned implements Serializable { + final String bookName + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + BookReturned(String bookName) { + this.bookName = bookName + } +} diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/groovy/io/codearte/accurest/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/groovy/io/codearte/accurest/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy new file mode 100644 index 0000000000..63102256f1 --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/groovy/io/codearte/accurest/stubrunner/messaging/camel/CamelStubRunnerSpec.groovy @@ -0,0 +1,108 @@ +package io.codearte.accurest.stubrunner.messaging.camel + +import com.fasterxml.jackson.databind.ObjectMapper +import io.codearte.accurest.stubrunner.StubFinder +import org.apache.activemq.camel.component.ActiveMQComponent +import org.apache.camel.CamelContext +import org.apache.camel.Exchange +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.SpringApplicationContextLoader +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration +import org.springframework.test.context.ContextConfiguration +import spock.lang.Specification +/** + * @author Marcin Grzejszczak + */ +@Configuration +@ComponentScan +@EnableAutoConfiguration +@ContextConfiguration(classes = CamelStubRunnerSpec, loader = SpringApplicationContextLoader) +class CamelStubRunnerSpec extends Specification { + + @Autowired StubFinder stubFinder + @Autowired CamelContext camelContext + + def 'should download the stub and register a route for it'() { + when: + camelContext.createProducerTemplate().sendBodyAndHeaders('jms:input', new BookReturned('foo'), [sample: 'header']) + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + and: + receivedMessage != null + receivedMessage.in.body == '{"bookName":"foo"}' + receivedMessage.in.headers.get('BOOK-NAME') == 'foo' + } + + def 'should trigger a message by label'() { + when: + stubFinder.trigger('return_book_1') + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + and: + receivedMessage != null + receivedMessage.in.body == '{ "bookName" : "foo" }' + receivedMessage.in.headers.get('BOOK-NAME') == 'foo' + } + + def 'should trigger a label for the existing groupId:artifactId'() { + when: + stubFinder.trigger('io.codearte.accurest.stubs:camelService', 'return_book_1') + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + and: + receivedMessage != null + receivedMessage.in.body == '{ "bookName" : "foo" }' + receivedMessage.in.headers.get('BOOK-NAME') == 'foo' + } + + def 'should trigger a label for the existing artifactId'() { + when: + stubFinder.trigger('camelService', 'return_book_1') + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + and: + receivedMessage != null + receivedMessage.in.body == '{ "bookName" : "foo" }' + receivedMessage.in.headers.get('BOOK-NAME') == 'foo' + } + + def 'should not run any wrong trigger when missing label is passed'() { + when: + stubFinder.trigger('missing label') + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 100) + and: + receivedMessage == null + } + + def 'should not run any wrong trigger when missing label and artifactid is passed'() { + when: + stubFinder.trigger('some:service', 'return_book_1') + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 100) + and: + receivedMessage == null + } + + def 'should trigger messages by running all triggers'() { + given: + ObjectMapper objectMapper = new ObjectMapper() + when: + stubFinder.trigger() + then: + Exchange receivedMessage = camelContext.createConsumerTemplate().receive('jms:output', 5000) + and: + receivedMessage != null + objectMapper.writeValueAsString(receivedMessage.in.body) == '{"bookName":"foo"}' + receivedMessage.in.headers.get('BOOK-NAME') == 'foo' + } + + @Bean + ActiveMQComponent activeMQComponent(@Value('${activemq.url:vm://localhost?broker.persistent=false}') String url) { + return new ActiveMQComponent(brokerURL: url) + } +} diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/application.yml b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/application.yml new file mode 100644 index 0000000000..6fadb526ec --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/application.yml @@ -0,0 +1,2 @@ +stubrunner.stubs.repository.root: classpath:m2repo/repository/ +stubrunner.stubs.ids: io.codearte.accurest.stubs:camelService \ No newline at end of file diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT-stubs.jar b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT-stubs.jar new file mode 100644 index 0000000000..17df8f09ab Binary files /dev/null and b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT-stubs.jar differ diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT.pom b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT.pom new file mode 100644 index 0000000000..4e8bab7de0 --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/camelService-0.0.1-SNAPSHOT.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + io.codearte.accurest.stubs + camelService + 0.0.1-SNAPSHOT + pom + diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/maven-metadata-local.xml b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/maven-metadata-local.xml new file mode 100644 index 0000000000..f8f49e32bb --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/0.0.1-SNAPSHOT/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + io.codearte.accurest.stubs + camelService + 0.0.1-SNAPSHOT + + + true + + 20160409062112 + + diff --git a/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/maven-metadata-local.xml b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/maven-metadata-local.xml new file mode 100644 index 0000000000..e71db595a7 --- /dev/null +++ b/stub-runner/stub-runner-messaging/stub-runner-messaging-camel/src/test/resources/m2repo/repository/io/codearte/accurest/stubs/camelService/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + io.codearte.accurest.stubs + camelService + 0.0.1-SNAPSHOT + + + 0.0.1-SNAPSHOT + + 20160409062112 + + diff --git a/stub-runner/stub-runner-spring/src/main/groovy/io/codearte/accurest/stubrunner/spring/StubRunnerConfiguration.java b/stub-runner/stub-runner-spring/src/main/groovy/io/codearte/accurest/stubrunner/spring/StubRunnerConfiguration.java index 0e803b4284..a375442b2c 100644 --- a/stub-runner/stub-runner-spring/src/main/groovy/io/codearte/accurest/stubrunner/spring/StubRunnerConfiguration.java +++ b/stub-runner/stub-runner-spring/src/main/groovy/io/codearte/accurest/stubrunner/spring/StubRunnerConfiguration.java @@ -3,11 +3,14 @@ package io.codearte.accurest.stubrunner.spring; import java.io.IOException; import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; +import io.codearte.accurest.messaging.AccurestMessaging; +import io.codearte.accurest.messaging.noop.NoOpAccurestMessaging; import io.codearte.accurest.stubrunner.BatchStubRunner; import io.codearte.accurest.stubrunner.BatchStubRunnerFactory; import io.codearte.accurest.stubrunner.StubConfiguration; @@ -22,6 +25,8 @@ import io.codearte.accurest.stubrunner.util.StubsParser; @Configuration public class StubRunnerConfiguration { + @Autowired(required = false) AccurestMessaging accurestMessaging; + /** * Bean that initializes stub runners, runs them and on shutdown closes them. Upon its instantiation * JAR with stubs is downloaded and unpacked to a temporary folder and WireMock server are started @@ -45,7 +50,8 @@ public class StubRunnerConfiguration { StubRunnerOptions stubRunnerOptions = new StubRunnerOptions(minPortValue, maxPortValue, uriStringOrEmpty(stubRepositoryRoot), stubRepositoryRoot == null || workOffline, stubsSuffix); Set dependencies = StubsParser.fromString(stubs, stubsSuffix); - BatchStubRunner batchStubRunner = new BatchStubRunnerFactory(stubRunnerOptions, dependencies).buildBatchStubRunner(); + BatchStubRunner batchStubRunner = new BatchStubRunnerFactory(stubRunnerOptions, dependencies, + accurestMessaging != null ? accurestMessaging : new NoOpAccurestMessaging()).buildBatchStubRunner(); // TODO: Consider running it in a separate thread batchStubRunner.runStubs(); return batchStubRunner; diff --git a/stub-runner/stub-runner-spring/src/main/resources/META-INF/spring.factories b/stub-runner/stub-runner-spring/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..24ddd934bf --- /dev/null +++ b/stub-runner/stub-runner-spring/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configuration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.codearte.accurest.stubrunner.spring.StubRunnerConfiguration \ No newline at end of file diff --git a/stub-runner/stub-runner/build.gradle b/stub-runner/stub-runner/build.gradle index d8a1265ef6..c6e992b79a 100644 --- a/stub-runner/stub-runner/build.gradle +++ b/stub-runner/stub-runner/build.gradle @@ -5,6 +5,7 @@ mainClassName = 'io.codearte.accurest.stubrunner.StubRunnerMain' dependencies { compile project(':accurest-core') + compile project(':accurest-messaging-root:accurest-messaging-core') compile 'org.apache.ivy:ivy:2.4.0' compile localGroovy() compile "com.github.tomakehurst:wiremock:$wiremockVersion" diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunner.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunner.groovy index a29a799eaf..7aff5d3a3d 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunner.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunner.groovy @@ -1,7 +1,7 @@ package io.codearte.accurest.stubrunner import groovy.transform.CompileStatic - +import io.codearte.accurest.dsl.GroovyDsl /** * Manages lifecycle of multiple {@link StubRunner} instances. * @@ -48,6 +48,29 @@ class BatchStubRunner implements StubRunning { return new RunningStubs(stubRunners.collect { StubRunner runner -> runner.findAllRunningStubs() }) } + @Override + Map> getAccurestContracts() { + return stubRunners.inject([:]) { Map> map, StubRunner stubRunner -> + map.putAll(stubRunner.accurestContracts) + return map + } as Map> + } + + @Override + void trigger(String ivyNotation, String labelName) { + stubRunners.each { it.trigger(ivyNotation, labelName) } + } + + @Override + void trigger(String labelName) { + stubRunners.each { it.trigger(labelName) } + } + + @Override + void trigger() { + stubRunners.each { it.trigger() } + } + @Override void close() throws IOException { stubRunners.each { diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunnerFactory.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunnerFactory.groovy index 99b01dcfc0..b57b1c37ad 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunnerFactory.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/BatchStubRunnerFactory.groovy @@ -1,6 +1,8 @@ package io.codearte.accurest.stubrunner import groovy.transform.CompileStatic +import io.codearte.accurest.messaging.AccurestMessaging +import io.codearte.accurest.messaging.noop.NoOpAccurestMessaging /** * Manages lifecycle of multiple {@link StubRunner} instances. @@ -14,21 +16,29 @@ class BatchStubRunnerFactory { private final StubRunnerOptions stubRunnerOptions private final Collection dependencies private final StubDownloader stubDownloader + private final AccurestMessaging accurestMessaging BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, Collection dependencies) { - this(stubRunnerOptions, dependencies, new GrapeStubDownloader()) + this(stubRunnerOptions, dependencies, new GrapeStubDownloader(), new NoOpAccurestMessaging()) + } + + BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, Collection dependencies, + AccurestMessaging accurestMessaging) { + this(stubRunnerOptions, dependencies, new GrapeStubDownloader(), accurestMessaging) } BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, Collection dependencies, - StubDownloader stubDownloader) { + StubDownloader stubDownloader, + AccurestMessaging accurestMessaging) { this.stubRunnerOptions = stubRunnerOptions this.dependencies = dependencies this.stubDownloader = stubDownloader + this.accurestMessaging = accurestMessaging } BatchStubRunner buildBatchStubRunner() { - StubRunnerFactory stubRunnerFactory = new StubRunnerFactory(stubRunnerOptions, dependencies, stubDownloader) + StubRunnerFactory stubRunnerFactory = new StubRunnerFactory(stubRunnerOptions, dependencies, stubDownloader, accurestMessaging) return new BatchStubRunner(stubRunnerFactory.createStubsFromServiceConfiguration()) } diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/GroovyDslWrapper.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/GroovyDslWrapper.groovy index af9af5b155..dbd73859b9 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/GroovyDslWrapper.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/GroovyDslWrapper.groovy @@ -11,7 +11,7 @@ import io.codearte.accurest.dsl.GroovyDsl @CompileStatic class GroovyDslWrapper { - @Delegate private final GroovyDsl groovyDsl + @Delegate final GroovyDsl groovyDsl GroovyDslWrapper(GroovyDsl groovyDsl) { this.groovyDsl = groovyDsl diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubConfiguration.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubConfiguration.groovy index 1ab0c82e0c..a4eea495dd 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubConfiguration.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubConfiguration.groovy @@ -1,5 +1,6 @@ package io.codearte.accurest.stubrunner +import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode import io.codearte.accurest.stubrunner.util.StringUtils @@ -51,11 +52,28 @@ public class StubConfiguration { return StringUtils.hasText(classifier) } - public String toColonSeparatedDependencyNotation() { + String toColonSeparatedDependencyNotation() { if(!isDefined()) { return "" } return [groupId, artifactId, classifier].join(STUB_COLON_DELIMITER) } + @CompileDynamic + boolean matches(String ivyNotationAsString) { + def (String groupId, String artifactId) = ivyNotationFrom(ivyNotationAsString) + if (!groupId) { + return this.artifactId == artifactId + } + return this.groupId == groupId && this.artifactId == artifactId + } + + private String[] ivyNotationFrom(String ivyNotation) { + String[] splitString = ivyNotation.split(":") + if (splitString.length == 1) { + // assuming that ivy notation represents artifactId only + return [null, splitString[0]] as String[] + } + return [splitString[0], splitString[1]] as String[] + } } \ No newline at end of file diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubData.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubData.groovy index 93741e2f57..dbbe08c4c6 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubData.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubData.groovy @@ -2,6 +2,8 @@ package io.codearte.accurest.stubrunner import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode +import io.codearte.accurest.dsl.GroovyDsl + /** * @author Marcin Grzejszczak */ @@ -9,5 +11,5 @@ import groovy.transform.EqualsAndHashCode @EqualsAndHashCode class StubData { final Integer port - final List contracts + final List contracts } diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubFinder.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubFinder.groovy index f67825bcef..9c14c75735 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubFinder.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubFinder.groovy @@ -1,6 +1,8 @@ package io.codearte.accurest.stubrunner -interface StubFinder { +import io.codearte.accurest.dsl.GroovyDsl + +interface StubFinder extends StubTriggerer { /** * For the given groupId and artifactId tries to find the matching * URL of the running stub. @@ -23,4 +25,9 @@ interface StubFinder { * Returns all running stubs */ RunningStubs findAllRunningStubs() + + /** + * Returns the list of Accurest contracts + */ + Map> getAccurestContracts() } \ No newline at end of file diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRepository.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRepository.groovy index f7f43f0f2a..49a06075be 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRepository.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRepository.groovy @@ -15,16 +15,23 @@ import org.codehaus.groovy.control.CompilerConfiguration class StubRepository { private final File path + final List projectDescriptors + final Collection accurestContracts StubRepository(File repository) { if (!repository.isDirectory()) { - throw new FileNotFoundException('Missing descriptor repository') + throw new FileNotFoundException("Missing descriptor repository under path [$path]") } this.path = repository + this.projectDescriptors = projectDescriptors() + this.accurestContracts = accurestContracts() } - Collection getAccurestContracts() { - List contracts = [] + /** + * Returns a list of {@link GroovyDsl} + */ + private Collection accurestContracts() { + List contracts = [] contracts.addAll(accurestDescriptors()) return contracts } @@ -32,7 +39,7 @@ class StubRepository { /** * Returns the list of WireMock JSON files wrapped in {@link WiremockMappingDescriptor} */ - List getProjectDescriptors() { + private List projectDescriptors() { List mappingDescriptors = [] mappingDescriptors.addAll(contextDescriptors()) return mappingDescriptors @@ -52,18 +59,17 @@ class StubRepository { return mappingDescriptors } - private Collection accurestDescriptors() { + private Collection accurestDescriptors() { return path.exists() ? collectAccurestDescriptors(path) : [] } - private Collection collectAccurestDescriptors(File descriptorsDirectory) { - List mappingDescriptors = [] + private Collection collectAccurestDescriptors(File descriptorsDirectory) { + List mappingDescriptors = [] descriptorsDirectory.eachFileRecurse { File file -> if (isAccurestDescriptor(file)) { try { - mappingDescriptors << new GroovyDslWrapper( + mappingDescriptors << ((new GroovyShell(delegate.class.classLoader, new Binding(), new CompilerConfiguration(sourceEncoding:'UTF-8')).evaluate(file)) as GroovyDsl) - ) } catch (Exception e) { log.warn("Exception occurred while trying to parse file [$file]", e) } diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunner.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunner.groovy index 496e1d49a3..839b12c401 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunner.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunner.groovy @@ -2,6 +2,10 @@ package io.codearte.accurest.stubrunner import groovy.transform.CompileStatic import groovy.util.logging.Slf4j +import io.codearte.accurest.dsl.GroovyDsl +import io.codearte.accurest.messaging.AccurestMessaging +import io.codearte.accurest.messaging.noop.NoOpAccurestMessaging + /** * Represents a single instance of ready-to-run stubs. * Can run the stubs and then will return the name of the collaborator together with @@ -16,28 +20,34 @@ class StubRunner implements StubRunning { private final StubRepository stubRepository private final StubConfiguration stubsConfiguration private final StubRunnerOptions stubRunnerOptions - private StubRunnerExecutor localStubRunner + private final StubRunnerExecutor localStubRunner + private final AccurestMessaging accurestMessaging @Deprecated StubRunner(Arguments arguments) { - stubsConfiguration = arguments.stub - stubRunnerOptions = arguments.stubRunnerOptions + this.stubsConfiguration = arguments.stub + this.stubRunnerOptions = arguments.stubRunnerOptions this.stubRepository = new StubRepository(new File(arguments.repositoryPath)) + AvailablePortScanner portScanner = new AvailablePortScanner(stubRunnerOptions.minPortValue, + stubRunnerOptions.maxPortValue) + this.accurestMessaging = new NoOpAccurestMessaging() + this.localStubRunner = new StubRunnerExecutor(portScanner, accurestMessaging) } - StubRunner(StubRunnerOptions stubRunnerOptions, String repositoryPath, StubConfiguration stubsConfiguration) { + StubRunner(StubRunnerOptions stubRunnerOptions, String repositoryPath, StubConfiguration stubsConfiguration, + AccurestMessaging accurestMessaging) { this.stubsConfiguration = stubsConfiguration this.stubRunnerOptions = stubRunnerOptions this.stubRepository = new StubRepository(new File(repositoryPath)) + AvailablePortScanner portScanner = new AvailablePortScanner(stubRunnerOptions.minPortValue, + stubRunnerOptions.maxPortValue) + this.accurestMessaging = accurestMessaging + this.localStubRunner = new StubRunnerExecutor(portScanner, accurestMessaging) } @Override RunningStubs runStubs() { - AvailablePortScanner portScanner = new AvailablePortScanner(stubRunnerOptions.minPortValue, - stubRunnerOptions.maxPortValue) - localStubRunner = new StubRunnerExecutor(portScanner) registerShutdownHook() - return localStubRunner.runStubs(stubRepository, stubsConfiguration) } @@ -50,7 +60,8 @@ class StubRunner implements StubRunning { URL findStubUrl(String ivyNotation) { String[] splitString = ivyNotation.split(":") if (splitString.length == 1) { - throw new IllegalArgumentException("$ivyNotation is invalid") + // assuming that ivy notation represents artifactId only + return findStubUrl(null, splitString[0]) } return findStubUrl(splitString[0], splitString[1]) } @@ -60,6 +71,26 @@ class StubRunner implements StubRunning { return localStubRunner.findAllRunningStubs() } + @Override + Map> getAccurestContracts() { + return localStubRunner.getAccurestContracts() + } + + @Override + void trigger(String ivyNotation, String labelName) { + localStubRunner.trigger(ivyNotation, labelName) + } + + @Override + void trigger(String labelName) { + localStubRunner.trigger(labelName) + } + + @Override + void trigger() { + localStubRunner.trigger() + } + private void registerShutdownHook() { Runnable stopAllServers = { this.close() } Runtime.runtime.addShutdownHook(new Thread(stopAllServers)) diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerExecutor.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerExecutor.groovy index 67a1b40fee..98f18aab2f 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerExecutor.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerExecutor.groovy @@ -2,6 +2,11 @@ package io.codearte.accurest.stubrunner import groovy.transform.CompileStatic import groovy.util.logging.Slf4j +import io.codearte.accurest.dsl.GroovyDsl +import io.codearte.accurest.messaging.AccurestMessage +import io.codearte.accurest.messaging.AccurestMessaging +import io.codearte.accurest.messaging.noop.NoOpAccurestMessaging + /** * Runs stubs for a particular {@link StubServer} */ @@ -10,10 +15,17 @@ import groovy.util.logging.Slf4j class StubRunnerExecutor implements StubFinder { private final AvailablePortScanner portScanner + private final AccurestMessaging accurestMessaging private StubServer stubServer + StubRunnerExecutor(AvailablePortScanner portScanner, AccurestMessaging accurestMessaging) { + this.portScanner = portScanner + this.accurestMessaging = accurestMessaging + } + StubRunnerExecutor(AvailablePortScanner portScanner) { this.portScanner = portScanner + this.accurestMessaging = new NoOpAccurestMessaging() } RunningStubs runStubs(StubRepository repository, StubConfiguration stubConfiguration) { @@ -30,7 +42,7 @@ class StubRunnerExecutor implements StubFinder { @Override URL findStubUrl(String groupId, String artifactId) { - if(!groupId) { + if (!groupId) { return returnStubUrlIfMatches(stubServer.stubConfiguration.artifactId == artifactId) } return returnStubUrlIfMatches(stubServer.stubConfiguration.artifactId == artifactId && @@ -51,13 +63,53 @@ class StubRunnerExecutor implements StubFinder { return new RunningStubs([(stubServer.stubConfiguration) : stubServer.port]) } + @Override + Map> getAccurestContracts() { + return [(stubServer.stubConfiguration): stubServer.contracts] + } + + @Override + void trigger(String ivyNotationAsString, String labelName) { + Collection matchingContracts = getAccurestContracts().findAll { + it.key.matches(ivyNotationAsString) + }.values().flatten() as Collection + triggerForDsls(matchingContracts, labelName) + } + + @Override + void trigger(String labelName) { + triggerForDsls(getAccurestContracts().values().flatten() as Collection, labelName) + } + + private void triggerForDsls(Collection dsls, String labelName) { + dsls.findAll { it.label == labelName}.each { + sendMessageIfApplicable(it) + } + } + + @Override + void trigger() { + (getAccurestContracts().values().flatten() as Collection).each { GroovyDsl groovyDsl -> + sendMessageIfApplicable(groovyDsl) + } + } + + private void sendMessageIfApplicable(GroovyDsl groovyDsl) { + if (!groovyDsl.outputMessage) { + return + } + AccurestMessage message = accurestMessaging.create(groovyDsl.outputMessage.body.clientValue, + groovyDsl.outputMessage.headers.asStubSideMap()) + accurestMessaging.send(message, groovyDsl.outputMessage.sentTo) + } + private URL returnStubUrlIfMatches(boolean condition) { return condition ? stubServer.stubUrl : null } private void startStubServers(StubConfiguration stubConfiguration, StubRepository repository) { List mappings = repository.getProjectDescriptors() - Collection contracts = repository.accurestContracts + Collection contracts = repository.accurestContracts stubServer = portScanner.tryToExecuteWithFreePort { int availablePort -> return new StubServer(availablePort, stubConfiguration, mappings, contracts).start() } diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerFactory.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerFactory.groovy index 9ea6992988..9a969213bf 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerFactory.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerFactory.groovy @@ -1,9 +1,8 @@ package io.codearte.accurest.stubrunner import groovy.transform.CompileStatic -import groovy.transform.PackageScope import groovy.util.logging.Slf4j - +import io.codearte.accurest.messaging.AccurestMessaging /** * Factory of StubRunners. Basing on the options and passed collaborators * downloads the stubs and returns a list of corresponding stub runners. @@ -15,13 +14,15 @@ class StubRunnerFactory { private final StubRunnerOptions stubRunnerOptions private final Collection collaborators private final StubDownloader stubDownloader + private final AccurestMessaging accurestMessaging StubRunnerFactory(StubRunnerOptions stubRunnerOptions, Collection collaborators, - StubDownloader stubDownloader) { + StubDownloader stubDownloader, AccurestMessaging accurestMessaging) { this.stubRunnerOptions = stubRunnerOptions this.collaborators = collaborators this.stubDownloader = stubDownloader + this.accurestMessaging = accurestMessaging } Collection createStubsFromServiceConfiguration() { @@ -42,7 +43,7 @@ class StubRunnerFactory { private StubRunner createStubRunner(File unzippedStubsDir, StubConfiguration stubsConfiguration, StubRunnerOptions stubRunnerOptions) { - return new StubRunner(stubRunnerOptions, unzippedStubsDir.path, stubsConfiguration) + return new StubRunner(stubRunnerOptions, unzippedStubsDir.path, stubsConfiguration, accurestMessaging) } } diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerMessagingTrigger.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerMessagingTrigger.groovy new file mode 100644 index 0000000000..0fd2ef1c8a --- /dev/null +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubRunnerMessagingTrigger.groovy @@ -0,0 +1,18 @@ +package io.codearte.accurest.stubrunner + +import groovy.transform.PackageScope +import io.codearte.accurest.messaging.AccurestMessaging +/** + * @author Marcin Grzejszczak + */ +@PackageScope +class StubRunnerMessagingTrigger { + + private final AccurestMessaging accurestMessaging + + StubRunnerMessagingTrigger(AccurestMessaging accurestMessaging) { + this.accurestMessaging = accurestMessaging + } + + void trigger +} diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubServer.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubServer.groovy index 8fb22a1dd0..62e5cc5952 100644 --- a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubServer.groovy +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubServer.groovy @@ -6,6 +6,7 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration import groovy.transform.CompileStatic import groovy.transform.PackageScope import groovy.util.logging.Slf4j +import io.codearte.accurest.dsl.GroovyDsl @CompileStatic @Slf4j @@ -14,10 +15,10 @@ class StubServer { private WireMockServer wireMockServer final StubConfiguration stubConfiguration final Collection mappings - final Collection contracts + final Collection contracts StubServer(int port, StubConfiguration stubConfiguration, Collection mappings, - Collection contracts) { + Collection contracts) { this.stubConfiguration = stubConfiguration this.mappings = mappings this.wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(port)) diff --git a/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubTriggerer.groovy b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubTriggerer.groovy new file mode 100644 index 0000000000..99090b8bdc --- /dev/null +++ b/stub-runner/stub-runner/src/main/groovy/io/codearte/accurest/stubrunner/StubTriggerer.groovy @@ -0,0 +1,25 @@ +package io.codearte.accurest.stubrunner + +interface StubTriggerer { + + /** + * Triggers an event by a given label for a given {@code groupid:artifactid} notation. You can use only {@code artifactId} too. + * + * Feature related to messaging. + */ + void trigger(String ivyNotation, String labelName) + + /** + * Triggers an event by a given label. + * + * Feature related to messaging. + */ + void trigger(String labelName) + + /** + * Triggers all possible events. + * + * Feature related to messaging. + */ + void trigger() +} \ No newline at end of file diff --git a/stub-runner/stub-runner/src/test/groovy/io/codearte/accurest/stubrunner/StubRunnerFactorySpec.groovy b/stub-runner/stub-runner/src/test/groovy/io/codearte/accurest/stubrunner/StubRunnerFactorySpec.groovy index 2baa98ea68..0d368096bb 100644 --- a/stub-runner/stub-runner/src/test/groovy/io/codearte/accurest/stubrunner/StubRunnerFactorySpec.groovy +++ b/stub-runner/stub-runner/src/test/groovy/io/codearte/accurest/stubrunner/StubRunnerFactorySpec.groovy @@ -1,5 +1,6 @@ package io.codearte.accurest.stubrunner +import io.codearte.accurest.messaging.noop.NoOpAccurestMessaging import org.junit.Rule import org.junit.rules.TemporaryFolder import spock.lang.Specification @@ -12,7 +13,7 @@ class StubRunnerFactorySpec extends Specification { Collection collaborators = [new StubConfiguration("a:b"), new StubConfiguration("c:d")] StubDownloader downloader = Mock(StubDownloader) StubRunnerOptions stubRunnerOptions = new StubRunnerOptions(stubRepositoryRoot: 'http://sth.net') - StubRunnerFactory factory = new StubRunnerFactory(stubRunnerOptions, collaborators, downloader) + StubRunnerFactory factory = new StubRunnerFactory(stubRunnerOptions, collaborators, downloader, new NoOpAccurestMessaging()) def "Should download stub definitions many times"() { given: