claude skills
This commit is contained in:
parent
94bf5d94b8
commit
9bbff7b016
40 changed files with 4072 additions and 34 deletions
89
.kiro/steering/testing.md
Normal file
89
.kiro/steering/testing.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Testing Standards
|
||||
|
||||
## Philosophy
|
||||
|
||||
- **TDD mandatory**: Write a failing test first, then the minimal implementation. The cycle is Red → Green → Refactor.
|
||||
- Test behavior, not implementation details.
|
||||
- Tests must run without a live server or external services.
|
||||
- A change is not complete until `make test` (and `make test-integration` where applicable) passes.
|
||||
|
||||
## Go Tests (apiserver / xcecli)
|
||||
|
||||
**Co-located** alongside source: `jobs.go` → `jobs_test.go`. Integration tests use descriptive names: `integration_test.go`, `host_control_test.go`.
|
||||
|
||||
**Table-driven** for validation/filter logic:
|
||||
|
||||
```go
|
||||
tests := []struct {
|
||||
name string
|
||||
input SomeRequest
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid request", validReq, false},
|
||||
{"missing field", missingReq, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := preCheckRequest(tt.input)
|
||||
if (err != nil) != tt.wantErr { t.Errorf(...) }
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**State isolation** — reset global store state between tests:
|
||||
|
||||
```go
|
||||
func resetRBACState() { /* clear in-memory stores */ }
|
||||
|
||||
func TestPermissions(t *testing.T) {
|
||||
t.Cleanup(resetRBACState)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Fixtures**: use `t.TempDir()` for file-system state; never rely on absolute paths or external services.
|
||||
|
||||
**Build targets**:
|
||||
- `make test` — unit tests only (`CGO_ENABLED=0`)
|
||||
- `make test-backend` — CGO-backed backend tests (requires nix dev shell + build dir)
|
||||
- `make test-integration` — full regression suite (requires `XCE_BIN` and `SRV_URL` env vars)
|
||||
|
||||
## C Tests (controller / worker / scheduler / lib)
|
||||
|
||||
**Location**: `testsuite/` directory inside each C component.
|
||||
|
||||
**Structure**: one `.c` test program per unit:
|
||||
|
||||
```
|
||||
src/controller/testsuite/
|
||||
test.c ← test runner harness
|
||||
test_ha_cluster.c ← tests for ha.c
|
||||
test_persist_wal.c ← WAL-specific tests
|
||||
test_e2e_checkpoint.c ← end-to-end checkpoint flow
|
||||
test_p1_integration.c ← P1 HA integration tier
|
||||
```
|
||||
|
||||
File naming convention: `test_<unit>.c`. E2E tests: `test_e2e_<topic>.c`. Integration tiers: `test_p1_*.c`, `test_p2_*.c`, `test_p3_hardening.c`.
|
||||
|
||||
**Test-only symbols** are guarded to prevent production bloat:
|
||||
|
||||
```c
|
||||
#ifdef XCE_TESTING
|
||||
extern void reset_ha_state(ha_state_t *s);
|
||||
#endif
|
||||
```
|
||||
|
||||
**Add a test case in `testsuite/` before modifying any C implementation.**
|
||||
|
||||
## Coverage Targets
|
||||
|
||||
- Go: 80% minimum on business logic (controllers, services, store)
|
||||
- C: every new function in a daemon must have at least one test case in `testsuite/`
|
||||
- Integration: all public REST endpoints must have at least one integration test case in `regression/`
|
||||
|
||||
## What Not to Mock
|
||||
|
||||
- Mock **external dependencies only** (network calls, file I/O that crosses component boundaries)
|
||||
- Do **not** mock the system under test
|
||||
- In-memory stores (`store/`) are real — use them directly in unit tests
|
||||
- CGO bridge (`backend/`) is covered by `make test-backend` — do not stub it in unit tests
|
||||
Loading…
Add table
Add a link
Reference in a new issue