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 "os"
5 "strings"
6 "testing"
7
8 "github.com/carlosframework/platform/internal/release"
9)
10
11func TestPlan14IndependentRecoveryRetainsMintBarrier(t *testing.T) {
12 e, u, c, source, pub := signedRecoveryFixture(t)
13 rt, err := e.root.reg.Get(observedHost)
14 if err != nil {
15 t.Fatal(err)
16 }
17 h := seedHostRootHistory(t, *rt)
18 b := release.HistoryBinding{Host: rt.Host, Account: rt.Account, App: rt.App}
19 u.crashNew = true
20 n := namedUnitRecovery{source: source, pub: pub, readLive: os.Readlink}
21 if _, err := n.recover(t.Context(), rt.Host, c, func(string) string { return "5s" }, e.root.reg); err == nil {
22 t.Fatal("failed forward repair reported success")
23 }
24 if refs, err := c.mintRefusals(h, b); err != nil || len(refs) != 1 || refs[0].Version != "v2" {
25 t.Fatalf("recovery denial lost: %+v %v", refs, err)
26 }
27 if err := checkedUnitRestart(u, u.opt, func(string) string { return "5s" }, nil, c)(*rt); err != nil {
28 t.Fatal(err)
29 }
30 if refs, err := c.mintRefusals(h, b); err != nil || len(refs) != 1 || refs[0].Version != "v2" {
31 t.Fatalf("ordinary restart erased recovery denial: %+v %v", refs, err)
32 }
33 disk, err := c.attempts()
34 if err != nil {
35 t.Fatal(err)
36 }
37 names, err := disk.Names()
38 if err != nil {
39 t.Fatal(err)
40 }
41 for _, name := range names {
42 if strings.HasSuffix(name, ".recovery") {
43 if err := disk.Remove(name); err != nil {
44 t.Fatal(err)
45 }
46 }
47 }
48 if refs, err := c.mintRefusals(h, b); err != nil || len(refs) != 1 || refs[0].SHA256 == "" {
49 t.Fatalf("removing old recovery erased retained digest: %+v %v", refs, err)
50 }
51 foreign := b
52 foreign.App = "another"
53 if err := c.retainRecoveryHistory(h, foreign); err != nil {
54 t.Fatalf("unrelated app blocked: %v", err)
55 }
56}
57
58func TestPlan14RecoveryMintEvidence(t *testing.T) {
59 for _, state := range []string{"verified", "pending", "malformed", "unsynced"} {
60 t.Run(state, func(t *testing.T) {
61 e, _, c, source, pub := signedRecoveryFixture(t)
62 rt, err := e.root.reg.Get(observedHost)
63 if err != nil {
64 t.Fatal(err)
65 }
66 h := seedHostRootHistory(t, *rt)
67 n := namedUnitRecovery{source: source, pub: pub, readLive: os.Readlink}
68 if _, err := n.recover(t.Context(), rt.Host, c, func(string) string { return "5s" }, e.root.reg); err != nil {
69 t.Fatal(err)
70 }
71 s, err := c.attempts()
72 if err != nil {
73 t.Fatal(err)
74 }
75 a, err := readRollbackAttempt(s, rt.Host)
76 if err != nil {
77 t.Fatal(err)
78 }
79 switch state {
80 case "pending":
81 a.Settled = false
82 if err := writeRollbackState(s, rollbackJournalKey(rt.Host), a); err != nil {
83 t.Fatal(err)
84 }
85 case "malformed":
86 if err := s.Write(recoveryResultKey(a), []byte("{")); err != nil {
87 t.Fatal(err)
88 }
89 case "unsynced":
90 s.(*rollbackMemory).failWrite = true
91 }
92 refs, err := c.mintRefusals(h, release.HistoryBinding{Host: rt.Host, Account: rt.Account, App: rt.App})
93 if state == "verified" {
94 if err != nil || len(refs) != 0 {
95 t.Fatalf("verified recovery blocked mint: %+v %v", refs, err)
96 }
97 } else if err == nil {
98 t.Fatalf("%s granted mint", state)
99 }
100 })
101 }
102}
103
104func TestPlan14IndependentRecoveryRecordsHistory(t *testing.T) {
105 for _, state := range []string{"success", "rollback", "failed rollback"} {
106 failed := state != "success"
107 t.Run(state, func(t *testing.T) {
108 e, u, c, source, pub := signedRecoveryFixture(t)
109 rt, err := e.root.reg.Get(observedHost)
110 if err != nil {
111 t.Fatal(err)
112 }
113 h := seedHostRootHistory(t, *rt)
114 c.history = func() (*release.RootHistoryPass, error) { return &release.RootHistoryPass{History: h}, nil }
115 u.crashNew = failed
116 u.badRollback = state == "failed rollback"
117 n := namedUnitRecovery{source: source, pub: pub, readLive: os.Readlink}
118 handled, err := n.recover(t.Context(), observedHost, c, func(string) string { return "5s" }, e.root.reg)
119 if !handled || (err != nil) != failed {
120 t.Fatalf("outcome: %v %v", handled, err)
121 }
122 disk, err := c.attempts()
123 if err != nil {
124 t.Fatal(err)
125 }
126 a, err := readRollbackAttempt(disk, observedHost)
127 if err != nil || !a.Settled || a.Verified != (state != "failed rollback") {
128 t.Fatalf("wrong retained verification: %+v %v", a, err)
129 }
130 refs, err := h.Refusals(release.HistoryBinding{Host: rt.Host, Account: rt.Account, App: rt.App})
131 if err != nil || len(refs) != map[bool]int{false: 0, true: 1}[failed] {
132 t.Fatalf("settlement did not retain outcome: %+v %v", refs, err)
133 }
134 })
135 }
136}
137