carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package rollout
2
3import (
4 "os"
5 "testing"
6 "time"
7)
8
9// I9's deterministic witnesses (fix wave 1, item 3; Astra final review 1,
10// finding 3). Each scripts the model's events around a grant and then
11// delivers the grant through the real Manager and book. The code is not
12// told of the restriction the model adds after the grant's issue, which is
13// exactly what a mutant that moves no generation does (M14's renewal): the
14// grant's generation still matches, the code accepts it and clears the
15// marker, and I9 must report it. The control shows that a restriction that
16// landed before the issue, in the same step, is not inside the check.
17
18// newI9WitnessSim is a seed whose book is on disk (seed%4 == 3), with h's
19// hold-ran marker naming x (h's installed build) in the model and, saved,
20// in the book, so the box publishes a generation for it and a grant for
21// (x, h) is accepted.
22func newI9WitnessSim(t *testing.T) (*sim, *simHost, string) {
23 t.Helper()
24 if os.Geteuid() == 0 {
25 t.Skip("as root a seed keeps its book in memory, and I9 is not checked")
26 }
27 s := newSim(3, t.TempDir(), t.TempDir(), map[string]bool{})
28 t.Cleanup(func() {
29 s.cancel()
30 close(s.dead)
31 os.RemoveAll(s.dir)
32 })
33 h := s.hosts[0]
34 x := s.installed[h.ch]
35 s.holdRanOn(h, x, s.now)
36 if err := s.book.MarkHoldRan(h.name, HoldRan{Account: "bab", App: "blog", Build: x, Exec: "w-witness-0", At: s.now}); err != nil {
37 t.Fatalf("MarkHoldRan: %v", err)
38 }
39 if s.published(x, h.name) == 0 {
40 t.Fatal("no published generation for the marker")
41 }
42 witnessStep(s)
43 return s, h, x
44}
45
46// witnessStep moves the model one step on.
47func witnessStep(s *sim) {
48 s.step++
49 s.now = s.now.Add(time.Second)
50}
51
52// lastGrant is the grant issueGrant just queued.
53func lastGrant(t *testing.T, s *sim) simGrant {
54 t.Helper()
55 if len(s.grants) == 0 {
56 t.Fatal("no grant was issued")
57 }
58 return s.grants[len(s.grants)-1]
59}
60
61// wantI9 runs fn, a delivery of a grant for h, and requires it to report an
62// I9 violation. Without one it says whether the code accepted the grant
63// (h's marker cleared), which is what makes a missed violation a miss.
64func wantI9(t *testing.T, s *sim, h *simHost, fn func()) {
65 t.Helper()
66 defer func() {
67 r := recover()
68 v, ok := r.(simViolation)
69 if !ok || v.inv != "I9" {
70 _, still := s.book.HoldRanOn(h.name)
71 t.Fatalf("got %v, want an I9 violation (the code accepted the grant: %v)", r, !still)
72 }
73 t.Logf("caught: %s", v.msg)
74 }()
75 fn()
76}
77
78// Astra's counterexample: issue G0; another hold execution of x begins on
79// h; issue G1; that execution's run renews the marker (with M14's missing
80// generation move); deliver G0 first. G1's issue must not answer the
81// renewal: only an applied clear discharges a fact.
82func TestI9WitnessAGrantsIssueMasksNothing(t *testing.T) {
83 s, h, x := newI9WitnessSim(t)
84 s.issueGrant(h, x)
85 g0 := lastGrant(t, s)
86 witnessStep(s)
87 start := s.now // another hold execution of x begins on h
88 witnessStep(s)
89 s.issueGrant(h, x) // G1: nothing has moved yet, so the same generation
90 witnessStep(s)
91 s.holdRanOn(h, x, start) // its run renews the marker; the code moves nothing
92 witnessStep(s)
93 wantI9(t, s, h, func() { s.deliver(g0) })
94}
95
96// A late outcome: an execution of x on h begins before the grant is issued,
97// and its failure lands after the issue, with the grant not yet applied (so
98// not PreRetry). It is inside the check, though its execution began first.
99func TestI9WitnessALateOutcomeIsInsideTheCheck(t *testing.T) {
100 s, h, x := newI9WitnessSim(t)
101 start := s.now // the execution begins
102 witnessStep(s)
103 s.issueGrant(h, x)
104 g := lastGrant(t, s)
105 witnessStep(s)
106 // The failure lands. The code is not told (its generation does not
107 // move), so I8, which reads the disk for it, is not this witness's.
108 dir := s.dir
109 s.dir = ""
110 s.failure(x, h.name, time.Time{}, false, start)
111 s.dir = dir
112 witnessStep(s)
113 wantI9(t, s, h, func() { s.deliver(g) })
114}
115
116// A change in the grant's own step, after its issue: the step's own action
117// runs a hold execution of x on h that renews the marker. The model's times
118// cannot order the two, its transition numbers can.
119func TestI9WitnessASameStepChangeIsInsideTheCheck(t *testing.T) {
120 s, h, x := newI9WitnessSim(t)
121 s.issueGrant(h, x)
122 g := lastGrant(t, s)
123 s.holdRanOn(h, x, s.now) // same step, after the issue
124 witnessStep(s)
125 wantI9(t, s, h, func() { s.deliver(g) })
126}
127
128// The control: a renewal that landed before the issue, in the same step,
129// and that the code saw (its generation moved, and the grant names the new
130// one), is what the grant was issued for. The grant clears it, and I9 holds.
131func TestI9WitnessASameStepChangeBeforeTheIssueIsNotInsideTheCheck(t *testing.T) {
132 s, h, x := newI9WitnessSim(t)
133 s.holdRanOn(h, x, s.now)
134 if err := s.book.MarkHoldRan(h.name, HoldRan{Account: "bab", App: "blog", Build: x, Exec: "w-witness-1", At: s.now}); err != nil {
135 t.Fatalf("MarkHoldRan: %v", err)
136 }
137 s.issueGrant(h, x)
138 g := lastGrant(t, s)
139 witnessStep(s)
140 s.deliver(g)
141 if _, still := s.book.HoldRanOn(h.name); still {
142 t.Fatal("the grant was not accepted: the control proves nothing")
143 }
144}
145