Added support for additional configuration of HTTP Server stubs

without this change it's hard to add HTTPs support for the stubs ran by stub runner. It's close to impossible to alter the default configuration of HTTP server stubs at all (e.g. lower the logging level of WireMock stubs etc.)
    with this change we allow to pass a class as a property to stub runner either via annotation, JUnit rule / extension or just system properties. That way the configurer will be applied at runtime for WireMock stubs (implementors of custom HTTP server stubs will need to perform some additional work to allow this)

    fixes gh-742
This commit is contained in:
Marcin Grzejszczak
2019-01-11 13:47:40 +01:00
parent 66f7e9329e
commit 6de903368a
20 changed files with 732 additions and 349 deletions

View File

@@ -146,6 +146,37 @@ structure in your stubs jar.
By maintaining this structure classpath gets scanned and you can profit from the messaging /
HTTP stubs without the need to download artifacts.
===== Configuring HTTP Server Stubs
Stub Runner has a notion of a `HttpServerStub` that abstracts the underlaying
concrete implementation of the HTTP server (e.g. WireMock is one of the implementations).
Sometimes, you need to perform some additional tuning of the stub servers,
that is concrete for the given implementation. To do that, Stub Runner gives you
the `httpServerStubConfigurer` property that is available in the annotation,
JUnit rule, and is accessible via system properties, where you can provide
your implementation of the `org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer` interface. The implementations can alter
the configuration files for the given HTTP server stub.
Spring Cloud Contract Stub Runner comes with an implementation that you
can extend, for WireMock - `org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer`. In the `configure` method
you can provide your own, custom configuration for the given stub. The use
case might be starting WireMock for the given artifact id, on an HTTPs port. Example:
.WireMockHttpServerStubConfigurer implementation
[source,groovy,indent=0]
----
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy[tags=wireMockHttpServerStubConfigurer]
----
You can then reuse it via the annotation
[source,groovy,indent=0]
----
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfigurationSpec.groovy[tags=annotation]
----
Whenever an https port is found, it will take precedence over the http one.
==== Running stubs
===== Running using main app
@@ -677,5 +708,4 @@ Then only the stubs registered under a path that contains the `foo-consumer` in
`src/test/resources/contracts/foo-consumer/some/contracts/...` folder) will be allowed to be referenced.
You can check out https://github.com/spring-cloud/spring-cloud-contract/issues/224[issue 224] for more
information about the reasons behind this change.
information about the reasons behind this change.

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2013-2019 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;
import java.io.File;
@@ -12,10 +27,17 @@ import java.util.Collection;
public interface HttpServerStub {
/**
* Port on which the server is running
* Port on which the server is running. Return {@code -1} if not applicable.
*/
int port();
/**
* Https port on which the server is running. Return {@code -1} if not applicable.
*/
default int httpsPort() {
return -1;
}
/**
* Returns {@code true} if the server is running
*/
@@ -23,14 +45,29 @@ public interface HttpServerStub {
/**
* Starts the server on a random port. Should return itself to allow chaining.
* @deprecated use {@link HttpServerStub#start(HttpServerStubConfiguration)}
*/
@Deprecated
HttpServerStub start();
/**
* Starts the server on a given port. Should return itself to allow chaining.
* @deprecated use {@link HttpServerStub#start(HttpServerStubConfiguration)}
*/
@Deprecated
HttpServerStub start(int port);
/**
* Starts the server. Should return itself to allow chaining.
* @param configuration - setup for the given stub
*/
default HttpServerStub start(HttpServerStubConfiguration configuration) {
if (configuration.isRandomPort()) {
return start();
}
return start(configuration.port);
};
/**
* Stops the server. Should return itself to allow chaining.
*/

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2013-2019 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;
/**
* Configuration class for an {@link HttpServerStub}
* @since 2.1.0
* @author Marcin Grzejszczak
*/
public final class HttpServerStubConfiguration {
public final HttpServerStubConfigurer configurer;
public final StubRunnerOptions stubRunnerOptions;
public final StubConfiguration stubConfiguration;
public final Integer port;
public HttpServerStubConfiguration(HttpServerStubConfigurer configurer, StubRunnerOptions stubRunnerOptions, StubConfiguration stubConfiguration, Integer port) {
this.configurer = configurer;
this.stubRunnerOptions = stubRunnerOptions;
this.stubConfiguration = stubConfiguration;
this.port = port;
}
public boolean isRandomPort() {
return this.port == null || this.port == 0;
}
public String toColonSeparatedDependencyNotation() {
return this.stubConfiguration != null ?
this.stubConfiguration.toColonSeparatedDependencyNotation() : "";
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.
*/
package org.springframework.cloud.contract.stubrunner;
/**
* Allows to perform additional configuration of the HTTP Server stub
*
* @author Marcin Grzejszczak
* @since 2.1.0
*/
public interface HttpServerStubConfigurer<T> {
/**
* Ensures that the HTTP server stub implementation configuration type is accepted
* @param httpStubConfiguration - HTTP server stub implementation
* @return {@code true} when this configurer can be applied for this object
*/
boolean isAccepted(Object httpStubConfiguration);
/**
* Performs additional configuration of the HTTP Server Stub
* @param httpStubConfiguration - stub implementation to configure
* @param httpServerStubConfiguration - Spring Cloud Contract stub configuration
*/
default T configure(T httpStubConfiguration,
HttpServerStubConfiguration httpServerStubConfiguration) {
return httpStubConfiguration;
}
/**
* Implementation that does nothing
*/
class NoOpHttpServerStubConfigurer implements HttpServerStubConfigurer {
public static HttpServerStubConfigurer INSTANCE = new NoOpHttpServerStubConfigurer();
@Override
public boolean isAccepted(Object httpStubConfiguration) {
return false;
}
}
}

View File

@@ -30,6 +30,8 @@ import java.util.Set;
import groovy.json.JsonOutput;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import wiremock.org.eclipse.jetty.util.ConcurrentHashSet;
import org.springframework.cloud.contract.spec.Contract;
import org.springframework.cloud.contract.spec.internal.DslProperty;
import org.springframework.cloud.contract.spec.internal.Headers;
@@ -39,7 +41,6 @@ import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockH
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 wiremock.org.eclipse.jetty.util.ConcurrentHashSet;
/**
* Runs stubs for a particular {@link StubServer}
@@ -72,7 +73,7 @@ class StubRunnerExecutor implements StubFinder {
}
StubRunnerExecutor(AvailablePortScanner portScanner) {
this(portScanner, new NoOpStubMessages(), new ArrayList<HttpServerStub>());
this(portScanner, new NoOpStubMessages(), new ArrayList<>());
}
public RunningStubs runStubs(StubRunnerOptions stubRunnerOptions,
@@ -84,7 +85,14 @@ class StubRunnerExecutor implements StubFinder {
}
return runningStubs();
}
startStubServers(stubRunnerOptions, stubConfiguration, repository);
try {
HttpServerStubConfigurer configurer = stubRunnerOptions
.getHttpServerStubConfigurer().newInstance();
startStubServers(configurer, stubRunnerOptions, stubConfiguration, repository);
}
catch (InstantiationException | IllegalAccessException ex) {
log.error("Failed to instantiate the HTTP stub configurer", ex);
}
RunningStubs runningCollaborators = runningStubs();
log.info("All stubs are now running " + runningCollaborators.toString());
return runningCollaborators;
@@ -257,22 +265,26 @@ class StubRunnerExecutor implements StubFinder {
return condition ? this.stubServer.getStubUrl() : null;
}
private void startStubServers(final StubRunnerOptions stubRunnerOptions,
private StubServer startStubServers(HttpServerStubConfigurer configurer,
final StubRunnerOptions stubRunnerOptions,
final StubConfiguration stubConfiguration, StubRepository repository) {
final List<File> mappings = repository.getStubs();
final Collection<Contract> contracts = repository.contracts;
Integer port = stubRunnerOptions.port(stubConfiguration);
HttpServerStubConfiguration configuration = new HttpServerStubConfiguration(
configurer, stubRunnerOptions, stubConfiguration, port
);
if (!hasRequest(contracts) && mappings.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("There are no HTTP related contracts. Won't start any servers");
}
this.stubServer = new StubServer(stubConfiguration, mappings, contracts,
new NoOpHttpServerStub()).start();
return;
new NoOpHttpServerStub()).start(configuration);
return this.stubServer;
}
if (port != null && port >= 0) {
this.stubServer = new StubServer(stubConfiguration, mappings, contracts,
httpServerStub()).start(port);
httpServerStub()).start(configuration);
}
else {
this.stubServer = this.portScanner
@@ -280,11 +292,15 @@ class StubRunnerExecutor implements StubFinder {
@Override
public StubServer call(int availablePort) {
return new StubServer(stubConfiguration, mappings, contracts,
httpServerStub()).start(availablePort);
httpServerStub()).start(
new HttpServerStubConfiguration(
configurer, stubRunnerOptions, stubConfiguration, availablePort
));
}
});
}
STUB_SERVERS.add(this.stubServer);
return this.stubServer;
}
private boolean hasRequest(Collection<Contract> contracts) {

View File

@@ -26,6 +26,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
@@ -114,13 +115,20 @@ public class StubRunnerOptions {
*/
private Map<String, String> properties = new HashMap<>();
/**
* Configuration for an HTTP server stub
* @return class that allows to perform additional HTTP server stub configuration
*/
private final Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer;
StubRunnerOptions(Integer minPortValue, Integer maxPortValue,
Resource stubRepositoryRoot, StubRunnerProperties.StubsMode stubsMode,
String stubsClassifier, Collection<StubConfiguration> dependencies,
Map<StubConfiguration, Integer> stubIdsToPortMapping, String username,
String password, final StubRunnerProxyOptions stubRunnerProxyOptions,
boolean stubsPerConsumer, String consumerName, String mappingsOutputFolder,
boolean deleteStubsAfterTest, Map<String, String> properties) {
boolean deleteStubsAfterTest, Map<String, String> properties,
Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer) {
this.minPortValue = minPortValue;
this.maxPortValue = maxPortValue;
this.stubRepositoryRoot = stubRepositoryRoot;
@@ -137,6 +145,7 @@ public class StubRunnerOptions {
this.mappingsOutputFolder = mappingsOutputFolder;
this.deleteStubsAfterTest = deleteStubsAfterTest;
this.properties = properties;
this.httpServerStubConfigurer = httpServerStubConfigurer;
}
public Integer port(StubConfiguration stubConfiguration) {
@@ -253,6 +262,7 @@ public class StubRunnerOptions {
return this.stubsPerConsumer;
}
@Deprecated
public void setStubsPerConsumer(boolean stubsPerConsumer) {
this.stubsPerConsumer = stubsPerConsumer;
}
@@ -261,6 +271,7 @@ public class StubRunnerOptions {
return this.consumerName;
}
@Deprecated
public void setConsumerName(String consumerName) {
this.consumerName = consumerName;
}
@@ -273,6 +284,7 @@ public class StubRunnerOptions {
return this.mappingsOutputFolder;
}
@Deprecated
public void setMappingsOutputFolder(String mappingsOutputFolder) {
this.mappingsOutputFolder = mappingsOutputFolder;
}
@@ -281,6 +293,7 @@ public class StubRunnerOptions {
return this.deleteStubsAfterTest;
}
@Deprecated
public void setDeleteStubsAfterTest(boolean deleteStubsAfterTest) {
this.deleteStubsAfterTest = deleteStubsAfterTest;
}
@@ -289,10 +302,15 @@ public class StubRunnerOptions {
return this.properties;
}
@Deprecated
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public Class<? extends HttpServerStubConfigurer> getHttpServerStubConfigurer() {
return this.httpServerStubConfigurer;
}
public static class StubRunnerProxyOptions {
private final String proxyHost;
@@ -317,7 +335,6 @@ public class StubRunnerOptions {
return "StubRunnerProxyOptions{" + "proxyHost='" + this.proxyHost + '\''
+ ", proxyPort=" + this.proxyPort + '}';
}
}
@Override
@@ -331,7 +348,7 @@ public class StubRunnerOptions {
+ '\'' + ", password='" + obfuscate(this.password) + '\''
+ ", stubRunnerProxyOptions='" + this.stubRunnerProxyOptions
+ "', stubsPerConsumer='" + this.stubsPerConsumer + '\''
+ ", stubsPerConsumer='" + this.stubsPerConsumer + '\'' + '}';
+ ", httpServerStubConfigurer='" + this.httpServerStubConfigurer+ '\'' + '}';
}
private String obfuscate(String string) {

View File

@@ -66,6 +66,10 @@ public class StubRunnerOptionsBuilder {
private Map<String, String> properties = new HashMap<>();
private Class httpServerStubConfigurer =
HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.class;
public StubRunnerOptionsBuilder() {
}
@@ -174,13 +178,18 @@ public class StubRunnerOptionsBuilder {
return this;
}
public StubRunnerOptionsBuilder withHttpServerStubConfigurer(Class httpServerStubConfigurer) {
this.httpServerStubConfigurer = httpServerStubConfigurer;
return this;
}
public StubRunnerOptions build() {
return new StubRunnerOptions(this.minPortValue, this.maxPortValue,
this.stubRepositoryRoot, this.stubsMode, this.stubsClassifier,
buildDependencies(), this.stubIdsToPortMapping, this.username,
this.password, this.stubRunnerProxyOptions, this.stubsPerConsumer,
this.consumerName, this.mappingsOutputFolder, this.deleteStubsAfterTest,
this.properties);
this.properties, this.httpServerStubConfigurer);
}
private Collection<StubConfiguration> buildDependencies() {

View File

@@ -46,13 +46,8 @@ class StubServer {
this.contracts = contracts;
}
public StubServer start() {
this.httpServerStub.start();
return stubServer();
}
public StubServer start(int port) {
this.httpServerStub.start(port);
public StubServer start(HttpServerStubConfiguration configuration) {
this.httpServerStub.start(configuration);
return stubServer();
}
@@ -77,7 +72,12 @@ class StubServer {
public int getPort() {
if (this.httpServerStub.isRunning()) {
return this.httpServerStub.port();
int httpsPort = this.httpServerStub.httpsPort();
int httpPort = this.httpServerStub.port();
if (log.isDebugEnabled()) {
log.debug("Ports for this server are https [" + httpsPort + "] and http [" + httpPort + "]");
}
return httpsPort != -1 ? httpsPort : httpPort;
}
if (log.isDebugEnabled()) {
log.debug("The HTTP Server stub is not running... That means that the "
@@ -86,9 +86,14 @@ class StubServer {
return -1;
}
private boolean hasHttps() {
int httpsPort = this.httpServerStub.httpsPort();
return httpsPort != -1;
}
public URL getStubUrl() {
try {
return new URL("http://localhost:" + getPort());
return new URL((hasHttps() ? "https:" : "http:") + "//localhost:" + getPort());
}
catch (MalformedURLException e) {
throw new IllegalStateException("Cannot parse URL", e);
@@ -107,6 +112,10 @@ class StubServer {
return this.httpServerStub.registeredMappings();
}
HttpServerStub httpServerStub() {
return this.httpServerStub;
}
@Override
public boolean equals(Object o) {
if (this == o)

View File

@@ -16,14 +16,23 @@
package org.springframework.cloud.contract.stubrunner.junit;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
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.HttpServerStubConfigurer;
import org.springframework.cloud.contract.stubrunner.RunningStubs;
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
import org.springframework.cloud.contract.stubrunner.StubFinder;
@@ -33,13 +42,6 @@ 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.
*
@@ -48,237 +50,245 @@ import java.util.Map;
*/
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);
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();
StubRunnerExtension delegate = this;
private BatchStubRunner stubFinder;
private StubRunnerOptionsBuilder stubRunnerOptionsBuilder = new StubRunnerOptionsBuilder(
StubRunnerOptions.fromSystemProps());
private MessageVerifier verifier = new ExceptionThrowingMessageVerifier();
public StubRunnerExtension() {
}
public StubRunnerExtension() {
}
StubRunnerExtension(StubRunnerExtension delegate) {
this.delegate = delegate;
}
StubRunnerExtension(StubRunnerExtension delegate) {
this.delegate = delegate;
}
@Override
public void beforeAll(ExtensionContext extensionContext) {
stubFinder(new BatchStubRunnerFactory(builder().build(), verifier()).buildBatchStubRunner());
stubFinder().runStubs();
}
@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 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 groupId, String artifactId) throws StubNotFoundException {
return stubFinder().findStubUrl(groupId, artifactId);
}
@Override
public URL findStubUrl(String ivyNotation) throws StubNotFoundException {
return stubFinder().findStubUrl(ivyNotation);
}
@Override
public URL findStubUrl(String ivyNotation) throws StubNotFoundException {
return stubFinder().findStubUrl(ivyNotation);
}
@Override
public RunningStubs findAllRunningStubs() {
return stubFinder().findAllRunningStubs();
}
@Override
public RunningStubs findAllRunningStubs() {
return stubFinder().findAllRunningStubs();
}
@Override
public Map<StubConfiguration, Collection<Contract>> getContracts() {
return stubFinder().getContracts();
}
@Override
public Map<StubConfiguration, Collection<Contract>> 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 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(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 boolean trigger() {
boolean result = stubFinder().trigger();
if (!result) {
throw new IllegalStateException("Failed to trigger a message");
}
return result;
}
@Override
public Map<String, Collection<String>> labels() {
return stubFinder().labels();
}
@Override
public Map<String, Collection<String>> labels() {
return stubFinder().labels();
}
@Override
public StubRunnerExtension messageVerifier(MessageVerifier messageVerifier) {
verifier(messageVerifier);
return delegate;
}
@Override
public StubRunnerExtension messageVerifier(MessageVerifier messageVerifier) {
verifier(messageVerifier);
return this.delegate;
}
@Override
public StubRunnerExtension options(StubRunnerOptions stubRunnerOptions) {
builder().withOptions(stubRunnerOptions);
return delegate;
}
@Override
public StubRunnerExtension options(StubRunnerOptions stubRunnerOptions) {
builder().withOptions(stubRunnerOptions);
return this.delegate;
}
@Override
public StubRunnerExtension minPort(int minPort) {
builder().withMinPort(minPort);
return delegate;
}
@Override
public StubRunnerExtension minPort(int minPort) {
builder().withMinPort(minPort);
return this.delegate;
}
@Override
public StubRunnerExtension maxPort(int maxPort) {
builder().withMaxPort(maxPort);
return delegate;
}
@Override
public StubRunnerExtension maxPort(int maxPort) {
builder().withMaxPort(maxPort);
return this.delegate;
}
@Override
public StubRunnerExtension repoRoot(String repoRoot) {
builder().withStubRepositoryRoot(repoRoot);
return delegate;
}
@Override
public StubRunnerExtension repoRoot(String repoRoot) {
builder().withStubRepositoryRoot(repoRoot);
return this.delegate;
}
@Override
public StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode) {
builder().withStubsMode(stubsMode);
return delegate;
}
@Override
public StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode) {
builder().withStubsMode(stubsMode);
return this.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 downloadStub(String groupId, String artifactId, String version, String classifier) {
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version
+ DELIMITER + classifier);
return new PortStubRunnerExtension(this.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 downloadLatestStub(String groupId, String artifactId, String classifier) {
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + LATEST_VERSION
+ DELIMITER + classifier);
return new PortStubRunnerExtension(this.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, String version) {
builder().withStubs(groupId + DELIMITER + artifactId + DELIMITER + version);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public PortStubRunnerExtension downloadStub(String groupId, String artifactId) {
builder().withStubs(groupId + DELIMITER + artifactId);
return new PortStubRunnerExtension(delegate);
}
@Override
public PortStubRunnerExtension downloadStub(String groupId, String artifactId) {
builder().withStubs(groupId + DELIMITER + artifactId);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public PortStubRunnerExtension downloadStub(String ivyNotation) {
builder().withStubs(ivyNotation);
return new PortStubRunnerExtension(delegate);
}
@Override
public PortStubRunnerExtension downloadStub(String ivyNotation) {
builder().withStubs(ivyNotation);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension downloadStubs(String... ivyNotations) {
builder().withStubs(Arrays.asList(ivyNotations));
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension downloadStubs(String... ivyNotations) {
builder().withStubs(Arrays.asList(ivyNotations));
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension downloadStubs(List<String> ivyNotations) {
builder().withStubs(ivyNotations);
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension downloadStubs(List<String> ivyNotations) {
builder().withStubs(ivyNotations);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer) {
builder().withStubPerConsumer(stubPerConsumer);
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer) {
builder().withStubPerConsumer(stubPerConsumer);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension withConsumerName(String consumerName) {
builder().withConsumerName(consumerName);
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension withConsumerName(String consumerName) {
builder().withConsumerName(consumerName);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder) {
builder().withMappingsOutputFolder(mappingsOutputFolder);
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder) {
builder().withMappingsOutputFolder(mappingsOutputFolder);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension withDeleteStubsAfterTest(boolean deleteStubsAfterTest) {
builder().withDeleteStubsAfterTest(deleteStubsAfterTest);
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension withDeleteStubsAfterTest(boolean deleteStubsAfterTest) {
builder().withDeleteStubsAfterTest(deleteStubsAfterTest);
return new PortStubRunnerExtension(this.delegate);
}
@Override
public StubRunnerExtension withProperties(Map<String, String> properties) {
builder().withProperties(properties);
return new PortStubRunnerExtension(delegate);
}
@Override
public StubRunnerExtension withProperties(Map<String, String> properties) {
builder().withProperties(properties);
return new PortStubRunnerExtension(this.delegate);
}
BatchStubRunner stubFinder() {
return this.delegate.stubFinder;
}
@Override
public StubRunnerExtension withHttpServerStubConfigurer(Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer) {
builder().withHttpServerStubConfigurer(httpServerStubConfigurer);
return new PortStubRunnerExtension(this.delegate);
}
void stubFinder(BatchStubRunner stubFinder) {
this.delegate.stubFinder = stubFinder;
}
BatchStubRunner stubFinder() {
return this.delegate.stubFinder;
}
StubRunnerOptionsBuilder builder() {
return delegate.stubRunnerOptionsBuilder;
}
void stubFinder(BatchStubRunner stubFinder) {
this.delegate.stubFinder = stubFinder;
}
MessageVerifier verifier() {
return delegate.verifier;
}
StubRunnerOptionsBuilder builder() {
return this.delegate.stubRunnerOptionsBuilder;
}
void verifier(MessageVerifier verifier) {
delegate.verifier = verifier;
}
MessageVerifier verifier() {
return this.delegate.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 {
void verifier(MessageVerifier verifier) {
this.delegate.verifier = verifier;
}
PortStubRunnerExtension(StubRunnerExtension delegate) {
super(delegate);
}
/**
* 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 {
@Override
public StubRunnerExtension withPort(Integer port) {
builder().withPort(port);
return delegate;
}
}
PortStubRunnerExtension(StubRunnerExtension delegate) {
super(delegate);
}
@Override
public StubRunnerExtension withPort(Integer port) {
builder().withPort(port);
return this.delegate;
}
}
}

View File

@@ -16,119 +16,125 @@
package org.springframework.cloud.contract.stubrunner.junit;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer;
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);
/**
* 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);
/**
* Override all options
*
* @see StubRunnerOptions
*/
StubRunnerExtension options(StubRunnerOptions stubRunnerOptions);
/**
* Min value of port for WireMock server
*/
StubRunnerExtension minPort(int minPort);
/**
* Min value of port for WireMock server
*/
StubRunnerExtension minPort(int minPort);
/**
* Max value of port for WireMock server
*/
StubRunnerExtension maxPort(int maxPort);
/**
* Max value of port for WireMock server
*/
StubRunnerExtension maxPort(int maxPort);
/**
* String URI of repository containing stubs
*/
StubRunnerExtension repoRoot(String repoRoot);
/**
* String URI of repository containing stubs
*/
StubRunnerExtension repoRoot(String repoRoot);
/**
* Stubs mode that should be used
*/
StubRunnerExtension stubsMode(StubRunnerProperties.StubsMode stubsMode);
/**
* 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, 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 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 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);
/**
* 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);
/**
* 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(String... ivyNotations);
/**
* Stubs to download in Ivy notations
*/
StubRunnerExtension downloadStubs(List<String> ivyNotations);
/**
* Stubs to download in Ivy notations
*/
StubRunnerExtension downloadStubs(List<String> ivyNotations);
/**
* Allows stub per consumer
*/
StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer);
/**
* Allows stub per consumer
*/
StubRunnerExtension withStubPerConsumer(boolean stubPerConsumer);
/**
* Allows setting consumer name
*/
StubRunnerExtension withConsumerName(String consumerName);
/**
* Allows setting consumer name
*/
StubRunnerExtension withConsumerName(String consumerName);
/**
* Allows setting the output folder for mappings
*/
StubRunnerExtension withMappingsOutputFolder(String mappingsOutputFolder);
/**
* 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);
/**
* 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<String, String> properties);
/**
* Map of properties that can be passed to custom
* {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}
*/
StubRunnerExtension withProperties(Map<String, String> properties);
/**
* Configuration for an HTTP server stub
*/
StubRunnerExtension withHttpServerStubConfigurer(Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer);
}

View File

@@ -16,12 +16,20 @@
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 org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
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.HttpServerStubConfigurer;
import org.springframework.cloud.contract.stubrunner.RunningStubs;
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
import org.springframework.cloud.contract.stubrunner.StubFinder;
@@ -30,12 +38,6 @@ 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.
*
@@ -190,6 +192,12 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
return this.delegate;
}
@Override
public StubRunnerRule withHttpServerStubConfigurer(Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer) {
builder().withHttpServerStubConfigurer(httpServerStubConfigurer);
return this.delegate;
}
@Override
public URL findStubUrl(String groupId, String artifactId) {
return this.stubFinder().findStubUrl(groupId, artifactId);

View File

@@ -16,13 +16,14 @@
package org.springframework.cloud.contract.stubrunner.junit;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer;
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 {
/**
@@ -127,4 +128,9 @@ interface StubRunnerRuleOptions {
*/
StubRunnerRule withProperties(Map<String, String> properties);
/**
* Configuration for an HTTP server stub
*/
StubRunnerRule withHttpServerStubConfigurer(Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer);
}

View File

@@ -34,12 +34,16 @@ import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.Slf4jNotifier;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.extension.Extension;
import com.github.tomakehurst.wiremock.security.ClientAuthenticator;
import com.github.tomakehurst.wiremock.security.NoClientAuthenticator;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import wiremock.com.github.jknack.handlebars.Helper;
import org.springframework.cloud.contract.stubrunner.HttpServerStub;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer;
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper;
import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsJsonPathHelper;
import org.springframework.cloud.contract.verifier.dsl.wiremock.DefaultResponseTransformer;
@@ -67,6 +71,10 @@ public class WireMockHttpServerStub implements HttpServerStub {
private WireMockServer wireMockServer;
private boolean https = false;
private WireMockConfiguration wireMockConfiguration;
private WireMockConfiguration config() {
if (ClassUtils.isPresent(
"org.springframework.cloud.contract.wiremock.WireMockSpring", null)) {
@@ -105,7 +113,9 @@ public class WireMockHttpServerStub implements HttpServerStub {
@Override
public int port() {
return isRunning() ? this.wireMockServer.port() : INVALID_PORT;
return isRunning() ? (this.https ?
this.wireMockServer.httpsPort() : this.wireMockServer.port())
: INVALID_PORT;
}
@Override
@@ -122,23 +132,55 @@ public class WireMockHttpServerStub implements HttpServerStub {
return this;
}
int port = SocketUtils.findAvailableTcpPort();
HttpServerStub serverStub = start(port);
HttpServerStub serverStub = start(defaultConfiguration(port));
cacheStubServer(true, port);
return serverStub;
}
private HttpServerStubConfiguration defaultConfiguration(int port) {
return new HttpServerStubConfiguration(HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.INSTANCE, null, null, port);
}
@Override
public HttpServerStub start(int port) {
this.wireMockServer = new WireMockServer(
config().port(port).notifier(new Slf4jNotifier(true)));
return start(defaultConfiguration(port));
}
@Override
public HttpServerStub start(
HttpServerStubConfiguration configuration) {
if (isRunning()) {
if (log.isTraceEnabled()) {
log.trace("The server is already running at port [" + port() + "]");
}
return this;
}
int port = configuration.port;
WireMockConfiguration wireMockConfiguration = config().port(port)
.notifier(new Slf4jNotifier(true));
if (configuration.configurer.isAccepted(wireMockConfiguration)) {
@SuppressWarnings("unchecked")
HttpServerStubConfigurer<WireMockConfiguration> configurer = configuration.configurer;
wireMockConfiguration = configurer.configure(wireMockConfiguration, configuration);
}
this.wireMockConfiguration = wireMockConfiguration;
this.https = wireMockConfiguration.httpsSettings().enabled();
port = this.https ? wireMockConfiguration.httpsSettings().port() :
wireMockConfiguration.portNumber();
this.wireMockServer = new WireMockServer(wireMockConfiguration);
this.wireMockServer.start();
if (log.isDebugEnabled()) {
log.debug("Started WireMock at port [" + port + "]");
log.debug("For " + configuration.toColonSeparatedDependencyNotation() + " Started WireMock at [" + (this.https ? "https" : "http") + "] port [" + port + "]");
}
cacheStubServer(false, port);
return this;
}
@Override
public int httpsPort() {
return this.https ? port() : INVALID_PORT;
}
@Override
public HttpServerStub reset() {
this.wireMockServer.resetAll();
@@ -205,7 +247,16 @@ public class WireMockHttpServerStub implements HttpServerStub {
}
private WireMock wireMock() {
return new WireMock("localhost", port(), "");
String scheme = this.https ? "https" : "http";
String host = "localhost";
int port = port();
String urlPathPrefix = null;
String hostHeader = null;
String proxyHost = this.wireMockConfiguration.proxyHostHeader();
int proxyPort = this.wireMockConfiguration.proxyVia().port();
ClientAuthenticator authenticator = NoClientAuthenticator.noClientAuthenticator();
return new WireMock(scheme, host, port, urlPathPrefix,
hostHeader, proxyHost, proxyPort, authenticator);
}
private void registerDefaultHealthChecks(WireMock wireMock) {
@@ -240,16 +291,6 @@ public class WireMockHttpServerStub implements HttpServerStub {
return mapping;
}
void registerDescriptors(List<StubMapping> stubMappings) {
if (log.isDebugEnabled()) {
log.debug("Registering stub mappings size [" + stubMappings.size()
+ "] at port [" + port() + "]");
}
for (StubMapping mapping : stubMappings) {
wireMock().register(mapping);
}
}
private void registerHealthCheck(WireMock wireMock, String url) {
registerHealthCheck(wireMock, url, "OK");
}

View File

@@ -0,0 +1,34 @@
/*
* 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.
*/
package org.springframework.cloud.contract.stubrunner.provider.wiremock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer;
/**
* Typed implementation of {@link HttpServerStubConfigurer} for WireMock's {@link WireMockConfiguration}
*
* @author Marcin Grzejszczak
* @since 2.1.0
*/
public class WireMockHttpServerStubConfigurer implements HttpServerStubConfigurer<WireMockConfiguration> {
@Override
public boolean isAccepted(Object httpStubConfiguration) {
return httpStubConfiguration instanceof WireMockConfiguration;
}
}

View File

@@ -25,6 +25,7 @@ import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.autoconfigure.properties.PropertyMapping;
import org.springframework.boot.test.autoconfigure.properties.SkipPropertyMapping;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer;
import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier;
/**
@@ -132,4 +133,11 @@ public @interface AutoConfigureStubRunner {
* folder after running tests
*/
boolean deleteStubsAfterTest() default true;
/**
* Configuration for an HTTP server stub
* @return class that allows to perform additional HTTP server stub configuration
*/
Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer()
default HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.class;
}

View File

@@ -97,7 +97,8 @@ public class StubRunnerConfiguration {
.withConsumerName(consumerName())
.withMappingsOutputFolder(this.props.getMappingsOutputFolder())
.withDeleteStubsAfterTest(this.props.isDeleteStubsAfterTest())
.withProperties(this.props.getProperties());
.withProperties(this.props.getProperties())
.withHttpServerStubConfigurer(this.props.getHttpServerStubConfigurer());
}
private String consumerName() {

View File

@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfigurer;
import org.springframework.cloud.contract.stubrunner.ResourceResolver;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
@@ -113,6 +114,12 @@ public class StubRunnerProperties {
*/
private Map<String, String> properties = new HashMap<>();
/**
* Configuration for an HTTP server stub
*/
private Class<? extends HttpServerStubConfigurer> httpServerStubConfigurer =
HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.class;
/**
* An enumeration stub modes.
*/
@@ -251,6 +258,14 @@ public class StubRunnerProperties {
return this.properties;
}
public Class getHttpServerStubConfigurer() {
return this.httpServerStubConfigurer;
}
public void setHttpServerStubConfigurer(Class httpServerStubConfigurer) {
this.httpServerStubConfigurer = httpServerStubConfigurer;
}
public void setProperties(String[] properties) {
Properties elements = StringUtils.splitArrayElementsIntoProperties(properties,
"=");

View File

@@ -231,7 +231,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
given:
StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, new FileSystemResource("root"), StubRunnerProperties.StubsMode.LOCAL,
"classifier", [new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "foo", "bar",
new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, [foo: "bar"]))
new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, [foo: "bar"], Foo))
builder.withStubs("foo:bar:baz")
when:
StubRunnerOptions options = builder.build()
@@ -252,6 +252,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
options.mappingsOutputFolder == "folder"
options.deleteStubsAfterTest == false
options.properties == [foo: "bar"]
options.httpServerStubConfigurer == Foo
}
def shouldNotPrintUsernameAndPassword() {
@@ -259,7 +260,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, new FileSystemResource("root"),
StubRunnerProperties.StubsMode.CLASSPATH, "classifier",
[new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "username123", "password123",
new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, [:]))
new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, [:], Foo))
builder.withStubs("foo:bar:baz")
when:
String options = builder.build().toString()
@@ -289,6 +290,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
System.setProperty("stubrunner.properties.foo-bar", "bar")
System.setProperty("stubrunner.properties.foo-baz", "baz")
System.setProperty("stubrunner.properties.bar.bar", "foo")
System.setProperty("stubrunner.httpServerStubConfigurer", "org.springframework.cloud.contract.stubrunner.Foo")
when:
StubRunnerOptions options = StubRunnerOptions.fromSystemProps()
then:
@@ -306,5 +308,14 @@ class StubRunnerOptionsBuilderSpec extends Specification {
options.consumerName == "consumer"
options.mappingsOutputFolder == "folder"
options.properties == ["foo-bar": "bar", "foo-baz": "baz", "bar.bar": "foo"]
options.httpServerStubConfigurer == Foo
}
}
class Foo implements HttpServerStubConfigurer {
@Override
boolean isAccepted(Object httpStubConfiguration) {
return true
}
}

View File

@@ -16,22 +16,30 @@
package org.springframework.cloud.contract.stubrunner.spring
import com.github.tomakehurst.wiremock.core.WireMockConfiguration
import groovy.transform.CompileStatic
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.junit.AfterClass
import org.junit.BeforeClass
import spock.lang.Issue
import spock.lang.Specification
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.cloud.contract.stubrunner.HttpServerStubConfiguration
import org.springframework.cloud.contract.stubrunner.StubFinder
import org.springframework.cloud.contract.stubrunner.StubNotFoundException
import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStubConfigurer
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
import org.springframework.util.SocketUtils
/**
* @author Marcin Grzejszczak
*/
@@ -42,7 +50,10 @@ import spock.lang.Specification
@SpringBootTest(properties = [" stubrunner.cloud.enabled=false",
'foo=${stubrunner.runningstubs.fraudDetectionServer.port}',
'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}'])
@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/")
// tag::annotation[]
@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/",
httpServerStubConfigurer = HttpsForFraudDetection)
// end::annotation[]
@ActiveProfiles("test")
class StubRunnerConfigurationSpec extends Specification {
@@ -74,6 +85,8 @@ class StubRunnerConfigurationSpec extends Specification {
and: 'Stubs were registered'
"${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
"${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
and: 'Fraud Detection is an HTTPS endpoint'
stubFinder.findStubUrl('fraudDetectionServer').toString().startsWith("https")
}
def 'should throw an exception when stub is not found'() {
@@ -129,5 +142,24 @@ class StubRunnerConfigurationSpec extends Specification {
@Configuration
@EnableAutoConfiguration
static class Config {}
// tag::wireMockHttpServerStubConfigurer[]
@CompileStatic
static class HttpsForFraudDetection extends WireMockHttpServerStubConfigurer {
private static final Log log = LogFactory.getLog(HttpsForFraudDetection)
@Override
WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
if (httpServerStubConfiguration.stubConfiguration.artifactId == "fraudDetectionServer") {
int httpsPort = SocketUtils.findAvailableTcpPort()
log.info("Will set HTTPs port [" + httpsPort + "] for fraud detection server")
return httpStubConfiguration
.httpsPort(httpsPort)
}
return httpStubConfiguration
}
}
// end::wireMockHttpServerStubConfigurer[]
}
// end::test[]

View File

@@ -138,13 +138,6 @@ public class WireMockConfiguration implements SmartLifecycle {
}
}
void reset() {
if (log.isDebugEnabled()) {
log.debug("Resetting stubs");
}
this.server.resetAll();
}
private void registerFiles(
com.github.tomakehurst.wiremock.core.WireMockConfiguration factory)
throws IOException {