diff --git a/spring-cloud-contract-wiremock/pom.xml b/spring-cloud-contract-wiremock/pom.xml index b9b983d31b..32fcd19c98 100644 --- a/spring-cloud-contract-wiremock/pom.xml +++ b/spring-cloud-contract-wiremock/pom.xml @@ -84,5 +84,18 @@ spring-cloud-contract-verifier test + + io.spring.initializr + initializr-web + 0.4.0.BUILD-SNAPSHOT + stubs + test + + + * + * + + + 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 a0fbb21622..92e3caef6f 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,13 +16,17 @@ package org.springframework.cloud.contract.wiremock; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import com.github.tomakehurst.wiremock.common.Slf4jNotifier; +import com.github.tomakehurst.wiremock.core.Options; + import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; -import com.github.tomakehurst.wiremock.common.Slf4jNotifier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -36,10 +40,6 @@ 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; - /** * Configuration and lifecycle for a Spring Application context that wants to run a * WireMock server. Can be used by adding @@ -120,7 +120,7 @@ public class WireMockConfiguration implements SmartLifecycle { private void registerFiles(com.github.tomakehurst.wiremock.core.WireMockConfiguration factory) throws IOException { List resources = new ArrayList<>(); - for (String files : this.wireMock.getServer().getFiles()) { + for (String files : this.wireMock.getServer().getFiles()) { if (StringUtils.hasText(files)) { PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver( this.resourceLoader); diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java index b83f90ff74..64228f8d04 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/file/ResourcesFileSource.java @@ -16,22 +16,25 @@ package org.springframework.cloud.contract.wiremock.file; +import com.github.tomakehurst.wiremock.common.BinaryFile; +import com.github.tomakehurst.wiremock.common.ClasspathFileSource; +import com.github.tomakehurst.wiremock.common.FileSource; +import com.github.tomakehurst.wiremock.common.SingleRootFileSource; +import com.github.tomakehurst.wiremock.common.TextFile; + import java.io.File; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; -import com.github.tomakehurst.wiremock.common.BinaryFile; -import com.github.tomakehurst.wiremock.common.ClasspathFileSource; -import com.github.tomakehurst.wiremock.common.FileSource; -import com.github.tomakehurst.wiremock.common.SingleRootFileSource; -import com.github.tomakehurst.wiremock.common.TextFile; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; +import static java.util.Arrays.asList; + /** * @author Dave Syer * @author Pei-Tang Huang @@ -61,8 +64,7 @@ public class ResourcesFileSource implements FileSource { sources[i] = new SingleRootFileSource(files.getFile()); } else if (resource instanceof UrlResource) { - UrlResource files = (UrlResource) resource; - sources[i] = new SingleRootFileSource(getFile(files)); + sources[i] = fileOrFallbackToClasspath(resource); } else { throw new IllegalArgumentException("Unsupported resource type for file source: " + resource.getClass()); @@ -71,9 +73,31 @@ public class ResourcesFileSource implements FileSource { return sources; } - private static File getFile(UrlResource files) { + private static FileSource fileOrFallbackToClasspath(Resource resource) { + UrlResource file = (UrlResource) resource; try { - return files.getFile(); + URI uri = file.getURI(); + if (compressedResource(uri)) { + return new ClasspathFileSource(pathFromCompressed(uri)); + } + return new SingleRootFileSource(getFile(file)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private static String pathFromCompressed(URI pathUri) { + String path = pathUri.getSchemeSpecificPart().split("!")[1]; + return path.startsWith("/") ? path.substring(1) : path; + } + + private static boolean compressedResource(URI pathUri) { + return asList("jar", "war", "ear", "zip").contains(pathUri.getScheme()); + } + + private static File getFile(UrlResource file) { + try { + return file.getFile(); } catch (IOException e) { throw new IllegalStateException(e); @@ -199,4 +223,4 @@ public class ResourcesFileSource implements FileSource { } -} +} \ No newline at end of file diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java index 25bbb9626f..59dd320804 100644 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/AutoConfigureWireMockFilesApplicationWithUrlResourceTests.java @@ -13,7 +13,8 @@ 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) @DirtiesContext -@AutoConfigureWireMock(port=0, files="classpath*:root") +// resource from a Initilizr stubs jar +@AutoConfigureWireMock(port=0, files="classpath*:META-INF/io.spring.initializr/initializr-web/0.4.0.BUILD-SNAPSHOT") public class AutoConfigureWireMockFilesApplicationWithUrlResourceTests { @Autowired @@ -21,7 +22,7 @@ public class AutoConfigureWireMockFilesApplicationWithUrlResourceTests { @Test public void contextLoads() throws Exception { - assertThat(this.service.go()).isEqualTo("{\"message\":\"Hello Root\"}"); + assertThat(this.service.pom()).contains("spring-boot-starter-parent"); } } diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java index df1a184074..2b22fe1708 100644 --- a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java +++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/WiremockTestsApplication.java @@ -1,11 +1,16 @@ package org.springframework.cloud.contract.wiremock; +import java.net.URI; +import java.util.stream.Stream; + import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -58,6 +63,19 @@ class Service { return this.restTemplate.getForEntity(this.base + "/test", String.class).getBody(); } + public String pom() { + return this.restTemplate.exchange( + RequestEntity.get(URI.create(this.base + "/pom.xml")) + .accept(mediaTypes()).build(), String.class).getBody(); + } + + private MediaType[] mediaTypes() { + return Stream + .of("text/plain", "text/plain", "application/json", "application/json", + "application/*+json", "application/*+json", "*/*", "*/*") + .map(MediaType::valueOf).toArray(MediaType[]::new); + } + public void setBase(String base) { this.base = base; }