refactor: Deflake and Try package

- feat: add CI multiplier
- refactor: readability
- feat: custom Sleep function
- refactor(integration): use custom Sleep
- feat: show Try progress
- feat(try): try response with status code
- refactor(try): use a dedicate package.
- refactor(integration): Try everywhere
- feat(CI): pass CI env var to Integration Tests.
- refactor(acme): increase timeout.
- feat(acme): show Traefik logs
- refactor(integration): use `http.StatusXXX`
- refactor: remove Sleep
This commit is contained in:
Fernandez Ludovic 2017-05-17 15:22:44 +02:00 committed by Ludovic Fernandez
parent ff3481f06b
commit 2610023131
25 changed files with 751 additions and 613 deletions

View file

@ -7,7 +7,8 @@ TRAEFIK_ENVS := \
-e VERBOSE \
-e VERSION \
-e CODENAME \
-e TESTDIRS
-e TESTDIRS \
-e CI
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/' | grep -v '^integration/vendor/')

View file

@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
shellwords "github.com/mattn/go-shellwords"
@ -31,10 +32,17 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) {
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
defer os.Remove("access.log")
defer os.Remove("traefik.log")
time.Sleep(500 * time.Millisecond)
err = try.Do(1*time.Second, func() error {
if _, err := os.Stat("traefik.log"); err != nil {
return fmt.Errorf("could not get stats for log file: %s", err)
}
return nil
})
c.Assert(err, checker.IsNil)
// Verify Traefik started OK
traefikLog, err := ioutil.ReadFile("traefik.log")
@ -53,11 +61,11 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) {
defer ts3.Close()
// Make some requests
_, err = http.Get("http://127.0.0.1:8000/test1")
err = try.GetRequest("http://127.0.0.1:8000/test1", 500*time.Millisecond)
c.Assert(err, checker.IsNil)
_, err = http.Get("http://127.0.0.1:8000/test2")
err = try.GetRequest("http://127.0.0.1:8000/test2", 500*time.Millisecond)
c.Assert(err, checker.IsNil)
_, err = http.Get("http://127.0.0.1:8000/test2")
err = try.GetRequest("http://127.0.0.1:8000/test2", 500*time.Millisecond)
c.Assert(err, checker.IsNil)
// Verify access.log output as expected
@ -71,14 +79,14 @@ func (s *AccessLogSuite) TestAccessLog(c *check.C) {
tokens, err := shellwords.Parse(line)
c.Assert(err, checker.IsNil)
c.Assert(len(tokens), checker.Equals, 13)
c.Assert(tokens[6], checker.Equals, "200")
c.Assert(regexp.MustCompile(`^\d{3}$`).MatchString(tokens[6]), checker.True)
c.Assert(tokens[9], checker.Equals, fmt.Sprintf("%d", i+1))
c.Assert(strings.HasPrefix(tokens[10], "frontend"), checker.True)
c.Assert(strings.HasPrefix(tokens[11], "http://127.0.0.1:808"), checker.True)
c.Assert(regexp.MustCompile("^\\d+ms$").MatchString(tokens[12]), checker.True)
c.Assert(regexp.MustCompile(`^\d+ms$`).MatchString(tokens[12]), checker.True)
}
}
c.Assert(count, checker.Equals, 3)
c.Assert(count, checker.GreaterOrEqualThan, 3)
// Verify no other Traefik problems
traefikLog, err = ioutil.ReadFile("traefik.log")

View file

@ -4,39 +4,27 @@ import (
"crypto/tls"
"net/http"
"os"
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
"errors"
"github.com/containous/traefik/integration/utils"
checker "github.com/vdemeester/shakers"
)
// ACME test suites (using libcompose)
type AcmeSuite struct {
BaseSuite
boulderIP string
}
func (s *AcmeSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "boulder")
s.composeProject.Start(c)
boulderHost := s.composeProject.Container(c, "boulder").NetworkSettings.IPAddress
s.boulderIP = s.composeProject.Container(c, "boulder").NetworkSettings.IPAddress
// wait for boulder
err := utils.Try(120*time.Second, func() error {
resp, err := http.Get("http://" + boulderHost + ":4000/directory")
if err != nil {
return err
}
if resp.StatusCode != 200 {
return errors.New("Expected http 200 from boulder")
}
return nil
})
err := try.GetRequest("http://"+s.boulderIP+":4000/directory", 120*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
@ -48,15 +36,15 @@ func (s *AcmeSuite) TearDownSuite(c *check.C) {
}
func (s *AcmeSuite) TestRetrieveAcmeCertificate(c *check.C) {
boulderHost := s.composeProject.Container(c, "boulder").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/acme/acme.toml", struct{ BoulderHost string }{boulderHost})
file := s.adaptFile(c, "fixtures/acme/acme.toml", struct{ BoulderHost string }{s.boulderIP})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
cmd, output := s.cmdTraefikWithConfigFile(file)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
backend := startTestServer("9010", 200)
backend := startTestServer("9010", http.StatusOK)
defer backend.Close()
tr := &http.Transport{
@ -65,13 +53,12 @@ func (s *AcmeSuite) TestRetrieveAcmeCertificate(c *check.C) {
client := &http.Client{Transport: tr}
// wait for traefik (generating acme account take some seconds)
err = utils.Try(30*time.Second, func() error {
err = try.Do(90*time.Second, func() error {
_, err := client.Get("https://127.0.0.1:5001")
if err != nil {
return err
}
return nil
})
// TODO: waiting a refactor of integration tests
s.displayTraefikLog(c, output)
c.Assert(err, checker.IsNil)
tr = &http.Transport{
@ -88,5 +75,5 @@ func (s *AcmeSuite) TestRetrieveAcmeCertificate(c *check.C) {
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
// Expected a 200
c.Assert(resp.StatusCode, checker.Equals, 200)
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
}

View file

@ -1,13 +1,15 @@
package main
import (
"bytes"
"fmt"
"net/http"
"os/exec"
"strings"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
"bytes"
checker "github.com/vdemeester/shakers"
)
@ -21,41 +23,45 @@ func (s *SimpleSuite) TestInvalidConfigShouldFail(c *check.C) {
cmd.Stdout = &b
cmd.Stderr = &b
cmd.Start()
time.Sleep(500 * time.Millisecond)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
output := b.Bytes()
c.Assert(string(output), checker.Contains, "Near line 0 (last key parsed ''): bare keys cannot contain '{'")
err = try.Do(500*time.Millisecond, func() error {
expected := "Near line 0 (last key parsed ''): bare keys cannot contain '{'"
actual := b.String()
if !strings.Contains(actual, expected) {
return fmt.Errorf("Got %s, wanted %s", actual, expected)
}
return nil
})
c.Assert(err, checker.IsNil)
}
func (s *SimpleSuite) TestSimpleDefaultConfig(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_default.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// TODO validate : run on 80
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *SimpleSuite) TestWithWebConfig(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_web.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
resp, err := http.Get("http://127.0.0.1:8080/api")
// Expected a 200
err = try.GetRequest("http://127.0.0.1:8080/api", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
}
func (s *SimpleSuite) TestDefaultEntryPoints(c *check.C) {
@ -65,12 +71,21 @@ func (s *SimpleSuite) TestDefaultEntryPoints(c *check.C) {
cmd.Stdout = &b
cmd.Stderr = &b
cmd.Start()
time.Sleep(500 * time.Millisecond)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
output := b.Bytes()
c.Assert(string(output), checker.Contains, "\"DefaultEntryPoints\":[\"http\"]")
err = try.Do(500*time.Millisecond, func() error {
expected := "\"DefaultEntryPoints\":[\"http\"]"
actual := b.String()
if !strings.Contains(actual, expected) {
return fmt.Errorf("Got %s, wanted %s", actual, expected)
}
return nil
})
c.Assert(err, checker.IsNil)
}
func (s *SimpleSuite) TestPrintHelp(c *check.C) {
@ -80,11 +95,23 @@ func (s *SimpleSuite) TestPrintHelp(c *check.C) {
cmd.Stdout = &b
cmd.Stderr = &b
cmd.Start()
time.Sleep(500 * time.Millisecond)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
output := b.Bytes()
c.Assert(string(output), checker.Not(checker.Contains), "panic:")
c.Assert(string(output), checker.Contains, "Usage:")
err = try.Do(500*time.Millisecond, func() error {
expected := "Usage:"
notExpected := "panic:"
actual := b.String()
if strings.Contains(actual, notExpected) {
return fmt.Errorf("Got %s", actual)
}
if !strings.Contains(actual, expected) {
return fmt.Errorf("Got %s, wanted %s", actual, expected)
}
return nil
})
c.Assert(err, checker.IsNil)
}

View file

@ -1,13 +1,14 @@
package main
import (
"fmt"
"net/http"
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
"github.com/hashicorp/consul/api"
checker "github.com/vdemeester/shakers"
)
@ -35,7 +36,16 @@ func (s *ConstraintSuite) SetUpSuite(c *check.C) {
s.consulClient = consulClient
// Wait for consul to elect itself leader
time.Sleep(2000 * time.Millisecond)
err = try.Do(3*time.Second, func() error {
leader, err := consulClient.Status().Leader()
if err != nil || len(leader) == 0 {
return fmt.Errorf("Leader not found. %v", err)
}
return nil
})
c.Assert(err, checker.IsNil)
}
func (s *ConstraintSuite) registerService(name string, address string, port int, tags []string) error {
@ -71,7 +81,12 @@ func (s *ConstraintSuite) deregisterService(name string, address string) error {
}
func (s *ConstraintSuite) TestMatchConstraintGlobal(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml", "--constraints=tag==api")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml",
"--constraints=tag==api")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -82,19 +97,21 @@ func (s *ConstraintSuite) TestMatchConstraintGlobal(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
}
func (s *ConstraintSuite) TestDoesNotMatchConstraintGlobal(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml", "--constraints=tag==api")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml",
"--constraints=tag==api")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -105,19 +122,21 @@ func (s *ConstraintSuite) TestDoesNotMatchConstraintGlobal(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *ConstraintSuite) TestMatchConstraintProvider(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml", "--consulCatalog.constraints=tag==api")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml",
"--consulCatalog.constraints=tag==api")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -128,19 +147,21 @@ func (s *ConstraintSuite) TestMatchConstraintProvider(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
}
func (s *ConstraintSuite) TestDoesNotMatchConstraintProvider(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml", "--consulCatalog.constraints=tag==api")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml",
"--consulCatalog.constraints=tag==api")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -151,19 +172,22 @@ func (s *ConstraintSuite) TestDoesNotMatchConstraintProvider(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *ConstraintSuite) TestMatchMultipleConstraint(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml", "--consulCatalog.constraints=tag==api", "--constraints=tag!=us-*")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml",
"--consulCatalog.constraints=tag==api",
"--constraints=tag!=us-*")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -174,19 +198,22 @@ func (s *ConstraintSuite) TestMatchMultipleConstraint(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
}
func (s *ConstraintSuite) TestDoesNotMatchMultipleConstraint(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml", "--consulCatalog.constraints=tag==api", "--constraints=tag!=us-*")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml",
"--consulCatalog.constraints=tag==api",
"--constraints=tag!=us-*")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -197,13 +224,10 @@ func (s *ConstraintSuite) TestDoesNotMatchMultipleConstraint(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View file

@ -1,14 +1,14 @@
package main
import (
"io/ioutil"
"fmt"
"net/http"
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
"github.com/hashicorp/consul/api"
checker "github.com/vdemeester/shakers"
)
@ -31,12 +31,21 @@ func (s *ConsulCatalogSuite) SetUpSuite(c *check.C) {
config.Address = s.consulIP + ":8500"
consulClient, err := api.NewClient(config)
if err != nil {
c.Fatalf("Error creating consul client")
c.Fatalf("Error creating consul client. %v", err)
}
s.consulClient = consulClient
// Wait for consul to elect itself leader
time.Sleep(2000 * time.Millisecond)
err = try.Do(3*time.Second, func() error {
leader, err := consulClient.Status().Leader()
if err != nil || len(leader) == 0 {
return fmt.Errorf("Leader not found. %v", err)
}
return nil
})
c.Assert(err, checker.IsNil)
}
func (s *ConsulCatalogSuite) registerService(name string, address string, port int, tags []string) error {
@ -72,22 +81,26 @@ func (s *ConsulCatalogSuite) deregisterService(name string, address string) erro
}
func (s *ConsulCatalogSuite) TestSimpleConfiguration(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--configFile=fixtures/consul_catalog/simple.toml")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--configFile=fixtures/consul_catalog/simple.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// TODO validate : run on 80
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *ConsulCatalogSuite) TestSingleService(c *check.C) {
cmd := exec.Command(traefikBinary, "--consulCatalog", "--consulCatalog.endpoint="+s.consulIP+":8500", "--consulCatalog.domain=consul.localhost", "--configFile=fixtures/consul_catalog/simple.toml")
cmd := exec.Command(traefikBinary,
"--consulCatalog",
"--consulCatalog.endpoint="+s.consulIP+":8500",
"--consulCatalog.domain=consul.localhost",
"--configFile=fixtures/consul_catalog/simple.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
@ -98,16 +111,10 @@ func (s *ConsulCatalogSuite) TestSingleService(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("Error registering service"))
defer s.deregisterService("test", nginx.NetworkSettings.IPAddress)
time.Sleep(5000 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.consul.localhost"
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
_, err = ioutil.ReadAll(resp.Body)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
}

View file

@ -2,18 +2,16 @@ package main
import (
"context"
"errors"
"io/ioutil"
"fmt"
"net/http"
"os"
"os/exec"
"strings"
"sync"
"time"
"github.com/containous/staert"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/provider"
"github.com/docker/libkv"
"github.com/docker/libkv/store"
@ -46,13 +44,7 @@ func (s *ConsulSuite) setupConsul(c *check.C) {
s.kv = kv
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := kv.Exists("test")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
@ -85,13 +77,7 @@ func (s *ConsulSuite) setupConsulTLS(c *check.C) {
s.kv = kv
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := kv.Exists("test")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
@ -109,17 +95,15 @@ func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulHost string }{consulHost})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *ConsulSuite) TestNominalConfiguration(c *check.C) {
@ -127,28 +111,29 @@ func (s *ConsulSuite) TestNominalConfiguration(c *check.C) {
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulHost string }{consulHost})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
whoami1 := s.composeProject.Container(c, "whoami1")
whoami2 := s.composeProject.Container(c, "whoami2")
whoami3 := s.composeProject.Container(c, "whoami3")
whoami4 := s.composeProject.Container(c, "whoami4")
whoami1IP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2IP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
whoami3IP := s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress
whoami4IP := s.composeProject.Container(c, "whoami4").NetworkSettings.IPAddress
backend1 := map[string]string{
"traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
"traefik/backends/backend1/servers/server1/url": "http://" + whoami1.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend1/servers/server1/url": "http://" + whoami1IP + ":80",
"traefik/backends/backend1/servers/server1/weight": "10",
"traefik/backends/backend1/servers/server2/url": "http://" + whoami2.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend1/servers/server2/url": "http://" + whoami2IP + ":80",
"traefik/backends/backend1/servers/server2/weight": "1",
}
backend2 := map[string]string{
"traefik/backends/backend2/loadbalancer/method": "drr",
"traefik/backends/backend2/servers/server1/url": "http://" + whoami3.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend2/servers/server1/url": "http://" + whoami3IP + ":80",
"traefik/backends/backend2/servers/server1/weight": "1",
"traefik/backends/backend2/servers/server2/url": "http://" + whoami4.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend2/servers/server2/url": "http://" + whoami4IP + ":80",
"traefik/backends/backend2/servers/server2/weight": "2",
}
frontend1 := map[string]string{
@ -181,68 +166,38 @@ func (s *ConsulSuite) TestNominalConfiguration(c *check.C) {
}
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := s.kv.Exists("traefik/frontends/frontend2/routes/test_2/rule")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(s.kv, "traefik/frontends/frontend2/routes/test_2/rule"))
c.Assert(err, checker.IsNil)
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Path:/test") {
return errors.New("Incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains("Path:/test"))
c.Assert(err, checker.IsNil)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.localhost"
response, err := client.Do(req)
err = try.Request(req, 500*time.Millisecond,
try.StatusCodeIs(200),
try.BodyContainsOr(whoami3IP, whoami4IP))
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
body, err := ioutil.ReadAll(response.Body)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/test", nil)
c.Assert(err, checker.IsNil)
if !strings.Contains(string(body), whoami3.NetworkSettings.IPAddress) &&
!strings.Contains(string(body), whoami4.NetworkSettings.IPAddress) {
c.Fail()
}
req, err = http.NewRequest("GET", "http://127.0.0.1:8000/test", nil)
err = try.Request(req, 500*time.Millisecond,
try.StatusCodeIs(200),
try.BodyContainsOr(whoami1IP, whoami2IP))
c.Assert(err, checker.IsNil)
response, err = client.Do(req)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/test2", nil)
try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
body, err = ioutil.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
if !strings.Contains(string(body), whoami1.NetworkSettings.IPAddress) &&
!strings.Contains(string(body), whoami2.NetworkSettings.IPAddress) {
c.Fail()
}
req, err = http.NewRequest("GET", "http://127.0.0.1:8000/test2", nil)
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
req, err = http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
req.Host = "test2.localhost"
resp, err = client.Do(req)
try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *ConsulSuite) TestGlobalConfiguration(c *check.C) {
@ -252,41 +207,33 @@ func (s *ConsulSuite) TestGlobalConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := s.kv.Exists("traefik/entrypoints/http/address")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(s.kv, "traefik/entrypoints/http/address"))
c.Assert(err, checker.IsNil)
// start traefik
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_web.toml", "--consul", "--consul.endpoint="+consulHost+":8500")
// cmd.Stdout = os.Stdout
// cmd.Stderr = os.Stderr
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
whoami1 := s.composeProject.Container(c, "whoami1")
whoami2 := s.composeProject.Container(c, "whoami2")
whoami3 := s.composeProject.Container(c, "whoami3")
whoami4 := s.composeProject.Container(c, "whoami4")
whoami1IP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2IP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
whoami3IP := s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress
whoami4IP := s.composeProject.Container(c, "whoami4").NetworkSettings.IPAddress
backend1 := map[string]string{
"traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
"traefik/backends/backend1/servers/server1/url": "http://" + whoami1.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend1/servers/server1/url": "http://" + whoami1IP + ":80",
"traefik/backends/backend1/servers/server1/weight": "10",
"traefik/backends/backend1/servers/server2/url": "http://" + whoami2.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend1/servers/server2/url": "http://" + whoami2IP + ":80",
"traefik/backends/backend1/servers/server2/weight": "1",
}
backend2 := map[string]string{
"traefik/backends/backend2/loadbalancer/method": "drr",
"traefik/backends/backend2/servers/server1/url": "http://" + whoami3.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend2/servers/server1/url": "http://" + whoami3IP + ":80",
"traefik/backends/backend2/servers/server1/weight": "1",
"traefik/backends/backend2/servers/server2/url": "http://" + whoami4.NetworkSettings.IPAddress + ":80",
"traefik/backends/backend2/servers/server2/url": "http://" + whoami4IP + ":80",
"traefik/backends/backend2/servers/server2/weight": "2",
}
frontend1 := map[string]string{
@ -319,37 +266,20 @@ func (s *ConsulSuite) TestGlobalConfiguration(c *check.C) {
}
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := s.kv.Exists("traefik/frontends/frontend2/routes/test_2/rule")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(s.kv, "traefik/frontends/frontend2/routes/test_2/rule"))
c.Assert(err, checker.IsNil)
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Path:/test") {
return errors.New("Incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Path:/test"))
c.Assert(err, checker.IsNil)
//check
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8001/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8001/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.localhost"
response, err := client.Do(req)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
}
func (s *ConsulSuite) skipTestGlobalConfigurationWithClientTLS(c *check.C) {
@ -361,13 +291,7 @@ func (s *ConsulSuite) skipTestGlobalConfigurationWithClientTLS(c *check.C) {
c.Assert(err, checker.IsNil)
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := s.kv.Exists("traefik/web/address")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(s.kv, "traefik/web/address"))
c.Assert(err, checker.IsNil)
// start traefik
@ -377,29 +301,24 @@ func (s *ConsulSuite) skipTestGlobalConfigurationWithClientTLS(c *check.C) {
"--consul.tls.cert=resources/tls/consul.cert",
"--consul.tls.key=resources/tls/consul.key",
"--consul.tls.insecureskipverify")
// cmd.Stdout = os.Stdout
// cmd.Stderr = os.Stderr
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, func(res *http.Response) error {
_, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second)
c.Assert(err, checker.IsNil)
}
func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
s.setupConsul(c)
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
cmd := exec.Command(traefikBinary, "storeconfig", "--configFile=fixtures/simple_web.toml", "--consul.endpoint="+consulHost+":8500")
cmd := exec.Command(traefikBinary,
"storeconfig",
"--configFile=fixtures/simple_web.toml",
"--consul.endpoint="+consulHost+":8500")
err := cmd.Start()
c.Assert(err, checker.IsNil)
@ -412,22 +331,18 @@ func (s *ConsulSuite) TestCommandStoreConfig(c *check.C) {
"/traefik/defaultentrypoints/0": "http",
"/traefik/entrypoints/http/address": ":8000",
"/traefik/web/address": ":8080",
"/traefik/consul/endpoint": (consulHost + ":8500"),
"/traefik/consul/endpoint": consulHost + ":8500",
}
for key, value := range checkmap {
var p *store.KVPair
err = utils.Try(60*time.Second, func() error {
err = try.Do(60*time.Second, func() error {
p, err = s.kv.Get(key)
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
c.Assert(string(p.Value), checker.Equals, value)
}
}
@ -457,12 +372,12 @@ func (s *ConsulSuite) TestDatastore(c *check.C) {
Int: 1,
})
c.Assert(err, checker.IsNil)
time.Sleep(2 * time.Second)
test1 := datastore1.Get().(*TestStruct)
c.Assert(test1.String, checker.Equals, "foo")
test2 := datastore2.Get().(*TestStruct)
c.Assert(test2.String, checker.Equals, "foo")
err = try.Do(3*time.Second, datastoreContains(datastore1, "foo"))
c.Assert(err, checker.IsNil)
err = try.Do(3*time.Second, datastoreContains(datastore2, "foo"))
c.Assert(err, checker.IsNil)
setter2, _, err := datastore2.Begin()
c.Assert(err, checker.IsNil)
@ -471,12 +386,12 @@ func (s *ConsulSuite) TestDatastore(c *check.C) {
Int: 2,
})
c.Assert(err, checker.IsNil)
time.Sleep(2 * time.Second)
test1 = datastore1.Get().(*TestStruct)
c.Assert(test1.String, checker.Equals, "bar")
test2 = datastore2.Get().(*TestStruct)
c.Assert(test2.String, checker.Equals, "bar")
err = try.Do(3*time.Second, datastoreContains(datastore1, "bar"))
c.Assert(err, checker.IsNil)
err = try.Do(3*time.Second, datastoreContains(datastore2, "bar"))
c.Assert(err, checker.IsNil)
wg := &sync.WaitGroup{}
wg.Add(4)
@ -520,3 +435,13 @@ func (s *ConsulSuite) TestDatastore(c *check.C) {
}()
wg.Wait()
}
func datastoreContains(datastore *cluster.Datastore, expectedValue string) func() error {
return func() error {
kvStruct := datastore.Get().(*TestStruct)
if kvStruct.String != expectedValue {
return fmt.Errorf("Got %s, wanted %s", kvStruct.String, expectedValue)
}
return nil
}
}

View file

@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/containous/traefik/integration/try"
"github.com/docker/docker/pkg/namesgenerator"
"github.com/go-check/check"
@ -84,13 +85,10 @@ func (s *DockerSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// TODO validate : run on 80
resp, err := http.Get("http://127.0.0.1:8000/")
c.Assert(err, checker.IsNil)
// Expected a 404 as we did not comfigure anything
c.Assert(resp.StatusCode, checker.Equals, 404)
err = try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(404))
c.Assert(err, checker.IsNil)
}
func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
@ -104,17 +102,13 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
time.Sleep(1500 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/version", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
req.Host = fmt.Sprintf("%s.docker.localhost", strings.Replace(name, "_", "-", -1))
resp, err := client.Do(req)
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, 200)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
body, err := ioutil.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
@ -140,17 +134,13 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
req.Host = "my.super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
time.Sleep(1500 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/version", nil)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
req.Host = fmt.Sprintf("my.super.host")
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
body, err := ioutil.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
@ -176,15 +166,13 @@ func (s *DockerSuite) TestDockerContainersWithOneMissingLabels(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
req.Host = "my.super.host"
// FIXME Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
time.Sleep(1500 * time.Millisecond)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/version", nil)
// TODO validate : run on 80
// Expected a 404 as we did not comfigure anything
err = try.Request(req, 1500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
req.Host = fmt.Sprintf("my.super.host")
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View file

@ -1,12 +1,9 @@
package main
import (
"errors"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
@ -14,7 +11,7 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/integration/try"
"github.com/containous/traefik/types"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
@ -49,7 +46,7 @@ func (s *DynamoDBSuite) SetUpSuite(c *check.C) {
Endpoint: aws.String(dynamoURL),
}
var sess *session.Session
err := utils.Try(60*time.Second, func() error {
err := try.Do(60*time.Second, func() error {
_, err := session.NewSession(config)
if err != nil {
return err
@ -154,24 +151,16 @@ func (s *DynamoDBSuite) TestSimpleConfiguration(c *check.C) {
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = utils.TryRequest("http://127.0.0.1:8081/api/providers", 120*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Host:test.traefik.io") {
return errors.New("incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 120*time.Second, try.BodyContains("Host:test.traefik.io"))
c.Assert(err, checker.IsNil)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8080", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.traefik.io"
response, err := client.Do(req)
err = try.Request(req, 200*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
}
func (s *DynamoDBSuite) TearDownSuite(c *check.C) {

View file

@ -1,23 +1,21 @@
package main
import (
"github.com/go-check/check"
"crypto/tls"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
checker "github.com/vdemeester/shakers"
"crypto/tls"
"errors"
"fmt"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/integration/try"
"github.com/docker/libkv"
"github.com/docker/libkv/store"
"github.com/docker/libkv/store/etcd"
"io/ioutil"
"os"
"strings"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
// Etcd test suites (using libcompose)
@ -45,12 +43,9 @@ func (s *EtcdSuite) SetUpTest(c *check.C) {
s.kv = kv
// wait for etcd
err = utils.Try(60*time.Second, func() error {
err = try.Do(60*time.Second, func() error {
_, err := kv.Exists("test")
if err != nil {
return fmt.Errorf("Etcd connection error to %s: %v", url, err)
}
return nil
return err
})
c.Assert(err, checker.IsNil)
}
@ -73,13 +68,10 @@ func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(1000 * time.Millisecond)
// TODO validate : run on 80
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
func (s *EtcdSuite) TestNominalConfiguration(c *check.C) {
@ -91,23 +83,23 @@ func (s *EtcdSuite) TestNominalConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
whoami1 := s.composeProject.Container(c, "whoami1")
whoami2 := s.composeProject.Container(c, "whoami2")
whoami3 := s.composeProject.Container(c, "whoami3")
whoami4 := s.composeProject.Container(c, "whoami4")
whoami1IP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2IP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
whoami3IP := s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress
whoami4IP := s.composeProject.Container(c, "whoami4").NetworkSettings.IPAddress
backend1 := map[string]string{
"/traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1IP + ":80",
"/traefik/backends/backend1/servers/server1/weight": "10",
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2IP + ":80",
"/traefik/backends/backend1/servers/server2/weight": "1",
}
backend2 := map[string]string{
"/traefik/backends/backend2/loadbalancer/method": "drr",
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3IP + ":80",
"/traefik/backends/backend2/servers/server1/weight": "1",
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4IP + ":80",
"/traefik/backends/backend2/servers/server2/weight": "2",
}
frontend1 := map[string]string{
@ -140,68 +132,55 @@ func (s *EtcdSuite) TestNominalConfiguration(c *check.C) {
}
// wait for etcd
err = utils.Try(60*time.Second, func() error {
err = try.Do(60*time.Second, func() error {
_, err := s.kv.Exists("/traefik/frontends/frontend2/routes/test_2/rule")
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Path:/test") {
return errors.New("Incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, try.BodyContains("Path:/test"))
c.Assert(err, checker.IsNil)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.localhost"
response, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
body, err := ioutil.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
if !strings.Contains(string(body), whoami3.NetworkSettings.IPAddress) &&
!strings.Contains(string(body), whoami4.NetworkSettings.IPAddress) {
if !strings.Contains(string(body), whoami3IP) &&
!strings.Contains(string(body), whoami4IP) {
c.Fail()
}
req, err = http.NewRequest("GET", "http://127.0.0.1:8000/test", nil)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/test", nil)
c.Assert(err, checker.IsNil)
response, err = client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
body, err = ioutil.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
if !strings.Contains(string(body), whoami1.NetworkSettings.IPAddress) &&
!strings.Contains(string(body), whoami2.NetworkSettings.IPAddress) {
if !strings.Contains(string(body), whoami1IP) &&
!strings.Contains(string(body), whoami2IP) {
c.Fail()
}
req, err = http.NewRequest("GET", "http://127.0.0.1:8000/test2", nil)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/test2", nil)
req.Host = "test2.localhost"
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
req, err = http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
resp, err = client.Do(req)
resp, err = http.Get("http://127.0.0.1:8000/")
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
}
func (s *EtcdSuite) TestGlobalConfiguration(c *check.C) {
@ -210,41 +189,36 @@ func (s *EtcdSuite) TestGlobalConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
// wait for etcd
err = utils.Try(60*time.Second, func() error {
err = try.Do(60*time.Second, func() error {
_, err := s.kv.Exists("/traefik/entrypoints/http/address")
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
// start traefik
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_web.toml", "--etcd", "--etcd.endpoint="+etcdHost+":4001")
// cmd.Stdout = os.Stdout
// cmd.Stderr = os.Stderr
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
whoami1 := s.composeProject.Container(c, "whoami1")
whoami2 := s.composeProject.Container(c, "whoami2")
whoami3 := s.composeProject.Container(c, "whoami3")
whoami4 := s.composeProject.Container(c, "whoami4")
whoami1IP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2IP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
whoami3IP := s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress
whoami4IP := s.composeProject.Container(c, "whoami4").NetworkSettings.IPAddress
backend1 := map[string]string{
"/traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1IP + ":80",
"/traefik/backends/backend1/servers/server1/weight": "10",
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2IP + ":80",
"/traefik/backends/backend1/servers/server2/weight": "1",
}
backend2 := map[string]string{
"/traefik/backends/backend2/loadbalancer/method": "drr",
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3IP + ":80",
"/traefik/backends/backend2/servers/server1/weight": "1",
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4IP + ":80",
"/traefik/backends/backend2/servers/server2/weight": "2",
}
frontend1 := map[string]string{
@ -277,50 +251,34 @@ func (s *EtcdSuite) TestGlobalConfiguration(c *check.C) {
}
// wait for etcd
err = utils.Try(60*time.Second, func() error {
err = try.Do(60*time.Second, func() error {
_, err := s.kv.Exists("/traefik/frontends/frontend2/routes/test_2/rule")
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Path:/test") {
return errors.New("Incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Path:/test"))
c.Assert(err, checker.IsNil)
//check
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8001/", nil)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8001/", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.localhost"
response, err := client.Do(req)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200)
}
func (s *EtcdSuite) TestCertificatesContentstWithSNIConfigHandshake(c *check.C) {
etcdHost := s.composeProject.Container(c, "etcd").NetworkSettings.IPAddress
// start traefik
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_web.toml", "--etcd", "--etcd.endpoint="+etcdHost+":4001")
// cmd.Stdout = os.Stdout
// cmd.Stderr = os.Stderr
whoami1 := s.composeProject.Container(c, "whoami1")
whoami2 := s.composeProject.Container(c, "whoami2")
whoami3 := s.composeProject.Container(c, "whoami3")
whoami4 := s.composeProject.Container(c, "whoami4")
whoami1IP := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2IP := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
whoami3IP := s.composeProject.Container(c, "whoami3").NetworkSettings.IPAddress
whoami4IP := s.composeProject.Container(c, "whoami4").NetworkSettings.IPAddress
//Copy the contents of the certificate files into ETCD
snitestComCert, err := ioutil.ReadFile("fixtures/https/snitest.com.cert")
@ -343,16 +301,16 @@ func (s *EtcdSuite) TestCertificatesContentstWithSNIConfigHandshake(c *check.C)
backend1 := map[string]string{
"/traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1IP + ":80",
"/traefik/backends/backend1/servers/server1/weight": "10",
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2IP + ":80",
"/traefik/backends/backend1/servers/server2/weight": "1",
}
backend2 := map[string]string{
"/traefik/backends/backend2/loadbalancer/method": "drr",
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3IP + ":80",
"/traefik/backends/backend2/servers/server1/weight": "1",
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4.NetworkSettings.IPAddress + ":80",
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4IP + ":80",
"/traefik/backends/backend2/servers/server2/weight": "2",
}
frontend1 := map[string]string{
@ -389,13 +347,7 @@ func (s *EtcdSuite) TestCertificatesContentstWithSNIConfigHandshake(c *check.C)
}
// wait for etcd
err = utils.Try(60*time.Second, func() error {
_, err := s.kv.Exists("/traefik/frontends/frontend2/routes/test_2/rule")
if err != nil {
return err
}
return nil
})
err = try.Do(60*time.Second, try.KVExists(s.kv, "/traefik/frontends/frontend2/routes/test_2/rule"))
c.Assert(err, checker.IsNil)
err = cmd.Start()
@ -403,16 +355,7 @@ func (s *EtcdSuite) TestCertificatesContentstWithSNIConfigHandshake(c *check.C)
defer cmd.Process.Kill()
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Host:snitest.org") {
return errors.New("Incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
//check
@ -448,21 +391,17 @@ func (s *EtcdSuite) TestCommandStoreConfig(c *check.C) {
"/traefik/defaultentrypoints/0": "http",
"/traefik/entrypoints/http/address": ":8000",
"/traefik/web/address": ":8080",
"/traefik/etcd/endpoint": (etcdHost + ":4001"),
"/traefik/etcd/endpoint": etcdHost + ":4001",
}
for key, value := range checkmap {
var p *store.KVPair
err = utils.Try(60*time.Second, func() error {
err = try.Do(60*time.Second, func() error {
p, err = s.kv.Get(key)
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
c.Assert(string(p.Value), checker.Equals, value)
}
}

View file

@ -2,8 +2,6 @@ package main
import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"os"
"os/exec"
@ -11,44 +9,43 @@ import (
"text/template"
"time"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
// Eureka test suites (using libcompose)
type EurekaSuite struct{ BaseSuite }
type EurekaSuite struct {
BaseSuite
eurekaIP string
eurekaURL string
}
func (s *EurekaSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "eureka")
s.composeProject.Start(c)
eureka := s.composeProject.Container(c, "eureka")
s.eurekaIP = eureka.NetworkSettings.IPAddress
s.eurekaURL = "http://" + s.eurekaIP + ":8761/eureka/apps"
// wait for eureka
err := try.GetRequest(s.eurekaURL, 60*time.Second)
c.Assert(err, checker.IsNil)
}
func (s *EurekaSuite) TestSimpleConfiguration(c *check.C) {
eurekaHost := s.composeProject.Container(c, "eureka").NetworkSettings.IPAddress
whoami1Host := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/eureka/simple.toml", struct{ EurekaHost string }{eurekaHost})
file := s.adaptFile(c, "fixtures/eureka/simple.toml", struct{ EurekaHost string }{s.eurekaIP})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
eurekaURL := "http://" + eurekaHost + ":8761/eureka/apps"
// wait for eureka
err = utils.TryRequest(eurekaURL, 60*time.Second, func(res *http.Response) error {
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
eurekaTemplate := `
{
"instance": {
@ -66,7 +63,7 @@ func (s *EurekaSuite) TestSimpleConfiguration(c *check.C) {
}
}`
tmpl, err := template.New("eurekaTemlate").Parse(eurekaTemplate)
tmpl, err := template.New("eurekaTemplate").Parse(eurekaTemplate)
c.Assert(err, checker.IsNil)
buf := new(bytes.Buffer)
templateVars := map[string]string{
@ -76,36 +73,28 @@ func (s *EurekaSuite) TestSimpleConfiguration(c *check.C) {
}
// add in eureka
err = tmpl.Execute(buf, templateVars)
resp, err := http.Post(eurekaURL+"/tests-integration-traefik", "application/json", strings.NewReader(buf.String()))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 204)
req, err := http.NewRequest(http.MethodPost, s.eurekaURL+"/tests-integration-traefik", strings.NewReader(buf.String()))
c.Assert(err, checker.IsNil)
req.Header.Set("Content-Type", "application/json")
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusNoContent))
c.Assert(err, checker.IsNil)
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Host:tests-integration-traefik") {
return errors.New("Incorrect traefik config")
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Host:tests-integration-traefik"))
c.Assert(err, checker.IsNil)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/", nil)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
req.Host = "tests-integration-traefik"
resp, err = client.Do(req)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
// TODO validate : run on 80
resp, err = http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View file

@ -5,8 +5,8 @@ import (
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
@ -25,12 +25,9 @@ func (s *FileSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(1000 * time.Millisecond)
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}
// #56 regression test, make sure it does not fail
@ -40,10 +37,7 @@ func (s *FileSuite) TestSimpleConfigurationNoPanic(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(1000 * time.Millisecond)
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View file

@ -14,6 +14,9 @@ defaultEntryPoints = ["https"]
CertFile = "fixtures/https/snitest.org.cert"
KeyFile = "fixtures/https/snitest.org.key"
[web]
address = ":8080"
[file]
[backends]

View file

@ -14,6 +14,9 @@ defaultEntryPoints = ["https"]
CertFile = "fixtures/https/snitest.org.cert"
KeyFile = "fixtures/https/snitest.org.key"
[web]
address = ":8080"
[file]
[backends]

View file

@ -14,6 +14,9 @@ defaultEntryPoints = ["https"]
CertFile = "fixtures/https/snitest.org.cert"
KeyFile = "fixtures/https/snitest.org.key"
[web]
address = ":8080"
[file]
[backends]

View file

@ -13,6 +13,9 @@ defaultEntryPoints = ["https"]
CertFile = "fixtures/https/snitest.org.cert"
KeyFile = "fixtures/https/snitest.org.key"
[web]
address = ":8080"
[file]
[backends]

View file

@ -2,17 +2,13 @@ package main
import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
@ -22,7 +18,6 @@ type HealthCheckSuite struct{ BaseSuite }
func (s *HealthCheckSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "healthcheck")
s.composeProject.Start(c)
}
func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
@ -42,50 +37,59 @@ func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
defer cmd.Process.Kill()
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Host:test.localhost") {
return errors.New("Incorrect traefik config: " + string(body))
}
return nil
})
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, try.BodyContains("Host:test.localhost"))
c.Assert(err, checker.IsNil)
frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)
c.Assert(err, checker.IsNil)
frontendHealthReq.Host = "test.localhost"
err = try.Request(frontendHealthReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
// Fix all whoami health to 500
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/health", nil)
whoamiHosts := []string{whoami1Host, whoami2Host}
for _, whoami := range whoamiHosts {
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+whoami+"/health", bytes.NewBuffer([]byte("500")))
c.Assert(err, checker.IsNil)
req.Host = "test.localhost"
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
}
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
// Waiting for Traefik healthcheck
try.Sleep(2 * time.Second)
resp, err = client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
healthReq, err := http.NewRequest("POST", "http://"+whoami1Host+"/health", bytes.NewBuffer([]byte("500")))
c.Assert(err, checker.IsNil)
_, err = client.Do(healthReq)
// Verify frontend health : 500
err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusInternalServerError))
c.Assert(err, checker.IsNil)
time.Sleep(time.Second * 3)
resp, err = client.Do(req)
// Change one whoami health to 200
statusOKReq1, err := http.NewRequest(http.MethodPost, "http://"+whoami1Host+"/health", bytes.NewBuffer([]byte("200")))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
resp, err = client.Do(req)
_, err = client.Do(statusOKReq1)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
// Verify frontend health : after
err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
frontendReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
frontendReq.Host = "test.localhost"
// Check if whoami1 respond
err = try.Request(frontendReq, 500*time.Millisecond, try.BodyContains(whoami1Host))
c.Assert(err, checker.IsNil)
// Check if the service with bad health check (whoami2) never respond.
err = try.Request(frontendReq, 2*time.Second, try.BodyContains(whoami2Host))
c.Assert(err, checker.Not(checker.IsNil))
// TODO validate : run on 80
resp, err = http.Get("http://127.0.0.1:8000/")
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
}

View file

@ -5,11 +5,10 @@ import (
"net"
"net/http"
"net/http/httptest"
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
@ -20,12 +19,14 @@ type HTTPSSuite struct{ BaseSuite }
// "snitest.com", which happens to match the CN of 'snitest.com.crt'. The test
// verifies that traefik presents the correct certificate.
func (s *HTTPSSuite) TestWithSNIConfigHandshake(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/https/https_sni.toml")
cmd, _ := s.cmdTraefikWithConfigFile("fixtures/https/https_sni.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
@ -51,17 +52,24 @@ func (s *HTTPSSuite) TestWithSNIConfigHandshake(c *check.C) {
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
// that traefik routes the requests to the expected backends.
func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/https/https_sni.toml")
cmd, _ := s.cmdTraefikWithConfigFile("fixtures/https/https_sni.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
backend1 := startTestServer("9010", 204)
backend2 := startTestServer("9020", 205)
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
backend1 := startTestServer("9010", http.StatusNoContent)
backend2 := startTestServer("9020", http.StatusResetContent)
defer backend1.Close()
defer backend2.Close()
time.Sleep(2000 * time.Millisecond)
err = try.GetRequest(backend1.URL, 1*time.Second, try.StatusCodeIs(http.StatusNoContent))
c.Assert(err, checker.IsNil)
err = try.GetRequest(backend2.URL, 1*time.Second, try.StatusCodeIs(http.StatusResetContent))
c.Assert(err, checker.IsNil)
tr1 := &http.Transport{
TLSClientConfig: &tls.Config{
@ -77,35 +85,39 @@ func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
}
client := &http.Client{Transport: tr1}
req, _ := http.NewRequest("GET", "https://127.0.0.1:4443/", nil)
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
c.Assert(err, checker.IsNil)
req.Host = "snitest.com"
req.Header.Set("Host", "snitest.com")
req.Header.Set("Accept", "*/*")
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
// Expected a 204 (from backend1)
c.Assert(resp.StatusCode, checker.Equals, 204)
c.Assert(resp.StatusCode, checker.Equals, http.StatusNoContent)
client = &http.Client{Transport: tr2}
req, _ = http.NewRequest("GET", "https://127.0.0.1:4443/", nil)
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
c.Assert(err, checker.IsNil)
req.Host = "snitest.org"
req.Header.Set("Host", "snitest.org")
req.Header.Set("Accept", "*/*")
resp, err = client.Do(req)
c.Assert(err, checker.IsNil)
// Expected a 205 (from backend2)
c.Assert(resp.StatusCode, checker.Equals, 205)
c.Assert(resp.StatusCode, checker.Equals, http.StatusResetContent)
}
// TestWithClientCertificateAuthentication
// The client has to send a certificate signed by a CA trusted by the server
func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/https/clientca/https_1ca1config.toml")
cmd, _ := s.cmdTraefikWithConfigFile("fixtures/https/clientca/https_1ca1config.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
@ -144,12 +156,14 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthentication(c *check.C) {
// TestWithClientCertificateAuthentication
// Use two CA:s and test that clients with client signed by either of them can connect
func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAs(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/https/clientca/https_2ca1config.toml")
cmd, _ := s.cmdTraefikWithConfigFile("fixtures/https/clientca/https_2ca1config.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 500*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
@ -201,12 +215,14 @@ func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAs(c *check.
// TestWithClientCertificateAuthentication
// Use two CA:s in two different files and test that clients with client signed by either of them can connect
func (s *HTTPSSuite) TestWithClientCertificateAuthenticationMultipeCAsMultipleFiles(c *check.C) {
cmd := exec.Command(traefikBinary, "--configFile=fixtures/https/clientca/https_2ca2config.toml")
cmd, _ := s.cmdTraefikWithConfigFile("fixtures/https/clientca/https_2ca2config.toml")
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1000*time.Millisecond, try.BodyContains("Host:snitest.org"))
c.Assert(err, checker.IsNil)
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
@ -269,5 +285,5 @@ func startTestServer(port string, statusCode int) (ts *httptest.Server) {
Config: &http.Server{Handler: handler},
}
ts.Start()
return
return ts
}

View file

@ -2,6 +2,7 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net"
@ -13,7 +14,6 @@ import (
"github.com/containous/traefik/integration/utils"
"github.com/go-check/check"
compose "github.com/libkermit/compose/check"
checker "github.com/vdemeester/shakers"
)
@ -71,12 +71,34 @@ func (s *BaseSuite) createComposeProject(c *check.C, name string) {
s.composeProject = compose.CreateProject(c, projectName, composeFile)
}
// Deprecated: unused
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) cmdTraefikWithConfigFile(file string) (*exec.Cmd, *bytes.Buffer) {
return s.cmdTraefik("--configFile=" + file)
}
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
cmd := exec.Command(traefikBinary, args...)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
return cmd, &out
}
func (s *BaseSuite) displayTraefikLog(c *check.C, output *bytes.Buffer) {
if output == nil || output.Len() == 0 {
fmt.Printf("%s: No Traefik logs present.", c.TestName())
} else {
fmt.Printf("%s: Traefik logs: ", c.TestName())
fmt.Println(output.String())
}
}
func (s *BaseSuite) adaptFileForHost(c *check.C, path string) string {
dockerHost := os.Getenv("DOCKER_HOST")
if dockerHost == "" {

View file

@ -5,8 +5,8 @@ import (
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
@ -16,18 +16,28 @@ type MarathonSuite struct{ BaseSuite }
func (s *MarathonSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "marathon")
s.composeProject.Start(c)
// wait for marathon
// err := utils.TryRequest("http://127.0.0.1:8080/ping", 60*time.Second, func(res *http.Response) error {
// body, err := ioutil.ReadAll(res.Body)
// if err != nil {
// return err
// }
// if !strings.Contains(string(body), "ping") {
// return errors.New("Incorrect marathon config")
// FIXME Doesn't work...
//// "github.com/gambol99/go-marathon"
//config := marathon.NewDefaultConfig()
//
//marathonClient, err := marathon.NewClient(config)
//if err != nil {
// c.Fatalf("Error creating Marathon client. %v", err)
//}
//
//// Wait for Marathon to elect itself leader
//err = try.Do(30*time.Second, func() error {
// leader, err := marathonClient.Leader()
//
// if err != nil || len(leader) == 0 {
// return fmt.Errorf("Leader not found. %v", err)
// }
//
// return nil
// })
// c.Assert(err, checker.IsNil)
//})
//
//c.Assert(err, checker.IsNil)
}
func (s *MarathonSuite) TestSimpleConfiguration(c *check.C) {
@ -36,11 +46,9 @@ func (s *MarathonSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// TODO validate : run on 80
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View file

@ -5,8 +5,8 @@ import (
"os/exec"
"time"
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
@ -23,11 +23,8 @@ func (s *MesosSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
time.Sleep(500 * time.Millisecond)
// TODO validate : run on 80
resp, err := http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View file

@ -0,0 +1,95 @@
package try
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/docker/libkv/store"
)
// ResponseCondition is a retry condition function.
// It receives a response, and returns an error
// if the response failed the condition.
type ResponseCondition func(*http.Response) error
// BodyContains returns a retry condition function.
// The condition returns an error if the request body does not contain all the given
// strings.
func BodyContains(values ...string) ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %s", err)
}
for _, value := range values {
if !strings.Contains(string(body), value) {
return fmt.Errorf("could not find '%s' in body '%s'", value, string(body))
}
}
return nil
}
}
// BodyContainsOr returns a retry condition function.
// The condition returns an error if the request body does not contain one of the given
// strings.
func BodyContainsOr(values ...string) ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %s", err)
}
for _, value := range values {
if strings.Contains(string(body), value) {
return nil
}
}
return fmt.Errorf("could not find '%v' in body '%s'", values, string(body))
}
}
// HasBody returns a retry condition function.
// The condition returns an error if the request body does not have body content.
func HasBody() ResponseCondition {
return func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %s", err)
}
if len(body) == 0 {
return errors.New("Response doesn't have body content")
}
return nil
}
}
// StatusCodeIs returns a retry condition function.
// The condition returns an error if the given response's status code is not the
// given HTTP status code.
func StatusCodeIs(status int) ResponseCondition {
return func(res *http.Response) error {
if res.StatusCode != status {
return fmt.Errorf("got status code %d, wanted %d", res.StatusCode, status)
}
return nil
}
}
// DoCondition is a retry condition function.
// It returns an error
type DoCondition func() error
// KVExists is a retry condition function.
// Verify if a Key exists in the store
func KVExists(kv store.Store, key string) DoCondition {
return func() error {
_, err := kv.Exists(key)
return err
}
}

156
integration/try/try.go Normal file
View file

@ -0,0 +1,156 @@
package try
import (
"fmt"
"math"
"net/http"
"os"
"time"
"github.com/containous/traefik/log"
)
const (
// CITimeoutMultiplier is the multiplier for all timeout in the CI
CITimeoutMultiplier = 3
maxInterval = 5 * time.Second
)
type timedAction func(timeout time.Duration, operation DoCondition) error
// Sleep pauses the current goroutine for at least the duration d.
// Deprecated: Use only when use an other Try[...] functions is not possible.
func Sleep(d time.Duration) {
d = applyCIMultiplier(d)
time.Sleep(d)
}
// Response is like Request, but returns the response for further
// processing at the call site.
// Conditions are not allowed since it would complicate signaling if the
// response body needs to be closed or not. Callers are expected to close on
// their own if the function returns a nil error.
func Response(req *http.Request, timeout time.Duration) (*http.Response, error) {
return doTryRequest(req, timeout)
}
// ResponseUntilStatusCode is like Request, but returns the response for further
// processing at the call site.
// Conditions are not allowed since it would complicate signaling if the
// response body needs to be closed or not. Callers are expected to close on
// their own if the function returns a nil error.
func ResponseUntilStatusCode(req *http.Request, timeout time.Duration, statusCode int) (*http.Response, error) {
return doTryRequest(req, timeout, StatusCodeIs(statusCode))
}
// GetRequest is like Do, but runs a request against the given URL and applies
// the condition on the response.
// ResponseCondition may be nil, in which case only the request against the URL must
// succeed.
func GetRequest(url string, timeout time.Duration, conditions ...ResponseCondition) error {
resp, err := doTryGet(url, timeout, conditions...)
if resp != nil && resp.Body != nil {
defer resp.Body.Close()
}
return err
}
// Request is like Do, but runs a request against the given URL and applies
// the condition on the response.
// ResponseCondition may be nil, in which case only the request against the URL must
// succeed.
func Request(req *http.Request, timeout time.Duration, conditions ...ResponseCondition) error {
resp, err := doTryRequest(req, timeout, conditions...)
if resp != nil && resp.Body != nil {
defer resp.Body.Close()
}
return err
}
// Do repeatedly executes an operation until no error condition occurs or the
// given timeout is reached, whatever comes first.
func Do(timeout time.Duration, operation DoCondition) error {
if timeout <= 0 {
panic("timeout must be larger than zero")
}
interval := time.Duration(math.Ceil(float64(timeout) / 15.0))
if interval > maxInterval {
interval = maxInterval
}
timeout = applyCIMultiplier(timeout)
var err error
if err = operation(); err == nil {
fmt.Println("+")
return nil
}
fmt.Print("*")
stopTimer := time.NewTimer(timeout)
defer stopTimer.Stop()
retryTick := time.NewTicker(interval)
defer retryTick.Stop()
for {
select {
case <-stopTimer.C:
fmt.Println("-")
return fmt.Errorf("try operation failed: %s", err)
case <-retryTick.C:
fmt.Print("*")
if err = operation(); err == nil {
fmt.Println("+")
return err
}
}
}
}
func doTryGet(url string, timeout time.Duration, conditions ...ResponseCondition) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
return doTryRequest(req, timeout, conditions...)
}
func doTryRequest(request *http.Request, timeout time.Duration, conditions ...ResponseCondition) (*http.Response, error) {
return doRequest(Do, timeout, request, conditions...)
}
func doRequest(action timedAction, timeout time.Duration, request *http.Request, conditions ...ResponseCondition) (*http.Response, error) {
var resp *http.Response
return resp, action(timeout, func() error {
var err error
client := http.DefaultClient
resp, err = client.Do(request)
if err != nil {
return err
}
for _, condition := range conditions {
if err := condition(resp); err != nil {
return err
}
}
return nil
})
}
func applyCIMultiplier(timeout time.Duration) time.Duration {
ci := os.Getenv("CI")
if len(ci) > 0 {
log.Debug("Apply CI multiplier:", CITimeoutMultiplier)
return time.Duration(float64(timeout) * CITimeoutMultiplier)
}
return timeout
}

View file

@ -70,15 +70,15 @@ func TestHelperProcess(t *testing.T) {
argsStr := strings.Join(args, " ")
switch argsStr {
case "an exitCode 127":
fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127")
fmt.Fprint(os.Stderr, "an error has occurred with exitCode 127")
os.Exit(127)
case "an error":
fmt.Fprintf(os.Stderr, "an error has occurred")
fmt.Fprint(os.Stderr, "an error has occurred")
os.Exit(1)
case "it works":
fmt.Fprintf(os.Stdout, "it works")
fmt.Fprint(os.Stdout, "it works")
default:
fmt.Fprintf(os.Stdout, "no arguments")
fmt.Fprint(os.Stdout, "no arguments")
}
default:
fmt.Fprintf(os.Stderr, "Command %s not found.", cmd)

View file

@ -1,50 +0,0 @@
package utils
import (
"errors"
"github.com/cenk/backoff"
"net/http"
"strconv"
"time"
)
// TryRequest try operation timeout, and retry backoff
func TryRequest(url string, timeout time.Duration, condition Condition) error {
exponentialBackOff := backoff.NewExponentialBackOff()
exponentialBackOff.MaxElapsedTime = timeout
var res *http.Response
err := backoff.Retry(func() error {
var err error
res, err = http.Get(url)
if err != nil {
return err
}
return condition(res)
}, exponentialBackOff)
return err
}
// Try try operation timeout, and retry backoff
func Try(timeout time.Duration, operation func() error) error {
exponentialBackOff := backoff.NewExponentialBackOff()
exponentialBackOff.MaxElapsedTime = timeout
err := backoff.Retry(operation, exponentialBackOff)
return err
}
// Condition is a retry condition function.
// It receives a response, and returns an error
// if the response failed the condition.
type Condition func(*http.Response) error
// ErrorIfStatusCodeIsNot returns a retry condition function.
// The condition returns an error
// if the given response's status code is not the given HTTP status code.
func ErrorIfStatusCodeIsNot(status int) Condition {
return func(res *http.Response) error {
if res.StatusCode != status {
return errors.New("Bad status. Got: " + res.Status + ", expected:" + strconv.Itoa(status))
}
return nil
}
}