Go Test Suite¶
Overview¶
The Go test suite covers the core operator services: expression engine, aggregation, field extraction, metric source compilation, RBAC engine/types/cache/filter, API handlers with RBAC integration, controllers, ingester, store layer, collector utilities, config loading, and utility parsing. Tests use standard library testing only (no testify/gomock). Redis is mocked with miniredis/v2.
Quick Start¶
# Run all tests
go test ./...
# Run with race detector
go test -race ./...
# Run with coverage
go test -cover ./...
go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
Test Inventory¶
Pure Function Tests (no external dependencies)¶
| Package | File | Tests | What It Covers |
|---|---|---|---|
pkg/utils |
parser_test.go |
41 | CPU/memory string parsing |
pkg/utils |
circuit_breaker_test.go |
6 | Circuit breaker state machine |
internal/metricsource/expression |
tokenizer_test.go |
25 | Lexical analysis (operators, strings, numbers, keywords) |
internal/metricsource/expression |
parser_test.go |
20 | AST building, precedence, functions, Compile/ExtractReferences |
internal/metricsource/expression |
evaluator_test.go |
35 | Expression evaluation, type coercion, short-circuit logic |
internal/metricsource/expression |
functions_test.go |
40 | All 20 built-in functions + toString/toFloat helpers |
internal/metricsource/aggregator |
filter_test.go |
20 | All 9 filter operators + regex caching |
internal/metricsource/aggregator |
aggregator_test.go |
25 | All 7 aggregation functions + grouping + filtering |
internal/metricsource/extractor |
extractor_test.go |
30 | Path navigation, type conversion, field extraction |
internal/metricsource/compiler |
compiler_test.go |
30 | Validation, helpers (parseAPIVersion, pluralize, etc.) |
internal/config |
config_test.go |
15 | Env var parsing (getEnv, getEnvInt, getEnvBool, getEnvIntWithMin) |
internal/collector |
buffer_test.go |
10 | Bounded FIFO buffer with concurrent access |
internal/collector |
agent_test.go |
13 | toFloat64, extractNodeMetrics, strVal, applyConfig, extractOperatorProto, extractClusterOperatorProto |
internal/rbac |
types_test.go |
20 | Principal/Resource/Request cache keys, MatchSpec, RBACDecision, CustomResourceDecision |
internal/rbac |
engine_test.go |
35 | RBAC engine security, FilterResources, evaluatePolicies (deny/disabled/default), matchCluster, matchesResource, aggregation rules, helpers |
internal/rbac |
filter_test.go |
12 | buildMatcherFromCompiled, filter helpers, pattern compilation |
internal/api |
handlers_test.go |
5 | HealthHandler + writeJSON |
internal/api |
aggregations_test.go |
22 | getFieldValue, matchesFilter, computeSingle, computeGrouped, toFloat |
internal/api |
config_test.go |
8 | envStr, envInt, envBool, isDevelopment |
internal/api |
clusters_helpers_test.go |
11 | paginate, queryInt, getStringSliceFromMap |
internal/api |
custom_types_helpers_test.go |
3 | extractNames |
internal/api |
middleware_test.go |
5 | getPrincipal, securityHeaders, resolveGroups |
internal/controller/policy |
compiler_test.go |
18 | Policy compilation, subject extraction, permissions |
internal/controller/policy |
validator_test.go |
6 | Policy validation, lifecycle parsing |
internal/controller/policy |
policy_controller_test.go |
7 | Reconcile (create/NotFound/DeletionTimestamp/compilation error), handleDeletion (Redis cleanup), updateStatusError, EvalCacheCleaner.Start |
internal/ingester |
handler_test.go |
8 | Proto-to-internal type conversions |
internal/ingester |
vmwriter_test.go |
4 | formatLine, boolToInt, VMWriter.Send |
internal/ingester |
server_tls_test.go |
2 | TLS cert/key loading |
internal/ingester |
server_test.go |
3 | Connection tracking lifecycle, heartbeat |
Controller Tests (pure helper methods)¶
| Package | File | Tests | What It Covers |
|---|---|---|---|
internal/client/pool |
pool_test.go |
6 | Remove (existing/nonexistent/concurrent), Close, cleanupIdleClients (all idle/empty pool) |
internal/client/cluster |
client_test.go |
24 | deriveConsoleURL, getStringValue, extractNodeMetrics (ready/unschedulable/notReady/noPods), extractClusterOperatorInfo, extractOperatorInfo, getLastUsed, GetNodeMetrics (populated/empty), GetClusterMetrics, GetNamespaces, TestConnection, collectDeployments/Services/StatefulSets/DaemonSets, GetResourceCollection (enabled/disabled) |
internal/client/registry |
client_test.go |
15 | NewDockerV2Client, HealthCheck (OK/401/500/refused/auth), CheckCatalog (OK/maxEntries/error), detectRegistryInfo, ExtendedHealthCheck |
internal/metricsource/collector |
collector_test.go |
16 | filterNamespaces (nil/include/exclude/combined/wildcards), useClusterWideList (nil ns/exclude/wildcard/exact names/mixed) |
internal/version |
version_test.go |
1 | Default build variable values |
internal/controller/cluster |
cluster_controller_test.go |
13 | getReconcileInterval, statusEqual, countAvailable, countDegraded, Reconcile (NotFound, DeletionTimestamp), handleDeletion, storeCRDData, updateClusterStatus, getClusterClient (SecretNotFound, EmptyToken) |
internal/controller/registry |
registry_controller_test.go |
17 | getReconcileInterval, calculateRegistryHealth, shouldUpdateStatus, generateHealthMessage, mapsEqual, Reconcile (NotFound, DeletionTimestamp), handleDeletion, storeRegistryData (success, with error) |
internal/controller/metricsource |
metricsource_controller_test.go |
8 | InvalidateClusterClient, GetCachedMetricSource (hit/miss), handleDeletion (cache+Redis cleanup), updateStatusSuccess, updateStatusError, Reconcile (NotFound, DeletionTimestamp) |
Miniredis-Backed Tests (store layer + RBAC cache)¶
| Package | File | Tests | What It Covers |
|---|---|---|---|
internal/store |
client_test.go |
20 | StoreOperators, StoreNodeMetrics, StoreClusterMetrics, StoreNamespaces, StoreClusterInfo/Status/Spec/Labels, StoreClusterOperators, PublishEvent, DeleteClusterData |
internal/store |
policy_storage_test.go |
15 | StorePolicy indexes, GetPolicy round-trip, RemovePolicy, ListPolicies, UpdatePolicyStatus, InvalidateEvaluationCaches, PublishPolicyEvent |
internal/store |
metricsource_storage_test.go |
12 | StoreCompiledMetricSource, GetCompiledMetricSourceByID, DeleteMetricSource, ListMetricSources, StoreCustomResourceCollection, StoreAggregationResults |
internal/store |
registry_storage_test.go |
8 | StoreRegistrySpec/Status/Metrics, GetRegistryStatus, GetAllRegistries, DeleteRegistryData |
internal/store |
resource_storage_test.go |
4 | StoreResourceCollection |
internal/store |
reader_test.go |
16 | GetJSON, GetJSONList, GetHashJSON, GetClusterBundle, GetAllClusterNames, GetClusterNodes, GetNodeMetricsHistory, GetPoliciesForPrincipal |
internal/rbac |
cache_test.go |
16 | NewCache, Get/SetDecision, ClearDecisions, Get/SetCustomDecision, DTO converter round-trips |
API Integration Tests (miniredis + httptest)¶
| Package | File | Tests | What It Covers |
|---|---|---|---|
internal/api |
handlers_readyz_test.go |
2 | ReadyHandler with Redis up/down |
internal/api |
middleware_integration_test.go |
7 | AuthMiddleware, OptionalAuthMiddleware, SecurityHeaders |
internal/api |
auth_handler_test.go |
8 | AuthStatus, GetMe, GetPermissions, Logout, ClearCache |
internal/api |
clusters_handler_test.go |
6 | ListClusters, GetCluster (accessible/denied), GetClusterNodes |
internal/api |
registries_handler_test.go |
3 | ListRegistriesStatus (unauth, empty, with data) |
internal/api |
custom_types_handler_test.go |
5 | ListCustomTypes, GetCustomResourceCounts |
Ingester Integration Tests (miniredis)¶
| Package | File | Tests | What It Covers |
|---|---|---|---|
internal/ingester |
handler_integration_test.go |
6 | ProcessBatch (cluster/node/info/custom), BuildConfigUpdate |
Testing with External Dependencies¶
Redis (miniredis)¶
Tests that require Redis use github.com/alicebob/miniredis/v2 which provides an in-memory Redis server. No real Redis instance is needed.
import "github.com/alicebob/miniredis/v2"
func TestSomething(t *testing.T) {
mr := miniredis.RunT(t) // auto-cleaned up
// Use mr.Addr() to connect
}
HTTP Handlers (httptest)¶
API handler tests use net/http/httptest with chi router for URL parameters. Auth middleware is bypassed by injecting the principal directly via context.WithValue.
Kubernetes Types¶
Controller and collector tests use K8s types directly (e.g., corev1.Node) without requiring a running cluster.
Testing Patterns¶
- Table-driven tests with
t.Runsubtests for parameterized coverage t.Context()(Go 1.24+) for test contexts instead ofcontext.Background()t.Setenv()for isolated environment variable testing- Direct assertions using
t.Fatal/t.Error(no assertion libraries) - Whitebox testing (test files in same package for internal access)
wg.Go()(Go 1.25+) for concurrent buffer testsminiredis.RunT(t)for Redis-backed tests (auto cleanup)
Running Specific Tests¶
# Single package
go test ./internal/metricsource/expression/...
# Single test function
go test ./internal/metricsource/expression/ -run TestEval_BinaryDiv_ByZero -v
# Pattern match
go test ./internal/rbac/ -run TestMatchSpec -v
# All metricsource packages
go test ./internal/metricsource/...
# Store layer tests
go test ./internal/store/...
# API handler tests
go test ./internal/api/...
Adding New Tests¶
- Create
*_test.goin the same package (whitebox) - Use table-driven tests with
t.Runfor multiple cases - Use
t.Fatalfor setup failures,t.Errorfor assertion failures - Run
go test -raceto verify thread safety - For Redis-dependent tests, use
miniredis.RunT(t)— no real Redis needed - For HTTP handler tests, use
httptest.NewRecorder()+httptest.NewRequest()
Continuous Integration¶
All tests run automatically on every pull request targeting main via GitHub Actions (.github/workflows/linting.yml).
CI Jobs¶
| Job | What it does |
|---|---|
| Lint | Runs golangci-lint with the project's .golangci.yml config |
| Test | Runs go test -race -coverprofile=coverage.out ./... |
| Build | Compiles all binaries (cmd/api, cmd/collector, cmd/manager) |
All three jobs must pass before a PR can be merged. Results are posted as a sticky comment on the PR with test counts and coverage percentage.
Running CI Checks Locally¶
# Run tests (same as CI)
make test
# Run linter (requires golangci-lint v2.1+)
make lint
# Verify build
make build
Linter Configuration¶
The project uses golangci-lint v2 with the standard preset. Configuration is in .golangci.yml at the project root. Generated code (zz_generated.deepcopy.go, protobuf files) is excluded automatically.