carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package release
2
3import (
4 "context"
5 "encoding/base64"
6 "encoding/json"
7 "os"
8 "os/exec"
9 "path/filepath"
10 "testing"
11 "time"
12
13 "github.com/carlosframework/platform/internal/registry"
14)
15
16type historyPassCrashStore struct {
17 *healthyRetryStore
18 boundary string
19 armed bool
20}
21
22func (s *historyPassCrashStore) Write(key string, raw []byte) error {
23 if err := s.healthyRetryStore.Write(key, raw); err != nil {
24 return err
25 }
26 var r historyRecord
27 if json.Unmarshal(raw, &r) == nil && r.Binding.Host != "" {
28 if r.Attempt != nil {
29 s.armed = true
30 if s.boundary == "intent" {
31 os.Exit(91)
32 }
33 } else if s.armed && s.boundary == "settled" {
34 os.Exit(91)
35 }
36 }
37 return nil
38}
39
40func TestPlan14RootHistoryPassProcessCrash(t *testing.T) {
41 if dir := os.Getenv("CARLOS_TEST_HISTORY_PASS_DIR"); dir != "" {
42 boundary := os.Getenv("CARLOS_TEST_HISTORY_PASS_BOUNDARY")
43 b := HistoryBinding{Host: proofHost, Account: "bab", App: "console"}
44 h := &RootHistory{Store: &historyPassCrashStore{healthyRetryStore: &healthyRetryStore{dir: filepath.Join(dir, "state")}, boundary: boundary}}
45 pub, err := ParsePublicKey(os.Getenv("CARLOS_TEST_HISTORY_PASS_PUB"), "test")
46 if err != nil {
47 t.Fatal(err)
48 }
49 reg, err := registry.Open(filepath.Join(dir, "registry.db"))
50 if err != nil {
51 t.Fatal(err)
52 }
53 defer reg.Close()
54 deps := &RootHistoryPass{History: h, Resolve: func(context.Context, registry.Route) (HistoryBinding, string, error) { return b, "record", nil }, Installed: func(context.Context, registry.Route, string) (string, error) { return "", nil }}
55 err = Pass(context.Background(), reg, NewDirStore(filepath.Join(dir, "store")), pub, filepath.Join(dir, "opt"), func(string) error {
56 if boundary == "restart" {
57 os.Exit(91)
58 }
59 return nil
60 }, BakeDir(filepath.Join(dir, "legacy")), WithRootHistory(deps))
61 if err != nil {
62 t.Fatal(err)
63 }
64 t.Fatal("crash boundary was not reached")
65 }
66 for _, boundary := range []string{"intent", "restart", "settled"} {
67 t.Run(boundary, func(t *testing.T) {
68 dir := t.TempDir()
69 if err := os.MkdirAll(filepath.Join(dir, "state"), 0700); err != nil {
70 t.Fatal(err)
71 }
72 h, _, b := rootHistoryFixture(t)
73 r, err := h.read(b)
74 if err != nil {
75 t.Fatal(err)
76 }
77 h.Store = &healthyRetryStore{dir: filepath.Join(dir, "state")}
78 if err := h.write(r); err != nil {
79 t.Fatal(err)
80 }
81 seedRootBake(t, h, b, time.Now().UTC().Add(-time.Hour))
82 reg, err := registry.Open(filepath.Join(dir, "registry.db"))
83 if err != nil {
84 t.Fatal(err)
85 }
86 addRoute(t, reg, b.Host, b.App, "canary/x", false)
87 if err := reg.Close(); err != nil {
88 t.Fatal(err)
89 }
90 st := NewDirStore(filepath.Join(dir, "store"))
91 priv, pub := testKeys(t)
92 shipRelease(t, st, b.Account, b.App, "new", adoptPlatform, []byte("new"))
93 if err := Promote(context.Background(), st, priv, b.Account, b.App, "canary/x", "new"); err != nil {
94 t.Fatal(err)
95 }
96 cmd := exec.Command(os.Args[0], "-test.run=^TestPlan14RootHistoryPassProcessCrash$")
97 cmd.Dir = dir
98 cmd.Env = append(os.Environ(), "CARLOS_TEST_HISTORY_PASS_DIR="+dir, "CARLOS_TEST_HISTORY_PASS_BOUNDARY="+boundary, "CARLOS_TEST_HISTORY_PASS_PUB="+base64.StdEncoding.EncodeToString(pub))
99 out, err := cmd.CombinedOutput()
100 if exit, ok := err.(*exec.ExitError); !ok || exit.ExitCode() != 91 {
101 t.Fatalf("child: %v\n%s", err, out)
102 }
103 r, err = h.read(b)
104 if err != nil {
105 t.Fatal(err)
106 }
107 live, _ := LiveVersion(filepath.Join(dir, "opt"), b.Host)
108 if boundary == "settled" {
109 if r.Attempt != nil || live != "new" {
110 t.Fatal("settled result lost")
111 }
112 } else {
113 if r.Attempt == nil {
114 t.Fatal("interrupted adoption lost its attempt")
115 }
116 if _, err := h.Refusals(b); err == nil {
117 t.Fatal("interrupted adoption allowed mint")
118 }
119 if boundary == "intent" && live != "" {
120 t.Fatal("link changed before durable intent")
121 }
122 if boundary == "restart" && live != "new" {
123 t.Fatal("did not crash after live-link change")
124 }
125 }
126 })
127 }
128}
129