guildhouse-spire-plugins/docs/testing.md

112 lines
3.5 KiB
Markdown

# Testing Strategy
How to test the Guildhouse SPIRE plugins.
## Running Tests
```bash
make test # Run all tests
make lint # Run go vet
# Verbose output
go test -v ./...
# Single package
go test -v ./pkg/shellstream/...
# With coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
```
## Test Structure
### Unit Tests (`pkg/`)
Each package has `*_test.go` files with unit tests:
| Package | Tests | Coverage Focus |
|---------|-------|---------------|
| `pkg/shellstream` | ~28 tests | Encode/decode round-trips, validation rules, format constraints, co-occurrence rules |
| `pkg/oidc` | 2 tests | Config validation (scaffolded) |
| `pkg/governance` | 2 tests | Client construction (scaffolded) |
| `pkg/sshcert` | 3 tests | Builder config validation (scaffolded) |
| `pkg/config` | 2 tests | Plugin config validation (scaffolded) |
### `pkg/shellstream` Tests (Fully Implemented)
The shellstream package has comprehensive tests covering:
- **Round-trip**: Encode → Decode produces identical values (full and minimal)
- **Required fields**: Missing tenant-id, missing roles produce validation errors
- **Format validation**: Invalid UUID, wrong hex length, uppercase hex, invalid base64
- **Co-occurrence**: sat-scope without sat-hash, ceremony-id without ceremony-type, merkle-proof without merkle-root
- **Parsing**: JSON sat-scope, comma-separated roles, base64 merkle proof, uint64 governance epoch
- **Edge cases**: Epoch value 0, nil extensions, unknown extensions ignored
- **Enum validation**: Unknown ceremony-type rejected
### Integration Test Approach (Future)
When plugin implementations are complete, integration tests will use mock gRPC servers:
```go
// Example mock GovernanceService
type mockGovernanceServer struct {
quartermasterv1.UnimplementedGovernanceServiceServer
intents map[string]*Intent
}
func (s *mockGovernanceServer) CreateIntent(ctx context.Context, req *quartermasterv1.CreateIntentRequest) (*quartermasterv1.CreateIntentResponse, error) {
// Return predictable responses for testing
}
```
Integration tests will:
1. Start mock gRPC servers for GovernanceService, CeremonyService, NotaryService
2. Create plugin instances pointed at the mock servers
3. Invoke plugin methods (Attest, Compose, Notify)
4. Verify the plugin made expected gRPC calls with correct parameters
5. Verify the plugin handled error conditions (unreachable service, denied intent, ceremony timeout)
## Test Fixtures
Test fixture files in `test/fixtures/`:
| File | Purpose |
|------|---------|
| `sample-oidc-token.json` | Example OIDC token payload for oidc-attestor testing |
| `sample-sat-scope.json` | Example SatScope for governance client testing |
| `sample-ssh-cert-extensions.json` | Example Shellstream extensions map for shellstream package testing |
| `spire-test-config.hcl` | Example SPIRE plugin configuration for config package testing |
Load fixtures in tests:
```go
func loadFixture(t *testing.T, name string) []byte {
t.Helper()
data, err := os.ReadFile(filepath.Join("../../test/fixtures", name))
if err != nil {
t.Fatalf("load fixture %s: %v", name, err)
}
return data
}
```
## CI Pipeline
```yaml
# .github/workflows/test.yaml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- run: make test
- run: make lint
- run: make build
```