diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6c5d8e7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,116 @@
+# 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/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..267cc9b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,27 @@
+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
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
index 88c1c9b..a0e224d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,14 @@
-[](https://travis-ci.org/microservices-demo/queue-master)
+[](https://travis-ci.org/microservices-demo/shipping) [](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`
diff --git a/docker/queue-master/Dockerfile b/docker/queue-master/Dockerfile
new file mode 100644
index 0000000..d157724
--- /dev/null
+++ b/docker/queue-master/Dockerfile
@@ -0,0 +1,6 @@
+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"]
diff --git a/pom.xml b/pom.xml
index 7db63a7..1e27b19 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,29 +4,127 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- works.weave.socks
+ works.weave.microservices-demo
queue-master
jar
queue-master
- Shipping queue master for socks eCommerce application
-
+ Queue service for microservices-demo application
- works.weave
- socks
- 0.0.1-SNAPSHOT
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.4.0.RELEASE
+
+ UTF-8
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-rest
+
+
+ org.springframework.data
+ spring-data-rest-hal-browser
+
org.springframework.boot
spring-boot-starter-amqp
- com.github.docker-java
- docker-java
- 3.0.0
+ com.github.docker-java
+ docker-java
+ 3.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.openpojo
+ openpojo
+ 0.8.4
+ test
+
+
+ queue-master
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.19.1
+
+
+ **/Unit*.java
+
+
+ **/IT*.java
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 2.18.1
+
+
+ **/IT*.java
+
+
+ **/Unit*.java
+
+
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.7.6.201602180812
+
+
+ prepare-agent
+
+ prepare-agent
+
+
+
+
+
+ org.eluder.coveralls
+ coveralls-maven-plugin
+ 4.2.0
+
+
+
+
+
+
+ spring-releases
+ https://repo.spring.io/libs-release
+
+
+
+
+ spring-releases
+ https://repo.spring.io/libs-release
+
+
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000..8ce9fcd
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,31 @@
+#!/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;
diff --git a/scripts/push.sh b/scripts/push.sh
new file mode 100755
index 0000000..e993474
--- /dev/null
+++ b/scripts/push.sh
@@ -0,0 +1,55 @@
+#!/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;
diff --git a/src/main/java/works/weave/socks/QueueMasterApplication.java b/src/main/java/works/weave/socks/QueueMasterApplication.java
deleted file mode 100644
index 7851c03..0000000
--- a/src/main/java/works/weave/socks/QueueMasterApplication.java
+++ /dev/null
@@ -1,45 +0,0 @@
-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...");
- }
-}
diff --git a/src/main/java/works/weave/socks/Shipment.java b/src/main/java/works/weave/socks/Shipment.java
deleted file mode 100644
index 9b2f678..0000000
--- a/src/main/java/works/weave/socks/Shipment.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package works.weave.socks;
-
-public class Shipment {
- private String id;
- private String name;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/works/weave/socks/DockerSpawner.java b/src/main/java/works/weave/socks/queuemaster/DockerSpawner.java
similarity index 92%
rename from src/main/java/works/weave/socks/DockerSpawner.java
rename to src/main/java/works/weave/socks/queuemaster/DockerSpawner.java
index 94e003d..7e6f480 100644
--- a/src/main/java/works/weave/socks/DockerSpawner.java
+++ b/src/main/java/works/weave/socks/queuemaster/DockerSpawner.java
@@ -1,22 +1,17 @@
-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 void run() {
}
});
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/works/weave/socks/queuemaster/QueueMasterApplication.java b/src/main/java/works/weave/socks/queuemaster/QueueMasterApplication.java
new file mode 100644
index 0000000..7e9d185
--- /dev/null
+++ b/src/main/java/works/weave/socks/queuemaster/QueueMasterApplication.java
@@ -0,0 +1,11 @@
+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);
+ }
+}
diff --git a/src/main/java/works/weave/socks/ShippingTaskHandler.java b/src/main/java/works/weave/socks/queuemaster/ShippingTaskHandler.java
similarity index 79%
rename from src/main/java/works/weave/socks/ShippingTaskHandler.java
rename to src/main/java/works/weave/socks/queuemaster/ShippingTaskHandler.java
index 7232640..950f817 100644
--- a/src/main/java/works/weave/socks/ShippingTaskHandler.java
+++ b/src/main/java/works/weave/socks/queuemaster/ShippingTaskHandler.java
@@ -1,7 +1,8 @@
-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 {
diff --git a/src/main/java/works/weave/socks/RabbitMqConfiguration.java b/src/main/java/works/weave/socks/queuemaster/configuration/RabbitMqConfiguration.java
similarity index 74%
rename from src/main/java/works/weave/socks/RabbitMqConfiguration.java
rename to src/main/java/works/weave/socks/queuemaster/configuration/RabbitMqConfiguration.java
index 0c7d60c..51eade1 100644
--- a/src/main/java/works/weave/socks/RabbitMqConfiguration.java
+++ b/src/main/java/works/weave/socks/queuemaster/configuration/RabbitMqConfiguration.java
@@ -1,6 +1,6 @@
-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.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 DefaultClassMapper classMapper()
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);
+ }
+}
diff --git a/src/main/java/works/weave/socks/ShippingConsumerConfiguration.java b/src/main/java/works/weave/socks/queuemaster/configuration/ShippingConsumerConfiguration.java
similarity index 92%
rename from src/main/java/works/weave/socks/ShippingConsumerConfiguration.java
rename to src/main/java/works/weave/socks/queuemaster/configuration/ShippingConsumerConfiguration.java
index 7cf0737..1e51094 100644
--- a/src/main/java/works/weave/socks/ShippingConsumerConfiguration.java
+++ b/src/main/java/works/weave/socks/queuemaster/configuration/ShippingConsumerConfiguration.java
@@ -1,4 +1,4 @@
-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.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 SimpleMessageListenerContainer listenerContainer() {
public MessageListenerAdapter messageListenerAdapter() {
return new MessageListenerAdapter(shippingTaskHandler, jsonMessageConverter());
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/works/weave/socks/shipping/entities/Shipment.java b/src/main/java/works/weave/socks/shipping/entities/Shipment.java
new file mode 100644
index 0000000..973f380
--- /dev/null
+++ b/src/main/java/works/weave/socks/shipping/entities/Shipment.java
@@ -0,0 +1,61 @@
+package works.weave.socks.shipping.entities;
+
+import java.util.UUID;
+
+public class Shipment {
+ private String id;
+ private String name;
+
+ public Shipment() {
+ this("");
+ }
+
+ public Shipment(String name) {
+ this(UUID.randomUUID().toString(), name);
+ }
+
+ public Shipment(String id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "Shipment{" +
+ "id='" + id + '\'' +
+ ", name='" + name + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Shipment shipment = (Shipment) o;
+
+ return getId() != null ? getId().equals(shipment.getId()) : shipment.getId() == null;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return getId() != null ? getId().hashCode() : 0;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/test/java/works/weave/socks/shipping/entities/UnitPojo.java b/src/test/java/works/weave/socks/shipping/entities/UnitPojo.java
new file mode 100644
index 0000000..a3c1c7e
--- /dev/null
+++ b/src/test/java/works/weave/socks/shipping/entities/UnitPojo.java
@@ -0,0 +1,77 @@
+package works.weave.socks.shipping.entities;
+
+import com.openpojo.reflection.PojoClass;
+import com.openpojo.reflection.PojoClassFilter;
+import com.openpojo.reflection.filters.FilterClassName;
+import com.openpojo.reflection.impl.PojoClassFactory;
+import com.openpojo.validation.Validator;
+import com.openpojo.validation.ValidatorBuilder;
+import com.openpojo.validation.affirm.Affirm;
+import com.openpojo.validation.rule.impl.*;
+import com.openpojo.validation.test.impl.GetterTester;
+import com.openpojo.validation.test.impl.SetterTester;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+public class UnitPojo {
+ // Configured for expectation, so we know when a class gets added or removed.
+ private static final int EXPECTED_CLASS_COUNT = 1;
+
+ // The package to test
+ private static final String POJO_PACKAGE = "works.weave.socks.shipping.entities";
+
+ private final PojoClassFilter filter = new FilterClassName("^((?!Unit).)*$");
+
+ @Test
+ public void ensureExpectedPojoCount() {
+ List pojoClasses = PojoClassFactory.getPojoClasses(POJO_PACKAGE, filter);
+ Affirm.affirmEquals("Classes added / removed?", EXPECTED_CLASS_COUNT, pojoClasses.size());
+ }
+
+ @Test
+ public void testPojoStructureAndBehavior() {
+ Validator validator = ValidatorBuilder.create()
+ // Add Rules to validate structure for POJO_PACKAGE
+ // See com.openpojo.validation.rule.impl for more ...
+ .with(new GetterMustExistRule())
+ .with(new SetterMustExistRule())
+ // Add Testers to validate behaviour for POJO_PACKAGE
+ // See com.openpojo.validation.test.impl for more ...
+ .with(new SetterTester())
+ .with(new GetterTester())
+ // Static fields must be final
+ .with(new NoStaticExceptFinalRule())
+ // Don't shadow parent's field names.
+ .with(new NoFieldShadowingRule())
+ // What about public fields, use one of the following rules
+ // allow them only if they are static and final.
+ .with(new NoPublicFieldsExceptStaticFinalRule())
+ .build();
+
+ validator.validate(POJO_PACKAGE, filter);
+ }
+
+ @Test
+ public void testEquals() throws Exception {
+ assertThat(new Shipment("id", "name"), is(equalTo(new Shipment("id", "name"))));
+ assertThat(new Shipment("id", "name"), is(equalTo(new Shipment("id", "another"))));
+ assertThat(new Shipment("id", "name"), is(not(equalTo(new Shipment("another", "name")))));
+ }
+
+ @Test
+ public void testHashcode() throws Exception {
+ assertThat(new Shipment("id", "name").hashCode(), is(equalTo(new Shipment("id", "name").hashCode())));
+ assertThat(new Shipment("id", "name").hashCode(), is(equalTo(new Shipment("id", "another").hashCode())));
+ assertThat(new Shipment("id", "name").hashCode(), is(not(equalTo(new Shipment("aa", "name").hashCode()))));
+ }
+
+ @Test
+ public void testString() throws Exception {
+ assertThat(new Shipment("id").toString(), is(notNullValue()));
+
+ }
+}
diff --git a/test/Dockerfile b/test/Dockerfile
new file mode 100644
index 0000000..8b921b3
--- /dev/null
+++ b/test/Dockerfile
@@ -0,0 +1,16 @@
+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
diff --git a/test/component.py b/test/component.py
new file mode 100644
index 0000000..2623007
--- /dev/null
+++ b/test/component.py
@@ -0,0 +1,19 @@
+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()
diff --git a/test/coveralls.py b/test/coveralls.py
new file mode 100644
index 0000000..2397b92
--- /dev/null
+++ b/test/coveralls.py
@@ -0,0 +1,31 @@
+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(Docker().execute(command))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test.sh b/test/test.sh
new file mode 100755
index 0000000..4bfa0d5
--- /dev/null
+++ b/test/test.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+set -e
+
+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/"$@"
diff --git a/test/unit.py b/test/unit.py
new file mode 100644
index 0000000..0b8acc5
--- /dev/null
+++ b/test/unit.py
@@ -0,0 +1,19 @@
+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()
diff --git a/test/util/Api.py b/test/util/Api.py
new file mode 100644
index 0000000..34953e0
--- /dev/null
+++ b/test/util/Api.py
@@ -0,0 +1,10 @@
+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
diff --git a/test/util/Docker.py b/test/util/Docker.py
new file mode 100644
index 0000000..c739f03
--- /dev/null
+++ b/test/util/Docker.py
@@ -0,0 +1,39 @@
+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()
+ stderr = p.stderr.read()
+ if p.wait() != 0:
+ p.stdout.close()
+ p.stderr.close()
+ raise RuntimeError(str(stderr.decode('utf-8')))
+ p.stdout.close()
+ p.stderr.close()
+ return str(out.decode('utf-8'))
+
+ def start_container(self, container_name="", image="", cmd="", host=""):
+ command = ['docker', 'run', '-d', '-h', host, '--name', container_name, image]
+ self.execute(command)
diff --git a/test/util/Dredd.py b/test/util/Dredd.py
new file mode 100644
index 0000000..03b0f89
--- /dev/null
+++ b/test/util/Dredd.py
@@ -0,0 +1,25 @@
+from util.Docker import Docker
+
+
+class Dredd:
+ image = 'weaveworksdemos/openapi'
+ container_name = ''
+
+ def test_against_endpoint(self, json_spec, endpoint_container_name, api_endpoint, mongo_endpoint_url,
+ mongo_container_name):
+ self.container_name = Docker().random_container_name('openapi')
+ command = ['docker', 'run',
+ '-h', 'openapi',
+ '--name', self.container_name,
+ '--link', mongo_container_name,
+ '--link', endpoint_container_name,
+ '--env', "MONGO_ENDPOINT={0}".format(mongo_endpoint_url),
+ Dredd.image,
+ "/usr/src/app/{0}".format(json_spec),
+ api_endpoint,
+ "-f",
+ "/usr/src/app/hooks.js"
+ ]
+ out = Docker().execute(command)
+ Docker().kill_and_remove(self.container_name)
+ return out
diff --git a/test/util/__init__.py b/test/util/__init__.py
new file mode 100644
index 0000000..e69de29