Automatic stub registration (#64)
before this change the support for Stub Runner Boot with Service Discovery was pretty useless since Stub Runner stubbed service discovery. That makes a lot of sense in unit / integration tests but not when you want to do some version of end to end tests. With this change you can pass a property to enable automated registration of stubs in Service Discovery. Technical changes: * Added Zookeeper registration * Added Eureka registration * Added Consul registration * Added checkstyle plugin - fixed part of exceptions
This commit is contained in:
committed by
GitHub
parent
ab535dc8ea
commit
64d6d3ef6c
51
pom.xml
51
pom.xml
@@ -27,6 +27,8 @@
|
||||
<camel.version>2.17.0</camel.version>
|
||||
<spring-cloud-stream.version>1.0.2.RELEASE</spring-cloud-stream.version>
|
||||
<spring-boot.version>1.4.0.RELEASE</spring-boot.version>
|
||||
<checkstyle.version>2.17</checkstyle.version>
|
||||
<spring-cloud-build.version>1.2.0.BUILD-SNAPSHOT</spring-cloud-build.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
@@ -310,6 +312,55 @@
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>checkstyle</id>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build-tools</artifactId>
|
||||
<version>${spring-cloud-build.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>validate</id>
|
||||
<phase>validate</phase>
|
||||
<configuration>
|
||||
<configLocation>checkstyle.xml</configLocation>
|
||||
<headerLocation>LICENSE.txt</headerLocation>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<failsOnError>true</failsOnError>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
<configuration>
|
||||
<configLocation>checkstyle.xml</configLocation>
|
||||
<headerLocation>LICENSE.txt</headerLocation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<spring-cloud-stream.version>1.0.2.RELEASE</spring-cloud-stream.version>
|
||||
<spring-cloud-zookeeper.version>1.0.3.BUILD-SNAPSHOT</spring-cloud-zookeeper.version>
|
||||
<spring-cloud-netflix.version>1.1.5.BUILD-SNAPSHOT</spring-cloud-netflix.version>
|
||||
<spring-cloud-consul.version>1.0.3.BUILD-SNAPSHOT</spring-cloud-consul.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -173,6 +174,13 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-consul-dependencies</artifactId>
|
||||
<version>${spring-cloud-consul.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<profiles>
|
||||
|
||||
@@ -2,22 +2,21 @@
|
||||
* Copyright 2009 Wilfred Springer
|
||||
* Copyright 2012 Jason Pell
|
||||
* Copyright 2013 Antonio García-Domínguez
|
||||
*
|
||||
* <p>
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* The class is bundled together with our code because it has not been
|
||||
* released to any central repository.
|
||||
*
|
||||
*/
|
||||
package repackaged.nl.flotsam.xeger;
|
||||
|
||||
@@ -35,67 +34,68 @@ import dk.brics.automaton.Transition;
|
||||
*/
|
||||
public class Xeger {
|
||||
|
||||
private final Automaton automaton;
|
||||
private Random random;
|
||||
private final Automaton automaton;
|
||||
private Random random;
|
||||
|
||||
/**
|
||||
* Constructs a new instance, accepting the regular expression and the randomizer.
|
||||
*
|
||||
* @param regex The regular expression. (Not <code>null</code>.)
|
||||
* @param random The object that will randomize the way the String is generated. (Not <code>null</code>.)
|
||||
* @throws IllegalArgumentException If the regular expression is invalid.
|
||||
*/
|
||||
public Xeger(String regex, Random random) {
|
||||
assert regex != null;
|
||||
assert random != null;
|
||||
this.automaton = new RegExp(regex).toAutomaton();
|
||||
this.random = random;
|
||||
}
|
||||
/**
|
||||
* Constructs a new instance, accepting the regular expression and the randomizer.
|
||||
*
|
||||
* @param regex The regular expression. (Not <code>null</code>.)
|
||||
* @param random The object that will randomize the way the String is generated. (Not <code>null</code>.)
|
||||
* @throws IllegalArgumentException If the regular expression is invalid.
|
||||
*/
|
||||
public Xeger(String regex, Random random) {
|
||||
assert regex != null;
|
||||
assert random != null;
|
||||
this.automaton = new RegExp(regex).toAutomaton();
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
/**
|
||||
* As {@link Xeger#Xeger(String, java.util.Random)}, creating a {@link java.util.Random} instance
|
||||
* implicityly.
|
||||
*
|
||||
* @param regex as string
|
||||
*/
|
||||
public Xeger(String regex) {
|
||||
this(regex, new Random());
|
||||
}
|
||||
/**
|
||||
* As {@link Xeger#Xeger(String, java.util.Random)}, creating a {@link java.util.Random} instance
|
||||
* implicityly.
|
||||
*
|
||||
* @param regex as string
|
||||
*/
|
||||
public Xeger(String regex) {
|
||||
this(regex, new Random());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random String that is guaranteed to match the regular expression passed to the constructor.
|
||||
* @return generated regexp
|
||||
*/
|
||||
public String generate() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
generate(builder, automaton.getInitialState());
|
||||
return builder.toString();
|
||||
}
|
||||
/**
|
||||
* Generates a random String that is guaranteed to match the regular expression passed to the constructor.
|
||||
* @return generated regexp
|
||||
*/
|
||||
public String generate() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
generate(builder, this.automaton.getInitialState());
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void generate(StringBuilder builder, State state) {
|
||||
List<Transition> transitions = state.getSortedTransitions(false);
|
||||
if (transitions.size() == 0) {
|
||||
assert state.isAccept();
|
||||
return;
|
||||
}
|
||||
int nroptions = state.isAccept() ? transitions.size() : transitions.size() - 1;
|
||||
int option = Xeger.getRandomInt(0, nroptions, random);
|
||||
if (state.isAccept() && option == 0) { // 0 is considered stop
|
||||
return;
|
||||
}
|
||||
// Moving on to next transition
|
||||
Transition transition = transitions.get(option - (state.isAccept() ? 1 : 0));
|
||||
appendChoice(builder, transition);
|
||||
generate(builder, transition.getDest());
|
||||
}
|
||||
private void generate(StringBuilder builder, State state) {
|
||||
List<Transition> transitions = state.getSortedTransitions(false);
|
||||
if (transitions.size() == 0) {
|
||||
assert state.isAccept();
|
||||
return;
|
||||
}
|
||||
int nroptions = state.isAccept() ? transitions.size() : transitions.size() - 1;
|
||||
int option = Xeger.getRandomInt(0, nroptions, this.random);
|
||||
if (state.isAccept() && option == 0) { // 0 is considered stop
|
||||
return;
|
||||
}
|
||||
// Moving on to next transition
|
||||
Transition transition = transitions.get(option - (state.isAccept() ? 1 : 0));
|
||||
appendChoice(builder, transition);
|
||||
generate(builder, transition.getDest());
|
||||
}
|
||||
|
||||
private void appendChoice(StringBuilder builder, Transition transition) {
|
||||
char c = (char) Xeger.getRandomInt(transition.getMin(), transition.getMax(), random);
|
||||
builder.append(c);
|
||||
}
|
||||
private void appendChoice(StringBuilder builder, Transition transition) {
|
||||
char c = (char) Xeger
|
||||
.getRandomInt(transition.getMin(), transition.getMax(), this.random);
|
||||
builder.append(c);
|
||||
}
|
||||
|
||||
public Random getRandom() {
|
||||
return random;
|
||||
return this.random;
|
||||
}
|
||||
|
||||
public void setRandom(Random random) {
|
||||
@@ -112,7 +112,7 @@ public class Xeger {
|
||||
*/
|
||||
static int getRandomInt(int min, int max, Random random) {
|
||||
// Use random.nextInt as it guarantees a uniform distribution
|
||||
int maxForRandom=max-min+1;
|
||||
int maxForRandom = max - min + 1;
|
||||
return random.nextInt(maxForRandom) + min;
|
||||
}
|
||||
}
|
||||
@@ -236,4 +236,41 @@ For Messaging
|
||||
[source,groovy,indent=0]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/server/StubRunnerBootSpec.groovy[tags=boot_usage]
|
||||
----
|
||||
----
|
||||
|
||||
==== Stub Runner Boot with Service Discovery
|
||||
|
||||
One of the possibilities of using Stub Runner Boot is to use it as a feed of stubs for "smoke-tests". What does it mean?
|
||||
Let's assume that you don't want to deploy 50 microservice to a test environment in order
|
||||
to check if your application is working fine. You've already executed a suite of tests during the build process
|
||||
but you would also like to ensure that the packaging of your application is fine. What you can do
|
||||
is to deploy your application to an environment, start it and run a couple of tests on it to see if
|
||||
it's working fine. We can call those tests smoke-tests since their idea is to check only a handful
|
||||
of testing scenarios.
|
||||
|
||||
The problem with this approach is such that if you're doing microservices most likely you're
|
||||
using a service discovery tool. Stub Runner Boot allows you to solve this issue by starting the
|
||||
required stubs and register them in a service discovery tool. Let's take a look at an example of
|
||||
such a setup with Eureka. Let's assume that Eureka was already running.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootEurekaExample.java[tags=stubrunnereureka]
|
||||
----
|
||||
|
||||
As you can see we want to start a Stub Runner Boot server `@EnableStubRunnerServer`, enable Eureka client `@EnableEurekaClient`
|
||||
and we want to have the stub runner feature turned on `@AutoConfigureStubRunner`.
|
||||
|
||||
Now let's assume that we want to start this application so that the stubs get automatically registered.
|
||||
We can do it by running the app `java -jar ${SYSTEM_PROPS} stub-runner-boot-eureka-example.jar` where
|
||||
`${SYSTEM_PROPS}` would contain the following list of properties
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/serverexamples/StubRunnerBootEurekaExample.java[tags=stubrunnereureka_args]
|
||||
----
|
||||
|
||||
That way your deployed application can send requests to started WireMock servers via the service
|
||||
discovery. Most likely points 1-3 could be set by default in `application.yml` cause they are not
|
||||
likely to change. That way you can provide only the list of stubs to download whenever you start
|
||||
the Stub Runner Boot.
|
||||
@@ -95,6 +95,11 @@
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
@@ -128,13 +133,23 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -85,7 +85,7 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
}
|
||||
|
||||
private boolean remoteReposMissing() {
|
||||
return remoteRepos == null || remoteRepos.isEmpty();
|
||||
return this.remoteRepos == null || this.remoteRepos.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,16 +121,16 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
if (!StringUtils.hasText(resolvedVersion)) {
|
||||
log.warn("Stub for group [" + stubsGroup + "] module [" + stubsModule
|
||||
+ "] and classifier [" + classifier + "] not found in "
|
||||
+ remoteRepos);
|
||||
+ this.remoteRepos);
|
||||
return null;
|
||||
}
|
||||
Artifact artifact = new DefaultArtifact(stubsGroup, stubsModule, classifier,
|
||||
ARTIFACT_EXTENSION, resolvedVersion);
|
||||
ArtifactRequest request = new ArtifactRequest(artifact, remoteRepos, null);
|
||||
ArtifactRequest request = new ArtifactRequest(artifact, this.remoteRepos, null);
|
||||
log.info("Resolving artifact [" + artifact
|
||||
+ "] using remote repositories " + remoteRepos);
|
||||
+ "] using remote repositories " + this.remoteRepos);
|
||||
try {
|
||||
ArtifactResult result = repositorySystem.resolveArtifact(session, request);
|
||||
ArtifactResult result = this.repositorySystem.resolveArtifact(this.session, request);
|
||||
log.info("Resolved artifact [" + artifact + "] to "
|
||||
+ result.getArtifact().getFile());
|
||||
File temporaryFile = unpackStubJarToATemporaryFolder(
|
||||
@@ -142,7 +142,7 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
log.warn(
|
||||
"Exception occurred while trying to download a stub for group ["
|
||||
+ stubsGroup + "] module [" + stubsModule
|
||||
+ "] and classifier [" + classifier + "] in " + remoteRepos,
|
||||
+ "] and classifier [" + classifier + "] in " + this.remoteRepos,
|
||||
e);
|
||||
return null;
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
remoteRepos, null);
|
||||
VersionRangeResult rangeResult;
|
||||
try {
|
||||
rangeResult = repositorySystem.resolveVersionRange(session,
|
||||
rangeResult = this.repositorySystem.resolveVersionRange(this.session,
|
||||
versionRangeRequest);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resolved version range is [" + rangeResult + "]");
|
||||
@@ -210,7 +210,7 @@ public class AetherStubDownloader implements StubDownloader {
|
||||
VersionRequest versionRequest = new VersionRequest(artifact, remoteRepos, null);
|
||||
VersionResult versionResult;
|
||||
try {
|
||||
versionResult = repositorySystem.resolveVersion(session, versionRequest);
|
||||
versionResult = this.repositorySystem.resolveVersion(this.session, versionRequest);
|
||||
}
|
||||
catch (VersionResolutionException e) {
|
||||
throw new IllegalStateException("Cannot resolve version", e);
|
||||
|
||||
@@ -60,13 +60,23 @@ class StubRunnerExecutor implements StubFinder {
|
||||
|
||||
public RunningStubs runStubs(StubRunnerOptions stubRunnerOptions,
|
||||
StubRepository repository, StubConfiguration stubConfiguration) {
|
||||
if (this.stubServer != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Returning cached version of stubs [" + stubConfiguration.toColonSeparatedDependencyNotation() + "]");
|
||||
}
|
||||
return runningStubs();
|
||||
}
|
||||
startStubServers(stubRunnerOptions, stubConfiguration, repository);
|
||||
RunningStubs runningCollaborators = new RunningStubs(Collections
|
||||
.singletonMap(stubServer.getStubConfiguration(), stubServer.getPort()));
|
||||
RunningStubs runningCollaborators = runningStubs();
|
||||
log.info("All stubs are now running " + runningCollaborators.toString());
|
||||
return runningCollaborators;
|
||||
}
|
||||
|
||||
private RunningStubs runningStubs() {
|
||||
return new RunningStubs(Collections
|
||||
.singletonMap(stubServer.getStubConfiguration(), stubServer.getPort()));
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (stubServer != null) {
|
||||
stubServer.stop();
|
||||
|
||||
@@ -61,8 +61,10 @@ 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) {
|
||||
public StubRunnerOptions(Integer minPortValue, Integer maxPortValue,
|
||||
String stubRepositoryRoot, boolean workOffline, String stubsClassifier,
|
||||
Collection<StubConfiguration> dependencies,
|
||||
Map<StubConfiguration, Integer> stubIdsToPortMapping) {
|
||||
this.minPortValue = minPortValue;
|
||||
this.maxPortValue = maxPortValue;
|
||||
this.stubRepositoryRoot = stubRepositoryRoot;
|
||||
|
||||
@@ -19,8 +19,10 @@ package org.springframework.cloud.contract.stubrunner;
|
||||
import java.io.Closeable;
|
||||
|
||||
public interface StubRunning extends Closeable, StubFinder {
|
||||
|
||||
/**
|
||||
* Runs the stubs and returns the {@link RunningStubs}
|
||||
* Runs the stubs and returns the {@link RunningStubs}. If the stubs were
|
||||
* already started then a cached version will be returned.
|
||||
*/
|
||||
RunningStubs runStubs();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -30,7 +31,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/stubs")
|
||||
@RequestMapping(value = "/stubs", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class HttpStubsController {
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -36,7 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/triggers")
|
||||
@RequestMapping(value = "/triggers", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class TriggerController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TriggerController.class);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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
|
||||
*
|
||||
* http://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.spring.cloud;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
/**
|
||||
* Conditional that checks if the user turned off the stubbed discovery mode
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.stubbed.discovery.enabled", havingValue = "false")
|
||||
public @interface ConditionalOnStubbedDiscoveryDisabled {
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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
|
||||
*
|
||||
* http://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.spring.cloud;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
/**
|
||||
* Conditional that checks if the user turned on the stubbed discovery mode.
|
||||
* The feature is turned on by default.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.stubbed.discovery.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public @interface ConditionalOnStubbedDiscoveryEnabled {
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Maps Ivy based ids to service Ids. You might want to name the service you're calling
|
||||
@@ -29,7 +31,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
* Just provide in your properties file for example:
|
||||
*
|
||||
* stubrunner.idsToServiceIds:
|
||||
* ivyNotation: someValueInsideYourCode
|
||||
* fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
@@ -59,7 +60,17 @@ public class StubMapperProperties {
|
||||
}
|
||||
|
||||
public String fromIvyNotationToId(String ivyNotation) {
|
||||
return idsToServiceIds.get(ivyNotation);
|
||||
StubConfiguration stubConfiguration = new StubConfiguration(ivyNotation);
|
||||
String id = idsToServiceIds.get(ivyNotation);
|
||||
if (StringUtils.hasText(id)) {
|
||||
return id;
|
||||
}
|
||||
String groupAndArtifact = idsToServiceIds.get(stubConfiguration.getGroupId() +
|
||||
":" + stubConfiguration.getArtifactId());
|
||||
if (StringUtils.hasText(groupAndArtifact)) {
|
||||
return groupAndArtifact;
|
||||
}
|
||||
return idsToServiceIds.get(stubConfiguration.getArtifactId());
|
||||
}
|
||||
|
||||
public String fromServiceIdToIvyNotation(String serviceId) {
|
||||
|
||||
@@ -16,16 +16,19 @@
|
||||
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.noop.NoopDiscoveryClient;
|
||||
|
||||
import org.springframework.cloud.contract.stubrunner.RunningStubs;
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder;
|
||||
import org.springframework.cloud.contract.stubrunner.util.StringUtils;
|
||||
@@ -40,6 +43,8 @@ import org.springframework.cloud.contract.stubrunner.util.StringUtils;
|
||||
*/
|
||||
class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final DiscoveryClient delegate;
|
||||
private final StubFinder stubFinder;
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
@@ -48,6 +53,9 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
StubMapperProperties stubMapperProperties, String springAppName) {
|
||||
this.delegate = delegate instanceof StubRunnerDiscoveryClient ?
|
||||
noOpDiscoveryClient(springAppName) : delegate;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found");
|
||||
}
|
||||
this.stubFinder = stubFinder;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
}
|
||||
@@ -55,6 +63,9 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
public StubRunnerDiscoveryClient(StubFinder stubFinder,
|
||||
StubMapperProperties stubMapperProperties, String springAppName) {
|
||||
this.delegate = noOpDiscoveryClient(springAppName);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will delegate calls to discovery service [" + this.delegate + "] if a stub is not found");
|
||||
}
|
||||
this.stubFinder = stubFinder;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
}
|
||||
@@ -65,12 +76,26 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return delegate.description();
|
||||
try {
|
||||
return this.delegate.description();
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to fetch description from delegate", e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServiceInstance getLocalServiceInstance() {
|
||||
return delegate.getLocalServiceInstance();
|
||||
try {
|
||||
return this.delegate.getLocalServiceInstance();
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to get local service instance from delegate", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,14 +103,27 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
String ivyNotation = stubMapperProperties.fromServiceIdToIvyNotation(serviceId);
|
||||
String serviceToFind = StringUtils.hasText(ivyNotation) ? ivyNotation : serviceId;
|
||||
URL stubUrl = stubFinder.findStubUrl(serviceToFind);
|
||||
log.info("Resolved from ivy [" + ivyNotation + "] service to find [" + serviceToFind + "]. "
|
||||
+ "Found stub is available under URL [" + stubUrl + "]");
|
||||
if (stubUrl == null) {
|
||||
return delegate.getInstances(serviceId);
|
||||
return getInstancesFromDelegate(serviceId);
|
||||
}
|
||||
return Collections.<ServiceInstance>singletonList(
|
||||
new StubRunnerServiceInstance(serviceId, stubUrl.getHost(), stubUrl.getPort(), toUri(stubUrl))
|
||||
);
|
||||
}
|
||||
|
||||
private List<ServiceInstance> getInstancesFromDelegate(String serviceId) {
|
||||
try {
|
||||
return this.delegate.getInstances(serviceId);
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to fetch instances from delegate", e);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private URI toUri(URL url) {
|
||||
try {
|
||||
return url.toURI();
|
||||
@@ -96,9 +134,20 @@ class StubRunnerDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Override
|
||||
public List<String> getServices() {
|
||||
List<String> services = delegate.getServices();
|
||||
RunningStubs runningStubs = stubFinder.findAllRunningStubs();
|
||||
List<String> services = getServicesFromDelegate();
|
||||
RunningStubs runningStubs = this.stubFinder.findAllRunningStubs();
|
||||
services.addAll(runningStubs.getAllServicesNames());
|
||||
return services;
|
||||
}
|
||||
|
||||
private List<String> getServicesFromDelegate() {
|
||||
try {
|
||||
return this.delegate.getServices();
|
||||
} catch (Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Failed to fetch services from delegate", e);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public class StubRunnerSpringCloudAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBean(DiscoveryClient.class)
|
||||
@Primary
|
||||
@ConditionalOnStubbedDiscoveryEnabled
|
||||
public DiscoveryClient stubRunnerDiscoveryClientWrapper(DiscoveryClient discoveryClient,
|
||||
StubFinder stubFinder,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
@@ -51,7 +52,9 @@ public class StubRunnerSpringCloudAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean(DiscoveryClient.class)
|
||||
@ConditionalOnStubbedDiscoveryEnabled
|
||||
public DiscoveryClient stubRunnerDiscoveryClient(StubFinder stubFinder,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
@Value("${spring.application.name:unknown}") String springAppName) {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud;
|
||||
|
||||
/**
|
||||
* Contract for registering stubs in a Service Discovery.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface StubsRegistrar extends AutoCloseable {
|
||||
void registerStubs();
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.consul;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
|
||||
/**
|
||||
* Registers all stubs in Zookeeper Service Discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ConsulStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
private final ConsulClient consulClient;
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
private final List<NewService> services = new LinkedList<>();
|
||||
|
||||
public ConsulStubsRegistrar(StubRunning stubRunning, ConsulClient consulClient,
|
||||
StubMapperProperties stubMapperProperties) {
|
||||
this.stubRunning = stubRunning;
|
||||
this.consulClient = consulClient;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
}
|
||||
|
||||
@Override public void registerStubs() {
|
||||
Map<StubConfiguration, Integer> activeStubs = this.stubRunning.runStubs()
|
||||
.validNamesAndPorts();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : activeStubs.entrySet()) {
|
||||
NewService newService = newService(entry.getKey(), entry.getValue());
|
||||
this.services.add(newService);
|
||||
try {
|
||||
this.consulClient.agentServiceRegister(newService);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception occurred while trying to register a stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected NewService newService(StubConfiguration stubConfiguration, Integer port) {
|
||||
NewService newService = new NewService();
|
||||
newService.setAddress("localhost");
|
||||
newService.setId(stubConfiguration.getArtifactId());
|
||||
newService.setName(name(stubConfiguration));
|
||||
newService.setPort(port);
|
||||
return newService;
|
||||
}
|
||||
|
||||
protected String name(StubConfiguration stubConfiguration) {
|
||||
String resolvedName = this.stubMapperProperties.fromIvyNotationToId(
|
||||
stubConfiguration.toColonSeparatedDependencyNotation());
|
||||
if (StringUtils.hasText(resolvedName)) {
|
||||
return resolvedName;
|
||||
}
|
||||
return stubConfiguration.getArtifactId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
for (NewService service : this.services) {
|
||||
this.consulClient.agentServiceDeregister(service.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.spring.cloud.consul;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryDisabled;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
|
||||
/**
|
||||
* Autoconfiguration for registering stubs in a Zookeeper Service discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(StubRunnerConfiguration.class)
|
||||
@ConditionalOnClass(ConsulClient.class)
|
||||
@ConditionalOnStubbedDiscoveryDisabled
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.consul.enabled", matchIfMissing = true)
|
||||
public class StubRunnerSpringCloudConsulAutoConfiguration {
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning, ConsulClient consulClient,
|
||||
StubMapperProperties stubMapperProperties) {
|
||||
return new ConsulStubsRegistrar(stubRunning, consulClient, stubMapperProperties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
|
||||
public class ApplicationStatus {
|
||||
private Application application;
|
||||
private InstanceInfo.InstanceStatus status;
|
||||
|
||||
public ApplicationStatus(Application application,
|
||||
InstanceInfo.InstanceStatus status) {
|
||||
this.application = application;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ApplicationStatus() {
|
||||
}
|
||||
|
||||
public Application getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
public InstanceInfo.InstanceStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2015 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
|
||||
*
|
||||
* http://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.spring.cloud.eureka;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
|
||||
/**
|
||||
* Conditional that checks if Eureka is enabled
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Documented
|
||||
@ConditionalOnProperty(value = "eureka.client.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@interface ConditionalOnEurekaEnabled {
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.InstanceInfoFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import com.netflix.discovery.shared.resolver.ClosableResolver;
|
||||
import com.netflix.discovery.shared.resolver.EurekaEndpoint;
|
||||
import com.netflix.discovery.shared.resolver.aws.ApplicationsResolver;
|
||||
import com.netflix.discovery.shared.resolver.aws.AwsEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClientFactory;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClients;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import com.netflix.discovery.shared.transport.EurekaTransportConfig;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
import com.netflix.discovery.shared.transport.decorator.MetricsCollectingEurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.jersey.JerseyEurekaHttpClientFactory;
|
||||
import com.sun.jersey.api.client.filter.ClientFilter;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* Taken from https://github.com/spencergibb/spring-cloud-netflix-eureka-lite
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Eureka {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final InetUtils inetUtils;
|
||||
final CloudEurekaClient eurekaClient;
|
||||
final EurekaClientConfigBean clientConfig;
|
||||
final EurekaTransport transport;
|
||||
|
||||
public Eureka(InetUtils inetUtils, CloudEurekaClient eurekaClient) {
|
||||
this.inetUtils = inetUtils;
|
||||
this.eurekaClient = eurekaClient;
|
||||
this.clientConfig = new EurekaClientConfigBean();
|
||||
this.clientConfig.setRegisterWithEureka(false); // turn off registering with eureka, let apps send heartbeats.
|
||||
this.transport = createTransport();
|
||||
}
|
||||
|
||||
public Registration register(Application application) {
|
||||
long start = System.currentTimeMillis();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Starting registration of %s", application));
|
||||
}
|
||||
InstanceInfo instanceInfo = getInstanceInfo(application);
|
||||
Registration registration = new Registration(instanceInfo, application);
|
||||
long duration = (System.currentTimeMillis() - start) ;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Created registration for %s in %s ms", application, duration));
|
||||
}
|
||||
register(registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
public InstanceInfo getInstanceInfo(Application application, long lastUpdatedTimestamp, long lastDirtyTimestamp) {
|
||||
InstanceInfo instanceInfo = getInstanceInfo(application);
|
||||
instanceInfo = new InstanceInfo.Builder(instanceInfo)
|
||||
.setLastDirtyTimestamp(lastDirtyTimestamp)
|
||||
.setLastUpdatedTimestamp(lastUpdatedTimestamp)
|
||||
.build();
|
||||
return instanceInfo;
|
||||
}
|
||||
|
||||
public InstanceInfo getInstanceInfo(Application application) {
|
||||
EurekaInstanceConfigBean instanceConfig = new EurekaInstanceConfigBean(inetUtils);
|
||||
instanceConfig.setInstanceEnabledOnit(true);
|
||||
instanceConfig.setAppname(application.getName());
|
||||
instanceConfig.setVirtualHostName(application.getName());
|
||||
instanceConfig.setInstanceId(application.getInstance_id());
|
||||
instanceConfig.setHostname(application.getHostname());
|
||||
instanceConfig.setNonSecurePort(application.getPort());
|
||||
|
||||
return new InstanceInfoFactory().create(instanceConfig);
|
||||
}
|
||||
|
||||
public EurekaTransport createTransport() {
|
||||
TransportClientFactory transportClientFactory = newTransportClientFactory(clientConfig, Collections.<ClientFilter>emptyList());
|
||||
EurekaTransportConfig transportConfig = clientConfig.getTransportConfig();
|
||||
|
||||
ClosableResolver<AwsEndpoint> bootstrapResolver = EurekaHttpClients.newBootstrapResolver(
|
||||
clientConfig,
|
||||
transportConfig,
|
||||
transportClientFactory,
|
||||
null,
|
||||
new ApplicationsResolver.ApplicationsSource() {
|
||||
@Override
|
||||
public Applications getApplications(int stalenessThreshold, TimeUnit timeUnit) {
|
||||
long thresholdInMs = TimeUnit.MILLISECONDS.convert(stalenessThreshold, timeUnit);
|
||||
long delay = eurekaClient.getLastSuccessfulRegistryFetchTimePeriod();
|
||||
if (delay > thresholdInMs) {
|
||||
log.info(String.format("Local registry is too stale for local lookup. Threshold:%s, actual:%s",
|
||||
thresholdInMs, delay));
|
||||
return null;
|
||||
} else {
|
||||
return eurekaClient.getApplications();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
EurekaHttpClientFactory httpClientFactory;
|
||||
try {
|
||||
httpClientFactory = EurekaHttpClients.registrationClientFactory(
|
||||
bootstrapResolver,
|
||||
transportClientFactory,
|
||||
transportConfig
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.warn("Experimental transport initialization failure", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return new EurekaTransport(httpClientFactory, httpClientFactory.newClient(), transportClientFactory, bootstrapResolver);
|
||||
}
|
||||
|
||||
public static TransportClientFactory newTransportClientFactory(
|
||||
final EurekaClientConfig clientConfig,
|
||||
final Collection<ClientFilter> additionalFilters) {
|
||||
final TransportClientFactory jerseyFactory = JerseyEurekaHttpClientFactory.create(
|
||||
clientConfig, additionalFilters, null, null);
|
||||
final TransportClientFactory metricsFactory = MetricsCollectingEurekaHttpClient.createFactory(jerseyFactory);
|
||||
|
||||
return new TransportClientFactory() {
|
||||
@Override
|
||||
public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
|
||||
return metricsFactory.newClient(serviceUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
metricsFactory.shutdown();
|
||||
jerseyFactory.shutdown();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Renew with the eureka service by making the appropriate REST call
|
||||
*/
|
||||
public boolean renew(Registration registration) {
|
||||
InstanceInfo instanceInfo = registration.getInstanceInfo();
|
||||
EurekaHttpResponse<InstanceInfo> httpResponse;
|
||||
try {
|
||||
httpResponse = this.transport.getEurekaHttpClient().sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("EurekaLite_%s/%s - Heartbeat status: %s", instanceInfo.getAppName(), instanceInfo.getId(), httpResponse.getStatusCode()));
|
||||
}
|
||||
if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND.value()) {
|
||||
log.info(String.format("EurekaLite_%s/%s - Re-registering apps/%s", instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo.getAppName()));
|
||||
return register(registration);
|
||||
}
|
||||
return httpResponse.getStatusCode() == HttpStatus.OK.value();
|
||||
} catch (Exception e) {
|
||||
log.error("EurekaLite_"+instanceInfo.getAppName()+"/"+ instanceInfo.getId() + " - was unable to send heartbeat!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with the eureka service by making the appropriate REST call.
|
||||
*/
|
||||
protected boolean register(Registration registration) {
|
||||
InstanceInfo instanceInfo = registration.getInstanceInfo();
|
||||
log.info(String.format("EurekaLite_%s/%s: registering service...", instanceInfo.getAppName(), instanceInfo.getId()));
|
||||
EurekaHttpResponse<Void> httpResponse;
|
||||
try {
|
||||
httpResponse = this.transport.getEurekaHttpClient().register(instanceInfo);
|
||||
} catch (Exception e) {
|
||||
log.warn("EurekaLite_"+instanceInfo.getAppName()+"/"+ instanceInfo.getId() + " - registration failed " + e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(String.format("EurekaLite_%s/%s - registration status: %s", instanceInfo.getAppName(), instanceInfo.getId(), httpResponse.getStatusCode()));
|
||||
}
|
||||
return httpResponse.getStatusCode() == HttpStatus.NO_CONTENT.value();
|
||||
}
|
||||
|
||||
public void shutdown(Registration registration) {
|
||||
InstanceInfo instanceInfo = registration.getInstanceInfo();
|
||||
try {
|
||||
EurekaHttpResponse<Void> httpResponse = this.transport.getEurekaHttpClient().cancel(instanceInfo.getAppName(), instanceInfo.getInstanceId());
|
||||
log.info(String.format("EurekaLite_%s/%s - deregister status: %s", instanceInfo.getAppName(), instanceInfo.getId(), httpResponse.getStatusCode()));
|
||||
} catch (Exception e) {
|
||||
log.error("EurekaLite_"+instanceInfo.getAppName()+"/"+ instanceInfo.getId() + " - de-registration failed " + e.getMessage(), e);
|
||||
}
|
||||
this.transport.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from https://github.com/spencergibb/spring-cloud-netflix-eureka-lite
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class EurekaTransport {
|
||||
private final EurekaHttpClientFactory eurekaHttpClientFactory;
|
||||
private final EurekaHttpClient eurekaHttpClient;
|
||||
private final TransportClientFactory transportClientFactory;
|
||||
private final ClosableResolver closableResolver;
|
||||
|
||||
public EurekaTransport(EurekaHttpClientFactory eurekaHttpClientFactory,
|
||||
EurekaHttpClient eurekaHttpClient,
|
||||
TransportClientFactory transportClientFactory,
|
||||
ClosableResolver closableResolver) {
|
||||
this.eurekaHttpClientFactory = eurekaHttpClientFactory;
|
||||
this.eurekaHttpClient = eurekaHttpClient;
|
||||
this.transportClientFactory = transportClientFactory;
|
||||
this.closableResolver = closableResolver;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
eurekaHttpClientFactory.shutdown();
|
||||
eurekaHttpClient.shutdown();
|
||||
transportClientFactory.shutdown();
|
||||
closableResolver.shutdown();
|
||||
}
|
||||
|
||||
public EurekaHttpClientFactory getEurekaHttpClientFactory() {
|
||||
return eurekaHttpClientFactory;
|
||||
}
|
||||
|
||||
public EurekaHttpClient getEurekaHttpClient() {
|
||||
return eurekaHttpClient;
|
||||
}
|
||||
|
||||
public TransportClientFactory getTransportClientFactory() {
|
||||
return transportClientFactory;
|
||||
}
|
||||
|
||||
public ClosableResolver getClosableResolver() {
|
||||
return closableResolver;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taken from https://github.com/spencergibb/spring-cloud-netflix-eureka-lite
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Application {
|
||||
private String name;
|
||||
private String instance_id;
|
||||
private String hostname;
|
||||
private int port;
|
||||
|
||||
public Application(String name, String instance_id, String hostname, int port) {
|
||||
this.name = name;
|
||||
this.instance_id = instance_id;
|
||||
this.hostname = hostname;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Application() {
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String getRegistrationKey() {
|
||||
return computeRegistrationKey(this.name, instance_id);
|
||||
}
|
||||
|
||||
static String computeRegistrationKey(String name, String instanceId) {
|
||||
return name + ":" + instanceId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getInstance_id() {
|
||||
return instance_id;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled service that automatically will renew registrations in Eureka
|
||||
*/
|
||||
class Renewer implements Runnable {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
final Eureka eureka;
|
||||
final Registration registration;
|
||||
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
|
||||
Renewer(int flushInterval, Eureka eureka,
|
||||
Registration registration) {
|
||||
this.eureka = eureka;
|
||||
this.registration = registration;
|
||||
this.scheduler.scheduleWithFixedDelay(this, 0, flushInterval, SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Renewing registration [" + this.registration + "]");
|
||||
}
|
||||
this.eureka.renew(this.registration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Registers all stubs in Eureka Service Discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class EurekaStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
private final Eureka eurekaClient;
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
private final List<Renewer> discoveryList = new LinkedList<>();
|
||||
|
||||
public EurekaStubsRegistrar(StubRunning stubRunning, Eureka eureka,
|
||||
StubMapperProperties stubMapperProperties) {
|
||||
this.stubRunning = stubRunning;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
this.eurekaClient = eureka;
|
||||
}
|
||||
|
||||
@Override public void registerStubs() {
|
||||
Map<StubConfiguration, Integer> activeStubs = this.stubRunning.runStubs()
|
||||
.validNamesAndPorts();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : activeStubs.entrySet()) {
|
||||
Application application = new Application(name(entry.getKey()), entry.getKey().getArtifactId(), "localhost", entry.getValue());
|
||||
try {
|
||||
Registration register = this.eurekaClient.register(application);
|
||||
this.discoveryList.add(new Renewer(this.eurekaClient.clientConfig.getInstanceInfoReplicationIntervalSeconds() / 2, this.eurekaClient, register));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception occurred while trying to register a stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String name(StubConfiguration stubConfiguration) {
|
||||
String resolvedName = this.stubMapperProperties.fromIvyNotationToId(
|
||||
stubConfiguration.toColonSeparatedDependencyNotation());
|
||||
if (StringUtils.hasText(resolvedName)) {
|
||||
return resolvedName;
|
||||
}
|
||||
return stubConfiguration.getArtifactId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
for (Renewer renewer : this.discoveryList) {
|
||||
this.eurekaClient.shutdown(renewer.registration);
|
||||
renewer.scheduler.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.eureka;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
|
||||
/**
|
||||
* Taken from https://github.com/spencergibb/spring-cloud-netflix-eureka-lite
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Registration {
|
||||
private final InstanceInfo instanceInfo;
|
||||
private final ApplicationStatus applicationStatus;
|
||||
|
||||
public Registration(InstanceInfo instanceInfo, ApplicationStatus applicationStatus) {
|
||||
this.instanceInfo = instanceInfo;
|
||||
this.applicationStatus = applicationStatus;
|
||||
}
|
||||
|
||||
public Registration(InstanceInfo instanceInfo, Application application) {
|
||||
this(instanceInfo, new ApplicationStatus(application, InstanceInfo.InstanceStatus.UP));
|
||||
}
|
||||
|
||||
public String getRegistrationKey() {
|
||||
return this.applicationStatus.getApplication().getRegistrationKey();
|
||||
}
|
||||
|
||||
public String getApplicationName() {
|
||||
return this.applicationStatus.getApplication().getName();
|
||||
}
|
||||
|
||||
public InstanceInfo getInstanceInfo() {
|
||||
return instanceInfo;
|
||||
}
|
||||
|
||||
public ApplicationStatus getApplicationStatus() {
|
||||
return applicationStatus;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "Registration{" + "instanceInfo=" + instanceInfo + ", applicationStatus="
|
||||
+ applicationStatus + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.spring.cloud.eureka;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryDisabled;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.netflix.appinfo.ApplicationInfoManager;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
|
||||
/**
|
||||
* Autoconfiguration for registering stubs in a Eureka Service discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({StubRunnerConfiguration.class, EurekaClientAutoConfiguration.class})
|
||||
@ConditionalOnClass(CloudEurekaClient.class)
|
||||
@ConditionalOnStubbedDiscoveryDisabled
|
||||
@ConditionalOnEurekaEnabled
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.eureka.enabled", matchIfMissing = true)
|
||||
public class StubRunnerSpringCloudEurekaAutoConfiguration {
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning, Eureka eureka,
|
||||
StubMapperProperties stubMapperProperties) {
|
||||
return new EurekaStubsRegistrar(stubRunning, eureka, stubMapperProperties);
|
||||
}
|
||||
|
||||
@Bean(name = "eurekaRegistrar")
|
||||
public Eureka eureka(InetUtils inetUtils, ApplicationInfoManager manager,
|
||||
EurekaClientConfig config, ApplicationContext applicationContext) {
|
||||
return new Eureka(inetUtils, new CloudEurekaClient(manager, config, applicationContext));
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,24 @@
|
||||
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.ribbon;
|
||||
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryEnabled;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClients;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ServerList.class)
|
||||
@ConditionalOnBean(StubMapperProperties.class)
|
||||
@AutoConfigureAfter(RibbonAutoConfiguration.class)
|
||||
@RibbonClients(defaultConfiguration = StubRunnerRibbonConfiguration.class)
|
||||
@ConditionalOnStubbedDiscoveryEnabled
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.ribbon.enabled", matchIfMissing = true)
|
||||
public class StubRunnerRibbonAutoConfiguration {
|
||||
|
||||
|
||||
@@ -43,9 +43,8 @@ class StubRunnerRibbonServerList implements ServerList<Server> {
|
||||
private final ServerList<Server> serverList;
|
||||
|
||||
StubRunnerRibbonServerList(final StubFinder stubFinder,
|
||||
final StubMapperProperties stubMapperProperties,
|
||||
final IClientConfig clientConfig,
|
||||
final ServerList<?> delegate) {
|
||||
final StubMapperProperties stubMapperProperties,
|
||||
final IClientConfig clientConfig, final ServerList<?> delegate) {
|
||||
String serviceName = clientConfig.getClientName();
|
||||
String mappedServiceName = StringUtils
|
||||
.hasText(stubMapperProperties.fromServiceIdToIvyNotation(serviceName)) ?
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.spring.cloud.zookeeper;
|
||||
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryDisabled;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar;
|
||||
import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Autoconfiguration for registering stubs in a Zookeeper Service discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(StubRunnerConfiguration.class)
|
||||
@ConditionalOnBean({ CuratorFramework.class, ZookeeperDiscoveryProperties.class})
|
||||
@ConditionalOnClass(org.apache.curator.x.discovery.ServiceInstance.class)
|
||||
@ConditionalOnStubbedDiscoveryDisabled
|
||||
@ConditionalOnProperty(value = "stubrunner.cloud.zookeeper.enabled", matchIfMissing = true)
|
||||
public class StubRunnerSpringCloudZookeeperAutoConfiguration {
|
||||
|
||||
@Bean(initMethod = "registerStubs")
|
||||
public StubsRegistrar stubsRegistrar(StubRunning stubRunning, CuratorFramework curatorFramework,
|
||||
StubMapperProperties stubMapperProperties, ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
|
||||
return new ZookeeperStubsRegistrar(stubRunning, curatorFramework, stubMapperProperties, zookeeperDiscoveryProperties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.x.discovery.ServiceDiscovery;
|
||||
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
||||
import org.apache.curator.x.discovery.ServiceInstance;
|
||||
import org.apache.curator.x.discovery.UriSpec;
|
||||
import org.springframework.cloud.contract.stubrunner.StubConfiguration;
|
||||
import org.springframework.cloud.contract.stubrunner.StubRunning;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubsRegistrar;
|
||||
import org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryProperties;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Registers all stubs in Zookeeper Service Discovery
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ZookeeperStubsRegistrar implements StubsRegistrar {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private final StubRunning stubRunning;
|
||||
private final CuratorFramework curatorFramework;
|
||||
private final StubMapperProperties stubMapperProperties;
|
||||
private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;
|
||||
private final List<ServiceDiscovery> discoveryList = new LinkedList<>();
|
||||
|
||||
public ZookeeperStubsRegistrar(StubRunning stubRunning, CuratorFramework curatorFramework,
|
||||
StubMapperProperties stubMapperProperties,
|
||||
ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
|
||||
this.stubRunning = stubRunning;
|
||||
this.curatorFramework = curatorFramework;
|
||||
this.stubMapperProperties = stubMapperProperties;
|
||||
this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
|
||||
}
|
||||
|
||||
@Override public void registerStubs() {
|
||||
Map<StubConfiguration, Integer> activeStubs = this.stubRunning.runStubs()
|
||||
.validNamesAndPorts();
|
||||
for (Map.Entry<StubConfiguration, Integer> entry : activeStubs.entrySet()) {
|
||||
ServiceInstance serviceInstance = serviceInstance(entry.getKey(), entry.getValue());
|
||||
ServiceDiscovery serviceDiscovery = serviceDiscovery(serviceInstance);
|
||||
this.discoveryList.add(serviceDiscovery);
|
||||
try {
|
||||
serviceDiscovery.start();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully registered stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("Exception occurred while trying to register a stub [" + entry.getKey().toColonSeparatedDependencyNotation()
|
||||
+ "] in Service Discovery", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected ServiceInstance serviceInstance(StubConfiguration stubConfiguration, int port) {
|
||||
try {
|
||||
return ServiceInstance.builder().uriSpec(new UriSpec(this.zookeeperDiscoveryProperties.getUriSpec()))
|
||||
.address("localhost").port(port).name(name(stubConfiguration))
|
||||
.build();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String name(StubConfiguration stubConfiguration) {
|
||||
String resolvedName = this.stubMapperProperties.fromIvyNotationToId(
|
||||
stubConfiguration.toColonSeparatedDependencyNotation());
|
||||
if (StringUtils.hasText(resolvedName)) {
|
||||
return resolvedName;
|
||||
}
|
||||
return stubConfiguration.getArtifactId();
|
||||
}
|
||||
|
||||
protected ServiceDiscovery serviceDiscovery(ServiceInstance serviceInstance) {
|
||||
return ServiceDiscoveryBuilder.builder(Void.class)
|
||||
.basePath(this.zookeeperDiscoveryProperties.getRoot())
|
||||
.client(this.curatorFramework).thisInstance(serviceInstance).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
for (ServiceDiscovery discovery : this.discoveryList) {
|
||||
discovery.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,4 +5,7 @@ org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloud
|
||||
org.springframework.cloud.contract.stubrunner.spring.cloud.ribbon.StubRunnerRibbonAutoConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.messaging.stream.StubRunnerStreamConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.messaging.integration.StubRunnerIntegrationConfiguration,\
|
||||
org.springframework.cloud.contract.stubrunner.messaging.camel.StubRunnerCamelConfiguration
|
||||
org.springframework.cloud.contract.stubrunner.messaging.camel.StubRunnerCamelConfiguration,\
|
||||
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
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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
|
||||
*
|
||||
* http://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 org.junit.Ignore
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Suite
|
||||
import org.junit.runners.Suite.SuiteClasses
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfigurationSpec
|
||||
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloudAutoConfigurationSpec
|
||||
|
||||
/**
|
||||
* A test suite for probing weird ordering problems in the tests.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(Suite)
|
||||
@SuiteClasses([
|
||||
StubRunnerSpringCloudAutoConfigurationSpec,
|
||||
StubRunnerConfigurationSpec
|
||||
])
|
||||
@Ignore
|
||||
public class AdhocTestSuite {
|
||||
|
||||
}
|
||||
@@ -34,4 +34,13 @@ class StubConfigurationSpec extends Specification {
|
||||
stubConfiguration.classifier == 'classifier'
|
||||
stubConfiguration.version == 'version'
|
||||
}
|
||||
|
||||
def 'should return ivy notation'() {
|
||||
given:
|
||||
String ivy = 'group:artifact:version:classifier'
|
||||
when:
|
||||
StubConfiguration stubConfiguration = new StubConfiguration(ivy)
|
||||
then:
|
||||
stubConfiguration.toColonSeparatedDependencyNotation() == ivy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.serverexamples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableStubRunnerServer
|
||||
@EnableDiscoveryClient
|
||||
@AutoConfigureStubRunner
|
||||
public class StubRunnerBootConsulExample {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StubRunnerBootConsulExample.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
|
||||
-Dstubrunner.repositoryRoot=classpath:m2repo/repository/
|
||||
-Dstubrunner.cloud.stubbed.discovery.enabled=false
|
||||
-Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.cloud.contract.verifier.stubs:bootService
|
||||
-Dstubrunner.idsToServiceIds.fraudDetectionServer=someNameThatShouldMapFraudDetectionServer
|
||||
-Dstubrunner.cloud.consul.enabled=true
|
||||
-Dstubrunner.camel.enabled=false
|
||||
-Dspring.cloud.zookeeper.enabled=false
|
||||
-Deureka.client.enabled=false
|
||||
-Dspring.cloud.zookeeper.discovery.enabled=false
|
||||
-Ddebug=true
|
||||
-Dspring.cloud.consul.host=192.168.99.100
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.serverexamples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
// tag::stubrunnereureka[]
|
||||
@SpringBootApplication
|
||||
@EnableStubRunnerServer
|
||||
@EnableEurekaClient
|
||||
@AutoConfigureStubRunner
|
||||
public class StubRunnerBootEurekaExample {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StubRunnerBootEurekaExample.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
// end::stubrunnereureka[]
|
||||
|
||||
/*
|
||||
|
||||
// tag::stubrunnereureka_args[]
|
||||
-Dstubrunner.repositoryRoot=http://repo.spring.io/snapshots (1)
|
||||
-Dstubrunner.cloud.stubbed.discovery.enabled=false (2)
|
||||
-Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.cloud.contract.verifier.stubs:bootService (3)
|
||||
-Dstubrunner.idsToServiceIds.fraudDetectionServer=someNameThatShouldMapFraudDetectionServer (4)
|
||||
|
||||
(1) - we tell Stub Runner where all the stubs reside
|
||||
(2) - we don't want the default behaviour where the discovery service is stubbed. That's why the stub registration will be picked
|
||||
(3) - we provide a list of stubs to download
|
||||
(4) - we provide a list of artifactId to serviceId mapping
|
||||
// end::stubrunnereureka_args[]
|
||||
|
||||
|
||||
-Dstubrunner.cloud.eureka.enabled=true
|
||||
-Dstubrunner.repositoryRoot=classpath:m2repo/repository/
|
||||
-Dstubrunner.camel.enabled=false
|
||||
-Dspring.cloud.zookeeper.enabled=false
|
||||
-Dspring.cloud.zookeeper.discovery.enabled=false
|
||||
-Ddebug=true
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.serverexamples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.contract.stubrunner.server.EnableStubRunnerServer;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableStubRunnerServer
|
||||
@EnableDiscoveryClient
|
||||
@AutoConfigureStubRunner
|
||||
public class StubRunnerBootZookeeperExample {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(StubRunnerBootZookeeperExample.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
|
||||
-Dstubrunner.ids=org.springframework.cloud.contract.verifier.stubs:loanIssuance,org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer,org.springframework.cloud.contract.verifier.stubs:bootService
|
||||
-Dstubrunner.idsToServiceIds.fraudDetectionServer=someNameThatShouldMapFraudDetectionServer
|
||||
-Dstubrunner.cloud.stubbed.discovery.enabled=false
|
||||
-Dstubrunner.cloud.zookeepr.enabled=true
|
||||
-Dstubrunner.repositoryRoot=classpath:m2repo/repository/
|
||||
-Dstubrunner.camel.enabled=false
|
||||
-Deureka.client.enabled=false
|
||||
-Ddebug=true
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class StubMapperPropertiesSpec extends Specification {
|
||||
|
||||
def "should convert ivy notation to serviceId by fallbacking to artifactId if nothing else matches"() {
|
||||
given:
|
||||
Map<String, String> idsToServiceIds = [
|
||||
fraudDetectionServer: 'someNameThatShouldMapFraudDetectionServer'
|
||||
]
|
||||
StubMapperProperties properties = new StubMapperProperties(idsToServiceIds: idsToServiceIds)
|
||||
expect:
|
||||
'someNameThatShouldMapFraudDetectionServer' == properties.fromIvyNotationToId('fraudDetectionServer')
|
||||
'someNameThatShouldMapFraudDetectionServer' == properties.fromIvyNotationToId('groupid:fraudDetectionServer')
|
||||
'someNameThatShouldMapFraudDetectionServer' == properties.fromIvyNotationToId('groupid:fraudDetectionServer:+:classifier')
|
||||
}
|
||||
}
|
||||
@@ -16,34 +16,37 @@
|
||||
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud
|
||||
|
||||
import org.apache.curator.test.TestingServer
|
||||
import org.junit.AfterClass
|
||||
import org.junit.BeforeClass
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced
|
||||
import org.springframework.cloud.consul.ConsulAutoConfiguration
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.cloud.zookeeper.ZookeeperProperties
|
||||
import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceDiscovery
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
|
||||
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.ContextConfiguration
|
||||
import org.springframework.util.SocketUtils
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = ["stubrunner.camel.enabled=false"])
|
||||
properties = ["stubrunner.camel.enabled=false",
|
||||
"spring.cloud.zookeeper.enabled=false",
|
||||
"spring.cloud.consul.enabled=false",
|
||||
"eureka.client.enabled=false",
|
||||
"stubrunner.cloud.stubbed.discovery.enabled=true",
|
||||
"spring.cloud.consul.discovery.enabled=false",
|
||||
"spring.cloud.zookeeper.discovery.enabled=false"])
|
||||
// tag::autoconfigure[]
|
||||
@AutoConfigureStubRunner(
|
||||
ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
|
||||
@@ -56,9 +59,6 @@ class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
|
||||
|
||||
@Autowired StubFinder stubFinder
|
||||
@Autowired @LoadBalanced RestTemplate restTemplate
|
||||
// TODO: this shouldn't be needed?
|
||||
@Autowired ZookeeperServiceDiscovery zookeeperServiceDiscovery
|
||||
@Autowired StubRunnerProperties stubRunnerProperties
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
@@ -67,10 +67,6 @@ class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
|
||||
System.clearProperty("stubrunner.classifier")
|
||||
}
|
||||
|
||||
def setup() {
|
||||
println "StubRunner properties are [$stubRunnerProperties]"
|
||||
}
|
||||
|
||||
// tag::test[]
|
||||
def 'should make service discovery work'() {
|
||||
expect: 'WireMocks are running'
|
||||
@@ -82,29 +78,11 @@ class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
|
||||
}
|
||||
// end::test[]
|
||||
|
||||
TestingServer startTestingServer() {
|
||||
return new TestingServer(SocketUtils.findAvailableTcpPort())
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
zookeeperServiceDiscovery?.serviceDiscovery?.close()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableDiscoveryClient
|
||||
@EnableAutoConfiguration(exclude = [RibbonZookeeperAutoConfiguration, EurekaClientAutoConfiguration,
|
||||
ConsulAutoConfiguration, ZookeeperAutoConfiguration])
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
TestingServer testingServer() {
|
||||
return new TestingServer(SocketUtils.findAvailableTcpPort())
|
||||
}
|
||||
|
||||
@Bean
|
||||
ZookeeperProperties zookeeperProperties() {
|
||||
return new ZookeeperProperties(connectString: testingServer().connectString)
|
||||
}
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.spring.cloud.consul
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient
|
||||
import com.ecwid.consul.v1.agent.model.NewService
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.TypeSafeMatcher
|
||||
import org.junit.AfterClass
|
||||
import org.junit.BeforeClass
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
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 spock.lang.Specification
|
||||
|
||||
import static org.mockito.BDDMockito.then
|
||||
import static org.mockito.Matchers.argThat
|
||||
import static org.mockito.Mockito.mock
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = ["stubrunner.camel.enabled=false",
|
||||
"eureka.client.enabled=false",
|
||||
"spring.cloud.zookeeper.enabled=false",
|
||||
"stubrunner.cloud.stubbed.discovery.enabled=false",
|
||||
"stubrunner.cloud.eureka.enabled=false",
|
||||
"spring.cloud.zookeeper.discovery.enabled=false",
|
||||
"stubrunner.cloud.consul.enabled=true",
|
||||
"stubrunner.cloud.zookeeper.enabled=false",
|
||||
"debug=true"])
|
||||
@AutoConfigureStubRunner( ids =
|
||||
["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
|
||||
"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
|
||||
"org.springframework.cloud.contract.verifier.stubs:bootService"],
|
||||
repositoryRoot = "classpath:m2repo/repository/")
|
||||
@DirtiesContext
|
||||
class StubRunnerSpringCloudConsulAutoConfigurationSpec extends Specification {
|
||||
|
||||
@Autowired ConsulClient client
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
static void setupProps() {
|
||||
System.clearProperty("stubrunner.stubs.repository.root");
|
||||
System.clearProperty("stubrunner.stubs.classifier");
|
||||
}
|
||||
|
||||
def 'should make service discovery work for #serviceName'() {
|
||||
given:
|
||||
final String expectedId = serviceName.split(':')[0]
|
||||
final String expectedName = serviceName.split(':')[1]
|
||||
when: 'Consul registration took place for 3 stubs'
|
||||
then(client).should().agentServiceRegister(argThat(new NewServiceMatcher(expectedId, expectedName)))
|
||||
then:
|
||||
noExceptionThrown()
|
||||
where:
|
||||
serviceName << ['loanIssuance:loanIssuance', 'bootService:bootService', 'fraudDetectionServer:someNameThatShouldMapFraudDetectionServer']
|
||||
}
|
||||
|
||||
private static class NewServiceMatcher extends TypeSafeMatcher<NewService> {
|
||||
|
||||
private final String expectedId
|
||||
private final String expectedName
|
||||
|
||||
NewServiceMatcher(String expectedId, String expectedName) {
|
||||
this.expectedId = expectedId
|
||||
this.expectedName = expectedName
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesSafely(NewService item) {
|
||||
return item.id == expectedId && item.name == expectedName
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeTo(Description description) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableDiscoveryClient
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ConsulClient mockedConsulClient() {
|
||||
return mock(ConsulClient)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
eureka:
|
||||
enableSelfPreservation: false
|
||||
client:
|
||||
fetchRegistry: false
|
||||
initialInstanceInfoReplicationIntervalSeconds: 1
|
||||
instance:
|
||||
registryFetchIntervalSeconds: 5
|
||||
leaseRenewalIntervalInSeconds: 5
|
||||
leaseExpirationDurationInSeconds: 5
|
||||
@@ -1,4 +1,9 @@
|
||||
spring.cloud:
|
||||
zookeeper.enabled: false
|
||||
consul.enabled: false
|
||||
eureka.client.enabled: false
|
||||
stubrunner:
|
||||
camel.enabled: false
|
||||
idsToServiceIds:
|
||||
ivyNotation: someValueInsideYourCode
|
||||
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
|
||||
@@ -40,7 +40,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
final LinkedList<String> methodsBuffer;
|
||||
|
||||
DelegatingJsonVerifiable(JsonVerifiable delegate,
|
||||
LinkedList<String> methodsBuffer) {
|
||||
LinkedList<String> methodsBuffer) {
|
||||
this.delegate = delegate;
|
||||
this.methodsBuffer = new LinkedList<>(methodsBuffer);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
}
|
||||
|
||||
private void appendMethodWithValue(String methodName, Object value) {
|
||||
methodsBuffer.offer("." + methodName + "(" + value + ")");
|
||||
this.methodsBuffer.offer("." + methodName + "(" + value + ")");
|
||||
}
|
||||
|
||||
private void appendMethodWithQuotedValue(String methodName, Object value) {
|
||||
@@ -71,7 +71,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable contains(Object value) {
|
||||
DelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(delegate.contains(value), methodsBuffer);
|
||||
DelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(this.delegate.contains(value), this.methodsBuffer);
|
||||
verifiable.appendMethodWithQuotedValue("contains", value);
|
||||
if (isAssertingAValueInArray()) {
|
||||
verifiable.methodsBuffer.offer(".value()");
|
||||
@@ -82,8 +82,8 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable field(Object value) {
|
||||
Object valueToPut = value instanceof ShouldTraverse ? ((ShouldTraverse) value).value : value;
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.field(valueToPut), methodsBuffer);
|
||||
if (delegate.isIteratingOverArray() && !(value instanceof ShouldTraverse)) {
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.field(valueToPut), this.methodsBuffer);
|
||||
if (this.delegate.isIteratingOverArray() && !(value instanceof ShouldTraverse)) {
|
||||
verifiable.appendMethodWithQuotedValue("contains", valueToPut);
|
||||
} else {
|
||||
verifiable.appendMethodWithQuotedValue("field", valueToPut);
|
||||
@@ -102,51 +102,51 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable array(Object value) {
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.array(value), methodsBuffer);
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.array(value), this.methodsBuffer);
|
||||
verifiable.appendMethodWithQuotedValue("array", value);
|
||||
return verifiable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable arrayField(Object value) {
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.field(value).arrayField(), methodsBuffer);
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.field(value).arrayField(), this.methodsBuffer);
|
||||
verifiable.appendMethodWithQuotedValue("array", value);
|
||||
return verifiable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable arrayField() {
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.arrayField(), methodsBuffer);
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.arrayField(), this.methodsBuffer);
|
||||
verifiable.methodsBuffer.offer(".arrayField()");
|
||||
return verifiable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable array() {
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.array(), methodsBuffer);
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.array(), this.methodsBuffer);
|
||||
verifiable.methodsBuffer.offer(".array()");
|
||||
return verifiable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonVerifiable elementWithIndex(int i) {
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(delegate.elementWithIndex(i), methodsBuffer);
|
||||
verifiable.methodsBuffer.offer(".elementWithIndex(" + i + ")");
|
||||
DelegatingJsonVerifiable verifiable = new DelegatingJsonVerifiable(this.delegate.elementWithIndex(i), this.methodsBuffer);
|
||||
this.methodsBuffer.offer(".elementWithIndex(" + i + ")");
|
||||
return verifiable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable iterationPassingArray() {
|
||||
return new DelegatingJsonVerifiable(delegate, methodsBuffer);
|
||||
return new DelegatingJsonVerifiable(this.delegate, this.methodsBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable isEqualTo(String value) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isEqualTo(value), methodsBuffer);
|
||||
if (delegate.isAssertingAValueInArray() && readyToCheck.methodsBuffer.peekLast().equals(".arrayField()")) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.isEqualTo(value), this.methodsBuffer);
|
||||
if (this.delegate.isAssertingAValueInArray() && readyToCheck.methodsBuffer.peekLast().equals(".arrayField()")) {
|
||||
readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapeJava(value));
|
||||
readyToCheck.methodsBuffer.offer(".value()");
|
||||
} else if (delegate.isAssertingAValueInArray() && !readyToCheck.methodsBuffer.peekLast().contains("array")) {
|
||||
} else if (this.delegate.isAssertingAValueInArray() && !readyToCheck.methodsBuffer.peekLast().contains("array")) {
|
||||
readyToCheck.methodsBuffer.offer(".value()");
|
||||
} else {
|
||||
readyToCheck.appendMethodWithQuotedValue("isEqualTo", escapeJava(value));
|
||||
@@ -164,11 +164,11 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable isEqualTo(Number value) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isEqualTo(value), methodsBuffer);
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.isEqualTo(value), this.methodsBuffer);
|
||||
// related to #271 - the problem is with asserting arrays of maps vs arrays of primitives
|
||||
String last = readyToCheck.methodsBuffer.peekLast();
|
||||
boolean containsAMatcher = containsAnyMatcher(last);
|
||||
if (delegate.isAssertingAValueInArray() && containsAMatcher) {
|
||||
if (this.delegate.isAssertingAValueInArray() && containsAMatcher) {
|
||||
readyToCheck.methodsBuffer.offer(".value()");
|
||||
} else {
|
||||
readyToCheck.appendMethodWithValue("isEqualTo", String.valueOf(value));
|
||||
@@ -182,15 +182,15 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable isNull() {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isNull(), methodsBuffer);
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.isNull(), this.methodsBuffer);
|
||||
readyToCheck.methodsBuffer.offer(".isNull()");
|
||||
return readyToCheck;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable matches(String value) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.matches(value), methodsBuffer);
|
||||
if (delegate.isAssertingAValueInArray()) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.matches(value), this.methodsBuffer);
|
||||
if (this.delegate.isAssertingAValueInArray()) {
|
||||
readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value));
|
||||
readyToCheck.methodsBuffer.offer(".value()");
|
||||
} else {
|
||||
@@ -201,8 +201,8 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable isEqualTo(Boolean value) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.isEqualTo(value), methodsBuffer);
|
||||
if (delegate.isAssertingAValueInArray()) {
|
||||
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.isEqualTo(value), this.methodsBuffer);
|
||||
if (this.delegate.isAssertingAValueInArray()) {
|
||||
readyToCheck.methodsBuffer.offer(".value()");
|
||||
} else {
|
||||
readyToCheck.appendMethodWithValue("isEqualTo", String.valueOf(value));
|
||||
@@ -212,12 +212,12 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public MethodBufferingJsonVerifiable value() {
|
||||
return new FinishedDelegatingJsonVerifiable(delegate, methodsBuffer);
|
||||
return new FinishedDelegatingJsonVerifiable(this.delegate, this.methodsBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean assertsSize() {
|
||||
for (String s : methodsBuffer) {
|
||||
for (String s : this.methodsBuffer) {
|
||||
if (s.contains(".hasSize(")) {
|
||||
return true;
|
||||
}
|
||||
@@ -227,7 +227,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public boolean assertsConcreteValue() {
|
||||
for (String s : methodsBuffer) {
|
||||
for (String s : this.methodsBuffer) {
|
||||
if (FIELD_PATTERN.matcher(s).matches()|| ARRAY_PATTERN.matcher(s).matches()) {
|
||||
return true;
|
||||
}
|
||||
@@ -237,39 +237,39 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
@Override
|
||||
public JsonVerifiable withoutThrowingException() {
|
||||
return delegate.withoutThrowingException();
|
||||
return this.delegate.withoutThrowingException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsonPath() {
|
||||
return delegate.jsonPath();
|
||||
return this.delegate.jsonPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void matchesJsonPath(String s) {
|
||||
delegate.matchesJsonPath(s);
|
||||
this.delegate.matchesJsonPath(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonVerifiable hasSize(int size) {
|
||||
FinishedDelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(delegate.hasSize(size), methodsBuffer);
|
||||
FinishedDelegatingJsonVerifiable verifiable = new FinishedDelegatingJsonVerifiable(this.delegate.hasSize(size), this.methodsBuffer);
|
||||
verifiable.methodsBuffer.offer(".hasSize(" + size + ")");
|
||||
return verifiable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIteratingOverNamelessArray() {
|
||||
return delegate.isIteratingOverNamelessArray();
|
||||
return this.delegate.isIteratingOverNamelessArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIteratingOverArray() {
|
||||
return delegate.isIteratingOverArray();
|
||||
return this.delegate.isIteratingOverArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssertingAValueInArray() {
|
||||
return delegate.isAssertingAValueInArray();
|
||||
return this.delegate.isAssertingAValueInArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -278,7 +278,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
}
|
||||
|
||||
private String createMethodString() {
|
||||
LinkedList<String> queue = new LinkedList<>(methodsBuffer);
|
||||
LinkedList<String> queue = new LinkedList<>(this.methodsBuffer);
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
while (!queue.isEmpty()) {
|
||||
stringBuffer.append(queue.remove());
|
||||
@@ -295,33 +295,33 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
|
||||
|
||||
DelegatingJsonVerifiable that = (DelegatingJsonVerifiable) o;
|
||||
|
||||
if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null)
|
||||
if (this.delegate != null ? !this.delegate.equals(that.delegate) : that.delegate != null)
|
||||
return false;
|
||||
if (delegate == null) {
|
||||
if (this.delegate == null) {
|
||||
return false;
|
||||
}
|
||||
if (delegate.jsonPath() == null && that.delegate.jsonPath() == null)
|
||||
if (this.delegate.jsonPath() == null && that.delegate.jsonPath() == null)
|
||||
return true;
|
||||
return delegate.jsonPath().equals(that.delegate.jsonPath());
|
||||
return this.delegate.jsonPath().equals(that.delegate.jsonPath());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = delegate != null ? delegate.jsonPath().hashCode() : 0;
|
||||
int result = this.delegate != null ? this.delegate.jsonPath().hashCode() : 0;
|
||||
return 31 * result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DelegatingJsonVerifiable{" +
|
||||
"delegate=\n" + delegate +
|
||||
", methodsBuffer=" + methodsBuffer +
|
||||
"delegate=\n" + this.delegate +
|
||||
", methodsBuffer=" + this.methodsBuffer +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T read(Class<T> aClass) {
|
||||
return delegate.read(aClass);
|
||||
return this.delegate.read(aClass);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.toomuchcoding.jsonassert.JsonVerifiable;
|
||||
class FinishedDelegatingJsonVerifiable extends DelegatingJsonVerifiable {
|
||||
|
||||
FinishedDelegatingJsonVerifiable(JsonVerifiable delegate,
|
||||
LinkedList<String> methodsBuffer) {
|
||||
LinkedList<String> methodsBuffer) {
|
||||
super(delegate, methodsBuffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@ public class CamelStubMessages implements MessageVerifier<Message> {
|
||||
@Override
|
||||
public void send(Message message, String destination) {
|
||||
try {
|
||||
ProducerTemplate producerTemplate = context.createProducerTemplate();
|
||||
Exchange exchange = new DefaultExchange(context);
|
||||
ProducerTemplate producerTemplate = this.context.createProducerTemplate();
|
||||
Exchange exchange = new DefaultExchange(this.context);
|
||||
exchange.setIn(message);
|
||||
producerTemplate.send(destination, exchange);
|
||||
} catch (Exception e) {
|
||||
@@ -64,13 +64,13 @@ public class CamelStubMessages implements MessageVerifier<Message> {
|
||||
|
||||
@Override
|
||||
public <T> void send(T payload, Map<String, Object> headers, String destination) {
|
||||
send(builder.create(payload, headers), destination);
|
||||
send(this.builder.create(payload, headers), destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
try {
|
||||
ConsumerTemplate consumerTemplate = context.createConsumerTemplate();
|
||||
ConsumerTemplate consumerTemplate = this.context.createConsumerTemplate();
|
||||
Exchange exchange = consumerTemplate.receive(destination, timeUnit.toMillis(timeout));
|
||||
return exchange.getIn();
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -49,13 +49,13 @@ public class SpringIntegrationStubMessages implements
|
||||
|
||||
@Override
|
||||
public <T> void send(T payload, Map<String, Object> headers, String destination) {
|
||||
send(builder.create(payload, headers), destination);
|
||||
send(this.builder.create(payload, headers), destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Message<?> message, String destination) {
|
||||
try {
|
||||
MessageChannel messageChannel = context.getBean(destination, MessageChannel.class);
|
||||
MessageChannel messageChannel = this.context.getBean(destination, MessageChannel.class);
|
||||
messageChannel.send(message);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception occurred while trying to send a message [" + message + "] " +
|
||||
@@ -67,7 +67,7 @@ public class SpringIntegrationStubMessages implements
|
||||
@Override
|
||||
public Message<?> receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
try {
|
||||
PollableChannel messageChannel = context.getBean(destination, PollableChannel.class);
|
||||
PollableChannel messageChannel = this.context.getBean(destination, PollableChannel.class);
|
||||
return messageChannel.receive(timeUnit.toMillis(timeout));
|
||||
} catch (Exception e) {
|
||||
log.error("Exception occurred while trying to read a message from " +
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ContractVerifierMessage {
|
||||
}
|
||||
|
||||
public Object getPayload() {
|
||||
return payload;
|
||||
return this.payload;
|
||||
}
|
||||
|
||||
public void setPayload(Object payload) {
|
||||
@@ -51,11 +51,11 @@ public class ContractVerifierMessage {
|
||||
}
|
||||
|
||||
public Map<String, Object> getHeaders() {
|
||||
return headers;
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
public Object getHeader(String name) {
|
||||
return headers.get(name);
|
||||
return this.headers.get(name);
|
||||
}
|
||||
|
||||
public void setHeaders(Map<String, Object> headers) {
|
||||
|
||||
@@ -33,11 +33,11 @@ public class ContractVerifierMessaging<M> {
|
||||
}
|
||||
|
||||
public void send(ContractVerifierMessage message, String destination) {
|
||||
exchange.send(message.getPayload(), message.getHeaders(), destination);
|
||||
this.exchange.send(message.getPayload(), message.getHeaders(), destination);
|
||||
}
|
||||
|
||||
public ContractVerifierMessage receive(String destination) {
|
||||
return convert(exchange.receive(destination));
|
||||
return convert(this.exchange.receive(destination));
|
||||
}
|
||||
|
||||
public <T> ContractVerifierMessage create(T payload, Map<String, Object> headers) {
|
||||
|
||||
@@ -41,6 +41,6 @@ public class ContractVerifierObjectMapper {
|
||||
if (payload instanceof String) {
|
||||
return payload.toString();
|
||||
}
|
||||
return objectMapper.writeValueAsString(payload);
|
||||
return this.objectMapper.writeValueAsString(payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,13 @@ public class StreamStubMessages implements MessageVerifier<Message<?>> {
|
||||
|
||||
@Override
|
||||
public <T> void send(T payload, Map<String, Object> headers, String destination) {
|
||||
send(builder.create(payload, headers), destination);
|
||||
send(this.builder.create(payload, headers), destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Message<?> message, String destination) {
|
||||
try {
|
||||
MessageChannel messageChannel = context
|
||||
MessageChannel messageChannel = this.context
|
||||
.getBean(resolvedDestination(destination), MessageChannel.class);
|
||||
messageChannel.send(message);
|
||||
}
|
||||
@@ -69,9 +69,9 @@ public class StreamStubMessages implements MessageVerifier<Message<?>> {
|
||||
@Override
|
||||
public Message<?> receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
try {
|
||||
MessageChannel messageChannel = context
|
||||
MessageChannel messageChannel = this.context
|
||||
.getBean(resolvedDestination(destination), MessageChannel.class);
|
||||
return messageCollector.forChannel(messageChannel).poll(timeout, timeUnit);
|
||||
return this.messageCollector.forChannel(messageChannel).poll(timeout, timeUnit);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Exception occurred while trying to read a message from "
|
||||
@@ -81,7 +81,7 @@ public class StreamStubMessages implements MessageVerifier<Message<?>> {
|
||||
}
|
||||
|
||||
private String resolvedDestination(String destination) {
|
||||
ChannelBindingServiceProperties channelBindingServiceProperties = context
|
||||
ChannelBindingServiceProperties channelBindingServiceProperties = this.context
|
||||
.getBean(ChannelBindingServiceProperties.class);
|
||||
for (Map.Entry<String, BindingProperties> entry : channelBindingServiceProperties
|
||||
.getBindings().entrySet()) {
|
||||
|
||||
@@ -43,72 +43,72 @@ public class ContractVerifierMessagingUtil {
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
return this.delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
return this.delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return delegate.containsKey(key);
|
||||
return this.delegate.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return delegate.containsValue(value);
|
||||
return this.delegate.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return delegate.get(key);
|
||||
return this.delegate.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
return delegate.put(key, value);
|
||||
return this.delegate.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
return delegate.remove(key);
|
||||
return this.delegate.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ?> m) {
|
||||
delegate.putAll(m);
|
||||
this.delegate.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate.clear();
|
||||
this.delegate.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return delegate.keySet();
|
||||
return this.delegate.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return delegate.values();
|
||||
return this.delegate.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
return delegate.entrySet();
|
||||
return this.delegate.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return delegate.equals(o);
|
||||
return this.delegate.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
return this.delegate.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,11 @@ import java.lang.annotation.Target;
|
||||
import org.springframework.boot.test.autoconfigure.properties.PropertyMapping;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import com.github.tomakehurst.wiremock.core.Options;
|
||||
|
||||
/**
|
||||
* Annotation for test classes that want to start a WireMock server as part of the Spring
|
||||
* Application Context. The port, https port and stub locations (if any) can all be
|
||||
* controlled directly here. For more fine-grained control of the server instance add a
|
||||
* bean of type {@link Options} to the application context.
|
||||
* bean of type {@link com.github.tomakehurst.wiremock.core.Options} to the application context.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
|
||||
@@ -139,9 +139,9 @@ class SpringBootHttpServer
|
||||
|
||||
private ContainerProperties container() {
|
||||
if (this.context != null) {
|
||||
return context.getBean(ContainerProperties.class);
|
||||
return this.context.getBean(ContainerProperties.class);
|
||||
}
|
||||
return new ContainerProperties(options);
|
||||
return new ContainerProperties(this.options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,7 +253,7 @@ class WiremockServerConfiguration {
|
||||
WiremockServerConfiguration.this.adminRequestHandler);
|
||||
servletContext.setAttribute(StubRequestHandler.class.getName(),
|
||||
WiremockServerConfiguration.this.stubRequestHandler);
|
||||
servletContext.setAttribute(Notifier.KEY, options.notifier());
|
||||
servletContext.setAttribute(Notifier.KEY, WiremockServerConfiguration.this.options.notifier());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -278,13 +278,13 @@ class ContainerProperties {
|
||||
}
|
||||
|
||||
public int port() {
|
||||
if (options.httpsSettings().enabled()) {
|
||||
return options.portNumber();
|
||||
if (this.options.httpsSettings().enabled()) {
|
||||
return this.options.portNumber();
|
||||
}
|
||||
if (this.localPort != null) {
|
||||
return this.localPort;
|
||||
}
|
||||
EmbeddedWebApplicationContext embedded = (EmbeddedWebApplicationContext) context;
|
||||
EmbeddedWebApplicationContext embedded = (EmbeddedWebApplicationContext) this.context;
|
||||
return embedded.getEmbeddedServletContainer().getPort();
|
||||
}
|
||||
|
||||
@@ -330,9 +330,9 @@ class ContainerConfiguration {
|
||||
|
||||
@EventListener
|
||||
public void serverUp(EmbeddedServletContainerInitializedEvent event) {
|
||||
if (connector != null) {
|
||||
container.setLocalPort(connector.getLocalPort());
|
||||
container
|
||||
if (this.connector != null) {
|
||||
this.container.setLocalPort(this.connector.getLocalPort());
|
||||
this.container
|
||||
.setLocalHttpsPort(event.getEmbeddedServletContainer().getPort());
|
||||
}
|
||||
}
|
||||
@@ -367,8 +367,8 @@ class ContainerConfiguration {
|
||||
undertow.addBuilderCustomizers(new UndertowBuilderCustomizer() {
|
||||
@Override
|
||||
public void customize(Builder builder) {
|
||||
builder.addHttpListener(options.portNumber(), "localhost");
|
||||
UndertowContainerConfiguration.this.port = options.portNumber();
|
||||
builder.addHttpListener(UndertowContainerConfiguration.this.options.portNumber(), "localhost");
|
||||
UndertowContainerConfiguration.this.port = UndertowContainerConfiguration.this.options.portNumber();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -377,10 +377,10 @@ class ContainerConfiguration {
|
||||
|
||||
@EventListener
|
||||
public void serverUp(EmbeddedServletContainerInitializedEvent event) {
|
||||
if (port != null) {
|
||||
if (this.port != null) {
|
||||
// TODO: make it dynamic as well
|
||||
container.setLocalPort(port);
|
||||
container
|
||||
this.container.setLocalPort(this.port);
|
||||
this.container
|
||||
.setLocalHttpsPort(event.getEmbeddedServletContainer().getPort());
|
||||
}
|
||||
}
|
||||
@@ -419,7 +419,7 @@ class ContainerConfiguration {
|
||||
Server server) {
|
||||
ServerConnector connector = new ServerConnector(server, -1, -1);
|
||||
connector.setHost("localhost");
|
||||
connector.setPort(options.portNumber());
|
||||
connector.setPort(this.options.portNumber());
|
||||
for (ConnectionFactory connectionFactory : connector
|
||||
.getConnectionFactories()) {
|
||||
if (connectionFactory instanceof HttpConfiguration.ConnectionFactory) {
|
||||
@@ -433,9 +433,9 @@ class ContainerConfiguration {
|
||||
|
||||
@EventListener
|
||||
public void serverUp(EmbeddedServletContainerInitializedEvent event) {
|
||||
if (connector != null) {
|
||||
container.setLocalPort(connector.getLocalPort());
|
||||
container
|
||||
if (this.connector != null) {
|
||||
this.container.setLocalPort(this.connector.getLocalPort());
|
||||
this.container
|
||||
.setLocalHttpsPort(event.getEmbeddedServletContainer().getPort());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,29 +71,29 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws IOException {
|
||||
if (options == null) {
|
||||
if (this.options == null) {
|
||||
com.github.tomakehurst.wiremock.core.WireMockConfiguration factory = WireMockSpring
|
||||
.options();
|
||||
if (wireMock.getPort() != 8080) {
|
||||
factory.port(wireMock.getPort());
|
||||
if (this.wireMock.getPort() != 8080) {
|
||||
factory.port(this.wireMock.getPort());
|
||||
}
|
||||
if (wireMock.getHttpsPort() != -1) {
|
||||
factory.httpsPort(wireMock.getHttpsPort());
|
||||
if (this.wireMock.getHttpsPort() != -1) {
|
||||
factory.httpsPort(this.wireMock.getHttpsPort());
|
||||
}
|
||||
this.options = factory;
|
||||
}
|
||||
server = new WireMockServer(options);
|
||||
this.server = new WireMockServer(this.options);
|
||||
registerStubs();
|
||||
if (!beanFactory.containsBean("wireMockServer")) {
|
||||
beanFactory.registerSingleton("wireMockServer", server);
|
||||
if (!this.beanFactory.containsBean("wireMockServer")) {
|
||||
this.beanFactory.registerSingleton("wireMockServer", this.server);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerStubs() throws IOException {
|
||||
if (StringUtils.hasText(wireMock.getStubs())) {
|
||||
if (StringUtils.hasText(this.wireMock.getStubs())) {
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(
|
||||
resourceLoader);
|
||||
String pattern = wireMock.getStubs();
|
||||
this.resourceLoader);
|
||||
String pattern = this.wireMock.getStubs();
|
||||
if (!pattern.contains("*")) {
|
||||
if (!pattern.endsWith("/")) {
|
||||
pattern = pattern + "/";
|
||||
@@ -101,7 +101,7 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
pattern = pattern + "**/*.json";
|
||||
}
|
||||
for (Resource resource : resolver.getResources(pattern)) {
|
||||
server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString(
|
||||
this.server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString(
|
||||
resource.getInputStream(), Charset.forName("UTF-8"))));
|
||||
}
|
||||
}
|
||||
@@ -109,22 +109,22 @@ public class WireMockConfiguration implements SmartLifecycle {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
server.start();
|
||||
WireMock.configureFor("localhost", server.port());
|
||||
running = true;
|
||||
this.server.start();
|
||||
WireMock.configureFor("localhost", this.server.port());
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (running) {
|
||||
server.stop();
|
||||
running = false;
|
||||
if (this.running) {
|
||||
this.server.stop();
|
||||
this.running = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
return this.running;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,7 +154,7 @@ class WireMockProperties {
|
||||
private String stubs;
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
@@ -162,7 +162,7 @@ class WireMockProperties {
|
||||
}
|
||||
|
||||
public int getHttpsPort() {
|
||||
return httpsPort;
|
||||
return this.httpsPort;
|
||||
}
|
||||
|
||||
public void setHttpsPort(int httpsPort) {
|
||||
@@ -170,7 +170,7 @@ class WireMockProperties {
|
||||
}
|
||||
|
||||
public String getStubs() {
|
||||
return stubs;
|
||||
return this.stubs;
|
||||
}
|
||||
|
||||
public void setStubs(String stubs) {
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.contract.wiremock;
|
||||
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
@@ -45,6 +42,9 @@ import com.github.tomakehurst.wiremock.matching.MultiValuePattern;
|
||||
import com.github.tomakehurst.wiremock.matching.RequestPattern;
|
||||
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
|
||||
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
/**
|
||||
* Convenience class for loading WireMock stubs into a {@link MockRestServiceServer}. In
|
||||
* this way using a {@link RestTemplate} can mock the responses from a server using
|
||||
@@ -136,7 +136,7 @@ public class WireMockRestServiceServer {
|
||||
* @return a MockRestServiceServer
|
||||
*/
|
||||
public MockRestServiceServer build() {
|
||||
MockRestServiceServer server = builder.build();
|
||||
MockRestServiceServer server = this.builder.build();
|
||||
for (String location : this.locations) {
|
||||
try {
|
||||
for (Resource resource : this.resolver.getResources(pattern(location))) {
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.apache.http.ssl.SSLContexts;
|
||||
import org.junit.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
|
||||
|
||||
/**
|
||||
@@ -37,7 +36,7 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
|
||||
* WireMockSpring.config());
|
||||
* </pre>
|
||||
*
|
||||
* and then use {@link WireMock} as normal in your test methods.
|
||||
* and then use {@link com.github.tomakehurst.wiremock.client.WireMock} as normal in your test methods.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
|
||||
@@ -67,20 +67,20 @@ public class ContractRequestHandler implements ResultHandler {
|
||||
Map<String, Object> configuration = getConfiguration(result);
|
||||
String actual = StreamUtils.copyToString(request.getInputStream(),
|
||||
Charset.forName("UTF-8"));
|
||||
for (JsonPath jsonPath : jsonPaths.values()) {
|
||||
for (JsonPath jsonPath : this.jsonPaths.values()) {
|
||||
new JsonPathValue(jsonPath, actual).assertHasValue(Object.class, "an object");
|
||||
}
|
||||
configuration.put("contract.jsonPaths", jsonPaths.keySet());
|
||||
if (contentType != null) {
|
||||
configuration.put("contract.contentType", contentType);
|
||||
configuration.put("contract.jsonPaths", this.jsonPaths.keySet());
|
||||
if (this.contentType != null) {
|
||||
configuration.put("contract.contentType", this.contentType);
|
||||
String resultType = request.getContentType();
|
||||
assertThat(resultType).isNotNull().as("no content type");
|
||||
assertThat(contentType.includes(MediaType.valueOf(resultType))).isTrue()
|
||||
assertThat(this.contentType.includes(MediaType.valueOf(resultType))).isTrue()
|
||||
.as("content type did not match");
|
||||
}
|
||||
if (builder != null) {
|
||||
builder.willReturn(getResponseDefinition(result));
|
||||
StubMapping stubMapping = builder.build();
|
||||
if (this.builder != null) {
|
||||
this.builder.willReturn(getResponseDefinition(result));
|
||||
StubMapping stubMapping = this.builder.build();
|
||||
MatchResult match = stubMapping.getRequest()
|
||||
.match(new WireMockHttpServletRequestAdapter(request));
|
||||
assertThat(match.isExactMatch()).as("wiremock did not match request").isTrue();
|
||||
@@ -137,7 +137,7 @@ public class ContractRequestHandler implements ResultHandler {
|
||||
(expression == null ? null : expression),
|
||||
"expression must not be null or empty");
|
||||
expression = String.format(expression, args);
|
||||
jsonPaths.put(expression, JsonPath.compile(expression));
|
||||
this.jsonPaths.put(expression, JsonPath.compile(expression));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.contract.wiremock.restdocs;
|
||||
|
||||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
|
||||
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
|
||||
@@ -24,7 +23,7 @@ import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
|
||||
/**
|
||||
* Custom configuration for Spring RestDocs that adds a WireMock snippet (for generating
|
||||
* JSON stubs). Applied automatically if you use
|
||||
* {@link AutoConfigureRestDocs @AutoConfigureRestDocs} in your test case and this class
|
||||
* {@link org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs @AutoConfigureRestDocs} in your test case and this class
|
||||
* is available. JSON stubs are generated and added to the restdocs path under "stubs".
|
||||
*
|
||||
* @see WireMockRestDocs for a convenient entry point for customizing and asserting the
|
||||
|
||||
@@ -16,16 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.contract.wiremock.restdocs;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.delete;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.put;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -50,6 +40,16 @@ import com.github.tomakehurst.wiremock.http.HttpHeaders;
|
||||
import com.github.tomakehurst.wiremock.matching.UrlPattern;
|
||||
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.delete;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.post;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.put;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
|
||||
public class WireMockSnippet implements Snippet {
|
||||
|
||||
private String snippetName = "stubs";
|
||||
@@ -66,10 +66,10 @@ public class WireMockSnippet implements Snippet {
|
||||
@Override
|
||||
public void document(Operation operation) throws IOException {
|
||||
extractMatchers(operation);
|
||||
if (stubMapping == null) {
|
||||
stubMapping = request(operation).willReturn(response(operation)).build();
|
||||
if (this.stubMapping == null) {
|
||||
this.stubMapping = request(operation).willReturn(response(operation)).build();
|
||||
}
|
||||
String json = Json.write(stubMapping);
|
||||
String json = Json.write(this.stubMapping);
|
||||
RestDocumentationContext context = (RestDocumentationContext) operation
|
||||
.getAttributes().get(RestDocumentationContext.class.getName());
|
||||
File output = new File(context.getOutputDirectory(),
|
||||
@@ -81,15 +81,15 @@ public class WireMockSnippet implements Snippet {
|
||||
}
|
||||
|
||||
private void extractMatchers(Operation operation) {
|
||||
stubMapping = (StubMapping) operation.getAttributes().get("contract.stubMapping");
|
||||
if (stubMapping != null) {
|
||||
this.stubMapping = (StubMapping) operation.getAttributes().get("contract.stubMapping");
|
||||
if (this.stubMapping != null) {
|
||||
return;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> jsonPaths = (Set<String>) operation.getAttributes()
|
||||
.get("contract.jsonPaths");
|
||||
this.jsonPaths = jsonPaths;
|
||||
contentType = (MediaType) operation.getAttributes().get("contract.contentType");
|
||||
this.contentType = (MediaType) operation.getAttributes().get("contract.contentType");
|
||||
}
|
||||
|
||||
private ResponseDefinitionBuilder response(Operation operation) {
|
||||
@@ -107,7 +107,7 @@ public class WireMockSnippet implements Snippet {
|
||||
.getHeaders();
|
||||
// TODO: whitelist headers
|
||||
for (String name : headers.keySet()) {
|
||||
if (!headerBlackList.contains(name.toLowerCase())) {
|
||||
if (!this.headerBlackList.contains(name.toLowerCase())) {
|
||||
if ("content-type".equalsIgnoreCase(name) && this.contentType != null) {
|
||||
continue;
|
||||
}
|
||||
@@ -138,8 +138,8 @@ public class WireMockSnippet implements Snippet {
|
||||
|
||||
private RemoteMappingBuilder<?, ?> bodyPattern(RemoteMappingBuilder<?, ?> builder,
|
||||
String content) {
|
||||
if (jsonPaths != null) {
|
||||
for (String jsonPath : jsonPaths) {
|
||||
if (this.jsonPaths != null) {
|
||||
for (String jsonPath : this.jsonPaths) {
|
||||
builder.withRequestBody(matchingJsonPath(jsonPath));
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ public class WireMockSnippet implements Snippet {
|
||||
.getHeaders();
|
||||
HttpHeaders result = new HttpHeaders();
|
||||
for (String name : headers.keySet()) {
|
||||
if (!headerBlackList.contains(name.toLowerCase())) {
|
||||
if (!this.headerBlackList.contains(name.toLowerCase())) {
|
||||
result = result.plus(new HttpHeader(name, headers.get(name)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<module>samples-messaging-spring</module>
|
||||
<module>samples-messaging-stream</module>
|
||||
<module>samples-messaging-integration</module>
|
||||
<module>spring-cloud-contract-stub-runner-boot-eureka</module>
|
||||
<module>spring-cloud-contract-stub-runner-boot-zookeeper</module>
|
||||
<module>spring-cloud-contract-stub-runner-camel</module>
|
||||
<module>spring-cloud-contract-stub-runner-integration</module>
|
||||
<module>spring-cloud-contract-stub-runner-stream</module>
|
||||
|
||||
85
tests/spring-cloud-contract-stub-runner-boot-eureka/pom.xml
Normal file
85
tests/spring-cloud-contract-stub-runner-boot-eureka/pom.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-tests</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-stub-runner-boot-eureka</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Stub Runner Boot Eureka</name>
|
||||
<description>Spring Cloud Contract Stub Runner Boot Eureka</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner-jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-eureka-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.solidsoft.spock</groupId>
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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
|
||||
*
|
||||
* http://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.spring.cloud.eureka
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.SpringApplication
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient
|
||||
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer
|
||||
import org.springframework.context.ConfigurableApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.client.ClientHttpResponse
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.web.client.*
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
import spock.util.concurrent.PollingConditions
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
//TODO: Speed up this test somehow
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = ["stubrunner.cloud.eureka.enabled=true",
|
||||
"stubrunner.cloud.stubbed.discovery.enabled=false",
|
||||
"stubrunner.cloud.ribbon.enabled=false",
|
||||
"eureka.client.enabled=true",
|
||||
"eureka.instance.leaseRenewalIntervalInSeconds=1",
|
||||
"ribbon.ServerListRefreshInterval=100"])
|
||||
@AutoConfigureStubRunner( ids =
|
||||
["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
|
||||
"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
|
||||
"org.springframework.cloud.contract.verifier.stubs:bootService"],
|
||||
repositoryRoot = "classpath:m2repo/repository/")
|
||||
@DirtiesContext
|
||||
class StubRunnerSpringCloudEurekaAutoConfigurationSpec extends Specification {
|
||||
|
||||
@Autowired StubFinder stubFinder
|
||||
@Autowired @LoadBalanced RestTemplate restTemplate
|
||||
@Shared @AutoCleanup ConfigurableApplicationContext eurekaServer
|
||||
|
||||
void setupSpec() {
|
||||
System.clearProperty("stubrunner.stubs.repository.root")
|
||||
System.clearProperty("stubrunner.stubs.classifier")
|
||||
eurekaServer = SpringApplication.run(EurekaServer,
|
||||
"--stubrunner.cloud.eureka.enabled=true",
|
||||
"--stubrunner.cloud.stubbed.discovery.enabled=false",
|
||||
"--eureka.client.enabled=true",
|
||||
"--server.port=8761",
|
||||
"--spring.profiles.active=eureka")
|
||||
}
|
||||
|
||||
void cleanupSpec() {
|
||||
System.clearProperty("stubrunner.stubs.repository.root")
|
||||
System.clearProperty("stubrunner.stubs.classifier")
|
||||
}
|
||||
|
||||
PollingConditions conditions = new PollingConditions(timeout: 40, delay: 1)
|
||||
|
||||
def 'should make service discovery work'() {
|
||||
expect: 'WireMocks are running'
|
||||
"${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
|
||||
"${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
|
||||
and: 'Stubs can be reached via load service discovery'
|
||||
conditions.eventually {
|
||||
assert restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance'
|
||||
}
|
||||
restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer'
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableEurekaClient
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
def template = new RestTemplate() {
|
||||
|
||||
@Override
|
||||
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws RestClientException {
|
||||
try {
|
||||
return super.doExecute(url, method, requestCallback, responseExtractor)
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
template.errorHandler = new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
void handleError(ClientHttpResponse response) throws IOException {
|
||||
try {
|
||||
super.handleError(response)
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableEurekaServer
|
||||
static class EurekaServer {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
stubrunner:
|
||||
camel.enabled: false
|
||||
idsToServiceIds:
|
||||
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
<logger name="org.springframework.cloud" level="DEBUG"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>bootService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>bootService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>fraudDetectionServer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>fraudDetectionServer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>loanIssuance</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>loanIssuance</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062111</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-tests</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-stub-runner-boot-zookeeper</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Stub Runner Boot Zookeeper</name>
|
||||
<description>Spring Cloud Contract Stub Runner Boot Zookeeper</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner-jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.solidsoft.spock</groupId>
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud
|
||||
package org.springframework.cloud.contract.stubrunner.spring.cloud.zookeeper
|
||||
|
||||
import org.apache.curator.test.TestingServer
|
||||
import org.junit.AfterClass
|
||||
import org.junit.BeforeClass
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@@ -26,31 +27,35 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced
|
||||
import org.springframework.cloud.contract.stubrunner.StubFinder
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.cloud.zookeeper.discovery.RibbonZookeeperAutoConfiguration
|
||||
import org.springframework.cloud.zookeeper.ZookeeperProperties
|
||||
import org.springframework.cloud.zookeeper.discovery.ZookeeperServiceDiscovery
|
||||
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 org.springframework.util.SocketUtils
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = ["stubrunner.camel.enabled=false",
|
||||
"spring.cloud.zookeeper.enabled=false",
|
||||
"spring.cloud.zookeeper.discovery.enabled=false"])
|
||||
"stubrunner.cloud.stubbed.discovery.enabled=false",
|
||||
"debug=true"])
|
||||
@AutoConfigureStubRunner( ids =
|
||||
["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
|
||||
"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
|
||||
"org.springframework.cloud.contract.verifier.stubs:bootService"],
|
||||
repositoryRoot = "classpath:m2repo/repository/")
|
||||
@DirtiesContext
|
||||
class StubRunnerSpringCloudAutoConfigurationWithoutDiscoverySpec extends Specification {
|
||||
class StubRunnerSpringCloudZookeeperAutoConfigurationSpec extends Specification {
|
||||
|
||||
@Autowired StubFinder stubFinder
|
||||
@Autowired @LoadBalanced RestTemplate restTemplate
|
||||
@Autowired ZookeeperServiceDiscovery zookeeperServiceDiscovery
|
||||
|
||||
@BeforeClass
|
||||
@AfterClass
|
||||
@@ -68,11 +73,31 @@ class StubRunnerSpringCloudAutoConfigurationWithoutDiscoverySpec extends Specifi
|
||||
restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer'
|
||||
}
|
||||
|
||||
def 'should have all apps registered in Service Discovery'() {
|
||||
expect:
|
||||
!zookeeperServiceDiscovery.getServiceDiscovery().queryForInstances('loanIssuance').empty
|
||||
!zookeeperServiceDiscovery.getServiceDiscovery().queryForInstances('someNameThatShouldMapFraudDetectionServer').empty
|
||||
}
|
||||
|
||||
def cleanup() {
|
||||
zookeeperServiceDiscovery?.serviceDiscovery?.close()
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = [RibbonZookeeperAutoConfiguration])
|
||||
@EnableAutoConfiguration
|
||||
@EnableDiscoveryClient
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
TestingServer testingServer() {
|
||||
return new TestingServer(SocketUtils.findAvailableTcpPort())
|
||||
}
|
||||
|
||||
@Bean
|
||||
ZookeeperProperties zookeeperProperties() {
|
||||
return new ZookeeperProperties(connectString: testingServer().connectString)
|
||||
}
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
@@ -0,0 +1,4 @@
|
||||
stubrunner:
|
||||
camel.enabled: false
|
||||
idsToServiceIds:
|
||||
fraudDetectionServer: someNameThatShouldMapFraudDetectionServer
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
<logger name="org.springframework.cloud" level="DEBUG"/>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
</root>
|
||||
</configuration>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>bootService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>bootService</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>fraudDetectionServer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>fraudDetectionServer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>loanIssuance</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 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
|
||||
~
|
||||
~ http://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.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs</groupId>
|
||||
<artifactId>loanIssuance</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062111</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Reference in New Issue
Block a user