From 47015433cc41d0b98c1bbd926b871a15d927d9de Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Sun, 27 Sep 2015 15:54:44 +0200 Subject: [PATCH 1/5] Split binary into 2 - binary (simple traefik build) - crossbinary, cross build using gox Signed-off-by: Vincent Demeester --- script/binary | 19 +------------------ script/crossbinary | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 18 deletions(-) create mode 100755 script/crossbinary diff --git a/script/binary b/script/binary index 60503e089..89d2dacf4 100755 --- a/script/binary +++ b/script/binary @@ -6,26 +6,9 @@ if ! test -e gen.go; then false fi -if [ -z "$1" ]; then - # Remove windows platform because of - # https://github.com/mailgun/log/issues/10 - OS_PLATFORM_ARG=(-os="darwin linux") -else - OS_PLATFORM_ARG=($1) -fi - -if [ -z "$2" ]; then - OS_ARCH_ARG=(-arch="386 amd64 arm") -else - OS_ARCH_ARG=($2) -fi - -# Get rid of existing binaries -rm -f dist/traefik* +rm -f dist/traefik rm -rf Godeps/_workspace/pkg # Build binaries CGO_ENABLED=0 godep go build -a -installsuffix nocgo -o dist/traefik . -GOPATH=`godep path`:$GOPATH gox "${OS_PLATFORM_ARG[@]}" "${OS_ARCH_ARG[@]}" \ - -output="dist/traefik_{{.OS}}-{{.Arch}}" diff --git a/script/crossbinary b/script/crossbinary new file mode 100755 index 000000000..5c82b1fd8 --- /dev/null +++ b/script/crossbinary @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +if ! test -e gen.go; then + echo >&2 'error: generate must be run before binary' + false +fi + +if [ -z "$1" ]; then + # Remove windows platform because of + # https://github.com/mailgun/log/issues/10 + OS_PLATFORM_ARG=(-os="darwin linux") +else + OS_PLATFORM_ARG=($1) +fi + +if [ -z "$2" ]; then + OS_ARCH_ARG=(-arch="386 amd64 arm") +else + OS_ARCH_ARG=($2) +fi + +# Get rid of existing binaries +rm -f dist/traefik_* +rm -rf Godeps/_workspace/pkg + +# Build binaries +GOPATH=`godep path`:$GOPATH gox "${OS_PLATFORM_ARG[@]}" "${OS_ARCH_ARG[@]}" \ + -output="dist/traefik_{{.OS}}-{{.Arch}}" + From a5a8d6929e793f6c3a70b1b84f68973c506deced Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Sun, 27 Sep 2015 15:56:53 +0200 Subject: [PATCH 2/5] =?UTF-8?q?Update=20build=20toolchain=20to=20the=20use?= =?UTF-8?q?=20of=20docker=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … for integration tests. - Update circle.yml to start the docker daemon listening on TCP (to be able to talk to it from the container running test-integration) - Update script/test-integration to prepare the use of go-check - Update Makefile in order to run less "binary" target and setting up the right environment variable for the builds Signed-off-by: Vincent Demeester --- Makefile | 18 +++++++++--------- build.Dockerfile | 16 ++++++++++++++++ circle.yml | 12 +++++++++--- script/make.sh | 1 + script/test-integration | 6 ++++-- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index b6fab990b..2d8c7dec7 100644 --- a/Makefile +++ b/Makefile @@ -5,15 +5,16 @@ TRAEFIK_ENVS := \ -e OS_PLATFORM_ARG \ -e TESTFLAGS -BIND_DIR := $(if $(DOCKER_HOST),,dist) -TRAEFIK_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/emilevauge/traefik/$(BIND_DIR)") +BIND_DIR := "dist" +TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/emilevauge/traefik/$(BIND_DIR)" GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) TRAEFIK_DEV_IMAGE := traefik-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH)) REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]') TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"emilevauge/traefik") +INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -v "/var/run/docker.sock:/var/run/docker.sock") -DOCKER_RUN_TRAEFIK := docker run $(if $(CIRCLECI),,--rm) -it $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)" +DOCKER_RUN_TRAEFIK := docker run $(if $(CIRCLECI),,--rm) $(INTEGRATION_OPTS) -it $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)" print-%: ; @echo $*=$($*) @@ -22,14 +23,17 @@ default: binary binary: build $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary +crossbinary: build + $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate crossbinary + test: build - $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit test-integration + $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration test-unit: build $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit test-integration: build - $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary test-integration + $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-integration validate: build $(DOCKER_RUN_TRAEFIK) ./script/make.sh validate-gofmt validate-govet @@ -47,10 +51,6 @@ shell: build $(DOCKER_RUN_TRAEFIK) /bin/bash image: build - if ! [ -a dist/traefik_linux-386 ] ; \ - then \ - $(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary; \ - fi; docker build -t $(TRAEFIK_IMAGE) . dist: diff --git a/build.Dockerfile b/build.Dockerfile index 4bf8cbf01..d161c5f18 100644 --- a/build.Dockerfile +++ b/build.Dockerfile @@ -4,10 +4,26 @@ RUN go get github.com/tools/godep RUN go get github.com/mitchellh/gox RUN go get github.com/tcnksm/ghr +# Which docker version to test on +ENV DOCKER_VERSION 1.6.2 + +# Download docker +RUN set -ex; \ + curl https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION} -o /usr/local/bin/docker-${DOCKER_VERSION}; \ + chmod +x /usr/local/bin/docker-${DOCKER_VERSION} + +# Set the default Docker to be run +RUN ln -s /usr/local/bin/docker-${DOCKER_VERSION} /usr/local/bin/docker + ENV PATH /go/src/github.com/emilevauge/traefik/Godeps/_workspace/bin:$PATH WORKDIR /go/src/github.com/emilevauge/traefik +# This is a hack (see libcompose#32) - will be removed when libcompose will be fixed +# (i.e go get able) +RUN mkdir -p /go/src/github.com/docker/docker/autogen/dockerversion/ +COPY Godeps/_workspace/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go /go/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go + RUN mkdir Godeps COPY Godeps/Godeps.json Godeps/ RUN godep restore diff --git a/circle.yml b/circle.yml index 50894762a..1665e6c79 100644 --- a/circle.yml +++ b/circle.yml @@ -1,11 +1,15 @@ machine: - services: - - docker + pre: + - sudo docker -d -e lxc -s btrfs -H tcp://0.0.0.0:2375: + background: true + - sleep 5 environment: REPO: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME + DOCKER_HOST: tcp://172.17.42.1:2375 dependencies: pre: + - docker version - go get github.com/tcnksm/ghr - make validate override: @@ -13,8 +17,10 @@ dependencies: test: override: - - make test + - make test-unit + - make MAKE_DOCKER_HOST=$DOCKER_HOST test-integration post: + - make crossbinary - make image deployment: diff --git a/script/make.sh b/script/make.sh index 2fc916bc5..a7276eb49 100755 --- a/script/make.sh +++ b/script/make.sh @@ -4,6 +4,7 @@ set -e # List of bundles to create when no argument is passed DEFAULT_BUNDLES=( validate-gofmt + validate-govet binary test-unit diff --git a/script/test-integration b/script/test-integration index e24a85eae..87a643808 100755 --- a/script/test-integration +++ b/script/test-integration @@ -3,6 +3,8 @@ export SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export DEST=. -TESTFLAGS="$TESTFLAGS" -#godep go test -v ./integration +TESTFLAGS="$TESTFLAGS -test.timeout=30m -check.v" + +cd integration +GOPATH=`godep path`:$GOPATH go test $TESTFLAGS From ad60b301b74a5927defa193fc0cb4f8dadee26a9 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Sun, 27 Sep 2015 15:59:51 +0200 Subject: [PATCH 3/5] Add initial test-integration suites Uses go-check in order to separate integration tests into suites, and have Setup and TearDown operations (on Suites and Tests) ; and use libcompose to start the external dependencies to test on (like consul, marathon, etcd, some http images, etc..). - Update Godeps to get dependencies needed for the use of libcompose - Setup initial suites and go-check + libcompose mini-framework - Add some hacks related to libcompose, will be fixed later (when fixed upstream) Signed-off-by: Vincent Demeester --- Godeps/Godeps.json | 236 ++++++++++++++++++ .../autogen/dockerversion/dockerversion.go | 12 + integration/basic_test.go | 51 ++++ integration/consul_test.go | 27 ++ integration/docker_test.go | 27 ++ integration/file_test.go | 27 ++ integration/fixtures/consul/simple.toml | 11 + integration/fixtures/docker/simple.toml | 16 ++ integration/fixtures/file/simple.toml | 11 + .../fixtures/invalid_configuration.toml | 3 + integration/fixtures/marathon/simple.toml | 11 + integration/fixtures/simple_default.toml | 9 + integration/integration_test.go | 130 ++++++++++ integration/marathon_test.go | 27 ++ integration/resources/compose/consul.yml | 21 ++ integration/resources/compose/file.yml | 20 ++ integration/resources/compose/marathon.yml | 42 ++++ 17 files changed, 681 insertions(+) create mode 100644 Godeps/_workspace/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go create mode 100644 integration/basic_test.go create mode 100644 integration/consul_test.go create mode 100644 integration/docker_test.go create mode 100644 integration/file_test.go create mode 100644 integration/fixtures/consul/simple.toml create mode 100644 integration/fixtures/docker/simple.toml create mode 100644 integration/fixtures/file/simple.toml create mode 100644 integration/fixtures/invalid_configuration.toml create mode 100644 integration/fixtures/marathon/simple.toml create mode 100644 integration/fixtures/simple_default.toml create mode 100644 integration/integration_test.go create mode 100644 integration/marathon_test.go create mode 100644 integration/resources/compose/consul.yml create mode 100644 integration/resources/compose/file.yml create mode 100644 integration/resources/compose/marathon.yml diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index cadcb2eba..a5abdb1fb 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,9 @@ { "ImportPath": "github.com/emilevauge/traefik", "GoVersion": "go1.4.2", + "Packages": [ + "./..." + ], "Deps": [ { "ImportPath": "github.com/BurntSushi/toml", @@ -36,10 +39,218 @@ "Comment": "v0.1-70-gc7477ad", "Rev": "c7477ad8e330bef55bf1ebe300cf8aa67c492d1b" }, + { + "ImportPath": "github.com/docker/distribution", + "Comment": "v2.0.0-467-g9038e48", + "Rev": "9038e48c3b982f8e82281ea486f078a73731ac4e" + }, + { + "ImportPath": "github.com/docker/docker/api", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/cliconfig", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/daemon/network", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/graph/tags", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/image", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/opts", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/archive", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/fileutils", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/homedir", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/httputils", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/ioutils", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/jsonmessage", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/mflag", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/nat", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/parsers", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/pools", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/promise", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/random", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/stdcopy", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/stringid", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/symlink", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/system", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/tarsum", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/term", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/timeutils", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/tlsconfig", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/ulimit", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/units", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/urlutil", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/useragent", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/pkg/version", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/registry", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/runconfig", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/utils", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/docker/volume", + "Comment": "v1.4.1-5200-gf39987a", + "Rev": "f39987afe8d611407887b3094c03d6ba6a766a67" + }, + { + "ImportPath": "github.com/docker/libcompose/docker", + "Rev": "aad672800904307e96a2c21cad1420f3080e0f35" + }, + { + "ImportPath": "github.com/docker/libcompose/logger", + "Rev": "aad672800904307e96a2c21cad1420f3080e0f35" + }, + { + "ImportPath": "github.com/docker/libcompose/lookup", + "Rev": "aad672800904307e96a2c21cad1420f3080e0f35" + }, + { + "ImportPath": "github.com/docker/libcompose/project", + "Rev": "aad672800904307e96a2c21cad1420f3080e0f35" + }, + { + "ImportPath": "github.com/docker/libcompose/utils", + "Rev": "aad672800904307e96a2c21cad1420f3080e0f35" + }, + { + "ImportPath": "github.com/docker/libtrust", + "Rev": "9cbd2a1374f46905c68a4eb3694a130610adc62a" + }, { "ImportPath": "github.com/elazarl/go-bindata-assetfs", "Rev": "d5cac425555ca5cf00694df246e04f05e6a55150" }, + { + "ImportPath": "github.com/flynn/go-shlex", + "Rev": "3f9db97f856818214da2e1057f8ad84803971cff" + }, { "ImportPath": "github.com/fsouza/go-dockerclient", "Rev": "0239034d42f665efa17fd77c39f891c2f9f32922" @@ -102,6 +313,15 @@ "ImportPath": "github.com/mailgun/timetools", "Rev": "fd192d755b00c968d312d23f521eb0cdc6f66bd0" }, + { + "ImportPath": "github.com/opencontainers/runc/libcontainer/user", + "Comment": "v0.0.4-21-g4ab1324", + "Rev": "4ab132458fc3e9dbeea624153e0331952dc4c8d5" + }, + { + "ImportPath": "github.com/samalba/dockerclient", + "Rev": "cfb489c624b635251a93e74e1e90eb0959c5367f" + }, { "ImportPath": "github.com/thoas/stats", "Rev": "54ed61c2b47e263ae2f01b86837b0c4bd1da28e8" @@ -110,11 +330,23 @@ "ImportPath": "github.com/unrolled/render", "Rev": "26b4e3aac686940fe29521545afad9966ddfc80c" }, + { + "ImportPath": "github.com/vdemeester/shakers", + "Rev": "8fe734f75f3a70b651cbfbf8a55a009da09e8dc5" + }, + { + "ImportPath": "golang.org/x/net/context", + "Rev": "d9558e5c97f85372afee28cf2b6059d7d3818919" + }, { "ImportPath": "gopkg.in/alecthomas/kingpin.v2", "Comment": "v2.0.12", "Rev": "639879d6110b1b0409410c7b737ef0bb18325038" }, + { + "ImportPath": "gopkg.in/check.v1", + "Rev": "11d3bc7aa68e238947792f30573146a3231fc0f1" + }, { "ImportPath": "gopkg.in/fsnotify.v1", "Comment": "v1.2.0", @@ -124,6 +356,10 @@ "ImportPath": "gopkg.in/mgo.v2/bson", "Comment": "r2015.06.03-5-g22287ba", "Rev": "22287bab4379e1fbf6002fb4eb769888f3fb224c" + }, + { + "ImportPath": "gopkg.in/yaml.v2", + "Rev": "7ad95dd0798a40da1ccdff6dff35fd177b5edf40" } ] } diff --git a/Godeps/_workspace/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go b/Godeps/_workspace/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go new file mode 100644 index 000000000..1c2d32547 --- /dev/null +++ b/Godeps/_workspace/src/github.com/docker/docker/autogen/dockerversion/dockerversion.go @@ -0,0 +1,12 @@ +// AUTOGENERATED FILE; see ./hack/make/.go-autogen +package dockerversion + +var ( + GITCOMMIT string = "" + VERSION string = "" + BUILDTIME string = "" + + IAMSTATIC string = "true" + INITSHA1 string = "" + INITPATH string = "" +) diff --git a/integration/basic_test.go b/integration/basic_test.go new file mode 100644 index 000000000..4ad3aafca --- /dev/null +++ b/integration/basic_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "net/http" + "os/exec" + "time" + + checker "github.com/vdemeester/shakers" + check "gopkg.in/check.v1" +) + +func (s *SimpleSuite) TestNoOrInexistentConfigShouldFail(c *check.C) { + cmd := exec.Command(traefikBinary) + output, err := cmd.CombinedOutput() + + c.Assert(err, checker.NotNil) + c.Assert(string(output), checker.Contains, "Error reading file open traefik.toml: no such file or directory") + + nonExistentFile := "non/existent/file.toml" + cmd = exec.Command(traefikBinary, nonExistentFile) + output, err = cmd.CombinedOutput() + + c.Assert(err, checker.NotNil) + c.Assert(string(output), checker.Contains, fmt.Sprintf("Error reading file open %s: no such file or directory", nonExistentFile)) +} + +func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) { + cmd := exec.Command(traefikBinary, "fixtures/invalid_configuration.toml") + output, err := cmd.CombinedOutput() + + c.Assert(err, checker.NotNil) + c.Assert(string(output), checker.Contains, "Error reading file Near line 1") +} + +func (s *SimpleSuite) TestSimpleDefaultConfig(c *check.C) { + cmd := exec.Command(traefikBinary, "fixtures/simple_default.toml") + err := cmd.Start() + c.Assert(err, checker.IsNil) + + time.Sleep(100 * time.Millisecond) + // TODO validate : run on 80 + resp, err := http.Get("http://127.0.0.1/") + + // Expected a 404 as we did not comfigure anything + c.Assert(err, checker.IsNil) + c.Assert(resp.StatusCode, checker.Equals, 404) + + killErr := cmd.Process.Kill() + c.Assert(killErr, checker.IsNil) +} diff --git a/integration/consul_test.go b/integration/consul_test.go new file mode 100644 index 000000000..f56efbc63 --- /dev/null +++ b/integration/consul_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "net/http" + "os/exec" + "time" + + checker "github.com/vdemeester/shakers" + check "gopkg.in/check.v1" +) + +func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) { + cmd := exec.Command(traefikBinary, "fixtures/consul/simple.toml") + err := cmd.Start() + c.Assert(err, checker.IsNil) + + time.Sleep(100 * time.Millisecond) + // TODO validate : run on 80 + resp, err := http.Get("http://127.0.0.1/") + + // Expected a 404 as we did not comfigure anything + c.Assert(err, checker.IsNil) + c.Assert(resp.StatusCode, checker.Equals, 404) + + killErr := cmd.Process.Kill() + c.Assert(killErr, checker.IsNil) +} diff --git a/integration/docker_test.go b/integration/docker_test.go new file mode 100644 index 000000000..8b031ff78 --- /dev/null +++ b/integration/docker_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "net/http" + "os/exec" + "time" + + checker "github.com/vdemeester/shakers" + check "gopkg.in/check.v1" +) + +func (s *DockerSuite) TestSimpleConfiguration(c *check.C) { + cmd := exec.Command(traefikBinary, "fixtures/docker/simple.toml") + err := cmd.Start() + c.Assert(err, checker.IsNil) + + time.Sleep(100 * time.Millisecond) + // TODO validate : run on 80 + resp, err := http.Get("http://127.0.0.1/") + + // Expected a 404 as we did not comfigure anything + c.Assert(err, checker.IsNil) + c.Assert(resp.StatusCode, checker.Equals, 404) + + killErr := cmd.Process.Kill() + c.Assert(killErr, checker.IsNil) +} diff --git a/integration/file_test.go b/integration/file_test.go new file mode 100644 index 000000000..3f1ec5c13 --- /dev/null +++ b/integration/file_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "net/http" + "os/exec" + "time" + + checker "github.com/vdemeester/shakers" + check "gopkg.in/check.v1" +) + +func (s *FileSuite) TestSimpleConfiguration(c *check.C) { + cmd := exec.Command(traefikBinary, "fixtures/file/simple.toml") + err := cmd.Start() + c.Assert(err, checker.IsNil) + + time.Sleep(100 * time.Millisecond) + // TODO validate : run on 80 + resp, err := http.Get("http://127.0.0.1/") + + // Expected a 404 as we did not comfigure anything + c.Assert(err, checker.IsNil) + c.Assert(resp.StatusCode, checker.Equals, 404) + + killErr := cmd.Process.Kill() + c.Assert(killErr, checker.IsNil) +} diff --git a/integration/fixtures/consul/simple.toml b/integration/fixtures/consul/simple.toml new file mode 100644 index 000000000..02707a085 --- /dev/null +++ b/integration/fixtures/consul/simple.toml @@ -0,0 +1,11 @@ +# Reverse proxy port +# +# Optional +# Default: ":80" +# +# port = ":80" +# +# LogLevel +logLevel = "DEBUG" + +[consul] diff --git a/integration/fixtures/docker/simple.toml b/integration/fixtures/docker/simple.toml new file mode 100644 index 000000000..02f412a65 --- /dev/null +++ b/integration/fixtures/docker/simple.toml @@ -0,0 +1,16 @@ +# Reverse proxy port +# +# Optional +# Default: ":80" +# +# port = ":80" +# +# LogLevel +logLevel = "DEBUG" + +[docker] + +# FIXME this should be "dynamic".. xD +endpoint = "tcp://172.17.42.1:2375" + +domain = "docker.localhost" diff --git a/integration/fixtures/file/simple.toml b/integration/fixtures/file/simple.toml new file mode 100644 index 000000000..100b58a93 --- /dev/null +++ b/integration/fixtures/file/simple.toml @@ -0,0 +1,11 @@ +# Reverse proxy port +# +# Optional +# Default: ":80" +# +# port = ":80" +# +# LogLevel +logLevel = "DEBUG" + +[file] diff --git a/integration/fixtures/invalid_configuration.toml b/integration/fixtures/invalid_configuration.toml new file mode 100644 index 000000000..ed4b5b30e --- /dev/null +++ b/integration/fixtures/invalid_configuration.toml @@ -0,0 +1,3 @@ +{ + "who": ["am", "I", "?", "JSON"] +} diff --git a/integration/fixtures/marathon/simple.toml b/integration/fixtures/marathon/simple.toml new file mode 100644 index 000000000..1e97650a6 --- /dev/null +++ b/integration/fixtures/marathon/simple.toml @@ -0,0 +1,11 @@ +# Reverse proxy port +# +# Optional +# Default: ":80" +# +# port = ":80" +# +# LogLevel +logLevel = "DEBUG" + +[marathon] diff --git a/integration/fixtures/simple_default.toml b/integration/fixtures/simple_default.toml new file mode 100644 index 000000000..ac7dee9f1 --- /dev/null +++ b/integration/fixtures/simple_default.toml @@ -0,0 +1,9 @@ +# Reverse proxy port +# +# Optional +# Default: ":80" +# +# port = ":80" +# +# LogLevel +logLevel = "DEBUG" diff --git a/integration/integration_test.go b/integration/integration_test.go new file mode 100644 index 000000000..888d65915 --- /dev/null +++ b/integration/integration_test.go @@ -0,0 +1,130 @@ +// This is the main file that sets up integration tests using go-check. +package main + +import ( + "fmt" + // "os" + "testing" + "time" + + "github.com/docker/libcompose/docker" + "github.com/docker/libcompose/project" + + checker "github.com/vdemeester/shakers" + check "gopkg.in/check.v1" +) + +func Test(t *testing.T) { + check.TestingT(t) +} + +func init() { + check.Suite(&SimpleSuite{}) + check.Suite(&FileSuite{}) + check.Suite(&DockerSuite{}) + check.Suite(&ConsulSuite{}) + check.Suite(&MarathonSuite{}) +} + +var traefikBinary = "../dist/traefik" + +// SimpleSuite +type SimpleSuite struct{ BaseSuite } + +// File test suites +type FileSuite struct{ BaseSuite } + +func (s *FileSuite) SetUpSuite(c *check.C) { + s.createComposeProject(c, "file") + + s.composeProject.Up() +} + +// Docker test suites +type DockerSuite struct{ BaseSuite } + +func (s *DockerSuite) SetUpSuite(c *check.C) { + // Make sure we can speak to docker +} + +func (s *DockerSuite) TearDownSuite(c *check.C) { + // Clean the mess +} + +// Consul test suites (using libcompose) +type ConsulSuite struct{ BaseSuite } + +func (s *ConsulSuite) SetUpSuite(c *check.C) { + s.createComposeProject(c, "consul") +} + +// Marathon test suites (using libcompose) +type MarathonSuite struct{ BaseSuite } + +func (s *MarathonSuite) SetUpSuite(c *check.C) { + s.createComposeProject(c, "marathon") +} + +type BaseSuite struct { + composeProject *project.Project + listenChan chan project.ProjectEvent + started chan bool + stopped chan bool + deleted chan bool +} + +func (s *BaseSuite) TearDownSuite(c *check.C) { + // shutdown and delete compose project + if s.composeProject != nil { + s.composeProject.Down() + // Waiting for libcompose#55 to be merged + // <-s.stopped + time.Sleep(2 * time.Second) + + s.composeProject.Delete() + // Waiting for libcompose#55 to be merged + // <-s.deleted + time.Sleep(2 * time.Second) + } +} + +func (s *BaseSuite) createComposeProject(c *check.C, name string) { + composeProject, err := docker.NewProject(&docker.Context{ + Context: project.Context{ + ComposeFile: fmt.Sprintf("resources/compose/%s.yml", name), + ProjectName: fmt.Sprintf("integration-test-%s", name), + }, + }) + c.Assert(err, checker.IsNil) + s.composeProject = composeProject + + s.listenChan = make(chan project.ProjectEvent) + go s.startListening(c) + + composeProject.AddListener(s.listenChan) + + composeProject.Start() + + // FIXME Wait for compose to start + // Waiting for libcompose#55 to be merged + // <-s.started + time.Sleep(2 * time.Second) + +} + +func (s *BaseSuite) startListening(c *check.C) { + for event := range s.listenChan { + // FIXME Remove this when it's working (libcompose#55) + // fmt.Fprintf(os.Stdout, "Event: %s (%v)\n", event.Event, event) + // FIXME Add a timeout on event + if event.Event == project.PROJECT_UP_DONE { + s.started <- true + } + if event.Event == project.PROJECT_DOWN_DONE { + s.stopped <- true + } + if event.Event == project.PROJECT_DELETE_DONE { + s.deleted <- true + } + } +} diff --git a/integration/marathon_test.go b/integration/marathon_test.go new file mode 100644 index 000000000..0c223357d --- /dev/null +++ b/integration/marathon_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "net/http" + "os/exec" + "time" + + checker "github.com/vdemeester/shakers" + check "gopkg.in/check.v1" +) + +func (s *MarathonSuite) TestSimpleConfiguration(c *check.C) { + cmd := exec.Command(traefikBinary, "fixtures/consul/simple.toml") + err := cmd.Start() + c.Assert(err, checker.IsNil) + + time.Sleep(100 * time.Millisecond) + // TODO validate : run on 80 + resp, err := http.Get("http://127.0.0.1/") + + // Expected a 404 as we did not comfigure anything + c.Assert(err, checker.IsNil) + c.Assert(resp.StatusCode, checker.Equals, 404) + + killErr := cmd.Process.Kill() + c.Assert(killErr, checker.IsNil) +} diff --git a/integration/resources/compose/consul.yml b/integration/resources/compose/consul.yml new file mode 100644 index 000000000..83f30b7a9 --- /dev/null +++ b/integration/resources/compose/consul.yml @@ -0,0 +1,21 @@ +consul: + image: progrium/consul + command: -server -bootstrap -advertise 12.0.0.254 -log-level debug -ui-dir /ui + ports: + - "8400:8400" + - "8500:8500" + - "8600:53/udp" + expose: + - "8300" + - "8301" + - "8301/udp" + - "8302" + - "8302/udp" + +registrator: + image: gliderlabs/registrator:master + command: -internal consulkv://consul:8500/traefik + volumes: + - /var/run/docker.sock:/tmp/docker.sock + links: + - consul \ No newline at end of file diff --git a/integration/resources/compose/file.yml b/integration/resources/compose/file.yml new file mode 100644 index 000000000..acd082616 --- /dev/null +++ b/integration/resources/compose/file.yml @@ -0,0 +1,20 @@ +nginx1: + image: nginx + ports: + - "8881:80" +nginx2: + image: nginx + ports: + - "8882:80" +nginx3: + image: nginx + ports: + - "8883:80" +nginx4: + image: nginx + ports: + - "8884:80" +nginx5: + image: nginx + ports: + - "8885:80" diff --git a/integration/resources/compose/marathon.yml b/integration/resources/compose/marathon.yml new file mode 100644 index 000000000..91685e963 --- /dev/null +++ b/integration/resources/compose/marathon.yml @@ -0,0 +1,42 @@ +zk: + image: bobrik/zookeeper + net: host + environment: + ZK_CONFIG: tickTime=2000,initLimit=10,syncLimit=5,maxClientCnxns=128,forceSync=no,clientPort=2181 + ZK_ID: 1 + +master: + image: mesosphere/mesos-master:0.23.0-1.0.ubuntu1404 + net: host + environment: + MESOS_ZK: zk://127.0.0.1:2181/mesos + MESOS_HOSTNAME: 127.0.0.1 + MESOS_IP: 127.0.0.1 + MESOS_QUORUM: 1 + MESOS_CLUSTER: docker-compose + MESOS_WORK_DIR: /var/lib/mesos + +slave: + image: mesosphere/mesos-slave:0.23.0-1.0.ubuntu1404 + net: host + pid: host + privileged: true + environment: + MESOS_MASTER: zk://127.0.0.1:2181/mesos + MESOS_HOSTNAME: 127.0.0.1 + MESOS_IP: 127.0.0.1 + MESOS_CONTAINERIZERS: docker,mesos + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup + - /usr/bin/docker:/usr/bin/docker:ro + - /usr/lib/x86_64-linux-gnu/libapparmor.so.1:/usr/lib/x86_64-linux-gnu/libapparmor.so.1:ro + - /var/run/docker.sock:/var/run/docker.sock + +marathon: + image: mesosphere/marathon:v0.9.2 + net: host + environment: + MARATHON_MASTER: zk://127.0.0.1:2181/mesos + MARATHON_ZK: zk://127.0.0.1:2181/marathon + MARATHON_HOSTNAME: 127.0.0.1 + command: --event_subscriber http_callback From ecbfbd4de0f240f0780e7f1b4a3bde172fc8f396 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Mon, 28 Sep 2015 22:37:19 +0200 Subject: [PATCH 4/5] Make fixtures files template-able :) So it can adapt to certain env (like tcp vs unix socket for docker suite) Signed-off-by: Vincent Demeester --- integration/docker_test.go | 6 +- integration/fixtures/docker/simple.toml | 4 +- integration/integration_test.go | 38 ++++++++++- integration/utils/traefikCmd.go | 16 +++++ integration/utils/traefikCmd_test.go | 89 +++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 integration/utils/traefikCmd.go create mode 100644 integration/utils/traefikCmd_test.go diff --git a/integration/docker_test.go b/integration/docker_test.go index 8b031ff78..bf55414ab 100644 --- a/integration/docker_test.go +++ b/integration/docker_test.go @@ -2,6 +2,7 @@ package main import ( "net/http" + "os" "os/exec" "time" @@ -10,7 +11,10 @@ import ( ) func (s *DockerSuite) TestSimpleConfiguration(c *check.C) { - cmd := exec.Command(traefikBinary, "fixtures/docker/simple.toml") + file := s.adaptFileForHost(c, "fixtures/docker/simple.toml") + defer os.Remove(file) + + cmd := exec.Command(traefikBinary, file) err := cmd.Start() c.Assert(err, checker.IsNil) diff --git a/integration/fixtures/docker/simple.toml b/integration/fixtures/docker/simple.toml index 02f412a65..8968895c0 100644 --- a/integration/fixtures/docker/simple.toml +++ b/integration/fixtures/docker/simple.toml @@ -10,7 +10,7 @@ logLevel = "DEBUG" [docker] -# FIXME this should be "dynamic".. xD -endpoint = "tcp://172.17.42.1:2375" +# It's dynamagic ! +endpoint = "{{.DockerHost}}" domain = "docker.localhost" diff --git a/integration/integration_test.go b/integration/integration_test.go index 888d65915..cf2281520 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -3,12 +3,17 @@ package main import ( "fmt" - // "os" + "io/ioutil" + "os" + "os/exec" + "path/filepath" "testing" + "text/template" "time" "github.com/docker/libcompose/docker" "github.com/docker/libcompose/project" + "github.com/emilevauge/traefik/integration/utils" checker "github.com/vdemeester/shakers" check "gopkg.in/check.v1" @@ -128,3 +133,34 @@ func (s *BaseSuite) startListening(c *check.C) { } } } + +func (s *BaseSuite) traefikCmd(c *check.C, args ...string) (*exec.Cmd, string) { + cmd, out, err := utils.RunCommand(traefikBinary, args...) + c.Assert(err, checker.IsNil, check.Commentf("Fail to run %s with %v", traefikBinary, args)) + return cmd, out +} + +func (s *BaseSuite) adaptFileForHost(c *check.C, path string) string { + dockerHost := os.Getenv("DOCKER_HOST") + if dockerHost == "" { + // Default docker socket + dockerHost = "unix:///var/run/docker.sock" + } + + // Load file + tmpl, err := template.ParseFiles(path) + c.Assert(err, checker.IsNil) + + folder, prefix := filepath.Split(path) + tmpFile, err := ioutil.TempFile(folder, prefix) + c.Assert(err, checker.IsNil) + defer tmpFile.Close() + + err = tmpl.ExecuteTemplate(tmpFile, prefix, struct{ DockerHost string }{dockerHost}) + c.Assert(err, checker.IsNil) + err = tmpFile.Sync() + + c.Assert(err, checker.IsNil) + + return tmpFile.Name() +} diff --git a/integration/utils/traefikCmd.go b/integration/utils/traefikCmd.go new file mode 100644 index 000000000..4e43fca89 --- /dev/null +++ b/integration/utils/traefikCmd.go @@ -0,0 +1,16 @@ +package utils + +import ( + "os/exec" +) + +var execCommand = exec.Command + +// RunCommand runs the specified command with arguments and returns +// the output and the error if any. +func RunCommand(binary string, args ...string) (*exec.Cmd, string, error) { + cmd := execCommand(binary, args...) + out, err := cmd.CombinedOutput() + output := string(out) + return cmd, output, err +} diff --git a/integration/utils/traefikCmd_test.go b/integration/utils/traefikCmd_test.go new file mode 100644 index 000000000..9a5965586 --- /dev/null +++ b/integration/utils/traefikCmd_test.go @@ -0,0 +1,89 @@ +package utils + +import ( + "fmt" + "os" + "os/exec" + "strings" + "testing" +) + +var traefikBinary = "traefik" + +func TestRunCommand(t *testing.T) { + // Override exec.Command :D + execCommand = fakeExecCommand + _, output, err := RunCommand(traefikBinary, "it", "works") + if err != nil { + t.Fatal(err) + } + if output != "it works" { + t.Fatalf("Expected 'it works' as output, got : %q", output) + } +} + +func TestRunCommandError(t *testing.T) { + // Override exec.Command :D + execCommand = fakeExecCommand + _, output, err := RunCommand(traefikBinary, "an", "error") + if err == nil { + t.Fatalf("Expected an error, got %q", output) + } +} + +// Helpers :) + +// Type implementing the io.Writer interface for analyzing output. +type String struct { + value string +} + +// The only function required by the io.Writer interface. Will append +// written data to the String.value string. +func (s *String) Write(p []byte) (n int, err error) { + s.value += string(p) + return len(p), nil +} + +// Helper function that mock the exec.Command call (and call the test binary) +func fakeExecCommand(command string, args ...string) *exec.Cmd { + cs := []string{"-test.run=TestHelperProcess", "--", command} + cs = append(cs, args...) + cmd := exec.Command(os.Args[0], cs...) + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + return cmd +} + +func TestHelperProcess(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + args := os.Args + + // Previous arguments are tests stuff, that looks like : + // /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess -- + cmd, args := args[3], args[4:] + // Handle the case where args[0] is dir:... + + switch cmd { + case traefikBinary: + argsStr := strings.Join(args, " ") + switch argsStr { + case "an exitCode 127": + fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127") + os.Exit(127) + case "an error": + fmt.Fprintf(os.Stderr, "an error has occurred") + os.Exit(1) + case "it works": + fmt.Fprintf(os.Stdout, "it works") + default: + fmt.Fprintf(os.Stdout, "no arguments") + } + default: + fmt.Fprintf(os.Stderr, "Command %s not found.", cmd) + os.Exit(1) + } + // some code here to check arguments perhaps? + os.Exit(0) +} From c088fdefa1b420f15d0833a552317a3e9749f43c Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Mon, 28 Sep 2015 23:16:52 +0200 Subject: [PATCH 5/5] =?UTF-8?q?Use=20curl=20to=20wait=20for=20docker=20to?= =?UTF-8?q?=20be=20up=20on=20circleci=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … <3 @emilevauge :D Signed-off-by: Vincent Demeester --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 1665e6c79..d0a2d6a1a 100644 --- a/circle.yml +++ b/circle.yml @@ -2,7 +2,7 @@ machine: pre: - sudo docker -d -e lxc -s btrfs -H tcp://0.0.0.0:2375: background: true - - sleep 5 + - curl --retry 15 --retry-delay 3 -v http://172.17.42.1:2375/version environment: REPO: $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME DOCKER_HOST: tcp://172.17.42.1:2375