Issues #110 user pass (#157)

can now configure username and password authentication and a proxy for accessing stub repository

Fixes #110
This commit is contained in:
Marcin Grzejszczak
2016-12-05 14:56:08 +01:00
committed by GitHub
parent cf2dbc24a6
commit 545874c951
20 changed files with 603 additions and 94 deletions

View File

@@ -1311,7 +1311,7 @@ Example of a `pom.xml` inside the `server` folder.
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-cloud-contract.version>1.0.2.BUILD-SNAPSHOT</spring-cloud-contract.version>
<spring-cloud-contract.version>1.0.3.BUILD-SNAPSHOT</spring-cloud-contract.version>
<spring-cloud-dependencies.version>Camden.BUILD-SNAPSHOT</spring-cloud-dependencies.version>
</properties>

View File

@@ -66,6 +66,8 @@ Some of the properties that are repetitive can be set using system properties or
|stubrunner.classifier|stubs| Default classifier for the stub artifacts
|stubrunner.workOffline|false| If true then will not contact any remote repositories to download stubs
|stubrunner.ids|| Array of Ivy notation stubs to download
|stubrunner.username|| Optional username to access the tool that stores the JARs with stubs
|stubrunner.password|| Optional password to access the tool that stores the JARs with stubs
|======================
===== Stub runner stubs ids
@@ -80,7 +82,7 @@ groupId:artifactId:version:classifier:port
`version`, `classifier` and `port` are optional.
* If you don't provide the `port` then a random one will be picked
* If you don't provide the `classifier` then the default one will be taken.
* If you don't provide the `classifier` then the default one will be taken. (NOTE that you can pass an empty classifier like this `groupId:artifactId:version:`)
* If you don't provide the `version` then the `+` will be passed and the latest one will be downloaded
Where `port` means the port of the WireMock server.

View File

@@ -14,24 +14,35 @@ You can set the following options to the main class:
[source,groovy,indent=0]
----
-maxp (--maxPort) N : Maximum port value to be assigned to the
Wiremock instance. Defaults to 15000
(default: 15000)
-minp (--minPort) N : Minimal port value to be assigned to the
Wiremock instance. Defaults to 10000
(default: 10000)
-s (--stubs) VAL : Comma separated list of Ivy representation of
jars with stubs. Eg. groupid:artifactid1,group
id2:artifactid2:version:classifier
-sr (--stubRepositoryRoot) VAL : Location of a Jar containing server where you
keep your stubs (e.g. http://nexus.net/content
/repositories/repository)
-ss (--stubsSuffix) VAL : Suffix for the jar containing stubs (e.g.
'stubs' if the stub jar would have a 'stubs'
classifier for stubs: foobar-stubs ).
Defaults to 'stubs' (default: stubs)
-wo (--workOffline) : Switch to work offline. Defaults to 'false'
(default: false)
-c, --classifier Suffix for the jar containing stubs (e.
g. 'stubs' if the stub jar would
have a 'stubs' classifier for stubs:
foobar-stubs ). Defaults to 'stubs'
(default: stubs)
--maxPort, --maxp <Integer> Maximum port value to be assigned to
the WireMock instance. Defaults to
15000 (default: 15000)
--minPort, --minp <Integer> Minimum port value to be assigned to
the WireMock instance. Defaults to
10000 (default: 10000)
-p, --password Password to user when connecting to
repository
--phost, --proxyHost Proxy host to use for repository
requests
--pport, --proxyPort [Integer] Proxy port to use for repository
requests
-r, --root Location of a Jar containing server
where you keep your stubs (e.g. http:
//nexus.
net/content/repositories/repository)
-s, --stubs Comma separated list of Ivy
representation of jars with stubs.
Eg. groupid:artifactid1,groupid2:
artifactid2:classifier
-u, --username Username to user when connecting to
repository
--wo, --workOffline Switch to work offline. Defaults to
'false'
----
===== HTTP Stubs

View File

@@ -94,6 +94,12 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>io.specto</groupId>
<artifactId>hoverfly-junit</artifactId>
<version>0.1.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>

View File

@@ -16,9 +16,6 @@
package org.springframework.cloud.contract.stubrunner;
import java.util.ArrayList;
import java.util.List;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
@@ -26,13 +23,11 @@ import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
import org.springframework.util.StringUtils;
class AetherFactories {
@@ -52,22 +47,12 @@ class AetherFactories {
if (!workOffline) {
session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS);
}
session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_WARN);
LocalRepository localRepo = new LocalRepository(localRepositoryDirectory());
session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
return session;
}
public static List<RemoteRepository> newRepositories(List<String> repositories) {
List<RemoteRepository> result = new ArrayList<>();
for (int index = 0; index < repositories.size(); index++) {
String repo = repositories.get(index);
if (StringUtils.hasText(repo)) {
result.add(new RemoteRepository.Builder("remote" + index, "default", repo).build());
}
}
return result;
}
private static String localRepositoryDirectory() {
return System.getProperty(MAVEN_LOCAL_REPOSITORY_LOCATION, System.getProperty("user.home") + "/.m2/repository");
}

View File

@@ -21,7 +21,6 @@ import java.io.IOException;
import java.net.URI;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -29,6 +28,7 @@ import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResult;
@@ -38,12 +38,13 @@ import org.eclipse.aether.resolution.VersionRangeResult;
import org.eclipse.aether.resolution.VersionRequest;
import org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions.StubRunnerProxyOptions;
import org.springframework.util.StringUtils;
import static java.nio.file.Files.createTempDirectory;
import static org.springframework.cloud.contract.stubrunner.AetherFactories.newRepositories;
import static org.springframework.cloud.contract.stubrunner.AetherFactories.newRepositorySystem;
import static org.springframework.cloud.contract.stubrunner.AetherFactories.newSession;
import static org.springframework.cloud.contract.stubrunner.util.ZipCategory.unzipTo;
@@ -106,13 +107,27 @@ public class AetherStubDownloader implements StubDownloader {
}
}
private List<RemoteRepository> remoteRepositories(
StubRunnerOptions stubRunnerOptions) {
private List<RemoteRepository> remoteRepositories(StubRunnerOptions stubRunnerOptions) {
if (stubRunnerOptions.stubRepositoryRoot == null) {
return new ArrayList<>();
}
List<RemoteRepository> remoteRepos = newRepositories(
Arrays.asList(stubRunnerOptions.stubRepositoryRoot.split(",")));
final String[] repos = stubRunnerOptions.stubRepositoryRoot.split(",");
final List<RemoteRepository> remoteRepos = new ArrayList<>();
for (int i = 0; i < repos.length; i++) {
if(StringUtils.hasText(repos[i])) {
final RemoteRepository.Builder builder = new RemoteRepository.Builder("remote" + i, "default", repos[i])
.setAuthentication(new AuthenticationBuilder()
.addUsername(stubRunnerOptions.username)
.addPassword(stubRunnerOptions.password)
.build());
if(stubRunnerOptions.getProxyOptions() != null) {
final StubRunnerProxyOptions p = stubRunnerOptions.getProxyOptions();
builder.setProxy(new Proxy(null, p.getProxyHost(), p.getProxyPort()));
}
remoteRepos.add(builder.build());
}
}
if (log.isDebugEnabled()) {
log.debug("Using the following remote repos " + remoteRepos);
}
@@ -165,8 +180,7 @@ public class AetherStubDownloader implements StubDownloader {
}
@Override
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(
StubRunnerOptions options, StubConfiguration stubConfiguration) {
public Map.Entry<StubConfiguration, File> downloadAndUnpackStubJar(StubConfiguration stubConfiguration) {
String version = getVersion(stubConfiguration.groupId,
stubConfiguration.artifactId, stubConfiguration.version,
stubConfiguration.classifier);

View File

@@ -48,4 +48,9 @@ class Arguments {
public StubConfiguration getStub() {
return this.stub;
}
@Override public String toString() {
return "Arguments{" + "stubRunnerOptions=" + this.stubRunnerOptions
+ ", repositoryPath='" + this.repositoryPath + '\'' + ", stub=" + this.stub + '}';
}
}

View File

@@ -91,7 +91,7 @@ public class ContractDownloader {
private File unpackAndDownloadContracts() {
log.info("Will download contracts for [" + this.contractsJarStubConfiguration + "]");
Map.Entry<StubConfiguration, File> unpackedContractStubs = this.stubDownloader
.downloadAndUnpackStubJar(null, this.contractsJarStubConfiguration);
.downloadAndUnpackStubJar(this.contractsJarStubConfiguration);
if (unpackedContractStubs == null) {
throw new IllegalStateException("The contracts failed to be downloaded!");
}

View File

@@ -25,5 +25,5 @@ public interface StubDownloader {
* Returns a mapping of updated StubConfiguration (it will contain the resolved version) and the location of the downloaded JAR.
* If there was no artifact this method will return {@code null}.
*/
Map.Entry<StubConfiguration,File> downloadAndUnpackStubJar(StubRunnerOptions options, StubConfiguration stubConfiguration);
Map.Entry<StubConfiguration,File> downloadAndUnpackStubJar(StubConfiguration stubConfiguration);
}

View File

@@ -57,7 +57,7 @@ class StubRunnerFactory {
Collection<StubRunner> result = new ArrayList<>();
for (StubConfiguration stubsConfiguration : this.stubRunnerOptions.getDependencies()) {
Map.Entry<StubConfiguration, File> entry = this.stubDownloader
.downloadAndUnpackStubJar(this.stubRunnerOptions, stubsConfiguration);
.downloadAndUnpackStubJar(stubsConfiguration);
if (log.isDebugEnabled()) {
log.debug("For stub configuration [" + stubsConfiguration + "] the downloaded entry is [" + entry + "]");
}

View File

@@ -38,11 +38,11 @@ public class StubRunnerMain {
ArgumentAcceptingOptionSpec<Integer> minPortValueOpt = parser
.acceptsAll(Arrays.asList("minp", "minPort"),
"Minimum port value to be assigned to the WireMock instance. Defaults to 10000")
.withRequiredArg().ofType(Integer.class);
.withRequiredArg().ofType(Integer.class).defaultsTo(10000);
ArgumentAcceptingOptionSpec<Integer> maxPortValueOpt = parser
.acceptsAll(Arrays.asList("maxp", "maxPort"),
"Maximum port value to be assigned to the WireMock instance. Defaults to 15000")
.withRequiredArg().ofType(Integer.class);
.withRequiredArg().ofType(Integer.class).defaultsTo(15000);
ArgumentAcceptingOptionSpec<String> stubsOpt = parser
.acceptsAll(Arrays.asList("s", "stubs"),
"Comma separated list of Ivy representation of jars with stubs. Eg. groupid:artifactid1,groupid2:artifactid2:classifier")
@@ -54,7 +54,19 @@ public class StubRunnerMain {
ArgumentAcceptingOptionSpec<String> rootOpt = parser
.acceptsAll(Arrays.asList("r", "root"),"Location of a Jar containing server where you keep your stubs (e.g. http://nexus.net/content/repositories/repository)")
.withRequiredArg();
ArgumentAcceptingOptionSpec<String> usernameOpt = parser
.acceptsAll(Arrays.asList("u", "username"),"Username to user when connecting to repository")
.withOptionalArg();
ArgumentAcceptingOptionSpec<String> passwordOpt = parser
.acceptsAll(Arrays.asList("p", "password"),"Password to user when connecting to repository")
.withOptionalArg();
ArgumentAcceptingOptionSpec<String> proxyHostOpt = parser
.acceptsAll(Arrays.asList("phost", "proxyHost"),"Proxy host to use for repository requests")
.withOptionalArg();
ArgumentAcceptingOptionSpec<Integer> proxyPortOpt = parser
.acceptsAll(Arrays.asList("pport", "proxyPort"),"Proxy port to use for repository requests")
.withOptionalArg()
.ofType(Integer.class);
parser.acceptsAll(Arrays.asList("wo", "workOffline"),
"Switch to work offline. Defaults to 'false'");
OptionSet options = parser.parse(args);
@@ -64,11 +76,21 @@ public class StubRunnerMain {
Integer maxPortValue = options.valueOf(maxPortValueOpt);
String stubRepositoryRoot= options.valueOf(rootOpt);
String stubsSuffix = options.valueOf(classifierOpt);
StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
final String username = options.valueOf(usernameOpt);
final String password = options.valueOf(passwordOpt);
final String proxyHost = options.valueOf(proxyHostOpt);
final Integer proxyPort = options.valueOf(proxyPortOpt);
final StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder()
.withMinMaxPort(minPortValue, maxPortValue)
.withStubRepositoryRoot(stubRepositoryRoot)
.withWorkOffline(workOffline).withStubsClassifier(stubsSuffix)
.withStubs(stubs).build();
.withUsername(username)
.withPassword(password)
.withStubs(stubs);
if (proxyHost != null) {
builder.withProxy(proxyHost, proxyPort);
}
StubRunnerOptions stubRunnerOptions = builder.build();
this.arguments = new Arguments(stubRunnerOptions);
}
catch (Exception e) {

View File

@@ -60,9 +60,26 @@ public class StubRunnerOptions {
*/
final Map<StubConfiguration, Integer> stubIdsToPortMapping;
public StubRunnerOptions(Integer minPortValue, Integer maxPortValue, String stubRepositoryRoot, boolean workOffline,
String stubsClassifier, Collection<StubConfiguration> dependencies,
Map<StubConfiguration, Integer> stubIdsToPortMapping) {
/**
* Optional username for authorization header
*/
final String username;
/**
* Optional password for authorization header
*/
final String password;
/**
* Optional proxy settings
*/
private final StubRunnerProxyOptions stubRunnerProxyOptions;
StubRunnerOptions(Integer minPortValue, Integer maxPortValue,
String stubRepositoryRoot, boolean workOffline, String stubsClassifier,
Collection<StubConfiguration> dependencies,
Map<StubConfiguration, Integer> stubIdsToPortMapping,
String username, String password, final StubRunnerProxyOptions stubRunnerProxyOptions) {
this.minPortValue = minPortValue;
this.maxPortValue = maxPortValue;
this.stubRepositoryRoot = stubRepositoryRoot;
@@ -70,17 +87,9 @@ public class StubRunnerOptions {
this.stubsClassifier = stubsClassifier;
this.dependencies = dependencies;
this.stubIdsToPortMapping = stubIdsToPortMapping;
}
/**
* @deprecated there is no context path any longer
*/
@Deprecated
public StubRunnerOptions(Integer minPortValue, Integer maxPortValue, String stubRepositoryRoot, boolean workOffline,
String stubsClassifier, Collection<StubConfiguration> dependencies,
Map<StubConfiguration, Integer> stubIdsToPortMapping, String contextPath) {
this(minPortValue, maxPortValue, stubRepositoryRoot, workOffline, stubsClassifier, dependencies,
stubIdsToPortMapping);
this.username = username;
this.password = password;
this.stubRunnerProxyOptions = stubRunnerProxyOptions;
}
public Integer port(StubConfiguration stubConfiguration) {
@@ -108,12 +117,41 @@ public class StubRunnerOptions {
return this.stubIdsToPortMapping;
}
@Override
public String toString() {
return "StubRunnerOptions [minPortValue=" + this.minPortValue + ", maxPortValue=" + this.maxPortValue
+ ", stubRepositoryRoot=" + this.stubRepositoryRoot + ", workOffline=" + this.workOffline
+ ", stubsClassifier=" + this.stubsClassifier + ", dependencies=" + this.dependencies
+ ", stubIdsToPortMapping=" + this.stubIdsToPortMapping + "]";
public StubRunnerProxyOptions getProxyOptions() {
return this.stubRunnerProxyOptions;
}
public static class StubRunnerProxyOptions {
private final String proxyHost;
private final int proxyPort;
public StubRunnerProxyOptions(final String proxyHost, final int proxyPort) {
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
}
public String getProxyHost() {
return this.proxyHost;
}
public int getProxyPort() {
return this.proxyPort;
}
@Override public String toString() {
return "StubRunnerProxyOptions{" + "proxyHost='" + this.proxyHost + '\''
+ ", proxyPort=" + this.proxyPort + '}';
}
}
@Override public String toString() {
return "StubRunnerOptions{" + "minPortValue=" + this.minPortValue + ", maxPortValue="
+ this.maxPortValue + ", stubRepositoryRoot='" + this.stubRepositoryRoot + '\''
+ ", workOffline=" + this.workOffline + ", stubsClassifier='" + this.stubsClassifier
+ '\'' + ", dependencies=" + this.dependencies + ", stubIdsToPortMapping="
+ this.stubIdsToPortMapping + ", username='" + this.username + '\'' + ", password='"
+ this.password + '\'' + ", stubRunnerProxyOptions=" + this.stubRunnerProxyOptions
+ '}';
}
}

View File

@@ -16,6 +16,9 @@
package org.springframework.cloud.contract.stubrunner;
import org.springframework.cloud.contract.stubrunner.util.StubsParser;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
@@ -23,9 +26,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.contract.stubrunner.util.StubsParser;
import org.springframework.util.StringUtils;
public class StubRunnerOptionsBuilder {
private static final String DELIMITER = ":";
@@ -37,6 +37,9 @@ public class StubRunnerOptionsBuilder {
private String stubRepositoryRoot;
private boolean workOffline = false;
private String stubsClassifier = "stubs";
private String username;
private String password;
private StubRunnerOptions.StubRunnerProxyOptions stubRunnerProxyOptions;
public StubRunnerOptionsBuilder() {
}
@@ -57,8 +60,7 @@ public class StubRunnerOptionsBuilder {
return this;
}
public StubRunnerOptionsBuilder withMinMaxPort(Integer minPortValue,
Integer maxPortValue) {
public StubRunnerOptionsBuilder withMinMaxPort(Integer minPortValue, Integer maxPortValue) {
this.minPortValue = minPortValue;
this.maxPortValue = maxPortValue;
return this;
@@ -114,7 +116,8 @@ public class StubRunnerOptionsBuilder {
public StubRunnerOptions build() {
return new StubRunnerOptions(this.minPortValue, this.maxPortValue, this.stubRepositoryRoot,
this.workOffline, this.stubsClassifier, buildDependencies(), this.stubIdsToPortMapping);
this.workOffline, this.stubsClassifier, buildDependencies(), this.stubIdsToPortMapping,
this.username, this.password, this.stubRunnerProxyOptions);
}
private Collection<StubConfiguration> buildDependencies() {
@@ -139,8 +142,7 @@ public class StubRunnerOptionsBuilder {
if (StubsParser.hasPort(notation)) {
addPort(notation);
this.stubs.add(StubsParser.ivyFromStringWithPort(notation));
}
else {
} else {
this.stubs.add(notation);
}
}
@@ -154,4 +156,18 @@ public class StubRunnerOptionsBuilder {
this.stubIdsToPortMapping.putAll(stubIdsToPortMapping);
}
public StubRunnerOptionsBuilder withUsername(final String username) {
this.username = username;
return this;
}
public StubRunnerOptionsBuilder withPassword(final String password) {
this.password = password;
return this;
}
public StubRunnerOptionsBuilder withProxy(final String proxyHost, final int proxyPort) {
this.stubRunnerProxyOptions = new StubRunnerOptions.StubRunnerProxyOptions(proxyHost, proxyPort);
return this;
}
}

View File

@@ -65,14 +65,20 @@ public class StubRunnerRule implements TestRule, StubFinder {
}
private StubRunnerOptions defaultStubRunnerOptions() {
return new StubRunnerOptionsBuilder()
StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder()
.withMinPort(Integer.valueOf(System.getProperty("stubrunner.port.range.min", "10000")))
.withMaxPort(Integer.valueOf(System.getProperty("stubrunner.port.range.max", "15000")))
.withStubRepositoryRoot(System.getProperty("stubrunner.repository.root", ""))
.withWorkOffline(Boolean.parseBoolean(System.getProperty("stubrunner.work-offline", "false")))
.withStubsClassifier(System.getProperty("stubrunner.classifier", "stubs"))
.withStubs(System.getProperty("stubrunner.ids", ""))
.build();
.withUsername(System.getProperty("stubrunner.username"))
.withPassword(System.getProperty("stubrunner.password"));
String proxyHost = System.getProperty("stubrunner.proxy.host");
if (proxyHost != null) {
builder.withProxy(proxyHost, Integer.parseInt(System.getProperty("stubrunner.proxy.port")));
}
return builder.build();
}
/**

View File

@@ -67,14 +67,11 @@ public class StubRunnerConfiguration {
*/
@Bean
public BatchStubRunner batchStubRunner() throws IOException {
StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
.withMinMaxPort(this.props.getMinPort(), this.props.getMaxPort())
.withStubRepositoryRoot(
uriStringOrEmpty(this.props.getRepositoryRoot()))
.withWorkOffline(this.props.isWorkOffline())
.withStubsClassifier(this.props.getClassifier())
.withStubs(this.props.getIds())
.build();
StubRunnerOptionsBuilder builder = builder();
if (this.props.getProxyHost() != null) {
builder.withProxy(this.props.getProxyHost(), this.props.getProxyPort());
}
StubRunnerOptions stubRunnerOptions = builder.build();
BatchStubRunner batchStubRunner = new BatchStubRunnerFactory(stubRunnerOptions,
this.stubDownloader != null ? this.stubDownloader
: new AetherStubDownloader(stubRunnerOptions),
@@ -86,6 +83,18 @@ public class StubRunnerConfiguration {
return batchStubRunner;
}
private StubRunnerOptionsBuilder builder() throws IOException {
return new StubRunnerOptionsBuilder()
.withMinMaxPort(this.props.getMinPort(), this.props.getMaxPort())
.withStubRepositoryRoot(
uriStringOrEmpty(this.props.getRepositoryRoot()))
.withWorkOffline(this.props.isWorkOffline())
.withStubsClassifier(this.props.getClassifier())
.withStubs(this.props.getIds())
.withUsername(this.props.getUsername())
.withPassword(this.props.getPassword());
}
private String uriStringOrEmpty(Resource stubRepositoryRoot) throws IOException {
return stubRepositoryRoot != null ? stubRepositoryRoot.getURI().toString() : "";
}

View File

@@ -65,6 +65,26 @@ public class StubRunnerProperties {
*/
private String contextPath = "";
/**
* Repository username
*/
private String username;
/**
* Repository password
*/
private String password;
/**
* Repository proxy port
*/
private Integer proxyPort;
/**
* Repository proxy host
*/
private String proxyHost;
public int getMinPort() {
return this.minPort;
}
@@ -97,6 +117,38 @@ public class StubRunnerProperties {
this.repositoryRoot = new DefaultResourceLoader().getResource(repositoryRoot);
}
public String getUsername() {
return this.username;
}
public void setUsername(final String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(final String password) {
this.password = password;
}
public Integer getProxyPort() {
return this.proxyPort;
}
public void setProxyPort(final Integer proxyPort) {
this.proxyPort = proxyPort;
}
public String getProxyHost() {
return this.proxyHost;
}
public void setProxyHost(final String proxyHost) {
this.proxyHost = proxyHost;
}
public String[] getIds() {
return this.ids;
}

View File

@@ -0,0 +1,30 @@
package org.springframework.cloud.contract.stubrunner
import io.specto.hoverfly.junit.HoverflyRule
import org.junit.Rule
import spock.lang.Specification
class AetherStubDownloaderSpec extends Specification {
@Rule
HoverflyRule hoverflyRule = HoverflyRule.buildFromClassPathResource("simulation.json").build()
def 'Should be able to download from a repository using username and password authentication'() {
given:
final StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
.withUsername("andrew.morgan")
.withPassword("k+hbZp8rpolRucXB09dGE/CxPXxidQryQUYSGbeo6JE=")
.withProxy("localhost", hoverflyRule.proxyPort)
.withStubRepositoryRoot("https://test.jfrog.io/test/libs-snapshot-local")
.build()
final AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions)
when:
final def jar = aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("io.test", "test-simulations-svc", "1.0-SNAPSHOT"))
then:
jar != null
}
}

View File

@@ -19,7 +19,7 @@ class ContractDownloaderSpec extends Specification {
stubConfiguration, contractPath, '', '')
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
and:
stubDownloader.downloadAndUnpackStubJar(_, _) >> new AbstractMap.SimpleEntry(stubConfiguration, file)
stubDownloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(stubConfiguration, file)
when:
contractDownloader.unpackedDownloadedContracts(properties)
then:
@@ -35,7 +35,7 @@ class ContractDownloaderSpec extends Specification {
stubConfiguration, contractPath, '', '')
ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties()
and:
stubDownloader.downloadAndUnpackStubJar(_, _) >> new AbstractMap.SimpleEntry(stubConfiguration, file)
stubDownloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(stubConfiguration, file)
when:
contractDownloader.unpackedDownloadedContracts(properties)
then:

View File

@@ -42,8 +42,8 @@ class StubRunnerFactorySpec extends Specification {
def "Should download stub definitions many times"() {
given:
folder.newFolder("mappings")
1 * downloader.downloadAndUnpackStubJar(_, _) >> new AbstractMap.SimpleEntry(new StubConfiguration('a:b'), folder.root)
1 * downloader.downloadAndUnpackStubJar(_, _) >> new AbstractMap.SimpleEntry(new StubConfiguration('c:d'), folder.root)
1 * downloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(new StubConfiguration('a:b'), folder.root)
1 * downloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(new StubConfiguration('c:d'), folder.root)
when:
Collection<StubRunner> stubRunners = collectOnlyPresentValues(factory.createStubsFromServiceConfiguration())
then:

View File

@@ -0,0 +1,313 @@
{
"data": [
{
"response": {
"status": 200,
"body": "\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cmetadata\u003e\n \u003cgroupId\u003eio.test\u003c/groupId\u003e\n \u003cartifactId\u003etest-simulations-svc\u003c/artifactId\u003e\n \u003cversion\u003e1.0-SNAPSHOT\u003c/version\u003e\n \u003cversioning\u003e\n \u003csnapshot\u003e\n \u003cbuildNumber\u003e1\u003c/buildNumber\u003e\n \u003c/snapshot\u003e\n \u003clastUpdated\u003e20161102142105\u003c/lastUpdated\u003e\n \u003c/versioning\u003e\n\u003c/metadata\u003e\n",
"encodedBody": false,
"headers": {
"Accept-Ranges": [
"bytes"
],
"Cache-Control": [
"no-store"
],
"Connection": [
"keep-alive"
],
"Content-Disposition": [
"attachment; filename=\"maven-metadata.xml\"; filename*=UTF-8''maven-metadata.xml"
],
"Content-Length": [
"320"
],
"Content-Type": [
"application/xml"
],
"Date": [
"Tue, 08 Nov 2016 15:22:26 GMT"
],
"Etag": [
"9a318b6f330aaf4b7088c3018e31dd4bb11b18f1"
],
"Hoverfly": [
"Was-Here"
],
"Last-Modified": [
"Wed, 02 Nov 2016 14:21:05 GMT"
],
"Server": [
"Artifactory/4.14.0"
],
"X-Artifactory-Filename": [
"maven-metadata.xml"
],
"X-Artifactory-Id": [
"aolprod1b-test"
],
"X-Checksum-Md5": [
"baa7a56ac80111c29099f9076e6a136f"
],
"X-Checksum-Sha1": [
"9a318b6f330aaf4b7088c3018e31dd4bb11b18f1"
],
"X-Node": [
"nginx-shared2b"
]
}
},
"request": {
"requestType": "template",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/maven-metadata.xml",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": "",
"headers": {
"Authorization": [
"Basic dXNlcm5hbWU6cGFzc3dvcmQK=="
]
}
}
},
{
"response": {
"status": 401
},
"request": {
"requestType": "template",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/maven-metadata.xml",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": ""
}
},
{
"response": {
"status": 401
},
"request": {
"requestType": "template",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/test-simulations-svc-1.0-SNAPSHOT-stubs.jar.sha1",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": ""
}
},
{
"response": {
"status": 401
},
"request": {
"requestType": "template",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/test-simulations-svc-1.0-SNAPSHOT-stubs.jar.md5",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": ""
}
},
{
"response": {
"status": 200,
"body": "9a318b6f330aaf4b7088c3018e31dd4bb11b18f1",
"encodedBody": false,
"headers": {
"Connection": [
"keep-alive"
],
"Content-Length": [
"40"
],
"Content-Type": [
"application/x-checksum"
],
"Date": [
"Tue, 08 Nov 2016 15:22:26 GMT"
],
"Hoverfly": [
"Was-Here"
],
"Last-Modified": [
"Tue, 08 Nov 2016 15:22:26 GMT"
],
"Server": [
"Artifactory/4.14.0"
],
"X-Artifactory-Id": [
"aolprod1b-test"
],
"X-Node": [
"nginx-shared2b"
]
}
},
"request": {
"requestType": "template",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/maven-metadata.xml.sha1",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": "",
"headers": {
"Accept-Encoding": [
"gzip,deflate"
],
"Authorization": [
"Basic dXNlcm5hbWU6cGFzc3dvcmQK=="
],
"Cache-Control": [
"no-cache, no-store"
],
"Connection": [
"Keep-Alive"
],
"Pragma": [
"no-cache"
],
"User-Agent": [
"Aether"
]
}
}
},
{
"response": {
"status": 200,
"body": "UEsDBAoAAAgIAJxyYkkAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAnHJiSbJ/Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM+zUjDUM+Dl4uUCAFBLAwQKAAAICACccmJJAAAAAAIAAAAAAAAACgAAAGNvbnRyYWN0cy8DAFBLAwQKAAAICACccmJJkcxXfpgAAADnAAAALwAAAGNvbnRyYWN0cy9zaG91bGRCZUFibGVUb0NyZWF0ZVNpbXVsYXRpb24uZ3Jvb3Z5VY1BDsIgFET3nIIdbUxo9QpewIUe4Id+kRQE/4dqYnp30bRGZzdvJjMJzAgWpYnXTGAyCxHJak7krvZMEPAeadTGxzLotVRjNHq/ugAjyqeQVYS3gpwX91bAfImDVIfTUX1hIS8n8AWbOsklIDWEFh+N6tiF4iG7yjtIrpu2f0hvVNu2n6F5eeRUA/y55Ay5sNz1/dKbxQtQSwMECgAACAgAnHJiSQAAAAACAAAAAAAAAAkAAABtYXBwaW5ncy8DAFBLAwQKAAAICACccmJJT/HGJIsAAADBAAAALAAAAG1hcHBpbmdzL3Nob3VsZEJlQWJsZVRvQ3JlYXRlU2ltdWxhdGlvbi5qc29uVY07DsIwEET7nMJyC8ZOlI/gFCngAGtlIyzl613TRLk7dqCAcp7mzWyZEDIE10lxExLLyti+QdUAWFX2plC2rq3CCK9VZ9DmvTwnxeMakDhZW8xpxA8tMKOfjilNbgwDsJsn0rA4/cr/0OV0DEVxRH7On//2cZcR7t8LWmITfz6IgQMlUBiTitn+BlBLAQIUAwoAAAgIAJxyYkkAAAAAAgAAAAAAAAAJAAAAAAAAAAAAEADtQQAAAABNRVRBLUlORi9QSwECFAMKAAAICACccmJJsn8C7hsAAAAZAAAAFAAAAAAAAAAAAAAApIEpAAAATUVUQS1JTkYvTUFOSUZFU1QuTUZQSwECFAMKAAAICACccmJJAAAAAAIAAAAAAAAACgAAAAAAAAAAABAA/UF2AAAAY29udHJhY3RzL1BLAQIUAwoAAAgIAJxyYkmRzFd+mAAAAOcAAAAvAAAAAAAAAAAAAAC0gaAAAABjb250cmFjdHMvc2hvdWxkQmVBYmxlVG9DcmVhdGVTaW11bGF0aW9uLmdyb292eVBLAQIUAwoAAAgIAJxyYkkAAAAAAgAAAAAAAAAJAAAAAAAAAAAAEAD9QYUBAABtYXBwaW5ncy9QSwECFAMKAAAICACccmJJT/HGJIsAAADBAAAALAAAAAAAAAAAAAAAtIGuAQAAbWFwcGluZ3Mvc2hvdWxkQmVBYmxlVG9DcmVhdGVTaW11bGF0aW9uLmpzb25QSwUGAAAAAAYABgCfAQAAgwIAAAAA",
"encodedBody": true,
"headers": {
"Accept-Ranges": [
"bytes"
],
"Cache-Control": [
"no-store"
],
"Connection": [
"keep-alive"
],
"Content-Disposition": [
"attachment; filename=\"test-simulations-svc-1.0-SNAPSHOT-stubs.jar\"; filename*=UTF-8''test-simulations-svc-1.0-SNAPSHOT-stubs.jar"
],
"Content-Length": [
"1080"
],
"Content-Type": [
"application/java-archive"
],
"Date": [
"Tue, 08 Nov 2016 15:22:26 GMT"
],
"Etag": [
"6c40475c58db6745b860e7b3f0ffa1c87faa83ce"
],
"Hoverfly": [
"Was-Here"
],
"Last-Modified": [
"Wed, 02 Nov 2016 14:21:06 GMT"
],
"Server": [
"Artifactory/4.14.0"
],
"X-Artifactory-Filename": [
"test-simulations-svc-1.0-SNAPSHOT-stubs.jar"
],
"X-Artifactory-Id": [
"aolprod1b-test"
],
"X-Checksum-Md5": [
"0b8c9e9880654871beaf1cf40cd07aaf"
],
"X-Checksum-Sha1": [
"6c40475c58db6745b860e7b3f0ffa1c87faa83ce"
],
"X-Node": [
"nginx-shared2b"
]
}
},
"request": {
"requestType": "template",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/test-simulations-svc-1.0-SNAPSHOT-stubs.jar",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": ""
}
},
{
"response": {
"status": 200,
"body": "6c40475c58db6745b860e7b3f0ffa1c87faa83ce",
"encodedBody": false,
"headers": {
"Connection": [
"keep-alive"
],
"Content-Length": [
"40"
],
"Content-Type": [
"application/x-checksum"
],
"Date": [
"Tue, 08 Nov 2016 15:22:26 GMT"
],
"Hoverfly": [
"Was-Here"
],
"Last-Modified": [
"Tue, 08 Nov 2016 15:22:26 GMT"
],
"Server": [
"Artifactory/4.14.0"
],
"X-Artifactory-Id": [
"aolprod1b-test"
],
"X-Node": [
"nginx-shared2b"
]
}
},
"request": {
"requestType": "recording",
"path": "/test/libs-snapshot-local/io/test/test-simulations-svc/1.0-SNAPSHOT/test-simulations-svc-1.0-SNAPSHOT-stubs.jar.sha1",
"method": "GET",
"destination": "test.jfrog.io",
"scheme": "https",
"query": "",
"body": "",
"headers": {
"Accept-Encoding": [
"gzip,deflate"
],
"Authorization": [
"Basic dXNlcm5hbWU6cGFzc3dvcmQK=="
],
"Cache-Control": [
"no-cache, no-store"
],
"Connection": [
"Keep-Alive"
],
"Pragma": [
"no-cache"
],
"User-Agent": [
"Aether"
]
}
}
}
]
}