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 "context"
5 "errors"
6 "os"
7 "path/filepath"
8 "testing"
9 "time"
10
11 "golang.org/x/sys/unix"
12
13 "github.com/carlosframework/platform/internal/release"
14)
15
16// Settings plan 4, Astra round 2 finding 2 (ruling R-CARRY-FENCE): the
17// agent's carry (buildStates.carryRequest) takes the carry fence only once
18// the row's move hold is effective, and holds it across the carry, so a root
19// publication in flight lands before the carry reads the file and is
20// carried.
21
22// rootHoldsFence takes root's side of host's fence as root's publication
23// does (the lock file created, flock exclusive) and returns its release.
24func rootHoldsFence(t *testing.T, optDir, host string) func() {
25 t.Helper()
26 if err := os.MkdirAll(filepath.Join(optDir, "consumed"), 0o755); err != nil {
27 t.Fatal(err)
28 }
29 f, err := os.OpenFile(release.ConsumedLockPath(optDir, host), os.O_RDWR|os.O_CREATE, 0o644)
30 if err != nil {
31 t.Fatal(err)
32 }
33 if err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil {
34 t.Fatal(err)
35 }
36 return func() { _ = unix.Flock(int(f.Fd()), unix.LOCK_UN); _ = f.Close() }
37}
38
39// Root holds the fence and is about to publish R1 completed, failed; the
40// cut, its row held moving, asks for the carry: it waits for root, then
41// carries the record root published.
42func TestTheCarryWaitsForRootsPublicationAndCarriesIt(t *testing.T) {
43 t.Parallel()
44 b, s, reg := testBuildStates(t)
45 ctx := context.Background()
46 if err := put(t, b, ctx, astraHost, release.BuildState{LastExecuted: "A", Resolved: &release.ResolvedRequest{ID: 1, Target: "T"}}); err != nil {
47 t.Fatal(err)
48 }
49 if err := reg.SetStatus(astraHost, "moving"); err != nil {
50 t.Fatal(err)
51 }
52 unlock := rootHoldsFence(t, b.optDir, astraHost)
53 done := make(chan error, 1)
54 go func() { done <- b.carryRequest(ctx, astraHost, "hib", "inst/"+astraHost) }()
55 select {
56 case err := <-done:
57 unlock()
58 t.Fatalf("the carry ran while root held the fence: %v", err)
59 case <-time.After(200 * time.Millisecond):
60 }
61 writeConsumed(t, b, release.Consumed{Resolved: &release.ResolvedRequest{ID: 1, Target: "T"}, Completed: 1, CompletedFailed: true})
62 unlock()
63 select {
64 case err := <-done:
65 if err != nil {
66 t.Fatal(err)
67 }
68 case <-time.After(10 * time.Second):
69 t.Fatal("the carry never took the fence")
70 }
71 st, _, err := getState(ctx, s, release.BuildStateKey("inst/"+astraHost), astraHost)
72 if err != nil || st == nil || st.Completed != 1 || !st.CompletedFailed || st.LastExecuted != "A" {
73 t.Fatalf("state %+v, %v; want R1 completed failed carried, A untouched", st, err)
74 }
75}
76
77// A carry for a row the move does not hold is refused: root could still
78// publish after it. Nothing is written.
79func TestTheCarryRefusesARowNoMoveHolds(t *testing.T) {
80 b, s, _ := testBuildStates(t)
81 ctx := context.Background()
82 writeConsumed(t, b, release.Consumed{Resolved: &release.ResolvedRequest{ID: 1, Target: "T"}, Completed: 1, CompletedFailed: true})
83 if err := b.carryRequest(ctx, astraHost, "hib", "inst/"+astraHost); err == nil {
84 t.Fatal("a carry for a row no move holds went ahead")
85 }
86 if _, _, err := s.Get(ctx, release.BuildStateKey("inst/"+astraHost)); !errors.Is(err, os.ErrNotExist) {
87 t.Fatalf("the refused carry wrote: %v", err)
88 }
89}
90
91// No consumed directory: no record to carry and no lock to take; the agent
92// creates nothing there.
93func TestTheCarryWithNoConsumedDirectoryTakesNoLock(t *testing.T) {
94 b, _, reg := testBuildStates(t)
95 if err := reg.SetStatus(astraHost, "moving"); err != nil {
96 t.Fatal(err)
97 }
98 if err := b.carryRequest(context.Background(), astraHost, "hib", "inst/"+astraHost); err != nil {
99 t.Fatal(err)
100 }
101 if _, err := os.Stat(filepath.Join(b.optDir, "consumed")); !errors.Is(err, os.ErrNotExist) {
102 t.Fatalf("the carry created the consumed directory: %v", err)
103 }
104}
105