Merge branch '1.2.x'

This commit is contained in:
Marcin Grzejszczak
2018-01-25 12:50:49 +01:00
42 changed files with 1855 additions and 56 deletions

View File

@@ -5,11 +5,15 @@ IMPORTANT: You need to have all the necessary Groovy plugins
Intellij IDEA having both Eclipse Groovy Compiler Plugin & GMavenPlus Intellij Plugin
results in properly imported project.
IMPORTANT: Spring Cloud Contract builds Docker images. Remember to
have Docker installed.
=== Project structure
Here you can find the Spring Cloud Contract folder structure
```
├── docker
├── samples
├── scripts
├── spring-cloud-contract-dependencies
@@ -22,6 +26,7 @@ Here you can find the Spring Cloud Contract folder structure
└── tests
```
- `docker` - folder contains docker images
- `samples` - folder contains test samples together with standalone ones used also to build documentation
- `scripts` - contains scripts to build and test `Spring Cloud Contract` with Maven, Gradle and standalone projects
- `spring-cloud-contract-dependencies` - contains Spring Cloud Contract BOM

View File

@@ -1,9 +1,10 @@
== Spring Cloud Contract Verifier Setup
You can set up Spring Cloud Contract Verifier in either of two ways
You can set up Spring Cloud Contract Verifier in the following ways:
* <<gradle-project,As a Gradle project>>
* <<maven-project,As a Maven project>>
* <<docker-project,As a Docker project>>
[[gradle-project]]
=== Gradle Project
@@ -898,3 +899,162 @@ More details about WireMock scenarios can be found at
http://wiremock.org/stateful-behaviour.html[http://wiremock.org/stateful-behaviour.html]
Spring Cloud Contract Verifier also generates tests with a guaranteed order of execution.
[[docker-project]]
=== Docker Project
We're publishing a `springcloud/spring-cloud-contract` Docker image
that contains a project that will generate tests and execute them in `EXPLICIT` mode
against a running application.
TIP: The `EXPLICIT` mode means that the tests generated from contracts will send
real requests and not the mocked ones.
==== Short intro to Maven, JARs and Binary storage
Since the Docker image can be used by non JVM projects, it's good to
explain the basic terms behind Spring Cloud Contract packaging defaults.
Part of the following definitions were taken from the https://maven.apache.org/glossary.html[Maven Glossary]
- `Project`: Maven thinks in terms of projects. Everything that you
will build are projects. Those projects follow a well defined
“Project Object Model”. Projects can depend on other projects,
in which case the latter are called “dependencies”. A project may
consistent of several subprojects, however these subprojects are still
treated equally as projects.
- `Artifact`: An artifact is something that is either produced or used
by a project. Examples of artifacts produced by Maven for a project
include: JARs, source and binary distributions. Each artifact
is uniquely identified by a group id and an artifact ID which is
unique within a group.
- `JAR`: JAR stands for Java ARchive. It's a format based on
the ZIP file format. Spring Cloud Contract packages the contracts and generated
stubs in a JAR file.
- `GroupId`: A group ID is a universally unique identifier for a project.
While this is often just the project name (eg. commons-collections),
it is helpful to use a fully-qualified package name to distinguish it
from other projects with a similar name (eg. org.apache.maven).
Typically, when published to the Artifact Manager, the `GroupId` will get
slash separated and form part of the URL. E.g. for group id `com.example`
and artifact id `application` would be `/com/example/application/`.
- `Classifier`: The Maven dependency notation looks as follows:
`groupId:artifactId:version:classifier`. The classifier is additional suffix
passed to the dependency. E.g. `stubs`, `sources`. The same dependency
e.g. `com.example:application` can produce multiple artifacts that
differ from each other with the classifier.
- `Artifact manager`: When you generate binaries / sources / packages, you would
like them to be available for others to download / reference or reuse. In case
of the JVM world those artifacts would be JARs, for Ruby these are gems
and for Docker those would be Docker images. You can store those artifacts
in a manager. Examples of such managers can be https://jfrog.com/artifactory/[Artifactory]
or http://www.sonatype.org/nexus/[Nexus].
==== How it works
The image searches for contracts under the `/contracts` folder.
The output from running the tests will be available under
`/spring-cloud-contract/build` folder (it's useful for debugging
purposes).
It's enough for you to mount your contracts, pass the environment variables
and the image will:
- generate the contract tests
- execute the tests against the provided URL
- generate the http://wiremock.org[WireMock] stubs
- (optional - turned on by default) publish the stubs to a Artifact Manager
===== Environment Variables
The Docker image requires some environment variables to point to
your running application, to the Artifact manager instance etc.
- `PROJECT_GROUP` - your project's group id. Defaults to `com.example`.
- `PROJECT_VERSION` - your project's version. Defaults to `0.0.1-SNAPSHOT`
- `PROJECT_NAME` - artifact id. Defaults to `example`
- `REPO_WITH_BINARIES_URL` - URL of your Artifact Manager. Defaults to `http://localhost:8081/artifactory/libs-release-local`
which is the default URL of https://jfrog.com/artifactory/[Artifactory] running locally
- `REPO_WITH_BINARIES_USERNAME` - (optional) username when the Artifact Manager is secured
- `REPO_WITH_BINARIES_PASSWORD` - (optional) password when the Artifact Manager is secured
- `PUBLISH_ARTIFACTS` - if set to `true` then will publish artifact to binary storage. Defaults to `true`.
These environment variables are used when tests are executed:
- `APPLICATION_BASE_URL` - url against which tests should be executed.
Remember that it has to be accessible from the Docker container (e.g. `localhost`
will not work)
- `APPLICATION_USERNAME` - (optional) username for basic authentication to your application
- `APPLICATION_PASSWORD` - (optional) password for basic authentication to your application
==== Example of usage
Let's take a look at a simple MVC application
```bash
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
$ cd bookstore
```
The contracts are available under `/contracts` folder.
[[docker-server-side]]
==== Server side (nodejs)
Since we want to run tests, we could just execute:
```bash
$ npm test
```
however, for learning purposes, let's split it into pieces:
```bash
# Stop docker infra (nodejs, artifactory)
$ ./stop_infra.sh
# Start docker infra (nodejs, artifactory)
$ ./setup_infra.sh
# Kill & Run app
$ pkill -f "node app"
$ nohup node app &
# Prepare environment variables
$ SC_CONTRACT_DOCKER_VERSION="..."
$ APP_IP="192.168.0.100"
$ APP_PORT="3000"
$ ARTIFACTORY_PORT="8081"
$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
$ CURRENT_DIR="$( pwd )"
$ CURRENT_FOLDER_NAME=${PWD##*/}
$ PROJECT_VERSION="0.0.1.RELEASE"
# Execute contract tests
$ docker run --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
# Kill app
$ pkill -f "node app"
```
What will happen is that via bash scripts:
- infrastructure will be set up (MongoDb, Artifactory).
In real life scenario you would just run the NodeJS application
with mocked database. In this example we want to show how we can
benefit from Spring Cloud Contract in no time.
- due to those constraints the contracts also represent the
stateful situation
** first request is a `POST` that causes data to get inserted to the database
** second request is a `GET` that returns a list of data with 1 previously inserted element
- the NodeJS application will be started (on port `3000`)
- contract tests will be generated via Docker and tests
will be executed against the running application
** the contracts will be taken from `/contracts` folder.
** the output of the test execution is available under
`node_modules/spring-cloud-contract/output`.
- the stubs will be uploaded to Artifactory. You can check them out
under http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/ .
The stubs will be here http://localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar.
To see how the client side looks like check out the <<stubrunner-docker>> section.

View File

@@ -111,3 +111,67 @@ IMPORTANT: Starting with version 1.0.4, you can provide a range of versions that
would like the Stub Runner to take into consideration. You can read more about the
https://wiki.eclipse.org/Aether/New_and_Noteworthy#Version_Ranges[Aether versioning
ranges here].
[[stubrunner-docker]]
=== Stub Runner Docker
We're publishing a `spring-cloud/spring-cloud-contract-stub-runner` Docker image
that will start the standalone version of Stub Runner.
If you want to learn more about the basics of Maven, artifact ids,
group ids, classifiers and Artifact Managers, just click here <<docker-project>>.
==== How to use it
Just execute the docker image. You can pass any of the <<common-properties-junit-spring>>
as environment variables. The convention is that all the
letters should be upper case. The camel case notation should
and the dot (`.`) should be separated via underscore (`_`). E.g.
the `stubrunner.repositoryRoot` property should be represented
as a `STUBRUNNER_REPOSITORY_ROOT` environment variable.
==== Example of client side usage in a non JVM project
We'd like to use the stubs created in this <<docker-server-side>> step.
Let's assume that we want to run the stubs on port `9876`. The NodeJS code
is available here:
```bash
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
$ cd bookstore
```
Let's run the Stub Runner Boot application with the stubs.
```bash
# Provide the Spring Cloud Contract Docker version
$ SC_CONTRACT_DOCKER_VERSION="..."
# The IP at which the app is running and Docker container can reach it
$ APP_IP="192.168.0.100"
# Spring Cloud Contract Stub Runner properties
$ STUBRUNNER_PORT="8083"
# Stub coordinates 'groupId:artifactId:version:classifier:port'
$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
# Run the docker with Stub Runner Boot
$ docker run --rm -e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" -e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" -p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" -p "9876:9876" springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"
```
What's happening is that
- a standalone Stub Runner application got started
- it downloaded the stub with coordinates `com.example:bookstore:0.0.1.RELEASE:stubs` on port `9876`
- it got downloaded from Artifactory running at `http://192.168.0.100:8081/artifactory/libs-release-local`
- after a while Stub Runner will be running on port `8083`
- and the stubs will be running at port `9876`
On the server side we built a stateful stub. Let's use curl to assert
that the stubs are setup properly.
```bash
# let's execute the first request (no response is returned)
$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
# Now time for the second request
$ curl -X GET http://localhost:9876/api/books
# You will receive contents of the JSON
```