1
0
Fork 0

Improve integration tests

Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
This commit is contained in:
Michael 2024-01-09 17:00:07 +01:00 committed by GitHub
parent cd8d5b8f10
commit e522446909
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
85 changed files with 3482 additions and 4609 deletions

View file

@ -11,13 +11,15 @@ import (
"os"
"strconv"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/accesslog"
checker "github.com/vdemeester/shakers"
)
const (
@ -28,6 +30,10 @@ const (
// AccessLogSuite tests suite.
type AccessLogSuite struct{ BaseSuite }
func TestAccessLogSuite(t *testing.T) {
suite.Run(t, new(AccessLogSuite))
}
type accessLogValue struct {
formatOnly bool
code string
@ -36,67 +42,67 @@ type accessLogValue struct {
serviceURL string
}
func (s *AccessLogSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "access_log")
s.composeUp(c)
func (s *AccessLogSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("access_log")
s.composeUp()
}
func (s *AccessLogSuite) TearDownTest(c *check.C) {
displayTraefikLogFile(c, traefikTestLogFile)
func (s *AccessLogSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *AccessLogSuite) TearDownTest() {
s.displayTraefikLogFile(traefikTestLogFile)
_ = os.Remove(traefikTestAccessLogFile)
}
func (s *AccessLogSuite) TestAccessLog(c *check.C) {
func (s *AccessLogSuite) TestAccessLog() {
ensureWorkingDirectoryIsClean()
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer func() {
traefikLog, err := os.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
log.WithoutContext().Info(string(traefikLog))
}()
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.waitForTraefik("server1")
waitForTraefik(c, "server1")
checkStatsForLogFile(c)
s.checkStatsForLogFile()
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Make some requests
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "frontend1.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "frontend2.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogOutput(c)
count := s.checkAccessLogOutput()
c.Assert(count, checker.GreaterOrEqualThan, 3)
assert.Equal(s.T(), 3, count)
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
func (s *AccessLogSuite) TestAccessLogAuthFrontend() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -124,48 +130,43 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontend(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "authFrontend")
s.waitForTraefik("authFrontend")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test auth entrypoint
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8006/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "frontend.auth.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.SetBasicAuth("test", "")
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.SetBasicAuth("test", "test")
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -193,27 +194,22 @@ func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "digestAuthMiddleware")
s.waitForTraefik("digestAuthMiddleware")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test auth entrypoint
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8008/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "entrypoint.digest.auth.docker.local"
resp, err := try.ResponseUntilStatusCode(req, 500*time.Millisecond, http.StatusUnauthorized)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
digest := digestParts(resp)
digest["uri"] = "/"
@ -225,22 +221,22 @@ func (s *AccessLogSuite) TestAccessLogDigestAuthMiddleware(c *check.C) {
req.Header.Set("Content-Type", "application/json")
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
digest["password"] = "test"
req.Header.Set("Authorization", getDigestAuthorization(digest))
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
// Thanks to mvndaai for digest authentication
@ -291,7 +287,7 @@ func getDigestAuthorization(digestParts map[string]string) string {
return authorization
}
func (s *AccessLogSuite) TestAccessLogFrontendRedirect(c *check.C) {
func (s *AccessLogSuite) TestAccessLogFrontendRedirect() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -308,38 +304,33 @@ func (s *AccessLogSuite) TestAccessLogFrontendRedirect(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "frontendRedirect")
s.waitForTraefik("frontendRedirect")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test frontend redirect
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8005/test", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = ""
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogJSONFrontendRedirect(c *check.C) {
func (s *AccessLogSuite) TestAccessLogJSONFrontendRedirect() {
ensureWorkingDirectoryIsClean()
type logLine struct {
@ -365,30 +356,25 @@ func (s *AccessLogSuite) TestAccessLogJSONFrontendRedirect(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_json_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_json_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "frontendRedirect")
s.waitForTraefik("frontendRedirect")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test frontend redirect
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8005/test", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = ""
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
lines := extractLines(c)
c.Assert(len(lines), checker.GreaterOrEqualThan, len(expected))
lines := s.extractLines()
assert.GreaterOrEqual(s.T(), len(lines), len(expected))
for i, line := range lines {
if line == "" {
@ -396,15 +382,15 @@ func (s *AccessLogSuite) TestAccessLogJSONFrontendRedirect(c *check.C) {
}
var logline logLine
err := json.Unmarshal([]byte(line), &logline)
c.Assert(err, checker.IsNil)
c.Assert(logline.DownstreamStatus, checker.Equals, expected[i].DownstreamStatus)
c.Assert(logline.OriginStatus, checker.Equals, expected[i].OriginStatus)
c.Assert(logline.RouterName, checker.Equals, expected[i].RouterName)
c.Assert(logline.ServiceName, checker.Equals, expected[i].ServiceName)
require.NoError(s.T(), err)
assert.Equal(s.T(), expected[i].DownstreamStatus, logline.DownstreamStatus)
assert.Equal(s.T(), expected[i].OriginStatus, logline.OriginStatus)
assert.Equal(s.T(), expected[i].RouterName, logline.RouterName)
assert.Equal(s.T(), expected[i].ServiceName, logline.ServiceName)
}
}
func (s *AccessLogSuite) TestAccessLogRateLimit(c *check.C) {
func (s *AccessLogSuite) TestAccessLogRateLimit() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -424,42 +410,37 @@ func (s *AccessLogSuite) TestAccessLogRateLimit(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "rateLimit")
s.waitForTraefik("rateLimit")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test rate limit
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8007/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "ratelimit.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogBackendNotFound(c *check.C) {
func (s *AccessLogSuite) TestAccessLogBackendNotFound() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -473,38 +454,33 @@ func (s *AccessLogSuite) TestAccessLogBackendNotFound(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.waitForTraefik("server1")
waitForTraefik(c, "server1")
checkStatsForLogFile(c)
s.checkStatsForLogFile()
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test rate limit
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "backendnotfound.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogFrontendWhitelist(c *check.C) {
func (s *AccessLogSuite) TestAccessLogFrontendWhitelist() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -518,38 +494,33 @@ func (s *AccessLogSuite) TestAccessLogFrontendWhitelist(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "frontendWhitelist")
s.waitForTraefik("frontendWhitelist")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test rate limit
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "frontend.whitelist.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusForbidden), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess(c *check.C) {
func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -563,39 +534,34 @@ func (s *AccessLogSuite) TestAccessLogAuthFrontendSuccess(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "authFrontend")
s.waitForTraefik("authFrontend")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test auth entrypoint
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8006/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "frontend.auth.docker.local"
req.SetBasicAuth("test", "test")
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func (s *AccessLogSuite) TestAccessLogPreflightHeadersMiddleware(c *check.C) {
func (s *AccessLogSuite) TestAccessLogPreflightHeadersMiddleware() {
ensureWorkingDirectoryIsClean()
expected := []accessLogValue{
@ -609,79 +575,74 @@ func (s *AccessLogSuite) TestAccessLogPreflightHeadersMiddleware(c *check.C) {
}
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.checkStatsForLogFile()
checkStatsForLogFile(c)
waitForTraefik(c, "preflightCORS")
s.waitForTraefik("preflightCORS")
// Verify Traefik started OK
checkTraefikStarted(c)
s.checkTraefikStarted()
// Test preflight response
req, err := http.NewRequest(http.MethodOptions, "http://127.0.0.1:8009/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "preflight.docker.local"
req.Header.Set("Origin", "whatever")
req.Header.Set("Access-Control-Request-Method", "GET")
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log output as expected
count := checkAccessLogExactValuesOutput(c, expected)
count := s.checkAccessLogExactValuesOutput(expected)
c.Assert(count, checker.GreaterOrEqualThan, len(expected))
assert.GreaterOrEqual(s.T(), count, len(expected))
// Verify no other Traefik problems
checkNoOtherTraefikProblems(c)
s.checkNoOtherTraefikProblems()
}
func checkNoOtherTraefikProblems(c *check.C) {
func (s *AccessLogSuite) checkNoOtherTraefikProblems() {
traefikLog, err := os.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if len(traefikLog) > 0 {
fmt.Printf("%s\n", string(traefikLog))
}
}
func checkAccessLogOutput(c *check.C) int {
lines := extractLines(c)
func (s *AccessLogSuite) checkAccessLogOutput() int {
lines := s.extractLines()
count := 0
for i, line := range lines {
if len(line) > 0 {
count++
CheckAccessLogFormat(c, line, i)
s.CheckAccessLogFormat(line, i)
}
}
return count
}
func checkAccessLogExactValuesOutput(c *check.C, values []accessLogValue) int {
lines := extractLines(c)
func (s *AccessLogSuite) checkAccessLogExactValuesOutput(values []accessLogValue) int {
lines := s.extractLines()
count := 0
for i, line := range lines {
fmt.Println(line)
if len(line) > 0 {
count++
if values[i].formatOnly {
CheckAccessLogFormat(c, line, i)
s.CheckAccessLogFormat(line, i)
} else {
checkAccessLogExactValues(c, line, i, values[i])
s.checkAccessLogExactValues(line, i, values[i])
}
}
}
return count
}
func extractLines(c *check.C) []string {
func (s *AccessLogSuite) extractLines() []string {
accessLog, err := os.ReadFile(traefikTestAccessLogFile)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
lines := strings.Split(string(accessLog), "\n")
@ -694,14 +655,14 @@ func extractLines(c *check.C) []string {
return clean
}
func checkStatsForLogFile(c *check.C) {
func (s *AccessLogSuite) checkStatsForLogFile() {
err := try.Do(1*time.Second, func() error {
if _, errStat := os.Stat(traefikTestLogFile); errStat != nil {
return fmt.Errorf("could not get stats for log file: %w", errStat)
}
return nil
})
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func ensureWorkingDirectoryIsClean() {
@ -709,69 +670,38 @@ func ensureWorkingDirectoryIsClean() {
os.Remove(traefikTestLogFile)
}
func checkTraefikStarted(c *check.C) []byte {
func (s *AccessLogSuite) checkTraefikStarted() []byte {
traefikLog, err := os.ReadFile(traefikTestLogFile)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if len(traefikLog) > 0 {
fmt.Printf("%s\n", string(traefikLog))
}
return traefikLog
}
func CheckAccessLogFormat(c *check.C, line string, i int) {
func (s *BaseSuite) CheckAccessLogFormat(line string, i int) {
results, err := accesslog.ParseAccessLog(line)
c.Assert(err, checker.IsNil)
c.Assert(results, checker.HasLen, 14)
c.Assert(results[accesslog.OriginStatus], checker.Matches, `^(-|\d{3})$`)
require.NoError(s.T(), err)
assert.Len(s.T(), results, 14)
assert.Regexp(s.T(), `^(-|\d{3})$`, results[accesslog.OriginStatus])
count, _ := strconv.Atoi(results[accesslog.RequestCount])
c.Assert(count, checker.GreaterOrEqualThan, i+1)
c.Assert(results[accesslog.RouterName], checker.Matches, `"(rt-.+@docker|api@internal)"`)
c.Assert(results[accesslog.ServiceURL], checker.HasPrefix, `"http://`)
c.Assert(results[accesslog.Duration], checker.Matches, `^\d+ms$`)
assert.GreaterOrEqual(s.T(), count, i+1)
assert.Regexp(s.T(), `"(rt-.+@docker|api@internal)"`, results[accesslog.RouterName])
assert.True(s.T(), strings.HasPrefix(results[accesslog.ServiceURL], `"http://`))
assert.Regexp(s.T(), `^\d+ms$`, results[accesslog.Duration])
}
func checkAccessLogExactValues(c *check.C, line string, i int, v accessLogValue) {
func (s *AccessLogSuite) checkAccessLogExactValues(line string, i int, v accessLogValue) {
results, err := accesslog.ParseAccessLog(line)
c.Assert(err, checker.IsNil)
c.Assert(results, checker.HasLen, 14)
require.NoError(s.T(), err)
assert.Len(s.T(), results, 14)
if len(v.user) > 0 {
c.Assert(results[accesslog.ClientUsername], checker.Equals, v.user)
assert.Equal(s.T(), v.user, results[accesslog.ClientUsername])
}
c.Assert(results[accesslog.OriginStatus], checker.Equals, v.code)
assert.Equal(s.T(), v.code, results[accesslog.OriginStatus])
count, _ := strconv.Atoi(results[accesslog.RequestCount])
c.Assert(count, checker.GreaterOrEqualThan, i+1)
c.Assert(results[accesslog.RouterName], checker.Matches, `^"?`+v.routerName+`.*(@docker)?$`)
c.Assert(results[accesslog.ServiceURL], checker.Matches, `^"?`+v.serviceURL+`.*$`)
c.Assert(results[accesslog.Duration], checker.Matches, `^\d+ms$`)
}
func waitForTraefik(c *check.C, containerName string) {
time.Sleep(1 * time.Second)
// Wait for Traefik to turn ready.
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
c.Assert(err, checker.IsNil)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains(containerName))
c.Assert(err, checker.IsNil)
}
func displayTraefikLogFile(c *check.C, path string) {
if c.Failed() {
if _, err := os.Stat(path); !os.IsNotExist(err) {
content, errRead := os.ReadFile(path)
fmt.Printf("%s: Traefik logs: \n", c.TestName())
if errRead == nil {
fmt.Println(content)
} else {
fmt.Println(errRead)
}
} else {
fmt.Printf("%s: No Traefik logs.\n", c.TestName())
}
errRemove := os.Remove(path)
if errRemove != nil {
fmt.Println(errRemove)
}
}
assert.GreaterOrEqual(s.T(), count, i+1)
assert.Regexp(s.T(), `^"?`+v.routerName+`.*(@docker)?$`, results[accesslog.RouterName])
assert.Regexp(s.T(), `^"?`+v.serviceURL+`.*$`, results[accesslog.ServiceURL])
assert.Regexp(s.T(), `^\d+ms$`, results[accesslog.Duration])
}

View file

@ -8,16 +8,19 @@ import (
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/go-check/check"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/provider/acme"
"github.com/traefik/traefik/v2/pkg/testhelpers"
"github.com/traefik/traefik/v2/pkg/types"
checker "github.com/vdemeester/shakers"
)
// ACME test suites.
@ -27,6 +30,10 @@ type AcmeSuite struct {
fakeDNSServer *dns.Server
}
func TestAcmeSuite(t *testing.T) {
suite.Run(t, new(AcmeSuite))
}
type subCases struct {
host string
expectedCommonName string
@ -87,17 +94,18 @@ func setupPebbleRootCA() (*http.Transport, error) {
}, nil
}
func (s *AcmeSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "pebble")
s.composeUp(c)
func (s *AcmeSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.fakeDNSServer = startFakeDNSServer(s.getContainerIP(c, "traefik"))
s.pebbleIP = s.getComposeServiceIP(c, "pebble")
s.createComposeProject("pebble")
s.composeUp()
// Retrieving the Docker host ip.
s.fakeDNSServer = startFakeDNSServer(s.hostIP)
s.pebbleIP = s.getComposeServiceIP("pebble")
pebbleTransport, err := setupPebbleRootCA()
if err != nil {
c.Fatal(err)
}
require.NoError(s.T(), err)
// wait for pebble
req := testhelpers.MustNewRequest(http.MethodGet, s.getAcmeURL(), nil)
@ -113,21 +121,24 @@ func (s *AcmeSuite) SetUpSuite(c *check.C) {
}
return try.StatusCodeIs(http.StatusOK)(resp)
})
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *AcmeSuite) TearDownSuite(c *check.C) {
func (s *AcmeSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
if s.fakeDNSServer != nil {
err := s.fakeDNSServer.Shutdown()
if err != nil {
c.Log(err)
log.WithoutContext().Info(err.Error())
}
}
s.composeDown(c)
s.composeDown()
}
func (s *AcmeSuite) TestHTTP01Domains(c *check.C) {
func (s *AcmeSuite) TestHTTP01Domains() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_domains.toml",
subCases: []subCases{{
@ -147,10 +158,10 @@ func (s *AcmeSuite) TestHTTP01Domains(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01StoreDomains(c *check.C) {
func (s *AcmeSuite) TestHTTP01StoreDomains() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_store_domains.toml",
subCases: []subCases{{
@ -170,10 +181,10 @@ func (s *AcmeSuite) TestHTTP01StoreDomains(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01DomainsInSAN(c *check.C) {
func (s *AcmeSuite) TestHTTP01DomainsInSAN() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_domains.toml",
subCases: []subCases{{
@ -194,10 +205,10 @@ func (s *AcmeSuite) TestHTTP01DomainsInSAN(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01OnHostRule(c *check.C) {
func (s *AcmeSuite) TestHTTP01OnHostRule() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_base.toml",
subCases: []subCases{{
@ -214,10 +225,10 @@ func (s *AcmeSuite) TestHTTP01OnHostRule(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestMultipleResolver(c *check.C) {
func (s *AcmeSuite) TestMultipleResolver() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_multiple_resolvers.toml",
subCases: []subCases{
@ -245,10 +256,10 @@ func (s *AcmeSuite) TestMultipleResolver(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01OnHostRuleECDSA(c *check.C) {
func (s *AcmeSuite) TestHTTP01OnHostRuleECDSA() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_base.toml",
subCases: []subCases{{
@ -266,10 +277,10 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleECDSA(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01OnHostRuleInvalidAlgo(c *check.C) {
func (s *AcmeSuite) TestHTTP01OnHostRuleInvalidAlgo() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_base.toml",
subCases: []subCases{{
@ -287,10 +298,10 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleInvalidAlgo(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01OnHostRuleDefaultDynamicCertificatesWithWildcard(c *check.C) {
func (s *AcmeSuite) TestHTTP01OnHostRuleDefaultDynamicCertificatesWithWildcard() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
subCases: []subCases{{
@ -307,10 +318,10 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleDefaultDynamicCertificatesWithWildcard(c
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard(c *check.C) {
func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_tls_dynamic.toml",
subCases: []subCases{{
@ -327,10 +338,10 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard(c *check
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestTLSALPN01OnHostRuleTCP(c *check.C) {
func (s *AcmeSuite) TestTLSALPN01OnHostRuleTCP() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_tcp.toml",
subCases: []subCases{{
@ -347,10 +358,10 @@ func (s *AcmeSuite) TestTLSALPN01OnHostRuleTCP(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
func (s *AcmeSuite) TestTLSALPN01OnHostRule() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_base.toml",
subCases: []subCases{{
@ -367,10 +378,10 @@ func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestTLSALPN01Domains(c *check.C) {
func (s *AcmeSuite) TestTLSALPN01Domains() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_domains.toml",
subCases: []subCases{{
@ -390,10 +401,10 @@ func (s *AcmeSuite) TestTLSALPN01Domains(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
func (s *AcmeSuite) TestTLSALPN01DomainsInSAN(c *check.C) {
func (s *AcmeSuite) TestTLSALPN01DomainsInSAN() {
testCase := acmeTestCase{
traefikConfFilePath: "fixtures/acme/acme_domains.toml",
subCases: []subCases{{
@ -414,12 +425,12 @@ func (s *AcmeSuite) TestTLSALPN01DomainsInSAN(c *check.C) {
},
}
s.retrieveAcmeCertificate(c, testCase)
s.retrieveAcmeCertificate(testCase)
}
// Test Let's encrypt down.
func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
func (s *AcmeSuite) TestNoValidLetsEncryptServer() {
file := s.adaptFile("fixtures/acme/acme_base.toml", templateModel{
Acme: map[string]static.CertificateResolver{
"default": {ACME: &acme.Configuration{
CAServer: "http://wrongurl:4001/directory",
@ -427,21 +438,16 @@ func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
}},
},
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// Expected traefik works
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
}
// Doing an HTTPS request and test the response certificate.
func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
func (s *AcmeSuite) retrieveAcmeCertificate(testCase acmeTestCase) {
if len(testCase.template.PortHTTP) == 0 {
testCase.template.PortHTTP = ":5002"
}
@ -456,14 +462,10 @@ func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
}
}
file := s.adaptFile(c, testCase.traefikConfFilePath, testCase.template)
defer os.Remove(file)
file := s.adaptFile(testCase.traefikConfFilePath, testCase.template)
s.traefikCmd(withConfigFile(file))
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// A real file is needed to have the right mode on acme.json file
defer os.Remove("/tmp/acme.json")
@ -477,11 +479,11 @@ func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
}
// wait for traefik (generating acme account take some seconds)
err = try.Do(60*time.Second, func() error {
err := try.Do(60*time.Second, func() error {
_, errGet := client.Get("https://127.0.0.1:5001")
return errGet
})
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
for _, sub := range testCase.subCases {
client = &http.Client{
@ -503,7 +505,7 @@ func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
var resp *http.Response
// Retry to send a Request which uses the LE generated certificate
err = try.Do(60*time.Second, func() error {
err := try.Do(60*time.Second, func() error {
resp, err = client.Do(req)
if err != nil {
return err
@ -517,10 +519,10 @@ func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase acmeTestCase) {
return nil
})
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusOK)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusOK, resp.StatusCode)
// Check Domain into response certificate
c.Assert(resp.TLS.PeerCertificates[0].Subject.CommonName, checker.Equals, sub.expectedCommonName)
c.Assert(resp.TLS.PeerCertificates[0].PublicKeyAlgorithm, checker.Equals, sub.expectedAlgorithm)
assert.Equal(s.T(), sub.expectedCommonName, resp.TLS.PeerCertificates[0].Subject.CommonName)
assert.Equal(s.T(), sub.expectedAlgorithm, resp.TLS.PeerCertificates[0].PublicKeyAlgorithm)
}
}

View file

@ -8,36 +8,38 @@ import (
"net/http"
"regexp"
"strconv"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
checker "github.com/vdemeester/shakers"
)
type ThrottlingSuite struct{ BaseSuite }
func (s *ThrottlingSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "rest")
s.composeUp(c)
func TestThrottlingSuite(t *testing.T) {
suite.Run(t, new(ThrottlingSuite))
}
func (s *ThrottlingSuite) TestThrottleConfReload(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/throttling/simple.toml"))
func (s *ThrottlingSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("rest")
s.composeUp()
}
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *ThrottlingSuite) TestThrottleConfReload() {
s.traefikCmd(withConfigFile("fixtures/throttling/simple.toml"))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains("rest@internal"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains("rest@internal"))
require.NoError(s.T(), err)
// 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)
require.NoError(s.T(), err)
config := &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
@ -47,7 +49,7 @@ func (s *ThrottlingSuite) TestThrottleConfReload(c *check.C) {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://" + s.getComposeServiceIP(c, "whoami1") + ":80",
URL: "http://" + s.getComposeServiceIP("whoami1") + ":80",
},
},
},
@ -68,28 +70,28 @@ func (s *ThrottlingSuite) TestThrottleConfReload(c *check.C) {
for i := 0; i < confChanges; i++ {
config.HTTP.Routers[fmt.Sprintf("routerHTTP%d", i)] = router
data, err := json.Marshal(config)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8080/api/providers/rest", bytes.NewReader(data))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
time.Sleep(200 * time.Millisecond)
}
reloadsRegexp := regexp.MustCompile(`traefik_config_reloads_total (\d*)\n`)
resp, err := http.Get("http://127.0.0.1:8080/metrics")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
fields := reloadsRegexp.FindStringSubmatch(string(body))
c.Assert(len(fields), checker.Equals, 2)
assert.Len(s.T(), fields, 2)
reloads, err := strconv.Atoi(fields[1])
if err != nil {
@ -101,5 +103,5 @@ func (s *ThrottlingSuite) TestThrottleConfReload(c *check.C) {
// Therefore the throttling (set at 400ms for this test) should only let
// (2s / 400 ms =) 5 config reloads happen in theory.
// In addition, we have to take into account the extra config reload from the internal provider (5 + 1).
c.Assert(reloads, checker.LessOrEqualThan, 6)
assert.LessOrEqual(s.T(), reloads, 6)
}

View file

@ -4,13 +4,14 @@ import (
"fmt"
"net"
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/hashicorp/consul/api"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type ConsulCatalogSuite struct {
@ -20,26 +21,36 @@ type ConsulCatalogSuite struct {
consulURL string
}
func (s *ConsulCatalogSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "consul_catalog")
s.composeUp(c)
func TestConsulCatalogSuite(t *testing.T) {
suite.Run(t, new(ConsulCatalogSuite))
}
s.consulURL = "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "consul"), "8500")
func (s *ConsulCatalogSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("consul_catalog")
s.composeUp()
s.consulURL = "http://" + net.JoinHostPort(s.getComposeServiceIP("consul"), "8500")
var err error
s.consulClient, err = api.NewClient(&api.Config{
Address: s.consulURL,
})
c.Check(err, check.IsNil)
require.NoError(s.T(), err)
// Wait for consul to elect itself leader
err = s.waitToElectConsulLeader()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
s.consulAgentClient, err = api.NewClient(&api.Config{
Address: "http://" + net.JoinHostPort(s.getComposeServiceIP(c, "consul-agent"), "8500"),
Address: "http://" + net.JoinHostPort(s.getComposeServiceIP("consul-agent"), "8500"),
})
c.Check(err, check.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
@ -83,36 +94,36 @@ func (s *ConsulCatalogSuite) deregisterService(id string, onAgent bool) error {
return client.Agent().ServiceDeregister(id)
}
func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *check.C) {
func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings() {
reg1 := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami",
Tags: []string{"traefik.enable=true"},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg1, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
reg2 := &api.AgentServiceRegistration{
ID: "whoami2",
Name: "whoami",
Tags: []string{"traefik.enable=true"},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami2"),
Address: s.getComposeServiceIP("whoami2"),
}
err = s.registerService(reg2, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
reg3 := &api.AgentServiceRegistration{
ID: "whoami3",
Name: "whoami",
Tags: []string{"traefik.enable=true"},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami3"),
Address: s.getComposeServiceIP("whoami3"),
}
err = s.registerService(reg3, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tempObjects := struct {
ConsulAddress string
@ -120,23 +131,18 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
ConsulAddress: s.consulURL,
}
file := s.adaptFile(c, "fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "whoami"
err = try.Request(req, 2*time.Second,
try.StatusCodeIs(200),
try.BodyContainsOr("Hostname: whoami1", "Hostname: whoami2", "Hostname: whoami3"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.StatusCodeIs(200),
@ -145,18 +151,18 @@ func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings(c *c
fmt.Sprintf(`"http://%s:80":"UP"`, reg2.Address),
fmt.Sprintf(`"http://%s:80":"UP"`, reg3.Address),
))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami2", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami3", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestByLabels(c *check.C) {
containerIP := s.getComposeServiceIP(c, "whoami1")
func (s *ConsulCatalogSuite) TestByLabels() {
containerIP := s.getComposeServiceIP("whoami1")
reg := &api.AgentServiceRegistration{
ID: "whoami1",
@ -171,7 +177,7 @@ func (s *ConsulCatalogSuite) TestByLabels(c *check.C) {
Address: containerIP,
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tempObjects := struct {
ConsulAddress string
@ -179,23 +185,18 @@ func (s *ConsulCatalogSuite) TestByLabels(c *check.C) {
ConsulAddress: s.consulURL,
}
file := s.adaptFile(c, "fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8000/whoami", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContainsOr("Hostname: whoami1", "Hostname: whoami2", "Hostname: whoami3"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestSimpleConfiguration(c *check.C) {
func (s *ConsulCatalogSuite) TestSimpleConfiguration() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -204,37 +205,32 @@ func (s *ConsulCatalogSuite) TestSimpleConfiguration(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
reg := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami",
Tags: []string{"traefik.enable=true"},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "whoami.consul.localhost"
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami1"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestSimpleConfigurationWithWatch(c *check.C) {
func (s *ConsulCatalogSuite) TestSimpleConfigurationWithWatch() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -243,39 +239,34 @@ func (s *ConsulCatalogSuite) TestSimpleConfigurationWithWatch(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple_watch.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple_watch.toml", tempObjects)
reg := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami",
Tags: []string{"traefik.enable=true"},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "whoami.consul.localhost"
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContainsOr("Hostname: whoami1"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
whoamiIP := s.getComposeServiceIP(c, "whoami1")
whoamiIP := s.getComposeServiceIP("whoami1")
reg.Check = &api.AgentServiceCheck{
CheckID: "some-ok-check",
TCP: whoamiIP + ":80",
@ -285,10 +276,10 @@ func (s *ConsulCatalogSuite) TestSimpleConfigurationWithWatch(c *check.C) {
}
err = s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContainsOr("Hostname: whoami1"))
c.Assert(err, checker.IsNil)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContainsOr("Hostname: whoami1"))
require.NoError(s.T(), err)
reg.Check = &api.AgentServiceCheck{
CheckID: "some-failing-check",
@ -299,16 +290,16 @@ func (s *ConsulCatalogSuite) TestSimpleConfigurationWithWatch(c *check.C) {
}
err = s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestRegisterServiceWithoutIP(c *check.C) {
func (s *ConsulCatalogSuite) TestRegisterServiceWithoutIP() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -317,8 +308,7 @@ func (s *ConsulCatalogSuite) TestRegisterServiceWithoutIP(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
reg := &api.AgentServiceRegistration{
ID: "whoami1",
@ -328,25 +318,21 @@ func (s *ConsulCatalogSuite) TestRegisterServiceWithoutIP(c *check.C) {
Address: "",
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/http/services", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("whoami@consulcatalog", "\"http://127.0.0.1:80\": \"UP\""))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestDefaultConsulService(c *check.C) {
func (s *ConsulCatalogSuite) TestDefaultConsulService() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -355,37 +341,32 @@ func (s *ConsulCatalogSuite) TestDefaultConsulService(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
reg := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami",
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "whoami.consul.localhost"
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami1"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulServiceWithTCPLabels(c *check.C) {
func (s *ConsulCatalogSuite) TestConsulServiceWithTCPLabels() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -394,8 +375,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithTCPLabels(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
// Start a container with some tags
reg := &api.AgentServiceRegistration{
@ -407,32 +387,28 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithTCPLabels(c *check.C) {
"traefik.tcp.Services.Super.Loadbalancer.server.port=8080",
},
Port: 8080,
Address: s.getComposeServiceIP(c, "whoamitcp"),
Address: s.getComposeServiceIP("whoamitcp"),
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`my.super.host`)"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
who, err := guessWho("127.0.0.1:8000", "my.super.host", true)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
c.Assert(who, checker.Contains, "whoamitcp")
assert.Contains(s.T(), who, "whoamitcp")
err = s.deregisterService("whoamitcp", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
func (s *ConsulCatalogSuite) TestConsulServiceWithLabels() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -441,8 +417,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
// Start a container with some tags
reg1 := &api.AgentServiceRegistration{
@ -452,11 +427,11 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
"traefik.http.Routers.Super.Rule=Host(`my.super.host`)",
},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg1, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Start another container by replacing a '.' by a '-'
reg2 := &api.AgentServiceRegistration{
@ -466,40 +441,36 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithLabels(c *check.C) {
"traefik.http.Routers.SuperHost.Rule=Host(`my-super.host`)",
},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami2"),
Address: s.getComposeServiceIP("whoami2"),
}
err = s.registerService(reg2, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my-super.host"
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami1"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my.super.host"
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami2"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami2", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C) {
func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -508,8 +479,7 @@ func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C)
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/default_not_exposed.toml", tempObjects)
// Start a container with some tags
tags := []string{
@ -523,50 +493,46 @@ func (s *ConsulCatalogSuite) TestSameServiceIDOnDifferentConsulAgent(c *check.C)
Name: "whoami",
Tags: tags,
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg1, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
reg2 := &api.AgentServiceRegistration{
ID: "whoami",
Name: "whoami",
Tags: tags,
Port: 80,
Address: s.getComposeServiceIP(c, "whoami2"),
Address: s.getComposeServiceIP("whoami2"),
}
err = s.registerService(reg2, true)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my.super.host"
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami1", "Hostname: whoami2"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(200),
try.BodyContainsOr(s.getComposeServiceIP(c, "whoami1"), s.getComposeServiceIP(c, "whoami2")))
c.Assert(err, checker.IsNil)
try.BodyContainsOr(s.getComposeServiceIP("whoami1"), s.getComposeServiceIP("whoami2")))
require.NoError(s.T(), err)
err = s.deregisterService("whoami", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami", true)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels() {
tempObjects := struct {
ConsulAddress string
DefaultRule string
@ -575,8 +541,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.consul.localhost`)",
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
// Start a container with some tags
reg := &api.AgentServiceRegistration{
@ -586,32 +551,28 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithOneMissingLabels(c *check.C) {
"traefik.random.value=my.super.host",
},
Port: 80,
Address: s.getComposeServiceIP(c, "whoami1"),
Address: s.getComposeServiceIP("whoami1"),
}
err := s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my.super.host"
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO validate : run on 80
// Expected a 404 as we did not configure anything
err = try.Request(req, 1500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
whoamiIP := s.getComposeServiceIP(c, "whoami1")
func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck() {
whoamiIP := s.getComposeServiceIP("whoami1")
tags := []string{
"traefik.enable=true",
"traefik.http.routers.router1.rule=Path(`/whoami`)",
@ -635,7 +596,7 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
}
err := s.registerService(reg1, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tempObjects := struct {
ConsulAddress string
@ -643,22 +604,17 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
ConsulAddress: s.consulURL,
}
file := s.adaptFile(c, "fixtures/consul_catalog/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/simple.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8000/whoami", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
whoami2IP := s.getComposeServiceIP(c, "whoami2")
whoami2IP := s.getComposeServiceIP("whoami2")
reg2 := &api.AgentServiceRegistration{
ID: "whoami2",
Name: "whoami",
@ -675,26 +631,26 @@ func (s *ConsulCatalogSuite) TestConsulServiceWithHealthCheck(c *check.C) {
}
err = s.registerService(reg2, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "whoami"
// TODO Need to wait for up to 10 seconds (for consul discovery or traefik to boot up ?)
err = try.Request(req, 10*time.Second, try.StatusCodeIs(200), try.BodyContainsOr("Hostname: whoami2"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami2", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulConnect(c *check.C) {
func (s *ConsulCatalogSuite) TestConsulConnect() {
// Wait for consul to fully initialize connect CA
err := s.waitForConnectCA()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
connectIP := s.getComposeServiceIP(c, "connect")
connectIP := s.getComposeServiceIP("connect")
reg := &api.AgentServiceRegistration{
ID: "uuid-api1",
Name: "uuid-api",
@ -712,9 +668,9 @@ func (s *ConsulCatalogSuite) TestConsulConnect(c *check.C) {
Address: connectIP,
}
err = s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
whoamiIP := s.getComposeServiceIP(c, "whoami1")
whoamiIP := s.getComposeServiceIP("whoami1")
regWhoami := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami",
@ -727,40 +683,35 @@ func (s *ConsulCatalogSuite) TestConsulConnect(c *check.C) {
Address: whoamiIP,
}
err = s.registerService(regWhoami, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tempObjects := struct {
ConsulAddress string
}{
ConsulAddress: s.consulURL,
}
file := s.adaptFile(c, "fixtures/consul_catalog/connect.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/connect.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8000/", 10*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 10*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("uuid-api1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault() {
// Wait for consul to fully initialize connect CA
err := s.waitForConnectCA()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
connectIP := s.getComposeServiceIP(c, "connect")
connectIP := s.getComposeServiceIP("connect")
reg := &api.AgentServiceRegistration{
ID: "uuid-api1",
Name: "uuid-api",
@ -777,9 +728,9 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
Address: connectIP,
}
err = s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
whoamiIP := s.getComposeServiceIP(c, "whoami1")
whoamiIP := s.getComposeServiceIP("whoami1")
regWhoami := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami1",
@ -792,9 +743,9 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
Address: whoamiIP,
}
err = s.registerService(regWhoami, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
whoami2IP := s.getComposeServiceIP(c, "whoami2")
whoami2IP := s.getComposeServiceIP("whoami2")
regWhoami2 := &api.AgentServiceRegistration{
ID: "whoami2",
Name: "whoami2",
@ -808,45 +759,40 @@ func (s *ConsulCatalogSuite) TestConsulConnect_ByDefault(c *check.C) {
Address: whoami2IP,
}
err = s.registerService(regWhoami2, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tempObjects := struct {
ConsulAddress string
}{
ConsulAddress: s.consulURL,
}
file := s.adaptFile(c, "fixtures/consul_catalog/connect_by_default.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/connect_by_default.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8000/", 10*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 10*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/whoami2", 10*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("uuid-api1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami2", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulCatalogSuite) TestConsulConnect_NotAware(c *check.C) {
func (s *ConsulCatalogSuite) TestConsulConnect_NotAware() {
// Wait for consul to fully initialize connect CA
err := s.waitForConnectCA()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
connectIP := s.getComposeServiceIP(c, "connect")
connectIP := s.getComposeServiceIP("connect")
reg := &api.AgentServiceRegistration{
ID: "uuid-api1",
Name: "uuid-api",
@ -864,9 +810,9 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware(c *check.C) {
Address: connectIP,
}
err = s.registerService(reg, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
whoamiIP := s.getComposeServiceIP(c, "whoami1")
whoamiIP := s.getComposeServiceIP("whoami1")
regWhoami := &api.AgentServiceRegistration{
ID: "whoami1",
Name: "whoami",
@ -879,30 +825,25 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware(c *check.C) {
Address: whoamiIP,
}
err = s.registerService(regWhoami, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tempObjects := struct {
ConsulAddress string
}{
ConsulAddress: s.consulURL,
}
file := s.adaptFile(c, "fixtures/consul_catalog/connect_not_aware.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/consul_catalog/connect_not_aware.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8000/", 10*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 10*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("uuid-api1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = s.deregisterService("whoami1", false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -10,16 +10,17 @@ import (
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/go-check/check"
"github.com/kvtools/consul"
"github.com/kvtools/valkeyrie"
"github.com/kvtools/valkeyrie/store"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
checker "github.com/vdemeester/shakers"
)
// Consul test suites.
@ -29,18 +30,16 @@ type ConsulSuite struct {
consulURL string
}
func (s *ConsulSuite) resetStore(c *check.C) {
err := s.kvClient.DeleteTree(context.Background(), "traefik")
if err != nil && !errors.Is(err, store.ErrKeyNotFound) {
c.Fatal(err)
}
func TestConsulSuite(t *testing.T) {
suite.Run(t, new(ConsulSuite))
}
func (s *ConsulSuite) setupStore(c *check.C) {
s.createComposeProject(c, "consul")
s.composeUp(c)
func (s *ConsulSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("consul")
s.composeUp()
consulAddr := net.JoinHostPort(s.getComposeServiceIP(c, "consul"), "8500")
consulAddr := net.JoinHostPort(s.getComposeServiceIP("consul"), "8500")
s.consulURL = fmt.Sprintf("http://%s", consulAddr)
kv, err := valkeyrie.NewStore(
@ -51,21 +50,27 @@ func (s *ConsulSuite) setupStore(c *check.C) {
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store consul")
}
require.NoError(s.T(), err, "Cannot create store consul")
s.kvClient = kv
// wait for consul
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
func (s *ConsulSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
defer os.Remove(file)
func (s *ConsulSuite) TearDownTest() {
err := s.kvClient.DeleteTree(context.Background(), "traefik")
if err != nil && !errors.Is(err, store.ErrKeyNotFound) {
require.ErrorIs(s.T(), err, store.ErrKeyNotFound)
}
}
func (s *ConsulSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
@ -115,39 +120,35 @@ func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.BodyContains(`"striper@consul":`, `"compressor@consul":`, `"srvcA@consul":`, `"srvcB@consul":`),
)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
expectedJSON := filepath.FromSlash("testdata/rawdata-consul.json")
if *updateExpected {
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
@ -159,33 +160,27 @@ func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
require.NoError(s.T(), err, text)
}
}
func (s *ConsulSuite) assertWhoami(c *check.C, host string, expectedStatusCode int) {
func (s *ConsulSuite) assertWhoami(host string, expectedStatusCode int) {
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
if err != nil {
c.Fatal(err)
}
require.NoError(s.T(), err)
req.Host = host
resp, err := try.ResponseUntilStatusCode(req, 15*time.Second, expectedStatusCode)
require.NoError(s.T(), err)
resp.Body.Close()
c.Assert(err, checker.IsNil)
}
func (s *ConsulSuite) TestDeleteRootKey(c *check.C) {
func (s *ConsulSuite) TestDeleteRootKey() {
// This test case reproduce the issue: https://github.com/traefik/traefik/issues/8092
s.setupStore(c)
s.resetStore(c)
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
defer os.Remove(file)
file := s.adaptFile("fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
ctx := context.Background()
svcaddr := net.JoinHostPort(s.getComposeServiceIP(c, "whoami"), "80")
svcaddr := net.JoinHostPort(s.getComposeServiceIP("whoami"), "80")
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
@ -202,32 +197,28 @@ func (s *ConsulSuite) TestDeleteRootKey(c *check.C) {
for k, v := range data {
err := s.kvClient.Put(ctx, k, []byte(v), nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.BodyContains(`"Router0@consul":`, `"Router1@consul":`, `"simplesvc0@consul":`, `"simplesvc1@consul":`),
)
c.Assert(err, checker.IsNil)
s.assertWhoami(c, "kv1.localhost", http.StatusOK)
s.assertWhoami(c, "kv2.localhost", http.StatusOK)
require.NoError(s.T(), err)
s.assertWhoami("kv1.localhost", http.StatusOK)
s.assertWhoami("kv2.localhost", http.StatusOK)
// delete router1
err = s.kvClient.DeleteTree(ctx, "traefik/http/routers/Router1")
c.Assert(err, checker.IsNil)
s.assertWhoami(c, "kv1.localhost", http.StatusOK)
s.assertWhoami(c, "kv2.localhost", http.StatusNotFound)
require.NoError(s.T(), err)
s.assertWhoami("kv1.localhost", http.StatusOK)
s.assertWhoami("kv2.localhost", http.StatusNotFound)
// delete simple services and router0
err = s.kvClient.DeleteTree(ctx, "traefik")
c.Assert(err, checker.IsNil)
s.assertWhoami(c, "kv1.localhost", http.StatusNotFound)
s.assertWhoami(c, "kv2.localhost", http.StatusNotFound)
require.NoError(s.T(), err)
s.assertWhoami("kv1.localhost", http.StatusNotFound)
s.assertWhoami("kv2.localhost", http.StatusNotFound)
}

View file

@ -3,15 +3,16 @@ package integration
import (
"encoding/json"
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
"github.com/traefik/traefik/v2/pkg/testhelpers"
checker "github.com/vdemeester/shakers"
)
// Docker tests suite.
@ -19,12 +20,21 @@ type DockerComposeSuite struct {
BaseSuite
}
func (s *DockerComposeSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "minimal")
s.composeUp(c)
func TestDockerComposeSuite(t *testing.T) {
suite.Run(t, new(DockerComposeSuite))
}
func (s *DockerComposeSuite) TestComposeScale(c *check.C) {
func (s *DockerComposeSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("minimal")
s.composeUp()
}
func (s *DockerComposeSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *DockerComposeSuite) TestComposeScale() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -32,45 +42,36 @@ func (s *DockerComposeSuite) TestComposeScale(c *check.C) {
DockerHost: s.getDockerHost(),
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/minimal.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/minimal.toml", tempObjects)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req := testhelpers.MustNewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
req.Host = "my.super.host"
_, err = try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
_, err := try.ResponseUntilStatusCode(req, 5*time.Second, http.StatusOK)
require.NoError(s.T(), err)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
defer resp.Body.Close()
var rtconf api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&rtconf)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// check that we have only three routers (the one from this test + 2 unrelated internal ones)
c.Assert(rtconf.Routers, checker.HasLen, 3)
assert.Len(s.T(), rtconf.Routers, 3)
// check that we have only one service (not counting the internal ones) with n servers
services := rtconf.Services
c.Assert(services, checker.HasLen, 4)
assert.Len(s.T(), services, 4)
for name, service := range services {
if strings.HasSuffix(name, "@internal") {
continue
}
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
c.Assert(name, checker.Equals, "whoami1-"+composeProject.Name+"@docker")
c.Assert(service.LoadBalancer.Servers, checker.HasLen, 2)
assert.Equal(s.T(), "service-mini@docker", name)
assert.Len(s.T(), service.LoadBalancer.Servers, 2)
// We could break here, but we don't just to keep us honest.
}
}

View file

@ -2,15 +2,15 @@ package integration
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// Docker tests suite.
@ -18,15 +18,24 @@ type DockerSuite struct {
BaseSuite
}
func (s *DockerSuite) SetUpTest(c *check.C) {
s.createComposeProject(c, "docker")
func TestDockerSuite(t *testing.T) {
suite.Run(t, new(DockerSuite))
}
func (s *DockerSuite) TearDownTest(c *check.C) {
s.composeDown(c)
func (s *DockerSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("docker")
}
func (s *DockerSuite) TestSimpleConfiguration(c *check.C) {
func (s *DockerSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *DockerSuite) TearDownTest() {
s.composeStop("simple", "withtcplabels", "withlabels1", "withlabels2", "withonelabelmissing", "powpow")
}
func (s *DockerSuite) TestSimpleConfiguration() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -35,24 +44,18 @@ func (s *DockerSuite) TestSimpleConfiguration(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
s.composeUp(c)
s.composeUp()
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// 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)
err := try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
}
func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
func (s *DockerSuite) TestDefaultDockerContainers() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -61,41 +64,30 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
s.composeUp(c, "simple")
s.composeUp("simple")
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "simple.docker.localhost"
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
req.Host = fmt.Sprintf("simple-%s.docker.localhost", composeProject.Name)
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
resp, err := try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var version map[string]interface{}
c.Assert(json.Unmarshal(body, &version), checker.IsNil)
c.Assert(version["Version"], checker.Equals, "swarm/1.0.0")
assert.NoError(s.T(), json.Unmarshal(body, &version))
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
}
func (s *DockerSuite) TestDockerContainersWithTCPLabels(c *check.C) {
func (s *DockerSuite) TestDockerContainersWithTCPLabels() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -104,29 +96,23 @@ func (s *DockerSuite) TestDockerContainersWithTCPLabels(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
s.composeUp(c, "withtcplabels")
s.composeUp("withtcplabels")
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`my.super.host`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`my.super.host`)"))
require.NoError(s.T(), err)
who, err := guessWho("127.0.0.1:8000", "my.super.host", true)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
c.Assert(who, checker.Contains, "my.super.host")
assert.Contains(s.T(), who, "my.super.host")
}
func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
func (s *DockerSuite) TestDockerContainersWithLabels() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -135,44 +121,37 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
s.composeUp(c, "withlabels1", "withlabels2")
s.composeUp("withlabels1", "withlabels2")
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my-super.host"
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
_, err = try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
_, err = try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
require.NoError(s.T(), err)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my.super.host"
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
resp, err := try.ResponseUntilStatusCode(req, 3*time.Second, http.StatusOK)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var version map[string]interface{}
c.Assert(json.Unmarshal(body, &version), checker.IsNil)
c.Assert(version["Version"], checker.Equals, "swarm/1.0.0")
assert.NoError(s.T(), json.Unmarshal(body, &version))
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
}
func (s *DockerSuite) TestDockerContainersWithOneMissingLabels(c *check.C) {
func (s *DockerSuite) TestDockerContainersWithOneMissingLabels() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -181,31 +160,23 @@ func (s *DockerSuite) TestDockerContainersWithOneMissingLabels(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
s.composeUp(c, "withonelabelmissing")
s.composeUp("withonelabelmissing")
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my.super.host"
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
// TODO validate : run on 80
// Expected a 404 as we did not configure anything
err = try.Request(req, 1500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err = try.Request(req, 3*time.Second, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
}
func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
func (s *DockerSuite) TestRestartDockerContainers() {
tempObjects := struct {
DockerHost string
DefaultRule string
@ -214,46 +185,40 @@ func (s *DockerSuite) TestRestartDockerContainers(c *check.C) {
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
}
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
defer os.Remove(file)
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
s.composeUp(c, "powpow")
s.composeUp("powpow")
// Start traefik
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/version", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "my.super.host"
// TODO Need to wait than 500 milliseconds more (for swarm or traefik to boot up ?)
resp, err := try.ResponseUntilStatusCode(req, 1500*time.Millisecond, http.StatusOK)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var version map[string]interface{}
c.Assert(json.Unmarshal(body, &version), checker.IsNil)
c.Assert(version["Version"], checker.Equals, "swarm/1.0.0")
assert.NoError(s.T(), json.Unmarshal(body, &version))
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("powpow"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
s.composeStop(c, "powpow")
s.composeStop("powpow")
time.Sleep(5 * time.Second)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("powpow"))
c.Assert(err, checker.NotNil)
assert.Error(s.T(), err)
s.composeUp(c, "powpow")
s.composeUp("powpow")
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("powpow"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -3,12 +3,12 @@ package integration
import (
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// ErrorPagesSuite test suites.
@ -18,83 +18,78 @@ type ErrorPagesSuite struct {
BackendIP string
}
func (s *ErrorPagesSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "error_pages")
s.composeUp(c)
s.ErrorPageIP = s.getComposeServiceIP(c, "nginx2")
s.BackendIP = s.getComposeServiceIP(c, "nginx1")
func TestErrorPagesSuite(t *testing.T) {
suite.Run(t, new(ErrorPagesSuite))
}
func (s *ErrorPagesSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/error_pages/simple.toml", struct {
func (s *ErrorPagesSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("error_pages")
s.composeUp()
s.ErrorPageIP = s.getComposeServiceIP("nginx2")
s.BackendIP = s.getComposeServiceIP("nginx1")
}
func (s *ErrorPagesSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *ErrorPagesSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/error_pages/simple.toml", struct {
Server1 string
Server2 string
}{"http://" + s.BackendIP + ":80", s.ErrorPageIP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
frontendReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendReq.Host = "test.local"
err = try.Request(frontendReq, 2*time.Second, try.BodyContains("nginx"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ErrorPagesSuite) TestErrorPage(c *check.C) {
func (s *ErrorPagesSuite) TestErrorPage() {
// error.toml contains a mis-configuration of the backend host
file := s.adaptFile(c, "fixtures/error_pages/error.toml", struct {
file := s.adaptFile("fixtures/error_pages/error.toml", struct {
Server1 string
Server2 string
}{s.BackendIP, s.ErrorPageIP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
frontendReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendReq.Host = "test.local"
err = try.Request(frontendReq, 2*time.Second, try.BodyContains("An error occurred."))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ErrorPagesSuite) TestErrorPageFlush(c *check.C) {
func (s *ErrorPagesSuite) TestErrorPageFlush() {
srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add("Transfer-Encoding", "chunked")
rw.WriteHeader(http.StatusInternalServerError)
_, _ = rw.Write([]byte("KO"))
}))
file := s.adaptFile(c, "fixtures/error_pages/simple.toml", struct {
file := s.adaptFile("fixtures/error_pages/simple.toml", struct {
Server1 string
Server2 string
}{srv.URL, s.ErrorPageIP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
frontendReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendReq.Host = "test.local"
err = try.Request(frontendReq, 2*time.Second,
try.BodyContains("An error occurred."),
try.HasHeaderValue("Content-Type", "text/html", true),
)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -8,16 +8,17 @@ import (
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/go-check/check"
"github.com/kvtools/etcdv3"
"github.com/kvtools/valkeyrie"
"github.com/kvtools/valkeyrie/store"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
checker "github.com/vdemeester/shakers"
)
// etcd test suites.
@ -27,12 +28,18 @@ type EtcdSuite struct {
etcdAddr string
}
func (s *EtcdSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "etcd")
s.composeUp(c)
func TestEtcdSuite(t *testing.T) {
suite.Run(t, new(EtcdSuite))
}
func (s *EtcdSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("etcd")
s.composeUp()
var err error
s.etcdAddr = net.JoinHostPort(s.getComposeServiceIP(c, "etcd"), "2379")
s.etcdAddr = net.JoinHostPort(s.getComposeServiceIP("etcd"), "2379")
s.kvClient, err = valkeyrie.NewStore(
context.Background(),
etcdv3.StoreName,
@ -41,18 +48,19 @@ func (s *EtcdSuite) SetUpSuite(c *check.C) {
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store etcd")
}
require.NoError(s.T(), err)
// wait for etcd
err = try.Do(60*time.Second, try.KVExists(s.kvClient, "test"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/etcd/simple.toml", struct{ EtcdAddress string }{s.etcdAddr})
defer os.Remove(file)
func (s *EtcdSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *EtcdSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/etcd/simple.toml", struct{ EtcdAddress string }{s.etcdAddr})
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
@ -102,39 +110,35 @@ func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.BodyContains(`"striper@etcd":`, `"compressor@etcd":`, `"srvcA@etcd":`, `"srvcB@etcd":`),
)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
expectedJSON := filepath.FromSlash("testdata/rawdata-etcd.json")
if *updateExpected {
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
@ -146,7 +150,6 @@ func (s *EtcdSuite) TestSimpleConfiguration(c *check.C) {
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
require.NoError(s.T(), err, text)
}
}

View file

@ -2,61 +2,58 @@ package integration
import (
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// File tests suite.
type FileSuite struct{ BaseSuite }
func (s *FileSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "file")
s.composeUp(c)
func TestFileSuite(t *testing.T) {
suite.Run(t, new(FileSuite))
}
func (s *FileSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/file/simple.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *FileSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("file")
s.composeUp()
}
func (s *FileSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *FileSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/file/simple.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
// 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)
err := try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
}
// #56 regression test, make sure it does not fail?
func (s *FileSuite) TestSimpleConfigurationNoPanic(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/file/56-simple-panic.toml"))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *FileSuite) TestSimpleConfigurationNoPanic() {
s.traefikCmd(withConfigFile("fixtures/file/56-simple-panic.toml"))
// 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)
err := try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
}
func (s *FileSuite) TestDirectoryConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/file/directory.toml"))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *FileSuite) TestDirectoryConfiguration() {
s.traefikCmd(withConfigFile("fixtures/file/directory.toml"))
// Expected a 404 as we did not configure anything at /test
err = try.GetRequest("http://127.0.0.1:8000/test", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8000/test", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
// Expected a 502 as there is no backend server
err = try.GetRequest("http://127.0.0.1:8000/test2", 1000*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -6,10 +6,14 @@
level = "DEBUG"
[entryPoints]
[entryPoints.web]
[entryPoints.trust]
address = ":8000"
[entryPoints.web.proxyProtocol]
trustedIPs = ["{{.HaproxyIP}}"]
[entryPoints.trust.proxyProtocol]
trustedIPs = ["127.0.0.1"]
[entryPoints.nottrust]
address = ":9000"
[entryPoints.nottrust.proxyProtocol]
trustedIPs = ["1.2.3.4"]
[api]
insecure = true

View file

@ -1,32 +0,0 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints]
[entryPoints.web]
address = ":8000"
[entryPoints.web.proxyProtocol]
trustedIPs = ["1.2.3.4"]
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[http.routers]
[http.routers.router1]
service = "service1"
rule = "Path(`/whoami`)"
[http.services]
[http.services.service1]
[http.services.service1.loadBalancer]
[[http.services.service1.loadBalancer.servers]]
url = "http://{{.WhoamiIP}}"

View file

@ -8,9 +8,11 @@ import (
"math/rand"
"net"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/helloworld"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
@ -29,16 +31,20 @@ const randCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567
// GRPCSuite tests suite.
type GRPCSuite struct{ BaseSuite }
func TestGRPCSuite(t *testing.T) {
suite.Run(t, new(GRPCSuite))
}
type myserver struct {
stopStreamExample chan bool
}
func (s *GRPCSuite) SetUpSuite(c *check.C) {
func (s *GRPCSuite) SetupSuite() {
var err error
LocalhostCert, err = os.ReadFile("./resources/tls/local.cert")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
LocalhostKey, err = os.ReadFile("./resources/tls/local.key")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}
func (s *myserver) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
@ -137,19 +143,18 @@ func callStreamExampleClientGRPC() (helloworld.Greeter_StreamExampleClient, func
return t, closer, nil
}
func (s *GRPCSuite) TestGRPC(c *check.C) {
func (s *GRPCSuite) TestGRPC() {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := startGRPCServer(lis, &myserver{})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config.toml", struct {
file := s.adaptFile("fixtures/grpc/config.toml", struct {
CertContent string
KeyContent string
GRPCServerPort string
@ -159,79 +164,65 @@ func (s *GRPCSuite) TestGRPC(c *check.C) {
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var response string
err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true)
return err
})
c.Assert(err, check.IsNil)
c.Assert(response, check.Equals, "Hello World")
assert.NoError(s.T(), err)
assert.Equal(s.T(), "Hello World", response)
}
func (s *GRPCSuite) TestGRPCh2c(c *check.C) {
func (s *GRPCSuite) TestGRPCh2c() {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := starth2cGRPCServer(lis, &myserver{})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config_h2c.toml", struct {
file := s.adaptFile("fixtures/grpc/config_h2c.toml", struct {
GRPCServerPort string
}{
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var response string
err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", false)
return err
})
c.Assert(err, check.IsNil)
c.Assert(response, check.Equals, "Hello World")
assert.NoError(s.T(), err)
assert.Equal(s.T(), "Hello World", response)
}
func (s *GRPCSuite) TestGRPCh2cTermination(c *check.C) {
func (s *GRPCSuite) TestGRPCh2cTermination() {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := starth2cGRPCServer(lis, &myserver{})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config_h2c_termination.toml", struct {
file := s.adaptFile("fixtures/grpc/config_h2c_termination.toml", struct {
CertContent string
KeyContent string
GRPCServerPort string
@ -241,40 +232,33 @@ func (s *GRPCSuite) TestGRPCh2cTermination(c *check.C) {
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var response string
err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true)
return err
})
c.Assert(err, check.IsNil)
c.Assert(response, check.Equals, "Hello World")
assert.NoError(s.T(), err)
assert.Equal(s.T(), "Hello World", response)
}
func (s *GRPCSuite) TestGRPCInsecure(c *check.C) {
func (s *GRPCSuite) TestGRPCInsecure() {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := startGRPCServer(lis, &myserver{})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config_insecure.toml", struct {
file := s.adaptFile("fixtures/grpc/config_insecure.toml", struct {
CertContent string
KeyContent string
GRPCServerPort string
@ -284,44 +268,37 @@ func (s *GRPCSuite) TestGRPCInsecure(c *check.C) {
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var response string
err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true)
return err
})
c.Assert(err, check.IsNil)
c.Assert(response, check.Equals, "Hello World")
assert.NoError(s.T(), err)
assert.Equal(s.T(), "Hello World", response)
}
func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
func (s *GRPCSuite) TestGRPCBuffer() {
stopStreamExample := make(chan bool)
defer func() { stopStreamExample <- true }()
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := startGRPCServer(lis, &myserver{
stopStreamExample: stopStreamExample,
})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config.toml", struct {
file := s.adaptFile("fixtures/grpc/config.toml", struct {
CertContent string
KeyContent string
GRPCServerPort string
@ -331,27 +308,21 @@ func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC()
defer func() { _ = closer() }()
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
received := make(chan bool)
go func() {
tr, err := client.Recv()
c.Assert(err, check.IsNil)
c.Assert(len(tr.GetData()), check.Equals, 512)
assert.NoError(s.T(), err)
assert.Len(s.T(), tr.GetData(), 512)
received <- true
}()
@ -363,25 +334,24 @@ func (s *GRPCSuite) TestGRPCBuffer(c *check.C) {
return errors.New("failed to receive stream data")
}
})
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}
func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
func (s *GRPCSuite) TestGRPCBufferWithFlushInterval() {
stopStreamExample := make(chan bool)
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := startGRPCServer(lis, &myserver{
stopStreamExample: stopStreamExample,
})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config.toml", struct {
file := s.adaptFile("fixtures/grpc/config.toml", struct {
CertContent string
KeyContent string
GRPCServerPort string
@ -390,17 +360,11 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
KeyContent: string(LocalhostKey),
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC()
@ -408,13 +372,13 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
_ = closer()
stopStreamExample <- true
}()
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
received := make(chan bool)
go func() {
tr, err := client.Recv()
c.Assert(err, check.IsNil)
c.Assert(len(tr.GetData()), check.Equals, 512)
assert.NoError(s.T(), err)
assert.Len(s.T(), tr.GetData(), 512)
received <- true
}()
@ -426,22 +390,21 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval(c *check.C) {
return errors.New("failed to receive stream data")
}
})
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}
func (s *GRPCSuite) TestGRPCWithRetry(c *check.C) {
func (s *GRPCSuite) TestGRPCWithRetry() {
lis, err := net.Listen("tcp", ":0")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
_, port, err := net.SplitHostPort(lis.Addr().String())
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
go func() {
err := startGRPCServer(lis, &myserver{})
c.Log(err)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
}()
file := s.adaptFile(c, "fixtures/grpc/config_retry.toml", struct {
file := s.adaptFile("fixtures/grpc/config_retry.toml", struct {
CertContent string
KeyContent string
GRPCServerPort string
@ -451,23 +414,17 @@ func (s *GRPCSuite) TestGRPCWithRetry(c *check.C) {
GRPCServerPort: port,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
var response string
err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true)
return err
})
c.Assert(err, check.IsNil)
c.Assert(response, check.Equals, "Hello World")
assert.NoError(s.T(), err)
assert.Equal(s.T(), "Hello World", response)
}

View file

@ -4,50 +4,45 @@ import (
"net"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// Headers tests suite.
type HeadersSuite struct{ BaseSuite }
func (s *HeadersSuite) TestSimpleConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/headers/basic.toml"))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// 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)
func TestHeadersSuite(t *testing.T) {
suite.Run(t, new(HeadersSuite))
}
func (s *HeadersSuite) TestReverseProxyHeaderRemoved(c *check.C) {
file := s.adaptFile(c, "fixtures/headers/remove_reverseproxy_headers.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
func (s *HeadersSuite) TestSimpleConfiguration() {
s.traefikCmd(withConfigFile("fixtures/headers/basic.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// 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))
require.NoError(s.T(), err)
}
func (s *HeadersSuite) TestReverseProxyHeaderRemoved() {
file := s.adaptFile("fixtures/headers/remove_reverseproxy_headers.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, found := r.Header["X-Forwarded-Host"]
c.Assert(found, checker.True)
assert.True(s.T(), found)
_, found = r.Header["Foo"]
c.Assert(found, checker.False)
assert.False(s.T(), found)
_, found = r.Header["X-Forwarded-For"]
c.Assert(found, checker.False)
assert.False(s.T(), found)
})
listener, err := net.Listen("tcp", "127.0.0.1:9000")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
ts := &httptest.Server{
Listener: listener,
@ -57,31 +52,25 @@ func (s *HeadersSuite) TestReverseProxyHeaderRemoved(c *check.C) {
defer ts.Close()
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "test.localhost"
req.Header = http.Header{
"Foo": {"bar"},
}
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *HeadersSuite) TestCorsResponses(c *check.C) {
file := s.adaptFile(c, "fixtures/headers/cors.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *HeadersSuite) TestCorsResponses() {
file := s.adaptFile("fixtures/headers/cors.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
backend := startTestServer("9000", http.StatusOK, "")
defer backend.Close()
err = try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err := try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
testCase := []struct {
desc string
@ -147,30 +136,24 @@ func (s *HeadersSuite) TestCorsResponses(c *check.C) {
for _, test := range testCase {
req, err := http.NewRequest(test.method, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = test.reqHost
req.Header = test.requestHeaders
err = try.Request(req, 500*time.Millisecond, try.HasHeaderStruct(test.expected))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
}
func (s *HeadersSuite) TestSecureHeadersResponses(c *check.C) {
file := s.adaptFile(c, "fixtures/headers/secure.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *HeadersSuite) TestSecureHeadersResponses() {
file := s.adaptFile("fixtures/headers/secure.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
backend := startTestServer("9000", http.StatusOK, "")
defer backend.Close()
err = try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err := try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
testCase := []struct {
desc string
@ -190,36 +173,30 @@ func (s *HeadersSuite) TestSecureHeadersResponses(c *check.C) {
for _, test := range testCase {
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = test.reqHost
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasHeaderStruct(test.expected))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/api/rawdata", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = test.internalReqHost
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasHeaderStruct(test.expected))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
}
func (s *HeadersSuite) TestMultipleSecureHeadersResponses(c *check.C) {
file := s.adaptFile(c, "fixtures/headers/secure_multiple.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *HeadersSuite) TestMultipleSecureHeadersResponses() {
file := s.adaptFile("fixtures/headers/secure_multiple.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
backend := startTestServer("9000", http.StatusOK, "")
defer backend.Close()
err = try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err := try.GetRequest(backend.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
testCase := []struct {
desc string
@ -238,10 +215,10 @@ func (s *HeadersSuite) TestMultipleSecureHeadersResponses(c *check.C) {
for _, test := range testCase {
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = test.reqHost
err = try.Request(req, 500*time.Millisecond, try.HasHeaderStruct(test.expected))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
}

View file

@ -7,11 +7,13 @@ import (
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// HealthCheck test suites.
@ -23,287 +25,272 @@ type HealthCheckSuite struct {
whoami4IP string
}
func (s *HealthCheckSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "healthcheck")
s.composeUp(c)
s.whoami1IP = s.getComposeServiceIP(c, "whoami1")
s.whoami2IP = s.getComposeServiceIP(c, "whoami2")
s.whoami3IP = s.getComposeServiceIP(c, "whoami3")
s.whoami4IP = s.getComposeServiceIP(c, "whoami4")
func TestHealthCheckSuite(t *testing.T) {
suite.Run(t, new(HealthCheckSuite))
}
func (s *HealthCheckSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/healthcheck/simple.toml", struct {
func (s *HealthCheckSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("healthcheck")
s.composeUp()
s.whoami1IP = s.getComposeServiceIP("whoami1")
s.whoami2IP = s.getComposeServiceIP("whoami2")
s.whoami3IP = s.getComposeServiceIP("whoami3")
s.whoami4IP = s.getComposeServiceIP("whoami4")
}
func (s *HealthCheckSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *HealthCheckSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/healthcheck/simple.toml", struct {
Server1 string
Server2 string
}{s.whoami1IP, s.whoami2IP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`test.localhost`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`test.localhost`)"))
require.NoError(s.T(), err)
frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendHealthReq.Host = "test.localhost"
err = try.Request(frontendHealthReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Fix all whoami health to 500
client := &http.Client{}
whoamiHosts := []string{s.whoami1IP, s.whoami2IP}
for _, whoami := range whoamiHosts {
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+whoami+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
// Verify no backend service is available due to failing health checks
err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Change one whoami health to 200
statusOKReq1, err := http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBufferString("200"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusOKReq1)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify frontend health : after
err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendReq.Host = "test.localhost"
// Check if whoami1 responds
err = try.Request(frontendReq, 500*time.Millisecond, try.BodyContains(s.whoami1IP))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Check if the service with bad health check (whoami2) never respond.
err = try.Request(frontendReq, 2*time.Second, try.BodyContains(s.whoami2IP))
c.Assert(err, checker.NotNil)
assert.Error(s.T(), err)
// TODO validate : run on 80
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, http.StatusNotFound)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusNotFound, resp.StatusCode)
}
func (s *HealthCheckSuite) TestMultipleEntrypoints(c *check.C) {
file := s.adaptFile(c, "fixtures/healthcheck/multiple-entrypoints.toml", struct {
func (s *HealthCheckSuite) TestMultipleEntrypoints() {
file := s.adaptFile("fixtures/healthcheck/multiple-entrypoints.toml", struct {
Server1 string
Server2 string
}{s.whoami1IP, s.whoami2IP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// Wait for traefik
err = try.GetRequest("http://localhost:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`test.localhost`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`test.localhost`)"))
require.NoError(s.T(), err)
// Check entrypoint http1
frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendHealthReq.Host = "test.localhost"
err = try.Request(frontendHealthReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.Request(frontendHealthReq, 5*time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
// Check entrypoint http2
frontendHealthReq, err = http.NewRequest(http.MethodGet, "http://127.0.0.1:9000/health", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendHealthReq.Host = "test.localhost"
err = try.Request(frontendHealthReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.Request(frontendHealthReq, 5*time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
// Set the both whoami health to 500
client := &http.Client{}
whoamiHosts := []string{s.whoami1IP, s.whoami2IP}
for _, whoami := range whoamiHosts {
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+whoami+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
// Verify no backend service is available due to failing health checks
err = try.Request(frontendHealthReq, 5*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// reactivate the whoami2
statusInternalServerOkReq, err := http.NewRequest(http.MethodPost, "http://"+s.whoami2IP+"/health", bytes.NewBufferString("200"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerOkReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontend1Req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontend1Req.Host = "test.localhost"
frontend2Req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:9000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontend2Req.Host = "test.localhost"
// Check if whoami1 never responds
err = try.Request(frontend2Req, 2*time.Second, try.BodyContains(s.whoami1IP))
c.Assert(err, checker.NotNil)
assert.Error(s.T(), err)
// Check if whoami1 never responds
err = try.Request(frontend1Req, 2*time.Second, try.BodyContains(s.whoami1IP))
c.Assert(err, checker.NotNil)
assert.Error(s.T(), err)
}
func (s *HealthCheckSuite) TestPortOverload(c *check.C) {
func (s *HealthCheckSuite) TestPortOverload() {
// Set one whoami health to 200
client := &http.Client{}
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBufferString("200"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
file := s.adaptFile(c, "fixtures/healthcheck/port_overload.toml", struct {
file := s.adaptFile("fixtures/healthcheck/port_overload.toml", struct {
Server1 string
}{s.whoami1IP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("Host(`test.localhost`)"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendHealthReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
frontendHealthReq.Host = "test.localhost"
// We test bad gateway because we use an invalid port for the backend
err = try.Request(frontendHealthReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Set one whoami health to 500
statusInternalServerErrorReq, err = http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify no backend service is available due to failing health checks
err = try.Request(frontendHealthReq, 3*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
// Checks if all the loadbalancers created will correctly update the server status.
func (s *HealthCheckSuite) TestMultipleRoutersOnSameService(c *check.C) {
file := s.adaptFile(c, "fixtures/healthcheck/multiple-routers-one-same-service.toml", struct {
func (s *HealthCheckSuite) TestMultipleRoutersOnSameService() {
file := s.adaptFile("fixtures/healthcheck/multiple-routers-one-same-service.toml", struct {
Server1 string
}{s.whoami1IP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`test.localhost`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`test.localhost`)"))
require.NoError(s.T(), err)
// Set whoami health to 200 to be sure to start with the wanted status
client := &http.Client{}
statusOkReq, err := http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBufferString("200"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusOkReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// check healthcheck on web1 entrypoint
healthReqWeb1, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/health", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
healthReqWeb1.Host = "test.localhost"
err = try.Request(healthReqWeb1, 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// check healthcheck on web2 entrypoint
healthReqWeb2, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:9000/health", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
healthReqWeb2.Host = "test.localhost"
err = try.Request(healthReqWeb2, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Set whoami health to 500
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify no backend service is available due to failing health checks
err = try.Request(healthReqWeb1, 3*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(healthReqWeb2, 3*time.Second, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Change one whoami health to 200
statusOKReq1, err := http.NewRequest(http.MethodPost, "http://"+s.whoami1IP+"/health", bytes.NewBufferString("200"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusOKReq1)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify health check
err = try.Request(healthReqWeb1, 3*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(healthReqWeb2, 3*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *HealthCheckSuite) TestPropagate(c *check.C) {
file := s.adaptFile(c, "fixtures/healthcheck/propagate.toml", struct {
func (s *HealthCheckSuite) TestPropagate() {
file := s.adaptFile("fixtures/healthcheck/propagate.toml", struct {
Server1 string
Server2 string
Server3 string
Server4 string
}{s.whoami1IP, s.whoami2IP, s.whoami3IP, s.whoami4IP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`root.localhost`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`root.localhost`)"))
require.NoError(s.T(), err)
rootReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
rootReq.Host = "root.localhost"
err = try.Request(rootReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Bring whoami1 and whoami3 down
client := http.Client{
@ -313,9 +300,9 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
whoamiHosts := []string{s.whoami1IP, s.whoami3IP}
for _, whoami := range whoamiHosts {
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+whoami+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
try.Sleep(time.Second)
@ -327,19 +314,19 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
reachedServers := make(map[string]int)
for i := 0; i < 4; i++ {
resp, err := client.Do(rootReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if reachedServers[s.whoami4IP] > reachedServers[s.whoami2IP] {
c.Assert(string(body), checker.Contains, want2)
assert.Contains(s.T(), string(body), want2)
reachedServers[s.whoami2IP]++
continue
}
if reachedServers[s.whoami2IP] > reachedServers[s.whoami4IP] {
c.Assert(string(body), checker.Contains, want4)
assert.Contains(s.T(), string(body), want4)
reachedServers[s.whoami4IP]++
continue
}
@ -356,48 +343,48 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
}
}
c.Assert(reachedServers[s.whoami2IP], checker.Equals, 2)
c.Assert(reachedServers[s.whoami4IP], checker.Equals, 2)
assert.Equal(s.T(), 2, reachedServers[s.whoami2IP])
assert.Equal(s.T(), 2, reachedServers[s.whoami4IP])
fooReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
fooReq.Host = "foo.localhost"
// Verify load-balancing on foo still works, and that we're getting wsp2, wsp2, wsp2, wsp2, etc.
want := `IP: ` + s.whoami2IP
for i := 0; i < 4; i++ {
resp, err := client.Do(fooReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
c.Assert(string(body), checker.Contains, want)
assert.Contains(s.T(), string(body), want)
}
barReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
barReq.Host = "bar.localhost"
// Verify load-balancing on bar still works, and that we're getting wsp2, wsp2, wsp2, wsp2, etc.
want = `IP: ` + s.whoami2IP
for i := 0; i < 4; i++ {
resp, err := client.Do(barReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
c.Assert(string(body), checker.Contains, want)
assert.Contains(s.T(), string(body), want)
}
// Bring whoami2 and whoami4 down
whoamiHosts = []string{s.whoami2IP, s.whoami4IP}
for _, whoami := range whoamiHosts {
statusInternalServerErrorReq, err := http.NewRequest(http.MethodPost, "http://"+whoami+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusInternalServerErrorReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
try.Sleep(time.Second)
@ -405,25 +392,25 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
// Verify that everything is down, and that we get 503s everywhere.
for i := 0; i < 2; i++ {
resp, err := client.Do(rootReq)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusServiceUnavailable)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusServiceUnavailable, resp.StatusCode)
resp, err = client.Do(fooReq)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusServiceUnavailable)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusServiceUnavailable, resp.StatusCode)
resp, err = client.Do(barReq)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, http.StatusServiceUnavailable)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusServiceUnavailable, resp.StatusCode)
}
// Bring everything back up.
whoamiHosts = []string{s.whoami1IP, s.whoami2IP, s.whoami3IP, s.whoami4IP}
for _, whoami := range whoamiHosts {
statusOKReq, err := http.NewRequest(http.MethodPost, "http://"+whoami+"/health", bytes.NewBufferString("200"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusOKReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
try.Sleep(time.Second)
@ -432,10 +419,10 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
reachedServers = make(map[string]int)
for i := 0; i < 4; i++ {
resp, err := client.Do(rootReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if strings.Contains(string(body), `IP: `+s.whoami1IP) {
reachedServers[s.whoami1IP]++
@ -458,19 +445,19 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
}
}
c.Assert(reachedServers[s.whoami1IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami2IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami3IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami4IP], checker.Equals, 1)
assert.Equal(s.T(), 1, reachedServers[s.whoami1IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami2IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami3IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami4IP])
// Verify everything is up on foo router.
reachedServers = make(map[string]int)
for i := 0; i < 4; i++ {
resp, err := client.Do(fooReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if strings.Contains(string(body), `IP: `+s.whoami1IP) {
reachedServers[s.whoami1IP]++
@ -493,19 +480,19 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
}
}
c.Assert(reachedServers[s.whoami1IP], checker.Equals, 2)
c.Assert(reachedServers[s.whoami2IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami3IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami4IP], checker.Equals, 0)
assert.Equal(s.T(), 2, reachedServers[s.whoami1IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami2IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami3IP])
assert.Equal(s.T(), 0, reachedServers[s.whoami4IP])
// Verify everything is up on bar router.
reachedServers = make(map[string]int)
for i := 0; i < 4; i++ {
resp, err := client.Do(barReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if strings.Contains(string(body), `IP: `+s.whoami1IP) {
reachedServers[s.whoami1IP]++
@ -528,102 +515,87 @@ func (s *HealthCheckSuite) TestPropagate(c *check.C) {
}
}
c.Assert(reachedServers[s.whoami1IP], checker.Equals, 2)
c.Assert(reachedServers[s.whoami2IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami3IP], checker.Equals, 1)
c.Assert(reachedServers[s.whoami4IP], checker.Equals, 0)
assert.Equal(s.T(), 2, reachedServers[s.whoami1IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami2IP])
assert.Equal(s.T(), 1, reachedServers[s.whoami3IP])
assert.Equal(s.T(), 0, reachedServers[s.whoami4IP])
}
func (s *HealthCheckSuite) TestPropagateNoHealthCheck(c *check.C) {
file := s.adaptFile(c, "fixtures/healthcheck/propagate_no_healthcheck.toml", struct {
func (s *HealthCheckSuite) TestPropagateNoHealthCheck() {
file := s.adaptFile("fixtures/healthcheck/propagate_no_healthcheck.toml", struct {
Server1 string
}{s.whoami1IP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`noop.localhost`)"), try.BodyNotContains("Host(`root.localhost`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`noop.localhost`)"), try.BodyNotContains("Host(`root.localhost`)"))
require.NoError(s.T(), err)
rootReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
rootReq.Host = "root.localhost"
err = try.Request(rootReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *HealthCheckSuite) TestPropagateReload(c *check.C) {
func (s *HealthCheckSuite) TestPropagateReload() {
// Setup a WSP service without the healthcheck enabled (wsp-service1)
withoutHealthCheck := s.adaptFile(c, "fixtures/healthcheck/reload_without_healthcheck.toml", struct {
withoutHealthCheck := s.adaptFile("fixtures/healthcheck/reload_without_healthcheck.toml", struct {
Server1 string
Server2 string
}{s.whoami1IP, s.whoami2IP})
defer os.Remove(withoutHealthCheck)
withHealthCheck := s.adaptFile(c, "fixtures/healthcheck/reload_with_healthcheck.toml", struct {
withHealthCheck := s.adaptFile("fixtures/healthcheck/reload_with_healthcheck.toml", struct {
Server1 string
Server2 string
}{s.whoami1IP, s.whoami2IP})
defer os.Remove(withHealthCheck)
cmd, display := s.traefikCmd(withConfigFile(withoutHealthCheck))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(withoutHealthCheck))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`root.localhost`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Host(`root.localhost`)"))
require.NoError(s.T(), err)
// Allow one of the underlying services on it to fail all servers HC (whoami2)
client := http.Client{
Timeout: 10 * time.Second,
}
statusOKReq, err := http.NewRequest(http.MethodPost, "http://"+s.whoami2IP+"/health", bytes.NewBufferString("500"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = client.Do(statusOKReq)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
rootReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
rootReq.Host = "root.localhost"
// Check the failed service (whoami2) is getting requests, but answer 500
err = try.Request(rootReq, 500*time.Millisecond, try.StatusCodeIs(http.StatusServiceUnavailable))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Enable the healthcheck on the root WSP (wsp-service1) and let Traefik reload the config
fr1, err := os.OpenFile(withoutHealthCheck, os.O_APPEND|os.O_WRONLY, 0o644)
c.Assert(fr1, checker.NotNil)
c.Assert(err, checker.IsNil)
assert.NotNil(s.T(), fr1)
require.NoError(s.T(), err)
err = fr1.Truncate(0)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
fr2, err := os.ReadFile(withHealthCheck)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = fmt.Fprint(fr1, string(fr2))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = fr1.Close()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
try.Sleep(1 * time.Second)
// Waiting for the reflected change.
err = try.Request(rootReq, 5*time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
// Check the failed service (whoami2) is not getting requests
wantIPs := []string{s.whoami1IP, s.whoami1IP, s.whoami1IP, s.whoami1IP}
for _, ip := range wantIPs {
want := "IP: " + ip
resp, err := client.Do(rootReq)
c.Assert(err, checker.IsNil)
body, err := io.ReadAll(resp.Body)
c.Assert(err, checker.IsNil)
c.Assert(string(body), checker.Contains, want)
err = try.Request(rootReq, 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("IP: "+ip))
require.NoError(s.T(), err)
}
}

View file

@ -2,27 +2,33 @@ package integration
import (
"net/http"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type HostResolverSuite struct{ BaseSuite }
func (s *HostResolverSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "hostresolver")
s.composeUp(c)
func TestHostResolverSuite(t *testing.T) {
suite.Run(t, new(HostResolverSuite))
}
func (s *HostResolverSuite) TestSimpleConfig(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/simple_hostresolver.toml"))
defer display(c)
func (s *HostResolverSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.createComposeProject("hostresolver")
s.composeUp()
}
func (s *HostResolverSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *HostResolverSuite) TestSimpleConfig() {
s.traefikCmd(withConfigFile("fixtures/simple_hostresolver.toml"))
testCase := []struct {
desc string
@ -43,10 +49,10 @@ func (s *HostResolverSuite) TestSimpleConfig(c *check.C) {
for _, test := range testCase {
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = test.host
err = try.Request(req, 1*time.Second, try.StatusCodeIs(test.status), try.HasBody())
c.Assert(err, checker.IsNil)
err = try.Request(req, 5*time.Second, try.StatusCodeIs(test.status), try.HasBody())
require.NoError(s.T(), err)
}
}

View file

@ -5,28 +5,27 @@ import (
"net"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
checker "github.com/vdemeester/shakers"
)
type HTTPSuite struct{ BaseSuite }
func (s *HTTPSuite) TestSimpleConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/http/simple.toml"))
defer display(c)
func TestHTTPSuite(t *testing.T) {
suite.Run(t, new(HTTPSuite))
}
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
func (s *HTTPSuite) TestSimpleConfiguration() {
s.traefikCmd(withConfigFile("fixtures/http/simple.toml"))
// Expect a 404 as we configured nothing.
err = try.GetRequest("http://127.0.0.1:8000/", time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8000/", time.Second, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
// Provide a configuration, fetched by Traefik provider.
configuration := &dynamic.Configuration{
@ -55,14 +54,14 @@ func (s *HTTPSuite) TestSimpleConfiguration(c *check.C) {
}
configData, err := json.Marshal(configuration)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
server := startTestServerWithResponse(configData)
defer server.Close()
// Expect configuration to be applied.
err = try.GetRequest("http://127.0.0.1:9090/api/rawdata", 3*time.Second, try.BodyContains("routerHTTP@http", "serviceHTTP@http", "http://bacon:80"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func startTestServerWithResponse(response []byte) (ts *httptest.Server) {

File diff suppressed because it is too large Load diff

View file

@ -9,210 +9,325 @@ import (
"fmt"
"io"
"io/fs"
stdlog "log"
"net/http"
"os"
"os/exec"
"path/filepath"
"regexp"
"slices"
"strings"
"testing"
"text/template"
"time"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/context/docker"
"github.com/docker/cli/cli/context/store"
manifeststore "github.com/docker/cli/cli/manifest/store"
registryclient "github.com/docker/cli/cli/registry/client"
"github.com/docker/cli/cli/streams"
"github.com/docker/cli/cli/trust"
cmdcompose "github.com/docker/compose/v2/cmd/compose"
"github.com/docker/compose/v2/cmd/formatter"
composeapi "github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/compose"
dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
dockernetwork "github.com/docker/docker/api/types/network"
"github.com/fatih/structs"
"github.com/go-check/check"
notaryclient "github.com/theupdateframework/notary/client"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/network"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
checker "github.com/vdemeester/shakers"
"gopkg.in/yaml.v3"
)
var (
integration = flag.Bool("integration", false, "run integration tests")
showLog = flag.Bool("tlog", false, "always show Traefik logs")
)
var showLog = flag.Bool("tlog", false, "always show Traefik logs")
func Test(t *testing.T) {
if !*integration {
log.WithoutContext().Info("Integration tests disabled.")
return
}
type composeConfig struct {
Services map[string]composeService `yaml:"services"`
}
// TODO(mpl): very niche optimization: do not start tailscale if none of the
// wanted tests actually need it (e.g. KeepAliveSuite does not).
var (
vpn *tailscaleNotSuite
useVPN bool
)
if os.Getenv("IN_DOCKER") != "true" {
if vpn = setupVPN(nil, "tailscale.secret"); vpn != nil {
defer vpn.TearDownSuite(nil)
useVPN = true
}
}
type composeService struct {
Image string `yaml:"image"`
Labels map[string]string `yaml:"labels"`
Hostname string `yaml:"hostname"`
Volumes []string `yaml:"volumes"`
CapAdd []string `yaml:"cap_add"`
Command []string `yaml:"command"`
Environment map[string]string `yaml:"environment"`
Privileged bool `yaml:"privileged"`
Deploy composeDeploy `yaml:"deploy"`
}
check.Suite(&AccessLogSuite{})
if !useVPN {
check.Suite(&AcmeSuite{})
}
check.Suite(&ConsulCatalogSuite{})
check.Suite(&ConsulSuite{})
check.Suite(&DockerComposeSuite{})
check.Suite(&DockerSuite{})
check.Suite(&ErrorPagesSuite{})
check.Suite(&EtcdSuite{})
check.Suite(&FileSuite{})
check.Suite(&GRPCSuite{})
check.Suite(&HeadersSuite{})
check.Suite(&HealthCheckSuite{})
check.Suite(&HostResolverSuite{})
check.Suite(&HTTPSSuite{})
check.Suite(&HTTPSuite{})
if !useVPN {
check.Suite(&K8sSuite{})
}
check.Suite(&KeepAliveSuite{})
check.Suite(&LogRotationSuite{})
check.Suite(&MarathonSuite{})
check.Suite(&MarathonSuite15{})
if !useVPN {
check.Suite(&ProxyProtocolSuite{})
}
check.Suite(&RateLimitSuite{})
check.Suite(&RedisSuite{})
check.Suite(&RestSuite{})
check.Suite(&RetrySuite{})
check.Suite(&SimpleSuite{})
check.Suite(&TCPSuite{})
check.Suite(&TimeoutSuite{})
check.Suite(&ThrottlingSuite{})
check.Suite(&TLSClientHeadersSuite{})
check.Suite(&TracingSuite{})
check.Suite(&UDPSuite{})
check.Suite(&WebsocketSuite{})
check.Suite(&ZookeeperSuite{})
check.TestingT(t)
type composeDeploy struct {
Replicas int `yaml:"replicas"`
}
var traefikBinary = "../dist/traefik"
type BaseSuite struct {
composeProjectOptions *cmdcompose.ProjectOptions
dockerComposeService composeapi.Service
dockerClient *client.Client
suite.Suite
containers map[string]testcontainers.Container
network *testcontainers.DockerNetwork
hostIP string
}
func (s *BaseSuite) TearDownSuite(c *check.C) {
if s.composeProjectOptions != nil && s.dockerComposeService != nil {
s.composeDown(c)
func (s *BaseSuite) waitForTraefik(containerName string) {
time.Sleep(1 * time.Second)
// Wait for Traefik to turn ready.
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
require.NoError(s.T(), err)
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains(containerName))
require.NoError(s.T(), err)
}
func (s *BaseSuite) displayTraefikLogFile(path string) {
if s.T().Failed() {
if _, err := os.Stat(path); !os.IsNotExist(err) {
content, errRead := os.ReadFile(path)
// TODO TestName
// fmt.Printf("%s: Traefik logs: \n", c.TestName())
fmt.Print("Traefik logs: \n")
if errRead == nil {
fmt.Println(content)
} else {
fmt.Println(errRead)
}
} else {
// fmt.Printf("%s: No Traefik logs.\n", c.TestName())
fmt.Print("No Traefik logs.\n")
}
errRemove := os.Remove(path)
if errRemove != nil {
fmt.Println(errRemove)
}
}
}
func (s *BaseSuite) SetupSuite() {
// configure default standard log.
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
// TODO
// stdlog.SetOutput(log.Logger)
ctx := context.Background()
// Create docker network
// docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
var opts []network.NetworkCustomizer
opts = append(opts, network.WithDriver("bridge"))
opts = append(opts, network.WithIPAM(&dockernetwork.IPAM{
Driver: "default",
Config: []dockernetwork.IPAMConfig{
{
Subnet: "172.31.42.0/24",
},
},
}))
dockerNetwork, err := network.New(ctx, opts...)
require.NoError(s.T(), err)
s.network = dockerNetwork
s.hostIP = "172.31.42.1"
if isDockerDesktop(ctx, s.T()) {
s.hostIP = getDockerDesktopHostIP(ctx, s.T())
s.setupVPN("tailscale.secret")
}
}
func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string {
t.Helper()
req := testcontainers.ContainerRequest{
Image: "alpine",
HostConfigModifier: func(config *container.HostConfig) {
config.AutoRemove = true
},
Cmd: []string{"getent", "hosts", "host.docker.internal"},
}
con, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
require.NoError(t, err)
closer, err := con.Logs(ctx)
require.NoError(t, err)
all, err := io.ReadAll(closer)
require.NoError(t, err)
ipRegex := regexp.MustCompile(`\b(?:\d{1,3}\.){3}\d{1,3}\b`)
matches := ipRegex.FindAllString(string(all), -1)
require.Len(t, matches, 1)
return matches[0]
}
func isDockerDesktop(ctx context.Context, t *testing.T) bool {
t.Helper()
cli, err := testcontainers.NewDockerClientWithOpts(ctx)
if err != nil {
t.Fatalf("failed to create docker client: %s", err)
}
info, err := cli.Info(ctx)
if err != nil {
t.Fatalf("failed to get docker info: %s", err)
}
return info.OperatingSystem == "Docker Desktop"
}
func (s *BaseSuite) TearDownSuite() {
s.composeDown()
err := try.Do(5*time.Second, func() error {
if s.network != nil {
err := s.network.Remove(context.Background())
if err != nil {
return err
}
}
return nil
})
require.NoError(s.T(), err)
}
// createComposeProject creates the docker compose project stored as a field in the BaseSuite.
// This method should be called before starting and/or stopping compose services.
func (s *BaseSuite) createComposeProject(c *check.C, name string) {
projectName := fmt.Sprintf("traefik-integration-test-%s", name)
func (s *BaseSuite) createComposeProject(name string) {
composeFile := fmt.Sprintf("resources/compose/%s.yml", name)
var err error
s.dockerClient, err = client.NewClientWithOpts()
c.Assert(err, checker.IsNil)
file, err := os.ReadFile(composeFile)
require.NoError(s.T(), err)
fakeCLI := &FakeDockerCLI{client: s.dockerClient}
s.dockerComposeService = compose.NewComposeService(fakeCLI)
var composeConfigData composeConfig
err = yaml.Unmarshal(file, &composeConfigData)
require.NoError(s.T(), err)
s.composeProjectOptions = &cmdcompose.ProjectOptions{
ProjectDir: ".",
ProjectName: projectName,
ConfigPaths: []string{composeFile},
if s.containers == nil {
s.containers = map[string]testcontainers.Container{}
}
ctx := context.Background()
for id, containerConfig := range composeConfigData.Services {
var mounts []mount.Mount
for _, volume := range containerConfig.Volumes {
split := strings.Split(volume, ":")
if len(split) != 2 {
continue
}
if strings.HasPrefix(split[0], "./") {
path, err := os.Getwd()
if err != nil {
log.WithoutContext().Errorf("can't determine current directory: %v", err)
continue
}
split[0] = strings.Replace(split[0], "./", path+"/", 1)
}
abs, err := filepath.Abs(split[0])
require.NoError(s.T(), err)
mounts = append(mounts, mount.Mount{Source: abs, Target: split[1], Type: mount.TypeBind})
}
if containerConfig.Deploy.Replicas > 0 {
for i := 0; i < containerConfig.Deploy.Replicas; i++ {
id = fmt.Sprintf("%s-%d", id, i+1)
con, err := s.createContainer(ctx, containerConfig, id, mounts)
require.NoError(s.T(), err)
s.containers[id] = con
}
continue
}
con, err := s.createContainer(ctx, containerConfig, id, mounts)
require.NoError(s.T(), err)
s.containers[id] = con
}
}
func (s *BaseSuite) createContainer(ctx context.Context, containerConfig composeService, id string, mounts []mount.Mount) (testcontainers.Container, error) {
req := testcontainers.ContainerRequest{
Image: containerConfig.Image,
Env: containerConfig.Environment,
Cmd: containerConfig.Command,
Labels: containerConfig.Labels,
Name: id,
Hostname: containerConfig.Hostname,
Privileged: containerConfig.Privileged,
Networks: []string{s.network.Name},
HostConfigModifier: func(config *container.HostConfig) {
if containerConfig.CapAdd != nil {
config.CapAdd = containerConfig.CapAdd
}
if !isDockerDesktop(ctx, s.T()) {
config.ExtraHosts = append(config.ExtraHosts, "host.docker.internal:"+s.hostIP)
}
config.Mounts = mounts
},
}
con, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: false,
})
return con, err
}
// composeUp starts the given services of the current docker compose project, if they are not already started.
// Already running services are not affected (i.e. not stopped).
func (s *BaseSuite) composeUp(c *check.C, services ...string) {
c.Assert(s.composeProjectOptions, check.NotNil)
c.Assert(s.dockerComposeService, check.NotNil)
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
// We use Create and Restart instead of Up, because the only option that actually works to control which containers
// are started is within the RestartOptions.
err = s.dockerComposeService.Create(context.Background(), composeProject, composeapi.CreateOptions{})
c.Assert(err, checker.IsNil)
err = s.dockerComposeService.Restart(context.Background(), composeProject.Name, composeapi.RestartOptions{Services: services})
c.Assert(err, checker.IsNil)
}
// composeExec runs the command in the given args in the given compose service container.
// Already running services are not affected (i.e. not stopped).
func (s *BaseSuite) composeExec(c *check.C, service string, args ...string) {
c.Assert(s.composeProjectOptions, check.NotNil)
c.Assert(s.dockerComposeService, check.NotNil)
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
_, err = s.dockerComposeService.Exec(context.Background(), composeProject.Name, composeapi.RunOptions{
Service: service,
Command: args,
Tty: false,
Index: 1,
})
c.Assert(err, checker.IsNil)
func (s *BaseSuite) composeUp(services ...string) {
for name, con := range s.containers {
if len(services) == 0 || slices.Contains(services, name) {
err := con.Start(context.Background())
require.NoError(s.T(), err)
}
}
}
// composeStop stops the given services of the current docker compose project and removes the corresponding containers.
func (s *BaseSuite) composeStop(c *check.C, services ...string) {
c.Assert(s.composeProjectOptions, check.NotNil)
c.Assert(s.dockerComposeService, check.NotNil)
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
err = s.dockerComposeService.Stop(context.Background(), composeProject.Name, composeapi.StopOptions{Services: services})
c.Assert(err, checker.IsNil)
err = s.dockerComposeService.Remove(context.Background(), composeProject.Name, composeapi.RemoveOptions{})
c.Assert(err, checker.IsNil)
func (s *BaseSuite) composeStop(services ...string) {
for name, con := range s.containers {
if len(services) == 0 || slices.Contains(services, name) {
timeout := 10 * time.Second
err := con.Stop(context.Background(), &timeout)
require.NoError(s.T(), err)
}
}
}
// composeDown stops all compose project services and removes the corresponding containers.
func (s *BaseSuite) composeDown(c *check.C) {
c.Assert(s.composeProjectOptions, check.NotNil)
c.Assert(s.dockerComposeService, check.NotNil)
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
err = s.dockerComposeService.Down(context.Background(), composeProject.Name, composeapi.DownOptions{})
c.Assert(err, checker.IsNil)
func (s *BaseSuite) composeDown() {
for _, c := range s.containers {
err := c.Terminate(context.Background())
require.NoError(s.T(), err)
}
s.containers = map[string]testcontainers.Container{}
}
func (s *BaseSuite) cmdTraefik(args ...string) (*exec.Cmd, *bytes.Buffer) {
cmd := exec.Command(traefikBinary, args...)
s.T().Cleanup(func() {
s.killCmd(cmd)
})
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err := cmd.Start()
require.NoError(s.T(), err)
return cmd, &out
}
func (s *BaseSuite) killCmd(cmd *exec.Cmd) {
if cmd.Process == nil {
log.WithoutContext().Error("No process to kill")
return
}
err := cmd.Process.Kill()
if err != nil {
log.WithoutContext().Errorf("Kill: %v", err)
@ -221,15 +336,18 @@ func (s *BaseSuite) killCmd(cmd *exec.Cmd) {
time.Sleep(100 * time.Millisecond)
}
func (s *BaseSuite) traefikCmd(args ...string) (*exec.Cmd, func(*check.C)) {
func (s *BaseSuite) traefikCmd(args ...string) *exec.Cmd {
cmd, out := s.cmdTraefik(args...)
return cmd, func(c *check.C) {
if c.Failed() || *showLog {
s.T().Cleanup(func() {
if s.T().Failed() || *showLog {
s.displayLogK3S()
s.displayLogCompose(c)
s.displayTraefikLog(c, out)
s.displayLogCompose()
s.displayTraefikLog(out)
}
}
})
return cmd
}
func (s *BaseSuite) displayLogK3S() {
@ -246,34 +364,33 @@ func (s *BaseSuite) displayLogK3S() {
log.WithoutContext().Println()
}
func (s *BaseSuite) displayLogCompose(c *check.C) {
if s.dockerComposeService == nil || s.composeProjectOptions == nil {
log.WithoutContext().Infof("%s: No docker compose logs.", c.TestName())
return
func (s *BaseSuite) displayLogCompose() {
for name, ctn := range s.containers {
readCloser, err := ctn.Logs(context.Background())
require.NoError(s.T(), err)
for {
b := make([]byte, 1024)
_, err := readCloser.Read(b)
if errors.Is(err, io.EOF) {
break
}
require.NoError(s.T(), err)
trimLogs := bytes.Trim(bytes.TrimSpace(b), string([]byte{0}))
if len(trimLogs) > 0 {
log.WithoutContext().WithField("container", name).Info(string(trimLogs))
}
}
}
log.WithoutContext().Infof("%s: docker compose logs: ", c.TestName())
logWriter := log.WithoutContext().WriterLevel(log.GetLevel())
logConsumer := formatter.NewLogConsumer(context.Background(), logWriter, logWriter, false, true, true)
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
err = s.dockerComposeService.Logs(context.Background(), composeProject.Name, logConsumer, composeapi.LogOptions{})
c.Assert(err, checker.IsNil)
log.WithoutContext().Println()
log.WithoutContext().Println("################################")
log.WithoutContext().Println()
}
func (s *BaseSuite) displayTraefikLog(c *check.C, output *bytes.Buffer) {
func (s *BaseSuite) displayTraefikLog(output *bytes.Buffer) {
if output == nil || output.Len() == 0 {
log.WithoutContext().Infof("%s: No Traefik logs.", c.TestName())
log.WithoutContext().Info("No Traefik logs.")
} else {
log.WithoutContext().Infof("%s: Traefik logs: ", c.TestName())
log.WithoutContext().Infof(output.String())
for _, line := range strings.Split(output.String(), "\n") {
log.WithoutContext().Info(line)
}
}
}
@ -287,73 +404,47 @@ func (s *BaseSuite) getDockerHost() string {
return dockerHost
}
func (s *BaseSuite) adaptFile(c *check.C, path string, tempObjects interface{}) string {
func (s *BaseSuite) adaptFile(path string, tempObjects interface{}) string {
// Load file
tmpl, err := template.ParseFiles(path)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
folder, prefix := filepath.Split(path)
tmpFile, err := os.CreateTemp(folder, strings.TrimSuffix(prefix, filepath.Ext(prefix))+"_*"+filepath.Ext(prefix))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
defer tmpFile.Close()
model := structs.Map(tempObjects)
model["SelfFilename"] = tmpFile.Name()
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = tmpFile.Sync()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
s.T().Cleanup(func() {
os.Remove(tmpFile.Name())
})
return tmpFile.Name()
}
func (s *BaseSuite) getComposeServiceIP(c *check.C, name string) string {
c.Assert(s.composeProjectOptions, check.NotNil)
c.Assert(s.dockerComposeService, check.NotNil)
composeProject, err := s.composeProjectOptions.ToProject(nil)
c.Assert(err, checker.IsNil)
filter := filters.NewArgs(
filters.Arg("label", fmt.Sprintf("%s=%s", composeapi.ProjectLabel, composeProject.Name)),
filters.Arg("label", fmt.Sprintf("%s=%s", composeapi.ServiceLabel, name)),
)
containers, err := s.dockerClient.ContainerList(context.Background(), dockertypes.ContainerListOptions{Filters: filter})
c.Assert(err, checker.IsNil)
c.Assert(containers, checker.HasLen, 1)
networkNames := composeProject.NetworkNames()
c.Assert(networkNames, checker.HasLen, 1)
network := composeProject.Networks[networkNames[0]]
return containers[0].NetworkSettings.Networks[network.Name].IPAddress
}
func (s *BaseSuite) getContainerIP(c *check.C, name string) string {
container, err := s.dockerClient.ContainerInspect(context.Background(), name)
c.Assert(err, checker.IsNil)
c.Assert(container.NetworkSettings.Networks, check.NotNil)
for _, network := range container.NetworkSettings.Networks {
return network.IPAddress
func (s *BaseSuite) getComposeServiceIP(name string) string {
container, ok := s.containers[name]
if !ok {
return ""
}
// Should never happen.
c.Error("No network found")
return ""
ip, err := container.ContainerIP(context.Background())
if err != nil {
return ""
}
return ip
}
func withConfigFile(file string) string {
return "--configFile=" + file
}
// tailscaleNotSuite includes a BaseSuite out of convenience, so we can benefit
// from composeUp et co., but it is not meant to function as a TestSuite per se.
type tailscaleNotSuite struct{ BaseSuite }
// setupVPN starts Tailscale on the corresponding container, and makes it a subnet
// router, for all the other containers (whoamis, etc) subsequently started for the
// integration tests.
@ -369,101 +460,35 @@ type tailscaleNotSuite struct{ BaseSuite }
// "172.0.0.0/8": ["your_tailscale_identity"],
// },
// },
//
// TODO(mpl): we could maybe even move this setup to the Makefile, to start it
// and let it run (forever, or until voluntarily stopped).
func setupVPN(c *check.C, keyFile string) *tailscaleNotSuite {
func (s *BaseSuite) setupVPN(keyFile string) {
data, err := os.ReadFile(keyFile)
if err != nil {
if !errors.Is(err, fs.ErrNotExist) {
log.Fatal(err)
log.WithoutContext().Error(err)
}
return nil
return
}
authKey := strings.TrimSpace(string(data))
// TODO: copy and create versions that don't need a check.C?
vpn := &tailscaleNotSuite{}
vpn.createComposeProject(c, "tailscale")
vpn.composeUp(c)
// // TODO: copy and create versions that don't need a check.C?
s.createComposeProject("tailscale")
s.composeUp()
time.Sleep(5 * time.Second)
// If we ever change the docker subnet in the Makefile,
// we need to change this one below correspondingly.
vpn.composeExec(c, "tailscaled", "tailscale", "up", "--authkey="+authKey, "--advertise-routes=172.31.42.0/24")
return vpn
s.composeExec("tailscaled", "tailscale", "up", "--authkey="+authKey, "--advertise-routes=172.31.42.0/24")
}
type FakeDockerCLI struct {
client client.APIClient
}
// composeExec runs the command in the given args in the given compose service container.
// Already running services are not affected (i.e. not stopped).
func (s *BaseSuite) composeExec(service string, args ...string) string {
require.Contains(s.T(), s.containers, service)
func (f FakeDockerCLI) Client() client.APIClient {
return f.client
}
_, reader, err := s.containers[service].Exec(context.Background(), args)
require.NoError(s.T(), err)
func (f FakeDockerCLI) In() *streams.In {
return streams.NewIn(os.Stdin)
}
content, err := io.ReadAll(reader)
require.NoError(s.T(), err)
func (f FakeDockerCLI) Out() *streams.Out {
return streams.NewOut(os.Stdout)
}
func (f FakeDockerCLI) Err() io.Writer {
return streams.NewOut(os.Stderr)
}
func (f FakeDockerCLI) SetIn(in *streams.In) {
panic("implement me if you need me")
}
func (f FakeDockerCLI) Apply(ops ...command.DockerCliOption) error {
panic("implement me if you need me")
}
func (f FakeDockerCLI) ConfigFile() *configfile.ConfigFile {
return &configfile.ConfigFile{}
}
func (f FakeDockerCLI) ServerInfo() command.ServerInfo {
panic("implement me if you need me")
}
func (f FakeDockerCLI) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
panic("implement me if you need me")
}
func (f FakeDockerCLI) DefaultVersion() string {
panic("implement me if you need me")
}
func (f FakeDockerCLI) CurrentVersion() string {
panic("implement me if you need me")
}
func (f FakeDockerCLI) ManifestStore() manifeststore.Store {
panic("implement me if you need me")
}
func (f FakeDockerCLI) RegistryClient(b bool) registryclient.RegistryClient {
panic("implement me if you need me")
}
func (f FakeDockerCLI) ContentTrustEnabled() bool {
panic("implement me if you need me")
}
func (f FakeDockerCLI) BuildKitEnabled() (bool, error) {
panic("implement me if you need me")
}
func (f FakeDockerCLI) ContextStore() store.Store {
panic("implement me if you need me")
}
func (f FakeDockerCLI) CurrentContext() string {
panic("implement me if you need me")
}
func (f FakeDockerCLI) DockerEndpoint() docker.Endpoint {
panic("implement me if you need me")
return string(content)
}

View file

@ -7,18 +7,21 @@ import (
"flag"
"fmt"
"io"
"net"
"net/http"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
"github.com/traefik/traefik/v2/pkg/log"
checker "github.com/vdemeester/shakers"
)
var updateExpected = flag.Bool("update_expected", false, "Update expected files in testdata")
@ -26,25 +29,39 @@ var updateExpected = flag.Bool("update_expected", false, "Update expected files
// K8sSuite tests suite.
type K8sSuite struct{ BaseSuite }
func (s *K8sSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "k8s")
s.composeUp(c)
func TestK8sSuite(t *testing.T) {
suite.Run(t, new(K8sSuite))
}
func (s *K8sSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("k8s")
s.composeUp()
abs, err := filepath.Abs("./fixtures/k8s/config.skip/kubeconfig.yaml")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Do(60*time.Second, func() error {
_, err := os.Stat(abs)
return err
})
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
data, err := os.ReadFile(abs)
require.NoError(s.T(), err)
content := strings.ReplaceAll(string(data), "https://server:6443", fmt.Sprintf("https://%s", net.JoinHostPort(s.getComposeServiceIP("server"), "6443")))
err = os.WriteFile(abs, []byte(content), 0o644)
require.NoError(s.T(), err)
err = os.Setenv("KUBECONFIG", abs)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *K8sSuite) TearDownSuite(c *check.C) {
s.composeDown(c)
func (s *K8sSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
generatedFiles := []string{
"./fixtures/k8s/config.skip/kubeconfig.yaml",
@ -62,109 +79,78 @@ func (s *K8sSuite) TearDownSuite(c *check.C) {
}
}
func (s *K8sSuite) TestIngressConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_default.toml"))
defer display(c)
func (s *K8sSuite) TestIngressConfiguration() {
s.traefikCmd(withConfigFile("fixtures/k8s_default.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
testConfiguration(c, "testdata/rawdata-ingress.json", "8080")
s.testConfiguration("testdata/rawdata-ingress.json", "8080")
}
func (s *K8sSuite) TestIngressLabelSelector(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_ingress_label_selector.toml"))
defer display(c)
func (s *K8sSuite) TestIngressLabelSelector() {
s.traefikCmd(withConfigFile("fixtures/k8s_ingress_label_selector.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
testConfiguration(c, "testdata/rawdata-ingress-label-selector.json", "8080")
s.testConfiguration("testdata/rawdata-ingress-label-selector.json", "8080")
}
func (s *K8sSuite) TestCRDConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_crd.toml"))
defer display(c)
func (s *K8sSuite) TestCRDConfiguration() {
s.traefikCmd(withConfigFile("fixtures/k8s_crd.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
testConfiguration(c, "testdata/rawdata-crd.json", "8000")
s.testConfiguration("testdata/rawdata-crd.json", "8000")
}
func (s *K8sSuite) TestCRDLabelSelector(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_crd_label_selector.toml"))
defer display(c)
func (s *K8sSuite) TestCRDLabelSelector() {
s.traefikCmd(withConfigFile("fixtures/k8s_crd_label_selector.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
testConfiguration(c, "testdata/rawdata-crd-label-selector.json", "8000")
s.testConfiguration("testdata/rawdata-crd-label-selector.json", "8000")
}
func (s *K8sSuite) TestGatewayConfiguration(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_gateway.toml"))
defer display(c)
func (s *K8sSuite) TestGatewayConfiguration() {
s.traefikCmd(withConfigFile("fixtures/k8s_gateway.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
testConfiguration(c, "testdata/rawdata-gateway.json", "8080")
s.testConfiguration("testdata/rawdata-gateway.json", "8080")
}
func (s *K8sSuite) TestIngressclass(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_ingressclass.toml"))
defer display(c)
func (s *K8sSuite) TestIngressclass() {
s.traefikCmd(withConfigFile("fixtures/k8s_ingressclass.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
testConfiguration(c, "testdata/rawdata-ingressclass.json", "8080")
s.testConfiguration("testdata/rawdata-ingressclass.json", "8080")
}
func testConfiguration(c *check.C, path, apiPort string) {
func (s *K8sSuite) testConfiguration(path, apiPort string) {
err := try.GetRequest("http://127.0.0.1:"+apiPort+"/api/entrypoints", 20*time.Second, try.BodyContains(`"name":"web"`))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
expectedJSON := filepath.FromSlash(path)
if *updateExpected {
fi, err := os.Create(expectedJSON)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = fi.Close()
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
var buf bytes.Buffer
err = try.GetRequest("http://127.0.0.1:"+apiPort+"/api/rawdata", 1*time.Minute, try.StatusCodeIs(http.StatusOK), matchesConfig(expectedJSON, &buf))
if !*updateExpected {
if err != nil {
c.Error(err)
}
require.NoError(s.T(), err)
return
}
if err != nil {
c.Logf("In file update mode, got expected error: %v", err)
log.WithoutContext().Infof("In file update mode, got expected error: %v", err)
}
var rtRepr api.RunTimeRepresentation
err = json.Unmarshal(buf.Bytes(), &rtRepr)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
newJSON, err := json.MarshalIndent(rtRepr, "", "\t")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = os.WriteFile(expectedJSON, newJSON, 0o644)
c.Assert(err, checker.IsNil)
c.Errorf("We do not want a passing test in file update mode")
require.NoError(s.T(), err)
s.T().Fatal("We do not want a passing test in file update mode")
}
func matchesConfig(wantConfig string, buf *bytes.Buffer) try.ResponseCondition {

View file

@ -5,18 +5,23 @@ import (
"net"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
"github.com/traefik/traefik/v2/pkg/log"
)
type KeepAliveSuite struct {
BaseSuite
}
func TestKeepAliveSuite(t *testing.T) {
suite.Run(t, new(KeepAliveSuite))
}
type KeepAliveConfig struct {
KeepAliveServer string
IdleConnTimeout string
@ -27,7 +32,7 @@ type connStateChangeEvent struct {
state http.ConnState
}
func (s *KeepAliveSuite) TestShouldRespectConfiguredBackendHttpKeepAliveTime(c *check.C) {
func (s *KeepAliveSuite) TestShouldRespectConfiguredBackendHttpKeepAliveTime() {
idleTimeout := time.Duration(75) * time.Millisecond
connStateChanges := make(chan connStateChangeEvent)
@ -59,18 +64,18 @@ func (s *KeepAliveSuite) TestShouldRespectConfiguredBackendHttpKeepAliveTime(c *
case <-noMoreRequests:
moreRequestsExpected = false
case <-maxWaitTimeExceeded:
c.Logf("timeout waiting for all connections to close, waited for %v, configured idle timeout was %v", maxWaitDuration, idleTimeout)
c.Fail()
log.WithoutContext().Infof("timeout waiting for all connections to close, waited for %v, configured idle timeout was %v", maxWaitDuration, idleTimeout)
s.T().Fail()
close(completed)
return
}
}
c.Check(connCount, checker.Equals, 1)
require.Equal(s.T(), 1, connCount)
for _, idlePeriod := range idlePeriodLengthMap {
// Our method of measuring the actual idle period is not precise, so allow some sub-ms deviation
c.Check(math.Round(idlePeriod.Seconds()), checker.LessOrEqualThan, idleTimeout.Seconds())
require.LessOrEqual(s.T(), math.Round(idlePeriod.Seconds()), idleTimeout.Seconds())
}
close(completed)
@ -87,22 +92,16 @@ func (s *KeepAliveSuite) TestShouldRespectConfiguredBackendHttpKeepAliveTime(c *
defer server.Close()
config := KeepAliveConfig{KeepAliveServer: server.URL, IdleConnTimeout: idleTimeout.String()}
file := s.adaptFile(c, "fixtures/timeout/keepalive.toml", config)
file := s.adaptFile("fixtures/timeout/keepalive.toml", config)
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Check(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// Wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Duration(1)*time.Second, try.StatusCodeIs(200), try.BodyContains("PathPrefix(`/keepalive`)"))
c.Check(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Duration(1)*time.Second, try.StatusCodeIs(200), try.BodyContains("PathPrefix(`/keepalive`)"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/keepalive", time.Duration(1)*time.Second, try.StatusCodeIs(200))
c.Check(err, checker.IsNil)
require.NoError(s.T(), err)
close(noMoreRequests)
<-completed

View file

@ -9,12 +9,14 @@ import (
"os"
"strings"
"syscall"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
checker "github.com/vdemeester/shakers"
)
const (
@ -25,13 +27,23 @@ const (
// Log rotation integration test suite.
type LogRotationSuite struct{ BaseSuite }
func (s *LogRotationSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "access_log")
s.composeUp(c)
func TestLogRorationSuite(t *testing.T) {
suite.Run(t, new(LogRotationSuite))
}
func (s *LogRotationSuite) TearDownSuite(c *check.C) {
s.composeDown(c)
func (s *LogRotationSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
os.Remove(traefikTestAccessLogFile)
os.Remove(traefikTestLogFile)
os.Remove(traefikTestAccessLogFileRotated)
s.createComposeProject("access_log")
s.composeUp()
}
func (s *LogRotationSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
generatedFiles := []string{
traefikTestLogFile,
@ -47,126 +59,116 @@ func (s *LogRotationSuite) TearDownSuite(c *check.C) {
}
}
func (s *LogRotationSuite) TestAccessLogRotation(c *check.C) {
func (s *LogRotationSuite) TestAccessLogRotation() {
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/access_log_config.toml"))
defer display(c)
defer displayTraefikLogFile(c, traefikTestLogFile)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
cmd, _ := s.cmdTraefik(withConfigFile("fixtures/access_log_config.toml"))
defer s.displayTraefikLogFile(traefikTestLogFile)
// Verify Traefik started ok
verifyEmptyErrorLog(c, "traefik.log")
s.verifyEmptyErrorLog("traefik.log")
waitForTraefik(c, "server1")
s.waitForTraefik("server1")
// Make some requests
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req.Host = "frontend1.docker.local"
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Rename access log
err = os.Rename(traefikTestAccessLogFile, traefikTestAccessLogFileRotated)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// in the midst of the requests, issue SIGUSR1 signal to server process
err = cmd.Process.Signal(syscall.SIGUSR1)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// continue issuing requests
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.Request(req, 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.HasBody())
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Verify access.log.rotated output as expected
logAccessLogFile(c, traefikTestAccessLogFileRotated)
lineCount := verifyLogLines(c, traefikTestAccessLogFileRotated, 0, true)
c.Assert(lineCount, checker.GreaterOrEqualThan, 1)
s.logAccessLogFile(traefikTestAccessLogFileRotated)
lineCount := s.verifyLogLines(traefikTestAccessLogFileRotated, 0, true)
assert.GreaterOrEqual(s.T(), lineCount, 1)
// make sure that the access log file is at least created before we do assertions on it
err = try.Do(1*time.Second, func() error {
_, err := os.Stat(traefikTestAccessLogFile)
return err
})
c.Assert(err, checker.IsNil, check.Commentf("access log file was not created in time"))
assert.NoError(s.T(), err, "access log file was not created in time")
// Verify access.log output as expected
logAccessLogFile(c, traefikTestAccessLogFile)
lineCount = verifyLogLines(c, traefikTestAccessLogFile, lineCount, true)
c.Assert(lineCount, checker.Equals, 3)
s.logAccessLogFile(traefikTestAccessLogFile)
lineCount = s.verifyLogLines(traefikTestAccessLogFile, lineCount, true)
assert.Equal(s.T(), 3, lineCount)
verifyEmptyErrorLog(c, traefikTestLogFile)
s.verifyEmptyErrorLog(traefikTestLogFile)
}
func (s *LogRotationSuite) TestTraefikLogRotation(c *check.C) {
func (s *LogRotationSuite) TestTraefikLogRotation() {
// Start Traefik
cmd, display := s.traefikCmd(withConfigFile("fixtures/traefik_log_config.toml"))
defer display(c)
defer displayTraefikLogFile(c, traefikTestLogFile)
cmd := s.traefikCmd(withConfigFile("fixtures/traefik_log_config.toml"))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
waitForTraefik(c, "server1")
s.waitForTraefik("server1")
// Rename traefik log
err = os.Rename(traefikTestLogFile, traefikTestLogFileRotated)
c.Assert(err, checker.IsNil)
err := os.Rename(traefikTestLogFile, traefikTestLogFileRotated)
require.NoError(s.T(), err)
// issue SIGUSR1 signal to server process
err = cmd.Process.Signal(syscall.SIGUSR1)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = cmd.Process.Signal(syscall.SIGTERM)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Allow time for switch to be processed
err = try.Do(3*time.Second, func() error {
_, err = os.Stat(traefikTestLogFile)
return err
})
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// we have at least 6 lines in traefik.log.rotated
lineCount := verifyLogLines(c, traefikTestLogFileRotated, 0, false)
lineCount := s.verifyLogLines(traefikTestLogFileRotated, 0, false)
// GreaterOrEqualThan used to ensure test doesn't break
// If more log entries are output on startup
c.Assert(lineCount, checker.GreaterOrEqualThan, 5)
assert.GreaterOrEqual(s.T(), lineCount, 5)
// Verify traefik.log output as expected
lineCount = verifyLogLines(c, traefikTestLogFile, lineCount, false)
c.Assert(lineCount, checker.GreaterOrEqualThan, 7)
lineCount = s.verifyLogLines(traefikTestLogFile, lineCount, false)
assert.GreaterOrEqual(s.T(), lineCount, 7)
}
func logAccessLogFile(c *check.C, fileName string) {
func (s *LogRotationSuite) logAccessLogFile(fileName string) {
output, err := os.ReadFile(fileName)
c.Assert(err, checker.IsNil)
c.Logf("Contents of file %s\n%s", fileName, string(output))
require.NoError(s.T(), err)
log.WithoutContext().Infof("Contents of file %s\n%s", fileName, string(output))
}
func verifyEmptyErrorLog(c *check.C, name string) {
func (s *LogRotationSuite) verifyEmptyErrorLog(name string) {
err := try.Do(5*time.Second, func() error {
traefikLog, e2 := os.ReadFile(name)
if e2 != nil {
return e2
}
c.Assert(string(traefikLog), checker.HasLen, 0)
assert.Empty(s.T(), string(traefikLog))
return nil
})
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func verifyLogLines(c *check.C, fileName string, countInit int, accessLog bool) int {
func (s *LogRotationSuite) verifyLogLines(fileName string, countInit int, accessLog bool) int {
rotated, err := os.Open(fileName)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
rotatedLog := bufio.NewScanner(rotated)
count := countInit
for rotatedLog.Scan() {
@ -174,7 +176,7 @@ func verifyLogLines(c *check.C, fileName string, countInit int, accessLog bool)
if accessLog {
if len(line) > 0 {
if !strings.Contains(line, "/api/rawdata") {
CheckAccessLogFormat(c, line, count)
s.CheckAccessLogFormat(line, count)
count++
}
}

View file

@ -2,13 +2,13 @@ package integration
import (
"net/http"
"os"
"testing"
"time"
"github.com/gambol99/go-marathon"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// Marathon test suites.
@ -17,42 +17,46 @@ type MarathonSuite15 struct {
marathonURL string
}
func (s *MarathonSuite15) SetUpSuite(c *check.C) {
s.createComposeProject(c, "marathon15")
s.composeUp(c)
func TestMarathonSuite15(t *testing.T) {
suite.Run(t, new(MarathonSuite))
}
s.marathonURL = "http://" + s.getComposeServiceIP(c, containerNameMarathon) + ":8080"
func (s *MarathonSuite15) SetUpSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("marathon15")
s.composeUp()
s.marathonURL = "http://" + s.getComposeServiceIP(containerNameMarathon) + ":8080"
// Wait for Marathon readiness prior to creating the client so that we
// don't run into the "all cluster members down" state right from the
// start.
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *MarathonSuite15) TestConfigurationUpdate(c *check.C) {
c.Skip("doesn't work")
func (s *MarathonSuite15) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *MarathonSuite15) TestConfigurationUpdate() {
s.T().Skip("doesn't work")
// Start Traefik.
file := s.adaptFile(c, "fixtures/marathon/simple.toml", struct {
file := s.adaptFile("fixtures/marathon/simple.toml", struct {
MarathonURL string
}{s.marathonURL})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// Wait for Traefik to turn ready.
err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
// Prepare Marathon client.
config := marathon.NewDefaultConfig()
config.URL = s.marathonURL
client, err := marathon.NewClient(config)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Create test application to be deployed.
app := marathon.NewDockerApplication().
@ -68,11 +72,11 @@ func (s *MarathonSuite15) TestConfigurationUpdate(c *check.C) {
*app.Networks = append(*app.Networks, *marathon.NewBridgePodNetwork())
// Deploy the test application.
deployApplication(c, client, app)
s.deployApplication(client, app)
// Query application via Traefik.
err = try.GetRequest("http://127.0.0.1:8000/service", 30*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Create test application with services to be deployed.
app = marathon.NewDockerApplication().
@ -88,9 +92,9 @@ func (s *MarathonSuite15) TestConfigurationUpdate(c *check.C) {
*app.Networks = append(*app.Networks, *marathon.NewBridgePodNetwork())
// Deploy the test application.
deployApplication(c, client, app)
s.deployApplication(client, app)
// Query application via Traefik.
err = try.GetRequest("http://127.0.0.1:8000/app", 30*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -2,13 +2,13 @@ package integration
import (
"net/http"
"os"
"testing"
"time"
"github.com/gambol99/go-marathon"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
const containerNameMarathon = "marathon"
@ -19,50 +19,55 @@ type MarathonSuite struct {
marathonURL string
}
func (s *MarathonSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "marathon")
s.composeUp(c)
func TestMarathonSuite(t *testing.T) {
suite.Run(t, new(MarathonSuite))
}
s.marathonURL = "http://" + s.getComposeServiceIP(c, containerNameMarathon) + ":8080"
func (s *MarathonSuite) SetUpSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("marathon")
s.composeUp()
s.marathonURL = "http://" + s.getComposeServiceIP(containerNameMarathon) + ":8080"
// Wait for Marathon readiness prior to creating the client so that we
// don't run into the "all cluster members down" state right from the
// start.
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func deployApplication(c *check.C, client marathon.Marathon, application *marathon.Application) {
func (s *MarathonSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *BaseSuite) deployApplication(client marathon.Marathon, application *marathon.Application) {
deploy, err := client.UpdateApplication(application, false)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Wait for deployment to complete.
c.Assert(client.WaitOnDeployment(deploy.DeploymentID, 1*time.Minute), checker.IsNil)
err = client.WaitOnDeployment(deploy.DeploymentID, 1*time.Minute)
require.NoError(s.T(), err)
}
func (s *MarathonSuite) TestConfigurationUpdate(c *check.C) {
c.Skip("doesn't work")
func (s *MarathonSuite) TestConfigurationUpdate() {
s.T().Skip("doesn't work")
// Start Traefik.
file := s.adaptFile(c, "fixtures/marathon/simple.toml", struct {
file := s.adaptFile("fixtures/marathon/simple.toml", struct {
MarathonURL string
}{s.marathonURL})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// Wait for Traefik to turn ready.
err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
// Prepare Marathon client.
config := marathon.NewDefaultConfig()
config.URL = s.marathonURL
client, err := marathon.NewClient(config)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Create test application to be deployed.
app := marathon.NewDockerApplication().
@ -75,11 +80,11 @@ func (s *MarathonSuite) TestConfigurationUpdate(c *check.C) {
Container("traefik/whoami")
// Deploy the test application.
deployApplication(c, client, app)
s.deployApplication(client, app)
// Query application via Traefik.
err = try.GetRequest("http://127.0.0.1:8000/service", 30*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// Create test application with services to be deployed.
app = marathon.NewDockerApplication().
@ -92,9 +97,9 @@ func (s *MarathonSuite) TestConfigurationUpdate(c *check.C) {
Container("traefik/whoami")
// Deploy the test application.
deployApplication(c, client, app)
s.deployApplication(client, app)
// Query application via Traefik.
err = try.GetRequest("http://127.0.0.1:8000/app", 30*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -1,103 +1,138 @@
package integration
import (
"net/http"
"os"
"bufio"
"net"
"testing"
"time"
"github.com/go-check/check"
"github.com/pires/go-proxyproto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type ProxyProtocolSuite struct {
BaseSuite
gatewayIP string
haproxyIP string
whoamiIP string
whoamiIP string
}
func (s *ProxyProtocolSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "proxy-protocol")
s.composeUp(c)
s.gatewayIP = s.getContainerIP(c, "traefik")
s.haproxyIP = s.getComposeServiceIP(c, "haproxy")
s.whoamiIP = s.getComposeServiceIP(c, "whoami")
func TestProxyProtocolSuite(t *testing.T) {
suite.Run(t, new(ProxyProtocolSuite))
}
func (s *ProxyProtocolSuite) TestProxyProtocolTrusted(c *check.C) {
file := s.adaptFile(c, "fixtures/proxy-protocol/with.toml", struct {
func (s *ProxyProtocolSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("proxy-protocol")
s.composeUp()
s.whoamiIP = s.getComposeServiceIP("whoami")
}
func (s *ProxyProtocolSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *ProxyProtocolSuite) TestProxyProtocolTrusted() {
file := s.adaptFile("fixtures/proxy-protocol/proxy-protocol.toml", struct {
HaproxyIP string
WhoamiIP string
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
defer os.Remove(file)
}{WhoamiIP: s.whoamiIP})
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://"+s.haproxyIP+"/whoami", 1*time.Second,
try.StatusCodeIs(http.StatusOK),
try.BodyContains("X-Forwarded-For: "+s.gatewayIP))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8000/whoami", 10*time.Second)
require.NoError(s.T(), err)
content, err := proxyProtoRequest("127.0.0.1:8000", 1)
require.NoError(s.T(), err)
assert.Contains(s.T(), content, "X-Forwarded-For: 1.2.3.4")
content, err = proxyProtoRequest("127.0.0.1:8000", 2)
require.NoError(s.T(), err)
assert.Contains(s.T(), content, "X-Forwarded-For: 1.2.3.4")
}
func (s *ProxyProtocolSuite) TestProxyProtocolV2Trusted(c *check.C) {
file := s.adaptFile(c, "fixtures/proxy-protocol/with.toml", struct {
func (s *ProxyProtocolSuite) TestProxyProtocolNotTrusted() {
file := s.adaptFile("fixtures/proxy-protocol/proxy-protocol.toml", struct {
HaproxyIP string
WhoamiIP string
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
defer os.Remove(file)
}{WhoamiIP: s.whoamiIP})
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://"+s.haproxyIP+":81/whoami", 1*time.Second,
try.StatusCodeIs(http.StatusOK),
try.BodyContains("X-Forwarded-For: "+s.gatewayIP))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:9000/whoami", 10*time.Second)
require.NoError(s.T(), err)
content, err := proxyProtoRequest("127.0.0.1:9000", 1)
require.NoError(s.T(), err)
assert.Contains(s.T(), content, "X-Forwarded-For: 127.0.0.1")
content, err = proxyProtoRequest("127.0.0.1:9000", 2)
require.NoError(s.T(), err)
assert.Contains(s.T(), content, "X-Forwarded-For: 127.0.0.1")
}
func (s *ProxyProtocolSuite) TestProxyProtocolNotTrusted(c *check.C) {
file := s.adaptFile(c, "fixtures/proxy-protocol/without.toml", struct {
HaproxyIP string
WhoamiIP string
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
defer os.Remove(file)
func proxyProtoRequest(address string, version byte) (string, error) {
// Open a TCP connection to the server
conn, err := net.Dial("tcp", address)
if err != nil {
return "", err
}
defer conn.Close()
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// Create a Proxy Protocol header with v1
proxyHeader := &proxyproto.Header{
Version: version,
Command: proxyproto.PROXY,
TransportProtocol: proxyproto.TCPv4,
DestinationAddr: &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 8000,
},
SourceAddr: &net.TCPAddr{
IP: net.ParseIP("1.2.3.4"),
Port: 62541,
},
}
err = try.GetRequest("http://"+s.haproxyIP+"/whoami", 1*time.Second,
try.StatusCodeIs(http.StatusOK),
try.BodyContains("X-Forwarded-For: "+s.haproxyIP))
c.Assert(err, checker.IsNil)
}
func (s *ProxyProtocolSuite) TestProxyProtocolV2NotTrusted(c *check.C) {
file := s.adaptFile(c, "fixtures/proxy-protocol/without.toml", struct {
HaproxyIP string
WhoamiIP string
}{HaproxyIP: s.haproxyIP, WhoamiIP: s.whoamiIP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://"+s.haproxyIP+":81/whoami", 1*time.Second,
try.StatusCodeIs(http.StatusOK),
try.BodyContains("X-Forwarded-For: "+s.haproxyIP))
c.Assert(err, checker.IsNil)
// After the connection was created write the proxy headers first
_, err = proxyHeader.WriteTo(conn)
if err != nil {
return "", err
}
// Create an HTTP request
request := "GET /whoami HTTP/1.1\r\n" +
"Host: 127.0.0.1\r\n" +
"Connection: close\r\n" +
"\r\n"
// Write the HTTP request to the TCP connection
writer := bufio.NewWriter(conn)
_, err = writer.WriteString(request)
if err != nil {
return "", err
}
// Flush the buffer to ensure the request is sent
err = writer.Flush()
if err != nil {
return "", err
}
// Read the response from the server
var content string
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
content += scanner.Text() + "\n"
}
if scanner.Err() != nil {
return "", err
}
return content, nil
}

View file

@ -2,12 +2,12 @@ package integration
import (
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type RateLimitSuite struct {
@ -15,33 +15,38 @@ type RateLimitSuite struct {
ServerIP string
}
func (s *RateLimitSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "ratelimit")
s.composeUp(c)
s.ServerIP = s.getComposeServiceIP(c, "whoami1")
func TestRateLimitSuite(t *testing.T) {
suite.Run(t, new(RateLimitSuite))
}
func (s *RateLimitSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/ratelimit/simple.toml", struct {
func (s *RateLimitSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("ratelimit")
s.composeUp()
s.ServerIP = s.getComposeServiceIP("whoami1")
}
func (s *RateLimitSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *RateLimitSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/ratelimit/simple.toml", struct {
Server1 string
}{s.ServerIP})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("ratelimit"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("ratelimit"))
require.NoError(s.T(), err)
start := time.Now()
count := 0
for {
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
count++
if count > 100 {
break
@ -50,6 +55,6 @@ func (s *RateLimitSuite) TestSimpleConfiguration(c *check.C) {
stop := time.Now()
elapsed := stop.Sub(start)
if elapsed < time.Second*99/100 {
c.Fatalf("requests throughput was too fast wrt to rate limiting: 100 requests in %v", elapsed)
s.T().Fatalf("requests throughput was too fast wrt to rate limiting: 100 requests in %v", elapsed)
}
}

View file

@ -0,0 +1,201 @@
package integration
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"testing"
"text/template"
"time"
"github.com/fatih/structs"
"github.com/kvtools/redis"
"github.com/kvtools/valkeyrie"
"github.com/kvtools/valkeyrie/store"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
"github.com/traefik/traefik/v2/pkg/log"
)
// Redis test suites.
type RedisSentinelSuite struct {
BaseSuite
kvClient store.Store
redisEndpoints []string
}
func TestRedisSentinelSuite(t *testing.T) {
suite.Run(t, new(RedisSentinelSuite))
}
func (s *RedisSentinelSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.setupSentinelConfiguration([]string{"26379", "26379", "26379"})
s.createComposeProject("redis_sentinel")
s.composeUp()
s.redisEndpoints = []string{
net.JoinHostPort(s.getComposeServiceIP("sentinel1"), "26379"),
net.JoinHostPort(s.getComposeServiceIP("sentinel2"), "26379"),
net.JoinHostPort(s.getComposeServiceIP("sentinel3"), "26379"),
}
kv, err := valkeyrie.NewStore(
context.Background(),
redis.StoreName,
s.redisEndpoints,
&redis.Config{
Sentinel: &redis.Sentinel{
MasterName: "mymaster",
},
},
)
require.NoError(s.T(), err, "Cannot create store redis")
s.kvClient = kv
// wait for redis
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
require.NoError(s.T(), err)
}
func (s *RedisSentinelSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
for _, filename := range []string{"sentinel1.conf", "sentinel2.conf", "sentinel3.conf"} {
_ = os.Remove(filepath.Join(".", "resources", "compose", "config", filename))
}
}
func (s *RedisSentinelSuite) setupSentinelConfiguration(ports []string) {
for i, port := range ports {
templateValue := struct{ SentinelPort string }{SentinelPort: port}
// Load file
templateFile := "resources/compose/config/sentinel_template.conf"
tmpl, err := template.ParseFiles(templateFile)
require.NoError(s.T(), err)
folder, prefix := filepath.Split(templateFile)
fileName := fmt.Sprintf("%s/sentinel%d.conf", folder, i+1)
tmpFile, err := os.Create(fileName)
require.NoError(s.T(), err)
defer tmpFile.Close()
model := structs.Map(templateValue)
model["SelfFilename"] = tmpFile.Name()
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
require.NoError(s.T(), err)
err = tmpFile.Sync()
require.NoError(s.T(), err)
}
}
func (s *RedisSentinelSuite) TestSentinelConfiguration() {
file := s.adaptFile("fixtures/redis/sentinel.toml", struct{ RedisAddress string }{
RedisAddress: strings.Join(s.redisEndpoints, `","`),
})
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
"traefik/http/routers/Router0/middlewares/0": "compressor",
"traefik/http/routers/Router0/middlewares/1": "striper",
"traefik/http/routers/Router0/service": "simplesvc",
"traefik/http/routers/Router0/rule": "Host(`kv1.localhost`)",
"traefik/http/routers/Router0/priority": "42",
"traefik/http/routers/Router0/tls": "true",
"traefik/http/routers/Router1/rule": "Host(`kv2.localhost`)",
"traefik/http/routers/Router1/priority": "42",
"traefik/http/routers/Router1/tls/domains/0/main": "aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/0": "aaa.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/1": "bbb.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/1/main": "bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/0": "aaa.bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/1": "bbb.bbb.localhost",
"traefik/http/routers/Router1/entryPoints/0": "web",
"traefik/http/routers/Router1/service": "simplesvc",
"traefik/http/services/simplesvc/loadBalancer/servers/0/url": "http://10.0.1.1:8888",
"traefik/http/services/simplesvc/loadBalancer/servers/1/url": "http://10.0.1.1:8889",
"traefik/http/services/srvcA/loadBalancer/servers/0/url": "http://10.0.1.2:8888",
"traefik/http/services/srvcA/loadBalancer/servers/1/url": "http://10.0.1.2:8889",
"traefik/http/services/srvcB/loadBalancer/servers/0/url": "http://10.0.1.3:8888",
"traefik/http/services/srvcB/loadBalancer/servers/1/url": "http://10.0.1.3:8889",
"traefik/http/services/mirror/mirroring/service": "simplesvc",
"traefik/http/services/mirror/mirroring/mirrors/0/name": "srvcA",
"traefik/http/services/mirror/mirroring/mirrors/0/percent": "42",
"traefik/http/services/mirror/mirroring/mirrors/1/name": "srvcB",
"traefik/http/services/mirror/mirroring/mirrors/1/percent": "42",
"traefik/http/services/Service03/weighted/services/0/name": "srvcA",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "srvcB",
"traefik/http/services/Service03/weighted/services/1/weight": "42",
"traefik/http/middlewares/compressor/compress": "true",
"traefik/http/middlewares/striper/stripPrefix/prefixes/0": "foo",
"traefik/http/middlewares/striper/stripPrefix/prefixes/1": "bar",
}
for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
require.NoError(s.T(), err)
}
s.traefikCmd(withConfigFile(file))
// wait for traefik
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.BodyContains(`"striper@redis":`, `"compressor@redis":`, `"srvcA@redis":`, `"srvcB@redis":`),
)
require.NoError(s.T(), err)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
require.NoError(s.T(), err)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
require.NoError(s.T(), err)
got, err := json.MarshalIndent(obtained, "", " ")
require.NoError(s.T(), err)
expectedJSON := filepath.FromSlash("testdata/rawdata-redis.json")
if *updateExpected {
err = os.WriteFile(expectedJSON, got, 0o666)
require.NoError(s.T(), err)
}
expected, err := os.ReadFile(expectedJSON)
require.NoError(s.T(), err)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
FromFile: "Expected",
A: difflib.SplitLines(string(expected)),
ToFile: "Got",
B: difflib.SplitLines(string(got)),
Context: 3,
}
text, err := difflib.GetUnifiedDiffString(diff)
require.NoError(s.T(), err)
log.WithoutContext().Info(text)
}
}

View file

@ -4,26 +4,22 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io/fs"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"text/template"
"testing"
"time"
"github.com/fatih/structs"
"github.com/go-check/check"
"github.com/kvtools/redis"
"github.com/kvtools/valkeyrie"
"github.com/kvtools/valkeyrie/store"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
checker "github.com/vdemeester/shakers"
)
// Redis test suites.
@ -33,23 +29,18 @@ type RedisSuite struct {
redisEndpoints []string
}
func (s *RedisSuite) TearDownSuite(c *check.C) {
s.composeDown(c)
for _, filename := range []string{"sentinel1.conf", "sentinel2.conf", "sentinel3.conf"} {
err := os.Remove(filepath.Join(".", "resources", "compose", "config", filename))
if err != nil && !errors.Is(err, fs.ErrNotExist) {
c.Fatal("unable to clean configuration file for sentinel: ", err)
}
}
func TestRedisSuite(t *testing.T) {
suite.Run(t, new(RedisSuite))
}
func (s *RedisSuite) setupStore(c *check.C) {
s.createComposeProject(c, "redis")
s.composeUp(c)
func (s *RedisSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("redis")
s.composeUp()
s.redisEndpoints = []string{}
s.redisEndpoints = append(s.redisEndpoints, net.JoinHostPort(s.getComposeServiceIP(c, "redis"), "6379"))
s.redisEndpoints = append(s.redisEndpoints, net.JoinHostPort(s.getComposeServiceIP("redis"), "6379"))
kv, err := valkeyrie.NewStore(
context.Background(),
@ -57,23 +48,23 @@ func (s *RedisSuite) setupStore(c *check.C) {
s.redisEndpoints,
&redis.Config{},
)
if err != nil {
c.Fatal("Cannot create store redis: ", err)
}
require.NoError(s.T(), err, "Cannot create store redis")
s.kvClient = kv
// wait for redis
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
func (s *RedisSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
file := s.adaptFile(c, "fixtures/redis/simple.toml", struct{ RedisAddress string }{
func (s *RedisSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/redis/simple.toml", struct{ RedisAddress string }{
RedisAddress: strings.Join(s.redisEndpoints, ","),
})
defer os.Remove(file)
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
@ -123,39 +114,35 @@ func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.BodyContains(`"striper@redis":`, `"compressor@redis":`, `"srvcA@redis":`, `"srvcB@redis":`),
)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
expectedJSON := filepath.FromSlash("testdata/rawdata-redis.json")
if *updateExpected {
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
@ -167,171 +154,6 @@ func (s *RedisSuite) TestSimpleConfiguration(c *check.C) {
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
}
}
func (s *RedisSuite) setupSentinelStore(c *check.C) {
s.setupSentinelConfiguration(c, []string{"26379", "36379", "46379"})
s.createComposeProject(c, "redis_sentinel")
s.composeUp(c)
s.redisEndpoints = []string{
net.JoinHostPort(s.getComposeServiceIP(c, "sentinel1"), "26379"),
net.JoinHostPort(s.getComposeServiceIP(c, "sentinel2"), "36379"),
net.JoinHostPort(s.getComposeServiceIP(c, "sentinel3"), "46379"),
}
kv, err := valkeyrie.NewStore(
context.Background(),
redis.StoreName,
s.redisEndpoints,
&redis.Config{
Sentinel: &redis.Sentinel{
MasterName: "mymaster",
},
},
)
if err != nil {
c.Fatal("Cannot create store redis sentinel")
}
s.kvClient = kv
// wait for redis
err = try.Do(60*time.Second, try.KVExists(kv, "test"))
c.Assert(err, checker.IsNil)
}
func (s *RedisSuite) setupSentinelConfiguration(c *check.C, ports []string) {
for i, port := range ports {
templateValue := struct{ SentinelPort string }{SentinelPort: port}
// Load file
templateFile := "resources/compose/config/sentinel_template.conf"
tmpl, err := template.ParseFiles(templateFile)
c.Assert(err, checker.IsNil)
folder, prefix := filepath.Split(templateFile)
fileName := fmt.Sprintf("%s/sentinel%d.conf", folder, i+1)
tmpFile, err := os.Create(fileName)
c.Assert(err, checker.IsNil)
defer tmpFile.Close()
model := structs.Map(templateValue)
model["SelfFilename"] = tmpFile.Name()
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
c.Assert(err, checker.IsNil)
err = tmpFile.Sync()
c.Assert(err, checker.IsNil)
}
}
func (s *RedisSuite) TestSentinelConfiguration(c *check.C) {
s.setupSentinelStore(c)
file := s.adaptFile(c, "fixtures/redis/sentinel.toml", struct{ RedisAddress string }{
RedisAddress: strings.Join(s.redisEndpoints, `","`),
})
defer os.Remove(file)
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
"traefik/http/routers/Router0/middlewares/0": "compressor",
"traefik/http/routers/Router0/middlewares/1": "striper",
"traefik/http/routers/Router0/service": "simplesvc",
"traefik/http/routers/Router0/rule": "Host(`kv1.localhost`)",
"traefik/http/routers/Router0/priority": "42",
"traefik/http/routers/Router0/tls": "true",
"traefik/http/routers/Router1/rule": "Host(`kv2.localhost`)",
"traefik/http/routers/Router1/priority": "42",
"traefik/http/routers/Router1/tls/domains/0/main": "aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/0": "aaa.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/0/sans/1": "bbb.aaa.localhost",
"traefik/http/routers/Router1/tls/domains/1/main": "bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/0": "aaa.bbb.localhost",
"traefik/http/routers/Router1/tls/domains/1/sans/1": "bbb.bbb.localhost",
"traefik/http/routers/Router1/entryPoints/0": "web",
"traefik/http/routers/Router1/service": "simplesvc",
"traefik/http/services/simplesvc/loadBalancer/servers/0/url": "http://10.0.1.1:8888",
"traefik/http/services/simplesvc/loadBalancer/servers/1/url": "http://10.0.1.1:8889",
"traefik/http/services/srvcA/loadBalancer/servers/0/url": "http://10.0.1.2:8888",
"traefik/http/services/srvcA/loadBalancer/servers/1/url": "http://10.0.1.2:8889",
"traefik/http/services/srvcB/loadBalancer/servers/0/url": "http://10.0.1.3:8888",
"traefik/http/services/srvcB/loadBalancer/servers/1/url": "http://10.0.1.3:8889",
"traefik/http/services/mirror/mirroring/service": "simplesvc",
"traefik/http/services/mirror/mirroring/mirrors/0/name": "srvcA",
"traefik/http/services/mirror/mirroring/mirrors/0/percent": "42",
"traefik/http/services/mirror/mirroring/mirrors/1/name": "srvcB",
"traefik/http/services/mirror/mirroring/mirrors/1/percent": "42",
"traefik/http/services/Service03/weighted/services/0/name": "srvcA",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "srvcB",
"traefik/http/services/Service03/weighted/services/1/weight": "42",
"traefik/http/middlewares/compressor/compress": "true",
"traefik/http/middlewares/striper/stripPrefix/prefixes/0": "foo",
"traefik/http/middlewares/striper/stripPrefix/prefixes/1": "bar",
"traefik/http/middlewares/striper/stripPrefix/forceSlash": "true",
}
for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
c.Assert(err, checker.IsNil)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
try.BodyContains(`"striper@redis":`, `"compressor@redis":`, `"srvcA@redis":`, `"srvcB@redis":`),
)
c.Assert(err, checker.IsNil)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
expectedJSON := filepath.FromSlash("testdata/rawdata-redis.json")
if *updateExpected {
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
}
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
FromFile: "Expected",
A: difflib.SplitLines(string(expected)),
ToFile: "Got",
B: difflib.SplitLines(string(got)),
Context: 3,
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
require.NoError(s.T(), err, text)
}
}

View file

@ -40,7 +40,7 @@ services:
traefik.http.routers.rt-authFrontend.entryPoints: httpFrontendAuth
traefik.http.routers.rt-authFrontend.rule: Host(`frontend.auth.docker.local`)
traefik.http.routers.rt-authFrontend.middlewares: basicauth
traefik.http.middlewares.basicauth.basicauth.users: test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/
traefik.http.middlewares.basicauth.basicauth.users: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
traefik.http.services.service3.loadbalancer.server.port: 80
digestAuthMiddleware:
@ -94,8 +94,3 @@ services:
traefik.http.routers.rt-preflightCORS.middlewares: preflightCORS
traefik.http.middlewares.preflightCORS.headers.accessControlAllowMethods: OPTIONS, GET
traefik.http.services.preflightCORS.loadbalancer.server.port: 80
networks:
default:
name: traefik-test-network
external: true

View file

@ -34,8 +34,3 @@ services:
traefik.http.routers.rt4.middlewares: wl4
traefik.http.middlewares.wl4.ipallowlist.sourceRange: 8.8.8.8
traefik.http.middlewares.wl4.ipallowlist.ipStrategy.excludedIPs: 10.0.0.1,10.0.0.2
networks:
default:
name: traefik-test-network
external: true

View file

@ -11,8 +11,3 @@ services:
image: traefik/whoami
labels:
traefik.enable: false
networks:
default:
name: traefik-test-network
external: true

View file

@ -4,8 +4,3 @@ services:
image: consul:1.6
whoami:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,11 +2,24 @@ version: "3.8"
services:
consul:
image: consul:1.6.2
command: agent -server -bootstrap -ui -client 0.0.0.0 -hcl 'connect { enabled = true }'
command:
- agent
- -server
- -bootstrap
- -ui
- -client
- 0.0.0.0
- -hcl
- 'connect { enabled = true }'
consul-agent:
image: consul:1.6.2
command: agent -retry-join consul -client 0.0.0.0
command:
- agent
- -retry-join
- consul
- -client
- 0.0.0.0
whoami1:
image: traefik/whoami
@ -30,8 +43,3 @@ services:
PORT: 443
BIND: 0.0.0.0
CONSUL_HTTP_ADDR: http://consul:8500
networks:
default:
name: traefik-test-network
external: true

View file

@ -36,8 +36,3 @@ services:
labels:
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
traefik.http.Services.powpow.LoadBalancer.server.Port: 2375
networks:
default:
name: traefik-test-network
external: true

View file

@ -1,12 +1,7 @@
version: "3.8"
services:
nginx1:
image: nginx:1.13.8-alpine
image: nginx:1.25.3-alpine3.18
nginx2:
image: nginx:1.13.8-alpine
networks:
default:
name: traefik-test-network
external: true
image: nginx:1.25.3-alpine3.18

View file

@ -2,9 +2,9 @@ version: "3.8"
services:
etcd:
image: quay.io/coreos/etcd:v3.3.18
command: etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2380
networks:
default:
name: traefik-test-network
external: true
command:
- etcd
- --listen-client-urls
- http://0.0.0.0:2379
- --advertise-client-urls
- http://0.0.0.0:2380

View file

@ -14,8 +14,3 @@ services:
whoami5:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -11,8 +11,3 @@ services:
whoami4:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -6,8 +6,3 @@ services:
traefik.enable: true
traefik.http.services.service1.loadbalancer.server.port: 80
traefik.http.routers.router1.rule: Host(`github.com`)
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,9 +2,23 @@ version: "3.8"
services:
server:
image: rancher/k3s:v1.20.15-k3s1
command: server --disable-agent --no-deploy coredns --no-deploy servicelb --no-deploy traefik --no-deploy local-storage --no-deploy metrics-server --log /output/k3s.log --bind-address=server --tls-san=server
privileged: true
command:
- server
- --disable-agent
- --disable=coredns
- --disable=servicelb
- --disable=traefik
- --disable=local-storage
- --disable=metrics-server
- --log=/output/k3s.log
- --bind-address=server
- --tls-san=server
- --tls-san=172.31.42.3
- --tls-san=172.31.42.4
environment:
K3S_CLUSTER_SECRET: somethingtotallyrandom
K3S_TOKEN: somethingtotallyrandom
K3S_KUBECONFIG_OUTPUT: /output/kubeconfig.yaml
K3S_KUBECONFIG_MODE: 666
volumes:
@ -15,10 +29,6 @@ services:
image: rancher/k3s:v1.20.15-k3s1
privileged: true
environment:
K3S_TOKEN: somethingtotallyrandom
K3S_URL: https://server:6443
K3S_CLUSTER_SECRET: somethingtotallyrandom
networks:
default:
name: traefik-test-network
external: true

View file

@ -3,12 +3,9 @@ services:
whoami1:
image: traefik/whoami
labels:
traefik.http.Routers.RouterMini.Rule: PathPrefix(`/whoami`)
traefik.http.routers.router-mini.Rule: PathPrefix(`/whoami`)
traefik.http.routers.router-mini.service: service-mini
traefik.http.services.service-mini.loadbalancer.server.port: 80
traefik.enable: true
deploy:
replicas: 2
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,14 +2,12 @@ version: "3.8"
services:
pebble:
image: letsencrypt/pebble:v2.3.1
command: pebble --dnsserver traefik:5053
command:
- pebble
- --dnsserver
- host.docker.internal:5053
environment:
# https://github.com/letsencrypt/pebble#testing-at-full-speed
PEBBLE_VA_NOSLEEP: 1
# https://github.com/letsencrypt/pebble#invalid-anti-replay-nonce-errors
PEBBLE_WFE_NONCEREJECT: 0
networks:
default:
name: traefik-test-network
external: true

View file

@ -1,14 +1,4 @@
version: "3.8"
services:
haproxy:
image: haproxy:2.2
volumes:
- ./resources/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
whoami:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,8 +2,3 @@ version: "3.8"
services:
whoami1:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,8 +2,3 @@ version: "3.8"
services:
redis:
image: redis:5.0
networks:
default:
name: traefik-test-network
external: true

View file

@ -3,59 +3,51 @@ services:
master:
image: redis
container_name: redis-master
command: redis-server --port 6380
ports:
- 6380:6380
healthcheck:
test: redis-cli -p 6380 ping
command:
- redis-server
- --port
- 6380
node1:
image: redis
container_name: redis-node-1
ports:
- 6381:6381
command: redis-server --port 6381 --slaveof redis-master 6380
healthcheck:
test: redis-cli -p 6381 ping
command:
- redis-server
- --port
- 6381
- --slaveof
- redis-master
- 6380
node2:
image: redis
container_name: redis-node-2
ports:
- 6382:6382
command: redis-server --port 6382 --slaveof redis-master 6380
healthcheck:
test: redis-cli -p 6382 ping
command:
- redis-server
- --port
- 6382
- --slaveof
- redis-master
- 6380
sentinel1:
image: redis
container_name: redis-sentinel-1
ports:
- 26379:26379
command: redis-sentinel /usr/local/etc/redis/conf/sentinel1.conf
healthcheck:
test: redis-cli -p 26379 ping
command:
- redis-sentinel
- /usr/local/etc/redis/conf/sentinel1.conf
volumes:
- ./resources/compose/config:/usr/local/etc/redis/conf
sentinel2:
image: redis
container_name: redis-sentinel-2
ports:
- 36379:26379
command: redis-sentinel /usr/local/etc/redis/conf/sentinel2.conf
healthcheck:
test: redis-cli -p 36379 ping
command:
- redis-sentinel
- /usr/local/etc/redis/conf/sentinel2.conf
volumes:
- ./resources/compose/config:/usr/local/etc/redis/conf
sentinel3:
image: redis
container_name: redis-sentinel-3
ports:
- 46379:26379
command: redis-sentinel /usr/local/etc/redis/conf/sentinel3.conf
healthcheck:
test: redis-cli -p 46379 ping
command:
- redis-sentinel
- /usr/local/etc/redis/conf/sentinel3.conf
volumes:
- ./resources/compose/config:/usr/local/etc/redis/conf
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,8 +2,3 @@ version: "3.8"
services:
whoami:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,8 +2,3 @@ version: "3.8"
services:
whoami1:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,8 +2,3 @@ version: "3.8"
services:
whoami:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -5,8 +5,3 @@ services:
whoami2:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -9,9 +9,5 @@ services:
cap_add: # Required for tailscale to work
- net_admin
- sys_module
command: tailscaled
networks:
default:
name: traefik-test-network
external: true
command:
- tailscaled

View file

@ -2,38 +2,58 @@ version: "3.8"
services:
whoami-a:
image: traefik/whoamitcp
command: -name whoami-a -certFile /certs/whoami-a.crt -keyFile /certs/whoami-a.key
command:
- -name
- whoami-a
- -certFile
- /certs/whoami-a.crt
- -keyFile
- /certs/whoami-a.key
volumes:
- ./fixtures/tcp:/certs
whoami-b:
image: traefik/whoamitcp
command: -name whoami-b -certFile /certs/whoami-b.crt -keyFile /certs/whoami-b.key
command:
- -name
- whoami-b
- -certFile
- /certs/whoami-b.crt
- -keyFile
- /certs/whoami-b.key
volumes:
- ./fixtures/tcp:/certs
whoami-ab:
image: traefik/whoamitcp
command: -name whoami-ab -certFile /certs/whoami-b.crt -keyFile /certs/whoami-b.key
command:
- -name
- whoami-ab
- -certFile
- /certs/whoami-b.crt
- -keyFile
- /certs/whoami-b.key
volumes:
- ./fixtures/tcp:/certs
whoami-no-cert:
image: traefik/whoamitcp
command: -name whoami-no-cert
command:
- -name
- whoami-no-cert
whoami-no-tls:
image: traefik/whoamitcp
command: -name whoami-no-tls
command:
- -name
- whoami-no-tls
whoami:
image: traefik/whoami
whoami-banner:
image: traefik/whoamitcp
command: -name whoami-banner --banner
networks:
default:
name: traefik-test-network
external: true
command:
- -name
- whoami-banner
- --banner

View file

@ -5,8 +5,3 @@ services:
environment:
PROTO: http
PORT: 9000
networks:
default:
name: traefik-test-network
external: true

View file

@ -7,8 +7,3 @@ services:
traefik.http.routers.route1.middlewares: passtls
traefik.http.routers.route1.tls: true
traefik.http.middlewares.passtls.passtlsclientcert.pem: true
networks:
default:
name: traefik-test-network
external: true

View file

@ -13,8 +13,3 @@ services:
whoami:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,20 +2,21 @@ version: "3.8"
services:
whoami-a:
image: traefik/whoamiudp:latest
command: -name whoami-a
command:
- -name
- whoami-a
whoami-b:
image: traefik/whoamiudp:latest
command: -name whoami-b
command:
- -name
- whoami-b
whoami-c:
image: traefik/whoamiudp:latest
command: -name whoami-c
command:
- -name
- whoami-c
whoami-d:
image: traefik/whoami
networks:
default:
name: traefik-test-network
external: true

View file

@ -2,8 +2,3 @@ version: "3.8"
services:
zookeeper:
image: zookeeper:3.5
networks:
default:
name: traefik-test-network
external: true

View file

@ -1,30 +0,0 @@
global
maxconn 4096
defaults
log global
mode http
retries 3
option redispatch
maxconn 2000
timeout connect 5000
timeout client 50000
timeout server 50000
frontend TestServerTest
bind 0.0.0.0:80
mode tcp
default_backend TestServerNodes
frontend TestServerTestV2
bind 0.0.0.0:81
mode tcp
default_backend TestServerNodesV2
backend TestServerNodes
mode tcp
server TestServer01 traefik:8000 send-proxy
backend TestServerNodesV2
mode tcp
server TestServer01 traefik:8000 send-proxy-v2

View file

@ -5,14 +5,15 @@ import (
"encoding/json"
"net"
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
checker "github.com/vdemeester/shakers"
)
type RestSuite struct {
@ -20,28 +21,33 @@ type RestSuite struct {
whoamiAddr string
}
func (s *RestSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "rest")
s.composeUp(c)
s.whoamiAddr = net.JoinHostPort(s.getComposeServiceIP(c, "whoami1"), "80")
func TestRestSuite(t *testing.T) {
suite.Run(t, new(RestSuite))
}
func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/rest/simple.toml"))
func (s *RestSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.createComposeProject("rest")
s.composeUp()
s.whoamiAddr = net.JoinHostPort(s.getComposeServiceIP("whoami1"), "80")
}
func (s *RestSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *RestSuite) TestSimpleConfigurationInsecure() {
s.traefikCmd(withConfigFile("fixtures/rest/simple.toml"))
// wait for Traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains("rest@internal"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains("rest@internal"))
require.NoError(s.T(), err)
// 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)
require.NoError(s.T(), err)
testCase := []struct {
desc string
@ -105,47 +111,41 @@ func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
for _, test := range testCase {
data, err := json.Marshal(test.config)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8080/api/providers/rest", bytes.NewReader(data))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 3*time.Second, try.BodyContains(test.ruleMatch))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
}
func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/rest/simple_secure.toml", struct{}{})
defer os.Remove(file)
func (s *RestSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/rest/simple_secure.toml", struct{}{})
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// 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)
err := try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2000*time.Millisecond, try.BodyContains("PathPrefix(`/secure`)"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8080/api/providers/rest", strings.NewReader("{}"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusNotFound)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusNotFound, response.StatusCode)
testCase := []struct {
desc string
@ -209,19 +209,19 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
for _, test := range testCase {
data, err := json.Marshal(test.config)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/secure/api/providers/rest", bytes.NewReader(data))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains(test.ruleMatch))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/", time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
}

View file

@ -3,13 +3,14 @@ package integration
import (
"io"
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type RetrySuite struct {
@ -17,96 +18,86 @@ type RetrySuite struct {
whoamiIP string
}
func (s *RetrySuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "retry")
s.composeUp(c)
s.whoamiIP = s.getComposeServiceIP(c, "whoami")
func TestRetrySuite(t *testing.T) {
suite.Run(t, new(RetrySuite))
}
func (s *RetrySuite) TestRetry(c *check.C) {
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct{ WhoamiIP string }{s.whoamiIP})
defer os.Remove(file)
func (s *RetrySuite) SetupSuite() {
s.BaseSuite.SetupSuite()
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.createComposeProject("retry")
s.composeUp()
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
c.Assert(err, checker.IsNil)
s.whoamiIP = s.getComposeServiceIP("whoami")
}
func (s *RetrySuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *RetrySuite) TestRetry() {
file := s.adaptFile("fixtures/retry/simple.toml", struct{ WhoamiIP string }{s.whoamiIP})
s.traefikCmd(withConfigFile(file))
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
require.NoError(s.T(), err)
response, err := http.Get("http://127.0.0.1:8000/")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// The test only verifies that the retry middleware makes sure that the working service is eventually reached.
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
}
func (s *RetrySuite) TestRetryBackoff(c *check.C) {
file := s.adaptFile(c, "fixtures/retry/backoff.toml", struct{ WhoamiIP string }{s.whoamiIP})
defer os.Remove(file)
func (s *RetrySuite) TestRetryBackoff() {
file := s.adaptFile("fixtures/retry/backoff.toml", struct{ WhoamiIP string }{s.whoamiIP})
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
require.NoError(s.T(), err)
response, err := http.Get("http://127.0.0.1:8000/")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// The test only verifies that the retry middleware allows finally to reach the working service.
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
}
func (s *RetrySuite) TestRetryWebsocket(c *check.C) {
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct{ WhoamiIP string }{s.whoamiIP})
defer os.Remove(file)
func (s *RetrySuite) TestRetryWebsocket() {
file := s.adaptFile("fixtures/retry/simple.toml", struct{ WhoamiIP string }{s.whoamiIP})
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
require.NoError(s.T(), err)
// The test only verifies that the retry middleware makes sure that the working service is eventually reached.
_, response, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8000/echo", nil)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusSwitchingProtocols)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusSwitchingProtocols, response.StatusCode)
// The test verifies a second time that the working service is eventually reached.
_, response, err = websocket.DefaultDialer.Dial("ws://127.0.0.1:8000/echo", nil)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusSwitchingProtocols)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusSwitchingProtocols, response.StatusCode)
}
func (s *RetrySuite) TestRetryWithStripPrefix(c *check.C) {
file := s.adaptFile(c, "fixtures/retry/strip_prefix.toml", struct{ WhoamiIP string }{s.whoamiIP})
defer os.Remove(file)
func (s *RetrySuite) TestRetryWithStripPrefix() {
file := s.adaptFile("fixtures/retry/strip_prefix.toml", struct{ WhoamiIP string }{s.whoamiIP})
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("PathPrefix(`/`)"))
require.NoError(s.T(), err)
response, err := http.Get("http://127.0.0.1:8000/test")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
body, err := io.ReadAll(response.Body)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
c.Assert(string(body), checker.Contains, "GET / HTTP/1.1")
c.Assert(string(body), checker.Contains, "X-Forwarded-Prefix: /test")
assert.Contains(s.T(), string(body), "GET / HTTP/1.1")
assert.Contains(s.T(), string(body), "X-Forwarded-Prefix: /test")
}

File diff suppressed because it is too large Load diff

View file

@ -5,63 +5,69 @@ import (
"crypto/x509"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type TCPSuite struct{ BaseSuite }
func (s *TCPSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "tcp")
s.composeUp(c)
func TestTCPSuite(t *testing.T) {
suite.Run(t, new(TCPSuite))
}
func (s *TCPSuite) TestMixed(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/mixed.toml", struct {
func (s *TCPSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("tcp")
s.composeUp()
}
func (s *TCPSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *TCPSuite) TestMixed() {
file := s.adaptFile("fixtures/tcp/mixed.toml", struct {
Whoami string
WhoamiA string
WhoamiB string
WhoamiNoCert string
}{
Whoami: "http://" + s.getComposeServiceIP(c, "whoami") + ":80",
WhoamiA: s.getComposeServiceIP(c, "whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP(c, "whoami-b") + ":8080",
WhoamiNoCert: s.getComposeServiceIP(c, "whoami-no-cert") + ":8080",
Whoami: "http://" + s.getComposeServiceIP("whoami") + ":80",
WhoamiA: s.getComposeServiceIP("whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP("whoami-b") + ":8080",
WhoamiNoCert: s.getComposeServiceIP("whoami-no-cert") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("Path(`/test`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("Path(`/test`)"))
require.NoError(s.T(), err)
// Traefik passes through, termination handled by whoami-a
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-a")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-a")
// Traefik passes through, termination handled by whoami-b
out, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-b")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-b")
// Termination handled by traefik
out, err = guessWho("127.0.0.1:8093", "whoami-c.test", true)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-no-cert")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-no-cert")
tr1 := &http.Transport{
TLSClientConfig: &tls.Config{
@ -69,174 +75,143 @@ func (s *TCPSuite) TestMixed(c *check.C) {
},
}
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8093/whoami/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.RequestWithTransport(req, 10*time.Second, tr1, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:8093/not-found/", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.RequestWithTransport(req, 10*time.Second, tr1, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8093/test", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8093/not-found", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *TCPSuite) TestTLSOptions(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/multi-tls-options.toml", struct {
func (s *TCPSuite) TestTLSOptions() {
file := s.adaptFile("fixtures/tcp/multi-tls-options.toml", struct {
WhoamiNoCert string
}{
WhoamiNoCert: s.getComposeServiceIP(c, "whoami-no-cert") + ":8080",
WhoamiNoCert: s.getComposeServiceIP("whoami-no-cert") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-c.test`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-c.test`)"))
require.NoError(s.T(), err)
// Check that we can use a client tls version <= 1.2 with hostSNI 'whoami-c.test'
out, err := guessWhoTLSMaxVersion("127.0.0.1:8093", "whoami-c.test", true, tls.VersionTLS12)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-no-cert")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-no-cert")
// Check that we can use a client tls version <= 1.3 with hostSNI 'whoami-d.test'
out, err = guessWhoTLSMaxVersion("127.0.0.1:8093", "whoami-d.test", true, tls.VersionTLS13)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-no-cert")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-no-cert")
// Check that we cannot use a client tls version <= 1.2 with hostSNI 'whoami-d.test'
_, err = guessWhoTLSMaxVersion("127.0.0.1:8093", "whoami-d.test", true, tls.VersionTLS12)
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "protocol version not supported")
assert.ErrorContains(s.T(), err, "protocol version not supported")
// Check that we can't reach a route with an invalid mTLS configuration.
conn, err := tls.Dial("tcp", "127.0.0.1:8093", &tls.Config{
ServerName: "whoami-i.test",
InsecureSkipVerify: true,
})
c.Assert(conn, checker.IsNil)
c.Assert(err, checker.NotNil)
assert.Nil(s.T(), conn)
assert.Error(s.T(), err)
}
func (s *TCPSuite) TestNonTLSFallback(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/non-tls-fallback.toml", struct {
func (s *TCPSuite) TestNonTLSFallback() {
file := s.adaptFile("fixtures/tcp/non-tls-fallback.toml", struct {
WhoamiA string
WhoamiB string
WhoamiNoCert string
WhoamiNoTLS string
}{
WhoamiA: s.getComposeServiceIP(c, "whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP(c, "whoami-b") + ":8080",
WhoamiNoCert: s.getComposeServiceIP(c, "whoami-no-cert") + ":8080",
WhoamiNoTLS: s.getComposeServiceIP(c, "whoami-no-tls") + ":8080",
WhoamiA: s.getComposeServiceIP("whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP("whoami-b") + ":8080",
WhoamiNoCert: s.getComposeServiceIP("whoami-no-cert") + ":8080",
WhoamiNoTLS: s.getComposeServiceIP("whoami-no-tls") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
require.NoError(s.T(), err)
// Traefik passes through, termination handled by whoami-a
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-a")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-a")
// Traefik passes through, termination handled by whoami-b
out, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-b")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-b")
// Termination handled by traefik
out, err = guessWho("127.0.0.1:8093", "whoami-c.test", true)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-no-cert")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-no-cert")
out, err = guessWho("127.0.0.1:8093", "", false)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-no-tls")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-no-tls")
}
func (s *TCPSuite) TestNonTlsTcp(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/non-tls.toml", struct {
func (s *TCPSuite) TestNonTlsTcp() {
file := s.adaptFile("fixtures/tcp/non-tls.toml", struct {
WhoamiNoTLS string
}{
WhoamiNoTLS: s.getComposeServiceIP(c, "whoami-no-tls") + ":8080",
WhoamiNoTLS: s.getComposeServiceIP("whoami-no-tls") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
require.NoError(s.T(), err)
// Traefik will forward every requests on the given port to whoami-no-tls
out, err := guessWho("127.0.0.1:8093", "", false)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-no-tls")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-no-tls")
}
func (s *TCPSuite) TestCatchAllNoTLS(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/catch-all-no-tls.toml", struct {
func (s *TCPSuite) TestCatchAllNoTLS() {
file := s.adaptFile("fixtures/tcp/catch-all-no-tls.toml", struct {
WhoamiBannerAddress string
}{
WhoamiBannerAddress: s.getComposeServiceIP(c, "whoami-banner") + ":8080",
WhoamiBannerAddress: s.getComposeServiceIP("whoami-banner") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
require.NoError(s.T(), err)
// Traefik will forward every requests on the given port to whoami-no-tls
out, err := welcome("127.0.0.1:8093")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "Welcome")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "Welcome")
}
func (s *TCPSuite) TestCatchAllNoTLSWithHTTPS(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/catch-all-no-tls-with-https.toml", struct {
func (s *TCPSuite) TestCatchAllNoTLSWithHTTPS() {
file := s.adaptFile("fixtures/tcp/catch-all-no-tls-with-https.toml", struct {
WhoamiNoTLSAddress string
WhoamiURL string
}{
WhoamiNoTLSAddress: s.getComposeServiceIP(c, "whoami-no-tls") + ":8080",
WhoamiURL: "http://" + s.getComposeServiceIP(c, "whoami") + ":80",
WhoamiNoTLSAddress: s.getComposeServiceIP("whoami-no-tls") + ":8080",
WhoamiURL: "http://" + s.getComposeServiceIP("whoami") + ":80",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`*`)"))
require.NoError(s.T(), err)
req := httptest.NewRequest(http.MethodGet, "https://127.0.0.1:8093/test", nil)
req.RequestURI = ""
@ -246,64 +221,52 @@ func (s *TCPSuite) TestCatchAllNoTLSWithHTTPS(c *check.C) {
InsecureSkipVerify: true,
},
}, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *TCPSuite) TestMiddlewareAllowList(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/ip-allowlist.toml", struct {
func (s *TCPSuite) TestMiddlewareAllowList() {
file := s.adaptFile("fixtures/tcp/ip-allowlist.toml", struct {
WhoamiA string
WhoamiB string
}{
WhoamiA: s.getComposeServiceIP(c, "whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP(c, "whoami-b") + ":8080",
WhoamiA: s.getComposeServiceIP("whoami-a") + ":8080",
WhoamiB: s.getComposeServiceIP("whoami-b") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-a.test`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-a.test`)"))
require.NoError(s.T(), err)
// Traefik not passes through, ipWhitelist closes connection
_, err = guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-a.test")
c.Assert(err, checker.ErrorMatches, "EOF")
assert.ErrorIs(s.T(), err, io.EOF)
// Traefik passes through, termination handled by whoami-b
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "whoami-b")
require.NoError(s.T(), err)
assert.Contains(s.T(), out, "whoami-b")
}
func (s *TCPSuite) TestWRR(c *check.C) {
file := s.adaptFile(c, "fixtures/tcp/wrr.toml", struct {
func (s *TCPSuite) TestWRR() {
file := s.adaptFile("fixtures/tcp/wrr.toml", struct {
WhoamiB string
WhoamiAB string
}{
WhoamiB: s.getComposeServiceIP(c, "whoami-b") + ":8080",
WhoamiAB: s.getComposeServiceIP(c, "whoami-ab") + ":8080",
WhoamiB: s.getComposeServiceIP("whoami-b") + ":8080",
WhoamiAB: s.getComposeServiceIP("whoami-ab") + ":8080",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-b.test`)"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-b.test`)"))
require.NoError(s.T(), err)
call := map[string]int{}
for i := 0; i < 4; i++ {
// Traefik passes through, termination handled by whoami-b or whoami-bb
out, err := guessWhoTLSPassthrough("127.0.0.1:8093", "whoami-b.test")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
switch {
case strings.Contains(out, "whoami-b"):
call["whoami-b"]++
@ -315,7 +278,7 @@ func (s *TCPSuite) TestWRR(c *check.C) {
time.Sleep(time.Second)
}
c.Assert(call, checker.DeepEquals, map[string]int{"whoami-b": 3, "whoami-ab": 1})
assert.EqualValues(s.T(), call, map[string]int{"whoami-b": 3, "whoami-ab": 1})
}
func welcome(addr string) (string, error) {

View file

@ -4,47 +4,53 @@ import (
"fmt"
"net"
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type TimeoutSuite struct{ BaseSuite }
func (s *TimeoutSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "timeout")
s.composeUp(c)
func TestTimeoutSuite(t *testing.T) {
suite.Run(t, new(TimeoutSuite))
}
func (s *TimeoutSuite) TestForwardingTimeouts(c *check.C) {
timeoutEndpointIP := s.getComposeServiceIP(c, "timeoutEndpoint")
file := s.adaptFile(c, "fixtures/timeout/forwarding_timeouts.toml", struct{ TimeoutEndpoint string }{timeoutEndpointIP})
defer os.Remove(file)
func (s *TimeoutSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.createComposeProject("timeout")
s.composeUp()
}
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Path(`/dialTimeout`)"))
c.Assert(err, checker.IsNil)
func (s *TimeoutSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *TimeoutSuite) TestForwardingTimeouts() {
timeoutEndpointIP := s.getComposeServiceIP("timeoutEndpoint")
file := s.adaptFile("fixtures/timeout/forwarding_timeouts.toml", struct{ TimeoutEndpoint string }{timeoutEndpointIP})
s.traefikCmd(withConfigFile(file))
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 60*time.Second, try.BodyContains("Path(`/dialTimeout`)"))
require.NoError(s.T(), err)
// This simulates a DialTimeout when connecting to the backend server.
response, err := http.Get("http://127.0.0.1:8000/dialTimeout")
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusGatewayTimeout)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusGatewayTimeout, response.StatusCode)
// Check that timeout service is available
statusURL := fmt.Sprintf("http://%s/statusTest?status=200",
net.JoinHostPort(timeoutEndpointIP, "9000"))
c.Assert(try.GetRequest(statusURL, 60*time.Second, try.StatusCodeIs(http.StatusOK)), checker.IsNil)
assert.NoError(s.T(), try.GetRequest(statusURL, 60*time.Second, try.StatusCodeIs(http.StatusOK)))
// This simulates a ResponseHeaderTimeout.
response, err = http.Get("http://127.0.0.1:8000/responseHeaderTimeout?sleep=1000")
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusGatewayTimeout)
require.NoError(s.T(), err)
assert.Equal(s.T(), http.StatusGatewayTimeout, response.StatusCode)
}

View file

@ -4,11 +4,13 @@ import (
"crypto/tls"
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
const (
@ -19,20 +21,30 @@ const (
type TLSClientHeadersSuite struct{ BaseSuite }
func (s *TLSClientHeadersSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "tlsclientheaders")
s.composeUp(c)
func TestTLSClientHeadersSuite(t *testing.T) {
suite.Run(t, new(TLSClientHeadersSuite))
}
func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
rootCertContent, err := os.ReadFile(rootCertPath)
c.Assert(err, check.IsNil)
serverCertContent, err := os.ReadFile(certPemPath)
c.Assert(err, check.IsNil)
ServerKeyContent, err := os.ReadFile(certKeyPath)
c.Assert(err, check.IsNil)
func (s *TLSClientHeadersSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
file := s.adaptFile(c, "fixtures/tlsclientheaders/simple.toml", struct {
s.createComposeProject("tlsclientheaders")
s.composeUp()
}
func (s *TLSClientHeadersSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *TLSClientHeadersSuite) TestTLSClientHeaders() {
rootCertContent, err := os.ReadFile(rootCertPath)
assert.NoError(s.T(), err)
serverCertContent, err := os.ReadFile(certPemPath)
assert.NoError(s.T(), err)
ServerKeyContent, err := os.ReadFile(certKeyPath)
assert.NoError(s.T(), err)
file := s.adaptFile("fixtures/tlsclientheaders/simple.toml", struct {
RootCertContent string
ServerCertContent string
ServerKeyContent string
@ -41,22 +53,17 @@ func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
ServerCertContent: string(serverCertContent),
ServerKeyContent: string(ServerKeyContent),
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second, try.BodyContains("PathPrefix(`/foo`)"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
request, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8443/foo", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
certificate, err := tls.LoadX509KeyPair(certPemPath, certKeyPath)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
tr := &http.Transport{
TLSClientConfig: &tls.Config{
@ -66,5 +73,5 @@ func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) {
}
err = try.RequestWithTransport(request, 2*time.Second, tr, try.BodyContains("Forwarded-Tls-Client-Cert: MIIDNTCCAh0CFD0QQcHXUJuKwMBYDA+bBExVSP26MA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxFTATBgNVBAoMDFRyYWVmaWsgTGFiczEQMA4GA1UECwwHdHJhZWZpazENMAsGA1UEAwwEcm9vdDAeFw0yMTAxMDgxNzQ0MjRaFw0zMTAxMDYxNzQ0MjRaMFgxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxFTATBgNVBAoMDFRyYWVmaWsgTGFiczEQMA4GA1UECwwHdHJhZWZpazEPMA0GA1UEAwwGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvYK2z8gLPOfFLgXNWP2460aeJ9vrH47x/lhKLlv4amSDHDx8Cmz/6blOUM8XOfMRW1xx++AgChWN9dx/kf7G2xlA5grZxRvUQ6xj7AvFG9TQUA3muNh2hvm9c3IjaZBNKH27bRKuDIBvZBvXdX4NL/aaFy7w7v7IKxk8j4WkfB23sgyH43g4b7NqKHJugZiedFu5GALmtLbShVOFbjWcre7Wvatdw8dIBmiFJqZQT3UjIuGAgqczIShtLxo4V+XyVkIPmzfPrRV+4zoMFIFOIaj3syyxb4krPBtxhe7nz2cWvvq0wePB2y4YbAAoVY8NYpd5JsMFwZtG6Uk59ygv4QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDaPg69wNeFNFisfBJTrscqVCTW+B80gMhpLdxXD+KO0/Wgc5xpB/wLSirNtRQyxAa3+EEcIwJv/wdh8EyjlDLSpFm/8ghntrKhkOfIOPDFE41M5HNfx/Fuh5btKEenOL/XdapqtNUt2ZE4RrsfbL79sPYepa9kDUVi2mCbeH5ollZ0MDU68HpB2YwHbCEuQNk5W3pjYK2NaDkVnxTkfEDM1k+3QydO1lqB5JJmcrs59BEveTqaJ3eeh/0I4OOab6OkTTZ0JNjJp1573oxO+fce/bfGud8xHY5gSN9huU7U6RsgvO7Dhmal/sDNl8XC8oU90hVDVXZdA7ewh4jjaoIv"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}

View file

@ -2,19 +2,24 @@ package integration
import (
"net/http"
"os"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
type TracingSuite struct {
BaseSuite
whoamiIP string
whoamiPort int
tracerIP string
whoamiIP string
whoamiPort int
tracerZipkinIP string
tracerJaegerIP string
}
func TestTracingSuite(t *testing.T) {
suite.Run(t, new(TracingSuite))
}
type TracingTemplate struct {
@ -24,302 +29,264 @@ type TracingTemplate struct {
TraceContextHeaderName string
}
func (s *TracingSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "tracing")
s.composeUp(c)
func (s *TracingSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.whoamiIP = s.getComposeServiceIP(c, "whoami")
s.createComposeProject("tracing")
s.composeUp()
s.whoamiIP = s.getComposeServiceIP("whoami")
s.whoamiPort = 80
}
func (s *TracingSuite) startZipkin(c *check.C) {
s.composeUp(c, "zipkin")
s.tracerIP = s.getComposeServiceIP(c, "zipkin")
func (s *TracingSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func (s *TracingSuite) startZipkin() {
s.composeUp("zipkin")
s.tracerZipkinIP = s.getComposeServiceIP("zipkin")
// Wait for Zipkin to turn ready.
err := try.GetRequest("http://"+s.tracerIP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://"+s.tracerZipkinIP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestZipkinRateLimit(c *check.C) {
s.startZipkin(c)
// defer s.composeStop(c, "zipkin")
func (s *TracingSuite) TestZipkinRateLimit() {
s.startZipkin()
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-zipkin.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.tracerIP,
IP: s.tracerZipkinIP,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// sleep for 4 seconds to be certain the configured time period has elapsed
// then test another request and verify a 200 status code
time.Sleep(4 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// continue requests at 3 second intervals to test the other rate limit time period
time.Sleep(3 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
time.Sleep(3 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
time.Sleep(3 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestZipkinRetry(c *check.C) {
s.startZipkin(c)
defer s.composeStop(c, "zipkin")
func (s *TracingSuite) TestZipkinRetry() {
s.startZipkin()
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-zipkin.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: 81,
IP: s.tracerIP,
IP: s.tracerZipkinIP,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestZipkinAuth(c *check.C) {
s.startZipkin(c)
defer s.composeStop(c, "zipkin")
func (s *TracingSuite) TestZipkinAuth() {
s.startZipkin()
file := s.adaptFile(c, "fixtures/tracing/simple-zipkin.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-zipkin.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.tracerIP,
IP: s.tracerZipkinIP,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint web", "basic-auth@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerZipkinIP+":9411/api/v2/spans?serviceName=tracing", 20*time.Second, try.BodyContains("entrypoint web", "basic-auth@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) startJaeger(c *check.C) {
s.composeUp(c, "jaeger", "whoami")
s.tracerIP = s.getComposeServiceIP(c, "jaeger")
func (s *TracingSuite) startJaeger() {
s.composeUp("jaeger", "whoami")
s.tracerJaegerIP = s.getComposeServiceIP("jaeger")
// Wait for Jaeger to turn ready.
err := try.GetRequest("http://"+s.tracerIP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestJaegerRateLimit(c *check.C) {
s.startJaeger(c)
defer s.composeStop(c, "jaeger")
func (s *TracingSuite) TestJaegerRateLimit() {
s.startJaeger()
// defer s.composeStop(c, "jaeger")
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-jaeger.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.tracerIP,
IP: s.tracerJaegerIP,
TraceContextHeaderName: "uber-trace-id",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// sleep for 4 seconds to be certain the configured time period has elapsed
// then test another request and verify a 200 status code
time.Sleep(4 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
// continue requests at 3 second intervals to test the other rate limit time period
time.Sleep(3 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
time.Sleep(3 * time.Second)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/ratelimit", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service1/router1@file", "ratelimit-1@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestJaegerRetry(c *check.C) {
s.startJaeger(c)
defer s.composeStop(c, "jaeger")
func (s *TracingSuite) TestJaegerRetry() {
s.startJaeger()
// defer s.composeStop(c, "jaeger")
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-jaeger.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: 81,
IP: s.tracerIP,
IP: s.tracerJaegerIP,
TraceContextHeaderName: "uber-trace-id",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/retry", 500*time.Millisecond, try.StatusCodeIs(http.StatusBadGateway))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("forward service2/router2@file", "retry@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestJaegerAuth(c *check.C) {
s.startJaeger(c)
defer s.composeStop(c, "jaeger")
func (s *TracingSuite) TestJaegerAuth() {
s.startJaeger()
// defer s.composeStop(c, "jaeger")
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-jaeger.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.tracerIP,
IP: s.tracerJaegerIP,
TraceContextHeaderName: "uber-trace-id",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestJaegerCustomHeader(c *check.C) {
s.startJaeger(c)
defer s.composeStop(c, "jaeger")
func (s *TracingSuite) TestJaegerCustomHeader() {
s.startJaeger()
// defer s.composeStop(c, "jaeger")
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-jaeger.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.tracerIP,
IP: s.tracerJaegerIP,
TraceContextHeaderName: "powpow",
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
require.NoError(s.T(), err)
}
func (s *TracingSuite) TestJaegerAuthCollector(c *check.C) {
s.startJaeger(c)
defer s.composeStop(c, "jaeger")
func (s *TracingSuite) TestJaegerAuthCollector() {
s.startJaeger()
// defer s.composeStop(c, "jaeger")
file := s.adaptFile(c, "fixtures/tracing/simple-jaeger-collector.toml", TracingTemplate{
file := s.adaptFile("fixtures/tracing/simple-jaeger-collector.toml", TracingTemplate{
WhoamiIP: s.whoamiIP,
WhoamiPort: s.whoamiPort,
IP: s.tracerIP,
IP: s.tracerJaegerIP,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("basic-auth"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8000/auth", 500*time.Millisecond, try.StatusCodeIs(http.StatusUnauthorized))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = try.GetRequest("http://"+s.tracerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
require.NoError(s.T(), err)
}

View file

@ -3,20 +3,32 @@ package integration
import (
"net"
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/go-check/check"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
"github.com/traefik/traefik/v2/pkg/log"
)
type UDPSuite struct{ BaseSuite }
func (s *UDPSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "udp")
s.composeUp(c)
func TestUDPSuite(t *testing.T) {
suite.Run(t, new(UDPSuite))
}
func (s *UDPSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("udp")
s.composeUp()
}
func (s *UDPSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
func guessWhoUDP(addr string) (string, error) {
@ -46,39 +58,33 @@ func guessWhoUDP(addr string) (string, error) {
return string(out[:n]), nil
}
func (s *UDPSuite) TestWRR(c *check.C) {
file := s.adaptFile(c, "fixtures/udp/wrr.toml", struct {
func (s *UDPSuite) TestWRR() {
file := s.adaptFile("fixtures/udp/wrr.toml", struct {
WhoamiAIP string
WhoamiBIP string
WhoamiCIP string
WhoamiDIP string
}{
WhoamiAIP: s.getComposeServiceIP(c, "whoami-a"),
WhoamiBIP: s.getComposeServiceIP(c, "whoami-b"),
WhoamiCIP: s.getComposeServiceIP(c, "whoami-c"),
WhoamiDIP: s.getComposeServiceIP(c, "whoami-d"),
WhoamiAIP: s.getComposeServiceIP("whoami-a"),
WhoamiBIP: s.getComposeServiceIP("whoami-b"),
WhoamiCIP: s.getComposeServiceIP("whoami-c"),
WhoamiDIP: s.getComposeServiceIP("whoami-d"),
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
s.traefikCmd(withConfigFile(file))
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("whoami-a"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains("whoami-a"))
require.NoError(s.T(), err)
err = try.GetRequest("http://127.0.0.1:8093/who", 5*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
stop := make(chan struct{})
go func() {
call := map[string]int{}
for i := 0; i < 8; i++ {
out, err := guessWhoUDP("127.0.0.1:8093")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
switch {
case strings.Contains(out, "whoami-a"):
call["whoami-a"]++
@ -90,13 +96,13 @@ func (s *UDPSuite) TestWRR(c *check.C) {
call["unknown"]++
}
}
c.Assert(call, checker.DeepEquals, map[string]int{"whoami-a": 3, "whoami-b": 2, "whoami-c": 3})
assert.EqualValues(s.T(), call, map[string]int{"whoami-a": 3, "whoami-b": 2, "whoami-c": 3})
close(stop)
}()
select {
case <-stop:
case <-time.Tick(5 * time.Second):
c.Error("Timeout")
log.WithoutContext().Info("Timeout")
}
}

View file

@ -8,19 +8,25 @@ import (
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/go-check/check"
gorillawebsocket "github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
"golang.org/x/net/websocket"
)
// WebsocketSuite tests suite.
type WebsocketSuite struct{ BaseSuite }
func (s *WebsocketSuite) TestBase(c *check.C) {
func TestWebsocketSuite(t *testing.T) {
suite.Run(t, new(WebsocketSuite))
}
func (s *WebsocketSuite) TestBase() {
upgrader := gorillawebsocket.Upgrader{} // use default options
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -41,36 +47,30 @@ func (s *WebsocketSuite) TestBase(c *check.C) {
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
conn, _, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = conn.WriteMessage(gorillawebsocket.TextMessage, []byte("OK"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, msg, err := conn.ReadMessage()
c.Assert(err, checker.IsNil)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
func (s *WebsocketSuite) TestWrongOrigin() {
upgrader := gorillawebsocket.Upgrader{} // use default options
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -91,35 +91,28 @@ func (s *WebsocketSuite) TestWrongOrigin(c *check.C) {
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:800")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
conn, err := net.DialTimeout("tcp", "127.0.0.1:8000", time.Second)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, err = websocket.NewClient(config, conn)
c.Assert(err, checker.NotNil)
c.Assert(err, checker.ErrorMatches, "bad status")
assert.ErrorContains(s.T(), err, "bad status")
}
func (s *WebsocketSuite) TestOrigin(c *check.C) {
func (s *WebsocketSuite) TestOrigin() {
// use default options
upgrader := gorillawebsocket.Upgrader{}
@ -141,44 +134,38 @@ func (s *WebsocketSuite) TestOrigin(c *check.C) {
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:8000")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
conn, err := net.DialTimeout("tcp", "127.0.0.1:8000", time.Second)
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
client, err := websocket.NewClient(config, conn)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
n, err := client.Write([]byte("OK"))
c.Assert(err, checker.IsNil)
c.Assert(n, checker.Equals, 2)
require.NoError(s.T(), err)
assert.Equal(s.T(), 2, n)
msg := make([]byte, 2)
n, err = client.Read(msg)
c.Assert(err, checker.IsNil)
c.Assert(n, checker.Equals, 2)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), 2, n)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
func (s *WebsocketSuite) TestWrongOriginIgnoredByServer() {
upgrader := gorillawebsocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
return true
}}
@ -201,44 +188,38 @@ func (s *WebsocketSuite) TestWrongOriginIgnoredByServer(c *check.C) {
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:80")
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
conn, err := net.DialTimeout("tcp", "127.0.0.1:8000", time.Second)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
client, err := websocket.NewClient(config, conn)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
n, err := client.Write([]byte("OK"))
c.Assert(err, checker.IsNil)
c.Assert(n, checker.Equals, 2)
require.NoError(s.T(), err)
assert.Equal(s.T(), 2, n)
msg := make([]byte, 2)
n, err = client.Read(msg)
c.Assert(err, checker.IsNil)
c.Assert(n, checker.Equals, 2)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), 2, n)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
func (s *WebsocketSuite) TestSSLTermination() {
upgrader := gorillawebsocket.Upgrader{} // use default options
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -258,44 +239,38 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) {
}
}
}))
file := s.adaptFile(c, "fixtures/websocket/config_https.toml", struct {
file := s.adaptFile("fixtures/websocket/config_https.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
// Add client self-signed cert
roots := x509.NewCertPool()
certContent, err := os.ReadFile("./resources/tls/local.cert")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
roots.AppendCertsFromPEM(certContent)
gorillawebsocket.DefaultDialer.TLSClientConfig = &tls.Config{
RootCAs: roots,
}
conn, _, err := gorillawebsocket.DefaultDialer.Dial("wss://127.0.0.1:8000/ws", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = conn.WriteMessage(gorillawebsocket.TextMessage, []byte("OK"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, msg, err := conn.ReadMessage()
c.Assert(err, checker.IsNil)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
func (s *WebsocketSuite) TestBasicAuth() {
upgrader := gorillawebsocket.Upgrader{} // use default options
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -306,8 +281,8 @@ func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
defer conn.Close()
user, password, _ := r.BasicAuth()
c.Assert(user, check.Equals, "traefiker")
c.Assert(password, check.Equals, "secret")
assert.Equal(s.T(), "traefiker", user)
assert.Equal(s.T(), "secret", password)
for {
mt, message, err := conn.ReadMessage()
@ -320,78 +295,66 @@ func (s *WebsocketSuite) TestBasicAuth(c *check.C) {
}
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:8000")
auth := "traefiker:secret"
config.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
c.Assert(err, check.IsNil)
assert.NoError(s.T(), err)
conn, err := net.DialTimeout("tcp", "127.0.0.1:8000", time.Second)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
client, err := websocket.NewClient(config, conn)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
n, err := client.Write([]byte("OK"))
c.Assert(err, checker.IsNil)
c.Assert(n, checker.Equals, 2)
require.NoError(s.T(), err)
assert.Equal(s.T(), 2, n)
msg := make([]byte, 2)
n, err = client.Read(msg)
c.Assert(err, checker.IsNil)
c.Assert(n, checker.Equals, 2)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), 2, n)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) {
func (s *WebsocketSuite) TestSpecificResponseFromBackend() {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
_, resp, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws", nil)
c.Assert(err, checker.NotNil)
c.Assert(resp.StatusCode, check.Equals, http.StatusUnauthorized)
assert.Error(s.T(), err)
assert.Equal(s.T(), http.StatusUnauthorized, resp.StatusCode)
}
func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
func (s *WebsocketSuite) TestURLWithURLEncodedChar() {
upgrader := gorillawebsocket.Upgrader{} // use default options
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c.Assert(r.URL.EscapedPath(), check.Equals, "/ws/http%3A%2F%2Ftest")
assert.Equal(s.T(), "/ws/http%3A%2F%2Ftest", r.URL.EscapedPath())
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
@ -409,36 +372,30 @@ func (s *WebsocketSuite) TestURLWithURLEncodedChar(c *check.C) {
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
conn, _, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws/http%3A%2F%2Ftest", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = conn.WriteMessage(gorillawebsocket.TextMessage, []byte("OK"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, msg, err := conn.ReadMessage()
c.Assert(err, checker.IsNil)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
func (s *WebsocketSuite) TestSSLhttp2() {
upgrader := gorillawebsocket.Upgrader{} // use default options
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -463,48 +420,42 @@ func (s *WebsocketSuite) TestSSLhttp2(c *check.C) {
ts.TLS.NextProtos = append(ts.TLS.NextProtos, `h2`, `http/1.1`)
ts.StartTLS()
file := s.adaptFile(c, "fixtures/websocket/config_https.toml", struct {
file := s.adaptFile("fixtures/websocket/config_https.toml", struct {
WebsocketServer string
}{
WebsocketServer: ts.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG", "--accesslog")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG", "--accesslog")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
// Add client self-signed cert
roots := x509.NewCertPool()
certContent, err := os.ReadFile("./resources/tls/local.cert")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
roots.AppendCertsFromPEM(certContent)
gorillawebsocket.DefaultDialer.TLSClientConfig = &tls.Config{
RootCAs: roots,
}
conn, _, err := gorillawebsocket.DefaultDialer.Dial("wss://127.0.0.1:8000/echo", nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = conn.WriteMessage(gorillawebsocket.TextMessage, []byte("OK"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, msg, err := conn.ReadMessage()
c.Assert(err, checker.IsNil)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), "OK", string(msg))
}
func (s *WebsocketSuite) TestHeaderAreForwarded(c *check.C) {
func (s *WebsocketSuite) TestHeaderAreForwarded() {
upgrader := gorillawebsocket.Upgrader{} // use default options
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c.Assert(r.Header.Get("X-Token"), check.Equals, "my-token")
assert.Equal(s.T(), "my-token", r.Header.Get("X-Token"))
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
@ -522,33 +473,27 @@ func (s *WebsocketSuite) TestHeaderAreForwarded(c *check.C) {
}
}))
file := s.adaptFile(c, "fixtures/websocket/config.toml", struct {
file := s.adaptFile("fixtures/websocket/config.toml", struct {
WebsocketServer string
}{
WebsocketServer: srv.URL,
})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
defer display(c)
err := cmd.Start()
c.Assert(err, check.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG")
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
c.Assert(err, checker.IsNil)
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 10*time.Second, try.BodyContains("127.0.0.1"))
require.NoError(s.T(), err)
headers := http.Header{}
headers.Add("X-Token", "my-token")
conn, _, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws", headers)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
err = conn.WriteMessage(gorillawebsocket.TextMessage, []byte("OK"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
_, msg, err := conn.ReadMessage()
c.Assert(err, checker.IsNil)
c.Assert(string(msg), checker.Equals, "OK")
require.NoError(s.T(), err)
assert.Equal(s.T(), "OK", string(msg))
}

View file

@ -8,16 +8,18 @@ import (
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/go-check/check"
"github.com/kvtools/valkeyrie"
"github.com/kvtools/valkeyrie/store"
"github.com/kvtools/zookeeper"
"github.com/pmezard/go-difflib/difflib"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/api"
checker "github.com/vdemeester/shakers"
"github.com/traefik/traefik/v2/pkg/log"
)
// Zk test suites.
@ -27,11 +29,17 @@ type ZookeeperSuite struct {
zookeeperAddr string
}
func (s *ZookeeperSuite) setupStore(c *check.C) {
s.createComposeProject(c, "zookeeper")
s.composeUp(c)
func TestZookeeperSuite(t *testing.T) {
suite.Run(t, new(ZookeeperSuite))
}
s.zookeeperAddr = net.JoinHostPort(s.getComposeServiceIP(c, "zookeeper"), "2181")
func (s *ZookeeperSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
s.createComposeProject("zookeeper")
s.composeUp()
s.zookeeperAddr = net.JoinHostPort(s.getComposeServiceIP("zookeeper"), "2181")
var err error
s.kvClient, err = valkeyrie.NewStore(
@ -42,20 +50,19 @@ func (s *ZookeeperSuite) setupStore(c *check.C) {
ConnectionTimeout: 10 * time.Second,
},
)
if err != nil {
c.Fatal("Cannot create store zookeeper")
}
require.NoError(s.T(), err, "Cannot create store zookeeper")
// wait for zk
err = try.Do(60*time.Second, try.KVExists(s.kvClient, "test"))
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
s.setupStore(c)
func (s *ZookeeperSuite) TearDownSuite() {
s.BaseSuite.TearDownSuite()
}
file := s.adaptFile(c, "fixtures/zookeeper/simple.toml", struct{ ZkAddress string }{s.zookeeperAddr})
defer os.Remove(file)
func (s *ZookeeperSuite) TestSimpleConfiguration() {
file := s.adaptFile("fixtures/zookeeper/simple.toml", struct{ ZkAddress string }{s.zookeeperAddr})
data := map[string]string{
"traefik/http/routers/Router0/entryPoints/0": "web",
@ -105,39 +112,35 @@ func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
s.traefikCmd(withConfigFile(file))
// wait for traefik
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2*time.Second,
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 5*time.Second,
try.BodyContains(`"striper@zookeeper":`, `"compressor@zookeeper":`, `"srvcA@zookeeper":`, `"srvcB@zookeeper":`),
)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
resp, err := http.Get("http://127.0.0.1:8080/api/rawdata")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
var obtained api.RunTimeRepresentation
err = json.NewDecoder(resp.Body).Decode(&obtained)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
got, err := json.MarshalIndent(obtained, "", " ")
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
expectedJSON := filepath.FromSlash("testdata/rawdata-zk.json")
if *updateExpected {
err = os.WriteFile(expectedJSON, got, 0o666)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
}
expected, err := os.ReadFile(expectedJSON)
c.Assert(err, checker.IsNil)
require.NoError(s.T(), err)
if !bytes.Equal(expected, got) {
diff := difflib.UnifiedDiff{
@ -149,7 +152,7 @@ func (s *ZookeeperSuite) TestSimpleConfiguration(c *check.C) {
}
text, err := difflib.GetUnifiedDiffString(diff)
c.Assert(err, checker.IsNil)
c.Error(text)
require.NoError(s.T(), err)
log.WithoutContext().Info(text)
}
}