mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-23 02:24:10 +00:00
Disable the thelper linter which triggers on inline test closures in table-driven tests. These closures are intentionally not standalone helpers and don't benefit from t.Helper(). Also remove explanatory comments from nolint directives throughout the codebase as they add noise without providing significant value.
131 lines
3.6 KiB
Go
131 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/creachadair/command"
|
|
)
|
|
|
|
var ErrTestPatternRequired = errors.New("test pattern is required as first argument or use --test flag")
|
|
|
|
type RunConfig struct {
|
|
TestPattern string `flag:"test,Test pattern to run"`
|
|
Timeout time.Duration `flag:"timeout,default=120m,Test timeout"`
|
|
FailFast bool `flag:"failfast,default=true,Stop on first test failure"`
|
|
UsePostgres bool `flag:"postgres,default=false,Use PostgreSQL instead of SQLite"`
|
|
GoVersion string `flag:"go-version,Go version to use (auto-detected from go.mod)"`
|
|
CleanBefore bool `flag:"clean-before,default=true,Clean stale resources before test"`
|
|
CleanAfter bool `flag:"clean-after,default=true,Clean resources after test"`
|
|
KeepOnFailure bool `flag:"keep-on-failure,default=false,Keep containers on test failure"`
|
|
LogsDir string `flag:"logs-dir,default=control_logs,Control logs directory"`
|
|
Verbose bool `flag:"verbose,default=false,Verbose output"`
|
|
Stats bool `flag:"stats,default=false,Collect and display container resource usage statistics"`
|
|
HSMemoryLimit float64 `flag:"hs-memory-limit,default=0,Fail test if any Headscale container exceeds this memory limit in MB (0 = disabled)"`
|
|
TSMemoryLimit float64 `flag:"ts-memory-limit,default=0,Fail test if any Tailscale container exceeds this memory limit in MB (0 = disabled)"`
|
|
}
|
|
|
|
// runIntegrationTest executes the integration test workflow.
|
|
func runIntegrationTest(env *command.Env) error {
|
|
args := env.Args
|
|
if len(args) > 0 && runConfig.TestPattern == "" {
|
|
runConfig.TestPattern = args[0]
|
|
}
|
|
|
|
if runConfig.TestPattern == "" {
|
|
return ErrTestPatternRequired
|
|
}
|
|
|
|
if runConfig.GoVersion == "" {
|
|
runConfig.GoVersion = detectGoVersion()
|
|
}
|
|
|
|
// Run pre-flight checks
|
|
if runConfig.Verbose {
|
|
log.Printf("Running pre-flight system checks...")
|
|
}
|
|
|
|
err := runDoctorCheck(env.Context())
|
|
if err != nil {
|
|
return fmt.Errorf("pre-flight checks failed: %w", err)
|
|
}
|
|
|
|
if runConfig.Verbose {
|
|
log.Printf("Running test: %s", runConfig.TestPattern)
|
|
log.Printf("Go version: %s", runConfig.GoVersion)
|
|
log.Printf("Timeout: %s", runConfig.Timeout)
|
|
log.Printf("Use PostgreSQL: %t", runConfig.UsePostgres)
|
|
}
|
|
|
|
return runTestContainer(env.Context(), &runConfig)
|
|
}
|
|
|
|
// detectGoVersion reads the Go version from go.mod file.
|
|
func detectGoVersion() string {
|
|
goModPath := filepath.Join("..", "..", "go.mod")
|
|
|
|
//nolint:noinlineerr
|
|
if _, err := os.Stat("go.mod"); err == nil {
|
|
goModPath = "go.mod"
|
|
//nolint:noinlineerr
|
|
} else if _, err := os.Stat("../../go.mod"); err == nil {
|
|
goModPath = "../../go.mod"
|
|
}
|
|
|
|
content, err := os.ReadFile(goModPath)
|
|
if err != nil {
|
|
return "1.25"
|
|
}
|
|
|
|
lines := splitLines(string(content))
|
|
for _, line := range lines {
|
|
if len(line) > 3 && line[:3] == "go " {
|
|
version := line[3:]
|
|
if idx := indexOf(version, " "); idx != -1 {
|
|
version = version[:idx]
|
|
}
|
|
|
|
return version
|
|
}
|
|
}
|
|
|
|
return "1.25"
|
|
}
|
|
|
|
// splitLines splits a string into lines without using strings.Split.
|
|
func splitLines(s string) []string {
|
|
var (
|
|
lines []string
|
|
current string
|
|
)
|
|
|
|
for _, char := range s {
|
|
if char == '\n' {
|
|
lines = append(lines, current)
|
|
current = ""
|
|
} else {
|
|
current += string(char)
|
|
}
|
|
}
|
|
|
|
if current != "" {
|
|
lines = append(lines, current)
|
|
}
|
|
|
|
return lines
|
|
}
|
|
|
|
// indexOf finds the first occurrence of substr in s.
|
|
func indexOf(s, substr string) int {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return i
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|