//go:build integration // +build integration package test import ( "context" "net/http" "net/url" "strconv" "testing" "time" "github.com/oauth2-proxy/mockoidc" "github.com/playwright-community/playwright-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/network" "github.com/testcontainers/testcontainers-go/wait" "github.com/xlgmokha/x/pkg/env" "github.com/xlgmokha/x/pkg/x" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/oidc" ) type StdoutLogConsumer struct { t *testing.T } func (lc *StdoutLogConsumer) Accept(l testcontainers.Log) { lc.t.Logf("%s", l.Content) } func TestContainer(t *testing.T) { srv := oidc.NewTestServer(t) defer srv.Close() image := env.Fetch("IMAGE_TAG", "sparkled:invalid") require.NotEmpty(t, image) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() nw, err := network.New(ctx) require.NoError(t, err) defer func() { require.NoError(t, nw.Remove(ctx)) }() address, err := url.Parse(srv.MockOIDC.Addr()) require.NoError(t, err) t.Logf("mockoidc: %v %v\n", address.String(), srv.Issuer()) container, err := testcontainers.Run( ctx, image, network.WithNetwork([]string{"host"}, nw), testcontainers.WithEnv(map[string]string{ "APP_ENV": "test", "BIND_ADDR": ":8080", "DEBUG": env.Fetch("DEBUG", ""), "HMAC_SESSION_SECRET": "secret", "OAUTH_CLIENT_ID": srv.MockOIDC.Config().ClientID, "OAUTH_CLIENT_SECRET": srv.MockOIDC.Config().ClientSecret, "OAUTH_REDIRECT_URL": "", "OIDC_ISSUER": srv.Issuer(), }), testcontainers.WithHostPortAccess(x.Must(strconv.Atoi(address.Port()))), testcontainers.WithExposedPorts("8080/tcp", "9901/tcp", "10000/tcp"), testcontainers.WithLogConsumers(&StdoutLogConsumer{t: t}), testcontainers.WithWaitStrategy(wait.ForLog("Listening on").WithStartupTimeout(time.Second*5)), ) require.NoError(t, err) defer func() { require.NoError(t, testcontainers.TerminateContainer(container)) testcontainers.CleanupNetwork(t, nw) }() oidcProviderEndpoint := address.String() sparkleEndpoint, err := container.PortEndpoint(ctx, "8080", "http") require.NoError(t, err) envoyEndpoint, err := container.PortEndpoint(ctx, "10000", "http") require.NoError(t, err) paths := []string{ envoyEndpoint + "/", envoyEndpoint + "/health", oidcProviderEndpoint + mockoidc.DiscoveryEndpoint, sparkleEndpoint + "/", sparkleEndpoint + "/favicon.ico", sparkleEndpoint + "/health", } client := &http.Client{Timeout: 5 * time.Second} for _, path := range paths { t.Run(path, func(t *testing.T) { request, err := http.NewRequestWithContext(ctx, http.MethodGet, path, nil) response, err := client.Do(request) require.NoError(t, err) assert.Equal(t, http.StatusOK, response.StatusCode) }) } t.Run("UI", func(t *testing.T) { if env.Fetch("SKIP_E2E", "") != "" { t.Skip() } _ = playwright.Install() pw := x.Must(playwright.Run()) browser := x.Must(pw.Firefox.Launch(playwright.BrowserTypeLaunchOptions{ Headless: playwright.Bool(env.Fetch("HEADLESS", "true") == "true"), SlowMo: playwright.Float(1000), })) page := x.Must(browser.NewPage()) defer func() { x.Check(browser.Close()) x.Check(pw.Stop()) }() t.Run("initiates an OIDC login", func(t *testing.T) { require.NoError(t, page.Context().ClearCookies()) response, err := page.Goto(sparkleEndpoint + "/") require.NoError(t, err) assert.True(t, response.Ok()) }) }) }