60 lines
3.0 KiB
Go
60 lines
3.0 KiB
Go
package recoveryconformance
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestProductionEquivalentRequiresAllRecoveryDrills(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
capture, now := recoveryFixture("PRODUCTION_EQUIVALENT")
|
||
|
|
report := Evaluate(capture, "0.64.0-rc.1", "sha256:"+strings.Repeat("a", 64), now)
|
||
|
|
if report.Result != "PASS" || report.EvidenceScope != "PRODUCTION_EQUIVALENT" || report.ExternalValidationRequired || report.DrillCount != 4 {
|
||
|
|
t.Fatalf("unexpected report: %+v", report)
|
||
|
|
}
|
||
|
|
capture.Drills = capture.Drills[:3]
|
||
|
|
report = Evaluate(capture, "0.64.0-rc.1", "sha256:"+strings.Repeat("a", 64), now)
|
||
|
|
if report.Result != "FAIL" || !report.ExternalValidationRequired {
|
||
|
|
t.Fatal("production-equivalent evidence without provider recovery was accepted")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLocalRecoverySubsetPreservesExternalGate(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
capture, now := recoveryFixture("LOCAL")
|
||
|
|
capture.Environment = "LOCAL"
|
||
|
|
capture.Drills = capture.Drills[1:3]
|
||
|
|
report := Evaluate(capture, "0.64.0-rc.1", "sha256:"+strings.Repeat("a", 64), now)
|
||
|
|
if report.Result != "PASS" || report.EvidenceScope != "LOCAL_RECOVERY" || !report.ExternalValidationRequired || report.DrillCount != 2 {
|
||
|
|
t.Fatalf("local recovery boundary changed: %+v", report)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStrictRecoveryCaptureAndReport(t *testing.T) {
|
||
|
|
t.Parallel()
|
||
|
|
if _, err := ParseCapture([]byte(`{"schema_version":"production-recovery-capture-v1","unknown":true}`)); err == nil {
|
||
|
|
t.Fatal("unknown capture field was accepted")
|
||
|
|
}
|
||
|
|
if _, err := ParseReport([]byte(`{"schema_version":"production-recovery-conformance-report-v1","unknown":true}`)); err == nil {
|
||
|
|
t.Fatal("unknown report field was accepted")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func recoveryFixture(source string) (Capture, time.Time) {
|
||
|
|
now := time.Date(2026, 8, 25, 12, 0, 0, 0, time.UTC)
|
||
|
|
drill := func(drillType string, offset int) DrillEvidence {
|
||
|
|
digest := strings.Repeat(string(rune('a'+offset)), 64)
|
||
|
|
return DrillEvidence{
|
||
|
|
DrillType: drillType, ScenarioRef: "scenario:" + strings.ToLower(drillType), StartedAt: now.Add(time.Duration(-20+offset) * time.Minute), CompletedAt: now.Add(time.Duration(-18+offset) * time.Minute), ObservedRecoverySeconds: 120,
|
||
|
|
RecoveryVerified: true, DataIntegrityVerified: true, BusinessContinuityVerified: true, NoDuplicateEffects: true, CleanupVerified: true,
|
||
|
|
BeforeStateDigest: digest, AfterStateDigest: digest, ExecutionRef: "execution:" + drillType, ValidationRef: "validation:" + drillType, AuditRef: "audit:" + drillType,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return Capture{
|
||
|
|
SchemaVersion: CaptureSchema, EvidenceSource: source, CandidateVersion: "0.64.0-rc.1", BuildDigest: "sha256:" + strings.Repeat("a", 64), Environment: "STAGING",
|
||
|
|
InfrastructureRef: "cluster:staging-primary", FailureDomainRef: "zone:masked-a", ChangeTicketRef: "change:masked-001", AttestedByRef: "sre-reviewer:masked-001", AttestedAt: now.Add(-time.Minute), CollectedAt: now,
|
||
|
|
Drills: []DrillEvidence{drill("POSTGRES_RESTORE", 0), drill("REDIS_REBUILD", 1), drill("SERVICE_ROLLING_RESTART", 2), drill("PROVIDER_OUTAGE_RECOVERY", 3)},
|
||
|
|
}, now
|
||
|
|
}
|