Compare commits
12 Commits
logging-fo
...
pact-messa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a18ad84da2 | ||
|
|
5e93dcb84b | ||
|
|
3b0eb77b5d | ||
|
|
a9c9faba1d | ||
|
|
8672d163e2 | ||
|
|
3eefd80192 | ||
|
|
5a36a2365e | ||
|
|
5f675f91a8 | ||
|
|
3559378d1a | ||
|
|
b72ab0d580 | ||
|
|
ed45066496 | ||
|
|
ddb3e08ee5 |
@@ -1,27 +0,0 @@
|
||||
package io.reflectoring.logging;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import ch.qos.logback.classic.pattern.LoggerConverter;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
|
||||
public class TruncatedLoggerConverter extends LoggerConverter {
|
||||
|
||||
@Override
|
||||
public String convert(ILoggingEvent event) {
|
||||
String maxLengthString = getFirstOption();
|
||||
int maxLength = Integer.parseInt(maxLengthString);
|
||||
String loggerName = super.convert(event);
|
||||
if (loggerName.length() <= maxLength) {
|
||||
return loggerName + generateSpaces(maxLength - loggerName.length());
|
||||
} else {
|
||||
return "..." + loggerName.substring(loggerName.length() - maxLength + 3);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateSpaces(int count) {
|
||||
return Stream.generate(() -> " ").limit(count).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package io.reflectoring.logging;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import ch.qos.logback.classic.pattern.ClassicConverter;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
|
||||
public class TruncatedThreadConverter extends ClassicConverter {
|
||||
|
||||
@Override
|
||||
public String convert(ILoggingEvent event) {
|
||||
String maxLengthString = getFirstOption();
|
||||
int maxLength = Integer.parseInt(maxLengthString);
|
||||
String threadName = event.getThreadName();
|
||||
|
||||
if (threadName.length() <= maxLength) {
|
||||
return threadName + generateSpaces(maxLength - threadName.length());
|
||||
} else {
|
||||
return "..." + threadName.substring(threadName.length() - maxLength + 3);
|
||||
}
|
||||
}
|
||||
|
||||
private String generateSpaces(int count) {
|
||||
return Stream.generate(() -> " ").limit(count).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
<!-- Appender to log to console -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %truncatedThread{20} | %5p | %truncatedLogger{25} | %12(ID: %8mdc{id}) | %m%n</pattern>
|
||||
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %5p | %-25.25logger{25} | %12(ID: %8mdc{id}) | %m%n</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@@ -10,18 +8,43 @@ buildscript {
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "au.com.dius.pact" version "3.5.20"
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
version '1.0.0.SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springcloud_version}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("org.springframework.boot:spring-boot-starter-data-jpa:${springboot_version}")
|
||||
compile("org.springframework.boot:spring-boot-starter-web:${springboot_version}")
|
||||
compile("org.springframework.cloud:spring-cloud-starter-feign:1.4.1.RELEASE")
|
||||
compile('org.springframework.boot:spring-boot-starter-data-jpa')
|
||||
compile('org.springframework.boot:spring-boot-starter-web')
|
||||
compile('org.springframework.cloud:spring-cloud-starter-openfeign')
|
||||
compile('org.springframework.cloud:spring-cloud-starter-netflix-ribbon')
|
||||
compile('com.h2database:h2:1.4.196')
|
||||
testCompile('org.codehaus.groovy:groovy-all:2.4.6')
|
||||
testCompile("au.com.dius:pact-jvm-consumer-junit_2.11:3.5.2")
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test:${springboot_version}")
|
||||
testCompile("au.com.dius:pact-jvm-consumer-junit5_2.12:${pact_version}")
|
||||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||||
}
|
||||
|
||||
pact {
|
||||
publish {
|
||||
pactDirectory = 'target/pacts'
|
||||
pactBrokerUrl = 'URL'
|
||||
pactBrokerUsername = 'USERNAME'
|
||||
pactBrokerPassword = 'PASSWORD'
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
springboot_version=1.5.9.RELEASE
|
||||
verifier_version=1.2.2.RELEASE
|
||||
springboot_version=2.0.4.RELEASE
|
||||
springcloud_version=Finchley.SR1
|
||||
pact_version=3.5.20
|
||||
@@ -2,10 +2,12 @@ package io.reflectoring;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.feign.EnableFeignClients;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
@RibbonClient(name = "userservice", configuration = RibbonConfiguration.class)
|
||||
public class ConsumerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.IRule;
|
||||
import com.netflix.loadbalancer.RandomRule;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
public class RibbonConfiguration {
|
||||
|
||||
@Bean
|
||||
public IRule ribbonRule(IClientConfig config) {
|
||||
return new RandomRule();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@@ -1,83 +1,85 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import au.com.dius.pact.consumer.Pact;
|
||||
import au.com.dius.pact.consumer.PactProviderRuleMk2;
|
||||
import au.com.dius.pact.consumer.PactVerification;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
|
||||
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt;
|
||||
import au.com.dius.pact.consumer.junit5.PactTestFor;
|
||||
import au.com.dius.pact.model.RequestResponsePact;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties = {
|
||||
// overriding provider address
|
||||
"userservice.ribbon.listOfServers: localhost:8888"
|
||||
@ExtendWith(PactConsumerTestExt.class)
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@PactTestFor(providerName = "userservice", port = "8888")
|
||||
@SpringBootTest({
|
||||
// overriding provider address
|
||||
"userservice.ribbon.listOfServers: localhost:8888"
|
||||
})
|
||||
public class UserServiceConsumerTest {
|
||||
class UserServiceConsumerTest {
|
||||
|
||||
@Rule
|
||||
public PactProviderRuleMk2 stubProvider = new PactProviderRuleMk2("userservice", "localhost", 8888, this);
|
||||
@Autowired
|
||||
private UserClient userClient;
|
||||
|
||||
@Autowired
|
||||
private UserClient userClient;
|
||||
@Pact(state = "provider accepts a new person", provider = "userservice", consumer = "userclient")
|
||||
RequestResponsePact createPersonPact(PactDslWithProvider builder) {
|
||||
// @formatter:off
|
||||
return builder
|
||||
.given("provider accepts a new person")
|
||||
.uponReceiving("a request to POST a person")
|
||||
.path("/user-service/users")
|
||||
.method("POST")
|
||||
.willRespondWith()
|
||||
.status(201)
|
||||
.matchHeader("Content-Type", "application/json")
|
||||
.body(new PactDslJsonBody()
|
||||
.integerType("id", 42))
|
||||
.toPact();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Pact(state = "provider accepts a new person", provider = "userservice", consumer = "userclient")
|
||||
public RequestResponsePact createPersonPact(PactDslWithProvider builder) {
|
||||
return builder
|
||||
.given("provider accepts a new person")
|
||||
.uponReceiving("a request to POST a person")
|
||||
.path("/user-service/users")
|
||||
.method("POST")
|
||||
.willRespondWith()
|
||||
.status(201)
|
||||
.matchHeader("Content-Type", "application/json")
|
||||
.body(new PactDslJsonBody()
|
||||
.integerType("id", 42))
|
||||
.toPact();
|
||||
}
|
||||
|
||||
@Pact(state = "person 42 exists", provider = "userservice", consumer = "userclient")
|
||||
public RequestResponsePact updatePersonPact(PactDslWithProvider builder) {
|
||||
return builder
|
||||
.given("person 42 exists")
|
||||
.uponReceiving("a request to PUT a person")
|
||||
.path("/user-service/users/42")
|
||||
.method("PUT")
|
||||
.willRespondWith()
|
||||
.status(200)
|
||||
.matchHeader("Content-Type", "application/json")
|
||||
.body(new PactDslJsonBody()
|
||||
.stringType("firstName", "Zaphod")
|
||||
.stringType("lastName", "Beeblebrox"))
|
||||
.toPact();
|
||||
}
|
||||
@Pact(state = "person 42 exists", provider = "userservice", consumer = "userclient")
|
||||
RequestResponsePact updatePersonPact(PactDslWithProvider builder) {
|
||||
// @formatter:off
|
||||
return builder
|
||||
.given("person 42 exists")
|
||||
.uponReceiving("a request to PUT a person")
|
||||
.path("/user-service/users/42")
|
||||
.method("PUT")
|
||||
.willRespondWith()
|
||||
.status(200)
|
||||
.matchHeader("Content-Type", "application/json")
|
||||
.body(new PactDslJsonBody()
|
||||
.stringType("firstName", "Zaphod")
|
||||
.stringType("lastName", "Beeblebrox"))
|
||||
.toPact();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@PactVerification(fragment = "createPersonPact")
|
||||
public void verifyCreatePersonPact() {
|
||||
User user = new User();
|
||||
user.setFirstName("Zaphod");
|
||||
user.setLastName("Beeblebrox");
|
||||
IdObject id = userClient.createUser(user);
|
||||
assertThat(id.getId()).isEqualTo(42);
|
||||
}
|
||||
@Test
|
||||
@PactTestFor(pactMethod = "createPersonPact")
|
||||
void verifyCreatePersonPact() {
|
||||
User user = new User();
|
||||
user.setFirstName("Zaphod");
|
||||
user.setLastName("Beeblebrox");
|
||||
IdObject id = userClient.createUser(user);
|
||||
assertThat(id.getId()).isEqualTo(42);
|
||||
}
|
||||
|
||||
@Test
|
||||
@PactVerification(fragment = "updatePersonPact")
|
||||
public void verifyUpdatePersonPact() {
|
||||
User user = new User();
|
||||
user.setFirstName("Zaphod");
|
||||
user.setLastName("Beeblebrox");
|
||||
User updatedUser = userClient.updateUser(42L, user);
|
||||
assertThat(updatedUser.getFirstName()).isEqualTo("Zaphod");
|
||||
assertThat(updatedUser.getLastName()).isEqualTo("Beeblebrox");
|
||||
}
|
||||
@Test
|
||||
@PactTestFor(pactMethod = "updatePersonPact")
|
||||
void verifyUpdatePersonPact() {
|
||||
User user = new User();
|
||||
user.setFirstName("Zaphod");
|
||||
user.setLastName("Beeblebrox");
|
||||
User updatedUser = userClient.updateUser(42L, user);
|
||||
assertThat(updatedUser.getFirstName()).isEqualTo("Zaphod");
|
||||
assertThat(updatedUser.getLastName()).isEqualTo("Beeblebrox");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"provider": {
|
||||
"name": "userservice"
|
||||
},
|
||||
"consumer": {
|
||||
"name": "userclient"
|
||||
},
|
||||
"interactions": [
|
||||
{
|
||||
"description": "a request to PUT a person",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"path": "/user-service/users/42"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"firstName": "Zaphod",
|
||||
"lastName": "Beeblebrox"
|
||||
},
|
||||
"matchingRules": {
|
||||
"body": {
|
||||
"$.firstName": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.lastName": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"Content-Type": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "regex",
|
||||
"regex": "application/json"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"providerStates": [
|
||||
{
|
||||
"name": "person 42 exists"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "a request to POST a person",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"path": "/user-service/users"
|
||||
},
|
||||
"response": {
|
||||
"status": 201,
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"id": 42
|
||||
},
|
||||
"matchingRules": {
|
||||
"header": {
|
||||
"Content-Type": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "regex",
|
||||
"regex": "application/json"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"$.id": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "integer"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"providerStates": [
|
||||
{
|
||||
"name": "provider accepts a new person"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"pactSpecification": {
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"pact-jvm": {
|
||||
"version": "3.5.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
25
pact/pact-message-consumer/.gitignore
vendored
Normal file
25
pact/pact-message-consumer/.gitignore
vendored
Normal 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/
|
||||
15
pact/pact-message-consumer/README.md
Normal file
15
pact/pact-message-consumer/README.md
Normal 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.
|
||||
11
pact/pact-message-consumer/application.yml
Normal file
11
pact/pact-message-consumer/application.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
driverClassName: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
|
||||
logging.level.org.hibernate.SQL: OFF
|
||||
36
pact/pact-message-consumer/build.gradle
Normal file
36
pact/pact-message-consumer/build.gradle
Normal file
@@ -0,0 +1,36 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
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('org.springframework.boot:spring-boot-starter-amqp')
|
||||
compile('com.h2database:h2:1.4.196')
|
||||
compileOnly('org.projectlombok:lombok')
|
||||
testCompile("au.com.dius:pact-jvm-consumer-junit_2.12:${pact_version}")
|
||||
testCompile("au.com.dius:pact-jvm-consumer-groovy_2.12:${pact_version}")
|
||||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||||
}
|
||||
|
||||
bootRun {
|
||||
jvmArgs = ["-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"]
|
||||
}
|
||||
2
pact/pact-message-consumer/gradle.properties
Normal file
2
pact/pact-message-consumer/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
springboot_version=2.0.4.RELEASE
|
||||
pact_version=3.5.20
|
||||
BIN
pact/pact-message-consumer/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
pact/pact-message-consumer/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
pact/pact-message-consumer/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
pact/pact-message-consumer/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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/pact-message-consumer/gradlew
vendored
Normal file
172
pact/pact-message-consumer/gradlew
vendored
Normal 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/pact-message-consumer/gradlew.bat
vendored
Normal file
84
pact/pact-message-consumer/gradlew.bat
vendored
Normal 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
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableRabbit
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.amqp.core.Binding;
|
||||
import org.springframework.amqp.core.BindingBuilder;
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class MessageConsumerConfiguration {
|
||||
|
||||
private static final String QUEUE_NAME = "myQueue";
|
||||
|
||||
private static final String EXCHANGE_NAME = "myExchange";
|
||||
|
||||
@Bean
|
||||
public TopicExchange receiverExchange() {
|
||||
return new TopicExchange(EXCHANGE_NAME);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Queue queue() {
|
||||
return new Queue(QUEUE_NAME);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Binding binding(Queue eventReceivingQueue, TopicExchange receiverExchange) {
|
||||
return BindingBuilder
|
||||
.bind(eventReceivingQueue)
|
||||
.to(receiverExchange)
|
||||
.with("*.*");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
|
||||
MessageListenerAdapter listenerAdapter) {
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
|
||||
container.setConnectionFactory(connectionFactory);
|
||||
container.setQueueNames(QUEUE_NAME);
|
||||
container.setMessageListener(listenerAdapter);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageListenerAdapter listenerAdapter(UserCreatedMessageConsumer userCreatedMessageConsumer) {
|
||||
return new MessageListenerAdapter(userCreatedMessageConsumer, "consumeStringMessage");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserCreatedMessageConsumer eventReceiver(ObjectMapper objectMapper) {
|
||||
return new UserCreatedMessageConsumer(objectMapper);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class User {
|
||||
|
||||
@NotNull
|
||||
private long id;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserCreatedMessage {
|
||||
|
||||
@NotNull
|
||||
private String messageUuid;
|
||||
|
||||
@NotNull
|
||||
private User user;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.reflectoring;
|
||||
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class UserCreatedMessageConsumer {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(UserCreatedMessageConsumer.class);
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
public UserCreatedMessageConsumer(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public void consumeStringMessage(String messageString) throws IOException {
|
||||
logger.info("Consuming message '{}'", messageString);
|
||||
UserCreatedMessage message = objectMapper.readValue(messageString, UserCreatedMessage.class);
|
||||
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
Set<ConstraintViolation<UserCreatedMessage>> violations = validator.validate(message);
|
||||
if(!violations.isEmpty()){
|
||||
throw new ConstraintViolationException(violations);
|
||||
}
|
||||
// pass message into business use case
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import au.com.dius.pact.consumer.MessagePactBuilder;
|
||||
import au.com.dius.pact.consumer.MessagePactProviderRule;
|
||||
import au.com.dius.pact.consumer.Pact;
|
||||
import au.com.dius.pact.consumer.PactVerification;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
|
||||
import au.com.dius.pact.model.v3.messaging.MessagePact;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class UserCreatedMessageConsumerTest {
|
||||
|
||||
@Rule
|
||||
public MessagePactProviderRule mockProvider = new MessagePactProviderRule(this);
|
||||
private byte[] currentMessage;
|
||||
|
||||
@Autowired
|
||||
private UserCreatedMessageConsumer userCreatedMessageConsumer;
|
||||
|
||||
@Pact(provider = "userservice", consumer = "userclient")
|
||||
public MessagePact userCreatedMessagePact(MessagePactBuilder builder) {
|
||||
PactDslJsonBody body = new PactDslJsonBody();
|
||||
body.stringType("messageUuid");
|
||||
body.object("user")
|
||||
.numberType("id", 42L)
|
||||
.stringType("name", "Zaphod Beeblebrox")
|
||||
.closeObject();
|
||||
|
||||
// @formatter:off
|
||||
return builder
|
||||
.expectsToReceive("a user created message")
|
||||
.withContent(body)
|
||||
.toPact();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
@PactVerification("userCreatedMessagePact")
|
||||
public void verifyCreatePersonPact() throws IOException {
|
||||
userCreatedMessageConsumer.consumeStringMessage(new String(this.currentMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by the Pact framework.
|
||||
*/
|
||||
public void setMessage(byte[] message) {
|
||||
this.currentMessage = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"consumer": {
|
||||
"name": "userclient"
|
||||
},
|
||||
"provider": {
|
||||
"name": "userservice"
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"description": "a user created message",
|
||||
"metaData": {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
"contents": {
|
||||
"messageUuid": "string",
|
||||
"user": {
|
||||
"name": "Zaphod Beeblebrox",
|
||||
"id": 42
|
||||
}
|
||||
},
|
||||
"matchingRules": {
|
||||
"body": {
|
||||
"$.messageUuid": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.user.id": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "number"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.user.name": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"pactSpecification": {
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"pact-jvm": {
|
||||
"version": "3.5.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
25
pact/pact-message-provider/.gitignore
vendored
Normal file
25
pact/pact-message-provider/.gitignore
vendored
Normal 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/
|
||||
15
pact/pact-message-provider/README.md
Normal file
15
pact/pact-message-provider/README.md
Normal 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.
|
||||
11
pact/pact-message-provider/application.yml
Normal file
11
pact/pact-message-provider/application.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
|
||||
driverClassName: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
|
||||
logging.level.org.hibernate.SQL: OFF
|
||||
35
pact/pact-message-provider/build.gradle
Normal file
35
pact/pact-message-provider/build.gradle
Normal file
@@ -0,0 +1,35 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
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('org.springframework.boot:spring-boot-starter-amqp')
|
||||
compile('com.h2database:h2:1.4.196')
|
||||
compileOnly('org.projectlombok:lombok')
|
||||
testCompile("au.com.dius:pact-jvm-provider-junit_2.12:${pact_version}")
|
||||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||||
}
|
||||
|
||||
bootRun {
|
||||
jvmArgs = ["-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"]
|
||||
}
|
||||
2
pact/pact-message-provider/gradle.properties
Normal file
2
pact/pact-message-provider/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
springboot_version=2.0.4.RELEASE
|
||||
pact_version=3.5.20
|
||||
BIN
pact/pact-message-provider/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
pact/pact-message-provider/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
pact/pact-message-provider/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
pact/pact-message-provider/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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/pact-message-provider/gradlew
vendored
Normal file
172
pact/pact-message-provider/gradlew
vendored
Normal 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/pact-message-provider/gradlew.bat
vendored
Normal file
84
pact/pact-message-provider/gradlew.bat
vendored
Normal 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
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
class MessageProviderConfiguration {
|
||||
|
||||
@Bean
|
||||
TopicExchange topicExchange() {
|
||||
return new TopicExchange("myExchange");
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
UserCreatedMessageProvider messageProvider(ObjectMapper objectMapper, UserCreatedMessagePublisher publisher) {
|
||||
return new UserCreatedMessageProvider(objectMapper, publisher);
|
||||
}
|
||||
|
||||
@Bean
|
||||
UserCreatedMessagePublisher messagePublisher(RabbitTemplate rabbitTemplate, TopicExchange topicExchange) {
|
||||
return new UserCreatedMessagePublisher(rabbitTemplate, topicExchange);
|
||||
}
|
||||
|
||||
@Bean
|
||||
SendMessageJob job(UserCreatedMessageProvider messageProvider) {
|
||||
return new SendMessageJob(messageProvider);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
class SendMessageJob {
|
||||
|
||||
private Random random = new Random();
|
||||
|
||||
private UserCreatedMessageProvider messageProvider;
|
||||
|
||||
SendMessageJob(UserCreatedMessageProvider messageProvider) {
|
||||
this.messageProvider = messageProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* This scheduled job simulates the "real" business logic that should produce messages.
|
||||
*/
|
||||
@Scheduled(fixedDelay = 1000)
|
||||
void sendUserCreatedMessage() {
|
||||
try {
|
||||
UserCreatedMessage userCreatedMessage = UserCreatedMessage.builder()
|
||||
.messageUuid(UUID.randomUUID().toString())
|
||||
.user(User.builder()
|
||||
.id(random.nextLong())
|
||||
.name("Zaphpod Beeblebrox")
|
||||
.build())
|
||||
.build();
|
||||
messageProvider.sendUserCreatedMessage(userCreatedMessage);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
class User {
|
||||
|
||||
@NotNull
|
||||
private long id;
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
class UserCreatedMessage {
|
||||
|
||||
@NotNull
|
||||
private String messageUuid;
|
||||
|
||||
@NotNull
|
||||
private User user;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Takes a {@link UserCreatedMessage}, converts it to a {@link String} and sends it to be published.
|
||||
*/
|
||||
class UserCreatedMessageProvider {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(UserCreatedMessageProvider.class);
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
private UserCreatedMessagePublisher userCreatedMessagePublisher;
|
||||
|
||||
UserCreatedMessageProvider(ObjectMapper objectMapper, UserCreatedMessagePublisher userCreatedMessagePublisher) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.userCreatedMessagePublisher = userCreatedMessagePublisher;
|
||||
}
|
||||
|
||||
void sendUserCreatedMessage(UserCreatedMessage message) throws IOException {
|
||||
String stringMessage = objectMapper.writeValueAsString(message);
|
||||
userCreatedMessagePublisher.publishMessage(stringMessage, "user.created");
|
||||
logger.info("Published message '{}'", stringMessage);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
|
||||
/**
|
||||
* Publishes a String message to RabbitMQ.
|
||||
*/
|
||||
class UserCreatedMessagePublisher {
|
||||
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
private TopicExchange topicExchange;
|
||||
|
||||
UserCreatedMessagePublisher(RabbitTemplate rabbitTemplate, TopicExchange topicExchange) {
|
||||
this.rabbitTemplate = rabbitTemplate;
|
||||
this.topicExchange = topicExchange;
|
||||
}
|
||||
|
||||
void publishMessage(String message, String routingKey) {
|
||||
rabbitTemplate.convertAndSend(topicExchange.getName(), routingKey, message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import au.com.dius.pact.model.Interaction;
|
||||
import au.com.dius.pact.model.ProviderState;
|
||||
import au.com.dius.pact.provider.ConsumerInfo;
|
||||
import au.com.dius.pact.provider.ProviderInfo;
|
||||
import au.com.dius.pact.provider.ProviderVerifier;
|
||||
import au.com.dius.pact.provider.junit.target.AmqpTarget;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CustomAmqpTarget extends AmqpTarget {
|
||||
|
||||
public CustomAmqpTarget(List<String> packagesToScan) {
|
||||
super(packagesToScan);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected ProviderVerifier setupVerifier(Interaction interaction, ProviderInfo provider, ConsumerInfo consumer) {
|
||||
ProviderVerifier verifier = new CustomProviderVerifier(getPackagesToScan());
|
||||
setupReporters(verifier, provider.getName(), interaction.getDescription());
|
||||
verifier.initialiseReporters(provider);
|
||||
verifier.reportVerificationForConsumer(consumer, provider);
|
||||
|
||||
if (!interaction.getProviderStates().isEmpty()) {
|
||||
for (ProviderState state : interaction.getProviderStates()) {
|
||||
verifier.reportStateForInteraction(state.getName(), provider, consumer, true);
|
||||
}
|
||||
}
|
||||
verifier.reportInteractionDescription(interaction);
|
||||
return verifier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import au.com.dius.pact.model.Interaction;
|
||||
import au.com.dius.pact.model.v3.messaging.Message;
|
||||
import au.com.dius.pact.provider.ConsumerInfo;
|
||||
import au.com.dius.pact.provider.PactVerifyProvider;
|
||||
import au.com.dius.pact.provider.ProviderInfo;
|
||||
import au.com.dius.pact.provider.ProviderVerifier;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.MethodAnnotationsScanner;
|
||||
import org.reflections.util.ConfigurationBuilder;
|
||||
|
||||
public class CustomProviderVerifier extends ProviderVerifier {
|
||||
|
||||
private List<String> packagesToScan;
|
||||
|
||||
public CustomProviderVerifier(List<String> packagesToScan) {
|
||||
this.packagesToScan = packagesToScan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyResponseByInvokingProviderMethods(ProviderInfo providerInfo, ConsumerInfo consumer,
|
||||
Object interaction, String interactionMessage, Map failures) {
|
||||
try {
|
||||
|
||||
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
|
||||
.setScanners(new MethodAnnotationsScanner())
|
||||
.forPackages(packagesToScan.toArray(new String[]{}));
|
||||
|
||||
Reflections reflections = new Reflections(configurationBuilder);
|
||||
Set<Method> methodsAnnotatedWith = reflections.getMethodsAnnotatedWith(PactVerifyProvider.class);
|
||||
Set<Method> providerMethods = methodsAnnotatedWith.stream()
|
||||
.filter(m -> {
|
||||
PactVerifyProvider annotation = m.getAnnotation(PactVerifyProvider.class);
|
||||
return annotation.value().equals(((Interaction)interaction).getDescription());
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (providerMethods.isEmpty()) {
|
||||
throw new RuntimeException("No annotated methods were found for interaction " +
|
||||
"'${interaction.description}'. You need to provide a method annotated with " +
|
||||
"@PactVerifyProvider(\"${interaction.description}\") that returns the message contents.");
|
||||
} else {
|
||||
if (interaction instanceof Message) {
|
||||
verifyMessagePact(providerMethods, (Message) interaction, interactionMessage, failures);
|
||||
} else {
|
||||
throw new RuntimeException("only supports Message interactions!");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("verification failed", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import au.com.dius.pact.provider.PactVerifyProvider;
|
||||
import au.com.dius.pact.provider.junit.PactRunner;
|
||||
import au.com.dius.pact.provider.junit.Provider;
|
||||
import au.com.dius.pact.provider.junit.loader.PactFolder;
|
||||
import au.com.dius.pact.provider.junit.target.AmqpTarget;
|
||||
import au.com.dius.pact.provider.junit.target.Target;
|
||||
import au.com.dius.pact.provider.junit.target.TestTarget;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(PactRunner.class)
|
||||
@Provider("userservice")
|
||||
@PactFolder("../pact-message-consumer/target/pacts")
|
||||
public class UserCreatedMessageProviderTest {
|
||||
|
||||
@TestTarget
|
||||
public final Target target = new CustomAmqpTarget(Collections.singletonList("io.reflectoring"));
|
||||
|
||||
private UserCreatedMessagePublisher publisher = Mockito.mock(UserCreatedMessagePublisher.class);
|
||||
|
||||
private UserCreatedMessageProvider messageProvider = new UserCreatedMessageProvider(new ObjectMapper(), publisher);
|
||||
|
||||
@PactVerifyProvider("a user created message")
|
||||
public String verifyUserCreatedMessage() throws IOException {
|
||||
// given
|
||||
doNothing().when(publisher).publishMessage(any(String.class), eq("user.created"));
|
||||
|
||||
// when
|
||||
UserCreatedMessage message = UserCreatedMessage.builder()
|
||||
.messageUuid(UUID.randomUUID().toString())
|
||||
.user(User.builder()
|
||||
.id(42L)
|
||||
.name("Zaphod Beeblebrox")
|
||||
.build())
|
||||
.build();
|
||||
messageProvider.sendUserCreatedMessage(message);
|
||||
|
||||
// then
|
||||
ArgumentCaptor<String> messageCapture = ArgumentCaptor.forClass(String.class);
|
||||
verify(publisher, times(1)).publishMessage(messageCapture.capture(), eq("user.created"));
|
||||
|
||||
// returning the message
|
||||
return messageCapture.getValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"consumer": {
|
||||
"name": "userclient"
|
||||
},
|
||||
"provider": {
|
||||
"name": "userservice"
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"description": "a user created message",
|
||||
"metaData": {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
},
|
||||
"contents": {
|
||||
"messageUuid": "string",
|
||||
"user": {
|
||||
"name": "Zaphod Beeblebrox",
|
||||
"id": 42
|
||||
}
|
||||
},
|
||||
"matchingRules": {
|
||||
"body": {
|
||||
"$.messageUuid": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.user.id": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "number"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
},
|
||||
"$.user.name": {
|
||||
"matchers": [
|
||||
{
|
||||
"match": "type"
|
||||
}
|
||||
],
|
||||
"combine": "AND"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"pactSpecification": {
|
||||
"version": "3.0.0"
|
||||
},
|
||||
"pact-jvm": {
|
||||
"version": "3.5.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '1.5.4.RELEASE'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}")
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = 1.8
|
||||
@@ -26,8 +24,7 @@ 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.16')
|
||||
testCompile('junit:junit:4.12')
|
||||
testCompile("au.com.dius:pact-jvm-provider-junit5_2.12:${pact_version}")
|
||||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||||
}
|
||||
|
||||
|
||||
2
pact/pact-spring-provider/gradle.properties
Normal file
2
pact/pact-spring-provider/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
springboot_version=2.0.4.RELEASE
|
||||
pact_version=3.5.20
|
||||
@@ -26,7 +26,7 @@ public class UserController {
|
||||
|
||||
@PutMapping(path = "/user-service/users/{id}")
|
||||
public ResponseEntity<User> updateUser(@RequestBody @Valid User user, @PathVariable long id) {
|
||||
User userFromDb = userRepository.findOne(id);
|
||||
User userFromDb = userRepository.findById(id).get();
|
||||
userFromDb.updateFrom(user);
|
||||
userFromDb = userRepository.save(userFromDb);
|
||||
return ResponseEntity.ok(userFromDb);
|
||||
@@ -34,7 +34,7 @@ public class UserController {
|
||||
|
||||
@GetMapping(path = "/user-service/users/{id}")
|
||||
public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
|
||||
return ResponseEntity.ok(userRepository.findOne(id));
|
||||
return ResponseEntity.ok(userRepository.findById(id).get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
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 io.reflectoring.User;
|
||||
import io.reflectoring.UserRepository;
|
||||
import org.junit.runner.RunWith;
|
||||
import au.com.dius.pact.provider.junit5.HttpTestTarget;
|
||||
import au.com.dius.pact.provider.junit5.PactVerificationContext;
|
||||
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(SpringRestPactRunner.class)
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {
|
||||
"server.port=8080"
|
||||
})
|
||||
@Provider("userservice")
|
||||
@PactFolder("../pact-angular/pacts")
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {
|
||||
"server.port=8080"
|
||||
})
|
||||
public class UserControllerProviderTest {
|
||||
|
||||
@MockBean
|
||||
private UserRepository userRepository;
|
||||
@MockBean
|
||||
private UserRepository userRepository;
|
||||
|
||||
@TestTarget
|
||||
public final Target target = new HttpTarget(8080);
|
||||
@BeforeEach
|
||||
void setupTestTarget(PactVerificationContext context) {
|
||||
context.setTarget(new HttpTestTarget("localhost", 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);
|
||||
}
|
||||
@TestTemplate
|
||||
@ExtendWith(PactVerificationInvocationContextProvider.class)
|
||||
void pactVerificationTestTemplate(PactVerificationContext context) {
|
||||
context.verifyInteraction();
|
||||
}
|
||||
|
||||
@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.findById(eq(42L))).thenReturn(Optional.of(user));
|
||||
when(userRepository.save(any(User.class))).thenReturn(user);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,8 @@ include 'spring-cloud:spring-cloud-contract-consumer'
|
||||
|
||||
include 'pact:pact-spring-provider'
|
||||
include 'pact:pact-feign-consumer'
|
||||
include 'pact:pact-message-consumer'
|
||||
include 'pact:pact-message-provider'
|
||||
|
||||
|
||||
include 'spring-boot:rabbitmq-event-brokering'
|
||||
@@ -16,6 +18,7 @@ include 'spring-boot:modular:security-module'
|
||||
include 'spring-boot:modular:booking-module'
|
||||
include 'spring-boot:modular:application'
|
||||
include 'spring-boot:spring-boot-testing'
|
||||
include 'spring-boot:spring-boot-logging'
|
||||
|
||||
include 'logging'
|
||||
|
||||
|
||||
26
spring-boot/spring-boot-logging/.gitignore
vendored
Normal file
26
spring-boot/spring-boot-logging/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
/out/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
31
spring-boot/spring-boot-logging/build.gradle
Normal file
31
spring-boot/spring-boot-logging/build.gradle
Normal file
@@ -0,0 +1,31 @@
|
||||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '2.0.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'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
group = 'io.reflectoring'
|
||||
version = '0.0.1-SNAPSHOT'
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
compile('org.springframework.boot:spring-boot-starter')
|
||||
testCompile('org.springframework.boot:spring-boot-starter-test')
|
||||
testCompile('org.junit.jupiter:junit-jupiter-engine:5.2.0')
|
||||
}
|
||||
BIN
spring-boot/spring-boot-logging/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
spring-boot/spring-boot-logging/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
spring-boot/spring-boot-logging/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
spring-boot/spring-boot-logging/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Tue Feb 06 12:27:20 CET 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
|
||||
172
spring-boot/spring-boot-logging/gradlew
vendored
Normal file
172
spring-boot/spring-boot-logging/gradlew
vendored
Normal 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
spring-boot/spring-boot-logging/gradlew.bat
vendored
Normal file
84
spring-boot/spring-boot-logging/gradlew.bat
vendored
Normal 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
|
||||
1
spring-boot/spring-boot-logging/settings.gradle
Normal file
1
spring-boot/spring-boot-logging/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'spring-boot-logging'
|
||||
@@ -0,0 +1,12 @@
|
||||
package io.reflectoring.springbootlogging;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringBootLoggingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootLoggingApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<springProfile name="dev">
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>
|
||||
%d{HH:mm:ss.SSS} | %5p | %logger{25} | %m%n
|
||||
</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="staging">
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>
|
||||
%d{yyyy-MM-dd};%d{HH:mm:ss.SSS};%t;%5p;%logger{25};%m%n
|
||||
</pattern>
|
||||
<charset>utf8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.reflectoring.springbootlogging;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(properties =
|
||||
"spring.profiles.active=dev"
|
||||
)
|
||||
class LoggingWithDevProfileTest {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(LoggingWithDevProfileTest.class);
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
logger.info("This is a test");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.reflectoring.springbootlogging;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(properties =
|
||||
"spring.profiles.active=staging"
|
||||
)
|
||||
class LoggingWithStagingProfileTest {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(LoggingWithStagingProfileTest.class);
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
logger.info("This is a test");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.reflectoring.springbootlogging;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest
|
||||
class LoggingWithoutProfileTest {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(LoggingWithoutProfileTest.class);
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
logger.info("This is a test");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.reflectoring.springbootlogging;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class SpringBootLoggingApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@@ -10,17 +8,27 @@ buildscript {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("org.springframework.boot:spring-boot-starter-data-jpa:${springboot_version}")
|
||||
compile("org.springframework.boot:spring-boot-starter-web:${springboot_version}")
|
||||
compile("org.springframework.cloud:spring-cloud-starter-feign:1.4.1.RELEASE")
|
||||
compile('com.h2database:h2:1.4.196')
|
||||
testCompile("org.springframework.cloud:spring-cloud-starter-contract-stub-runner:${verifier_version}")
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test:${springboot_version}")
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springcloud_version}"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
compile("org.springframework.boot:spring-boot-starter-web")
|
||||
compile("org.springframework.cloud:spring-cloud-starter-openfeign")
|
||||
compile('org.springframework.cloud:spring-cloud-starter-netflix-ribbon')
|
||||
compile('com.h2database:h2:1.4.196')
|
||||
testCompile("org.springframework.cloud:spring-cloud-starter-contract-stub-runner")
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test")
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
springboot_version=1.5.9.RELEASE
|
||||
verifier_version=1.2.2.RELEASE
|
||||
springboot_version=2.0.4.RELEASE
|
||||
springcloud_version=Finchley.SR1
|
||||
springcloudcontract_version=2.0.1.RELEASE
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@ package io.reflectoring;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.feign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureStubRunner(ids = "io.reflectoring:user-service:+:stubs:6565", workOffline = true)
|
||||
@Ignore("Cannot work on CI because workOffline is set to true.")
|
||||
@AutoConfigureStubRunner(ids = "io.reflectoring:user-service:+:stubs:6565",
|
||||
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
|
||||
public class UserClientTest {
|
||||
|
||||
@Autowired
|
||||
private UserClient userClient;
|
||||
@Autowired
|
||||
private UserClient userClient;
|
||||
|
||||
@Test
|
||||
public void createUserCompliesToContract() {
|
||||
User user = new User();
|
||||
user.setFirstName("Arthur");
|
||||
user.setLastName("Dent");
|
||||
IdObject id = userClient.createUser(user);
|
||||
assertThat(id.getId()).isEqualTo(42L);
|
||||
}
|
||||
@Test
|
||||
public void createUserCompliesToContract() {
|
||||
User user = new User();
|
||||
user.setFirstName("Arthur");
|
||||
user.setLastName("Dent");
|
||||
IdObject id = userClient.createUser(user);
|
||||
assertThat(id.getId()).isEqualTo(42L);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,48 +1,55 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springboot_version}"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${springcloudcontract_version}"
|
||||
classpath "org.springframework.cloud:spring-cloud-contract-spec-pact:${springcloudcontract_pact_version}"
|
||||
classpath 'au.com.dius:pact-jvm-model:2.4.18'
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
apply plugin: 'spring-cloud-contract'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
group = 'io.reflectoring'
|
||||
version = '1.0.0'
|
||||
|
||||
|
||||
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" }
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springcloud_version}"
|
||||
}
|
||||
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'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
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("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
compile("org.springframework.boot:spring-boot-starter-web")
|
||||
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}")
|
||||
testCompile("org.springframework.cloud:spring-cloud-starter-contract-verifier")
|
||||
testCompile("org.springframework.cloud:spring-cloud-contract-spec:${springcloudcontract_pact_version}")
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test")
|
||||
}
|
||||
|
||||
contracts {
|
||||
baseClassMappings {
|
||||
baseClassMapping(".*userservice.*", "io.reflectoring.UserServiceBase")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a hack to locally publish the contract stubs when executing the build task
|
||||
// so that it works in the CI build without a Nexus or Artifactory server
|
||||
build.doLast {
|
||||
tasks.generatePomFileForStubsPublication.execute()
|
||||
tasks.publishStubsPublicationToMavenLocal.execute()
|
||||
}
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
springboot_version=1.5.9.RELEASE
|
||||
verifier_version=1.2.2.RELEASE
|
||||
springboot_version=2.0.4.RELEASE
|
||||
springcloud_version=Finchley.SR1
|
||||
springcloudcontract_version=2.0.1.RELEASE
|
||||
springcloudcontract_pact_version=1.2.5.RELEASE
|
||||
@@ -26,7 +26,7 @@ public class UserController {
|
||||
|
||||
@PutMapping(path = "/user-service/users/{id}")
|
||||
public ResponseEntity<User> updateUser(@RequestBody @Valid User user, @PathVariable long id) {
|
||||
User userFromDb = userRepository.findOne(id);
|
||||
User userFromDb = userRepository.findById(id).get();
|
||||
userFromDb.updateFrom(user);
|
||||
userFromDb = userRepository.save(userFromDb);
|
||||
return ResponseEntity.ok(userFromDb);
|
||||
@@ -34,7 +34,7 @@ public class UserController {
|
||||
|
||||
@GetMapping(path = "/user-service/users/{id}")
|
||||
public ResponseEntity<User> getUser(@PathVariable("id") Long id) {
|
||||
return ResponseEntity.ok(userRepository.findOne(id));
|
||||
return ResponseEntity.ok(userRepository.findById(id).get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.reflectoring;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -35,7 +37,7 @@ public abstract class UserServiceBase {
|
||||
when(userRepository.save(any(User.class))).thenReturn(savedUser);
|
||||
RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
|
||||
|
||||
when(userRepository.findOne(eq(42L))).thenReturn(savedUser);
|
||||
when(userRepository.findById(eq(42L))).thenReturn(Optional.of(savedUser));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user