carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5 "encoding/json"
6 "github.com/carlosframework/platform/internal/rootparticipation"
7 "os"
8 "path/filepath"
9 "testing"
10)
11
12func updateParticipationFixture(t *testing.T) *rootparticipation.Ledger {
13 t.Helper()
14 disk := &rollbackDisk{dir: t.TempDir()}
15 raw, _ := json.Marshal(rootparticipation.Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true})
16 if err := disk.Write("census.json", raw); err != nil {
17 t.Fatal(err)
18 }
19 return &rootparticipation.Ledger{State: disk, VerifyLaunches: func(context.Context, uint64) error { return nil }, ExcludeLaunches: func(ctx context.Context, fn func(context.Context) error) error { return fn(ctx) }}
20}
21
22func TestPlan14ExecutionSystemUpdateExclusion(t *testing.T) {
23 for _, pending := range []bool{false, true} {
24 t.Run(map[bool]string{true: "participating", false: "empty"}[pending], func(t *testing.T) {
25 f := newApplyFixture(t, "stable", "old")
26 f.a.regionHA = true
27 f.a.participation = updateParticipationFixture(t)
28 if pending {
29 if err := f.a.participation.State.Write("shop.example.json", []byte("{\"Schema\":1,\"Status\":\"pending\"}")); err != nil {
30 t.Fatal(err)
31 }
32 }
33 mirror := filepath.Join(f.a.dataDir, ".hostexec")
34 if err := os.MkdirAll(mirror, 0700); err != nil {
35 t.Fatal(err)
36 }
37 if err := os.Remove(mirror); err != nil {
38 t.Fatal(err)
39 }
40 err := f.a.beginExecutableChange(t.Context(), "new", f.now)
41 if pending {
42 if err == nil {
43 t.Fatal("system update trusted deleted agent state")
44 }
45 return
46 }
47 if err != nil {
48 t.Fatal(err)
49 }
50 if err := f.a.participation.Acquire(t.Context(), func() error { return nil }); err == nil {
51 t.Fatal("acquisition crossed durable system update")
52 }
53 f.a.settleUpdateBegun(t.Context())
54 if err := f.a.participation.Acquire(t.Context(), func() error { return nil }); err != nil {
55 t.Fatal("settled update still excludes", err)
56 }
57 })
58 }
59}
60
61func TestPlan14ExecutionRecoveryWithoutArmedFloor(t *testing.T) {
62 for _, recoverable := range []bool{false, true} {
63 t.Run(map[bool]string{false: "unresolved", true: "settled"}[recoverable], func(t *testing.T) {
64 f := newApplyFixture(t, "stable", "old")
65 if f.a.guarded() {
66 t.Fatal("fixture has an armed floor")
67 }
68 if err := f.a.beginExecutableChange(t.Context(), "new", f.now); err != nil {
69 t.Fatal(err)
70 }
71 if err := f.a.participation.State.Write("shop.example.json", []byte(`{"Schema":1,"Status":"lost"}`)); err != nil {
72 t.Fatal(err)
73 }
74 old := recoverPendingControllers
75 t.Cleanup(func() { recoverPendingControllers = old })
76 calls := 0
77 recoverPendingControllers = func(_ context.Context, data, guard string) error {
78 calls++
79 if data != f.a.dataDir || guard != systemGuardDir(f.a.optDir) {
80 t.Fatal("wrong recovery scope")
81 }
82 if !recoverable {
83 return rootparticipation.ErrUnavailable
84 }
85 return f.a.participation.State.Remove("shop.example.json")
86 }
87 err := f.a.checkGuardRecovery(t.Context())
88 if (err == nil) != recoverable || calls != 1 {
89 t.Fatalf("recovery=%t calls=%d err=%v", recoverable, calls, err)
90 }
91 if _, err := f.a.participation.UpdateID(); err != nil {
92 t.Fatal("recovery removed update exclusion", err)
93 }
94 })
95 }
96}
97
98func TestPlan14ExecutionLegacyJournalRecoversBeforeReservation(t *testing.T) {
99 f := newApplyFixture(t, "stable", "old")
100 if err := f.a.journal(systemJournal{Phase: systemPhaseInstalling, Target: "new"}); err != nil {
101 t.Fatal(err)
102 }
103 if err := f.a.participation.State.Write("shop.example.json", []byte(`{"Schema":1,"Status":"lost"}`)); err != nil {
104 t.Fatal(err)
105 }
106 old := recoverPendingControllers
107 t.Cleanup(func() { recoverPendingControllers = old })
108 calls := 0
109 recoverPendingControllers = func(context.Context, string, string) error {
110 calls++
111 return f.a.participation.State.Remove("shop.example.json")
112 }
113 if err := f.a.checkGuardRecovery(t.Context()); err != nil {
114 t.Fatal(err)
115 }
116 if calls != 1 {
117 t.Fatalf("recovery calls=%d", calls)
118 }
119 if _, err := f.a.participation.UpdateID(); err != nil {
120 t.Fatal("legacy journal lacked root exclusion", err)
121 }
122}
123