forgejo/tests/e2e/utils_e2e_test.go
Julian Schlarb 68d690b6b9
Some checks are pending
/ release (push) Waiting to run
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
chore(e2e): simplify authentication setup (#6400)
Replaced manual login and context loading across tests with Playwright's `test.use` configuration for user authentication. This simplifies test setup, improves readability, and reduces repetition.

For #6362

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6400
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Julian Schlarb <julian.schlarb@denktmit.de>
Co-committed-by: Julian Schlarb <julian.schlarb@denktmit.de>
2025-01-05 05:17:04 +00:00

193 lines
4.8 KiB
Go

// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package e2e
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
modules_session "code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/tests"
"code.forgejo.org/go-chi/session"
"github.com/stretchr/testify/require"
)
var rootPathRe = regexp.MustCompile("\\[repository\\]\nROOT\\s=\\s.*")
func onForgejoRunTB(t testing.TB, callback func(testing.TB, *url.URL), prepare ...bool) {
if len(prepare) == 0 || prepare[0] {
defer tests.PrepareTestEnv(t, 1)()
}
createSessions(t)
s := http.Server{
Handler: testE2eWebRoutes,
}
u, err := url.Parse(setting.AppURL)
require.NoError(t, err)
listener, err := net.Listen("tcp", u.Host)
i := 0
for err != nil && i <= 10 {
time.Sleep(100 * time.Millisecond)
listener, err = net.Listen("tcp", u.Host)
i++
}
require.NoError(t, err)
u.Host = listener.Addr().String()
// Override repository root in config.
conf, err := os.ReadFile(setting.CustomConf)
require.NoError(t, err)
require.NoError(t, os.WriteFile(setting.CustomConf, rootPathRe.ReplaceAll(conf, []byte("[repository]\nROOT = "+setting.RepoRootPath)), 0o644))
defer func() {
require.NoError(t, os.WriteFile(setting.CustomConf, conf, 0o644))
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
s.Shutdown(ctx)
cancel()
}()
go s.Serve(listener)
// Started by config go ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers, setting.SSH.ServerKeyExchanges, setting.SSH.ServerMACs)
callback(t, u)
}
func onForgejoRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bool) {
onForgejoRunTB(t, func(t testing.TB, u *url.URL) {
callback(t.(*testing.T), u)
}, prepare...)
}
func createSessions(t testing.TB) {
t.Helper()
// copied from playwright.config.ts
browsers := []string{
"chromium",
"firefox",
"webkit",
"Mobile Chrome",
"Mobile Safari",
}
scopes := []string{
"shared",
}
users := []string{
"user1",
"user2",
"user12",
"user40",
}
authState := filepath.Join(filepath.Dir(setting.AppPath), "tests", "e2e", ".auth")
err := os.RemoveAll(authState)
require.NoError(t, err)
err = os.MkdirAll(authState, os.ModePerm)
require.NoError(t, err)
createSessionCookie := stateHelper(t)
for _, user := range users {
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: strings.ToLower(user)})
for _, browser := range browsers {
for _, scope := range scopes {
stateFile := strings.ReplaceAll(strings.ToLower(fmt.Sprintf("state-%s-%s-%s.json", browser, user, scope)), " ", "-")
createSessionCookie(filepath.Join(authState, stateFile), u)
}
}
}
}
func stateHelper(t testing.TB) func(stateFile string, user *user_model.User) {
type Cookie struct {
Name string `json:"name"`
Value string `json:"value"`
Domain string `json:"domain"`
Path string `json:"path"`
Expires int `json:"expires"`
HTTPOnly bool `json:"httpOnly"`
Secure bool `json:"secure"`
SameSite string `json:"sameSite"`
}
type BrowserState struct {
Cookies []Cookie `json:"cookies"`
Origins []string `json:"origins"`
}
options := session.Options{
Provider: setting.SessionConfig.Provider,
ProviderConfig: setting.SessionConfig.ProviderConfig,
CookieName: setting.SessionConfig.CookieName,
CookiePath: setting.SessionConfig.CookiePath,
Gclifetime: setting.SessionConfig.Gclifetime,
Maxlifetime: setting.SessionConfig.Maxlifetime,
Secure: setting.SessionConfig.Secure,
SameSite: setting.SessionConfig.SameSite,
Domain: setting.SessionConfig.Domain,
}
opt := session.PrepareOptions([]session.Options{options})
vsp := modules_session.VirtualSessionProvider{}
err := vsp.Init(opt.Maxlifetime, opt.ProviderConfig)
require.NoError(t, err)
return func(stateFile string, user *user_model.User) {
buf := make([]byte, opt.IDLength/2)
_, err = rand.Read(buf)
require.NoError(t, err)
sessionID := hex.EncodeToString(buf)
s, err := vsp.Read(sessionID)
require.NoError(t, err)
err = s.Set("uid", user.ID)
require.NoError(t, err)
err = s.Release()
require.NoError(t, err)
state := BrowserState{
Cookies: []Cookie{
{
Name: opt.CookieName,
Value: sessionID,
Domain: setting.Domain,
Path: "/",
Expires: -1,
HTTPOnly: true,
Secure: false,
SameSite: "Lax",
},
},
Origins: []string{},
}
jsonData, err := json.Marshal(state)
require.NoError(t, err)
err = os.WriteFile(stateFile, jsonData, 0o644)
require.NoError(t, err)
}
}