Merge branch '1.0.x'
This commit is contained in:
@@ -111,7 +111,7 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
method 'PUT' // (2)
|
||||
url '/fraudcheck' // (3)
|
||||
body([ // (4)
|
||||
clientId: $(regex('[0-9]{10}')),
|
||||
"client.id": $(regex('[0-9]{10}')),
|
||||
loanAmount: 99999
|
||||
])
|
||||
headers { // (5)
|
||||
@@ -122,7 +122,7 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
status 200 // (7)
|
||||
body([ // (8)
|
||||
fraudCheckStatus: "FRAUD",
|
||||
rejectionReason: "Amount too high"
|
||||
"rejection.reason": "Amount too high"
|
||||
])
|
||||
headers { // (9)
|
||||
contentType('application/json')
|
||||
@@ -381,7 +381,7 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
method 'PUT' // (2)
|
||||
url '/fraudcheck' // (3)
|
||||
body([ // (4)
|
||||
clientId: $(regex('[0-9]{10}')),
|
||||
"client.id": $(regex('[0-9]{10}')),
|
||||
loanAmount: 99999
|
||||
])
|
||||
headers { // (5)
|
||||
@@ -392,7 +392,7 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
status 200 // (7)
|
||||
body([ // (8)
|
||||
fraudCheckStatus: "FRAUD",
|
||||
rejectionReason: "Amount too high"
|
||||
"rejection.reason": "Amount too high"
|
||||
])
|
||||
headers { // (9)
|
||||
contentType('application/json')
|
||||
|
||||
@@ -100,6 +100,7 @@ After that rule gets executed Stub Runner connects to your Maven repository and
|
||||
- unzip them to a temporary folder
|
||||
- start a WireMock server for each Maven dependency on a random port from the provided range of ports / provided port
|
||||
- feed the WireMock server with all JSON files that are valid WireMock definitions
|
||||
- can also send messages (remember to pass an implementation of `MessageVerifier` interface)
|
||||
|
||||
Stub Runner uses https://wiki.eclipse.org/Aether[Eclipse Aether] mechanism to download the Maven dependencies.
|
||||
Check their https://wiki.eclipse.org/Aether[docs] for more information.
|
||||
@@ -127,6 +128,10 @@ include::src/test/groovy/org/springframework/cloud/contract/stubrunner/junit/Stu
|
||||
|
||||
Check the *Common properties for JUnit and Spring* for more information on how to apply global configuration of Stub Runner.
|
||||
|
||||
IMPORTANT: To use the JUnit rule together with messaging you have to provide an implementation of the
|
||||
`MessageVerifier` interface to the rule builder (e.g. `rule.messageVerifier(new MyMessageVerifier())`).
|
||||
If you don't do this then whenever you try to send a message an exception will be thrown.
|
||||
|
||||
==== Maven settings
|
||||
|
||||
The stub downloader honors Maven settings for a different local repository folder.
|
||||
|
||||
@@ -32,7 +32,11 @@ public class BatchStubRunnerFactory {
|
||||
private final MessageVerifier<?> contractVerifierMessaging;
|
||||
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions) {
|
||||
this(stubRunnerOptions, aetherStubDownloader(stubRunnerOptions), new NoOpStubMessages());
|
||||
this(stubRunnerOptions, new NoOpStubMessages());
|
||||
}
|
||||
|
||||
public BatchStubRunnerFactory(StubRunnerOptions stubRunnerOptions, MessageVerifier verifier) {
|
||||
this(stubRunnerOptions, aetherStubDownloader(stubRunnerOptions), verifier);
|
||||
}
|
||||
|
||||
private static StubDownloader aetherStubDownloader(StubRunnerOptions stubRunnerOptions) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.contract.stubrunner;
|
||||
|
||||
import groovy.json.JsonOutput;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
@@ -38,8 +40,6 @@ import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages;
|
||||
import org.springframework.cloud.contract.verifier.util.BodyExtractor;
|
||||
|
||||
import groovy.json.JsonOutput;
|
||||
|
||||
/**
|
||||
* Runs stubs for a particular {@link StubServer}
|
||||
*/
|
||||
@@ -173,7 +173,7 @@ class StubRunnerExecutor implements StubFinder {
|
||||
private boolean triggerForDsls(Collection<Contract> dsls, String labelName) {
|
||||
Collection<Contract> matchingDsls = new ArrayList<>();
|
||||
for (Contract contract : dsls) {
|
||||
if (labelName.equals(contract.getLabel())) {
|
||||
if (labelName.equals(contract.getLabel()) && contract.getOutputMessage() != null) {
|
||||
matchingDsls.add(contract);
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ class StubRunnerExecutor implements StubFinder {
|
||||
return false;
|
||||
}
|
||||
for (Contract contract : matchingDsls) {
|
||||
sendMessageIfApplicable(contract);
|
||||
sendMessage(contract);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -190,10 +190,17 @@ class StubRunnerExecutor implements StubFinder {
|
||||
public boolean trigger() {
|
||||
Collection<Contract> matchingContracts = new ArrayList<>();
|
||||
for (Collection<Contract> it : getContracts().values()) {
|
||||
matchingContracts.addAll(it);
|
||||
for (Contract contract : it) {
|
||||
if (contract.getOutputMessage() != null) {
|
||||
matchingContracts.add(contract);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchingContracts.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (Contract contract : matchingContracts) {
|
||||
sendMessageIfApplicable(contract);
|
||||
sendMessage(contract);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -213,11 +220,8 @@ class StubRunnerExecutor implements StubFinder {
|
||||
return labels;
|
||||
}
|
||||
|
||||
private void sendMessageIfApplicable(Contract groovyDsl) {
|
||||
private void sendMessage(Contract groovyDsl) {
|
||||
OutputMessage outputMessage = groovyDsl.getOutputMessage();
|
||||
if (outputMessage == null) {
|
||||
return;
|
||||
}
|
||||
DslProperty<?> body = outputMessage.getBody();
|
||||
Headers headers = outputMessage.getHeaders();
|
||||
this.contractVerifierMessaging.send(
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
|
||||
/**
|
||||
* JUnit class rule that allows you to download the provided stubs.
|
||||
@@ -45,6 +47,7 @@ public class StubRunnerRule implements TestRule, StubFinder {
|
||||
|
||||
private final StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder(defaultStubRunnerOptions());
|
||||
private BatchStubRunner stubFinder;
|
||||
private MessageVerifier verifier = new ExceptionThrowingMessageVerifier();
|
||||
|
||||
@Override
|
||||
public Statement apply(final Statement base, Description description) {
|
||||
@@ -58,7 +61,8 @@ public class StubRunnerRule implements TestRule, StubFinder {
|
||||
|
||||
private void before() {
|
||||
StubRunnerRule.this.stubFinder = new BatchStubRunnerFactory(
|
||||
StubRunnerRule.this.stubRunnerOptionsBuilder.build()).buildBatchStubRunner();
|
||||
StubRunnerRule.this.stubRunnerOptionsBuilder.build(),
|
||||
StubRunnerRule.this.verifier).buildBatchStubRunner();
|
||||
StubRunnerRule.this.stubFinder.runStubs();
|
||||
}
|
||||
};
|
||||
@@ -81,6 +85,16 @@ public class StubRunnerRule implements TestRule, StubFinder {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the {@link MessageVerifier} that this rule should use.
|
||||
* If you don't pass anything a {@link ExceptionThrowingMessageVerifier} will be used.
|
||||
* That means that an exception will be thrown whenever you try to do sth messaging related.
|
||||
*/
|
||||
public StubRunnerRule messageVerifier(MessageVerifier messageVerifier) {
|
||||
this.verifier = messageVerifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override all options
|
||||
*
|
||||
@@ -209,17 +223,29 @@ public class StubRunnerRule implements TestRule, StubFinder {
|
||||
|
||||
@Override
|
||||
public boolean trigger(String ivyNotation, String labelName) {
|
||||
return this.stubFinder.trigger(ivyNotation, labelName);
|
||||
boolean result = this.stubFinder.trigger(ivyNotation, labelName);
|
||||
if (!result) {
|
||||
throw new IllegalStateException("Failed to trigger a message with notation [" + ivyNotation + "] and label [" + labelName + "]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trigger(String labelName) {
|
||||
return this.stubFinder.trigger(labelName);
|
||||
boolean result = this.stubFinder.trigger(labelName);
|
||||
if (!result) {
|
||||
throw new IllegalStateException("Failed to trigger a message with label [" + labelName + "]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trigger() {
|
||||
return this.stubFinder.trigger();
|
||||
boolean result = this.stubFinder.trigger();
|
||||
if (!result) {
|
||||
throw new IllegalStateException("Failed to trigger a message");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,4 +253,27 @@ public class StubRunnerRule implements TestRule, StubFinder {
|
||||
return this.stubFinder.labels();
|
||||
}
|
||||
|
||||
|
||||
static class ExceptionThrowingMessageVerifier implements MessageVerifier {
|
||||
|
||||
private static final String EXCEPTION_MESSAGE = "Please provide a custom MessageVerifier to use this feature";
|
||||
|
||||
@Override public void send(Object message, String destination) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@Override public Object receive(String destination, long timeout,
|
||||
TimeUnit timeUnit) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@Override public Object receive(String destination) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
@Override public void send(Object payload, Map headers, String destination) {
|
||||
throw new UnsupportedOperationException(EXCEPTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -116,6 +116,21 @@ class StubRunnerExecutorSpec extends Specification {
|
||||
executor.shutdown()
|
||||
}
|
||||
|
||||
def 'should return false if no messages are found'() {
|
||||
given:
|
||||
def stubConf = new StubConfiguration('asd', 'asd', 'asd', '')
|
||||
StubRunnerExecutor executor = new StubRunnerExecutor(portScanner)
|
||||
when:
|
||||
executor.runStubs(stubRunnerOptions,
|
||||
new StubRepository(new File('src/test/resources/repository/httpcontract')), stubConf)
|
||||
then:
|
||||
!executor.trigger()
|
||||
!executor.trigger("missing", "label")
|
||||
!executor.trigger("label")
|
||||
cleanup:
|
||||
executor.shutdown()
|
||||
}
|
||||
|
||||
Map<StubConfiguration, Integer> stubIdsWithPortsFromString(String stubIdsToPortMapping) {
|
||||
return stubIdsToPortMapping.split(',').collectEntries { String entry ->
|
||||
return StubsParser.fromStringWithPort(entry)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.junit
|
||||
|
||||
import org.junit.AfterClass
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.ClassRule
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubRunnerRuleCustomMsgVerifierSpec extends Specification {
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
void setupProps() {
|
||||
System.clearProperty("stubrunner.repository.root")
|
||||
System.clearProperty("stubrunner.classifier")
|
||||
}
|
||||
|
||||
@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
|
||||
.repoRoot(StubRunnerRuleCustomMsgVerifierSpec.getResource("/m2repo/repository").toURI().toString())
|
||||
.downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService")
|
||||
.messageVerifier(new MyMessageVerifier())
|
||||
|
||||
def 'should use the provided message verifier in the junit rule'() {
|
||||
when:
|
||||
rule.trigger()
|
||||
then:
|
||||
IllegalStateException e = thrown(IllegalStateException)
|
||||
e.message.contains("Failed to send a message with headers")
|
||||
when:
|
||||
rule.trigger("return_book_1")
|
||||
then:
|
||||
e = thrown(IllegalStateException)
|
||||
e.message.contains("Failed to send a message with headers")
|
||||
when:
|
||||
rule.trigger("bootService", "return_book_1")
|
||||
then:
|
||||
e = thrown(IllegalStateException)
|
||||
e.message.contains("Failed to send a message with headers")
|
||||
}
|
||||
|
||||
static class MyMessageVerifier implements MessageVerifier {
|
||||
|
||||
@Override
|
||||
void send(Object message, String destination) {
|
||||
throw new IllegalStateException("Failed to send a message")
|
||||
}
|
||||
|
||||
@Override
|
||||
Object receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
throw new IllegalStateException("Failed to receive a message with timeout")
|
||||
}
|
||||
|
||||
@Override
|
||||
Object receive(String destination) {
|
||||
throw new IllegalStateException("Failed to receive a message")
|
||||
}
|
||||
|
||||
@Override
|
||||
void send(Object payload, Map headers, String destination) {
|
||||
throw new IllegalStateException("Failed to send a message with headers")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.junit
|
||||
|
||||
import org.junit.AfterClass
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.ClassRule
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubRunnerRuleExceptionThrowingSpec extends Specification {
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
void setupProps() {
|
||||
System.clearProperty("stubrunner.repository.root")
|
||||
System.clearProperty("stubrunner.classifier")
|
||||
}
|
||||
|
||||
@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
|
||||
.repoRoot(StubRunnerRuleExceptionThrowingSpec.getResource("/m2repo/repository").toURI().toString())
|
||||
.downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService")
|
||||
|
||||
def 'should throw exception when no message verifier was passed and message related method was triggered'() {
|
||||
when:
|
||||
rule.trigger()
|
||||
then:
|
||||
thrown(UnsupportedOperationException)
|
||||
when:
|
||||
rule.trigger("return_book_1")
|
||||
then:
|
||||
thrown(UnsupportedOperationException)
|
||||
when:
|
||||
rule.trigger("bootService", "return_book_1")
|
||||
then:
|
||||
thrown(UnsupportedOperationException)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
org.springframework.cloud.contract.spec.Contract.make {
|
||||
request {
|
||||
method """PUT"""
|
||||
url """/fraudcheck"""
|
||||
body("""
|
||||
{
|
||||
"clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}",
|
||||
"loanAmount":99999}
|
||||
"""
|
||||
)
|
||||
headers {
|
||||
contentType("application/vnd.fraud.v1+json")
|
||||
}
|
||||
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
body( """{
|
||||
"fraudCheckStatus": "${value(c('FRAUD'), p(regex('[A-Z]{5}')))}",
|
||||
"rejectionReason": "Amount too high"
|
||||
}""")
|
||||
headers {
|
||||
contentType("application/vnd.fraud.v1+json")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user