carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package rootparticipation
2
3import (
4 "context"
5 "encoding/json"
6 "os"
7 "path/filepath"
8 "sync"
9 "testing"
10)
11
12type testDisk struct {
13 dir string
14 mu sync.Mutex
15}
16
17func (d *testDisk) Read(n string) ([]byte, error) { return os.ReadFile(filepath.Join(d.dir, n)) }
18func (d *testDisk) Write(n string, b []byte) error {
19 return os.WriteFile(filepath.Join(d.dir, n), b, 0600)
20}
21func (d *testDisk) Remove(n string) error { return os.Remove(filepath.Join(d.dir, n)) }
22func (d *testDisk) Names() ([]string, error) {
23 es, e := os.ReadDir(d.dir)
24 var out []string
25 for _, v := range es {
26 out = append(out, v.Name())
27 }
28 return out, e
29}
30func (d *testDisk) Close() error { return nil }
31func (d *testDisk) Lock(context.Context, string) (func(), error) {
32 d.mu.Lock()
33 return d.mu.Unlock, nil
34}
35func censusFixture(t *testing.T) Ledger {
36 t.Helper()
37 s := &testDisk{dir: t.TempDir()}
38 b, _ := json.Marshal(Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, Complete: true, LaunchRevision: 1})
39 if err := s.Write("census.json", b); err != nil {
40 t.Fatal(err)
41 }
42 return Ledger{State: s, Box: "box", Enrollment: "en", VerifyLaunches: func(context.Context, uint64) error { return nil }}
43}
44
45func TestPlan14ExecutionUpdateExclusion(t *testing.T) {
46 for _, first := range []string{"acquisition", "update"} {
47 t.Run(first, func(t *testing.T) {
48 l := censusFixture(t)
49 entered, release := make(chan struct{}), make(chan struct{})
50 acquire := func() error {
51 return l.Acquire(t.Context(), func() error {
52 close(entered)
53 <-release
54 return l.State.Write("shop.example.json", []byte(`{"Schema":1,"Status":"pending"}`))
55 })
56 }
57 update := func() error { return l.BeginUpdate(t.Context(), "update-1") }
58 var winner, loser func() error
59 if first == "acquisition" {
60 winner, loser = acquire, update
61 } else {
62 l.VerifyLaunches = func(context.Context, uint64) error { close(entered); <-release; return nil }
63 winner, loser = update, acquire
64 }
65 done := make(chan error, 1)
66 go func() { done <- winner() }()
67 <-entered
68 other := make(chan error, 1)
69 go func() { other <- loser() }()
70 // Removing every service mirror cannot change the root transaction.
71 data := t.TempDir()
72 if err := os.Mkdir(filepath.Join(data, ".hostexec"), 0700); err != nil {
73 t.Fatal(err)
74 }
75 if err := os.RemoveAll(filepath.Join(data, ".hostexec")); err != nil {
76 t.Fatal(err)
77 }
78 close(release)
79 if err := <-done; err != nil {
80 t.Fatal(err)
81 }
82 if err := <-other; err == nil {
83 t.Fatal("update and acquisition both succeeded")
84 }
85 })
86 }
87}
88func TestPlan14ParticipationRequiresCompleteRootCensus(t *testing.T) {
89 l := censusFixture(t)
90 if err := l.Idle(t.Context()); err != nil {
91 t.Fatal(err)
92 }
93 if err := l.State.Remove("census.json"); err != nil {
94 t.Fatal(err)
95 }
96 if err := l.Idle(t.Context()); err == nil {
97 t.Fatal("missing root census became empty")
98 }
99 if err := l.Acquire(t.Context(), func() error { t.Fatal("unknown history acquired"); return nil }); err == nil {
100 t.Fatal("unknown history admitted")
101 }
102}
103