carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package hostfloor
2
3import (
4 "context"
5 "encoding/json"
6 "os"
7 "path/filepath"
8 "sync"
9 "testing"
10
11 "github.com/carlosframework/platform/internal/rootparticipation"
12)
13
14type floorParticipationDisk struct {
15 dir string
16 mu sync.Mutex
17 beforeWrite func(string)
18}
19
20func (d *floorParticipationDisk) Read(n string) ([]byte, error) {
21 return os.ReadFile(filepath.Join(d.dir, n))
22}
23func (d *floorParticipationDisk) Write(n string, b []byte) error {
24 if d.beforeWrite != nil {
25 d.beforeWrite(n)
26 }
27 return Durable(filepath.Join(d.dir, n), b, 0600)
28}
29func (d *floorParticipationDisk) Remove(n string) error {
30 return RemoveDurable(filepath.Join(d.dir, n))
31}
32func (d *floorParticipationDisk) Names() ([]string, error) {
33 entries, err := os.ReadDir(d.dir)
34 var out []string
35 for _, e := range entries {
36 out = append(out, e.Name())
37 }
38 return out, err
39}
40func (d *floorParticipationDisk) Lock(context.Context, string) (func(), error) {
41 d.mu.Lock()
42 return d.mu.Unlock, nil
43}
44func (d *floorParticipationDisk) Close() error { return nil }
45func floorParticipationFixture(t *testing.T) *rootparticipation.Ledger {
46 t.Helper()
47 d := &floorParticipationDisk{dir: t.TempDir()}
48 raw, _ := json.Marshal(rootparticipation.Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true})
49 if err := d.Write("census.json", raw); err != nil {
50 t.Fatal(err)
51 }
52 return &rootparticipation.Ledger{State: d, VerifyLaunches: func(context.Context, uint64) error { return nil }, ExcludeLaunches: func(ctx context.Context, fn func(context.Context) error) error { return fn(ctx) }}
53}
54
55func TestPlan14ExecutionFloorUsesRootCensus(t *testing.T) {
56 d := Disk{Dir: t.TempDir(), Participation: floorParticipationFixture(t)}
57 data := t.TempDir()
58 if err := d.Participation.State.Write("shop.example.json", []byte("{\"Schema\":1,\"Status\":\"lost\"}")); err != nil {
59 t.Fatal(err)
60 }
61 if err := d.Begin(t.Context(), "update", data); err == nil {
62 t.Fatal("missing agent directory cleared root obligation")
63 }
64 if err := d.Participation.State.Remove("shop.example.json"); err != nil {
65 t.Fatal(err)
66 }
67 d.Participation.VerifyLaunches = nil
68 if err := d.Begin(t.Context(), "update", data); err == nil {
69 t.Fatal("missing kernel completeness permitted update")
70 }
71 d.Participation.VerifyLaunches = func(context.Context, uint64) error { return nil }
72 if err := d.Begin(t.Context(), "update", data); err != nil {
73 t.Fatal(err)
74 }
75 if err := d.Participation.Acquire(t.Context(), func() error { return nil }); err == nil {
76 t.Fatal("floor update admitted acquisition")
77 }
78}
79
80func TestPlan14ExecutionFloorUpdateRace(t *testing.T) {
81 for _, first := range []string{"acquisition", "update"} {
82 t.Run(first, func(t *testing.T) {
83 d := Disk{Dir: t.TempDir(), Participation: floorParticipationFixture(t)}
84 state := d.Participation.State.(*floorParticipationDisk)
85 entered, release := make(chan struct{}), make(chan struct{})
86 target := "census.json"
87 if first == "update" {
88 target = "update.json"
89 }
90 var once sync.Once
91 state.beforeWrite = func(name string) {
92 if name == target {
93 once.Do(func() { close(entered); <-release })
94 }
95 }
96 acquisition := func() error {
97 return d.Participation.Acquire(t.Context(), func() error { return state.Write("shop.example.json", []byte(`{"Schema":1,"Status":"pending"}`)) })
98 }
99 data := t.TempDir()
100 update := func() error { return d.Begin(t.Context(), "update", data) }
101 a, b := acquisition, update
102 if first == "update" {
103 a, b = update, acquisition
104 }
105 one, two := make(chan error, 1), make(chan error, 1)
106 go func() { one <- a() }()
107 <-entered
108 go func() { two <- b() }()
109 mirror := filepath.Join(data, ".hostexec")
110 if err := os.Mkdir(mirror, 0700); err != nil {
111 t.Fatal(err)
112 }
113 if err := os.Remove(mirror); err != nil {
114 t.Fatal(err)
115 }
116 close(release)
117 if err := <-one; err != nil {
118 t.Fatal(err)
119 }
120 if err := <-two; err == nil {
121 t.Fatal("floor update and acquisition both admitted")
122 }
123 })
124 }
125}
126