Compare commits

..

14 Commits

Author SHA1 Message Date
Tom Hombergs
99f6e3fb71 added example with spring cloud contract 2018-01-08 20:23:04 +01:00
Tom Hombergs
7bce17b055 upgraded pact-web and pact-jvm-provider-spring 2018-01-02 23:01:38 +01:00
Tom Hombergs
c9ae2ca600 updated pact between Angular app and Spring provider 2017-12-31 15:25:57 +01:00
Tom Hombergs
5f46041ccd updated gradle 2017-12-31 15:25:06 +01:00
Tom Hombergs
d139eecb2d updated angular-pact example 2017-12-10 20:24:55 +01:00
Tom Hombergs
671f5e501e moved angular-pact to pact-angular 2017-12-09 13:30:06 +01:00
Tom Hombergs
a885f98f2f fixed dependency to pact-node 2017-11-13 23:17:08 +01:00
Tom Hombergs
f10c8d2bfc added angular pact example 2017-11-06 23:16:47 +01:00
Tom Hombergs
b93c05fbe5 fixed unit test 2017-10-18 21:01:54 +02:00
Tom Hombergs
8e69a627cf Merge pull request #3 from thombergs/angular-pact
Angular pact
2017-10-18 20:32:07 +02:00
Tom Hombergs
c8af61e065 Merge remote-tracking branch 'origin/master' 2017-10-10 23:14:27 +02:00
Tom Hombergs
d1c5091ee8 added junit examples 2017-10-10 23:14:19 +02:00
Tom Hombergs
83b7eb429e Merge pull request #1 from snicoll/patch-1
Remove unnecessary EnableAutoConfiguration
2017-09-19 20:23:18 +02:00
Stéphane Nicoll
3e866fbe44 Remove unnecessary EnableAutoConfiguration 2017-09-19 08:41:04 +02:00
88 changed files with 2342 additions and 734 deletions

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-all.zip

25
junit5/.gitignore vendored Normal file
View File

@@ -0,0 +1,25 @@
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

3
junit5/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Examples with JUnit 4 and JUnit 5
Have a look at [the code](/src/test/java/com/example/demo/)

25
junit5/build.gradle Normal file
View File

@@ -0,0 +1,25 @@
buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'java'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
ext {
springCloudVersion = 'Dalston.SR2'
}
dependencies {
testCompile 'org.junit.jupiter:junit-jupiter-engine:5.0.1'
testCompile 'junit:junit:4.12'
}

BIN
junit5/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

172
junit5/gradlew vendored Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## 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
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
junit5/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@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
: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=%*
: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,17 @@
server.port: 8081
logging.level.com.example.demo.CustomerClient: DEBUG
logging.level.com.example.demo.AddressClient: DEBUG
logging.level.org.hibernate.SQL: DEBUG
customers:
ribbon:
eureka:
enabled: false
listOfServers: localhost:8080
addresses:
ribbon:
eureka:
enabled: false
listOfServers: localhost:8080

View File

@@ -0,0 +1,15 @@
package com.example.demo.connectionchecking;
public class ConnectionChecker {
private String uri;
public ConnectionChecker(String uri) {
this.uri = uri;
}
public boolean connect() {
return false;
}
}

View File

@@ -0,0 +1,31 @@
package com.example.demo.connectionchecking.junit4;
import com.example.demo.connectionchecking.ConnectionChecker;
import org.junit.AssumptionViolatedException;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class AssumingConnection implements TestRule {
private ConnectionChecker checker;
public AssumingConnection(ConnectionChecker checker) {
this.checker = checker;
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
if (!checker.connect()) {
throw new AssumptionViolatedException("Could not connect. Skipping test!");
} else {
base.evaluate();
}
}
};
}
}

View File

@@ -0,0 +1,19 @@
package com.example.demo.connectionchecking.junit4;
import com.example.demo.connectionchecking.ConnectionChecker;
import org.junit.ClassRule;
import org.junit.Test;
import static org.junit.Assert.fail;
public class ConnectionCheckingJunit4Test {
@ClassRule
public static AssumingConnection assumingConnection = new AssumingConnection(new ConnectionChecker("http://my.integration.system"));
@Test
public void testOnlyWhenConnected() {
fail("Booh!");
}
}

View File

@@ -0,0 +1,14 @@
package com.example.demo.connectionchecking.junit5;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.jupiter.api.extension.ExtendWith;
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(AssumeConnectionCondition.class)
public @interface AssumeConnection {
String uri();
}

View File

@@ -0,0 +1,28 @@
package com.example.demo.connectionchecking.junit5;
import java.util.Optional;
import com.example.demo.connectionchecking.ConnectionChecker;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation;
public class AssumeConnectionCondition implements ExecutionCondition {
@Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
Optional<AssumeConnection> annotation = findAnnotation(context.getElement(), AssumeConnection.class);
if (annotation.isPresent()) {
String uri = annotation.get().uri();
ConnectionChecker checker = new ConnectionChecker(uri);
if (!checker.connect()) {
return ConditionEvaluationResult.disabled(String.format("Could not connect to '%s'. Skipping test!", uri));
} else {
return ConditionEvaluationResult.enabled(String.format("Successfully connected to '%s'. Continuing test!", uri));
}
}
return ConditionEvaluationResult.enabled("No AssumeConnection annotation found. Continuing test.");
}
}

View File

@@ -0,0 +1,14 @@
package com.example.demo.connectionchecking.junit5;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
@AssumeConnection(uri = "http://my.integration.system")
public class ConnectionCheckingJunit5Test {
@Test
public void testOnlyWhenConnected() {
fail("Booh!");
}
}

View File

@@ -0,0 +1,120 @@
{
"provider": {
"name": "customerServiceProvider"
},
"consumer": {
"name": "addressClient"
},
"interactions": [
{
"description": "a request to the address collection resource",
"request": {
"method": "GET",
"path": "/addresses/"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/hal+json"
},
"body": {
"_embedded": {
"addresses": [
{
"street": "Elm Street",
"_links": {
"self": {
"href": "http://localhost:8080/addresses/1"
},
"address": {
"href": "http://localhost:8080/addresses/1"
},
"customer": {
"href": "http://localhost:8080/addresses/1/customer"
}
}
},
{
"street": "High Street",
"_links": {
"self": {
"href": "http://localhost:8080/addresses/2"
},
"address": {
"href": "http://localhost:8080/addresses/2"
},
"customer": {
"href": "http://localhost:8080/addresses/2/customer"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/addresses{?page,size,sort}",
"templated": true
},
"profile": {
"href": "http://localhost:8080/profile/addresses"
},
"search": {
"href": "http://localhost:8080/addresses/search"
}
},
"page": {
"size": 20,
"totalElements": 2,
"totalPages": 1,
"number": 0
}
}
},
"providerStates": [
{
"name": "a collection of 2 addresses"
}
]
},
{
"description": "a request to the address resource",
"request": {
"method": "GET",
"path": "/addresses/1"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/hal+json"
},
"body": {
"street": "Elm Street",
"_links": {
"self": {
"href": "http://localhost:8080/addresses/1"
},
"address": {
"href": "http://localhost:8080/addresses/1"
},
"customer": {
"href": "http://localhost:8080/addresses/1/customer"
}
}
}
},
"providerStates": [
{
"name": "a single address"
}
]
}
],
"metadata": {
"pact-specification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "3.5.2"
}
}
}

View File

@@ -18,3 +18,13 @@ a consumer against the Pact.
Run `npm install` to load the needed javascript libraries and then `npm run test` to
run the tests. After the tests have successfully run the created pact file will be
created in the folder `pacts`.
Then, you can call `npm run publish-pacts` to publish the pact files to a [Pact Broker](https://github.com/pact-foundation/pact_broker).
You must set the following npm configs for the `publish-pacts` script to work:
```
npm config set angular-pact:brokerUrl <URL>
npm config set angular-pact:brokerUsername <USER>
npm config set angular-pact:brokerPassword <PASS>
```

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,8 @@
"build": "ng build",
"test": "cross-env LOGLEVEL=DEBUG ng test",
"lint": "ng lint",
"e2e": "ng e2e"
"e2e": "ng e2e",
"publish-pacts": "node publish-pacts.js"
},
"private": true,
"dependencies": {
@@ -45,9 +46,9 @@
"ts-node": "~3.2.0",
"tslint": "~5.7.0",
"typescript": "~2.3.3",
"@pact-foundation/pact-node": "~4.12",
"@pact-foundation/karma-pact": "~2.1.0",
"pact-web": "~3.0",
"@pact-foundation/pact-node": "6.5.0",
"@pact-foundation/karma-pact": "2.1.3",
"@pact-foundation/pact-web": "5.3.0",
"cross-env": "^5.0.5"
}
}

View File

@@ -0,0 +1,78 @@
{
"consumer": {
"name": "ui"
},
"provider": {
"name": "userservice"
},
"interactions": [
{
"description": "a request to POST a person",
"providerState": "provider accepts a new person",
"request": {
"method": "POST",
"path": "/user-service/users",
"headers": {
"Content-Type": "application/json"
},
"body": {
"firstName": "Arthur",
"lastName": "Dent"
}
},
"response": {
"status": 201,
"headers": {
"Content-Type": "application/json"
},
"body": {
"id": 42
},
"matchingRules": {
"$.body": {
"match": "type"
}
}
}
},
{
"description": "a request to PUT a person",
"providerState": "person 42 exists",
"request": {
"method": "PUT",
"path": "/user-service/users/42",
"headers": {
"Content-Type": "application/json"
},
"body": {
"firstName": "Zaphod",
"lastName": "Beeblebrox"
},
"matchingRules": {
"$.body": {
"match": "type"
}
}
},
"response": {
"status": 200,
"headers": {
},
"body": {
"firstName": "Zaphod",
"lastName": "Beeblebrox"
},
"matchingRules": {
"$.body": {
"match": "type"
}
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "2.0.0"
}
}
}

View File

@@ -0,0 +1,20 @@
let projectFolder = __dirname;
let pact = require('@pact-foundation/pact-node');
let project = require('./package.json');
let pactBrokerUrl = process.env.npm_package_config_brokerUrl;
let pactBrokerUsername = process.env.npm_package_config_brokerUsername;
let pactBrokerPassword = process.env.npm_package_config_brokerPassword;
let options = {
pactFilesOrDirs: [projectFolder + '/pacts'],
pactBroker: pactBrokerUrl,
consumerVersion: project.version,
tags: ['latest'],
pactBrokerUsername: pactBrokerUsername,
pactBrokerPassword: pactBrokerPassword
};
pact.publishPacts(options).then(function () {
console.log("Pacts successfully published!");
});

View File

@@ -2,20 +2,18 @@ import {TestBed} from '@angular/core/testing';
import {HttpClientModule} from '@angular/common/http';
import {UserService} from './user.service';
import {User} from './user';
import * as Pact from 'pact-web';
import {PactWeb, Matchers} from '@pact-foundation/pact-web';
describe('UserService', () => {
let provider;
beforeAll(function (done) {
provider = Pact({
provider = new PactWeb({
consumer: 'ui',
provider: 'userservice',
web: true,
port: 1234,
host: '127.0.0.1',
logLevel: 'DEBUG'
});
// required for slower CI environments
@@ -72,7 +70,7 @@ describe('UserService', () => {
},
willRespondWith: {
status: 201,
body: Pact.Matchers.somethingLike({
body: Matchers.somethingLike({
id: createdUserId
}),
headers: {
@@ -94,4 +92,41 @@ describe('UserService', () => {
});
describe('update()', () => {
const expectedUser: User = {
firstName: 'Zaphod',
lastName: 'Beeblebrox'
};
beforeAll((done) => {
provider.addInteraction({
state: `person 42 exists`,
uponReceiving: 'a request to PUT a person',
withRequest: {
method: 'PUT',
path: '/user-service/users/42',
body: Matchers.somethingLike(expectedUser),
headers: {
'Content-Type': 'application/json'
}
},
willRespondWith: {
status: 200,
body: Matchers.somethingLike(expectedUser)
}
}).then(done, error => done.fail(error));
});
it('should update a Person', (done) => {
const userService: UserService = TestBed.get(UserService);
userService.update(expectedUser, 42).subscribe(response => {
done();
}, error => {
done.fail(error);
});
});
});
});

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

25
pact-spring-provider/.gitignore vendored Normal file
View File

@@ -0,0 +1,25 @@
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

View File

@@ -0,0 +1,15 @@
# Consumer-Driven-Contract Test for a Spring Boot Provider
This repo contains an example of consumer-driven-contract testing for a Spring
Boot API provider. The corresponding consumer to the contract is
implemented in the module `pact-angular`.
The contract is created and verified with [Pact](https://docs.pact.io/).
Before running the build, you need to follow the instructions on the [consumer-side](../pact-angular/)
to create the consumer-driven contract file (pact file).
## Running the application
The interesting part in this code base is the class `UserControllerProviderTest`.
You can run the tests with `gradlew test` on Windows or `./gradlew test` on Unix.

View File

@@ -0,0 +1,36 @@
buildscript {
ext {
springBootVersion = '1.5.4.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-web')
compile('com.h2database:h2:1.4.196')
testCompile('au.com.dius:pact-jvm-provider-spring_2.12:3.5.11')
testCompile('junit:junit:4.12')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
bootRun {
jvmArgs = ["-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"]
}

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

172
pact-spring-provider/gradlew vendored Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## 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
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
pact-spring-provider/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@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
: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=%*
: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,14 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@SpringBootApplication
@EnableWebMvc
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@@ -0,0 +1,15 @@
package com.example.demo;
public class IdObject {
private final long id;
public IdObject(long id) {
this.id = id;
}
public long getId() {
return id;
}
}

View File

@@ -0,0 +1,52 @@
package com.example.demo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
@Column
@NotNull
private String firstName;
@Column
@NotNull
private String lastName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void updateFrom(User user){
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
}
}

View File

@@ -0,0 +1,42 @@
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
public class UserController {
private UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@PostMapping(path = "/user-service/users")
public ResponseEntity<IdObject> createUser(@RequestBody @Valid User user) {
User savedUser = this.userRepository.save(user);
return ResponseEntity
.status(201)
.body(new IdObject(savedUser.getId()));
}
@PutMapping(path = "/user-service/users/{id}")
public ResponseEntity<User> updateUser(@RequestBody @Valid User user, @PathVariable long id) {
User userFromDb = userRepository.findOne(id);
userFromDb.updateFrom(user);
userFromDb = userRepository.save(userFromDb);
return ResponseEntity.ok(userFromDb);
}
@GetMapping(path = "/user-service/users/{id}")
public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
return ResponseEntity.ok(userRepository.findOne(id));
}
}

View File

@@ -0,0 +1,6 @@
package com.example.demo;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long>{
}

View File

@@ -0,0 +1,7 @@
spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
logging.level.org.hibernate.SQL=OFF

View File

@@ -0,0 +1,42 @@
package com.example.demo;
import au.com.dius.pact.provider.junit.Provider;
import au.com.dius.pact.provider.junit.State;
import au.com.dius.pact.provider.junit.loader.PactFolder;
import au.com.dius.pact.provider.junit.target.HttpTarget;
import au.com.dius.pact.provider.junit.target.Target;
import au.com.dius.pact.provider.junit.target.TestTarget;
import au.com.dius.pact.provider.spring.SpringRestPactRunner;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.when;
@RunWith(SpringRestPactRunner.class)
@Provider("userservice")
@PactFolder("../pact-angular/pacts")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {
"server.port=8080"
})
public class UserControllerProviderTest {
@MockBean
private UserRepository userRepository;
@TestTarget
public final Target target = new HttpTarget(8080);
@State({"provider accepts a new person",
"person 42 exists"})
public void toCreatePersonState() {
User user = new User();
user.setId(42L);
user.setFirstName("Arthur");
user.setLastName("Dent");
when(userRepository.findOne(eq(42L))).thenReturn(user);
when(userRepository.save(any(User.class))).thenReturn(user);
}
}

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

View File

@@ -1,11 +1,9 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableAutoConfiguration
public class EventingApplication {
public static void main(String[] args) {

View File

@@ -5,7 +5,16 @@ include 'spring-data-rest-springfox'
// pact-feign-consumer must run before pact-spring-data-rest-provider because it creates a shared pact file
include 'pact-feign-consumer'
include 'pact-spring-data-rest-provider'
include 'pact-spring-provider'
include 'spring-cloud-contract-provider'
include 'sleuth-downstream-service'
include 'sleuth-upstream-service'
include 'rabbitmq-event-brokering'
include 'junit5'
include 'spring-boot-tests'

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

View File

@@ -0,0 +1,41 @@
buildscript {
repositories {
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:${springboot_version}"
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${verifier_version}"
classpath "org.springframework.cloud:spring-cloud-contract-spec-pact:${verifier_version}"
classpath 'au.com.dius:pact-jvm-model:2.4.18'
}
}
apply plugin: 'groovy'
apply plugin: 'spring-cloud-contract'
repositories {
mavenCentral()
jcenter()
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.boot:spring-boot-starter-data-jpa:${springboot_version}")
compile("org.springframework.boot:spring-boot-starter-web:${springboot_version}")
compile('com.h2database:h2:1.4.196')
testCompile('org.codehaus.groovy:groovy-all:2.4.6')
testCompile("org.springframework.cloud:spring-cloud-starter-contract-verifier:${verifier_version}")
testCompile("org.springframework.cloud:spring-cloud-contract-spec:${verifier_version}")
testCompile("org.springframework.boot:spring-boot-starter-test:${springboot_version}")
}
contracts {
baseClassMappings {
baseClassMapping(".*userservice.*", "io.reflectoring.UserServiceBase")
}
}

View File

@@ -0,0 +1,2 @@
springboot_version=1.5.9.RELEASE
verifier_version=1.2.2.BUILD-SNAPSHOT

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip

172
spring-cloud-contract-provider/gradlew vendored Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## 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
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View File

@@ -0,0 +1,84 @@
@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
: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=%*
: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,16 @@
package io.reflectoring;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@SpringBootApplication
@EnableWebMvc
@EnableSpringDataWebSupport
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@@ -0,0 +1,15 @@
package io.reflectoring;
public class IdObject {
private final long id;
public IdObject(long id) {
this.id = id;
}
public long getId() {
return id;
}
}

View File

@@ -0,0 +1,52 @@
package io.reflectoring;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
@Column
@NotNull
private String firstName;
@Column
@NotNull
private String lastName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void updateFrom(User user){
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
}
}

View File

@@ -0,0 +1,41 @@
package io.reflectoring;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
private UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@PostMapping(path = "/user-service/users")
public ResponseEntity<IdObject> createUser(@RequestBody @Valid User user) {
User savedUser = this.userRepository.save(user);
return ResponseEntity
.status(201)
.body(new IdObject(savedUser.getId()));
}
@PutMapping(path = "/user-service/users/{id}")
public ResponseEntity<User> updateUser(@RequestBody @Valid User user, @PathVariable long id) {
User userFromDb = userRepository.findOne(id);
userFromDb.updateFrom(user);
userFromDb = userRepository.save(userFromDb);
return ResponseEntity.ok(userFromDb);
}
@GetMapping(path = "/user-service/users/{id}")
public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
return ResponseEntity.ok(userRepository.findOne(id));
}
}

View File

@@ -0,0 +1,6 @@
package io.reflectoring;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long>{
}

View File

@@ -0,0 +1,41 @@
package io.reflectoring;
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.any;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public abstract class UserServiceBase {
@Autowired
WebApplicationContext webApplicationContext;
@MockBean
private UserRepository userRepository;
@Before
public void setup() {
User savedUser = new User();
savedUser.setFirstName("Arthur");
savedUser.setLastName("Dent");
savedUser.setId(42L);
when(userRepository.save(any(User.class))).thenReturn(savedUser);
RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
when(userRepository.findOne(eq(42L))).thenReturn(savedUser);
}
}

View File

@@ -0,0 +1,27 @@
package userservice
import org.springframework.cloud.contract.spec.Contract
Contract.make {
description("When a POST request with a User is made, the created user's ID is returned")
request {
method 'POST'
url '/user-service/users'
body(
firstName: "Arthur",
lastName: "Dent"
)
headers {
contentType(applicationJson())
}
}
response {
status 201
body(
id: 42
)
headers {
contentType(applicationJson())
}
}
}

View File

@@ -0,0 +1,27 @@
package userservice
import org.springframework.cloud.contract.spec.Contract
Contract.make {
description("When a PUT request with a User is made, the updated user's ID is returned")
request {
method 'PUT'
url '/user-service/users/42'
body(
firstName: "Arthur",
lastName: "Dent"
)
headers {
contentType(applicationJson())
}
}
response {
status 200
body(
id: 42
)
headers {
contentType(applicationJson())
}
}
}

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip