Testing
Test Commands
# All unit tests with race detector
make test
# Single package
go test ./internal/supervisor/...
# Single test
go test -run TestHooksIntegration ./cmd/runix/...
# E2E tests (no race flag, longer timeout)
go test -v -count=1 -timeout 120s ./internal/e2e/...
Full CI Reproduction
make test && go test -v -count=1 -timeout 120s ./internal/e2e/...
Test Conventions
Framework
- Standard library
testingonly — no testify, ginkgo, or other frameworks - Use
t.Fatal,t.Fatalf,t.Error,t.Errorffor assertions - Use
t.TempDir()for temporary directories (auto-cleaned)
File Placement
| Test Type | Location |
|---|---|
| Unit tests | <package>/<name>_test.go (same package) |
| Integration tests | <package>/integration_test.go or internal/e2e/ |
| CLI tests | cmd/runix/<name>_test.go |
Table-Driven Tests
func TestValidateRuntime(t *testing.T) {
tests := []struct {
name string
runtime string
wantErr bool
}{
{"go", "go", false},
{"python", "python", false},
{"invalid", "ruby", true},
{"empty", "", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validateRuntime(tt.runtime)
if (err != nil) != tt.wantErr {
t.Errorf("validateRuntime(%q) error = %v, wantErr %v", tt.runtime, err, tt.wantErr)
}
})
}
}
Hook Integration Tests
Hook tests use marker files to verify execution:
func TestHooksIntegration(t *testing.T) {
dir := t.TempDir()
markerFile := dir + "/hook_markers.txt"
// Configure hooks that write to marker file
cfg := types.ProcessConfig{
Hooks: &types.ProcessHooks{
PreStart: &types.HookConfig{
Command: "echo pre_start >> " + markerFile,
Timeout: 5 * time.Second,
},
},
}
// Start and stop process, then verify markers
// ...
}
E2E Tests
E2E tests in internal/e2e/ use a real supervisor with actual sleep commands:
func TestE2EStartStop(t *testing.T) {
dir := t.TempDir()
sup := supervisor.New(supervisor.Options{
LogDir: dir + "/logs",
Defaults: types.DefaultsConfig{
RestartPolicy: types.RestartNever,
},
})
cfg := types.ProcessConfig{
Name: "sleeper",
Runtime: "unknown",
Entrypoint: "sleep",
Args: []string{"60"},
Cwd: dir,
}
proc, err := sup.AddProcess(context.Background(), cfg)
if err != nil {
t.Fatalf("AddProcess: %v", err)
}
// Verify running, then stop
// ...
}
Test Packages with Tests
| Package | Test Files |
|---|---|
cmd/runix | hooks_test.go |
internal/supervisor | *_test.go |
internal/config | *_test.go |
internal/hooks | *_test.go |
internal/healthcheck | *_test.go |
internal/secrets | *_test.go |
internal/cgroups | *_test.go |
internal/logrot | *_test.go |
internal/events | *_test.go |
internal/updater | *_test.go |
internal/e2e | E2E suite |
What's Next
- Building — Build commands
- Contributing — Code conventions