diff --git a/docs/src/main/asciidoc/verifier_faq.adoc b/docs/src/main/asciidoc/verifier_faq.adoc
index 4640f8b32c..3c4d7ee7e6 100644
--- a/docs/src/main/asciidoc/verifier_faq.adoc
+++ b/docs/src/main/asciidoc/verifier_faq.adoc
@@ -634,7 +634,7 @@ In order to do that, use the usual producer setup, and then add the `pushStubsTo
On the consumer side when passing the `repositoryRoot` parameter,
either from the `@AutoConfigureStubRunner` annotation, the
-JUnit rule or properties, it's enough to pass the URL of the
+JUnit rule, JUnit 5 extension or properties, it's enough to pass the URL of the
SCM repository, prefixed with the protocol. For example
[source,java,indent=0]
@@ -868,9 +868,9 @@ logging.level.com.github.tomakehurst.wiremock=ERROR
==== How can I see what got registered in the HTTP server stub?
-You can use the `mappingsOutputFolder` property on `@AutoConfigureStubRunner` or `StubRunnerRule`
-to dump all mappings per artifact id. Also the port at which the given stub server was
-started will be attached.
+You can use the `mappingsOutputFolder` property on `@AutoConfigureStubRunner`, `StubRunnerRule` or
+`StubRunnerExtension`to dump all mappings per artifact id. Also the port at which the given stub server
+was started will be attached.
==== Can I reference text from file?
diff --git a/spring-cloud-contract-stub-runner/README.adoc b/spring-cloud-contract-stub-runner/README.adoc
index c2b1b3fe70..b67974ab42 100644
--- a/spring-cloud-contract-stub-runner/README.adoc
+++ b/spring-cloud-contract-stub-runner/README.adoc
@@ -267,7 +267,7 @@ mappings available for the given server:
Depending on the provided Stub Runner dependency and the DSL the messaging routes are automatically set up.
-=== Stub Runner JUnit Rule
+=== Stub Runner JUnit Rule and Stub Runner JUnit5 Extension
Stub Runner comes with a JUnit rule thanks to which you can very easily download and run stubs for given group and artifact id:
@@ -276,7 +276,8 @@ Stub Runner comes with a JUnit rule thanks to which you can very easily download
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleJUnitTest.java[tags=classrule]
----
-After that rule gets executed Stub Runner connects to your Maven repository and for the given list of dependencies tries to:
+There's also a `StubRunnerExtension` available for JUnit 5. `StubRunnerRule` and `StubRunnerExtension` work in a very
+similar fashion. After the rule/ extension is executed, Stub Runner connects to your Maven repository and for the given list of dependencies tries to:
- download them
- cache them locally
@@ -288,7 +289,7 @@ After that rule gets executed Stub Runner connects to your Maven repository and
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.
-Since the `StubRunnerRule` implements the `StubFinder` it allows you to find the started stubs:
+Since the `StubRunnerRule` and `StubRunnerExtension` implement the `StubFinder` they allow you to find the started stubs:
[source,groovy,indent=0]
----
@@ -309,11 +310,18 @@ Example of usage in JUnit tests:
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleJUnitTest.java[tags=test]
----
+JUnit 5 Extension example:
+
+[source,java,indent=0]
+----
+include::src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java[tags=extension]
+----
+
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
+IMPORTANT: To use the JUnit rule or JUnit 5 extension 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.
+If you don't do this, then whenever you try to send a message an exception will be thrown.
==== Maven settings
@@ -327,7 +335,7 @@ JUnit rule.
==== Fluent API
-When using the `StubRunnerRule` you can add a stub to download and then pass the port for the last downloaded stub.
+When using the `StubRunnerRule` or `StubRunnerExtension` you can add a stub to download and then pass the port for the last downloaded stub.
[source,java,indent=0]
----
diff --git a/spring-cloud-contract-stub-runner/pom.xml b/spring-cloud-contract-stub-runner/pom.xml
index bb4af4fa08..7f0f2e2aaa 100644
--- a/spring-cloud-contract-stub-runner/pom.xml
+++ b/spring-cloud-contract-stub-runner/pom.xml
@@ -153,6 +153,14 @@
spring-cloud-starter-consul-discovery
true
+
+ org.junit.jupiter
+ junit-jupiter-engine
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java
new file mode 100644
index 0000000000..3724f595b1
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/ExceptionThrowingMessageVerifier.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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.springframework.cloud.contract.verifier.messaging.MessageVerifier;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+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);
+ }
+
+}
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java
new file mode 100644
index 0000000000..aece0f3369
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/PortStubRunnerExtensionOptions.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 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;
+
+/**
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+interface PortStubRunnerExtensionOptions {
+
+ StubRunnerExtension withPort(Integer port);
+}
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java
new file mode 100644
index 0000000000..0773d10e42
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2018 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.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.springframework.cloud.contract.spec.Contract;
+import org.springframework.cloud.contract.stubrunner.BatchStubRunner;
+import org.springframework.cloud.contract.stubrunner.BatchStubRunnerFactory;
+import org.springframework.cloud.contract.stubrunner.RunningStubs;
+import org.springframework.cloud.contract.stubrunner.StubConfiguration;
+import org.springframework.cloud.contract.stubrunner.StubFinder;
+import org.springframework.cloud.contract.stubrunner.StubNotFoundException;
+import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
+import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
+import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
+import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * JUnit 5 extension that allows to download and run stubs.
+ *
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+public class StubRunnerExtension implements BeforeAllCallback, AfterAllCallback, StubFinder, StubRunnerExtensionOptions {
+
+ private static final String DELIMITER = ":";
+ private static final String LATEST_VERSION = "+";
+ private static final Log LOG = LogFactory.getLog(StubRunnerExtension.class);
+
+ StubRunnerExtension delegate = this;
+ private BatchStubRunner stubFinder;
+ private StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder(
+ StubRunnerOptions.fromSystemProps());
+ private MessageVerifier verifier = new ExceptionThrowingMessageVerifier();
+
+ public StubRunnerExtension() {
+ }
+
+ StubRunnerExtension(StubRunnerExtension delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void beforeAll(ExtensionContext extensionContext) {
+ stubFinder(new BatchStubRunnerFactory(builder().build(), verifier()).buildBatchStubRunner());
+ stubFinder().runStubs();
+ }
+
+ @Override
+ public void afterAll(ExtensionContext extensionContext) {
+ try {
+ stubFinder().close();
+ } catch (IOException exception) {
+ LOG.warn(exception.getMessage(), exception);
+ }
+ }
+
+ @Override
+ public URL findStubUrl(String groupId, String artifactId) throws StubNotFoundException {
+ return stubFinder().findStubUrl(groupId, artifactId);
+ }
+
+ @Override
+ public URL findStubUrl(String ivyNotation) throws StubNotFoundException {
+ return stubFinder().findStubUrl(ivyNotation);
+ }
+
+ @Override
+ public RunningStubs findAllRunningStubs() {
+ return stubFinder().findAllRunningStubs();
+ }
+
+ @Override
+ public Map> getContracts() {
+ return stubFinder().getContracts();
+ }
+
+ @Override
+ public boolean trigger(String ivyNotation, String labelName) {
+ boolean result = 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) {
+ boolean result = stubFinder().trigger(labelName);
+ if (!result) {
+ throw new IllegalStateException(
+ "Failed to trigger a message with label [" + labelName + "]");
+ }
+ return result;
+ }
+
+ @Override
+ public boolean trigger() {
+ boolean result = stubFinder().trigger();
+ if (!result) {
+ throw new IllegalStateException("Failed to trigger a message");
+ }
+ return result;
+ }
+
+ @Override
+ public Map> labels() {
+ return stubFinder().labels();
+ }
+
+ @Override
+ public StubRunnerExtension messageVerifier(MessageVerifier messageVerifier) {
+ verifier(messageVerifier);
+ return delegate;
+ }
+
+ @Override
+ public StubRunnerExtension options(StubRunnerOptions stubRunnerOptions) {
+ builder().withOptions(stubRunnerOptions);
+ return delegate;
+ }
+
+ @Override
+ public StubRunnerExtension minPort(int minPort) {
+ builder().withMinPort(minPort);
+ return delegate;
+ }
+
+ @Override
+ public StubRunnerExtension maxPort(int maxPort) {
+ builder().withMaxPort(maxPort);
+ return delegate;
+ }
+
+ @Override
+ public StubRunnerExtension repoRoot(String repoRoot) {
+ builder().withStubRepositoryRoot(repoRoot);
+ return delegate;
+ }
+
+ @Override
+ public StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode) {
+ builder().withStubsMode(stubsMode);
+ return delegate;
+ }
+
+ @Override
+ public PortStubRunnerExtension downloadStub(String groupId, String artifactId, String version, String classifier) {
+ builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version
+ + DELIMITER + classifier);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public PortStubRunnerExtension downloadLatestStub(String groupId, String artifactId, String classifier) {
+ builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + LATEST_VERSION
+ + DELIMITER + classifier);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public PortStubRunnerExtension downloadStub(String groupId, String artifactId, String version) {
+ builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public PortStubRunnerExtension downloadStub(String groupId, String artifactId) {
+ builder().withStubs(groupId + DELIMITER + artifactId);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public PortStubRunnerExtension downloadStub(String ivyNotation) {
+ builder().withStubs(ivyNotation);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension downloadStubs(String... ivyNotations) {
+ builder().withStubs(Arrays.asList(ivyNotations));
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension downloadStubs(List ivyNotations) {
+ builder().withStubs(ivyNotations);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer) {
+ builder().withStubPerConsumer(stubPerConsumer);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension withConsumerName(String consumerName) {
+ builder().withConsumerName(consumerName);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder) {
+ builder().withMappingsOutputFolder(mappingsOutputFolder);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension withDeleteStubsAfterTest(boolean deleteStubsAfterTest) {
+ builder().withDeleteStubsAfterTest(deleteStubsAfterTest);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension withProperties(Map properties) {
+ builder().withProperties(properties);
+ return new PortStubRunnerExtension(delegate);
+ }
+
+ BatchStubRunner stubFinder() {
+ return this.delegate.stubFinder;
+ }
+
+ void stubFinder(BatchStubRunner stubFinder) {
+ this.delegate.stubFinder = stubFinder;
+ }
+
+ StubRunnerOptionsBuilder builder() {
+ return delegate.stubRunnerOptionsBuilder;
+ }
+
+ MessageVerifier verifier() {
+ return delegate.verifier;
+ }
+
+ void verifier(MessageVerifier verifier) {
+ delegate.verifier = verifier;
+ }
+
+ /**
+ * Helper class with additional port, related methods once you pick a stub to download
+ *
+ * @since 1.2.0
+ */
+ public static class PortStubRunnerExtension extends StubRunnerExtension implements PortStubRunnerExtensionOptions {
+
+ PortStubRunnerExtension(StubRunnerExtension delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public StubRunnerExtension withPort(Integer port) {
+ builder().withPort(port);
+ return delegate;
+ }
+ }
+}
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java
new file mode 100644
index 0000000000..a9ca98d922
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 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.springframework.cloud.contract.stubrunner.StubRunnerOptions;
+import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
+import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+interface StubRunnerExtensionOptions {
+
+ /**
+ * 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.
+ */
+ StubRunnerExtension messageVerifier(MessageVerifier messageVerifier);
+
+ /**
+ * Override all options
+ *
+ * @see StubRunnerOptions
+ */
+ StubRunnerExtension options(StubRunnerOptions stubRunnerOptions);
+
+ /**
+ * Min value of port for WireMock server
+ */
+ StubRunnerExtension minPort(int minPort);
+
+ /**
+ * Max value of port for WireMock server
+ */
+ StubRunnerExtension maxPort(int maxPort);
+
+ /**
+ * String URI of repository containing stubs
+ */
+ StubRunnerExtension repoRoot(String repoRoot);
+
+ /**
+ * Stubs mode that should be used
+ */
+ StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode);
+
+ /**
+ * Group Id, artifact Id, version and classifier of a single stub to download
+ */
+ PortStubRunnerExtensionOptions downloadStub(String groupId, String artifactId,
+ String version, String classifier);
+
+ /**
+ * Group Id, artifact Id and classifier of a single stub to download in the latest
+ * version
+ */
+ PortStubRunnerExtensionOptions downloadLatestStub(String groupId, String artifactId,
+ String classifier);
+
+ /**
+ * Group Id, artifact Id and version of a single stub to download
+ */
+ PortStubRunnerExtensionOptions downloadStub(String groupId, String artifactId,
+ String version);
+
+ /**
+ * Group Id, artifact Id of a single stub to download. Default classifier will be
+ * picked.
+ */
+ PortStubRunnerExtensionOptions downloadStub(String groupId, String artifactId);
+
+ /**
+ * Ivy notation of a single stub to download.
+ */
+ PortStubRunnerExtensionOptions downloadStub(String ivyNotation);
+
+ /**
+ * Stubs to download in Ivy notations
+ */
+ StubRunnerExtension downloadStubs(String... ivyNotations);
+
+ /**
+ * Stubs to download in Ivy notations
+ */
+ StubRunnerExtension downloadStubs(List ivyNotations);
+
+ /**
+ * Allows stub per consumer
+ */
+ StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer);
+
+ /**
+ * Allows setting consumer name
+ */
+ StubRunnerExtension withConsumerName(String consumerName);
+
+ /**
+ * Allows setting the output folder for mappings
+ */
+ StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder);
+
+ /**
+ * If set to {@code false} will NOT delete stubs from a temporary folder after running
+ * tests
+ */
+ StubRunnerExtension withDeleteStubsAfterTest(boolean deleteStubsAfterTest);
+
+ /**
+ * Map of properties that can be passed to custom
+ * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
+ */
+ StubRunnerExtension withProperties(Map properties);
+
+}
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java
index 024590e02e..b5412e4507 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java
@@ -16,13 +16,6 @@
package org.springframework.cloud.contract.stubrunner.junit;
-import java.net.URL;
-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;
import org.junit.runners.model.Statement;
@@ -37,6 +30,12 @@ import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
/**
* JUnit class rule that allows you to download the provided stubs.
*
@@ -269,32 +268,6 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
return this.delegate.stubRunnerOptionsBuilder;
}
- 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);
- }
-
- }
-
/**
* Helper class with additional port, related methods once you pick a stub to download
*
diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java
index f5441e0da9..3eeda394e6 100644
--- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java
+++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java
@@ -1,17 +1,33 @@
-package org.springframework.cloud.contract.stubrunner.junit;
+/*
+ * Copyright 2013-2018 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.
+ */
-import java.util.List;
-import java.util.Map;
+package org.springframework.cloud.contract.stubrunner.junit;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
+import java.util.List;
+import java.util.Map;
+
interface StubRunnerRuleOptions {
/**
* Pass the {@link MessageVerifier} that this rule should use. If you don't pass
- * anything a {@link StubRunnerRule.ExceptionThrowingMessageVerifier} will be used.
+ * anything a {@link ExceptionThrowingMessageVerifier} will be used.
* That means that an exception will be thrown whenever you try to do sth messaging
* related.
*/
@@ -48,20 +64,20 @@ interface StubRunnerRuleOptions {
* Group Id, artifact Id, version and classifier of a single stub to download
*/
PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId,
- String version, String classifier);
+ String version, String classifier);
/**
* Group Id, artifact Id and classifier of a single stub to download in the latest
* version
*/
PortStubRunnerRuleOptions downloadLatestStub(String groupId, String artifactId,
- String classifier);
+ String classifier);
/**
* Group Id, artifact Id and version of a single stub to download
*/
PortStubRunnerRuleOptions downloadStub(String groupId, String artifactId,
- String version);
+ String version);
/**
* Group Id, artifact Id of a single stub to download. Default classifier will be
diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java
new file mode 100644
index 0000000000..34b888f6d5
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomMessageVerifierTests.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2018 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.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
+import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+class StubRunnerJUnit5ExtensionCustomMessageVerifierTests {
+
+ @BeforeAll
+ @AfterAll
+ static void setupProps() {
+ System.clearProperty("stubrunner.repository.root");
+ System.clearProperty("stubrunner.classifier");
+ }
+
+ // Visible for testing
+ @RegisterExtension
+ static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
+ .stubsMode(StubRunnerProperties.StubsMode.REMOTE)
+ .repoRoot(repoRoot())
+ .downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService")
+ .messageVerifier(new MyMessageVerifier());
+
+ @Test
+ void should_use_provided_message_verifier_in_junit5_extension() {
+ IllegalStateException emptyTriggerException = assertThrows(IllegalStateException.class,
+ () -> stubRunnerExtension.trigger());
+ assertThat(emptyTriggerException.getMessage()).contains("Failed to send a message with headers");
+ IllegalStateException wrongLabelException = assertThrows(IllegalStateException.class,
+ () -> stubRunnerExtension.trigger("return_book_1"));
+ assertThat(wrongLabelException.getMessage()).contains("Failed to send a message with headers");
+ IllegalStateException wrongLabelWithIvyNotation = assertThrows(IllegalStateException.class,
+ () -> stubRunnerExtension.trigger("bootService", "return_book_1"));
+ assertThat(wrongLabelWithIvyNotation.getMessage()).contains("Failed to send a message with headers");
+ }
+
+ static class MyMessageVerifier implements MessageVerifier {
+
+ @Override
+ public void send(Object message, String destination) {
+ throw new IllegalStateException("Failed to send a message");
+ }
+
+ @Override
+ public Object receive(String destination, long timeout, TimeUnit timeUnit) {
+ throw new IllegalStateException("Failed to receive a message with timeout");
+ }
+
+ @Override
+ public Object receive(String destination) {
+ throw new IllegalStateException("Failed to receive a message");
+ }
+
+ @Override
+ public void send(Object payload, Map headers, String destination) {
+ throw new IllegalStateException("Failed to send a message with headers");
+ }
+ }
+
+ private static String repoRoot() {
+ try {
+ return StubRunnerRuleCustomPortJUnitTest.class.getResource("/m2repo/repository/").toURI().toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java
new file mode 100644
index 0000000000..3a1b45e8c4
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionCustomPortTests.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 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.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
+import org.springframework.util.StreamUtils;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.Charset;
+
+import static org.assertj.core.api.BDDAssertions.then;
+
+/**
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+class StubRunnerJUnit5ExtensionCustomPortTests {
+
+ @BeforeAll
+ @AfterAll
+ static void setupProps() {
+ System.clearProperty("stubrunner.repository.root");
+ System.clearProperty("stubrunner.classifier");
+ }
+
+ @RegisterExtension
+ static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
+ .repoRoot(repoRoot())
+ .stubsMode(StubRunnerProperties.StubsMode.REMOTE)
+ .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")
+ .withPort(12345)
+ .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:12346");
+
+ @Test
+ void should_start_wiremock_servers() throws Exception {
+ then(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")).isNotNull();
+ then(stubRunnerExtension.findStubUrl("loanIssuance")).isNotNull();
+ then(stubRunnerExtension.findStubUrl("loanIssuance"))
+ .isEqualTo(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance"));
+ then(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull();
+ then(stubRunnerExtension.findAllRunningStubs().isPresent("loanIssuance")).isTrue();
+ then(stubRunnerExtension.findAllRunningStubs()
+ .isPresent("org.springframework.cloud.contract.verifier.stubs", "fraudDetectionServer")).isTrue();
+ then(stubRunnerExtension.findAllRunningStubs()
+ .isPresent("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isTrue();
+ then(httpGet(stubRunnerExtension.findStubUrl("loanIssuance").toString() + "/name")).isEqualTo("loanIssuance");
+ then(httpGet(stubRunnerExtension.findStubUrl("fraudDetectionServer").toString() + "/name")).isEqualTo("fraudDetectionServer");
+ then(stubRunnerExtension.findStubUrl("loanIssuance")).isEqualTo(URI.create("http://localhost:12345").toURL());
+ then(stubRunnerExtension.findStubUrl("fraudDetectionServer")).isEqualTo(URI.create("http://localhost:12346").toURL());
+ }
+
+ private static String repoRoot() {
+ try {
+ return StubRunnerJUnit5ExtensionCustomPortTests.class.getResource("/m2repo/repository/")
+ .toURI().toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ private String httpGet(String url) throws Exception {
+ try (InputStream stream = URI.create(url).toURL().openStream()) {
+ return StreamUtils.copyToString(stream, Charset.forName("UTF-8"));
+ }
+ }
+}
diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java
new file mode 100644
index 0000000000..64bc403e37
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionExceptionThrowingTests.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 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.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * @author Olga Maciaszek-Sharma
+ * @since 2.1.0
+ */
+public class StubRunnerJUnit5ExtensionExceptionThrowingTests {
+
+ @RegisterExtension
+ static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
+ .stubsMode(StubRunnerProperties.StubsMode.REMOTE)
+ .repoRoot(repoRoot())
+ .downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService");
+
+ @BeforeAll
+ @AfterAll
+ static void setupProps() {
+ System.clearProperty("stubrunner.repository.root");
+ System.clearProperty("stubrunner.classifier");
+ }
+
+ @Test
+ void should_throw_exception_when_no_message_verifier_was_passed_and_message_related_method_was_triggered() {
+ UnsupportedOperationException emptyTriggerException = assertThrows(UnsupportedOperationException.class,
+ () -> stubRunnerExtension.trigger());
+ UnsupportedOperationException wrongLabelException = assertThrows(UnsupportedOperationException.class,
+ () -> stubRunnerExtension.trigger("return_book_1"));
+ UnsupportedOperationException wrongLabelWithIvyNotation = assertThrows(UnsupportedOperationException.class,
+ () -> stubRunnerExtension.trigger("bootService", "return_book_1"));
+ }
+
+ private static String repoRoot() {
+ try {
+ return StubRunnerRuleCustomPortJUnitTest.class.getResource("/m2repo/repository/").toURI().toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+}
diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java
new file mode 100644
index 0000000000..3104b99c6f
--- /dev/null
+++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerJUnit5ExtensionTests.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018 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.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
+
+import java.io.File;
+import java.net.URL;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @since 2.1.0
+ * @author Olga Maciaszek-Sharma
+ */
+
+class StubRunnerJUnit5ExtensionTests {
+
+ @BeforeAll
+ @AfterAll
+ static void setupProps() {
+ System.clearProperty("stubrunner.repository.root");
+ System.clearProperty("stubrunner.classifier");
+ }
+
+ // tag::extension[]
+ // Visible for Junit
+ @RegisterExtension
+ static StubRunnerExtension stubRunnerExtension = new StubRunnerExtension()
+ .repoRoot(repoRoot())
+ .stubsMode(StubRunnerProperties.StubsMode.REMOTE)
+ .downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")
+ .downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")
+ .withMappingsOutputFolder("target/outputmappingsforrule");
+
+ @Test
+ void should_start_WireMock_servers() {
+ assertThat(stubRunnerExtension.findStubUrl("org.springframework.cloud.contract.verifier.stubs",
+ "loanIssuance")).isNotNull();
+ assertThat(stubRunnerExtension.findStubUrl("loanIssuance")).isNotNull();
+ assertThat(stubRunnerExtension.findStubUrl("loanIssuance")).isEqualTo(stubRunnerExtension
+ .findStubUrl("org.springframework.cloud.contract.verifier.stubs", "loanIssuance"));
+ assertThat(stubRunnerExtension
+ .findStubUrl("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")).isNotNull();
+ }
+ // end::extension[]
+
+ @Test
+ void should_output_mappings_to_output_folder() {
+ // when
+ URL url = stubRunnerExtension.findStubUrl("fraudDetectionServer");
+
+ //then
+ assertThat(new File("target/outputmappingsforrule", "fraudDetectionServer_" + url.getPort())).exists();
+ }
+
+ private static String repoRoot() {
+ try {
+ return StubRunnerRuleJUnitTest.class.getResource("/m2repo/repository/").toURI().toString();
+ } catch (Exception e) {
+ return "";
+ }
+ }
+}