Added support for the stubs:// protocol

Currently Stub Runner can fetch a JAR, unpack it and only then pick the contract and stubs. Sometimes, what you want to achieve, is to point to a given folder where the stubs are already unpacked. Another option is a multimodule project, where the stubs are generated and then the user would like to just reference those instead of installing a JAR in a local m2.

With this change we suggest adding a protocol called stubs that would allow to define a path where the unpacked contracts and stub lay.

fixes gh-1150
This commit is contained in:
Marcin Grzejszczak
2019-08-02 17:24:44 +02:00
parent 5e84a38377
commit 34af2fcc58
5 changed files with 546 additions and 175 deletions

View File

@@ -16,19 +16,6 @@
package org.springframework.cloud.contract.stubrunner;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
@@ -36,9 +23,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;
/**
@@ -73,188 +58,37 @@ public class ClasspathStubProvider implements StubDownloaderBuilder {
private static final Log log = LogFactory.getLog(ClasspathStubProvider.class);
private static final int TEMP_DIR_ATTEMPTS = 10000;
private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
new DefaultResourceLoader());
@Override
public StubDownloader build(final StubRunnerOptions stubRunnerOptions) {
if (stubRunnerOptions.stubsMode != StubRunnerProperties.StubsMode.CLASSPATH) {
return null;
}
log.info("Will download stubs from classpath");
return new StubDownloader() {
@Override
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
StubConfiguration config) {
List<RepoRoot> repoRoots = repoRoot(stubRunnerOptions, config);
List<String> paths = toPaths(repoRoots);
List<Resource> resources = resolveResources(paths);
if (log.isDebugEnabled()) {
log.debug("For paths " + paths + " found following resources "
+ resources);
}
if (resources.isEmpty()) {
throw new IllegalStateException(
"No stubs were found on classpath for [" + config.getGroupId()
+ ":" + config.getArtifactId() + "]");
}
final File tmp = createTempDir();
if (stubRunnerOptions.isDeleteStubsAfterTest()) {
tmp.deleteOnExit();
}
Pattern groupAndArtifactPattern = Pattern.compile("^(.*)("
+ config.getGroupId() + "." + config.getArtifactId() + ")(.*)$");
String version = config.getVersion();
for (Resource resource : resources) {
try {
String relativePath = relativePathPicker(resource,
groupAndArtifactPattern);
if (log.isDebugEnabled()) {
log.debug("Relative path for resource is [" + relativePath
+ "]");
}
// the relative path is OS agnostic and contains / only
int lastIndexOf = relativePath.lastIndexOf("/");
String relativePathWithoutFile = lastIndexOf > -1
? relativePath.substring(0, lastIndexOf) : relativePath;
if (log.isDebugEnabled()) {
log.debug("Relative path without file name is ["
+ relativePathWithoutFile + "]");
}
Path directory = Files.createDirectories(
new File(tmp, relativePathWithoutFile).toPath());
File newFile = new File(directory.toFile(),
resource.getFilename());
if (!newFile.exists() && !isDirectory(resource)) {
try (InputStream stream = resource.getInputStream()) {
Files.copy(stream, newFile.toPath());
}
}
if (log.isDebugEnabled()) {
log.debug("Stored file [" + newFile + "]");
}
}
catch (IOException e) {
log.error("Exception occurred while trying to create dirs", e);
throw new IllegalStateException(e);
}
}
log.info("Unpacked files for [" + config.getGroupId() + ":"
+ config.getArtifactId() + ":" + version + "] to folder [" + tmp
+ "]");
return new AbstractMap.SimpleEntry<>(
new StubConfiguration(config.getGroupId(), config.getArtifactId(),
version, config.getClassifier()),
tmp);
}
boolean isDirectory(Resource resource) {
try {
return resource.getFile().isDirectory();
}
catch (Exception e) {
if (log.isTraceEnabled()) {
log.trace(
"Exception occurred while trying to convert path to file for resource ["
+ resource + "]",
e);
}
return false;
}
}
String relativePathPicker(Resource resource, Pattern groupAndArtifactPattern)
throws IOException {
String uri = resource.getURI().toString();
Matcher groupAndArtifactMatcher = groupAndArtifactPattern.matcher(uri);
if (groupAndArtifactMatcher.matches()) {
MatchResult groupAndArtifactResult = groupAndArtifactMatcher
.toMatchResult();
return groupAndArtifactResult.group(2)
+ groupAndArtifactResult.group(3);
}
else {
throw new IllegalArgumentException("Illegal uri [" + uri + "]");
}
}
};
return new ResourceResolvingStubDownloader(stubRunnerOptions, this::repoRoot,
this::gavPattern);
}
private List<String> toPaths(List<RepoRoot> repoRoots) {
List<String> list = new ArrayList<>();
for (RepoRoot repoRoot : repoRoots) {
list.add(repoRoot.fullPath);
}
return list;
}
List<Resource> resolveResources(List<String> paths) {
List<Resource> resources = new ArrayList<>();
for (String path : paths) {
try {
List<Resource> list = Arrays.asList(this.resolver.getResources(path));
resources.addAll(list);
}
catch (IOException e) {
log.error("Exception occurred while trying to fetch resources from ["
+ path + "]");
throw new IllegalStateException(e);
}
}
return resources;
}
private List<RepoRoot> repoRoot(StubRunnerOptions stubRunnerOptions,
private RepoRoots repoRoot(StubRunnerOptions stubRunnerOptions,
StubConfiguration configuration) {
Resource repositoryRoot = stubRunnerOptions.getStubRepositoryRoot();
if (repositoryRoot instanceof ClassPathResource) {
ClassPathResource classPathResource = (ClassPathResource) repositoryRoot;
String path = classPathResource.getPath();
if (StringUtils.hasText(path)) {
return Collections.singletonList(
return RepoRoots.asList(
new RepoRoot(stubRunnerOptions.getStubRepositoryRootAsString()));
}
}
String path = "/**/" + configuration.getGroupId() + "/"
+ configuration.getArtifactId();
return Arrays.asList(new RepoRoot("classpath*:/META-INF" + path, "/**/*.*"),
return RepoRoots.asList(new RepoRoot("classpath*:/META-INF" + path, "/**/*.*"),
new RepoRoot("classpath*:/contracts" + path, "/**/*.*"),
new RepoRoot("classpath*:/mappings" + path, "/**/*.*"));
}
// Taken from Guava
private File createTempDir() {
File baseDir = new File(System.getProperty("java.io.tmpdir"));
String baseName = System.currentTimeMillis() + "-";
for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
File tempDir = new File(baseDir, baseName + counter);
if (tempDir.mkdir()) {
return tempDir;
}
}
throw new IllegalStateException("Failed to create directory within "
+ TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName
+ (TEMP_DIR_ATTEMPTS - 1) + ")");
}
private static class RepoRoot {
final String repoRoot;
final String fullPath;
RepoRoot(String repoRoot) {
this.repoRoot = repoRoot;
this.fullPath = repoRoot + "";
}
RepoRoot(String repoRoot, String suffix) {
this.repoRoot = repoRoot;
this.fullPath = repoRoot + suffix;
}
private Pattern gavPattern(StubConfiguration config) {
String ga = config.getGroupId() + "." + config.getArtifactId();
return Pattern.compile("^(.*)(" + ga + ")(.*)$");
}
}

View File

@@ -0,0 +1,209 @@
/*
* 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
*
* https://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;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
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.AbstractResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
/**
* Allows to read stubs and contracts from a given location. Contrary to
* {@link org.springframework.cloud.contract.stubrunner.AetherStubDownloaderBuilder},
* doesn't require the location to be a maven repository.
*
* @author Marcin Grzejszczak
*/
public class FileStubDownloader implements StubDownloaderBuilder {
private static final List<String> ACCEPTABLE_PROTOCOLS = Collections
.singletonList("stubs");
/**
* Does any of the accepted protocols matches the URL of the repository.
* @param url - of the repository
* @return {@code true} if protocol is accepted
*/
public static boolean isProtocolAccepted(String url) {
return ACCEPTABLE_PROTOCOLS.stream().anyMatch(url::startsWith);
}
@Override
public StubDownloader build(StubRunnerOptions stubRunnerOptions) {
// should work only in remote and local option
if (stubRunnerOptions.getStubsMode() == StubRunnerProperties.StubsMode.CLASSPATH
|| stubRunnerOptions.getStubRepositoryRoot() == null) {
return null;
}
Resource resource = stubRunnerOptions.getStubRepositoryRoot();
// we verify whether the protocol starts with `stubs://`
if (!(resource instanceof StubsResource)) {
return null;
}
return new StubsStubDownloader(stubRunnerOptions);
}
@Override
public Resource resolve(String location, ResourceLoader resourceLoader) {
if (StringUtils.isEmpty(location) || !isProtocolAccepted(location)) {
return null;
}
return new StubsResource(location);
}
}
/**
* Primitive version of a Stubs {@link Resource}. Automatically makes Spring convert the
* URL to a Resource.
*/
class StubsResource extends AbstractResource {
private final String rawLocation;
StubsResource(String location) {
this.rawLocation = location;
}
@Override
public String getDescription() {
return this.rawLocation;
}
@Override
public InputStream getInputStream() throws IOException {
return null;
}
@Override
public URI getURI() throws IOException {
return URI.create(this.rawLocation);
}
}
/**
* Concrete logic of picking stubs.
*/
class StubsStubDownloader implements StubDownloader {
private static final Log log = LogFactory.getLog(StubsStubDownloader.class);
private static final String STUBS_FIND_PRODUCER_PROPERTY = "stubs.find-producer";
private static final String LATEST_VERSION = "+";
private final StubRunnerOptions stubRunnerOptions;
StubsStubDownloader(StubRunnerOptions stubRunnerOptions) {
this.stubRunnerOptions = stubRunnerOptions;
}
// StubConfiguration is the concrete stub to be fetched
@Override
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
StubConfiguration stubConfiguration) {
boolean shouldFindProducer = shouldFindProducer();
if (!shouldFindProducer) {
String schemeSpecific = schemeSpecificPart();
log.info("Stubs are present under [" + schemeSpecific + "]");
return new AbstractMap.SimpleEntry<>(stubConfiguration,
new File(schemeSpecific));
}
return new ResourceResolvingStubDownloader(stubRunnerOptions, this::repoRoot,
this::gavPattern).downloadAndUnpackStubJar(stubConfiguration);
}
// for group id a.b.c and artifact id d
// a.b.c/d
// a/b/c/d
private RepoRoots repoRoot(StubRunnerOptions stubRunnerOptions,
StubConfiguration configuration) {
String pathWithGroupAndArtifactId = "/" + configuration.getGroupId() + "/"
+ configuration.getArtifactId();
String pathWithGroupAndArtifactIdSlashSeparated = "/"
+ configuration.getGroupId().replace(".", File.separator) + "/"
+ configuration.getArtifactId();
String anyFileSuffix = "/**/*.*";
RepoRoots roots = RepoRoots.asList(
new RepoRoot(schemeSpecificPart() + pathWithGroupAndArtifactId,
anyFileSuffix),
new RepoRoot(
schemeSpecificPart() + pathWithGroupAndArtifactIdSlashSeparated,
anyFileSuffix),
new RepoRoot(schemeSpecificPart() + anyFileSuffix));
if (!latestVersionIsSet(configuration)) {
String pathWithGAV = pathWithGroupAndArtifactId + "/"
+ configuration.getVersion();
String pathWithSlashSeparatedGAV = pathWithGroupAndArtifactIdSlashSeparated
+ "/" + configuration.getVersion();
roots.addAll(RepoRoots.asList(
new RepoRoot(schemeSpecificPart() + pathWithGAV, anyFileSuffix),
new RepoRoot(schemeSpecificPart() + pathWithSlashSeparatedGAV,
anyFileSuffix)));
}
return roots;
}
private Pattern gavPattern(StubConfiguration config) {
String version = config.getVersion();
String ga = config.getGroupId() + "." + config.getArtifactId();
String gav = latestVersionIsSet(config) ? ga : (ga + "." + version);
return Pattern.compile("^(.*)(" + gav + ")(.*)$");
}
private boolean latestVersionIsSet(StubConfiguration configuration) {
return LATEST_VERSION.equals(configuration.getVersion());
}
private boolean shouldFindProducer() {
Map<String, String> args = this.stubRunnerOptions.getProperties();
String findProducer = StubRunnerPropertyUtils.getProperty(args,
STUBS_FIND_PRODUCER_PROPERTY);
return Boolean.parseBoolean(findProducer);
}
// stubs://foo -> foo
private String schemeSpecificPart() {
try {
String part = this.stubRunnerOptions.getStubRepositoryRoot().getURI()
.getSchemeSpecificPart();
if (StringUtils.isEmpty(part)) {
return part;
}
return part.startsWith("//") ? part.substring(2) : part;
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}

View File

@@ -0,0 +1,243 @@
/*
* 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
*
* https://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;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import shaded.com.google.common.base.Function;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;
class ResourceResolvingStubDownloader implements StubDownloader {
private static final Log log = LogFactory
.getLog(ResourceResolvingStubDownloader.class);
private static final int TEMP_DIR_ATTEMPTS = 10000;
private static final String LATEST_VERSION = "+";
private final StubRunnerOptions stubRunnerOptions;
private final BiFunction<StubRunnerOptions, StubConfiguration, RepoRoots> repoRootFunction;
private final Function<StubConfiguration, Pattern> gavPattern;
private final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
new DefaultResourceLoader());
ResourceResolvingStubDownloader(StubRunnerOptions stubRunnerOptions,
BiFunction<StubRunnerOptions, StubConfiguration, RepoRoots> repoRootFunction,
Function<StubConfiguration, Pattern> gavPattern) {
this.stubRunnerOptions = stubRunnerOptions;
this.repoRootFunction = repoRootFunction;
this.gavPattern = gavPattern;
}
@Override
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
StubConfiguration config) {
List<RepoRoot> repoRoots = repoRootFunction.apply(stubRunnerOptions, config);
List<String> paths = toPaths(repoRoots);
List<Resource> resources = resolveResources(paths);
if (log.isDebugEnabled()) {
log.debug("For paths " + paths + " found following resources " + resources);
}
if (resources.isEmpty()) {
throw new IllegalStateException("No stubs were found on classpath for ["
+ config.getGroupId() + ":" + config.getArtifactId() + "]");
}
final File tmp = createTempDir();
if (stubRunnerOptions.isDeleteStubsAfterTest()) {
tmp.deleteOnExit();
}
boolean atLeastOneFound = false;
for (Resource resource : resources) {
try {
String relativePath = relativePathPicker(resource,
this.gavPattern.apply(config));
if (log.isDebugEnabled()) {
log.debug("Relative path for resource is [" + relativePath + "]");
}
if (StringUtils.isEmpty(relativePath)) {
log.warn("Unable to match the URI [" + resource.getURI() + "]");
continue;
}
atLeastOneFound = true;
copyTheFoundFiles(tmp, resource, relativePath);
}
catch (IOException e) {
log.error("Exception occurred while trying to create dirs", e);
throw new IllegalStateException(e);
}
}
if (!atLeastOneFound) {
log.warn("Didn't find any matching stubs");
return null;
}
log.info("Unpacked files for [" + config.getGroupId() + ":"
+ config.getArtifactId() + ":" + config.getVersion() + "] to folder ["
+ tmp + "]");
return new AbstractMap.SimpleEntry<>(new StubConfiguration(config.getGroupId(),
config.getArtifactId(), config.getVersion(), config.getClassifier()),
tmp);
}
private void copyTheFoundFiles(File tmp, Resource resource, String relativePath)
throws IOException {
// the relative path is OS agnostic and contains / only
int lastIndexOf = relativePath.lastIndexOf("/");
String relativePathWithoutFile = lastIndexOf > -1
? relativePath.substring(0, lastIndexOf) : relativePath;
if (log.isDebugEnabled()) {
log.debug("Relative path without file name is [" + relativePathWithoutFile
+ "]");
}
Path directory = Files
.createDirectories(new File(tmp, relativePathWithoutFile).toPath());
File newFile = new File(directory.toFile(), resource.getFilename());
if (!newFile.exists() && !isDirectory(resource)) {
try (InputStream stream = resource.getInputStream()) {
Files.copy(stream, newFile.toPath());
}
}
if (log.isDebugEnabled()) {
log.debug("Stored file [" + newFile + "]");
}
}
boolean isDirectory(Resource resource) {
try {
return resource.getFile().isDirectory();
}
catch (Exception e) {
if (log.isTraceEnabled()) {
log.trace(
"Exception occurred while trying to convert path to file for resource ["
+ resource + "]",
e);
}
return false;
}
}
String relativePathPicker(Resource resource, Pattern groupAndArtifactPattern)
throws IOException {
String uri = resource.getURI().toString();
Matcher groupAndArtifactMatcher = groupAndArtifactPattern.matcher(uri);
if (groupAndArtifactMatcher.matches()) {
MatchResult groupAndArtifactResult = groupAndArtifactMatcher.toMatchResult();
return groupAndArtifactResult.group(2) + groupAndArtifactResult.group(3);
}
else {
return "";
}
}
private List<String> toPaths(List<RepoRoot> repoRoots) {
List<String> list = new ArrayList<>();
for (RepoRoot repoRoot : repoRoots) {
list.add(repoRoot.fullPath);
}
return list;
}
List<Resource> resolveResources(List<String> paths) {
List<Resource> resources = new ArrayList<>();
for (String path : paths) {
try {
List<Resource> list = Arrays.asList(this.resolver.getResources(path));
resources.addAll(list);
}
catch (IOException e) {
log.error("Exception occurred while trying to fetch resources from ["
+ path + "]");
throw new IllegalStateException(e);
}
}
return resources;
}
// Taken from Guava
private File createTempDir() {
File baseDir = new File(System.getProperty("java.io.tmpdir"));
String baseName = System.currentTimeMillis() + "-";
for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
File tempDir = new File(baseDir, baseName + counter);
if (tempDir.mkdir()) {
return tempDir;
}
}
throw new IllegalStateException("Failed to create directory within "
+ TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName
+ (TEMP_DIR_ATTEMPTS - 1) + ")");
}
}
class RepoRoot {
final String repoRoot;
final String fullPath;
RepoRoot(String repoRoot) {
this.repoRoot = repoRoot;
this.fullPath = repoRoot;
}
RepoRoot(String repoRoot, String suffix) {
this.repoRoot = repoRoot;
this.fullPath = repoRoot + suffix;
}
}
class RepoRoots extends LinkedList<RepoRoot> {
RepoRoots() {
}
RepoRoots(Collection<? extends RepoRoot> c) {
super(c);
}
static RepoRoots asList(RepoRoot... repoRoots) {
return new RepoRoots(Arrays.asList(repoRoots));
}
}

View File

@@ -62,7 +62,7 @@ public class StubDownloaderBuilderProvider {
List<StubDownloaderBuilder> defaultStubDownloaderBuilders() {
return Arrays.asList(new ScmStubDownloaderBuilder(), new ClasspathStubProvider(),
new AetherStubDownloaderBuilder());
new FileStubDownloader(), new AetherStubDownloaderBuilder());
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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
*
* https://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;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.assertj.core.api.BDDAssertions;
import org.junit.Test;
public class StubsStubDownloaderTests {
URL url = StubsStubDownloaderTests.class.getResource("/repository/mappings");
@Test
public void should_pick_stubs_from_a_given_location() {
String path = url.getPath();
StubRunnerOptions options = new StubRunnerOptionsBuilder()
.withStubRepositoryRoot("stubs://file://" + path).build();
StubsStubDownloader downloader = new StubsStubDownloader(options);
Map.Entry<StubConfiguration, File> entry = downloader
.downloadAndUnpackStubJar(new StubConfiguration("lv.spring.cloud:bye"));
BDDAssertions.then(entry).isNotNull();
BDDAssertions.then(entry.getValue().getPath()).endsWith("repository/mappings");
}
@Test
public void should_pick_stubs_from_a_given_location_for_a_find_producer_with_ga() {
String path = url.getPath();
StubRunnerOptions options = new StubRunnerOptionsBuilder()
.withStubRepositoryRoot("stubs://file://" + path)
.withProperties(propsWithFindProducer()).build();
StubsStubDownloader downloader = new StubsStubDownloader(options);
Map.Entry<StubConfiguration, File> entry = downloader
.downloadAndUnpackStubJar(new StubConfiguration("lv.spring.cloud:bye"));
BDDAssertions.then(entry).isNotNull();
File stub = new File(entry.getValue().getPath(),
"lv/spring/cloud/bye/lv_bye.json");
BDDAssertions.then(stub).exists();
}
@Test
public void should_pick_stubs_from_a_given_location_for_a_find_producer_with_gav() {
String path = url.getPath();
StubRunnerOptions options = new StubRunnerOptionsBuilder()
.withStubRepositoryRoot("stubs://file://" + path)
.withProperties(propsWithFindProducer()).build();
StubsStubDownloader downloader = new StubsStubDownloader(options);
Map.Entry<StubConfiguration, File> entry = downloader
.downloadAndUnpackStubJar(new StubConfiguration("lv.spring:cloud:bye"));
BDDAssertions.then(entry).isNotNull();
File stub = new File(entry.getValue().getPath(),
"lv/spring/cloud/bye/lv_bye.json");
BDDAssertions.then(stub).exists();
}
private Map<String, String> propsWithFindProducer() {
Map<String, String> map = new HashMap<>();
map.put("stubs.find-producer", "true");
return map;
}
}