package hostbox import ( "context" "database/sql" "errors" "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/genselect" ) func TestColdRestoreEnrollmentPrecedesEveryMutation(t *testing.T) { for _, empty := range []bool{false, true} { for _, refuse := range []string{"", "legacy", "enroll"} { t.Run(map[bool]string{false: "baseline", true: "empty"}[empty]+"/"+refuse, func(t *testing.T) { db := filepath.Join(t.TempDir(), "legacy.db") legacy := []byte("legacy database") if err := os.WriteFile(db, legacy, 0600); err != nil { t.Fatal(err) } work := &restoreWork{} key, body, crc := snapshotFixture(t, "production-restore") rd := &restoreReader{data: map[string][]byte{key + "@v1": body}} plan := &genselect.Plan{Generation: "baseline", MaxTXID: 1, Pin: &genselect.Pin{SnapshotCRC64: crc}, Files: []genselect.File{{Key: key, VersionID: "v1", Level: 9, MinTXID: 1, MaxTXID: 1, Size: int64(len(body))}}} var calls []string failure := errors.New("injected enrollment refusal") r := ColdRestore{Reader: rd, Bucket: "bucket", Generation: "new", Work: work, BeforeLegacyInstall: func(_ context.Context, path, generation string) error { if work.active || path != db || generation != "new" { t.Fatal("legacy callback boundary") } calls = append(calls, "legacy") if refuse == "legacy" { return failure } if string(mustRead(t, db)) != string(legacy) { t.Fatal("legacy source changed before parking") } // Explicit parking seam; root identity/retention belongs to the host tests. return os.Rename(db, db+".parked") }, BeforeInstallLocked: func(_ context.Context, path, generation string) error { if !work.active || path != db || generation != "new" { t.Fatal("enrollment callback boundary") } calls = append(calls, "enroll") if _, err := os.Stat(db); !errors.Is(err, os.ErrNotExist) { t.Fatal("database appeared before enrollment") } if _, err := os.Stat(db + ".gen"); !errors.Is(err, os.ErrNotExist) { t.Fatal("marker appeared before enrollment") } if refuse == "enroll" { return failure } return nil }} var err error if empty { err = r.InstallEmpty(t.Context(), db, func(context.Context) error { return nil }) } else { err = r.Install(t.Context(), db, plan) } if refuse != "" { if !errors.Is(err, failure) { t.Fatalf("refusal: %v", err) } if _, err := os.Stat(db + ".gen"); !errors.Is(err, os.ErrNotExist) { t.Fatal("refused enrollment wrote marker") } if refuse == "legacy" { if string(mustRead(t, db)) != string(legacy) { t.Fatal("refusal destroyed legacy database") } } else if string(mustRead(t, db+".parked")) != string(legacy) { t.Fatal("refusal destroyed park") } return } if err != nil { t.Fatal(err) } if len(calls) != 2 || calls[0] != "legacy" || calls[1] != "enroll" { t.Fatalf("callbacks %v", calls) } if string(mustRead(t, db+".gen")) != "new\n" { t.Fatal("missing successor marker") } if empty { if _, err := os.Stat(db); !errors.Is(err, os.ErrNotExist) { t.Fatal("empty restore wrote a database") } return } check, err := sql.Open("sqlite", db) if err != nil { t.Fatal(err) } defer check.Close() var value string if err := check.QueryRow("SELECT value FROM fixture").Scan(&value); err != nil || value != "production-restore" { t.Fatalf("restored %q: %v", value, err) } }) } } }