112 lines
3.5 KiB
Markdown
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
|
|
```
|