Files
story/internal/firmwareconformance/conformance_test.go
T

106 lines
4.4 KiB
Go
Raw Normal View History

2026-08-26 06:41:07 +08:00
package firmwareconformance
import (
"encoding/json"
"strings"
"testing"
"time"
)
func TestEvaluateABRollbackEvidence(t *testing.T) {
cloud, device := rollbackFixture()
report := Evaluate(cloud, device, time.Date(2026, 8, 25, 2, 0, 0, 0, time.UTC))
if report.Result != "PASS" || report.EvidenceScope != "PROTOCOL_SIMULATION" || report.CloudEventCount != 4 || len(report.Checks) < 10 {
t.Fatalf("report=%+v", report)
}
device.FinalVersion = "3.1.0"
report = Evaluate(cloud, device, time.Now())
if report.Result != "FAIL" {
t.Fatalf("mismatched rollback version passed: %+v", report)
}
found := false
for _, check := range report.Checks {
if check.Code == "VERSION_TRANSITION" && check.Status == "FAIL" {
found = true
}
}
if !found {
t.Fatal("version mismatch was not identified")
}
}
func TestParseCloudEnvelopeAndStrictDeviceEvidence(t *testing.T) {
cloud, device := rollbackFixture()
cloudJSON, _ := json.Marshal(map[string]any{"request_id": "request-1", "data": cloud})
parsed, err := ParseCloud(cloudJSON)
if err != nil || parsed.ID != cloud.ID {
t.Fatalf("parsed cloud=%+v err=%v", parsed, err)
}
deviceJSON, _ := json.Marshal(device)
if _, err := ParseDeviceEvidence(deviceJSON); err != nil {
t.Fatalf("valid evidence error=%v", err)
}
var payload map[string]any
_ = json.Unmarshal(deviceJSON, &payload)
payload["unexpected_secret"] = "must-not-be-accepted"
invalid, _ := json.Marshal(payload)
if _, err := ParseDeviceEvidence(invalid); err == nil {
t.Fatal("unknown device evidence field was accepted")
}
}
func TestParseReportRejectsUnknownFields(t *testing.T) {
t.Parallel()
if _, err := ParseReport([]byte(`{"schema_version":"firmware-conformance-report-v1","unknown":true}`)); err == nil {
t.Fatal("unknown firmware report field was accepted")
}
}
func rollbackFixture() (CloudRollout, DeviceEvidence) {
base := time.Date(2026, 8, 25, 1, 0, 0, 0, time.UTC)
deviceID := "10000000-0000-0000-0000-000000000511"
releaseID := "20000000-0000-0000-0000-000000000001"
commandID := "30000000-0000-0000-0000-000000000001"
bootAttemptID := "boot-attempt-1"
phases := []string{"staging", "reboot_pending", "boot_verifying", "rolled_back"}
cloudEvents := make([]CloudEvent, 0, len(phases))
deviceEvents := make([]DeviceEvent, 0, len(phases))
for index, phase := range phases {
commandStatus, assignmentStatus := "ACKNOWLEDGED", "INSTALLING"
if phase == "rolled_back" {
commandStatus, assignmentStatus = "FAILED", "FAILED"
}
reported := base.Add(time.Duration(index) * time.Minute)
event := CloudEvent{
ID: "40000000-0000-0000-0000-00000000000" + string(rune('1'+index)), CommandID: commandID,
CommandStatus: commandStatus, AssignmentStatus: assignmentStatus, Phase: phase, ResultDigest: strings.Repeat(string(rune('a'+index)), 64),
ReportedAt: reported, BootAttemptID: bootAttemptID,
}
if phase == "staging" {
event.ActiveSlot, event.TargetSlot = "A", "B"
event.VerifiedSHA256, event.VerifiedSigningKeyID = strings.Repeat("d", 64), "sim-key"
}
if phase == "rolled_back" {
rollbackApplied := true
event.RollbackApplied = &rollbackApplied
event.RollbackVersion = "0.2.0-sim"
event.ActiveSlot, event.FailedSlot = "A", "B"
}
cloudEvents = append(cloudEvents, event)
deviceEvents = append(deviceEvents, DeviceEvent{Phase: phase, OccurredAt: reported.Add(-2 * time.Second), ActiveSlot: event.ActiveSlot, TargetSlot: event.TargetSlot, BootAttemptID: bootAttemptID})
}
cloud := CloudRollout{
ID: "50000000-0000-0000-0000-000000000001", ReleaseID: releaseID, Status: "PAUSED",
Assignments: []CloudAssignment{{DeviceID: deviceID, DeviceModel: "simulated-terminal", PreviousVersion: "0.2.0-sim", Status: "FAILED", Events: cloudEvents}},
}
device := DeviceEvidence{
SchemaVersion: DeviceEvidenceSchema, EvidenceSource: "SIMULATOR", CandidateVersion: "candidate-1", BuildDigest: "sha256:" + strings.Repeat("b", 64),
DeviceID: deviceID, DeviceModel: "simulated-terminal", HardwareRevision: "sim-rev-a", ReleaseID: releaseID, CommandID: commandID, Scenario: "AB_ROLLBACK",
BootloaderVersion: "sim-boot-1", PartitionTableSHA256: strings.Repeat("c", 64), SecureBootEnabled: false,
ArtifactSHA256: strings.Repeat("d", 64), SigningKeyID: "sim-key", InitialSlot: "A", TargetSlot: "B", FinalSlot: "A",
InitialVersion: "0.2.0-sim", TargetVersion: "3.1.0", FinalVersion: "0.2.0-sim", BootAttemptID: bootAttemptID,
CollectedAt: base.Add(10 * time.Minute), Events: deviceEvents,
}
return cloud, device
}