Commit 5a0ebd8a authored by Phil Winder's avatar Phil Winder

Add build and test harnesses. Add travis builder. Coveralls builder.

parent 567d06ed
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
### Go template
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
### Java template
/target/
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### OSX template
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea
## File-based project format:
*.iws
*.iml
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Created by .ignore support plugin (hsz.mobi)
# Maven builds
*/target
*/*/target
# AWS ECS install scripts generates an SSH key file
weave-ecs-demo-key.pem
# Load test generates pyc files
*.pyc
# Ignore Vagrant cache files
*.vagrant/
language: java
sudo: required
services:
- docker
jdk:
- oraclejdk8
install: true
env:
- GROUP=weaveworksdemos COMMIT=$TRAVIS_COMMIT TAG=$TRAVIS_TAG;
script:
- set -e
- ./scripts/build.sh;
- ./test/test.sh unit.py
- ./test/test.sh component.py
# - ./test/test.sh container.py --tag $TAG
after_success:
- set -e;
- ./test/test.sh coveralls.py
- if [ -z "$DOCKER_PASS" ] ; then
echo "This is a build triggered by an external PR. Skipping docker push.";
exit 0;
fi;
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS;
- ./scripts/push.sh
This diff is collapsed.
[![Build Status](https://travis-ci.org/microservices-demo/queue-master.svg?branch=master)](https://travis-ci.org/microservices-demo/queue-master)
[![Build Status](https://travis-ci.org/microservices-demo/shipping.svg?branch=master)](https://travis-ci.org/microservices-demo/shipping) [![Coverage Status](https://coveralls.io/repos/github/microservices-demo/shipping/badge.svg?branch=master)](https://coveralls.io/github/microservices-demo/shipping?branch=master)
# shipping
A microservices-demo service that provides shipping capabilities.
queue-master
---
This build is built, tested and released by travis.
A microservices-demo service that processes the orders queue.
# Test
`./test/test.sh < python testing file >`. For example: `./test/test.sh unit.py`
# Build
`GROUP=weaveworksdemos COMMIT=test ./scripts/build.sh`
# Push
`GROUP=weaveworksdemos COMMIT=test ./scripts/push.sh`
FROM java:openjdk-8-alpine
WORKDIR /usr/src/app
COPY *.jar ./app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/urandom","-jar","./app.jar", "--port=80"]
......@@ -4,29 +4,127 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>works.weave.socks</groupId>
<groupId>works.weave.microservices-demo</groupId>
<artifactId>queue-master</artifactId>
<packaging>jar</packaging>
<name>queue-master</name>
<description>Shipping queue master for socks eCommerce application
</description>
<description>Queue service for microservices-demo application</description>
<parent>
<groupId>works.weave</groupId>
<artifactId>socks</artifactId>
<version>0.0.1-SNAPSHOT</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-hal-browser</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.0.0</version>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.openpojo</groupId>
<artifactId>openpojo</artifactId>
<version>0.8.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>queue-master</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<includes>
<include>**/Unit*.java</include>
</includes>
<excludes>
<exclude>**/IT*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<includes>
<include>**/IT*.java</include>
</includes>
<excludes>
<exclude>**/Unit*.java</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.eluder.coveralls</groupId>
<artifactId>coveralls-maven-plugin</artifactId>
<version>4.2.0</version>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
#!/usr/bin/env bash
set -ev
SCRIPT_DIR=$(dirname "$0")
if [[ -z "$GROUP" ]] ; then
echo "Cannot find GROUP env var"
exit 1
fi
if [[ -z "$COMMIT" ]] ; then
echo "Cannot find COMMIT env var"
exit 1
fi
if [[ "$(uname)" == "Darwin" ]]; then
DOCKER_CMD=docker
else
DOCKER_CMD="sudo docker"
fi
CODE_DIR=$(cd $SCRIPT_DIR/..; pwd)
echo $CODE_DIR
$DOCKER_CMD run --rm -v $HOME/.m2:/root/.m2 -v $CODE_DIR:/usr/src/mymaven -w /usr/src/mymaven maven:3.2-jdk-8 mvn -DskipTests package
cp $CODE_DIR/target/*.jar $CODE_DIR/docker/$(basename $CODE_DIR)
for m in ./docker/*/; do
REPO=${GROUP}/$(basename $m)
$DOCKER_CMD build -t ${REPO}:${COMMIT} $CODE_DIR/$m;
done;
#!/usr/bin/env bash
set -ev
if [[ -z "$GROUP" ]] ; then
echo "Cannot find GROUP env var"
exit 1
fi
if [[ -z "$COMMIT" ]] ; then
echo "Cannot find COMMIT env var"
exit 1
fi
push() {
DOCKER_PUSH=1;
while [ $DOCKER_PUSH -gt 0 ] ; do
echo "Pushing $1";
docker push $1;
DOCKER_PUSH=$(echo $?);
if [[ "$DOCKER_PUSH" -gt 0 ]] ; then
echo "Docker push failed with exit code $DOCKER_PUSH";
fi;
done;
}
tag_and_push_all() {
if [[ -z "$1" ]] ; then
echo "Please pass the tag"
exit 1
else
TAG=$1
fi
for m in ./docker/*/; do
REPO=${GROUP}/$(basename $m)
if [[ "$COMMIT" != "$TAG" ]]; then
docker tag ${REPO}:${COMMIT} ${REPO}:${TAG}
fi
push "$REPO:$TAG";
done;
}
# Always push commit
tag_and_push_all $COMMIT
# Push snapshot when in master
if [ "$TRAVIS_BRANCH" == "master" ]; then
tag_and_push_all snapshot
fi;
# Push tag and latest when tagged
if [ -n "$TRAVIS_TAG" ]; then
tag_and_push_all ${TRAVIS_TAG}
tag_and_push_all latest
fi;
package works.weave.socks;
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.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class QueueMasterApplication implements CommandLineRunner {
final static String queueName = "shipping-task";
@Autowired
RabbitTemplate rabbitTemplate;
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(QueueMasterApplication.class, args);
}
@Bean
Queue queue() {
return new Queue(queueName, false);
}
@Bean
TopicExchange exchange() {
return new TopicExchange("shipping-task-exchange");
}
@Bean
Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(queueName);
}
@Override
public void run(String... args) throws Exception {
System.out.println("Starting QueueMasterApplication...");
}
}
package works.weave.socks;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
package works.weave.socks.queuemaster;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.Network;
import com.github.dockerjava.api.exception.DockerException;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.core.command.PullImageResultCallback;
import com.github.dockerjava.core.command.ExecStartResultCallback;
import com.github.dockerjava.api.exception.DockerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.Exception;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.List;
@Component
public class DockerSpawner {
......@@ -69,4 +64,4 @@ public class DockerSpawner {
}
});
}
}
\ No newline at end of file
}
package works.weave.socks.queuemaster;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class QueueMasterApplication {
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(QueueMasterApplication.class, args);
}
}
package works.weave.socks;
package works.weave.socks.queuemaster;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import works.weave.socks.shipping.entities.Shipment;
@Component
public class ShippingTaskHandler {
......
package works.weave.socks;
package works.weave.socks.queuemaster.configuration;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
......@@ -9,10 +9,13 @@ import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import works.weave.socks.shipping.entities.Shipment;
@Configuration
public class RabbitMqConfiguration
{
final static String queueName = "shipping-task";
@Bean
public ConnectionFactory connectionFactory()
{
......@@ -44,4 +47,19 @@ public class RabbitMqConfiguration
typeMapper.setDefaultType(Shipment.class);
return typeMapper;
}
}
\ No newline at end of file
@Bean
Queue queue() {
return new Queue(queueName, false);
}
@Bean
TopicExchange exchange() {
return new TopicExchange("shipping-task-exchange");
}
@Bean
Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(queueName);
}
}
package works.weave.socks;
package works.weave.socks.queuemaster.configuration;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
......@@ -7,6 +7,7 @@ import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import works.weave.socks.queuemaster.ShippingTaskHandler;
@Configuration
public class ShippingConsumerConfiguration extends RabbitMqConfiguration
......@@ -43,4 +44,4 @@ public class ShippingConsumerConfiguration extends RabbitMqConfiguration
public MessageListenerAdapter messageListenerAdapter() {
return new MessageListenerAdapter(shippingTaskHandler, jsonMessageConverter());
}
}
\ No newline at end of file
}
package works.weave.socks;
package works.weave.socks.shipping.entities;
public class Shipment {
private String id;
......@@ -19,4 +19,4 @@ public class Shipment {
public void setName(String name) {
this.name = name;
}
}
\ No newline at end of file
}
FROM python:3.6-alpine
RUN apk add --no-cache \
ca-certificates \
curl \
openssl
ENV DOCKER_BUCKET get.docker.com
ENV DOCKER_VERSION 1.8.3
RUN set -x \
&& curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz" -o docker.tgz \
&& tar -xzvf docker.tgz \
&& docker -v
RUN pip install requests
import os
import unittest
from os.path import expanduser
from util.Docker import Docker
class JavaServices(unittest.TestCase):
def test_maven(self):
script_dir = os.path.dirname(os.path.realpath(__file__))
code_dir = script_dir + "/.."
home = expanduser("~")
command = ['docker', 'run', '--rm', '-v', home + '/.m2:/root/.m2', '-v', code_dir + ':/usr/src/mymaven', '-w',
'/usr/src/mymaven', 'maven:3.2-jdk-8', 'mvn', 'integration-test']
print(Docker().execute(command))
if __name__ == '__main__':
unittest.main()
import os
import unittest
from os.path import expanduser
from util.Docker import Docker
class JavaServices(unittest.TestCase):
def test_maven(self):
script_dir = os.path.dirname(os.path.realpath(__file__))
code_dir = script_dir + "/.."
home = expanduser("~")
command = ['docker', 'run', '--rm',
'-v', home + '/.m2:/root/.m2',
'-v', code_dir + ':/usr/src/mymaven',
'-w', '/usr/src/mymaven',
'maven:3.2-jdk-8',
'mvn',
'-DrepoToken=' + os.getenv('COVERALLS_TOKEN'),
'-DserviceJobId=' + os.getenv('TRAVIS_JOB_ID'),
'-Dbranch=' + os.getenv('TRAVIS_BRANCH'),
'-DpullRequest=' + os.getenv('TRAVIS_PULL_REQUEST'),
'-DserviceName=' + os.getenv('TRAVIS'),
'verify',
'jacoco:report',
'coveralls:report']
print("Coveralls command: ",
'-DserviceJobId=' + os.getenv('TRAVIS_JOB_ID'),
'-Dbranch=' + os.getenv('TRAVIS_BRANCH'),
'-DpullRequest=' + os.getenv('TRAVIS_PULL_REQUEST'),
'-DserviceName=' + 'TRAVIS')
print(Docker().execute(command))
if __name__ == '__main__':
unittest.main()
#!/usr/bin/env bash
set -ev
SCRIPT_DIR=`dirname "$0"`
SCRIPT_NAME=`basename "$0"`
SSH_OPTS=-oStrictHostKeyChecking=no
if [[ "$(uname)" == "Darwin" ]]; then
DOCKER_CMD=docker
else
DOCKER_CMD="sudo docker"
fi
if [[ -z $($DOCKER_CMD images | grep test-container) ]] ; then
echo "Building test container"
docker build -t test-container $SCRIPT_DIR > /dev/null
fi
echo "Testing $1"
CODE_DIR=$(cd $SCRIPT_DIR/..; pwd)
echo "$@"
$DOCKER_CMD run \
--rm \
--name test \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $CODE_DIR:$CODE_DIR -w $CODE_DIR \
-e COVERALLS_TOKEN=$COVERALLS_TOKEN \
-e TRAVIS_JOB_ID=$TRAVIS_JOB_ID \
-e TRAVIS_BRANCH=$TRAVIS_BRANCH \
-e TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST \
-e TRAVIS=$TRAVIS \
test-container \
sh -c export PYTHONPATH=\$PYTHONPATH:\$PWD/test ; python test/"$@"
import os
import unittest
from os.path import expanduser
from util.Docker import Docker
class JavaServices(unittest.TestCase):
def test_maven(self):
script_dir = os.path.dirname(os.path.realpath(__file__))
code_dir = script_dir + "/.."
home = expanduser("~")
command = ['docker', 'run', '--rm', '-v', home + '/.m2:/root/.m2', '-v', code_dir + ':/usr/src/mymaven', '-w',
'/usr/src/mymaven', 'maven:3.2-jdk-8', 'mvn', 'test']
print(Docker().execute(command))
if __name__ == '__main__':
unittest.main()
import requests
class Api:
def noResponse(self, url):
try:
r = requests.get(url, timeout=5)
except requests.exceptions.ConnectionError:
return True
return r.status_code > 299
import re
from random import random
from subprocess import Popen, PIPE
# From http://blog.bordage.pro/avoid-docker-py/
class Docker:
def kill_and_remove(self, ctr_name):
command = ['docker', 'rm', '-f', ctr_name]
self.execute(command)
def random_container_name(self, prefix):
retstr = prefix + '-'
for i in range(5):
retstr += chr(int(round(random() * (122 - 97) + 97)))
return retstr
def get_container_ip(self, ctr_name):
command = ['docker', 'inspect',
'--format', '\'{{.NetworkSettings.IPAddress}}\'',
ctr_name]
return re.sub(r'[^0-9.]*', '', self.execute(command))
def execute(self, command):
print("Running: " + ' '.join(command))
p = Popen(command, stdout=PIPE, stderr=PIPE)
out = p.stdout.read()