carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux && rootrunner
2
3package host
4
5import (
6 "errors"
7 "os"
8 "path/filepath"
9 "testing"
10
11 "github.com/carlosframework/platform/internal/rootstate"
12 "golang.org/x/sys/unix"
13)
14
15// Real rootstate locks, same-bind deletion and metadata collection; claim,
16// receipt, tenant-start and completion authorization remain explicit fixtures.
17func TestRootServingParkCollection(t *testing.T) {
18 servingRootRunner(t)
19 root, err := os.MkdirTemp("/var/lib", "carlos-rootrunner-collection-")
20 if err != nil {
21 t.Fatal(err)
22 }
23 t.Cleanup(func() {
24 if err := os.RemoveAll(root); err != nil {
25 t.Error(err)
26 }
27 })
28 t.Setenv("TMPDIR", root)
29 for _, lost := range []bool{false, true} {
30 t.Run(map[bool]string{false: "ordinary", true: "lost-record-remove-reply"}[lost], func(t *testing.T) {
31 f := newServingParkDiskFixture(t)
32 servingRunnerMount(t, f.data)
33 state, err := rootstate.Open(filepath.Join(t.TempDir(), "authority"), true, false)
34 if err != nil {
35 t.Fatal(err)
36 }
37 t.Cleanup(func() {
38 if err := state.Close(); err != nil {
39 t.Error(err)
40 }
41 })
42 f.fs = newServingParkFS(f.data, state)
43 f.ledger.fs, f.ledger.state = f.fs, state
44 f.put("", "legacy bytes")
45 old, receipts := f.evidence(10, true, "missing")
46 if _, err = f.park(old, receipts); err != nil {
47 t.Fatal(err)
48 }
49 f.complete(old)
50 f.put("", "latest served bytes")
51 f.put(".gen", "G11")
52 next, receipts := f.evidence(11, false, "started")
53 if _, err = f.park(next, receipts); err != nil {
54 t.Fatal(err)
55 }
56 f.complete(next)
57 if err = f.ledger.recoverCompleted(t.Context(), old.ID); err != nil {
58 t.Fatal(err)
59 }
60 r, err := f.ledger.read(old.ID)
61 if err != nil || r.CollectAfter.IsZero() {
62 t.Fatal("no replay window", err)
63 }
64 f.now = r.CollectAfter
65 prep := "reboot-" + old.ID + "-" + servingOtherBoot + ".json"
66 if err := state.Write(prep, []byte("{}")); err != nil {
67 t.Fatal(err)
68 }
69 if lost {
70 fault := &servingCollectionFaultStore{Store: state}
71 fault.remove = func(name string) error {
72 if err := state.Remove(name); err != nil {
73 return err
74 }
75 if name == "retirement-"+old.ID+".json" {
76 return unix.EIO
77 }
78 return nil
79 }
80 f.ledger.state = fault
81 }
82 err = f.ledger.recoverCompleted(t.Context(), old.ID)
83 if lost && !errors.Is(err, unix.EIO) || !lost && err != nil {
84 t.Fatal("collection", err)
85 }
86 f.ledger.state = state
87 if _, err := state.Read(prep); !errors.Is(err, os.ErrNotExist) {
88 t.Fatal("preparation survived collection", err)
89 }
90 binding := "current-retirement-" + old.ID + ".json"
91 if err := state.Write(binding, []byte("{}")); err != nil {
92 t.Fatal(err)
93 }
94 if err := f.ledger.maintainParks(t.Context(), func() error { return nil }); err != nil {
95 t.Fatal(err)
96 }
97 if _, err := state.Read(binding); !errors.Is(err, os.ErrNotExist) {
98 t.Fatal("binding survived maintenance", err)
99 }
100 for _, suffix := range []string{".json", ".lock"} {
101 if _, err = state.Read("retirement-" + old.ID + suffix); !errors.Is(err, os.ErrNotExist) {
102 t.Fatal("collected file survived", suffix, err)
103 }
104 }
105 consumed, err := f.ledger.legacyConsumption(old.Successor)
106 if err != nil || consumed == nil || !consumed.Collected {
107 t.Fatal("lost permanent legacy consumption", err)
108 }
109 ids, more, err := f.ledger.recoveryIDs(t.Context(), "", servingParkRecoveryLimit)
110 if err != nil || more || len(ids) != 1 || ids[0] != next.ID {
111 t.Fatal("restart rediscovered obsolete record", ids, more, err)
112 }
113 f.retained(next, "latest served bytes", r.ReapAfter)
114 })
115 }
116}
117