test(suites): load environment into suites (#4762)

* test(suites): load environment into suites

* test(suites): default setup suite

* test(suites): create base suite

* test(suites): fix nil ptr

* test(suites): add logging

* test: fix missing devworkflow path

* refactor: apply suggestions

* refactor: log

* fix: dev workflow requires env file to trigger vite hmr

* fix(suites): fix dynamic configuration in dev workflow for all proxies

* refactor: apply final suggestions

* fix: pass log level to suites

* fix(suites): include pathprefix to prevent react router basename issues

* fix: missing setup logging calls

* fix: gate suite setup funcs

* test: fix lint

* test: fix tmp dir

* fix(suites): fix gitignore of .env.development with vite hmr

Co-authored-by: Amir Zarrinkafsh <nightah@me.com>
pull/4818/head
James Elliott 2023-01-25 15:11:05 +11:00 committed by GitHub
parent 74995264e2
commit 36e817df92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 285 additions and 99 deletions

View File

@ -348,6 +348,8 @@ func runSuiteTests(suiteName string, withEnv bool) error {
cmd.Env = append(cmd.Env, "HEADLESS=y") cmd.Env = append(cmd.Env, "HEADLESS=y")
} }
cmd.Env = append(cmd.Env, "SUITES_LOG_LEVEL="+log.GetLevel().String())
testErr := cmd.Run() testErr := cmd.Run()
// If the tests failed, run the error hook. // If the tests failed, run the error hook.

View File

@ -140,9 +140,7 @@ func setupSuite(cmd *cobra.Command, args []string) {
log.Fatal(err) log.Fatal(err)
} }
err = s.SetUp(suiteTmpDirectory) if err = s.SetUp(suiteTmpDirectory); err != nil {
if err != nil {
log.Error("Failure during environment deployment.") log.Error("Failure during environment deployment.")
teardownSuite(nil, args) teardownSuite(nil, args)
log.Fatal(err) log.Fatal(err)

View File

@ -2,7 +2,6 @@ package suites
import ( import (
"fmt" "fmt"
"os"
"github.com/authelia/authelia/v4/internal/configuration/schema" "github.com/authelia/authelia/v4/internal/configuration/schema"
) )
@ -14,9 +13,6 @@ var (
Example3DotCom = "example3.com:8080" Example3DotCom = "example3.com:8080"
) )
// PathPrefix the prefix/url_base of the login portal.
var PathPrefix = os.Getenv("PathPrefix")
// LoginBaseURLFmt the base URL of the login portal for specified baseDomain. // LoginBaseURLFmt the base URL of the login portal for specified baseDomain.
func LoginBaseURLFmt(baseDomain string) string { func LoginBaseURLFmt(baseDomain string) string {
if baseDomain == "" { if baseDomain == "" {
@ -81,6 +77,8 @@ const (
) )
const ( const (
envFileProd = "./web/.env.production"
envFileDev = "./web/.env.development"
namespaceAuthelia = "authelia" namespaceAuthelia = "authelia"
namespaceDashboard = "kubernetes-dashboard" namespaceDashboard = "kubernetes-dashboard"
namespaceKube = "kube-system" namespaceKube = "kube-system"

View File

@ -21,11 +21,11 @@ services:
- '${GOPATH}:/go' - '${GOPATH}:/go'
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;PathPrefix:/.well-known,/api,/locales,/devworkflow,/jwks.json'
- 'traefik.protocol=https' - 'traefik.protocol=https'
# Traefik 2.x # Traefik 2.x
- 'traefik.enable=true' - '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(`/devworkflow`) || Host(`login.example.com`) && Path(`${PathPrefix}/devworkflow`) || Host(`login.example.com`) && Path(`/jwks.json`) || Host(`login.example.com`) && Path(`${PathPrefix}/jwks.json`) || Host(`login.example.com`) && Path(`/static/media/logo.png`) || Host(`login.example.com`) && Path(`${PathPrefix}/static/media/logo.png`)' # 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'

View File

@ -29,6 +29,10 @@ login.example.com:8080 {
import tls-transport import tls-transport
} }
reverse_proxy /devworkflow authelia-backend:9091 {
import tls-transport
}
reverse_proxy /jwks.json authelia-backend:9091 { reverse_proxy /jwks.json authelia-backend:9091 {
import tls-transport import tls-transport
} }

View File

@ -40,6 +40,10 @@ static_resources:
prefix: "/locales/" prefix: "/locales/"
route: route:
cluster: authelia-backend cluster: authelia-backend
- match:
path: "/devworkflow"
route:
cluster: authelia-backend
- match: - match:
path: "/jwks.json" path: "/jwks.json"
route: route:

View File

@ -25,6 +25,10 @@ frontend fe_http
bind *:8080 ssl crt /usr/local/etc/haproxy/haproxy.pem bind *:8080 ssl crt /usr/local/etc/haproxy/haproxy.pem
acl api-path path_beg -i /api acl api-path path_beg -i /api
acl wellknown-path path_beg -i /.well-known
acl locales-path path_beg -i /locales
acl devworkflow-path path -i -m end /devworkflow
acl jwks-path path -i -m end /jwks.json
acl headers-path path -i -m end /headers acl headers-path path -i -m end /headers
acl host-authelia-portal hdr(host) -i login.example.com:8080 acl host-authelia-portal hdr(host) -i login.example.com:8080
acl protected-frontends hdr(host) -m reg -i ^(?i)(admin|home|public|secure|singlefactor)\.example\.com acl protected-frontends hdr(host) -m reg -i ^(?i)(admin|home|public|secure|singlefactor)\.example\.com
@ -54,18 +58,16 @@ frontend fe_http
http-request redirect location https://login.example.com:8080/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query] if protected-frontends !{ var(txn.auth_response_successful) -m bool } http-request redirect location https://login.example.com:8080/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query] if protected-frontends !{ var(txn.auth_response_successful) -m bool }
use_backend be_authelia if host-authelia-portal api-path use_backend be_authelia if host-authelia-portal api-path || wellknown-path || locales-path || devworkflow-path || jwks-path
use_backend fe_authelia if host-authelia-portal !api-path use_backend fe_authelia if host-authelia-portal !api-path
use_backend be_httpbin if protected-frontends headers-path use_backend be_httpbin if protected-frontends headers-path
use_backend be_mail if { hdr(host) -i mail.example.com:8080 } use_backend be_mail if { hdr(host) -i mail.example.com:8080 }
use_backend be_protected if protected-frontends use_backend be_protected if protected-frontends
backend be_auth_request backend be_auth_request
mode http
server proxy 127.0.0.1:8085 server proxy 127.0.0.1:8085
listen be_auth_request_proxy listen be_auth_request_proxy
mode http
bind 127.0.0.1:8085 bind 127.0.0.1:8085
server authelia-backend authelia-backend:9091 resolvers docker ssl verify none server authelia-backend authelia-backend:9091 resolvers docker ssl verify none
@ -73,6 +75,9 @@ 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
option httpchk
http-check expect rstatus ^2
server authelia-frontend authelia-frontend:3000 check resolvers docker server authelia-frontend authelia-frontend:3000 check resolvers docker
server authelia-backend authelia-backend:9091 check backup resolvers docker ssl verify none server authelia-backend authelia-backend:9091 check backup resolvers docker ssl verify none

View File

@ -16,7 +16,7 @@ type AvailableMethodsScenario struct {
func NewAvailableMethodsScenario(methods []string) *AvailableMethodsScenario { func NewAvailableMethodsScenario(methods []string) *AvailableMethodsScenario {
return &AvailableMethodsScenario{ return &AvailableMethodsScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
methods: methods, methods: methods,
} }
} }

View File

@ -16,7 +16,7 @@ type BypassPolicyScenario struct {
func NewBypassPolicyScenario() *BypassPolicyScenario { func NewBypassPolicyScenario() *BypassPolicyScenario {
return &BypassPolicyScenario{ return &BypassPolicyScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -19,7 +19,7 @@ type CustomHeadersScenario struct {
func NewCustomHeadersScenario() *CustomHeadersScenario { func NewCustomHeadersScenario() *CustomHeadersScenario {
return &CustomHeadersScenario{ return &CustomHeadersScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -18,7 +18,7 @@ type DefaultRedirectionURLScenario struct {
func NewDefaultRedirectionURLScenario() *DefaultRedirectionURLScenario { func NewDefaultRedirectionURLScenario() *DefaultRedirectionURLScenario {
return &DefaultRedirectionURLScenario{ return &DefaultRedirectionURLScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -18,7 +18,7 @@ type InactivityScenario struct {
func NewInactivityScenario() *InactivityScenario { func NewInactivityScenario() *InactivityScenario {
return &InactivityScenario{ return &InactivityScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -19,7 +19,7 @@ type MultiCookieDomainScenario struct {
// NewMultiCookieDomainScenario returns a new Multi Cookie Domain Test Scenario. // NewMultiCookieDomainScenario returns a new Multi Cookie Domain Test Scenario.
func NewMultiCookieDomainScenario(domain, nextDomain string, remember bool) *MultiCookieDomainScenario { func NewMultiCookieDomainScenario(domain, nextDomain string, remember bool) *MultiCookieDomainScenario {
return &MultiCookieDomainScenario{ return &MultiCookieDomainScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
domain: domain, domain: domain,
nextDomain: nextDomain, nextDomain: nextDomain,
remember: remember, remember: remember,

View File

@ -22,7 +22,7 @@ type OIDCScenario struct {
func NewOIDCScenario() *OIDCScenario { func NewOIDCScenario() *OIDCScenario {
return &OIDCScenario{ return &OIDCScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -16,7 +16,7 @@ type OneFactorSuite struct {
func New1FAScenario() *OneFactorSuite { func New1FAScenario() *OneFactorSuite {
return &OneFactorSuite{ return &OneFactorSuite{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }
@ -49,7 +49,7 @@ func (s *OneFactorSuite) TearDownTest() {
} }
func (s *OneFactorSuite) TestShouldAuthorizeSecretAfterOneFactor() { func (s *OneFactorSuite) TestShouldAuthorizeSecretAfterOneFactor() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer func() { defer func() {
cancel() cancel()
s.collectScreenshot(ctx.Err(), s.Page) s.collectScreenshot(ctx.Err(), s.Page)

View File

@ -14,7 +14,7 @@ type PasswordComplexityScenario struct {
} }
func NewPasswordComplexityScenario() *PasswordComplexityScenario { func NewPasswordComplexityScenario() *PasswordComplexityScenario {
return &PasswordComplexityScenario{RodSuite: new(RodSuite)} return &PasswordComplexityScenario{RodSuite: NewRodSuite("")}
} }
func (s *PasswordComplexityScenario) SetupSuite() { func (s *PasswordComplexityScenario) SetupSuite() {

View File

@ -15,7 +15,7 @@ type RedirectionCheckScenario struct {
func NewRedirectionCheckScenario() *RedirectionCheckScenario { func NewRedirectionCheckScenario() *RedirectionCheckScenario {
return &RedirectionCheckScenario{ return &RedirectionCheckScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -16,7 +16,7 @@ type RedirectionURLScenario struct {
func NewRedirectionURLScenario() *RedirectionURLScenario { func NewRedirectionURLScenario() *RedirectionURLScenario {
return &RedirectionURLScenario{ return &RedirectionURLScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -16,7 +16,7 @@ type RegulationScenario struct {
func NewRegulationScenario() *RegulationScenario { func NewRegulationScenario() *RegulationScenario {
return &RegulationScenario{ return &RegulationScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -14,7 +14,7 @@ type ResetPasswordScenario struct {
} }
func NewResetPasswordScenario() *ResetPasswordScenario { func NewResetPasswordScenario() *ResetPasswordScenario {
return &ResetPasswordScenario{RodSuite: new(RodSuite)} return &ResetPasswordScenario{RodSuite: NewRodSuite("")}
} }
func (s *ResetPasswordScenario) SetupSuite() { func (s *ResetPasswordScenario) SetupSuite() {

View File

@ -18,7 +18,7 @@ type SigninEmailScenario struct {
func NewSigninEmailScenario() *SigninEmailScenario { func NewSigninEmailScenario() *SigninEmailScenario {
return &SigninEmailScenario{ return &SigninEmailScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -18,7 +18,7 @@ type TwoFactorSuite struct {
func New2FAScenario() *TwoFactorSuite { func New2FAScenario() *TwoFactorSuite {
return &TwoFactorSuite{ return &TwoFactorSuite{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -15,7 +15,7 @@ type UserPreferencesScenario struct {
func NewUserPreferencesScenario() *UserPreferencesScenario { func NewUserPreferencesScenario() *UserPreferencesScenario {
return &UserPreferencesScenario{ return &UserPreferencesScenario{
RodSuite: new(RodSuite), RodSuite: NewRodSuite(""),
} }
} }

View File

@ -11,7 +11,9 @@ type ActiveDirectorySuite struct {
} }
func NewActiveDirectorySuite() *ActiveDirectorySuite { func NewActiveDirectorySuite() *ActiveDirectorySuite {
return &ActiveDirectorySuite{RodSuite: new(RodSuite)} return &ActiveDirectorySuite{
RodSuite: NewRodSuite(activedirectorySuiteName),
}
} }
func (s *ActiveDirectorySuite) Test1FAScenario() { func (s *ActiveDirectorySuite) Test1FAScenario() {

View File

@ -15,10 +15,14 @@ type BypassAllWebDriverSuite struct {
} }
func NewBypassAllWebDriverSuite() *BypassAllWebDriverSuite { func NewBypassAllWebDriverSuite() *BypassAllWebDriverSuite {
return &BypassAllWebDriverSuite{RodSuite: new(RodSuite)} return &BypassAllWebDriverSuite{
RodSuite: NewRodSuite(""),
}
} }
func (s *BypassAllWebDriverSuite) SetupSuite() { func (s *BypassAllWebDriverSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
browser, err := StartRod() browser, err := StartRod()
if err != nil { if err != nil {
@ -61,11 +65,15 @@ func (s *BypassAllWebDriverSuite) TestShouldAccessPublicResource() {
} }
type BypassAllSuite struct { type BypassAllSuite struct {
suite.Suite *BaseSuite
} }
func NewBypassAllSuite() *BypassAllSuite { func NewBypassAllSuite() *BypassAllSuite {
return &BypassAllSuite{} return &BypassAllSuite{
BaseSuite: &BaseSuite{
Name: bypassAllSuiteName,
},
}
} }
func (s *BypassAllSuite) TestBypassAllWebDriverSuite() { func (s *BypassAllSuite) TestBypassAllWebDriverSuite() {

View File

@ -11,7 +11,9 @@ type CaddySuite struct {
} }
func NewCaddySuite() *CaddySuite { func NewCaddySuite() *CaddySuite {
return &CaddySuite{RodSuite: new(RodSuite)} return &CaddySuite{
RodSuite: NewRodSuite(caddySuiteName),
}
} }
func (s *CaddySuite) Test1FAScenario() { func (s *CaddySuite) Test1FAScenario() {

View File

@ -23,10 +23,18 @@ type CLISuite struct {
} }
func NewCLISuite() *CLISuite { func NewCLISuite() *CLISuite {
return &CLISuite{CommandSuite: new(CommandSuite)} return &CLISuite{
CommandSuite: &CommandSuite{
BaseSuite: &BaseSuite{
Name: cliSuiteName,
},
},
}
} }
func (s *CLISuite) SetupSuite() { func (s *CLISuite) SetupSuite() {
s.BaseSuite.SetupSuite()
dockerEnvironment := NewDockerEnvironment([]string{ dockerEnvironment := NewDockerEnvironment([]string{
"internal/suites/docker-compose.yml", "internal/suites/docker-compose.yml",
"internal/suites/CLI/docker-compose.yml", "internal/suites/CLI/docker-compose.yml",

View File

@ -11,7 +11,9 @@ type DockerSuite struct {
} }
func NewDockerSuite() *DockerSuite { func NewDockerSuite() *DockerSuite {
return &DockerSuite{RodSuite: new(RodSuite)} return &DockerSuite{
RodSuite: NewRodSuite(dockerSuiteName),
}
} }
func (s *DockerSuite) Test1FAScenario() { func (s *DockerSuite) Test1FAScenario() {

View File

@ -20,7 +20,9 @@ type DuoPushWebDriverSuite struct {
} }
func NewDuoPushWebDriverSuite() *DuoPushWebDriverSuite { func NewDuoPushWebDriverSuite() *DuoPushWebDriverSuite {
return &DuoPushWebDriverSuite{RodSuite: new(RodSuite)} return &DuoPushWebDriverSuite{
RodSuite: NewRodSuite(""),
}
} }
func (s *DuoPushWebDriverSuite) SetupSuite() { func (s *DuoPushWebDriverSuite) SetupSuite() {
@ -386,10 +388,12 @@ type DuoPushDefaultRedirectionSuite struct {
} }
func NewDuoPushDefaultRedirectionSuite() *DuoPushDefaultRedirectionSuite { func NewDuoPushDefaultRedirectionSuite() *DuoPushDefaultRedirectionSuite {
return &DuoPushDefaultRedirectionSuite{RodSuite: new(RodSuite)} return &DuoPushDefaultRedirectionSuite{RodSuite: NewRodSuite(duoPushSuiteName)}
} }
func (s *DuoPushDefaultRedirectionSuite) SetupSuite() { func (s *DuoPushDefaultRedirectionSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
browser, err := StartRod() browser, err := StartRod()
if err != nil { if err != nil {
@ -444,11 +448,15 @@ func (s *DuoPushDefaultRedirectionSuite) TestUserIsRedirectedToDefaultURL() {
} }
type DuoPushSuite struct { type DuoPushSuite struct {
suite.Suite *BaseSuite
} }
func NewDuoPushSuite() *DuoPushSuite { func NewDuoPushSuite() *DuoPushSuite {
return &DuoPushSuite{} return &DuoPushSuite{
BaseSuite: &BaseSuite{
Name: duoPushSuiteName,
},
}
} }
func (s *DuoPushSuite) TestDuoPushWebDriverSuite() { func (s *DuoPushSuite) TestDuoPushWebDriverSuite() {

View File

@ -11,7 +11,9 @@ type EnvoySuite struct {
} }
func NewEnvoySuite() *EnvoySuite { func NewEnvoySuite() *EnvoySuite {
return &EnvoySuite{RodSuite: new(RodSuite)} return &EnvoySuite{
RodSuite: NewRodSuite(envoySuiteName),
}
} }
func (s *EnvoySuite) Test1FAScenario() { func (s *EnvoySuite) Test1FAScenario() {

View File

@ -11,7 +11,9 @@ type HAProxySuite struct {
} }
func NewHAProxySuite() *HAProxySuite { func NewHAProxySuite() *HAProxySuite {
return &HAProxySuite{RodSuite: new(RodSuite)} return &HAProxySuite{
RodSuite: NewRodSuite(haproxySuiteName),
}
} }
func (s *HAProxySuite) Test1FAScenario() { func (s *HAProxySuite) Test1FAScenario() {

View File

@ -17,10 +17,14 @@ type HighAvailabilityWebDriverSuite struct {
} }
func NewHighAvailabilityWebDriverSuite() *HighAvailabilityWebDriverSuite { func NewHighAvailabilityWebDriverSuite() *HighAvailabilityWebDriverSuite {
return &HighAvailabilityWebDriverSuite{RodSuite: new(RodSuite)} return &HighAvailabilityWebDriverSuite{
RodSuite: NewRodSuite(""),
}
} }
func (s *HighAvailabilityWebDriverSuite) SetupSuite() { func (s *HighAvailabilityWebDriverSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
browser, err := StartRod() browser, err := StartRod()
if err != nil { if err != nil {
@ -183,7 +187,9 @@ func (s *HighAvailabilityWebDriverSuite) TestShouldKeepSessionAfterAutheliaResta
} }
var UserJohn = "john" var UserJohn = "john"
var UserBob = "bob" var UserBob = "bob"
var UserHarry = "harry" var UserHarry = "harry"
var Users = []string{UserJohn, UserBob, UserHarry} var Users = []string{UserJohn, UserBob, UserHarry}
@ -263,11 +269,15 @@ func (s *HighAvailabilityWebDriverSuite) TestShouldVerifyAccessControl() {
} }
type HighAvailabilitySuite struct { type HighAvailabilitySuite struct {
suite.Suite *BaseSuite
} }
func NewHighAvailabilitySuite() *HighAvailabilitySuite { func NewHighAvailabilitySuite() *HighAvailabilitySuite {
return &HighAvailabilitySuite{} return &HighAvailabilitySuite{
BaseSuite: &BaseSuite{
Name: highAvailabilitySuiteName,
},
}
} }
func DoGetWithAuth(t *testing.T, username, password string) int { func DoGetWithAuth(t *testing.T, username, password string) int {

View File

@ -11,7 +11,9 @@ type KubernetesSuite struct {
} }
func NewKubernetesSuite() *KubernetesSuite { func NewKubernetesSuite() *KubernetesSuite {
return &KubernetesSuite{RodSuite: new(RodSuite)} return &KubernetesSuite{
RodSuite: NewRodSuite(kubernetesSuiteName),
}
} }
func (s *KubernetesSuite) Test1FAScenario() { func (s *KubernetesSuite) Test1FAScenario() {

View File

@ -11,7 +11,9 @@ type LDAPSuite struct {
} }
func NewLDAPSuite() *LDAPSuite { func NewLDAPSuite() *LDAPSuite {
return &LDAPSuite{RodSuite: new(RodSuite)} return &LDAPSuite{
RodSuite: NewRodSuite(ldapSuiteName),
}
} }
func (s *LDAPSuite) Test1FAScenario() { func (s *LDAPSuite) Test1FAScenario() {

View File

@ -11,7 +11,9 @@ type MariaDBSuite struct {
} }
func NewMariaDBSuite() *MariaDBSuite { func NewMariaDBSuite() *MariaDBSuite {
return &MariaDBSuite{RodSuite: new(RodSuite)} return &MariaDBSuite{
RodSuite: NewRodSuite(mariadbSuiteName),
}
} }
func (s *MariaDBSuite) Test1FAScenario() { func (s *MariaDBSuite) Test1FAScenario() {

View File

@ -7,11 +7,15 @@ import (
) )
func NewMultiCookieDomainSuite() *MultiCookieDomainSuite { func NewMultiCookieDomainSuite() *MultiCookieDomainSuite {
return &MultiCookieDomainSuite{} return &MultiCookieDomainSuite{
BaseSuite: &BaseSuite{
Name: multiCookieDomainSuiteName,
},
}
} }
type MultiCookieDomainSuite struct { type MultiCookieDomainSuite struct {
suite.Suite *BaseSuite
} }
func (s *MultiCookieDomainSuite) TestMultiCookieDomainFirstDomainScenario() { func (s *MultiCookieDomainSuite) TestMultiCookieDomainFirstDomainScenario() {

View File

@ -11,7 +11,9 @@ type MySQLSuite struct {
} }
func NewMySQLSuite() *MySQLSuite { func NewMySQLSuite() *MySQLSuite {
return &MySQLSuite{RodSuite: new(RodSuite)} return &MySQLSuite{
RodSuite: NewRodSuite(mysqlSuiteName),
}
} }
func (s *MySQLSuite) Test1FAScenario() { func (s *MySQLSuite) Test1FAScenario() {

View File

@ -10,11 +10,15 @@ import (
) )
type NetworkACLSuite struct { type NetworkACLSuite struct {
suite.Suite *BaseSuite
} }
func NewNetworkACLSuite() *NetworkACLSuite { func NewNetworkACLSuite() *NetworkACLSuite {
return &NetworkACLSuite{} return &NetworkACLSuite{
BaseSuite: &BaseSuite{
Name: networkACLSuiteName,
},
}
} }
func (s *NetworkACLSuite) TestShouldAccessSecretUpon2FA() { func (s *NetworkACLSuite) TestShouldAccessSecretUpon2FA() {

View File

@ -11,7 +11,9 @@ type OIDCSuite struct {
} }
func NewOIDCSuite() *OIDCSuite { func NewOIDCSuite() *OIDCSuite {
return &OIDCSuite{RodSuite: new(RodSuite)} return &OIDCSuite{
RodSuite: NewRodSuite(oidcSuiteName),
}
} }
func (s *OIDCSuite) TestOIDCScenario() { func (s *OIDCSuite) TestOIDCScenario() {

View File

@ -11,7 +11,9 @@ type OIDCTraefikSuite struct {
} }
func NewOIDCTraefikSuite() *OIDCTraefikSuite { func NewOIDCTraefikSuite() *OIDCTraefikSuite {
return &OIDCTraefikSuite{RodSuite: new(RodSuite)} return &OIDCTraefikSuite{
RodSuite: NewRodSuite(oidcTraefikSuiteName),
}
} }
func (s *OIDCTraefikSuite) TestOIDCScenario() { func (s *OIDCTraefikSuite) TestOIDCScenario() {

View File

@ -11,18 +11,18 @@ import (
) )
type OneFactorOnlySuite struct { type OneFactorOnlySuite struct {
suite.Suite
}
type OneFactorOnlyWebSuite struct {
*RodSuite *RodSuite
} }
func NewOneFactorOnlyWebSuite() *OneFactorOnlyWebSuite { func NewOneFactorOnlySuite() *OneFactorOnlySuite {
return &OneFactorOnlyWebSuite{RodSuite: new(RodSuite)} return &OneFactorOnlySuite{
RodSuite: NewRodSuite(oneFactorOnlySuiteName),
}
} }
func (s *OneFactorOnlyWebSuite) SetupSuite() { func (s *OneFactorOnlySuite) SetupSuite() {
s.BaseSuite.SetupSuite()
browser, err := StartRod() browser, err := StartRod()
if err != nil { if err != nil {
@ -32,7 +32,7 @@ func (s *OneFactorOnlyWebSuite) SetupSuite() {
s.RodSession = browser s.RodSession = browser
} }
func (s *OneFactorOnlyWebSuite) TearDownSuite() { func (s *OneFactorOnlySuite) TearDownSuite() {
err := s.RodSession.Stop() err := s.RodSession.Stop()
if err != nil { if err != nil {
@ -40,18 +40,18 @@ func (s *OneFactorOnlyWebSuite) TearDownSuite() {
} }
} }
func (s *OneFactorOnlyWebSuite) SetupTest() { func (s *OneFactorOnlySuite) SetupTest() {
s.Page = s.doCreateTab(s.T(), HomeBaseURL) s.Page = s.doCreateTab(s.T(), HomeBaseURL)
s.verifyIsHome(s.T(), s.Page) s.verifyIsHome(s.T(), s.Page)
} }
func (s *OneFactorOnlyWebSuite) TearDownTest() { func (s *OneFactorOnlySuite) TearDownTest() {
s.collectCoverage(s.Page) s.collectCoverage(s.Page)
s.MustClose() s.MustClose()
} }
// No target url is provided, then the user should be redirect to the default url. // No target url is provided, then the user should be redirect to the default url.
func (s *OneFactorOnlyWebSuite) TestShouldRedirectUserToDefaultURL() { func (s *OneFactorOnlySuite) TestShouldRedirectUserToDefaultURL() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer func() { defer func() {
cancel() cancel()
@ -63,7 +63,7 @@ func (s *OneFactorOnlyWebSuite) TestShouldRedirectUserToDefaultURL() {
} }
// Unsafe URL is provided, then the user should be redirect to the default url. // Unsafe URL is provided, then the user should be redirect to the default url.
func (s *OneFactorOnlyWebSuite) TestShouldRedirectUserToDefaultURLWhenURLIsUnsafe() { func (s *OneFactorOnlySuite) TestShouldRedirectUserToDefaultURLWhenURLIsUnsafe() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer func() { defer func() {
cancel() cancel()
@ -75,7 +75,7 @@ func (s *OneFactorOnlyWebSuite) TestShouldRedirectUserToDefaultURLWhenURLIsUnsaf
} }
// When use logged in and visit the portal again, she gets redirect to the authenticated view. // When use logged in and visit the portal again, she gets redirect to the authenticated view.
func (s *OneFactorOnlyWebSuite) TestShouldDisplayAuthenticatedView() { func (s *OneFactorOnlySuite) TestShouldDisplayAuthenticatedView() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer func() { defer func() {
cancel() cancel()
@ -88,7 +88,7 @@ func (s *OneFactorOnlyWebSuite) TestShouldDisplayAuthenticatedView() {
s.verifyIsAuthenticatedPage(s.T(), s.Context(ctx)) s.verifyIsAuthenticatedPage(s.T(), s.Context(ctx))
} }
func (s *OneFactorOnlyWebSuite) TestShouldRedirectAlreadyAuthenticatedUser() { func (s *OneFactorOnlySuite) TestShouldRedirectAlreadyAuthenticatedUser() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer func() { defer func() {
cancel() cancel()
@ -103,7 +103,7 @@ func (s *OneFactorOnlyWebSuite) TestShouldRedirectAlreadyAuthenticatedUser() {
s.verifyURLIs(s.T(), s.Context(ctx), "https://singlefactor.example.com:8080/secret.html") s.verifyURLIs(s.T(), s.Context(ctx), "https://singlefactor.example.com:8080/secret.html")
} }
func (s *OneFactorOnlyWebSuite) TestShouldNotRedirectAlreadyAuthenticatedUserToUnsafeURL() { func (s *OneFactorOnlySuite) TestShouldNotRedirectAlreadyAuthenticatedUserToUnsafeURL() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer func() { defer func() {
cancel() cancel()
@ -118,14 +118,10 @@ func (s *OneFactorOnlyWebSuite) TestShouldNotRedirectAlreadyAuthenticatedUserToU
s.verifyNotificationDisplayed(s.T(), s.Context(ctx), "Redirection was determined to be unsafe and aborted. Ensure the redirection URL is correct.") s.verifyNotificationDisplayed(s.T(), s.Context(ctx), "Redirection was determined to be unsafe and aborted. Ensure the redirection URL is correct.")
} }
func (s *OneFactorOnlySuite) TestWeb() {
suite.Run(s.T(), NewOneFactorOnlyWebSuite())
}
func TestOneFactorOnlySuite(t *testing.T) { func TestOneFactorOnlySuite(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("skipping suite test in short mode") t.Skip("skipping suite test in short mode")
} }
suite.Run(t, new(OneFactorOnlySuite)) suite.Run(t, NewOneFactorOnlySuite())
} }

View File

@ -11,7 +11,9 @@ type PathPrefixSuite struct {
} }
func NewPathPrefixSuite() *PathPrefixSuite { func NewPathPrefixSuite() *PathPrefixSuite {
return &PathPrefixSuite{RodSuite: new(RodSuite)} return &PathPrefixSuite{
RodSuite: NewRodSuite(pathPrefixSuiteName),
}
} }
func (s *PathPrefixSuite) Test1FAScenario() { func (s *PathPrefixSuite) Test1FAScenario() {

View File

@ -11,7 +11,9 @@ type PostgresSuite struct {
} }
func NewPostgresSuite() *PostgresSuite { func NewPostgresSuite() *PostgresSuite {
return &PostgresSuite{RodSuite: new(RodSuite)} return &PostgresSuite{
RodSuite: NewRodSuite(postgresSuiteName),
}
} }
func (s *PostgresSuite) Test1FAScenario() { func (s *PostgresSuite) Test1FAScenario() {

View File

@ -11,7 +11,9 @@ type ShortTimeoutsSuite struct {
} }
func NewShortTimeoutsSuite() *ShortTimeoutsSuite { func NewShortTimeoutsSuite() *ShortTimeoutsSuite {
return &ShortTimeoutsSuite{RodSuite: new(RodSuite)} return &ShortTimeoutsSuite{
RodSuite: NewRodSuite(shortTimeoutsSuiteName),
}
} }
func (s *ShortTimeoutsSuite) TestDefaultRedirectionURLScenario() { func (s *ShortTimeoutsSuite) TestDefaultRedirectionURLScenario() {

View File

@ -22,10 +22,14 @@ type StandaloneWebDriverSuite struct {
} }
func NewStandaloneWebDriverSuite() *StandaloneWebDriverSuite { func NewStandaloneWebDriverSuite() *StandaloneWebDriverSuite {
return &StandaloneWebDriverSuite{RodSuite: new(RodSuite)} return &StandaloneWebDriverSuite{
RodSuite: NewRodSuite(""),
}
} }
func (s *StandaloneWebDriverSuite) SetupSuite() { func (s *StandaloneWebDriverSuite) SetupSuite() {
s.BaseSuite.SetupSuite()
browser, err := StartRod() browser, err := StartRod()
if err != nil { if err != nil {
@ -169,11 +173,15 @@ func (s *StandaloneWebDriverSuite) TestShouldCheckUserIsAskedToRegisterDevice()
} }
type StandaloneSuite struct { type StandaloneSuite struct {
suite.Suite *BaseSuite
} }
func NewStandaloneSuite() *StandaloneSuite { func NewStandaloneSuite() *StandaloneSuite {
return &StandaloneSuite{} return &StandaloneSuite{
BaseSuite: &BaseSuite{
Name: standaloneSuiteName,
},
}
} }
func (s *StandaloneSuite) TestShouldRespectMethodsACL() { func (s *StandaloneSuite) TestShouldRespectMethodsACL() {

View File

@ -14,7 +14,9 @@ type Traefik2Suite struct {
} }
func NewTraefik2Suite() *Traefik2Suite { func NewTraefik2Suite() *Traefik2Suite {
return &Traefik2Suite{RodSuite: new(RodSuite)} return &Traefik2Suite{
RodSuite: NewRodSuite(traefik2SuiteName),
}
} }
func (s *Traefik2Suite) Test1FAScenario() { func (s *Traefik2Suite) Test1FAScenario() {

View File

@ -11,7 +11,9 @@ type TraefikSuite struct {
} }
func NewTraefikSuite() *TraefikSuite { func NewTraefikSuite() *TraefikSuite {
return &TraefikSuite{RodSuite: new(RodSuite)} return &TraefikSuite{
RodSuite: NewRodSuite(traefikSuiteName),
}
} }
func (s *TraefikSuite) Test1FAScenario() { func (s *TraefikSuite) Test1FAScenario() {

View File

@ -5,17 +5,31 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
) )
func NewRodSuite(name string) *RodSuite {
return &RodSuite{
BaseSuite: &BaseSuite{
Name: name,
},
}
}
// RodSuite is a go-rod suite. // RodSuite is a go-rod suite.
type RodSuite struct { type RodSuite struct {
suite.Suite *BaseSuite
*RodSession *RodSession
*rod.Page *rod.Page
} }
type BaseSuite struct {
suite.Suite
Name string
}
// CommandSuite is a command line interface suite. // CommandSuite is a command line interface suite.
type CommandSuite struct { type CommandSuite struct {
suite.Suite *BaseSuite
testArg string //nolint:structcheck // TODO: Remove when bug fixed: https://github.com/golangci/golangci-lint/issues/537. testArg string //nolint:structcheck // TODO: Remove when bug fixed: https://github.com/golangci/golangci-lint/issues/537.
coverageArg string //nolint:structcheck // TODO: Remove when bug fixed: https://github.com/golangci/golangci-lint/issues/537. coverageArg string //nolint:structcheck // TODO: Remove when bug fixed: https://github.com/golangci/golangci-lint/issues/537.

View File

@ -1,12 +1,12 @@
package suites package suites
import ( import (
"bufio"
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -16,6 +16,7 @@ import (
"github.com/go-rod/rod" "github.com/go-rod/rod"
"github.com/google/uuid" "github.com/google/uuid"
log "github.com/sirupsen/logrus"
) )
var browserPaths = []string{"/usr/bin/chromium-browser", "/usr/bin/chromium"} var browserPaths = []string{"/usr/bin/chromium-browser", "/usr/bin/chromium"}
@ -52,8 +53,8 @@ func GetBrowserPath() (path string, err error) {
// GetLoginBaseURL returns the URL of the login portal and the path prefix if specified. // GetLoginBaseURL returns the URL of the login portal and the path prefix if specified.
func GetLoginBaseURL(baseDomain string) string { func GetLoginBaseURL(baseDomain string) string {
if PathPrefix != "" { if pathPrefix := os.Getenv("PathPrefix"); pathPrefix != "" {
return LoginBaseURLFmt(baseDomain) + PathPrefix return LoginBaseURLFmt(baseDomain) + pathPrefix
} }
return LoginBaseURLFmt(baseDomain) return LoginBaseURLFmt(baseDomain)
@ -84,6 +85,87 @@ func (rs *RodSession) collectCoverage(page *rod.Page) {
} }
} }
func (s *BaseSuite) SetupSuite() {
s.SetupLogging()
s.SetupEnvironment()
}
func (s *BaseSuite) SetupLogging() {
if os.Getenv("SUITE_SETUP_LOGGING") == t {
return
}
var (
level string
ok bool
)
if level, ok = os.LookupEnv("SUITES_LOG_LEVEL"); !ok {
return
}
l, err := log.ParseLevel(level)
s.NoError(err)
log.SetLevel(l)
log.SetFormatter(&log.TextFormatter{
ForceColors: true,
})
s.T().Setenv("SUITE_SETUP_LOGGING", t)
}
func (s *BaseSuite) SetupEnvironment() {
if s.Name == "" || os.Getenv("SUITE_SETUP_ENVIRONMENT") == t {
return
}
log.Debugf("Checking Suite %s for .env file", s.Name)
path := filepath.Join(s.Name, ".env")
var (
info os.FileInfo
err error
)
path, err = filepath.Abs(path)
s.Require().NoError(err)
if info, err = os.Stat(path); err != nil {
s.Assert().True(os.IsNotExist(err))
log.Debugf("Suite %s does not have an .env file or it can't be read: %v", s.Name, err)
return
}
s.Require().False(info.IsDir())
log.Debugf("Suite %s does have an .env file at path: %s", s.Name, path)
var file *os.File
file, err = os.Open(path)
s.Require().NoError(err)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
v := strings.Split(scanner.Text(), "=")
s.Require().Len(v, 2)
s.T().Setenv(v[0], v[1])
}
s.T().Setenv("SUITE_SETUP_ENVIRONMENT", t)
}
func (rs *RodSession) collectScreenshot(err error, page *rod.Page) { func (rs *RodSession) collectScreenshot(err error, page *rod.Page) {
if err == context.DeadlineExceeded && os.Getenv("CI") == t { if err == context.DeadlineExceeded && os.Getenv("CI") == t {
base := "/buildkite/screenshots" base := "/buildkite/screenshots"
@ -140,7 +222,7 @@ func fixCoveragePath(path string, file os.FileInfo, err error) error {
} }
// getEnvInfoFromURL gets environments variables for specified cookie domain // getEnvInfoFromURL gets environments variables for specified cookie domain
// this func makes a http call to https://login.<domain>/override and is only useful for suite tests. // this func makes a http call to https://login.<domain>/devworkflow and is only useful for suite tests.
func getDomainEnvInfo(domain string) (map[string]string, error) { func getDomainEnvInfo(domain string) (map[string]string, error) {
info := make(map[string]string) info := make(map[string]string)
@ -186,18 +268,12 @@ func getDomainEnvInfo(domain string) (map[string]string, error) {
// generateDevEnvFile generates web/.env.development based on opts. // generateDevEnvFile generates web/.env.development based on opts.
func generateDevEnvFile(opts map[string]string) error { func generateDevEnvFile(opts map[string]string) error {
wd, _ := os.Getwd() tmpl, err := template.ParseFiles(envFileProd)
path := strings.TrimSuffix(wd, "internal/suites")
src := fmt.Sprintf("%s/web/.env.production", path)
dst := fmt.Sprintf("%s/web/.env.development", path)
tmpl, err := template.ParseFiles(src)
if err != nil { if err != nil {
return err return err
} }
file, _ := os.Create(dst) file, _ := os.Create(envFileDev)
defer file.Close() defer file.Close()
if err := tmpl.Execute(file, opts); err != nil { if err := tmpl.Execute(file, opts); err != nil {
@ -210,10 +286,15 @@ func generateDevEnvFile(opts map[string]string) error {
// updateDevEnvFileForDomain updates web/.env.development. // updateDevEnvFileForDomain updates web/.env.development.
// this function only affects local dev environments. // this function only affects local dev environments.
func updateDevEnvFileForDomain(domain string, setup bool) error { func updateDevEnvFileForDomain(domain string, setup bool) error {
if os.Getenv("CI") == "true" { if os.Getenv("CI") == t {
return nil return nil
} }
if _, err := os.Stat(envFileDev); err != nil && os.IsNotExist(err) {
file, _ := os.Create(envFileDev)
file.Close()
}
info, err := getDomainEnvInfo(domain) info, err := getDomainEnvInfo(domain)
if err != nil { if err != nil {
return err return err

View File

@ -36,7 +36,9 @@ func TestShouldReturnErrWhenX509DirectoryNotExist(t *testing.T) {
} }
func TestShouldNotReturnErrWhenX509DirectoryExist(t *testing.T) { func TestShouldNotReturnErrWhenX509DirectoryExist(t *testing.T) {
pool, warnings, errors := NewX509CertPool("/tmp") dir := t.TempDir()
pool, warnings, errors := NewX509CertPool(dir)
assert.NotNil(t, pool) assert.NotNil(t, pool)
if runtime.GOOS == windows { if runtime.GOOS == windows {