# Testing Patterns **Analysis Date:** 2026-02-23 ## Test Framework **Language-Specific Runners:** **Go:** - Runner: `go test` (standard library `testing` package) - Config: No config file (uses built-in conventions) - Run Commands: ```bash go test ./... # Run all tests go test -v ./... # Verbose output go test -run TestContains ./... # Run specific test go test -cover ./... # Show coverage ``` **Bash:** - Runner: Custom shell scripts in `scripts/` - No formal test framework; uses `set -euo pipefail` for error handling - Manual health checks via `bash scripts/cluster_healthcheck.sh` **Terraform:** - Framework: No automated testing detected (no terraform test files, no tftest.hcl) - Validation: Manual `terraform validate`, `terraform plan`, visual inspection - Integration: Terragrunt applies validate before execution ## Test File Organization **Location:** - Go tests: Co-located with source code: `/files/internal/scraper/validate_test.go` - Shell/Infrastructure: No test files (manual validation/health checks only) **Naming:** - Go: `*_test.go` suffix - Script tests: `.sh` for check/validation scripts **Structure:** ``` stacks/f1-stream/files/internal/scraper/ ├── main.go ├── validate.go └── validate_test.go # Test file co-located ``` ## Test Structure **Go Table-Driven Tests:** ```golang func TestContainsVideoMarkers(t *testing.T) { tests := []struct { name string body string want bool }{ { name: "video tag", body: `
`, want: true, }, // ... more test cases } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := containsVideoMarkers(tt.body) if got != tt.want { t.Errorf("containsVideoMarkers(%q) = %v, want %v", truncate(tt.body, 60), got, tt.want) } }) } } ``` **Patterns:** - Slice of anonymous structs with `name`, input fields, and `want` for expected result - Loop with `t.Run(tt.name, ...)` for individual test case execution and reporting - Descriptive test case names: `"video tag"`, `"HLS manifest reference"`, `"empty string"` - Separate positive cases (upper) and negative cases (lower) with comments **Bash Health Check Structure:** ```bash check_nodes() { section 1 "Node Status" local nodes not_ready versions unique_versions detail="" nodes=$($KUBECTL get nodes --no-headers 2>&1) || { fail "Cannot reach cluster"; json_add "node_status" "FAIL" "Cannot reach cluster"; return 0; } # ... processing if [[ -n "$not_ready" ]]; then fail "NotReady nodes: $not_ready" json_add "node_status" "FAIL" "$detail" elif [[ "$unique_versions" -gt 1 ]]; then warn "Version mismatch..." json_add "node_status" "WARN" "$detail" else pass "All nodes Ready..." json_add "node_status" "PASS" "$detail" fi } ``` **Patterns:** - Each check function follows same structure: setup → validation → status reporting - Status reported via `pass()`, `warn()`, `fail()` helper functions - JSON output optional via `json_add()` for programmatic consumption - Error handling inline with `||` fallback and graceful degradation ## Mocking **Framework:** - Go: No mocking framework detected (table-driven tests use real function calls) - Bash: External commands mocked implicitly (KUBECONFIG override, kubectl invocation through `$KUBECTL` variable) **Patterns (Go):** - No mock objects or stubs - Real function behavior tested directly - Test data provided as input in struct fields **Patterns (Bash):** ```bash # Kubeconfig override allows testing against different clusters KUBECTL="kubectl --kubeconfig $KUBECONFIG_PATH" nodes=$($KUBECTL get nodes --no-headers 2>&1) || { fail "Cannot reach cluster"; return 0; } ``` **What NOT to Mock:** - Core functionality being tested (test actual behavior) - Standard library functions (test integration) **What to Mock (Bash):** - External kubectl calls via variable indirection: allows `KUBECONFIG` override - Conditional output by flag: `--json`, `--quiet` flags change output, not behavior ## Fixtures and Factories **Test Data (Go):** - Inline strings in struct fields: HTML content, MIME types - Examples from `validate_test.go`: ```golang { name: "HLS manifest reference", body: `var url = "https://cdn.example.com/live.m3u8";`, want: true, }, ``` **Location:** - Embedded directly in test file as struct field values - No separate fixture files or factories **Bash Fixtures:** - Real cluster fixtures: tests run against actual Kubernetes cluster - No data files; tests fetch live state via kubectl ## Coverage **Requirements:** None enforced (no coverage thresholds, targets, or CI/CD gates detected) **View Coverage (Go):** ```bash go test -cover ./... # Show coverage percentages go test -coverprofile=coverage.out ./... go tool cover -html=coverage.out # Open HTML report ``` **Note:** Coverage tools not integrated into CI/CD pipeline; manual check only. ## Test Types **Unit Tests (Go):** - Scope: Single function validation - Approach: Table-driven with parameterized inputs - Example: `TestContainsVideoMarkers()` tests HTML content detection - Example: `TestIsDirectVideoContentType()` tests MIME type classification - In file: `stacks/f1-stream/files/internal/scraper/validate_test.go` **Integration Tests:** - Bash health checks (`scripts/cluster_healthcheck.sh`) serve as integration tests - Tests 24 separate checks against live Kubernetes cluster: - Node status and readiness - Node resource utilization - Container metrics - Pod crash loops - Persistent volume health - DNS resolution - Networking - RBAC - Logs aggregation - Can run with `--fix` flag for auto-remediation - Can output JSON for CI integration **E2E Tests:** - Not formally implemented - Manual validation via Terragrunt apply → cluster state verification **Infrastructure Testing:** - Terraform: `terraform validate` and `terraform plan` provide syntax/logic validation - Application health: Manual checks via scripts and cluster_healthcheck.sh - No automated test suite for infrastructure code ## Common Patterns **Async Testing (Go):** - Not applicable (synchronous function testing only) **Error Testing (Go):** ```golang { name: "empty string", body: "", want: false, }, ``` - Negative test cases included in same table - Error/edge cases named descriptively: `"empty string"`, `"reddit link page"` - Expected failure behavior verified: `want: false` for invalid inputs **Error Reporting (Go):** ```golang t.Errorf("containsVideoMarkers(%q) = %v, want %v", truncate(tt.body, 60), got, tt.want) ``` - Formatted message includes: function name, input (truncated), actual, expected - Test name automatically prefixed by `t.Run(tt.name, ...)` **Status Reporting (Bash):** - Color-coded status: `${GREEN}[PASS]${NC}`, `${YELLOW}[WARN]${NC}`, `${RED}[FAIL]${NC}` - Counter incremented per status - Optional quiet mode (`--quiet`) suppresses PASS output - Optional JSON output (`--json`) for CI integration - Summary printed at end: `$PASS_COUNT/$WARN_COUNT/$FAIL_COUNT` ## Running Tests **Go Tests:** ```bash # From service directory containing *_test.go go test -v ./... ``` **Bash Health Checks:** ```bash # Comprehensive checks bash scripts/cluster_healthcheck.sh # Quiet mode (WARN/FAIL only) bash scripts/cluster_healthcheck.sh --quiet # Auto-fix mode bash scripts/cluster_healthcheck.sh --fix # JSON output bash scripts/cluster_healthcheck.sh --json # Custom kubeconfig bash scripts/cluster_healthcheck.sh --kubeconfig /path/to/config ``` **Terraform Validation:** ```bash # Format check terraform fmt -recursive # Syntax validation terraform validate # Plan without apply terraform plan # From stack directory cd stacks/ && terragrunt plan cd stacks/ && terragrunt apply --non-interactive ``` --- *Testing analysis: 2026-02-23*