Removed dirties context on any tests

This commit is contained in:
Marcin Grzejszczak
2018-08-08 18:00:58 +02:00
73 changed files with 343 additions and 113 deletions

View File

@@ -148,14 +148,6 @@ HTTP stubs without the need to download artifacts.
==== Running stubs
===== Limitations
IMPORTANT: There might be a problem with StubRunner shutting down ports between tests. You might
have a situation in which you get port conflicts. As long as you use the same context across tests
everything works fine. But when the context are different (e.g. different stubs or different profiles)
then you have to either use `@DirtiesContext` to shut down the stub servers, or else run them on
different ports per test.
===== Running using main app
You can set the following options to the main class:

View File

@@ -82,6 +82,11 @@
<groupId>com.jcraft</groupId>
<artifactId>jsch.agentproxy.usocket-jna</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>

View File

@@ -25,6 +25,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import groovy.json.JsonOutput;
import org.slf4j.Logger;
@@ -38,12 +39,15 @@ 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}
*/
class StubRunnerExecutor implements StubFinder {
static final Set<StubServer> STUB_SERVERS = new ConcurrentHashSet<>();
private static final Logger log = LoggerFactory.getLogger(StubRunnerExecutor.class);
private final AvailablePortScanner portScanner;
private final MessageVerifier<?> contractVerifierMessaging;
@@ -261,6 +265,7 @@ class StubRunnerExecutor implements StubFinder {
}
});
}
STUB_SERVERS.add(this.stubServer);
}
private boolean hasRequest(Collection<Contract> contracts) {

View File

@@ -20,6 +20,7 @@ import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,7 +60,14 @@ class StubServer {
return this;
}
public boolean isRunning() {
return this.httpServerStub.isRunning();
}
public void stop() {
if (log.isDebugEnabled()) {
log.debug("Stopping the server at port [" + this.getPort() + "]");
}
this.httpServerStub.stop();
}
@@ -95,4 +103,22 @@ class StubServer {
return this.httpServerStub.registeredMappings();
}
@Override public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
StubServer that = (StubServer) o;
return Objects.equals(this.stubConfiguration, that.stubConfiguration) && Objects
.equals(this.contracts, that.contracts);
}
@Override public int hashCode() {
return Objects.hash(this.stubConfiguration, this.contracts);
}
@Override public String toString() {
return "StubServer{" + "stubConfiguration=" + this.stubConfiguration + ", mappingsSize="
+ this.mappings.size() + '}';
}
}

View File

@@ -0,0 +1,63 @@
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.context.ApplicationContext;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
/**
* Stops the {@link HttpServerStub} after each test class
*
* @author Marcin Grzejszczak
* @since 1.2.6
*/
public final class StubRunnerWireMockTestExecutionListener extends AbstractTestExecutionListener {
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) {
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);
Assert.isTrue(new RestTemplate().getForEntity("http://localhost:" + entry.getValue().port + "/__admin/mappings", String.class)
.getStatusCode().is2xxSuccessful(), "__admin/mappings endpoint wasn't accessible");
}
}
}
@Override public void afterTestClass(TestContext testContext) {
STUBS.put(testContext.getApplicationContext(), WireMockHttpServerStub.SERVERS);
if (log.isDebugEnabled()) {
log.debug("Stopping servers " + WireMockHttpServerStub.SERVERS);
}
for (HttpServerStub serverStub : WireMockHttpServerStub.SERVERS.keySet()) {
serverStub.stop();
}
}
}

View File

@@ -10,6 +10,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
@@ -43,6 +44,8 @@ public class WireMockHttpServerStub implements HttpServerStub {
private static final Logger log = LoggerFactory.getLogger(WireMockHttpServerStub.class);
private static final int INVALID_PORT = -1;
static final Map<WireMockHttpServerStub, PortAndMappings> SERVERS = new ConcurrentHashMap<>();
private WireMockServer wireMockServer;
private WireMockConfiguration config() {
@@ -107,6 +110,12 @@ public class WireMockHttpServerStub implements HttpServerStub {
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<StubMapping>()));
}
return this;
}
@@ -159,20 +168,25 @@ public class WireMockHttpServerStub implements HttpServerStub {
}
private void registerStubMappings(Collection<File> stubFiles) {
WireMock wireMock = new WireMock("localhost", port(), "");
WireMock wireMock = wireMock();
registerDefaultHealthChecks(wireMock);
registerStubs(stubFiles, wireMock);
}
private WireMock wireMock() {
return new WireMock("localhost", port(), "");
}
private void registerDefaultHealthChecks(WireMock wireMock) {
registerHealthCheck(wireMock, "/ping");
registerHealthCheck(wireMock, "/health");
}
private void registerStubs(Collection<File> sortedMappings, WireMock wireMock) {
List<StubMapping> stubMappings = new ArrayList<>();
for (File mappingDescriptor : sortedMappings) {
try {
wireMock.register(getMapping(mappingDescriptor));
stubMappings.add(registerDescriptor(wireMock, mappingDescriptor));
if (log.isDebugEnabled()) {
log.debug("Registered stub mappings from [" + mappingDescriptor + "]");
}
@@ -183,6 +197,23 @@ public class WireMockHttpServerStub implements HttpServerStub {
}
}
}
PortAndMappings portAndMappings = SERVERS.get(this);
SERVERS.put(this, new PortAndMappings(portAndMappings.port, stubMappings));
}
private StubMapping registerDescriptor(WireMock wireMock, File mappingDescriptor) {
StubMapping mapping = getMapping(mappingDescriptor);
wireMock.register(mapping);
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) {
@@ -194,3 +225,17 @@ public class WireMockHttpServerStub implements HttpServerStub {
WireMock.get(WireMock.urlEqualTo(url)).willReturn(WireMock.aResponse().withBody(body).withStatus(200)));
}
}
class PortAndMappings {
final Integer port;
final List<StubMapping> mappings;
PortAndMappings(Integer port, List<StubMapping> mappings) {
this.port = port;
this.mappings = mappings;
}
@Override public String toString() {
return "PortAndMappings{" + "port=" + this.port + ", mappings=" + this.mappings.size() + '}';
}
}

View File

@@ -8,4 +8,8 @@ org.springframework.cloud.contract.stubrunner.messaging.integration.StubRunnerIn
org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper.StubRunnerSpringCloudZookeeperAutoConfiguration,\
org.springframework.cloud.contract.stubrunner.spring.cloud.eureka.StubRunnerSpringCloudEurekaAutoConfiguration,\
org.springframework.cloud.contract.stubrunner.spring.cloud.consul.StubRunnerSpringCloudConsulAutoConfiguration,\
org.springframework.cloud.contract.stubrunner.messaging.StubRunnerStreamsIntegrationAutoConfiguration
org.springframework.cloud.contract.stubrunner.messaging.StubRunnerStreamsIntegrationAutoConfiguration
# Test Execution Listeners
org.springframework.test.context.TestExecutionListener=\
org.springframework.cloud.contract.stubrunner.provider.wiremock.StubRunnerWireMockTestExecutionListener

View File

@@ -29,7 +29,6 @@ import org.springframework.cloud.contract.stubrunner.StubFinder
import org.springframework.cloud.contract.stubrunner.StubNotFoundException
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
@@ -44,7 +43,6 @@ import spock.lang.Specification
'foo=${stubrunner.runningstubs.fraudDetectionServer.port}',
'fooWithGroup=${stubrunner.runningstubs.org.springframework.cloud.contract.verifier.stubs.fraudDetectionServer.port}'])
@AutoConfigureStubRunner(mappingsOutputFolder = "target/outputmappings/")
@DirtiesContext
@ActiveProfiles("test")
class StubRunnerConfigurationSpec extends Specification {

View File

@@ -31,7 +31,6 @@ import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration
import org.springframework.cloud.zookeeper.discovery.RibbonZookeeperAutoConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration
import org.springframework.web.client.RestTemplate
@@ -50,7 +49,6 @@ import spock.lang.Specification
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "classpath:m2repo/repository/")
// end::autoconfigure[]
@DirtiesContext
class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
@Autowired StubFinder stubFinder

View File

@@ -33,7 +33,6 @@ import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import org.springframework.http.ResponseEntity
import org.springframework.messaging.Message
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
/**
* @author Marcin Grzejszczak
@@ -45,7 +44,6 @@ import org.springframework.test.context.ContextConfiguration
repositoryRoot = "classpath:m2repo/repository/",
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
stubsPerConsumer = true)
@DirtiesContext
class StubRunnerStubsPerConsumerSpec extends Specification {
// end::test[]

View File

@@ -33,7 +33,6 @@ import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import org.springframework.http.ResponseEntity
import org.springframework.messaging.Message
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
/**
* @author Marcin Grzejszczak
@@ -46,7 +45,6 @@ import org.springframework.test.context.ContextConfiguration
consumerName = "foo-consumer",
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
stubsPerConsumer = true)
@DirtiesContext
class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification {
// end::test[]

View File

@@ -33,7 +33,6 @@ import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRun
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
import static org.mockito.BDDMockito.then
@@ -58,7 +57,6 @@ import static org.mockito.Mockito.mock
"org.springframework.cloud.contract.verifier.stubs:bootService"],
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "classpath:m2repo/repository/")
@DirtiesContext
class StubRunnerSpringCloudConsulAutoConfigurationSpec extends Specification {
@Autowired ConsulClient client

View File

@@ -47,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
maxPort = 10020,
mappingsOutputFolder = "target/outputmappings/",
properties = {"hello=world", "foo=bar"})
@DirtiesContext
@ActiveProfiles("test")
public class StubRunnerSliceTests {