Fixed issues with bound ports
This commit is contained in:
@@ -936,40 +936,4 @@ started will be attached.
|
||||
|
||||
Yes! With version 1.2.0 we've added such a possibility. It's enough to call `file(...)` method in the
|
||||
DSL and provide a path relative to where the contract lays.
|
||||
If you're using YAML just use the `bodyFromFile` property.
|
||||
|
||||
==== Why do I sometimes get `SocketException`
|
||||
|
||||
When using an HTTP client (e.g. `RestTemplate`) and running several tests that share a Spring context, you might sometimes get the following exception:
|
||||
|
||||
```
|
||||
java.net.SocketException: Unexpected end of file from server
|
||||
```
|
||||
|
||||
Tom Akehurst, the creator of WireMock did the following analysis of this issue.
|
||||
|
||||
> I looked at tcpdump while running the failing test. `HttpUrlConnection` is doing something weird - it's creating a connection in a previous test case, which works fine, then the usual `fin` -> `fin ack` etc. ending handshake happens. But it seems it isn't discarded, but reused after that. Because the server thinks (rightly) that the connection is closed, it just sends a RST packet. Calling the `/__admin` endpoint just happened to remove the dead connection from the pool. This also fixes the problem (which using the Java HTTP client): System.setProperty("http.keepAlive", "false");
|
||||
|
||||
There are the ways to solve this problem.
|
||||
|
||||
First, just use a different HTTP client for `RestTemplate`. Example for using Apache HTTP client:
|
||||
|
||||
.pom.xml
|
||||
[source,xml,indent=0]
|
||||
----
|
||||
include::{standalone_restdocs_path}/http-client/pom.xml[tags=httpclient,indent=0]
|
||||
----
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{standalone_restdocs_path}/http-client/src/main/java/com/example/loan/LoanApplicationService.java[tags=custom_request_factory,indent=0]
|
||||
----
|
||||
|
||||
Second option is to set the system property. You can set it either in code or pass it to your tests via a plugin.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
static {
|
||||
System.setProperty("http.keepAlive", "false");
|
||||
}
|
||||
----
|
||||
If you're using YAML just use the `bodyFromFile` property.
|
||||
@@ -10,6 +10,7 @@ import java.util.Collection;
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public interface HttpServerStub {
|
||||
|
||||
/**
|
||||
* Port on which the server is running
|
||||
*/
|
||||
@@ -21,14 +22,12 @@ public interface HttpServerStub {
|
||||
boolean isRunning();
|
||||
|
||||
/**
|
||||
* Starts the server on a random port. Should return itself
|
||||
* to allow chaining.
|
||||
* Starts the server on a random port. Should return itself to allow chaining.
|
||||
*/
|
||||
HttpServerStub start();
|
||||
|
||||
/**
|
||||
* Starts the server on a given port. Should return itself
|
||||
* to allow chaining.
|
||||
* Starts the server on a given port. Should return itself to allow chaining.
|
||||
*/
|
||||
HttpServerStub start(int port);
|
||||
|
||||
@@ -38,8 +37,15 @@ public interface HttpServerStub {
|
||||
HttpServerStub stop();
|
||||
|
||||
/**
|
||||
* Registers the stub files in the HTTP server stub. Should return itself
|
||||
* to allow chaining.
|
||||
* Resets the server. Should return itself to allow chaining.
|
||||
*/
|
||||
default HttpServerStub reset() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the stub files in the HTTP server stub. Should return itself to allow
|
||||
* chaining.
|
||||
*/
|
||||
HttpServerStub registerMappings(Collection<File> stubFiles);
|
||||
|
||||
|
||||
@@ -17,23 +17,16 @@
|
||||
|
||||
package org.springframework.cloud.contract.stubrunner.provider.wiremock;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.contract.stubrunner.HttpServerStub;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
import org.springframework.cloud.contract.wiremock.WireMockUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
|
||||
/**
|
||||
* Stops the {@link HttpServerStub} after each test class
|
||||
* Marks context to be restarted if at least one stub has a fixed port
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.2.6
|
||||
@@ -44,55 +37,24 @@ public final class StubRunnerWireMockTestExecutionListener
|
||||
private static final Log log = LogFactory
|
||||
.getLog(StubRunnerWireMockTestExecutionListener.class);
|
||||
|
||||
private static Map<ApplicationContext, Map<WireMockHttpServerStub, PortAndMappings>> STUBS = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(TestContext testContext) {
|
||||
if (testContext.getTestClass().getAnnotationsByType(AutoConfigureStubRunner.class).length == 0) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("No @AutoConfigureStubRunner annotation found on [" + testContext.getTestClass() + "]. Skipping");
|
||||
}
|
||||
return;
|
||||
}
|
||||
Map<WireMockHttpServerStub, PortAndMappings> stubs = STUBS
|
||||
.get(testContext.getApplicationContext());
|
||||
if (stubs != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a matching application context from ["
|
||||
+ testContext.getTestClass().getName() + "]");
|
||||
}
|
||||
for (Map.Entry<WireMockHttpServerStub, PortAndMappings> entry : stubs
|
||||
.entrySet()) {
|
||||
while (entry.getKey().isRunning()) {
|
||||
entry.getKey().stop();
|
||||
}
|
||||
List<StubMapping> mappings = entry.getValue().mappings;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stopped a running WireMock instance at " + "port ["
|
||||
+ entry.getValue().port + "] with stub mappings size ["
|
||||
+ mappings.size() + "]. Restarting the stub.");
|
||||
}
|
||||
entry.getKey().start(entry.getValue().port);
|
||||
entry.getKey().registerDescriptors(mappings);
|
||||
WireMockUtils.getMappingsEndpoint(entry.getValue().port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestClass(TestContext testContext) {
|
||||
if (testContext.getTestClass().getAnnotationsByType(AutoConfigureStubRunner.class).length == 0) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("No @AutoConfigureStubRunner annotation found on [" + testContext.getTestClass() + "]. Skipping");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No @AutoConfigureStubRunner annotation found on [" + testContext.getTestClass() + "]. Skipping");
|
||||
}
|
||||
return;
|
||||
}
|
||||
STUBS.put(testContext.getApplicationContext(), WireMockHttpServerStub.SERVERS);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stopping servers " + WireMockHttpServerStub.SERVERS);
|
||||
}
|
||||
for (HttpServerStub serverStub : WireMockHttpServerStub.SERVERS.keySet()) {
|
||||
serverStub.stop();
|
||||
if (WireMockHttpServerStub.SERVERS.values().stream().anyMatch(p -> !p.random)) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("You've used fixed ports for WireMock setup - "
|
||||
+ "will mark context as dirty. Please use random ports, as much "
|
||||
+ "as possible. Your tests will be faster and more reliable and this"
|
||||
+ "warning will go away");
|
||||
}
|
||||
testContext.markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE);
|
||||
}
|
||||
// potential race condition
|
||||
WireMockHttpServerStub.SERVERS.clear();
|
||||
}
|
||||
}
|
||||
@@ -68,9 +68,9 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
private WireMockServer wireMockServer;
|
||||
|
||||
private WireMockConfiguration config() {
|
||||
if (ClassUtils.isPresent("org.springframework.cloud.contract.wiremock.WireMockSpring", null)) {
|
||||
return WireMockSpring.options()
|
||||
.extensions(responseTransformers());
|
||||
if (ClassUtils.isPresent(
|
||||
"org.springframework.cloud.contract.wiremock.WireMockSpring", null)) {
|
||||
return WireMockSpring.options().extensions(responseTransformers());
|
||||
}
|
||||
return new WireMockConfiguration().extensions(responseTransformers());
|
||||
}
|
||||
@@ -83,7 +83,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
for (WireMockExtensions wireMockExtension : wireMockExtensions) {
|
||||
extensions.addAll(wireMockExtension.extensions());
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
extensions.add(new DefaultResponseTransformer(false, helpers()));
|
||||
}
|
||||
return extensions.toArray(new Extension[extensions.size()]);
|
||||
@@ -91,9 +92,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
|
||||
/**
|
||||
* Override this if you want to register your own helpers
|
||||
*
|
||||
* @deprecated - please use the {@link WireMockExtensions} mechanism and pass
|
||||
* the helpers in your implementation
|
||||
* @deprecated - please use the {@link WireMockExtensions} mechanism and pass the
|
||||
* helpers in your implementation
|
||||
*/
|
||||
@Deprecated
|
||||
protected Map<String, Helper> helpers() {
|
||||
@@ -121,23 +121,34 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return start(SocketUtils.findAvailableTcpPort());
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
HttpServerStub serverStub = start(port);
|
||||
cacheStubServer(true, port);
|
||||
return serverStub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServerStub start(int port) {
|
||||
this.wireMockServer = new WireMockServer(config().port(port)
|
||||
.notifier(new Slf4jNotifier(true)));
|
||||
this.wireMockServer = new WireMockServer(
|
||||
config().port(port).notifier(new Slf4jNotifier(true)));
|
||||
this.wireMockServer.start();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Started WireMock at port [" + port + "]");
|
||||
}
|
||||
if (!SERVERS.containsKey(this)) {
|
||||
SERVERS.put(this, new PortAndMappings(port, new ArrayList<>()));
|
||||
}
|
||||
cacheStubServer(false, port);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServerStub reset() {
|
||||
this.wireMockServer.resetAll();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void cacheStubServer(boolean random, int port) {
|
||||
SERVERS.put(this, new PortAndMappings(random, port, new ArrayList<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServerStub stop() {
|
||||
if (!isRunning()) {
|
||||
@@ -159,7 +170,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public String registeredMappings() {
|
||||
@Override
|
||||
public String registeredMappings() {
|
||||
Collection<String> mappings = new ArrayList<>();
|
||||
for (StubMapping stubMapping : this.wireMockServer.getStubMappings()) {
|
||||
mappings.add(stubMapping.toString());
|
||||
@@ -207,17 +219,19 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
try {
|
||||
stubMappings.add(registerDescriptor(wireMock, mappingDescriptor));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Registered stub mappings from [" + mappingDescriptor + "]");
|
||||
log.debug(
|
||||
"Registered stub mappings from [" + mappingDescriptor + "]");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to register the stub mapping [" + mappingDescriptor + "]", e);
|
||||
log.debug("Failed to register the stub mapping [" + mappingDescriptor
|
||||
+ "]", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
PortAndMappings portAndMappings = SERVERS.get(this);
|
||||
SERVERS.put(this, new PortAndMappings(portAndMappings.port, stubMappings));
|
||||
SERVERS.put(this, new PortAndMappings(portAndMappings.random, portAndMappings.port, stubMappings));
|
||||
}
|
||||
|
||||
private StubMapping registerDescriptor(WireMock wireMock, File mappingDescriptor) {
|
||||
@@ -228,7 +242,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
|
||||
void registerDescriptors(List<StubMapping> stubMappings) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Registering stub mappings size [" + stubMappings.size() + "] at port [" + port() + "]");
|
||||
log.debug("Registering stub mappings size [" + stubMappings.size()
|
||||
+ "] at port [" + port() + "]");
|
||||
}
|
||||
for (StubMapping mapping : stubMappings) {
|
||||
wireMock().register(mapping);
|
||||
@@ -240,21 +255,30 @@ public class WireMockHttpServerStub implements HttpServerStub {
|
||||
}
|
||||
|
||||
private void registerHealthCheck(WireMock wireMock, String url, String body) {
|
||||
wireMock.register(
|
||||
WireMock.get(WireMock.urlEqualTo(url)).willReturn(WireMock.aResponse().withBody(body).withStatus(200)));
|
||||
wireMock.register(WireMock.get(WireMock.urlEqualTo(url))
|
||||
.willReturn(WireMock.aResponse().withBody(body).withStatus(200)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PortAndMappings {
|
||||
|
||||
final boolean random;
|
||||
final Integer port;
|
||||
final List<StubMapping> mappings;
|
||||
|
||||
PortAndMappings(Integer port, List<StubMapping> mappings) {
|
||||
PortAndMappings(boolean random, Integer port, List<StubMapping> mappings) {
|
||||
this.random = random;
|
||||
this.port = port;
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "PortAndMappings{" + "port=" + this.port + ", mappings=" + this.mappings.size() + '}';
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PortAndMappings{" +
|
||||
"random=" + this.random +
|
||||
", port=" + this.port +
|
||||
", mappings=" + this.mappings +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class WireMockHttpServerStubSpec extends Specification {
|
||||
expect:
|
||||
"surprise!" == new RestTemplate().getForObject("http://localhost:" + mappingDescriptor.port() + "/ping", String.class)
|
||||
cleanup:
|
||||
mappingDescriptor.stop()
|
||||
mappingDescriptor?.stop()
|
||||
}
|
||||
|
||||
def 'should make WireMock print out logs on INFO'() {
|
||||
@@ -69,6 +69,6 @@ class WireMockHttpServerStubSpec extends Specification {
|
||||
capture.toString().contains("Matched response definition")
|
||||
|
||||
cleanup:
|
||||
mappingDescriptor.stop()
|
||||
mappingDescriptor?.stop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.springframework.util.SocketUtils
|
||||
|
||||
class DslToWireMockClientConverterSpec extends Specification {
|
||||
|
||||
static int port = SocketUtils.findAvailableTcpPort()
|
||||
int port = SocketUtils.findAvailableTcpPort()
|
||||
@Rule public WireMockRule wireMockRule = new WireMockRule(port)
|
||||
@Rule public TemporaryFolder tmpFolder = new TemporaryFolder()
|
||||
TestRestTemplate restTemplate = new TestRestTemplate()
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class MvcTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setupTest() throws Exception {
|
||||
int port = findAvailableTcpPort(8000);
|
||||
int port = findAvailableTcpPort(10000);
|
||||
URI baseUri = UriBuilder.fromUri("http://localhost").port(port).build();
|
||||
// Create Server
|
||||
Server server = new Server(port);
|
||||
|
||||
@@ -183,13 +183,13 @@ class JavaTestGenerator implements SingleTestGenerator {
|
||||
|
||||
class ClassPresenceChecker {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass())
|
||||
private static final Log log = LogFactory.getLog(ClassPresenceChecker)
|
||||
|
||||
boolean isClassPresent(String className) {
|
||||
try {
|
||||
Class.forName(className)
|
||||
return true
|
||||
} catch (ClassNotFoundException e) {
|
||||
} catch (ClassNotFoundException ex) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("[${className}] is not present on classpath. Will not add a static import.")
|
||||
}
|
||||
|
||||
@@ -16,18 +16,17 @@
|
||||
|
||||
package org.springframework.cloud.contract.verifier.builder
|
||||
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import spock.lang.Issue
|
||||
import spock.lang.Specification
|
||||
|
||||
import org.springframework.cloud.contract.verifier.TestGenerator
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
import org.springframework.cloud.contract.verifier.config.TestMode
|
||||
import org.springframework.cloud.contract.verifier.file.ContractMetadata
|
||||
import org.springframework.cloud.contract.verifier.util.SyntaxChecker
|
||||
import org.springframework.util.FileSystemUtils
|
||||
import org.springframework.util.StringUtils
|
||||
import spock.lang.Issue
|
||||
import spock.lang.Specification
|
||||
|
||||
import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT
|
||||
import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK
|
||||
@@ -184,7 +183,7 @@ class SingleTestGeneratorSpec extends Specification {
|
||||
SPOCK | TestMode.EXPLICIT | GROOVY_ASSERTER | "ContractsSpec.groovy"
|
||||
}
|
||||
|
||||
def "should build test class for #testFramework with Rest Assured 2.x"() {
|
||||
def "should build test class for #testFramework with Rest Assured 2x"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
|
||||
properties.targetFramework = testFramework
|
||||
|
||||
@@ -77,7 +77,7 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
@Autowired
|
||||
private WireMockProperties wireMock;
|
||||
WireMockProperties wireMock;
|
||||
|
||||
@Autowired
|
||||
private ResourceLoader resourceLoader;
|
||||
@@ -100,6 +100,11 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
}
|
||||
}
|
||||
if (this.server == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Creating a new server at "
|
||||
+ "http port [" + this.wireMock.getServer().getPort() + "] and "
|
||||
+ "https port [" + this.wireMock.getServer().getHttpsPort() + "]");
|
||||
}
|
||||
this.server = new WireMockServer(this.options);
|
||||
}
|
||||
registerStubs();
|
||||
@@ -126,21 +131,23 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
}
|
||||
for (Resource resource : resolver.getResources(pattern)) {
|
||||
this.server.addStubMapping(WireMockStubMapping
|
||||
.buildFrom(StreamUtils.copyToString(resource.getInputStream(), Charset.forName("UTF-8"))));
|
||||
.buildFrom(StreamUtils.copyToString(resource.getInputStream(),
|
||||
Charset.forName("UTF-8"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int port() {
|
||||
return this.server.port();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resetting stubs");
|
||||
}
|
||||
this.server.resetAll();
|
||||
}
|
||||
|
||||
private void registerFiles(com.github.tomakehurst.wiremock.core.WireMockConfiguration factory) throws IOException {
|
||||
private void registerFiles(
|
||||
com.github.tomakehurst.wiremock.core.WireMockConfiguration factory)
|
||||
throws IOException {
|
||||
List<Resource> resources = new ArrayList<>();
|
||||
for (String files : this.wireMock.getServer().getFiles()) {
|
||||
if (StringUtils.hasText(files)) {
|
||||
@@ -154,31 +161,46 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
}
|
||||
}
|
||||
if (!resources.isEmpty()) {
|
||||
ResourcesFileSource fileSource = new ResourcesFileSource(resources.toArray(new Resource[0]));
|
||||
ResourcesFileSource fileSource = new ResourcesFileSource(
|
||||
resources.toArray(new Resource[0]));
|
||||
factory.fileSource(fileSource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (isRunning()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Server is already running");
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.server.start();
|
||||
WireMock.configureFor("localhost", this.server.port());
|
||||
updateCurrentServer();
|
||||
}
|
||||
|
||||
private void updateCurrentServer() {
|
||||
WireMock.configureFor(new WireMock(this.server));
|
||||
this.running = true;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Started WireMock at port [" + this.server.port() + "]. It has [" + this.server.getStubMappings().size() + "] mappings registered");
|
||||
log.debug("Started WireMock at port [" + this.server.port() + "]. It has ["
|
||||
+ this.server.getStubMappings().size() + "] mappings registered");
|
||||
}
|
||||
WireMockUtils.getMappingsEndpoint(this.port());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.running) {
|
||||
reset();
|
||||
this.server.shutdownServer();
|
||||
this.server.stop();
|
||||
this.server = null;
|
||||
this.running = false;
|
||||
this.options = null;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Stopped WireMock instance");
|
||||
}
|
||||
this.beanFactory.destroySingleton(WIREMOCK_SERVER_BEAN_NAME);
|
||||
} else if (log.isDebugEnabled()) {
|
||||
log.debug("Server already stopped");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +224,6 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConfigurationProperties("wiremock")
|
||||
@@ -269,6 +290,7 @@ class WireMockProperties {
|
||||
public void setFiles(String[] files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,12 @@ package org.springframework.cloud.contract.wiremock;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
|
||||
/**
|
||||
* Stops the WireMock server after each test class and restarts it before every class
|
||||
* Dirties the test context if WireMock was running on a fixed port
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.2.6
|
||||
@@ -33,59 +34,51 @@ public final class WireMockTestExecutionListener extends AbstractTestExecutionLi
|
||||
|
||||
private static final Log log = LogFactory.getLog(WireMockTestExecutionListener.class);
|
||||
|
||||
@Override public void beforeTestClass(TestContext testContext) {
|
||||
try {
|
||||
if (wireMockConfigMissing(testContext)) {
|
||||
return;
|
||||
}
|
||||
WireMockConfiguration wireMockConfiguration = wireMockConfiguration(testContext);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("WireMock configuration is running [" + wireMockConfiguration.isRunning() + "]");
|
||||
}
|
||||
if (!wireMockConfiguration.isRunning()) {
|
||||
wireMockConfiguration.init();
|
||||
wireMockConfiguration.start();
|
||||
WireMockUtils.getMappingsEndpoint(wireMockConfiguration.port());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exception occurred while trying to init WireMock configuration", e);
|
||||
@Override
|
||||
public void afterTestClass(TestContext testContext) {
|
||||
if (wireMockConfigurationMissing(testContext) || annotationMissing(testContext)) {
|
||||
return;
|
||||
}
|
||||
if (portIsFixed(testContext)) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("You've used fixed ports for WireMock setup - "
|
||||
+ "will mark context as dirty. Please use random ports, as much "
|
||||
+ "as possible. Your tests will be faster and more reliable and this"
|
||||
+ "warning will go away");
|
||||
}
|
||||
testContext.markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean wireMockConfigMissing(TestContext testContext) {
|
||||
boolean missing = !testContext.getApplicationContext().containsBean(WireMockConfiguration.class.getName());
|
||||
private boolean annotationMissing(TestContext testContext) {
|
||||
if (testContext.getTestClass()
|
||||
.getAnnotationsByType(AutoConfigureWireMock.class).length == 0) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No @AutoConfigureWireMock annotation found on [" + testContext
|
||||
.getTestClass() + "]. Skipping");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean wireMockConfigurationMissing(TestContext testContext) {
|
||||
boolean missing = !testContext.getApplicationContext()
|
||||
.containsBean(WireMockConfiguration.class.getName());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("WireMockConfig is missing [" + missing + "]");
|
||||
log.debug("WireMockConfiguration is missing [" + missing + "]");
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
@Override public void afterTestClass(TestContext testContext) {
|
||||
try {
|
||||
if (wireMockConfigMissing(testContext)) {
|
||||
return;
|
||||
}
|
||||
stopWireMockConfiguration(testContext);
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exception occurred while trying to init WireMock configuration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopWireMockConfiguration(TestContext testContext) {
|
||||
WireMockConfiguration wireMockConfiguration = wireMockConfiguration(testContext);
|
||||
if (wireMockConfiguration.isRunning()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("WireMock is running, will stop it");
|
||||
}
|
||||
wireMockConfiguration.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private WireMockConfiguration wireMockConfiguration(TestContext testContext) {
|
||||
private WireMockConfiguration wireMockConfig(TestContext testContext) {
|
||||
return testContext.getApplicationContext().getBean(WireMockConfiguration.class);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean portIsFixed(TestContext testContext) {
|
||||
WireMockConfiguration wireMockProperties = wireMockConfig(testContext);
|
||||
int httpPort = wireMockProperties.wireMock.getServer().getPort();
|
||||
int httpsPort = wireMockProperties.wireMock.getServer().getHttpsPort();
|
||||
return (httpPort != 0 || httpsPort != -1) && httpsPort != 0;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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.wiremock;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility class to work with WireMock.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.3
|
||||
*/
|
||||
public final class WireMockUtils {
|
||||
|
||||
private WireMockUtils() {
|
||||
throw new IllegalStateException("Don't instantiate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Thanks to Tom Akehurst: I looked at tcpdump while running the failing
|
||||
* test. HttpUrlConnection is doing something weird - it's creating a
|
||||
* connection in a previous test case, which works fine, then the usual
|
||||
* fin -> fin ack etc. etc. ending handshake happens. But it seems it
|
||||
* isn't discarded, but reused after that. Because the server thinks
|
||||
* (rightly) that the connection is closed, it just sends a RST packet.
|
||||
* Calling the admin endpoint just happened to remove the dead connection
|
||||
* from the pool. This also fixes the problem (which using the Java HTTP
|
||||
* client): System.setProperty("http.keepAlive", "false");
|
||||
**/
|
||||
public static CloseableHttpResponse getMappingsEndpoint(int port) {
|
||||
CloseableHttpClient client = HttpClientBuilder.create().build();
|
||||
try {
|
||||
CloseableHttpResponse response = client
|
||||
.execute(new HttpHost("localhost", port), new HttpGet("/__admin/mappings"));
|
||||
Assert.isTrue(response.getStatusLine().getStatusCode() == 200, "Status code must be 200");
|
||||
return response;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
package org.springframework.cloud.contract.wiremock;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment=WebEnvironment.NONE)
|
||||
@SpringBootTest(classes = WiremockTestsApplication.class,
|
||||
properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port = 12345)
|
||||
public class AutoConfigureWireMockApplicationTests {
|
||||
|
||||
@@ -25,8 +25,8 @@ public class AutoConfigureWireMockApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws Exception {
|
||||
stubFor(get(urlEqualTo("/test"))
|
||||
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
stubFor(get(urlEqualTo("/test")).willReturn(aResponse()
|
||||
.withHeader("Content-Type", "text/plain").withBody("Hello World!")));
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package org.springframework.cloud.contract.wiremock;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment=WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port=0)
|
||||
@SpringBootTest(classes = WiremockTestsApplication.class,
|
||||
properties = "app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment = WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
// Default stubs work at classpath:/mappings
|
||||
public class AutoConfigureWireMockAutoStubsApplicationTests {
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
package org.springframework.cloud.contract.wiremock;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=https://localhost:${wiremock.server.https-port}", webEnvironment=WebEnvironment.NONE)
|
||||
@AutoConfigureWireMock(port=0, httpsPort=0)
|
||||
@@ -28,4 +29,4 @@ public class AutoConfigureWireMockRandomPortHttpsApplicationTests {
|
||||
assertThat(this.service.go()).isEqualTo("Hello World!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import com.github.tomakehurst.wiremock.stubbing.StubMapping;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import wiremock.org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||
@@ -21,7 +22,6 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -32,8 +32,6 @@ import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.docu
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import wiremock.org.eclipse.jetty.http.HttpStatus;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = TestConfiguration.class)
|
||||
@AutoConfigureRestDocs(outputDir = "target/snippets")
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.springframework.cloud.contract.wiremock;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import org.junit.ComparisonFailure;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
@@ -23,8 +25,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = TestConfiguration.class)
|
||||
@AutoConfigureRestDocs(outputDir = "target/snippets")
|
||||
|
||||
Reference in New Issue
Block a user