From eb691717a20fbbf6928bb18a24a72f8ac42ee310 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 26 Jul 2016 12:28:18 +0100 Subject: [PATCH] Add support for automatically registering stubs in @AutoConfigureWireMock --- .../standalone/restdocs/http-client/pom.xml | 5 + .../example/loan/LoanApplicationService.java | 2 + .../loan/LoanApplicationServiceTests.java | 10 +- .../test/resources/application-test-repo.yaml | 3 - .../src/test/resources/application.yaml | 3 - spring-cloud-contract-wiremock/pom.xml | 5 + .../wiremock/AutoConfigureWireMock.java | 2 + .../wiremock/WireMockConfiguration.java | 110 +++++++++++++----- .../wiremock/WireMockExpectations.java | 2 +- ...onfigureWireMockStubsApplicationTests.java | 27 +++++ .../{stubs => mappings}/resource.json | 0 11 files changed, 126 insertions(+), 43 deletions(-) delete mode 100644 samples/standalone/restdocs/http-client/src/test/resources/application-test-repo.yaml delete mode 100644 samples/standalone/restdocs/http-client/src/test/resources/application.yaml create mode 100644 spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java rename spring-cloud-contract-wiremock/src/test/resources/{stubs => mappings}/resource.json (100%) diff --git a/samples/standalone/restdocs/http-client/pom.xml b/samples/standalone/restdocs/http-client/pom.xml index d238266617..62759e90b3 100644 --- a/samples/standalone/restdocs/http-client/pom.xml +++ b/samples/standalone/restdocs/http-client/pom.xml @@ -57,6 +57,11 @@ org.springframework.boot spring-boot-starter-activemq + + org.springframework.boot + spring-boot-configuration-processor + true + diff --git a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java index 33cd026aac..6c5d0861f5 100644 --- a/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java +++ b/samples/standalone/restdocs/http-client/src/main/java/com/example/loan/LoanApplicationService.java @@ -1,5 +1,6 @@ package com.example.loan; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -15,6 +16,7 @@ import com.example.loan.model.LoanApplicationResult; import com.example.loan.model.LoanApplicationStatus; @Service +@ConfigurationProperties("service") public class LoanApplicationService { private static final String FRAUD_SERVICE_JSON_VERSION_1 = diff --git a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java b/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java index 92dda26732..fef4e71669 100644 --- a/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java +++ b/samples/standalone/restdocs/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java @@ -22,12 +22,12 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.stubbing.StubMapping; @RunWith(SpringRunner.class) -@SpringBootTest -@AutoConfigureWireMock +@SpringBootTest(properties="service.port=${wiremock.server.port}") +@AutoConfigureWireMock(port=0) public class LoanApplicationServiceTests { @Autowired - private LoanApplicationService sut; + private LoanApplicationService service; @Value("classpath:META-INF/com.example/http-server-restdocs/0.0.1-SNAPSHOT/mappings/markClientAsFraud.json") private Resource markClientAsFraud; @@ -46,7 +46,7 @@ public class LoanApplicationServiceTests { LoanApplication application = new LoanApplication(new Client("1234567890"), 123.123); // when: - LoanApplicationResult loanApplication = sut.loanApplication(application); + LoanApplicationResult loanApplication = service.loanApplication(application); // then: assertThat(loanApplication.getLoanApplicationStatus()) .isEqualTo(LoanApplicationStatus.LOAN_APPLIED); @@ -61,7 +61,7 @@ public class LoanApplicationServiceTests { LoanApplication application = new LoanApplication(new Client("1234567890"), 99999); // when: - LoanApplicationResult loanApplication = sut.loanApplication(application); + LoanApplicationResult loanApplication = service.loanApplication(application); // then: assertThat(loanApplication.getLoanApplicationStatus()) .isEqualTo(LoanApplicationStatus.LOAN_APPLICATION_REJECTED); diff --git a/samples/standalone/restdocs/http-client/src/test/resources/application-test-repo.yaml b/samples/standalone/restdocs/http-client/src/test/resources/application-test-repo.yaml deleted file mode 100644 index 2ac488ce08..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/resources/application-test-repo.yaml +++ /dev/null @@ -1,3 +0,0 @@ -stubrunner.stubs: - ids: 'com.example:http-server:+:stubs:8080' - repositoryRoot: http://repo.spring.io/libs-snapshot diff --git a/samples/standalone/restdocs/http-client/src/test/resources/application.yaml b/samples/standalone/restdocs/http-client/src/test/resources/application.yaml deleted file mode 100644 index b260e2bac4..0000000000 --- a/samples/standalone/restdocs/http-client/src/test/resources/application.yaml +++ /dev/null @@ -1,3 +0,0 @@ -stubrunner: - work-offline: true - stubs.ids: 'com.example:http-server:+:stubs:8080' \ No newline at end of file diff --git a/spring-cloud-contract-wiremock/pom.xml b/spring-cloud-contract-wiremock/pom.xml index a1f9205a69..d611bac3e0 100644 --- a/spring-cloud-contract-wiremock/pom.xml +++ b/spring-cloud-contract-wiremock/pom.xml @@ -59,5 +59,10 @@ assertj-core compile + + org.springframework.boot + spring-boot-configuration-processor + true + diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java index c81e4fb5a4..ff47a6c607 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMock.java @@ -39,5 +39,7 @@ public @interface AutoConfigureWireMock { int port() default 8080; int httpsPort() default -1; + + String stubs() default ""; } diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java index ca6dab5bc1..0ec8547b58 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockConfiguration.java @@ -16,27 +16,35 @@ package org.springframework.cloud.contract.wiremock; +import java.io.IOException; +import java.nio.charset.Charset; + import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.SmartLifecycle; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportAware; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.util.StreamUtils; +import org.springframework.util.StringUtils; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.core.Options; +import com.github.tomakehurst.wiremock.stubbing.StubMapping; /** * @author Dave Syer * */ @Configuration -public class WireMockConfiguration implements SmartLifecycle, ImportAware { +@EnableConfigurationProperties(WireMockProperties.class) +public class WireMockConfiguration implements SmartLifecycle { private volatile boolean running; @@ -45,47 +53,53 @@ public class WireMockConfiguration implements SmartLifecycle, ImportAware { @Autowired(required = false) private Options options; - @Value("${wiremock.server.port:8080}") - private int port = 8080; - - @Value("${wiremock.server.https-port:-1}") - private int httpsPort = -1; - @Autowired private DefaultListableBeanFactory beanFactory; - - @Override - public void setImportMetadata(AnnotationMetadata metadata) { - AnnotationAttributes map = AnnotationAttributes.fromMap( - metadata.getAnnotationAttributes(AutoConfigureWireMock.class.getName())); - int port = map.getNumber("port").intValue(); - if (port > 0) { - this.port = port; - } - int httpsPort = map.getNumber("httpsPort").intValue(); - if (httpsPort > 0) { - this.httpsPort = httpsPort; - } - } + + @Autowired + private WireMockProperties wireMock; + + @Autowired + private ResourceLoader resourceLoader; @PostConstruct - public void init() { + public void init() throws IOException { if (options == null) { - com.github.tomakehurst.wiremock.core.WireMockConfiguration factory = WireMockSpring.options(); - if (port != 8080) { - factory.port(port); + com.github.tomakehurst.wiremock.core.WireMockConfiguration factory = WireMockSpring + .options(); + if (wireMock.getPort() != 8080) { + factory.port(wireMock.getPort()); } - if (httpsPort != -1) { - factory.httpsPort(httpsPort); + if (wireMock.getHttpsPort() != -1) { + factory.httpsPort(wireMock.getHttpsPort()); } this.options = factory; } server = new WireMockServer(options); + registerStubs(); if (!beanFactory.containsBean("wireMockServer")) { beanFactory.registerSingleton("wireMockServer", server); } } + private void registerStubs() throws IOException { + if (StringUtils.hasText(wireMock.getStubs())) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( + resourceLoader); + String pattern = wireMock.getStubs(); + if (!pattern.contains("*")) { + if (!pattern.endsWith("/")) { + pattern = pattern + "/"; + } + pattern = pattern + "**/*.json"; + } + for (Resource resource : resolver.getResources(pattern)) { + server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString( + resource.getInputStream(), Charset.forName("UTF-8")))); + } + } + } + @Override public void start() { server.start(); @@ -123,3 +137,37 @@ public class WireMockConfiguration implements SmartLifecycle, ImportAware { } } + +@ConfigurationProperties("wiremock.server") +class WireMockProperties { + private int port = 8080; + + private int httpsPort = -1; + + private String stubs; + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public int getHttpsPort() { + return httpsPort; + } + + public void setHttpsPort(int httpsPort) { + this.httpsPort = httpsPort; + } + + public String getStubs() { + return stubs; + } + + public void setStubs(String stubs) { + this.stubs = stubs; + } + +} \ No newline at end of file diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java index c82a00beff..d764ed5aba 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/WireMockExpectations.java @@ -40,7 +40,7 @@ public class WireMockExpectations { private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - private String prefix = "classpath:/stubs/"; + private String prefix = "classpath:/mappings/"; private String suffix = ".json"; diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java new file mode 100644 index 0000000000..e5e5b6e238 --- /dev/null +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockStubsApplicationTests.java @@ -0,0 +1,27 @@ +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.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes=WiremockTestsApplication.class, properties="app.baseUrl=http://localhost:${wiremock.server.port}", webEnvironment=WebEnvironment.NONE) +@DirtiesContext +@AutoConfigureWireMock(port=0, stubs="file:src/test/resources/mappings") +public class AutoConfigureWireMockStubsApplicationTests { + + @Autowired + private Service service; + + @Test + public void contextLoads() throws Exception { + assertThat(this.service.go()).isEqualTo("Hello World"); + } + +} diff --git a/spring-cloud-contract-wiremock/src/test/resources/stubs/resource.json b/spring-cloud-contract-wiremock/src/test/resources/mappings/resource.json similarity index 100% rename from spring-cloud-contract-wiremock/src/test/resources/stubs/resource.json rename to spring-cloud-contract-wiremock/src/test/resources/mappings/resource.json