refactor(suites): stop integration tests on first failure (#3270)

* refactor(suites): stop integration tests on first failure

* refactor(suites): remove additional nginx instance

* refactor(suites): log relevant containers

* refactor(suites): add traefik2 logs to stdout

* refactor(suites): explicitly enable traefik for tests

* refactor(suites): remove redis restart and duplicate pathprefix tests

* ci(buildkite): allow manual retry on integration tests
This commit is contained in:
Amir Zarrinkafsh 2022-05-02 14:50:37 +10:00 committed by GitHub
parent 11a8e24b71
commit 91c0c81818
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 143 additions and 61 deletions

View File

@ -4,9 +4,11 @@ set -eu
for SUITE_NAME in $(authelia-scripts suites list); do for SUITE_NAME in $(authelia-scripts suites list); do
cat << EOF cat << EOF
- label: ":selenium: ${SUITE_NAME} Suite" - label: ":selenium: ${SUITE_NAME} Suite"
command: "authelia-scripts --log-level debug suites test ${SUITE_NAME} --headless" command: "authelia-scripts --log-level debug suites test ${SUITE_NAME} --failfast --headless"
retry: retry:
automatic: true automatic: true
manual:
permit_on_passed: true
EOF EOF
if [[ "${SUITE_NAME}" = "ActiveDirectory" ]]; then if [[ "${SUITE_NAME}" = "ActiveDirectory" ]]; then
cat << EOF cat << EOF

View File

@ -26,10 +26,12 @@ var ErrNoRunningSuite = errors.New("no running suite")
// runningSuiteFile name of the file containing the currently running suite. // runningSuiteFile name of the file containing the currently running suite.
var runningSuiteFile = ".suite" var runningSuiteFile = ".suite"
var failfast bool
var headless bool var headless bool
var testPattern string var testPattern string
func init() { func init() {
SuitesTestCmd.Flags().BoolVar(&failfast, "failfast", false, "Stops tests on first failure")
SuitesTestCmd.Flags().BoolVar(&headless, "headless", false, "Run tests in headless mode") SuitesTestCmd.Flags().BoolVar(&headless, "headless", false, "Run tests in headless mode")
SuitesTestCmd.Flags().StringVar(&testPattern, "test", "", "The single test to run") SuitesTestCmd.Flags().StringVar(&testPattern, "test", "", "The single test to run")
} }
@ -279,7 +281,12 @@ func runSuiteTests(suiteName string, withEnv bool) error {
timeout = fmt.Sprintf("%ds", int64(suite.TestTimeout/time.Second)) timeout = fmt.Sprintf("%ds", int64(suite.TestTimeout/time.Second))
} }
testCmdLine := fmt.Sprintf("go test -count=1 -v ./internal/suites -timeout %s ", timeout) fail := ""
if failfast {
fail = "-failfast"
}
testCmdLine := fmt.Sprintf("go test -count=1 -v ./internal/suites -timeout %s %s ", timeout, fail)
if testPattern != "" { if testPattern != "" {
testCmdLine += fmt.Sprintf("-run '%s'", testPattern) testCmdLine += fmt.Sprintf("-run '%s'", testPattern)

View File

@ -24,6 +24,7 @@ services:
- 'traefik.frontend.rule=Host:login.example.com;PathPrefix:/api,/locales' - 'traefik.frontend.rule=Host:login.example.com;PathPrefix:/api,/locales'
- 'traefik.protocol=https' - 'traefik.protocol=https'
# Traefik 2.x # Traefik 2.x
- 'traefik.enable=true'
- 'traefik.http.routers.authelia_backend.rule=Host(`login.example.com`) && PathPrefix(`/.well-known`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/.well-known`) || Host(`login.example.com`) && PathPrefix(`/api`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/api`) || Host(`login.example.com`) && PathPrefix(`/locales`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/locales`) || Host(`login.example.com`) && Path(`/jwks.json`) || Host(`login.example.com`) && Path(`${PathPrefix}/jwks.json`)' # yamllint disable-line rule:line-length - 'traefik.http.routers.authelia_backend.rule=Host(`login.example.com`) && PathPrefix(`/.well-known`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/.well-known`) || Host(`login.example.com`) && PathPrefix(`/api`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/api`) || Host(`login.example.com`) && PathPrefix(`/locales`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/locales`) || Host(`login.example.com`) && Path(`/jwks.json`) || Host(`login.example.com`) && Path(`${PathPrefix}/jwks.json`)' # yamllint disable-line rule:line-length
- 'traefik.http.routers.authelia_backend.entrypoints=https' - 'traefik.http.routers.authelia_backend.entrypoints=https'
- 'traefik.http.routers.authelia_backend.tls=true' - 'traefik.http.routers.authelia_backend.tls=true'

View File

@ -5,14 +5,16 @@ services:
image: authelia:dist image: authelia:dist
labels: labels:
# Traefik 1.x # Traefik 1.x
- 'traefik.frontend.rule=Host:login.example.com;PathPrefix:/api,/locales' - 'traefik.frontend.rule=Host:login.example.com'
- 'traefik.protocol=https' - 'traefik.protocol=https'
# Traefik 2.x # Traefik 2.x
- 'traefik.http.routers.authelia_backend.rule=Host(`login.example.com`) && PathPrefix(`/.well-known`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/.well-known`) || Host(`login.example.com`) && PathPrefix(`/api`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/api`) || Host(`login.example.com`) && PathPrefix(`/locales`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/locales`) || Host(`login.example.com`) && Path(`/jwks.json`) || Host(`login.example.com`) && Path(`${PathPrefix}/jwks.json`)' # yamllint disable-line rule:line-length - 'traefik.enable=true'
- 'traefik.http.routers.authelia_backend.rule=Host(`login.example.com`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/`)' # yamllint disable-line rule:line-length
- 'traefik.http.routers.authelia_backend.entrypoints=https' - 'traefik.http.routers.authelia_backend.entrypoints=https'
- 'traefik.http.routers.authelia_backend.tls=true' - 'traefik.http.routers.authelia_backend.tls=true'
- 'traefik.http.services.authelia_backend.loadbalancer.server.scheme=https' - 'traefik.http.services.authelia_backend.loadbalancer.server.scheme=https'
- 'traefik.http.services.authelia_backend.passHostHeader=true' healthcheck:
disable: true
volumes: volumes:
- '../..:/authelia' - '../..:/authelia'
environment: environment:

View File

@ -19,6 +19,7 @@ services:
# Traefik 1.x # Traefik 1.x
- 'traefik.frontend.rule=Host:login.example.com' - 'traefik.frontend.rule=Host:login.example.com'
# Traefik 2.x # Traefik 2.x
- 'traefik.enable=true'
- 'traefik.http.routers.authelia_frontend.rule=Host(`login.example.com`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/`)' # yamllint disable-line rule:line-length - 'traefik.http.routers.authelia_frontend.rule=Host(`login.example.com`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/`)' # yamllint disable-line rule:line-length
- 'traefik.http.routers.authelia_frontend.entrypoints=https' - 'traefik.http.routers.authelia_frontend.entrypoints=https'
- 'traefik.http.routers.authelia_frontend.tls=true' - 'traefik.http.routers.authelia_frontend.tls=true'

View File

@ -9,6 +9,7 @@ services:
# Traefik 1.x # Traefik 1.x
- 'traefik.frontend.rule=Host:login.example.com' - 'traefik.frontend.rule=Host:login.example.com'
# Traefik 2.x # Traefik 2.x
- 'traefik.enable=true'
- 'traefik.http.routers.authelia_frontend.rule=Host(`login.example.com`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/`)' # yamllint disable-line rule:line-length - 'traefik.http.routers.authelia_frontend.rule=Host(`login.example.com`) || Host(`login.example.com`) && PathPrefix(`${PathPrefix}/`)' # yamllint disable-line rule:line-length
- 'traefik.http.routers.authelia_frontend.entrypoints=https' - 'traefik.http.routers.authelia_frontend.entrypoints=https'
- 'traefik.http.routers.authelia_frontend.tls=true' - 'traefik.http.routers.authelia_frontend.tls=true'

View File

@ -73,7 +73,8 @@ backend be_authelia
server authelia-backend authelia-backend:9091 resolvers docker ssl verify none server authelia-backend authelia-backend:9091 resolvers docker ssl verify none
backend fe_authelia backend fe_authelia
server authelia-frontend authelia-frontend:3000 resolvers docker server authelia-frontend authelia-frontend:3000 check resolvers docker
server authelia-backend authelia-backend:9091 check backup resolvers docker ssl verify none
backend be_httpbin backend be_httpbin
acl remote_user_exist var(req.auth_response_header.remote_user) -m found acl remote_user_exist var(req.auth_response_header.remote_user) -m found

View File

@ -14,6 +14,7 @@ services:
- 'traefik.frontend.auth.forward.trustForwardHeader=true' - 'traefik.frontend.auth.forward.trustForwardHeader=true'
- 'traefik.frontend.auth.forward.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' - 'traefik.frontend.auth.forward.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email'
# Traefik 2.x # Traefik 2.x
- 'traefik.enable=true'
- 'traefik.http.routers.httpbin.rule=Host(`public.example.com`) && Path(`/headers`)' - 'traefik.http.routers.httpbin.rule=Host(`public.example.com`) && Path(`/headers`)'
- 'traefik.http.routers.httpbin.priority=150' - 'traefik.http.routers.httpbin.priority=150'
- 'traefik.http.routers.httpbin.tls=true' - 'traefik.http.routers.httpbin.tls=true'

View File

@ -11,6 +11,7 @@ services:
- 'traefik.frontend.auth.forward.trustForwardHeader=true' - 'traefik.frontend.auth.forward.trustForwardHeader=true'
- 'traefik.frontend.auth.forward.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email' - 'traefik.frontend.auth.forward.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email'
# Traefik 2.x # Traefik 2.x
- 'traefik.enable=true'
- 'traefik.http.routers.protectedapps.rule=Host(`home.example.com`,`public.example.com`,`secure.example.com`,`admin.example.com`,`singlefactor.example.com`)' # yamllint disable-line rule:line-length - 'traefik.http.routers.protectedapps.rule=Host(`home.example.com`,`public.example.com`,`secure.example.com`,`admin.example.com`,`singlefactor.example.com`)' # yamllint disable-line rule:line-length
- 'traefik.http.routers.protectedapps.entrypoints=https' - 'traefik.http.routers.protectedapps.entrypoints=https'
- 'traefik.http.routers.protectedapps.tls=true' - 'traefik.http.routers.protectedapps.tls=true'

View File

@ -11,6 +11,7 @@ services:
expose: expose:
- 8080 - 8080
labels: labels:
- 'traefik.enable=true'
- 'traefik.http.routers.oidc.rule=Host(`oidc.example.com`)' - 'traefik.http.routers.oidc.rule=Host(`oidc.example.com`)'
- 'traefik.http.routers.oidc.priority=150' - 'traefik.http.routers.oidc.priority=150'
- 'traefik.http.routers.oidc.tls=true' - 'traefik.http.routers.oidc.tls=true'

View File

@ -8,6 +8,7 @@ services:
labels: labels:
- 'traefik.frontend.rule=Host:mail.example.com' - 'traefik.frontend.rule=Host:mail.example.com'
- 'traefik.port=1080' - 'traefik.port=1080'
- 'traefik.enable=true'
- 'traefik.http.routers.mail.rule=Host(`mail.example.com`)' - 'traefik.http.routers.mail.rule=Host(`mail.example.com`)'
- 'traefik.http.routers.mail.entrypoints=https' - 'traefik.http.routers.mail.entrypoints=https'
- 'traefik.http.routers.mail.tls=true' - 'traefik.http.routers.mail.tls=true'

View File

@ -6,6 +6,7 @@ services:
volumes: volumes:
- '/var/run/docker.sock:/var/run/docker.sock' - '/var/run/docker.sock:/var/run/docker.sock'
labels: labels:
- 'traefik.enable=true'
- 'traefik.http.routers.api.rule=Host(`traefik.example.com`)' - 'traefik.http.routers.api.rule=Host(`traefik.example.com`)'
- 'traefik.http.routers.api.entrypoints=https' - 'traefik.http.routers.api.entrypoints=https'
- 'traefik.http.routers.api.service=api@internal' - 'traefik.http.routers.api.service=api@internal'
@ -16,13 +17,14 @@ services:
- 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true' - 'traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true'
- 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' # yamllint disable-line rule:line-length - 'traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' # yamllint disable-line rule:line-length
command: command:
- '--accesslog=true'
- '--api' - '--api'
- '--providers.docker=true' - '--providers.docker=true'
- '--entrypoints.https=true' - '--entrypoints.https=true'
- '--entrypoints.https.address=:8080' - '--entrypoints.https.address=:8080'
- '--log=true' - '--log=true'
- '--log.level=DEBUG' - '--log.level=DEBUG'
- '--log.filepath=/var/log/traefik.log' - '--providers.docker.exposedByDefault=false'
- '--serversTransport.insecureSkipVerify=true' - '--serversTransport.insecureSkipVerify=true'
networks: networks:
authelianet: authelianet:

View File

@ -2,6 +2,7 @@ package suites
import ( import (
"fmt" "fmt"
"os"
"time" "time"
) )
@ -19,6 +20,18 @@ func init() {
"internal/suites/example/compose/httpbin/docker-compose.yml", "internal/suites/example/compose/httpbin/docker-compose.yml",
}) })
if os.Getenv("CI") == t {
dockerEnvironment = NewDockerEnvironment([]string{
"internal/suites/docker-compose.yml",
"internal/suites/HAProxy/docker-compose.yml",
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
"internal/suites/example/compose/haproxy/docker-compose.yml",
"internal/suites/example/compose/smtp/docker-compose.yml",
"internal/suites/example/compose/httpbin/docker-compose.yml",
})
}
setup := func(suitePath string) error { setup := func(suitePath string) error {
if err := dockerEnvironment.Up(); err != nil { if err := dockerEnvironment.Up(); err != nil {
return err return err
@ -35,12 +48,14 @@ func init() {
fmt.Println(backendLogs) fmt.Println(backendLogs)
if os.Getenv("CI") != t {
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil) frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(frontendLogs) fmt.Println(frontendLogs)
}
haproxyLogs, err := dockerEnvironment.Logs("haproxy", nil) haproxyLogs, err := dockerEnvironment.Logs("haproxy", nil)
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@ package suites
import ( import (
"fmt" "fmt"
"os"
"time" "time"
) )
@ -20,6 +21,19 @@ func init() {
"internal/suites/example/compose/redis/docker-compose.yml", "internal/suites/example/compose/redis/docker-compose.yml",
}) })
if os.Getenv("CI") == t {
dockerEnvironment = NewDockerEnvironment([]string{
"internal/suites/docker-compose.yml",
"internal/suites/OIDCTraefik/docker-compose.yml",
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
"internal/suites/example/compose/traefik2/docker-compose.yml",
"internal/suites/example/compose/smtp/docker-compose.yml",
"internal/suites/example/compose/oidc-client/docker-compose.yml",
"internal/suites/example/compose/redis/docker-compose.yml",
})
}
setup := func(suitePath string) error { setup := func(suitePath string) error {
// TODO(c.michaud): use version in tags for oidc-client but in the meantime we pull the image to make sure it's // TODO(c.michaud): use version in tags for oidc-client but in the meantime we pull the image to make sure it's
// up to date. // up to date.
@ -46,12 +60,14 @@ func init() {
fmt.Println(backendLogs) fmt.Println(backendLogs)
if os.Getenv("CI") != t {
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil) frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(frontendLogs) fmt.Println(frontendLogs)
}
oidcClientLogs, err := dockerEnvironment.Logs("oidc-client", nil) oidcClientLogs, err := dockerEnvironment.Logs("oidc-client", nil)
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@ package suites
import ( import (
"fmt" "fmt"
"os"
"time" "time"
) )
@ -19,6 +20,18 @@ func init() {
"internal/suites/example/compose/httpbin/docker-compose.yml", "internal/suites/example/compose/httpbin/docker-compose.yml",
}) })
if os.Getenv("CI") == t {
dockerEnvironment = NewDockerEnvironment([]string{
"internal/suites/docker-compose.yml",
"internal/suites/PathPrefix/docker-compose.yml",
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
"internal/suites/example/compose/traefik2/docker-compose.yml",
"internal/suites/example/compose/smtp/docker-compose.yml",
"internal/suites/example/compose/httpbin/docker-compose.yml",
})
}
setup := func(suitePath string) error { setup := func(suitePath string) error {
if err := dockerEnvironment.Up(); err != nil { if err := dockerEnvironment.Up(); err != nil {
return err return err
@ -35,12 +48,14 @@ func init() {
fmt.Println(backendLogs) fmt.Println(backendLogs)
if os.Getenv("CI") != t {
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil) frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(frontendLogs) fmt.Println(frontendLogs)
}
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package suites
import ( import (
"fmt" "fmt"
"os"
"time" "time"
) )
@ -19,6 +20,18 @@ func init() {
"internal/suites/example/compose/httpbin/docker-compose.yml", "internal/suites/example/compose/httpbin/docker-compose.yml",
}) })
if os.Getenv("CI") == t {
dockerEnvironment = NewDockerEnvironment([]string{
"internal/suites/docker-compose.yml",
"internal/suites/Traefik/docker-compose.yml",
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
"internal/suites/example/compose/traefik/docker-compose.yml",
"internal/suites/example/compose/smtp/docker-compose.yml",
"internal/suites/example/compose/httpbin/docker-compose.yml",
})
}
setup := func(suitePath string) error { setup := func(suitePath string) error {
if err := dockerEnvironment.Up(); err != nil { if err := dockerEnvironment.Up(); err != nil {
return err return err
@ -35,12 +48,14 @@ func init() {
fmt.Println(backendLogs) fmt.Println(backendLogs)
if os.Getenv("CI") != t {
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil) frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(frontendLogs) fmt.Println(frontendLogs)
}
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package suites
import ( import (
"fmt" "fmt"
"os"
"time" "time"
) )
@ -20,6 +21,19 @@ var traefik2DockerEnvironment = NewDockerEnvironment([]string{
}) })
func init() { func init() {
if os.Getenv("CI") == t {
traefik2DockerEnvironment = NewDockerEnvironment([]string{
"internal/suites/docker-compose.yml",
"internal/suites/Traefik2/docker-compose.yml",
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
"internal/suites/example/compose/redis/docker-compose.yml",
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
"internal/suites/example/compose/traefik2/docker-compose.yml",
"internal/suites/example/compose/smtp/docker-compose.yml",
"internal/suites/example/compose/httpbin/docker-compose.yml",
})
}
setup := func(suitePath string) error { setup := func(suitePath string) error {
if err := traefik2DockerEnvironment.Up(); err != nil { if err := traefik2DockerEnvironment.Up(); err != nil {
return err return err
@ -36,12 +50,28 @@ func init() {
fmt.Println(backendLogs) fmt.Println(backendLogs)
if os.Getenv("CI") != t {
frontendLogs, err := traefik2DockerEnvironment.Logs("authelia-frontend", nil) frontendLogs, err := traefik2DockerEnvironment.Logs("authelia-frontend", nil)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(frontendLogs) fmt.Println(frontendLogs)
}
redisLogs, err := traefik2DockerEnvironment.Logs("redis", nil)
if err != nil {
return err
}
fmt.Println(redisLogs)
traefikLogs, err := traefik2DockerEnvironment.Logs("traefik", nil)
if err != nil {
return err
}
fmt.Println(traefikLogs)
return nil return nil
} }

View File

@ -1,10 +1,7 @@
package suites package suites
import ( import (
"context"
"fmt"
"testing" "testing"
"time"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
@ -29,35 +26,8 @@ func (s *Traefik2Suite) TestCustomHeaders() {
suite.Run(s.T(), NewCustomHeadersScenario()) suite.Run(s.T(), NewCustomHeadersScenario())
} }
func (s *Traefik2Suite) TestShouldKeepSessionAfterRedisRestart() { func (s *Traefik2Suite) TestResetPasswordScenario() {
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second) suite.Run(s.T(), NewResetPasswordScenario())
defer func() {
cancel()
s.collectCoverage(s.Page)
s.collectScreenshot(ctx.Err(), s.Page)
s.MustClose()
err := s.RodSession.Stop()
s.Require().NoError(err)
}()
browser, err := StartRod()
s.Require().NoError(err)
s.RodSession = browser
s.Page = s.doCreateTab(s.T(), HomeBaseURL)
s.verifyIsHome(s.T(), s.Page)
secret := s.doRegisterThenLogout(s.T(), s.Context(ctx), "john", "password")
s.doLoginTwoFactor(s.T(), s.Context(ctx), "john", "password", false, secret, "")
s.doVisit(s.T(), s.Context(ctx), fmt.Sprintf("%s/secret.html", SecureBaseURL))
s.verifySecretAuthorized(s.T(), s.Context(ctx))
err = traefik2DockerEnvironment.Restart("redis")
s.Require().NoError(err)
s.doVisit(s.T(), s.Context(ctx), fmt.Sprintf("%s/secret.html", SecureBaseURL))
s.verifySecretAuthorized(s.T(), s.Context(ctx))
} }
func TestTraefik2Suite(t *testing.T) { func TestTraefik2Suite(t *testing.T) {