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 "bytes"
5 "os"
6 "testing"
7
8 "github.com/carlosframework/platform/internal/hostwrite"
9 "github.com/carlosframework/platform/internal/release"
10)
11
12func TestPlan14ERecoveryNoCensus(t *testing.T) {
13 for _, state := range []string{"active", "failed", "inactive"} {
14 for _, flag := range []bool{false, true} {
15 t.Run(state+map[bool]string{false: "/flag off", true: "/flag on"}[flag], func(t *testing.T) {
16 e, u, c, source, pub := signedRecoveryFixture(t)
17 c.legacy = func() (bool, error) { return true, nil }
18 c.legacyReady = c.ready
19 if state != "active" {
20 u.props.ActiveState, u.props.MainPID = state, 0
21 }
22 n := namedUnitRecovery{source: source, pub: pub, readLive: os.Readlink, writes: hostwrite.Config{Enabled: flag, Selector: namedRecoveryWork{}}}
23 handled, err := n.recover(t.Context(), observedHost, c, func(string) string { return "5s" }, e.root.reg)
24 live, liveErr := release.LiveVersion(u.opt, observedHost)
25 if handled || err != nil || liveErr != nil || live != "v1" || len(u.effects) != 0 {
26 t.Fatalf("no-census recovery drove an effect: handled=%v err=%v live=%s/%v effects=%v", handled, err, live, liveErr, u.effects)
27 }
28 disk, _ := c.attempts()
29 if names, err := disk.Names(); err != nil || len(names) != 0 {
30 t.Fatalf("recovery created authority: %v %v", names, err)
31 }
32 })
33 }
34 }
35}
36
37func TestPlan14ERecoveryNoCensusResume(t *testing.T) {
38 for _, independent := range []bool{false, true} {
39 t.Run(map[bool]string{false: "linked", true: "independent"}[independent], func(t *testing.T) {
40 e, u, c, _, _ := signedRecoveryFixture(t)
41 b, err := c.host(t.Context(), observedHost)
42 if err != nil {
43 t.Fatal(err)
44 }
45 disk, err := c.attempts()
46 if err != nil {
47 t.Fatal(err)
48 }
49 target := release.VersionPath(u.opt, b.Route.Account, "v2", b.Route.App)
50 a, err := captureRollback(disk, b, c.now(), unitSettleTimeout(func(string) string { return "5s" }), target, c.identity, historyRollbackLink{Binding: release.HistoryBinding{Host: b.Route.Host, Account: b.Route.Account, App: b.Route.App}, Attempt: release.HistoryAttempt{ID: "linked", Source: b.Source, Version: "v2", SHA256: "failed-digest", Platform: release.AdoptPlatform(), Started: c.now(), PromotedAt: c.now()}, Independent: independent})
51 if err != nil {
52 t.Fatal(err)
53 }
54 if err := release.StageArtifact(u.opt, b.Route.Account, "v2", b.Route.App, []byte("new build")); err != nil {
55 t.Fatal(err)
56 }
57 if err := release.PointLive(u.opt, observedHost, b.Route.Account, "v2", b.Route.App); err != nil {
58 t.Fatal(err)
59 }
60 u.props.ActiveState, u.props.MainPID = "failed", 0
61 before, err := disk.Read(rollbackJournalKey(a.Host))
62 if err != nil {
63 t.Fatal(err)
64 }
65 rt, _ := e.root.reg.Get(observedHost)
66 h := seedHostRootHistory(t, *rt)
67 c.history = func() (*release.RootHistoryPass, error) { return &release.RootHistoryPass{History: h}, nil }
68 c.legacy = func() (bool, error) { return true, nil }
69 if err := resumeHistoryRestart(t.Context(), u, u.opt, func(string) string { return "5s" }, c, hostwrite.Config{}, disk, a); err != nil {
70 t.Fatal(err)
71 }
72 after, err := disk.Read(rollbackJournalKey(a.Host))
73 if err != nil {
74 t.Fatal(err)
75 }
76 live, err := release.LiveVersion(u.opt, observedHost)
77 if err != nil || live != "v2" || len(u.effects) != 0 || !bytes.Equal(before, after) {
78 t.Fatalf("resume changed effects/evidence: live=%s/%v effects=%v journalChanged=%v", live, err, u.effects, !bytes.Equal(before, after))
79 }
80 if independent {
81 if _, err := h.Refusals(a.HistoryBinding); err == nil {
82 t.Fatal("no-census observation lost pending evidence")
83 }
84 if _, err := c.mintRefusals(h, a.HistoryBinding); err == nil {
85 t.Fatal("pending recovery granted mint")
86 }
87 }
88 })
89 }
90}
91
92func TestPlan14ERecoveryOrdinaryNoCensusRead(t *testing.T) {
93 e, _, c, source, pub := signedRecoveryFixture(t)
94 rt, err := e.root.reg.Get(observedHost)
95 if err != nil {
96 t.Fatal(err)
97 }
98 rt.Unit = ""
99 if err := e.root.reg.Delete(rt.Host); err != nil {
100 t.Fatal(err)
101 }
102 if err := e.root.reg.Upsert(*rt); err != nil {
103 t.Fatal(err)
104 }
105 c.legacy = func() (bool, error) { t.Fatal("ordinary E recovery read census"); return true, nil }
106 n := namedUnitRecovery{source: source, pub: pub, readLive: os.Readlink}
107 if handled, err := n.recover(t.Context(), observedHost, c, func(string) string { return "5s" }, e.root.reg); handled || err != nil {
108 t.Fatalf("ordinary recovery: %v %v", handled, err)
109 }
110}
111