Introduces explicit mode of stub downloading (#503)

* Introduces explicit mode of stub downloading

you have to explicitly provide the mode [CLASSPATH, REMOTE, LOCAL] of how you want to fetch and register stubs

fixes gh-287
This commit is contained in:
Marcin Grzejszczak
2018-01-03 08:25:29 +01:00
committed by GitHub
parent d6871beeb3
commit 748e512f4d
165 changed files with 4316 additions and 165 deletions

View File

@@ -4,8 +4,8 @@ jobs:
docker:
- image: springcloud/pipeline-base
environment:
_JAVA_OPTIONS: "-Xms512m -Xmx768m"
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx768m -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.daemon=false'
JAVA_TOOL_OPTIONS: "-Xms512m -Xmx1024m"
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx1024m -XX:+HeapDumpOnOutOfMemoryError" -Dorg.gradle.daemon=false'
TERM: dumb
branches:
ignore:

View File

@@ -213,7 +213,7 @@ Annotate your test class with `@AutoConfigureStubRunner`. In the annotation prov
----
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, workOffline = true)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceTests {
----
@@ -640,7 +640,7 @@ can also provide the offline work switch.
----
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, workOffline = true)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceTests {
----
@@ -861,13 +861,14 @@ git merge --no-ff contract-change-pr
Now you can disable the offline work for Spring Cloud Contract Stub Runner and indicate
where the repository with your stubs is located. At this moment the stubs of the server
side are automatically downloaded from Nexus/Artifactory. You can switch off the value of
the `workOffline` parameter in your annotation. The following code shows an example of
side are automatically downloaded from Nexus/Artifactory. You can set the value of
`stubsMode` to `REMOTE`. The following code shows an example of
achieving the same thing by changing the properties.
[source,yaml,indent=0]
----
stubrunner:
stubsMode: REMOTE
ids: 'com.example:http-server-dsl:+:stubs:8080'
repositoryRoot: http://repo.spring.io/libs-snapshot
----

View File

@@ -1367,8 +1367,7 @@ com.example.CustomStubDownloaderBuilder
Now you can pick a folder with the source of your stubs.
IMPORTANT: If you do not provide any implementation, then the default is used.
If you use the `repositoryRoot` property or the `workOffline` flag, then an Aether-based
implementation that downloads stubs from a remote repository is used. If you do not
provide these values, the `ClasspathStubProvider` (which will scan the classpath) is
used. If you provide more than one, then the first one on the list is used.
IMPORTANT: If you do not provide any implementation, then the default is used (scan classpath).
If you provide the `stubsMode = StubRunnerProperties.StubsMode.LOCAL` or
`, stubsMode = StubRunnerProperties.StubsMode.REMOTE` then the Aether implementation will be used
If you provide more than one, then the first one on the list is used.

View File

@@ -567,8 +567,8 @@ git merge --no-ff contract-change-pr
Now you can disable the offline work for Spring Cloud Contract Stub Runner and indicate
where the repository with your stubs is located. At this moment the stubs of the server
side are automatically downloaded from Nexus/Artifactory. You can switch off the value of
the `workOffline` parameter in your annotation. The following code shows an example of
side are automatically downloaded from Nexus/Artifactory. You can set the value of
`stubsMode` to `REMOTE`. The following code shows an example of
achieving the same thing by changing the properties.
[source,yaml,indent=0]

View File

@@ -74,8 +74,7 @@ properties. Here are their names with their default values:
|stubrunner.maxPort|15000| Maximum value of a port for a started WireMock with stubs.
|stubrunner.repositoryRoot|| Maven repo URL. If blank, then call the local maven repo.
|stubrunner.classifier|stubs| Default classifier for the stub artifacts.
|stubrunner.workOffline|false| If true, then do not contact any remote repositories to
download stubs.
|stubrunner.stubsMode|CLASSPATH| The way you want to fetch and register the stubs
|stubrunner.ids|| Array of Ivy notation stubs to download.
|stubrunner.username|| Optional username to access the tool that stores the JARs with
stubs.

View File

@@ -43,8 +43,7 @@ Example for Maven
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<configuration>
<!-- url not required for working locally -->
<contractsWorkOffline>true<contractsWorkOffline>
<stubsMode>LOCAL</stubsMode>
<contractDependency>
<groupId>com.example.standalone</groupId>
<artifactId>contracts</artifactId>
@@ -61,7 +60,7 @@ contracts {
targetFramework = 'Spock'
testMode = 'JaxRsClient'
baseClassForTests = 'org.springframework.cloud.MvcSpec'
contractsWorkOffline = true
stubsMode = 'LOCAL'
contractDependency {
stringNotation = "com.example:contracts"
}

View File

@@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -18,7 +19,8 @@ import com.example.loan.model.LoanApplicationStatus;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE, properties="server.context-path=/app")
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, workOffline = true)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceContextPathTests {

View File

@@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -19,7 +20,8 @@ import static org.assertj.core.api.Assertions.assertThat;
// tag::autoconfigure_stubrunner[]
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, workOffline = true)
@AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceTests {
// end::autoconfigure_stubrunner[]

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.contract.stubrunner.StubTrigger;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.integration.support.management.MessageChannelMetrics;
import org.springframework.messaging.SubscribableChannel;
@@ -36,7 +37,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Marius Bogoevici
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = "spring.cloud.stream.bindings.input.destination=sensor-data")
@SpringBootTest(webEnvironment = WebEnvironment.NONE,
properties = "spring.cloud.stream.bindings.input.destination=sensor-data",
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@AutoConfigureStubRunner
public class MessageConsumedTests {

View File

@@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.core.env.Environment;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@@ -20,7 +21,8 @@ import com.example.loan.model.LoanApplicationStatus;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.example:pact-http-server:+:stubs"}, workOffline = true)
@AutoConfigureStubRunner(ids = {"com.example:pact-http-server:+:stubs"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
@DirtiesContext
public class LoanApplicationServiceTests {

View File

@@ -18,23 +18,25 @@ The latter example is described in the <<custom_stub_runner, Custom Stub Runner>
===== Stub downloading
If you provide the `stubrunner.repositoryRoot` or `stubrunner.workOffline` flag will be set
to `true` then Stub Runner will connect to the given server and download the required jars.
It will then unpack the JAR to a temporary folder and reference those files in further
contract processing.
You can control the stub downloading via the `stubsMode` switch. It picks value from the
`StubRunnerProperties.StubsMode` enum. You can use the following options
- `StubRunnerProperties.StubsMode.CLASSPATH` (default value) - will pick stubs from the classpath
- `StubRunnerProperties.StubsMode.LOCAL` - will pick stubs from a local storage (e.g. `.m2`)
- `StubRunnerProperties.StubsMode.REMOTE` - will pick stubs from a remote location
Example:
[source,java]
----
@AutoConfigureStubRunner(repositoryRoot="http://foo.bar", ids = "com.example:beer-api-producer:+:stubs:8095")
@AutoConfigureStubRunner(repositoryRoot="http://foo.bar", ids = "com.example:beer-api-producer:+:stubs:8095", stubsMode = StubRunnerProperties.StubsMode.LOCAL)
----
===== Classpath scanning
If you *DON'T* provide the `stubrunner.repositoryRoot` and `stubrunner.workOffline` flag will
be set to `false` (that's the default) then classpath will get scanned. Let's look at the
following example:
If you set the `stubsMode` property to `StubRunnerProperties.StubsMode.CLASSPATH`
(or set nothing since `CLASSPATH` is the default value) then classpath will get scanned.
Let's look at the following example:
[source,java]
----
@@ -182,10 +184,10 @@ You can set the following options to the main class:
representation of jars with stubs.
Eg. groupid:artifactid1,groupid2:
artifactid2:classifier
--sm, --stubsMode Stubs mode to be used. Acceptable values
[CLASSPATH, LOCAL, REMOTE]
-u, --username Username to user when connecting to
repository
--wo, --workOffline Switch to work offline. Defaults to
'false'
----
===== HTTP Stubs
@@ -483,7 +485,7 @@ or a subdirectory called `config` or in `~/.spring-cloud`. The file could look l
[source,yml,indent=0]
----
stubrunner:
workOffline: true
stubsMode: LOCAL
ids:
- com.example:beer-api-producer:+:9876
----

View File

@@ -47,6 +47,7 @@ import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions.StubRunnerProxyOptions;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.util.StringUtils;
import static java.nio.file.Files.createTempDirectory;
@@ -84,20 +85,20 @@ public class AetherStubDownloader implements StubDownloader {
}
this.remoteRepos = remoteRepositories(stubRunnerOptions);
boolean remoteReposMissing = remoteReposMissing();
if (remoteReposMissing && stubRunnerOptions.workOffline) {
log.info("Remote repos not passed but the switch to work offline was set. "
+ "Stubs will be used from your local Maven repository.");
}
if (remoteReposMissing && !stubRunnerOptions.workOffline) {
throw new IllegalStateException("Remote repositories for stubs are not specified and work offline flag wasn't passed");
}
if (!remoteReposMissing && stubRunnerOptions.workOffline) {
throw new IllegalStateException("Remote repositories for stubs are specified and work offline flag is set. "
+ "You have to provide one of them.");
switch (stubRunnerOptions.stubsMode) {
case LOCAL:
log.info("Remote repos not passed but the switch to work offline was set. "
+ "Stubs will be used from your local Maven repository.");
break;
case REMOTE:
if (remoteReposMissing) throw new IllegalStateException("Remote repositories for stubs are not specified and work offline flag wasn't passed");
break;
case CLASSPATH:
throw new UnsupportedOperationException("You can't use Aether downloader when you use classpath to find stubs");
}
this.repositorySystem = newRepositorySystem();
this.session = newSession(this.repositorySystem, stubRunnerOptions.workOffline);
this.workOffline = stubRunnerOptions.workOffline;
this.workOffline = stubRunnerOptions.stubsMode == StubRunnerProperties.StubsMode.LOCAL;
this.session = newSession(this.repositorySystem, this.workOffline);
registerShutdownHook();
}

View File

@@ -25,8 +25,9 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
/**
* Stub downloader that picks stubs and contracts from the provided resource.
* If no {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#repositoryRoot}
* is provided then by default classpath is searched according to what has been passed in
* If {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#stubsMode} is set
* to {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties.StubsMode#CLASSPATH}
* then classpath is searched according to what has been passed in
* {@link org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties#ids}. The
* pattern to search for stubs looks like this
*

View File

@@ -6,8 +6,8 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.StringUtils;
/**
* Provider for {@link StubDownloaderBuilder}. It can also pick a default
@@ -40,8 +40,8 @@ public class StubDownloaderBuilderProvider {
log.info("A custom Stub Downloader was passed - will pick [" + get() + "]");
return get().build(stubRunnerOptions);
}
if (!stubRunnerOptions.isWorkOffline() && StringUtils.isEmpty(stubRunnerOptions.getStubRepositoryRoot())) {
log.info("Classpath scanning will be used due to passed propreties");
if (stubRunnerOptions.stubsMode == StubRunnerProperties.StubsMode.CLASSPATH) {
log.info("Classpath scanning will be used due to passed properties");
return new ClasspathStubProvider().build(stubRunnerOptions);
}
log.info("Will download stubs using Aether");

View File

@@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
public class StubRunnerMain {
@@ -67,11 +68,14 @@ public class StubRunnerMain {
.acceptsAll(Arrays.asList("pport", "proxyPort"),"Proxy port to use for repository requests")
.withOptionalArg()
.ofType(Integer.class);
parser.acceptsAll(Arrays.asList("wo", "workOffline"),
"Switch to work offline. Defaults to 'false'");
ArgumentAcceptingOptionSpec<String> stubsMode = parser
.acceptsAll(Arrays.asList("sm", "stubsMode"),"Stubs mode to be used. Acceptable values " + Arrays
.toString(StubRunnerProperties.StubsMode.values()))
.withRequiredArg().defaultsTo(StubRunnerProperties.StubsMode.CLASSPATH.toString());
OptionSet options = parser.parse(args);
String stubs = options.valueOf(stubsOpt);
boolean workOffline = options.has("wo");
StubRunnerProperties.StubsMode stubsModeValue = StubRunnerProperties.StubsMode.valueOf(
options.valueOf(stubsMode));
Integer minPortValue = options.valueOf(minPortValueOpt);
Integer maxPortValue = options.valueOf(maxPortValueOpt);
String stubRepositoryRoot= options.valueOf(rootOpt);
@@ -83,7 +87,7 @@ public class StubRunnerMain {
final StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder()
.withMinMaxPort(minPortValue, maxPortValue)
.withStubRepositoryRoot(stubRepositoryRoot)
.withWorkOffline(workOffline).withStubsClassifier(stubsSuffix)
.withStubsMode(stubsModeValue).withStubsClassifier(stubsSuffix)
.withUsername(username)
.withPassword(password)
.withStubs(stubs);

View File

@@ -19,6 +19,7 @@ package org.springframework.cloud.contract.stubrunner;
import java.util.Collection;
import java.util.Map;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.stubrunner.util.StringUtils;
/**
@@ -45,11 +46,6 @@ public class StubRunnerOptions {
*/
final String stubRepositoryRoot;
/**
* avoids local repository in dependency resolution
*/
final boolean workOffline;
/**
* stub definition classifier
*/
@@ -93,8 +89,10 @@ public class StubRunnerOptions {
*/
private String mappingsOutputFolder;
final StubRunnerProperties.StubsMode stubsMode;
StubRunnerOptions(Integer minPortValue, Integer maxPortValue,
String stubRepositoryRoot, boolean workOffline, String stubsClassifier,
String stubRepositoryRoot, StubRunnerProperties.StubsMode stubsMode, String stubsClassifier,
Collection<StubConfiguration> dependencies,
Map<StubConfiguration, Integer> stubIdsToPortMapping,
String username, String password, final StubRunnerProxyOptions stubRunnerProxyOptions,
@@ -102,7 +100,7 @@ public class StubRunnerOptions {
this.minPortValue = minPortValue;
this.maxPortValue = maxPortValue;
this.stubRepositoryRoot = stubRepositoryRoot;
this.workOffline = workOffline;
this.stubsMode = stubsMode != null ? stubsMode : StubRunnerProperties.StubsMode.CLASSPATH;
this.stubsClassifier = stubsClassifier;
this.dependencies = dependencies;
this.stubIdsToPortMapping = stubIdsToPortMapping;
@@ -128,7 +126,7 @@ public class StubRunnerOptions {
.withMinPort(Integer.valueOf(System.getProperty("stubrunner.port.range.min", "10000")))
.withMaxPort(Integer.valueOf(System.getProperty("stubrunner.port.range.max", "15000")))
.withStubRepositoryRoot(System.getProperty("stubrunner.repository.root", ""))
.withWorkOffline(Boolean.parseBoolean(System.getProperty("stubrunner.work-offline", "false")))
.withStubsMode(System.getProperty("stubrunner.stubs-mode", "CLASSPATH"))
.withStubsClassifier(System.getProperty("stubrunner.classifier", "stubs"))
.withStubs(System.getProperty("stubrunner.ids", ""))
.withUsername(System.getProperty("stubrunner.username"))
@@ -163,8 +161,8 @@ public class StubRunnerOptions {
return this.stubRepositoryRoot;
}
public boolean isWorkOffline() {
return this.workOffline;
public StubRunnerProperties.StubsMode getStubsMode() {
return this.stubsMode;
}
public String getStubsClassifier() {
@@ -242,7 +240,7 @@ public class StubRunnerOptions {
@Override public String toString() {
return "StubRunnerOptions{" + "minPortValue=" + this.minPortValue + ", maxPortValue="
+ this.maxPortValue + ", stubRepositoryRoot='" + this.stubRepositoryRoot + '\''
+ ", workOffline=" + this.workOffline + ", stubsClassifier='" + this.stubsClassifier
+ ", stubsMode='" + this.stubsMode + "', stubsClassifier='" + this.stubsClassifier
+ '\'' + ", dependencies=" + this.dependencies + ", stubIdsToPortMapping="
+ this.stubIdsToPortMapping + ", username='" + obfuscate(this.username) + '\'' + ", password='"
+ obfuscate(this.password) + '\'' + ", stubRunnerProxyOptions='" + this.stubRunnerProxyOptions + "', stubsPerConsumer='"

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.stubrunner.util.StubsParser;
import org.springframework.util.StringUtils;
@@ -38,7 +39,6 @@ public class StubRunnerOptionsBuilder {
private Integer minPortValue = 10000;
private Integer maxPortValue = 15000;
private String stubRepositoryRoot;
private boolean workOffline = false;
private String stubsClassifier = "stubs";
private String username;
private String password;
@@ -46,6 +46,7 @@ public class StubRunnerOptionsBuilder {
private boolean stubsPerConsumer = false;
private String consumerName;
private String mappingsOutputFolder;
private StubRunnerProperties.StubsMode stubsMode;
public StubRunnerOptionsBuilder() {
}
@@ -87,8 +88,13 @@ public class StubRunnerOptionsBuilder {
return this;
}
public StubRunnerOptionsBuilder withWorkOffline(boolean workOffline) {
this.workOffline = workOffline;
public StubRunnerOptionsBuilder withStubsMode(StubRunnerProperties.StubsMode stubsMode) {
this.stubsMode = stubsMode;
return this;
}
public StubRunnerOptionsBuilder withStubsMode(String stubsMode) {
this.stubsMode = StubRunnerProperties.StubsMode.valueOf(stubsMode);
return this;
}
@@ -107,7 +113,7 @@ public class StubRunnerOptionsBuilder {
this.minPortValue = options.minPortValue;
this.maxPortValue = options.maxPortValue;
this.stubRepositoryRoot = options.stubRepositoryRoot;
this.workOffline = options.workOffline;
this.stubsMode = options.stubsMode;
this.stubsClassifier = options.stubsClassifier;
this.username = options.username;
this.password = options.password;
@@ -129,7 +135,7 @@ public class StubRunnerOptionsBuilder {
public StubRunnerOptions build() {
return new StubRunnerOptions(this.minPortValue, this.maxPortValue, this.stubRepositoryRoot,
this.workOffline, this.stubsClassifier, buildDependencies(), this.stubIdsToPortMapping,
this.stubsMode, this.stubsClassifier, buildDependencies(), this.stubIdsToPortMapping,
this.username, this.password, this.stubRunnerProxyOptions, this.stubsPerConsumer, this.consumerName,
this.mappingsOutputFolder);
}

View File

@@ -34,6 +34,7 @@ import org.springframework.cloud.contract.stubrunner.StubConfiguration;
import org.springframework.cloud.contract.stubrunner.StubFinder;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptionsBuilder;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
/**
@@ -95,8 +96,8 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio
return this.delegate;
}
@Override public StubRunnerRule workOffline(boolean workOffline) {
builder().withWorkOffline(workOffline);
@Override public StubRunnerRule stubsMode(StubRunnerProperties.StubsMode stubsMode) {
builder().withStubsMode(stubsMode);
return this.delegate;
}

View File

@@ -3,6 +3,7 @@ package org.springframework.cloud.contract.stubrunner.junit;
import java.util.List;
import org.springframework.cloud.contract.stubrunner.StubRunnerOptions;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
interface StubRunnerRuleOptions {
@@ -36,9 +37,9 @@ interface StubRunnerRuleOptions {
StubRunnerRule repoRoot(String repoRoot);
/**
* Should download stubs or use only the local repository
* Stubs mode that should be used
*/
StubRunnerRule workOffline(boolean workOffline);
StubRunnerRule stubsMode(StubRunnerProperties.StubsMode stubsMode);
/**
* Group Id, artifact Id, version and classifier of a single stub to download

View File

@@ -49,11 +49,6 @@ public @interface AutoConfigureStubRunner {
*/
int maxPort() default 15000;
/**
* Should the stubs be checked for presence only locally
*/
boolean workOffline() default false;
/**
* The repository root to use (where the stubs should be downloaded from)
*/
@@ -106,4 +101,11 @@ public @interface AutoConfigureStubRunner {
* @see <a href="https://github.com/spring-cloud/spring-cloud-contract/issues/355">issue 355</a>
*/
String mappingsOutputFolder() default "";
/**
* The way stubs should be found and registered. Defaults to
* {@link StubRunnerProperties.StubsMode#CLASSPATH}.
* @return the type of stubs mode
*/
StubRunnerProperties.StubsMode stubsMode() default StubRunnerProperties.StubsMode.CLASSPATH;
}

View File

@@ -86,7 +86,7 @@ public class StubRunnerConfiguration {
.withMinMaxPort(this.props.getMinPort(), this.props.getMaxPort())
.withStubRepositoryRoot(
uriStringOrEmpty(this.props.getRepositoryRoot()))
.withWorkOffline(this.props.isWorkOffline())
.withStubsMode(this.props.getStubsMode())
.withStubsClassifier(this.props.getClassifier())
.withStubs(this.props.getIds())
.withUsername(this.props.getUsername())

View File

@@ -39,11 +39,6 @@ public class StubRunnerProperties {
*/
private int maxPort = 15000;
/**
* Should the stubs be checked for presence only locally
*/
private boolean workOffline;
/**
* The repository root to use (where the stubs should be downloaded from)
*/
@@ -95,6 +90,29 @@ public class StubRunnerProperties {
*/
private String mappingsOutputFolder;
private StubsMode stubsMode;
/**
* An enumeration stub modes.
*/
public enum StubsMode {
/**
* Pick the stubs from classpath
*/
CLASSPATH,
/**
* Fetch the stubs from local .m2
*/
LOCAL,
/**
* Fetch the stubs from a remote location
*/
REMOTE,
}
public int getMinPort() {
return this.minPort;
}
@@ -111,14 +129,6 @@ public class StubRunnerProperties {
this.maxPort = maxPort;
}
public boolean isWorkOffline() {
return this.workOffline;
}
public void setWorkOffline(boolean workOffline) {
this.workOffline = workOffline;
}
public Resource getRepositoryRoot() {
return this.repositoryRoot;
}
@@ -203,11 +213,20 @@ public class StubRunnerProperties {
this.mappingsOutputFolder = mappingsOutputFolder;
}
public StubsMode getStubsMode() {
return this.stubsMode;
}
public void setStubsMode(StubsMode stubsMode) {
this.stubsMode = stubsMode;
}
@Override public String toString() {
return "StubRunnerProperties{" + "minPort=" + this.minPort + ", maxPort=" + this.maxPort
+ ", workOffline=" + this.workOffline + ", repositoryRoot=" + this.repositoryRoot
+ ", repositoryRoot=" + this.repositoryRoot
+ ", ids=" + Arrays.toString(this.ids) + ", classifier='" + this.classifier + '\''
+ ", setStubsPerConsumer='" + this.stubsPerConsumer + "', consumerName='" + this.consumerName + '\''
+ ", stubsMode='" + this.stubsMode + '\''
+ '}';
}
}

View File

@@ -3,41 +3,21 @@ package org.springframework.cloud.contract.stubrunner
import io.specto.hoverfly.junit.HoverflyRule
import org.eclipse.aether.RepositorySystemSession
import org.junit.Rule
import org.springframework.util.ResourceUtils
import spock.lang.Ignore
import spock.lang.Specification
import spock.util.environment.RestoreSystemProperties
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
import org.springframework.util.ResourceUtils
class AetherStubDownloaderSpec extends Specification {
@Rule
HoverflyRule hoverflyRule = HoverflyRule.inSimulationMode("simulation.json")
// CI tools sometimes can't reach the `test.jfrog.io` address
// @IgnoreIf({ Boolean.valueOf(env['CI']) })
@Ignore("There's sth wrong with the test jfrog API")
def 'Should be able to download from a repository using username and password authentication'() {
given:
StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
.withUsername("andrew.morgan")
.withPassword("k+hbZp8rpolRucXB09dGE/CxPXxidQryQUYSGbeo6JE=")
.withProxy("localhost", hoverflyRule.proxyPort)
.withStubRepositoryRoot("https://test.jfrog.io/test/libs-snapshot-local")
.build()
AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions)
when:
def jar = aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("io.test", "test-simulations-svc", "1.0-SNAPSHOT"))
then:
jar != null
}
def 'Should throw an exception when artifact not found'() {
given:
StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
.withWorkOffline(true)
.withStubsMode(StubRunnerProperties.StubsMode.LOCAL)
.build()
AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions)
@@ -53,6 +33,7 @@ class AetherStubDownloaderSpec extends Specification {
def 'Should throw an exception when a jar is in local m2 and not in remote repo'() {
given:
StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
.withStubsMode(StubRunnerProperties.StubsMode.REMOTE)
.withStubRepositoryRoot("https://test.jfrog.io/test/libs-snapshot-local")
.build()
@@ -79,7 +60,7 @@ class AetherStubDownloaderSpec extends Specification {
and:
StubRunnerOptions stubRunnerOptions = new StubRunnerOptionsBuilder()
.withWorkOffline(true)
.withStubsMode(StubRunnerProperties.StubsMode.LOCAL)
.build()
AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions)

View File

@@ -20,6 +20,8 @@ import spock.lang.Issue
import spock.lang.Specification
import spock.util.environment.RestoreSystemProperties
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
class StubRunnerOptionsBuilderSpec extends Specification {
private StubRunnerOptionsBuilder builder = new StubRunnerOptionsBuilder()
@@ -139,8 +141,8 @@ class StubRunnerOptionsBuilderSpec extends Specification {
@Issue("#466")
def shouldSetAllDependenciesFromOptions() {
given:
StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, "root", true, "classifier",
[new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "foo", "bar",
StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, "root", StubRunnerProperties.StubsMode.LOCAL,
"classifier", [new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "foo", "bar",
new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder"))
builder.withStubs("foo:bar:baz")
when:
@@ -149,7 +151,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
options.minPortValue == 1
options.maxPortValue == 2
options.stubRepositoryRoot == "root"
options.workOffline == true
options.stubsMode == StubRunnerProperties.StubsMode.LOCAL
options.stubsClassifier == "classifier"
options.dependencies == [new StubConfiguration("a:b:c"), new StubConfiguration("foo:bar:baz:classifier")]
options.stubIdsToPortMapping == [(new StubConfiguration("a:b:c")): 3]
@@ -164,7 +166,8 @@ class StubRunnerOptionsBuilderSpec extends Specification {
def shouldNotPrintUsernameAndPassword() {
given:
StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, "root", true, "classifier",
StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, "root",
StubRunnerProperties.StubsMode.CLASSPATH, "classifier",
[new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "username123", "password123",
new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder"))
builder.withStubs("foo:bar:baz")
@@ -183,7 +186,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
System.setProperty("stubrunner.port.range.min", "1")
System.setProperty("stubrunner.port.range.max", "2")
System.setProperty("stubrunner.repository.root", "root")
System.setProperty("stubrunner.work-offline", "true")
System.setProperty("stubrunner.stubs-mode", "LOCAL")
System.setProperty("stubrunner.classifier", "classifier")
System.setProperty("stubrunner.ids", "a:b:c,foo:bar:baz:classifier")
System.setProperty("stubrunner.username", "foo")
@@ -199,7 +202,7 @@ class StubRunnerOptionsBuilderSpec extends Specification {
options.minPortValue == 1
options.maxPortValue == 2
options.stubRepositoryRoot == "root"
options.workOffline == true
options.stubsMode == StubRunnerProperties.StubsMode.LOCAL
options.stubsClassifier == "classifier"
options.dependencies == [new StubConfiguration("a:b:c"), new StubConfiguration("foo:bar:baz:classifier")]
options.username == "foo"

View File

@@ -19,6 +19,8 @@ package org.springframework.cloud.contract.stubrunner.junit
import org.junit.AfterClass
import org.junit.BeforeClass
import org.junit.ClassRule
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier
import spock.lang.Shared
import spock.lang.Specification
@@ -38,6 +40,7 @@ class StubRunnerRuleCustomMsgVerifierSpec extends Specification {
}
@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
.repoRoot(StubRunnerRuleCustomMsgVerifierSpec.getResource("/m2repo/repository").toURI().toString())
.downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService")
.messageVerifier(new MyMessageVerifier())

View File

@@ -22,6 +22,8 @@ import org.junit.ClassRule
import spock.lang.Shared
import spock.lang.Specification
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
/**
* @author Marcin Grzejszczak
*/
@@ -35,6 +37,7 @@ class StubRunnerRuleExceptionThrowingSpec extends Specification {
}
@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
.repoRoot(StubRunnerRuleExceptionThrowingSpec.getResource("/m2repo/repository").toURI().toString())
.downloadStub("org.springframework.cloud.contract.verifier.stubs", "bootService")

View File

@@ -22,6 +22,8 @@ import org.junit.ClassRule
import spock.lang.Shared
import spock.lang.Specification
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
/**
* @author Marcin Grzejszczak
*/
@@ -36,6 +38,7 @@ class StubRunnerRuleSpec extends Specification {
// tag::classrule[]
@ClassRule @Shared StubRunnerRule rule = new StubRunnerRule()
.stubsMode(StubRunnerProperties.StubsMode.REMOTE)
.repoRoot(StubRunnerRuleSpec.getResource("/m2repo/repository").toURI().toString())
.downloadStub("org.springframework.cloud.contract.verifier.stubs", "loanIssuance")
.downloadStub("org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer")

View File

@@ -25,6 +25,7 @@ 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.netflix.eureka.EurekaClientAutoConfiguration
import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration
import org.springframework.cloud.zookeeper.discovery.RibbonZookeeperAutoConfiguration
@@ -46,6 +47,7 @@ import spock.lang.Specification
ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
"org.springframework.cloud.contract.verifier.stubs:bootService"],
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "classpath:m2repo/repository/")
// end::autoconfigure[]
@DirtiesContext

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
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.contract.verifier.messaging.MessageVerifier
import org.springframework.cloud.stream.annotation.EnableBinding
import org.springframework.cloud.stream.messaging.Sink
@@ -42,6 +43,7 @@ import org.springframework.test.context.ContextConfiguration
@SpringBootTest(properties = ["spring.application.name=bar-consumer"])
@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
repositoryRoot = "classpath:m2repo/repository/",
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
stubsPerConsumer = true)
@DirtiesContext
class StubRunnerStubsPerConsumerSpec extends Specification {

View File

@@ -25,6 +25,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
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.contract.verifier.messaging.MessageVerifier
import org.springframework.cloud.stream.annotation.EnableBinding
import org.springframework.cloud.stream.messaging.Sink
@@ -43,6 +44,7 @@ import org.springframework.test.context.ContextConfiguration
@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
repositoryRoot = "classpath:m2repo/repository/",
consumerName = "foo-consumer",
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
stubsPerConsumer = true)
@DirtiesContext
class StubRunnerStubsPerConsumerWithConsumerNameSpec extends Specification {

View File

@@ -30,6 +30,7 @@ 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.cloud.contract.stubrunner.spring.StubRunnerProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.annotation.DirtiesContext
@@ -55,6 +56,7 @@ import static org.mockito.Mockito.mock
["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
"org.springframework.cloud.contract.verifier.stubs:bootService"],
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "classpath:m2repo/repository/")
@DirtiesContext
class StubRunnerSpringCloudConsulAutoConfigurationSpec extends Specification {

View File

@@ -5,6 +5,7 @@ stubrunner:
- org.springframework.cloud.contract.verifier.stubs:loanIssuance
- org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer
- org.springframework.cloud.contract.verifier.stubs:bootService
stubs-mode: remote
# end::test[]
cloud:
enabled: false

View File

@@ -0,0 +1,17 @@
#
# Copyright 2013-2017 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.
#
implementation-class=org.springframework.cloud.contract.verifier.plugin.SpringCloudContractVerifierGradlePlugin

View File

@@ -0,0 +1,65 @@
buildscript {
repositories {
mavenCentral()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
maven { url "http://repo.spring.io/release" }
}
}
apply plugin: 'groovy'
apply plugin: 'spring-cloud-contract'
apply plugin: 'maven-publish'
group = 'org.springframework.cloud.testprojects'
ext {
restAssuredVersion = '3.0.2'
contractsDir = file("repository/mappings")
stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/repository/")
}
repositories {
mavenCentral()
mavenLocal()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
maven { url "http://repo.spring.io/release" }
}
dependencies {
compile "org.springframework:spring-web"
compile "org.springframework:spring-context-support"
compile "org.codehaus.groovy:groovy-all:2.5.0-beta-1"
compile 'com.jayway.jsonpath:json-path-assert:2.2.0'
testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}"
testCompile "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}"
testCompile "org.spockframework:spock-spring:1.0-groovy-2.4"
testCompile "io.restassured:rest-assured:$restAssuredVersion"
testCompile "io.restassured:spring-mock-mvc:$restAssuredVersion"
testCompile "ch.qos.logback:logback-classic:1.1.2"
testCompile "org.springframework.cloud:spring-cloud-contract-verifier:${verifierVersion}"
}
contracts {
baseClassForTests = 'org.springframework.cloud.contract.verifier.twitter.places.BaseMockMvcSpec'
basePackageForTests = 'contracts'
contractsDslDir = contractsDir
// generatedTestSourcesDir = file("${project.rootDir}/src/test/groovy/")
stubsOutputDir = stubsOutputDirRoot
targetFramework = 'Spock'
}
generateContractTests.dependsOn generateWireMockClientStubs
wrapper {
gradleVersion '3.5'
}
test {
testLogging {
exceptionFormat = 'full'
}
}

View File

@@ -0,0 +1,19 @@
#
# Copyright 2013-2017 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.
#
wiremockVersion=2.12.0
jsonAssertVersion=0.4.10
verifierVersion=2.0.0.BUILD-SNAPSHOT

View File

@@ -0,0 +1,6 @@
#Fri Apr 28 10:55:26 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip

View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2013-2017 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.
*/
import org.springframework.cloud.contract.spec.Contract
Contract.make {
priority 2
request {
method 'PUT'
url '/api/12'
headers {
header 'Content-Type': 'application/json'
}
body '''\
[{
"text": "Gonna see you at Warsaw"
}]
'''
}
response {
status 200
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013-2017 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.
*/
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
method 'PUT'
url $(consumer(regex('^/api/[0-9]{2}$')), producer('/api/12'))
headers {
header 'Content-Type': 'application/json'
}
body '''\
[{
"text": "Gonna see you at Warsaw"
}]
'''
}
response {
headers {
header 'Content-Type': $(consumer('application/json'), producer(regex('application/json.*')))
header 'Location': $(consumer('https://localhost:8080'), producer(execute('isEmpty($it)')))
}
body (
path: $(consumer('/api/12'), producer(regex('^/api/[0-9]{2}$'))),
correlationId: $(consumer('1223456'), producer(execute('isProperCorrelationId($it)')))
)
status 200
}
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2013-2017 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.
*/
rootProject.name='bootSimple'

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2013-2017 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.verifier.twitter.place
import groovy.transform.TypeChecked
import groovy.util.logging.Slf4j
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import static org.springframework.web.bind.annotation.RequestMethod.PUT
@Slf4j
@RestController
@RequestMapping('/api')
@TypeChecked
class PairIdController {
@RequestMapping(
value = '{pairId}',
method = PUT,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
String getPlacesFromTweets(@PathVariable long pairId, @RequestBody List<org.springframework.cloud.contract.verifier.twitter.place.Tweet> tweets) {
log.info("Inside PairIdController, doing very important logic")
if (tweets?.text != ["Gonna see you at Warsaw"]) {
throw new IllegalArgumentException("Wrong text in tweet: ${tweets?.text}")
}
return """
{
"path" : "/api/$pairId",
"correlationId" : 123456
}
"""
}
}

View File

@@ -0,0 +1,13 @@
package org.springframework.cloud.contract.verifier.twitter.place;
public class Tweet {
private String text;
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2013-2017 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.verifier.twitter.places
import org.springframework.cloud.contract.verifier.twitter.place.PairIdController
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import spock.lang.Specification
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
class AcceptanceSpec extends Specification {
def "should have controller up and running"() {
given:
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new PairIdController()).build()
expect:
mockMvc.perform(put("/api/${1}").
contentType(MediaType.APPLICATION_JSON).
content("""[{"text":"Gonna see you at Warsaw"}]""")).
andExpect(status().isOk())
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2013-2017 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.verifier.twitter.places
import io.restassured.module.mockmvc.RestAssuredMockMvc
import org.springframework.cloud.contract.verifier.twitter.place.PairIdController
import spock.lang.Specification
// tag::base_class[]
abstract class BaseMockMvcSpec extends Specification {
def setup() {
RestAssuredMockMvc.standaloneSetup(new PairIdController())
}
void isProperCorrelationId(Integer correlationId) {
assert correlationId == 123456
}
void isEmpty(String value) {
assert value == null
}
}
// end::base_class[]

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2013-2017 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.
*/
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
String console = "CONSOLE"
String logPattern = "%d{yyyy-MM-dd HH:mm:ss.SSSZ, Europe/Warsaw} | %-5level | %X{correlationId} | %thread | %logger{1} | %m%n"
appender(console, ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = logPattern
}
}
root(INFO, [console])
logger("org.springframework.cloud", DEBUG)

View File

@@ -0,0 +1,152 @@
/*
* Copyright 2013-2017 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.
*/
buildscript {
repositories {
mavenLocal()
mavenCentral()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
maven { url "http://repo.spring.io/release" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.M3")
}
}
apply plugin: 'checkstyle'
allprojects {
group = 'com.example.jersey'
}
ext {
spockVersion = '1.0-groovy-2.4'
contractVerifierStubsBaseDirectory = 'src/test/resources/stubs'
}
subprojects {
apply plugin: 'groovy'
repositories {
mavenCentral()
mavenLocal()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
maven { url "http://repo.spring.io/release" }
}
dependencies {
testCompile 'org.codehaus.groovy:groovy-all:2.5.0-beta-1'
testCompile "org.spockframework:spock-core:$spockVersion"
testCompile 'junit:junit:4.12'
testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}"
testCompile "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}"
testCompile "org.springframework.cloud:spring-cloud-contract-verifier:${verifierVersion}"
}
}
configure([project(':fraudDetectionService'), project(':loanApplicationService')]) {
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'maven-publish'
ext['jetty.version'] = '9.2.17.v20160517'
jar {
version = '0.0.1'
}
configurations {
compile.exclude module: "spring-boot-starter-tomcat"
}
dependencies {
compile('org.glassfish.jersey.containers:jersey-container-jetty-http:2.23.2') {
exclude group: 'org.eclipse.jetty'
}
compile 'org.springframework.boot:spring-boot-starter-jersey'
compile 'org.springframework.boot:spring-boot-starter-jetty'
testRuntime "org.spockframework:spock-spring:$spockVersion"
compile('org.glassfish.jersey.connectors:jersey-apache-connector:2.23.2') {
exclude group: 'org.eclipse.jetty'
}
testCompile "org.mockito:mockito-core"
testCompile "org.springframework:spring-test"
testCompile "org.springframework.boot:spring-boot-test"
testCompile("com.github.tomakehurst:wiremock:${wiremockVersion}") {
exclude group: 'org.eclipse.jetty'
}
}
task cleanup(type: Delete) {
delete 'src/test/resources/mappings', 'src/test/resources/stubs'
}
clean.dependsOn('cleanup')
test {
testLogging {
exceptionFormat = 'full'
}
}
}
configure(project(':fraudDetectionService')) {
test.dependsOn('generateWireMockClientStubs')
apply plugin: 'spring-cloud-contract'
ext {
contractsDir = file("mappings")
stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/")
}
ext['jetty.version'] = '9.2.17.v20160517'
contracts {
targetFramework = 'Spock'
testMode = 'JaxRsClient'
baseClassForTests = 'org.springframework.cloud.MvcSpec'
contractsRepositoryUrl = "file://" + file("${project.rootDir.absolutePath}/m2repo/repository").absolutePath
contractDependency {
stringNotation("com.example:jersey-contracts:+:")
}
generatedTestSourcesDir = file("${project.buildDir}/generated-test-sources/")
stubsOutputDir = stubsOutputDirRoot
disableStubPublication(project.hasProperty("disablePublication"))
}
}
configure(project(':loanApplicationService')) {
task copyCollaboratorStubs(type: Copy) {
File fraudBuildDir = project(':fraudDetectionService').buildDir
from(new File(fraudBuildDir, "/production/${project(':fraudDetectionService').name}-stubs/")) {
include '**/*.json'
}
into "src/test/resources/mappings"
}
test.dependsOn('copyCollaboratorStubs')
}
wrapper {
gradleVersion '3.5'
}

View File

@@ -0,0 +1,24 @@
package org.springframework.cloud.frauddetection;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
ResourceConfig resourceConfig() {
return ResourceConfig.forApplication(new FraudRestApplication());
}
}

View File

@@ -0,0 +1,38 @@
package org.springframework.cloud.frauddetection;
import org.springframework.cloud.frauddetection.model.FraudCheck;
import org.springframework.cloud.frauddetection.model.FraudCheckResult;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import javax.ws.rs.*;
import java.math.BigDecimal;
import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.FRAUD;
import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.OK;
@Controller
@Path("/")
public class FraudDetectionController {
private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json";
private static final String NO_REASON = null;
private static final String AMOUNT_TOO_HIGH = "Amount too high";
private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000");
@PUT
@Path("/fraudcheck")
@Produces(FRAUD_SERVICE_JSON_VERSION_1)
@Consumes(FRAUD_SERVICE_JSON_VERSION_1)
public FraudCheckResult fraudCheck(@RequestBody(required = false) FraudCheck fraudCheck) {
if (amountGreaterThanThreshold(fraudCheck)) {
return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH);
}
return new FraudCheckResult(OK, NO_REASON);
}
private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) {
return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0;
}
}

View File

@@ -0,0 +1,13 @@
package org.springframework.cloud.frauddetection;
import java.util.Collections;
import java.util.Set;
public class FraudRestApplication extends javax.ws.rs.core.Application {
@Override
public Set<Class<?>> getClasses() {
return Collections.<Class<?>>singleton(FraudDetectionController.class);
}
}

View File

@@ -0,0 +1,29 @@
package org.springframework.cloud.frauddetection.model;
import java.math.BigDecimal;
public class FraudCheck {
private String clientPesel;
private BigDecimal loanAmount;
public FraudCheck() {
}
public String getClientPesel() {
return this.clientPesel;
}
public void setClientPesel(String clientPesel) {
this.clientPesel = clientPesel;
}
public BigDecimal getLoanAmount() {
return this.loanAmount;
}
public void setLoanAmount(BigDecimal loanAmount) {
this.loanAmount = loanAmount;
}
}

View File

@@ -0,0 +1,32 @@
package org.springframework.cloud.frauddetection.model;
public class FraudCheckResult {
private FraudCheckStatus fraudCheckStatus;
private String rejectionReason;
public FraudCheckResult() {
}
public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) {
this.fraudCheckStatus = fraudCheckStatus;
this.rejectionReason = rejectionReason;
}
public FraudCheckStatus getFraudCheckStatus() {
return this.fraudCheckStatus;
}
public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) {
this.fraudCheckStatus = fraudCheckStatus;
}
public String getRejectionReason() {
return this.rejectionReason;
}
public void setRejectionReason(String rejectionReason) {
this.rejectionReason = rejectionReason;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2013-2017 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
import org.springframework.cloud.frauddetection.Application
import org.springframework.cloud.frauddetection.FraudRestApplication
import org.eclipse.jetty.server.Server
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider
import org.glassfish.jersey.client.ClientConfig
import org.glassfish.jersey.jetty.JettyHttpContainerFactory
import org.glassfish.jersey.server.ResourceConfig
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Shared
import spock.lang.Specification
import javax.ws.rs.client.Client
import javax.ws.rs.client.ClientBuilder
import javax.ws.rs.client.WebTarget
import javax.ws.rs.core.UriBuilder
import static org.springframework.util.SocketUtils.findAvailableTcpPort
abstract class MvcSpec extends Specification {
@Shared
WebTarget webTarget
@Shared
private Server server
@Shared
private Client client
def setupSpec() {
URI baseUri = UriBuilder.fromUri("http://localhost").port(findAvailableTcpPort(8000)).build()
ResourceConfig resourceConfig = ResourceConfig.forApplication(new FraudRestApplication())
resourceConfig.property("contextConfig", new AnnotationConfigApplicationContext(Application))
server = JettyHttpContainerFactory.createServer(baseUri, resourceConfig, true)
ClientConfig clientConfig = new ClientConfig()
clientConfig.connectorProvider(new ApacheConnectorProvider())
client = ClientBuilder.newClient(clientConfig)
webTarget = client.target(baseUri)
server.start()
}
def cleanupSpec() {
client?.close()
server?.stop()
}
void assertThatRejectionReasonIsNull(def rejectionReason) {
assert !rejectionReason
}
}

View File

@@ -0,0 +1,70 @@
package org.springframework.cloud;
import org.springframework.cloud.frauddetection.Application;
import org.springframework.cloud.frauddetection.FraudRestApplication;
import org.eclipse.jetty.server.Server;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import static org.springframework.util.SocketUtils.findAvailableTcpPort;
public abstract class MvcTest {
public static WebTarget webTarget;
private static Server server;
private static Client client;
@BeforeClass
public static void setupTest() {
URI baseUri = UriBuilder.fromUri("http://localhost").port(findAvailableTcpPort(8000)).build();
ResourceConfig resourceConfig = ResourceConfig.forApplication(new FraudRestApplication());
resourceConfig.property("contextConfig", new AnnotationConfigApplicationContext(Application.class));
server = JettyHttpContainerFactory.createServer(baseUri, resourceConfig, true);
ClientConfig clientConfig = new ClientConfig();
clientConfig.connectorProvider(new ApacheConnectorProvider());
client = ClientBuilder.newClient(clientConfig);
webTarget = client.target(baseUri);
try {
server.start();
} catch (Exception e) {
e.printStackTrace();
}
}
@AfterClass
public static void cleanupTest() {
if(client != null) {
client.close();
}
if (server != null) {
try {
server.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void assertThatRejectionReasonIsNull(Object rejectionReason) {
assert rejectionReason == null;
}
}

View File

@@ -0,0 +1,18 @@
#
# Copyright 2013-2017 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.
#
wiremockVersion=2.12.0
jsonAssertVersion=0.4.10
verifierVersion=2.0.0.BUILD-SNAPSHOT

View File

@@ -0,0 +1,6 @@
#Fri Apr 28 10:55:26 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip

View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2013-2017 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.frauddetection;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2013-2017 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.frauddetection;
import org.springframework.cloud.frauddetection.model.FraudCheckStatus;
import org.springframework.cloud.frauddetection.model.FraudServiceRequest;
import org.springframework.cloud.frauddetection.model.FraudServiceResponse;
import org.springframework.cloud.frauddetection.model.LoanApplication;
import org.springframework.cloud.frauddetection.model.LoanApplicationResult;
import org.springframework.cloud.frauddetection.model.LoanApplicationStatus;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class LoanApplicationService {
private static final String FRAUD_SERVICE_JSON_VERSION_1 =
"application/vnd.fraud.v1+json";
private final RestTemplate restTemplate;
private int port = 8080;
public LoanApplicationService() {
this.restTemplate = new RestTemplate();
}
public LoanApplicationResult loanApplication(LoanApplication loanApplication) {
FraudServiceRequest request =
new FraudServiceRequest(loanApplication);
FraudServiceResponse response =
sendRequestToFraudDetectionService(request);
return buildResponseFromFraudResult(response);
}
private FraudServiceResponse sendRequestToFraudDetectionService(
FraudServiceRequest request) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1);
ResponseEntity<FraudServiceResponse> response =
this.restTemplate.exchange("http://localhost:" + this.port + "/fraudcheck", HttpMethod.PUT,
new HttpEntity<>(request, httpHeaders),
FraudServiceResponse.class);
return response.getBody();
}
private LoanApplicationResult buildResponseFromFraudResult(FraudServiceResponse response) {
LoanApplicationStatus applicationStatus = null;
if (FraudCheckStatus.OK == response.getFraudCheckStatus()) {
applicationStatus = LoanApplicationStatus.LOAN_APPLIED;
} else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) {
applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED;
}
return new LoanApplicationResult(applicationStatus, response.getRejectionReason());
}
public void setPort(int port) {
this.port = port;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
public class Client {
private String pesel;
public String getPesel() {
return this.pesel;
}
public void setPesel(String pesel) {
this.pesel = pesel;
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
public enum FraudCheckStatus {
OK, FRAUD
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
import java.math.BigDecimal;
public class FraudServiceRequest {
private String clientPesel;
private BigDecimal loanAmount;
public FraudServiceRequest() {
}
public FraudServiceRequest(LoanApplication loanApplication) {
this.clientPesel = loanApplication.getClient().getPesel();
this.loanAmount = loanApplication.getAmount();
}
public String getClientPesel() {
return this.clientPesel;
}
public void setClientPesel(String clientPesel) {
this.clientPesel = clientPesel;
}
public BigDecimal getLoanAmount() {
return this.loanAmount;
}
public void setLoanAmount(BigDecimal loanAmount) {
this.loanAmount = loanAmount;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
public class FraudServiceResponse {
private FraudCheckStatus fraudCheckStatus;
private String rejectionReason;
public FraudServiceResponse() {
}
public FraudCheckStatus getFraudCheckStatus() {
return this.fraudCheckStatus;
}
public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) {
this.fraudCheckStatus = fraudCheckStatus;
}
public String getRejectionReason() {
return this.rejectionReason;
}
public void setRejectionReason(String rejectionReason) {
this.rejectionReason = rejectionReason;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
import java.math.BigDecimal;
public class LoanApplication {
private Client client;
private BigDecimal amount;
private String loanApplicationId;
public Client getClient() {
return this.client;
}
public void setClient(Client client) {
this.client = client;
}
public BigDecimal getAmount() {
return this.amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public String getLoanApplicationId() {
return this.loanApplicationId;
}
public void setLoanApplicationId(String loanApplicationId) {
this.loanApplicationId = loanApplicationId;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
public class LoanApplicationResult {
private LoanApplicationStatus loanApplicationStatus;
private String rejectionReason;
public LoanApplicationResult() {
}
public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, String rejectionReason) {
this.loanApplicationStatus = loanApplicationStatus;
this.rejectionReason = rejectionReason;
}
public LoanApplicationStatus getLoanApplicationStatus() {
return this.loanApplicationStatus;
}
public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) {
this.loanApplicationStatus = loanApplicationStatus;
}
public String getRejectionReason() {
return this.rejectionReason;
}
public void setRejectionReason(String rejectionReason) {
this.rejectionReason = rejectionReason;
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2013-2017 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.frauddetection.model;
public enum LoanApplicationStatus {
LOAN_APPLIED, LOAN_APPLICATION_REJECTED
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2013-2017 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
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.cloud.frauddetection.Application
import org.springframework.cloud.frauddetection.LoanApplicationService
import org.springframework.cloud.frauddetection.model.Client
import org.springframework.cloud.frauddetection.model.LoanApplication
import org.springframework.cloud.frauddetection.model.LoanApplicationResult
import org.springframework.cloud.frauddetection.model.LoanApplicationStatus
import com.github.tomakehurst.wiremock.junit.WireMockClassRule
import org.junit.ClassRule
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
import spock.lang.Shared
import spock.lang.Specification
@ContextConfiguration(loader = SpringBootContextLoader, classes = Application)
class LoanApplicationServiceSpec extends Specification {
public static int port = org.springframework.util.SocketUtils.findAvailableTcpPort()
@ClassRule
@Shared
WireMockClassRule wireMockRule = new WireMockClassRule(port)
@Autowired
LoanApplicationService sut
def setup() {
sut.port = port
}
def 'should successfully apply for loan'() {
given:
LoanApplication application =
new LoanApplication(client: new Client(pesel: '1234567890'), amount: 123.123)
when:
LoanApplicationResult loanApplication = sut.loanApplication(application)
then:
loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED
loanApplication.rejectionReason == null
}
def 'should be rejected due to abnormal loan amount'() {
given:
LoanApplication application =
new LoanApplication(client: new Client(pesel: '1234567890'), amount: 99_999)
when:
LoanApplicationResult loanApplication = sut.loanApplication(application)
then:
loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLICATION_REJECTED
loanApplication.rejectionReason == 'Amount too high'
}
}

View File

@@ -0,0 +1,23 @@
{
"request": {
"method": "PUT",
"headers": {
"Content-Type": {
"equalTo": "application/vnd.fraud.v1+json"
}
},
"url": "/fraudcheck",
"bodyPatterns": [
{
"matches": "\\s*\\{\\s*\"clientPesel\"\\s*:\\s*\"?[0-9]{10}\"?\\s*,\\s*\"loanAmount\"\\s*:\\s*\"?99999\"?\\s*\\}\\s*"
}
]
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/vnd.fraud.v1+json"
},
"body": "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}"
}
}

View File

@@ -0,0 +1,23 @@
{
"request": {
"method": "PUT",
"headers": {
"Content-Type": {
"equalTo": "application/vnd.fraud.v1+json"
}
},
"url": "/fraudcheck",
"bodyPatterns": [
{
"matches": "\\s*\\{\\s*\"clientPesel\"\\s*:\\s*\"?[0-9]{10}\"?\\s*,\\s*\"loanAmount\"\\s*:\\s*\"?123.123\"?\\s*\\}\\s*"
}
]
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/vnd.fraud.v1+json"
},
"body": "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}"
}
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 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>com.example</groupId>
<artifactId>jersey-contracts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
</project>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
<groupId>com.example</groupId>
<artifactId>jersey-contracts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<versioning>
<snapshot>
<localCopy>true</localCopy>
</snapshot>
<lastUpdated>20160916125313</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>0.0.1-SNAPSHOT</value>
<updated>20160916125313</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
<value>0.0.1-SNAPSHOT</value>
<updated>20160916125313</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
</metadata>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 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>com.example</groupId>
<artifactId>jersey-contracts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<versioning>
<versions>
<version>0.0.1-SNAPSHOT</version>
</versions>
<lastUpdated>20160409062112</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1,18 @@
/*
* Copyright 2013-2017 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.
*/
include ':fraudDetectionService'
include ':loanApplicationService'

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2013-2017 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.
*/
buildscript {
repositories {
mavenCentral()
mavenLocal()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
maven { url "http://repo.spring.io/release" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.M3")
}
}
ext {
restAssuredVersion = '3.0.2'
spockVersion = '1.0-groovy-2.4'
contractVerifierStubsBaseDirectory = 'src/test/resources/stubs'
}
group = 'org.springframework.cloud.testprojects'
subprojects {
apply plugin: 'groovy'
repositories {
mavenCentral()
mavenLocal()
maven { url "http://repo.spring.io/snapshot" }
maven { url "http://repo.spring.io/milestone" }
maven { url "http://repo.spring.io/release" }
}
dependencies {
testCompile "org.codehaus.groovy:groovy-all:2.5.0-beta-1"
testCompile "org.spockframework:spock-core:$spockVersion"
testCompile("junit:junit:4.12")
testCompile "com.github.tomakehurst:wiremock:${wiremockVersion}"
testCompile "com.toomuchcoding.jsonassert:jsonassert:${jsonAssertVersion}"
testCompile "org.springframework.cloud:spring-cloud-contract-verifier:${verifierVersion}"
}
}
configure([project(':fraudDetectionService'), project(':loanApplicationService')]) {
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'spring-cloud-contract'
apply plugin: 'maven-publish'
ext {
contractsDir = file("mappings")
stubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/")
}
contracts {
targetFramework = 'Spock'
testMode = 'MockMvc'
baseClassForTests = 'org.springframework.cloud.MvcSpec'
contractsDslDir = file("${project.projectDir.absolutePath}/mappings/")
generatedTestSourcesDir = file("${project.buildDir}/generated-test-sources/")
stubsOutputDir = stubsOutputDirRoot
}
jar {
version = '0.0.1'
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web") {
exclude module: "spring-boot-starter-tomcat"
}
compile("org.springframework.boot:spring-boot-starter-jetty")
compile("org.springframework.boot:spring-boot-starter-actuator")
testRuntime "org.spockframework:spock-spring:$spockVersion"
testCompile "org.mockito:mockito-core"
testCompile "org.springframework:spring-test"
testCompile "org.springframework.boot:spring-boot-test"
testCompile "io.rest-assured:rest-assured:$restAssuredVersion"
testCompile "io.rest-assured:spring-mock-mvc:$restAssuredVersion"
}
task cleanup(type: Delete) {
delete 'src/test/resources/mappings', 'src/test/resources/stubs'
}
clean.dependsOn('cleanup')
test {
testLogging {
exceptionFormat = 'full'
}
}
}
configure(project(':fraudDetectionService')) {
test.dependsOn('generateWireMockClientStubs')
}
configure(project(':loanApplicationService')) {
task copyCollaboratorStubs(type: Copy) {
File fraudBuildDir = project(':fraudDetectionService').buildDir
from(new File(fraudBuildDir, "/production/${project(':fraudDetectionService').name}-stubs/"))
into "src/test/resources/"
}
generateContractTests.dependsOn('copyCollaboratorStubs')
}
wrapper {
gradleVersion '3.5'
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2013-2017 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.
*/
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
method """PUT"""
url """/fraudcheck"""
body("""
{
"clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}",
"loanAmount":99999}
"""
)
headers {
header("""Content-Type""", """application/vnd.fraud.v1+json""")
}
}
response {
status 200
body( """{
"fraudCheckStatus": "${value(consumer('FRAUD'), producer(regex('[A-Z]{5}')))}",
"rejectionReason": "Amount too high"
}""")
headers {
header('Content-Type': value(
producer(regex('application/vnd.fraud.v1.json.*')),
consumer('application/vnd.fraud.v1+json'))
)
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2013-2017 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.
*/
import org.springframework.cloud.contract.spec.Contract
Contract.make {
request {
method 'PUT'
url '/fraudcheck'
body("""
{
"clientPesel":"${value(consumer(regex('[0-9]{10}')), producer('1234567890'))}",
"loanAmount":123.123
}
"""
)
headers {
header('Content-Type', 'application/vnd.fraud.v1+json')
}
}
response {
status 200
body(
fraudCheckStatus: "OK",
rejectionReason: $(consumer(null), producer(execute('assertThatRejectionReasonIsNull($it)')))
)
headers {
header('Content-Type': value(
producer(regex('application/vnd.fraud.v1.json.*')),
consumer('application/vnd.fraud.v1+json'))
)
}
}
}

View File

@@ -0,0 +1,18 @@
package org.springframework.cloud.frauddetection;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(
org.springframework.cloud.frauddetection.Application.class, args);
}
}

View File

@@ -0,0 +1,39 @@
package org.springframework.cloud.frauddetection;
import org.springframework.cloud.frauddetection.model.FraudCheck;
import org.springframework.cloud.frauddetection.model.FraudCheckResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.FRAUD;
import static org.springframework.cloud.frauddetection.model.FraudCheckStatus.OK;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
@RestController
public class FraudDetectionController {
private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json";
private static final String NO_REASON = null;
private static final String AMOUNT_TOO_HIGH = "Amount too high";
private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000");
@RequestMapping(
value = "/fraudcheck",
method = PUT,
consumes = FRAUD_SERVICE_JSON_VERSION_1,
produces = FRAUD_SERVICE_JSON_VERSION_1)
public FraudCheckResult fraudCheck(@RequestBody FraudCheck fraudCheck) {
if (amountGreaterThanThreshold(fraudCheck)) {
return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH);
}
return new FraudCheckResult(OK, NO_REASON);
}
private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) {
return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0;
}
}

View File

@@ -0,0 +1,29 @@
package org.springframework.cloud.frauddetection.model;
import java.math.BigDecimal;
public class FraudCheck {
private String clientPesel;
private BigDecimal loanAmount;
public FraudCheck() {
}
public String getClientPesel() {
return this.clientPesel;
}
public void setClientPesel(String clientPesel) {
this.clientPesel = clientPesel;
}
public BigDecimal getLoanAmount() {
return this.loanAmount;
}
public void setLoanAmount(BigDecimal loanAmount) {
this.loanAmount = loanAmount;
}
}

View File

@@ -0,0 +1,32 @@
package org.springframework.cloud.frauddetection.model;
public class FraudCheckResult {
private FraudCheckStatus fraudCheckStatus;
private String rejectionReason;
public FraudCheckResult() {
}
public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) {
this.fraudCheckStatus = fraudCheckStatus;
this.rejectionReason = rejectionReason;
}
public FraudCheckStatus getFraudCheckStatus() {
return this.fraudCheckStatus;
}
public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) {
this.fraudCheckStatus = fraudCheckStatus;
}
public String getRejectionReason() {
return this.rejectionReason;
}
public void setRejectionReason(String rejectionReason) {
this.rejectionReason = rejectionReason;
}
}

View File

@@ -0,0 +1,5 @@
package org.springframework.cloud.frauddetection.model;
public enum FraudCheckStatus {
OK, FRAUD
}

View File

@@ -0,0 +1,4 @@
#WireMock password - http://wiremock.org/docs/running-standalone/
server.ssl.key-store-password=password
server.ssl.key-password=password
server.ssl.trust-store-password=password

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2013-2017 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
import org.springframework.cloud.frauddetection.FraudDetectionController
import io.restassured.module.mockmvc.RestAssuredMockMvc
import spock.lang.Specification
class MvcSpec extends Specification {
def setup() {
RestAssuredMockMvc.standaloneSetup(new FraudDetectionController())
}
void assertThatRejectionReasonIsNull(def rejectionReason) {
assert !rejectionReason
}
}

View File

@@ -0,0 +1,16 @@
package org.springframework.cloud;
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
public class MvcTest {
@Before
public void setup() {
RestAssuredMockMvc.standaloneSetup(new org.springframework.cloud.frauddetection.FraudDetectionController());
}
public void assertThatRejectionReasonIsNull(Object rejectionReason) {
assert rejectionReason == null;
}
}

View File

@@ -0,0 +1,18 @@
#
# Copyright 2013-2017 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.
#
wiremockVersion=2.12.0
jsonAssertVersion=0.4.10
verifierVersion=2.0.0.BUILD-SNAPSHOT

View File

@@ -0,0 +1,6 @@
#Fri Apr 28 10:55:26 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip

View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,18 @@
package org.springframework.cloud.frauddetection;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(
org.springframework.cloud.frauddetection.Application.class, args);
}
}

Some files were not shown because too many files have changed in this diff Show More