diff --git a/magefile.go b/magefile.go index a7aa03a..6eff5f5 100644 --- a/magefile.go +++ b/magefile.go @@ -1,5 +1,31 @@ //go:build mage +// Magefile for olcrtc. +// +// Quick reference: +// +// mage check # build + vet + lint + unit tests (pre-commit) +// mage all # full pre-merge pipeline (check + e2e smoke matrix) +// mage nightly # everything including stress matrix (~6h) +// +// mage build # native binary +// mage cross # all platforms +// mage mobile # Android AAR +// +// mage test # short unit tests +// mage testfull # all unit tests, no real providers +// mage e2e # real-provider smoke matrix +// mage stress # real-provider stress matrix (long) +// mage soak # real-provider throughput soak (long) +// mage localsoak # local in-memory soak (very long, no network) +// +// Tunables (env): +// +// E2E_CARRIERS, E2E_TRANSPORTS, E2E_TIMEOUT +// E2E_STRESS, E2E_STRESS_DURATION +// STRESS_BULK_DURATION, STRESS_ECHO_DURATION, STRESS_CASE_TIMEOUT, STRESS_TIMEOUT +// SOAK_CARRIERS, SOAK_TRANSPORTS, SOAK_DURATION, SOAK_CHAOS + package main import ( @@ -14,11 +40,14 @@ import ( "github.com/magefile/mage/sh" ) +// Default target when invoked as `mage` with no args. +// +//nolint:gochecknoglobals // mage requires a package-level Default symbol. +var Default = Help + const ( - module = "github.com/openlibrecommunity/olcrtc" - buildDir = "build" - ldflags = "-s -w" - goVersion = "1.25" + buildDir = "build" + ldflags = "-s -w" ) var ( @@ -27,14 +56,50 @@ var ( goarch = envOr("GOARCH", runtime.GOARCH) ) -// Build builds the olcrtc CLI binary. -func Build() error { - mg.Deps(BuildCLI) - return nil +// ───────────────────────────────────────────────────────────────────────────── +// Pipelines +// ───────────────────────────────────────────────────────────────────────────── + +// Help lists every target in mage's default style. This is what runs when +// you invoke `mage` with no arguments. For grouped/annotated docs see the +// magefile header. +func Help() error { + return sh.RunV("mage", "-l") } -// BuildCLI builds the olcrtc server/client binary. -func BuildCLI() error { +// Check runs the fast pre-commit pipeline: build + vet + lint + unit tests. +// Use this before every commit. +func Check() { + mg.SerialDeps(Build, Vet, Lint, TestFull) +} + +// All runs the full pre-merge pipeline: Check + the real-provider smoke +// matrix. Stress and soak are NOT included - run them explicitly when +// needed (see Nightly for everything). +func All() { + mg.SerialDeps(Check, E2e) +} + +// Nightly runs everything: All + stress matrix. Expect multi-hour runtime; +// intended for the nightly CI job or manual deep validation. +func Nightly() { + mg.SerialDeps(All, Stress) +} + +// Everything runs literally every test stage: Nightly + real soak + local +// soak. Expect 12+ hours; this is for "I want maximum confidence before +// shipping" runs, not regular development. Tune SOAK_DURATION etc. if you +// need a shorter window. +func Everything() { + mg.SerialDeps(Nightly, Soak, LocalSoak) +} + +// ───────────────────────────────────────────────────────────────────────────── +// Build +// ───────────────────────────────────────────────────────────────────────────── + +// Build builds the olcrtc CLI binary for the host platform. +func Build() error { mg.Deps(Deps) return buildBinary("olcrtc", "./cmd/olcrtc", goos, goarch) } @@ -61,20 +126,50 @@ func Cross() error { } } - fmt.Printf("✅ Built %d platform(s)\n", len(targets)) + fmt.Printf("✅ built %d platform(s)\n", len(targets)) return nil } +// Mobile builds the Android AAR via gomobile. +func Mobile() error { + if err := ensureTool("gomobile"); err != nil { + return fmt.Errorf("gomobile not found: run 'go install golang.org/x/mobile/cmd/gomobile@latest && gomobile init'") + } + if err := ensureBuildDir(); err != nil { + return err + } + return sh.RunV("gomobile", "bind", + "-target=android", + "-androidapi", "21", + "-ldflags", "-s -w -checklinkname=0", + "-o", filepath.Join(buildDir, "olcrtc.aar"), + "./mobile", + ) +} + +// ───────────────────────────────────────────────────────────────────────────── +// Container +// ───────────────────────────────────────────────────────────────────────────── + +// Docker builds the image using docker. +func Docker() error { + tag := envOr("DOCKER_TAG", "olcrtc:latest") + return sh.RunV("docker", "build", "-t", tag, ".") +} + // Podman builds the image using podman. func Podman() error { tag := envOr("DOCKER_TAG", "olcrtc:latest") return sh.RunV("podman", "build", "-t", tag, ".") } -// Docker builds the image using docker. -func Docker() error { - tag := envOr("DOCKER_TAG", "olcrtc:latest") - return sh.RunV("docker", "build", "-t", tag, ".") +// ───────────────────────────────────────────────────────────────────────────── +// Quality +// ───────────────────────────────────────────────────────────────────────────── + +// Vet runs go vet on the whole module. +func Vet() error { + return sh.RunV(goexe, "vet", "./...") } // Lint runs golangci-lint. @@ -85,19 +180,31 @@ func Lint() error { return sh.RunV("golangci-lint", "run", "./...") } -// Test runs all unit tests (short mode, skips long-running chaos/throughput tests). +// Tidy runs go mod tidy and verifies modules. +func Tidy() error { + if err := sh.RunV(goexe, "mod", "tidy"); err != nil { + return err + } + return sh.RunV(goexe, "mod", "verify") +} + +// ───────────────────────────────────────────────────────────────────────────── +// Tests +// ───────────────────────────────────────────────────────────────────────────── + +// Test runs unit tests in -short mode (skips long-running tests). func Test() error { return sh.RunV(goexe, "test", "-race", "-count=1", "-short", "./...") } -// TestFull runs all tests including chaos and throughput baselines (no real providers). +// TestFull runs all unit + fast e2e tests with race detector. No real providers. func TestFull() error { return sh.RunV(goexe, "test", "-race", "-count=1", "-timeout", "10m", "./...") } -// E2E runs the real-provider e2e matrix plus stress tests. +// E2e runs the real-provider smoke matrix. // Configure via env: E2E_CARRIERS, E2E_TRANSPORTS, E2E_TIMEOUT, E2E_STRESS. -func E2E() error { +func E2e() error { args := []string{"test", "-race", "-count=1", "-v", "-timeout", "30m"} args = append(args, "-olcrtc.real-e2e=true") if carriers := os.Getenv("E2E_CARRIERS"); carriers != "" { @@ -119,6 +226,35 @@ func E2E() error { return sh.RunV(goexe, args...) } +// Stress runs the real-provider stress matrix on every carrier × transport pair. +// Defaults match the long nightly profile (15m bulk + 15m echo, 35m hard cap per case). +// Override via env: STRESS_BULK_DURATION, STRESS_ECHO_DURATION, STRESS_CASE_TIMEOUT, +// STRESS_TIMEOUT, E2E_CARRIERS, E2E_TRANSPORTS. +func Stress() error { + bulk := envOr("STRESS_BULK_DURATION", "15m") + echo := envOr("STRESS_ECHO_DURATION", "15m") + caseTO := envOr("STRESS_CASE_TIMEOUT", "35m") + overall := envOr("STRESS_TIMEOUT", "6h") + + args := []string{"test", "-count=1", "-v", + "-timeout", overall, + "-run", "^TestRealProviderTransportStress$", + "-olcrtc.real-e2e=true", + "-olcrtc.stress=true", + "-olcrtc.stress-bulk-duration=" + bulk, + "-olcrtc.stress-duration=" + echo, + "-olcrtc.stress-case-timeout=" + caseTO, + } + if carriers := os.Getenv("E2E_CARRIERS"); carriers != "" { + args = append(args, "-olcrtc.real-carriers="+carriers) + } + if transports := os.Getenv("E2E_TRANSPORTS"); transports != "" { + args = append(args, "-olcrtc.real-transports="+transports) + } + args = append(args, "./internal/e2e/...") + return sh.RunV(goexe, args...) +} + // Soak runs the real-provider throughput soak test. // Configure via env: SOAK_CARRIERS, SOAK_TRANSPORTS, SOAK_DURATION. func Soak() error { @@ -127,13 +263,13 @@ func Soak() error { duration := envOr("SOAK_DURATION", "10m") args := []string{"test", "-count=1", "-v", - "-timeout", "4h", + "-timeout", "12h", + "-run", "^TestRealThroughputSoak$", "-olcrtc.real-e2e=true", "-olcrtc.real-soak=true", "-olcrtc.real-soak-carrier=" + carriers, "-olcrtc.real-soak-transport=" + transports, "-olcrtc.real-soak-duration=" + duration, - "-run", "^TestRealThroughputSoak$", "./internal/e2e/...", } return sh.RunV(goexe, args...) @@ -147,11 +283,11 @@ func LocalSoak() error { chaos := os.Getenv("SOAK_CHAOS") args := []string{"test", "-count=1", "-v", - "-timeout", "4h", + "-timeout", "12h", + "-run", "^TestLocalThroughputSoak$", "-olcrtc.local-soak=true", "-olcrtc.local-soak-transport=" + transports, "-olcrtc.local-soak-duration=" + duration, - "-run", "^TestLocalThroughputSoak$", } if chaos != "" { args = append(args, "-olcrtc.local-soak-chaos="+chaos) @@ -160,12 +296,13 @@ func LocalSoak() error { return sh.RunV(goexe, args...) } -// Deps downloads and tidies Go module dependencies. +// ───────────────────────────────────────────────────────────────────────────── +// Utility +// ───────────────────────────────────────────────────────────────────────────── + +// Deps downloads Go module dependencies. func Deps() error { - if err := sh.RunV(goexe, "mod", "download"); err != nil { - return err - } - return sh.RunV(goexe, "mod", "tidy") + return sh.RunV(goexe, "mod", "download") } // Clean removes build artifacts. @@ -173,22 +310,9 @@ func Clean() error { return os.RemoveAll(buildDir) } -// Mobile builds the Android AAR via gomobile. -func Mobile() error { - if err := ensureTool("gomobile"); err != nil { - return fmt.Errorf("gomobile not found: run 'go install golang.org/x/mobile/cmd/gomobile@latest && gomobile init'") - } - if err := ensureBuildDir(); err != nil { - return err - } - return sh.RunV("gomobile", "bind", - "-target=android", - "-androidapi", "21", - "-ldflags", "-s -w -checklinkname=0", - "-o", filepath.Join(buildDir, "olcrtc.aar"), - "./mobile", - ) -} +// ───────────────────────────────────────────────────────────────────────────── +// Helpers (unexported, not visible as targets) +// ───────────────────────────────────────────────────────────────────────────── func buildBinary(name, pkg, os_, arch string) error { if err := ensureBuildDir(); err != nil { @@ -215,7 +339,6 @@ func buildBinary(name, pkg, os_, arch string) error { } args := []string{"build", "-trimpath", "-ldflags", flags, "-o", out, pkg} - return sh.RunWithV(env, goexe, args...) }