package main import ( "context" "crypto/sha256" "encoding/hex" "encoding/json" "path/filepath" "testing" "time" "git.yuntuo.hk/k2safe/orbit/internal/retention" core "git.yuntuo.hk/k2safe/orbit/model" ) func TestRetentionArchiveValidationBeforeDatabase(t *testing.T) { t.Setenv("ORBIT_MYSQL_DSN", "") for _, args := range [][]string{ {}, {"--directory", "relative"}, {"--directory", t.TempDir(), "--namespace", "invalid"}, {"--directory", t.TempDir(), "--namespace", "11111111111111111111111111111111", "--kind", "tasks", "--revision", "1", "--max-batches", "0"}, } { if err := runRetentionArchive(args); err == nil { t.Fatalf("invalid args accepted: %v", args) } } } func TestVerifyArchiveOfflinePinsDigest(t *testing.T) { t.Setenv("ORBIT_MYSQL_DSN", "") dir := filepath.Join(t.TempDir(), "job") ns := core.ID("11111111111111111111111111111111") spec := retention.JobSpec{NamespaceID: ns, Kind: "tasks", PolicyRevision: 1, BatchSize: 1} status, err := retention.RunArchive(context.Background(), dir, spec, retention.JobOptions{MaxBatches: 1, MaxBytes: 1 << 20}, func(ctx context.Context, id core.ID, input retention.ArchiveInput) (retention.ArchiveSnapshot, error) { policy := retention.Defaults(ns) policy.Enabled = true policy.Revision = 1 raw, err := json.Marshal(map[string]any{"policy": policy, "kind": "tasks", "cutoff": time.Now().UTC(), "root_count": 0, "source_retained": true, "next_cursor": ""}) digest := sha256.Sum256(raw) return retention.ArchiveSnapshot{FormatVersion: 1, SHA256: hex.EncodeToString(digest[:]), Content: string(raw)}, err }) if err != nil { t.Fatal(err) } if err := runRetentionVerifyArchive([]string{"--directory", dir, "--expected-sha256", status.LastSHA256}); err != nil { t.Fatal(err) } if err := runRetentionVerifyArchive([]string{"--directory", dir, "--expected-sha256", "0000000000000000000000000000000000000000000000000000000000000000"}); err == nil { t.Fatal("trusted digest mismatch accepted") } }