carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package host
4
5import (
6 "context"
7 "errors"
8 "path/filepath"
9 "testing"
10
11 "github.com/carlosframework/platform/internal/activator"
12 "github.com/carlosframework/platform/internal/hostclaim"
13)
14
15func TestClaimRestoreOwnWriteMaterializes(t *testing.T) {
16 for _, foreign := range []string{"", "before-retag", "after-restore"} {
17 t.Run(foreign, func(t *testing.T) {
18 t.Setenv("CARLOS_HOST_CLAIM", "1")
19 t.Setenv("CARLOS_HOST_CLAIM_ORIGINS", "1")
20 d := plan9D4Landing(t)
21 c := d.controller("boot-1", "controller-1", 4101, "start-1", true)
22 proofs := 0
23 d.f.materialize = func(ctx context.Context, o hostclaim.Observed) error {
24 h := o.Claim.Holder
25 tuple := hostclaim.OriginTuple{Incarnation: h.Incarnation, Location: h.Location, Region: "ie", Generation: h.Generation}
26 proven, err := hostclaim.AdmittedOrigins(ctx, d.f.claims, o, []hostclaim.OriginTuple{tuple})
27 if err != nil {
28 return err
29 }
30 if !proven[tuple] {
31 t.Fatal("admission origin not proven")
32 }
33 proofs++
34 return nil
35 }
36 materialize := func(o hostclaim.Observed, s activator.ClaimStart) error {
37 if err := s.Reserve(t.Context(), 0); err != nil {
38 return err
39 }
40 return s.Materialize(t.Context())
41 }
42 first, err := d.start(t, c, plan9D4Probe, false, materialize)
43 if err != nil {
44 t.Fatal("first start", err)
45 }
46 writeForeign := func() {
47 d.step(t, "foreign inventory write", func(claim *hostclaim.Claim) error {
48 claim.Inventory["box-1"].Paths[recoveryHost+".env"] = claim.Holder.Stamp
49 return nil
50 })
51 }
52 if foreign == "before-retag" {
53 retire := c.wake.RetireArtifacts
54 c.wake.RetireArtifacts = func(ctx context.Context, o hostclaim.Observed, in ClaimLaunchInputs, generation string) error {
55 writeForeign()
56 return retire(ctx, o, in, generation)
57 }
58 }
59 second, err := d.start(t, c, plan9D4Probe, true, func(o hostclaim.Observed, s activator.ClaimStart) error {
60 after := d.f.read()
61 if foreign != "before-retag" && after.Claim.Gen != o.Claim.Gen+1 {
62 t.Fatalf("Restore did not perform exactly its retag CAS: %d -> %d", o.Claim.Gen, after.Claim.Gen)
63 }
64 h := o.Claim.Holder
65 _, stale := hostclaim.AdmittedOrigins(t.Context(), d.f.claims, o, []hostclaim.OriginTuple{{Incarnation: h.Incarnation, Location: h.Location, Region: "ie", Generation: h.Generation}})
66 if !errors.Is(stale, hostclaim.ErrConflict) {
67 t.Fatalf("Prepare's read was not stale after retirement: %v", stale)
68 }
69 if foreign == "after-restore" {
70 writeForeign()
71 }
72 return materialize(o, s)
73 })
74 if foreign != "" {
75 if !errors.Is(err, hostclaim.ErrConflict) {
76 t.Fatalf("foreign claim write: %v", err)
77 }
78 if proofs != 1 {
79 t.Fatal("foreign writer reached C8", proofs)
80 }
81 return
82 }
83 if err != nil {
84 t.Fatal("retiring cold start", err)
85 }
86 d.requireRetired(t, first, second, false)
87 if proofs != 2 {
88 t.Fatal("both starts must prove C8 origins", proofs)
89 }
90 })
91 }
92}
93
94func TestClaimRestoreWriteOnlyRetagsPair(t *testing.T) {
95 for _, foreign := range []string{"", "op", "holder", "session", "stamp", "admission", "other-path", "before-etag", "generation"} {
96 t.Run(foreign, func(t *testing.T) {
97 f := newRecoveryFixture(t)
98 c := f.controller("boot", "controller", 4101, "start")
99 before := c.admit(t, f)
100 current, err := servingWriterIdentity(before, "box-1", "ie")
101 if err != nil {
102 t.Fatal(err)
103 }
104 after, err := hostclaim.Update(t.Context(), f.claims, before, servingInventoryTransition(current, "state/data.db", 0))
105 if err != nil {
106 t.Fatal(err)
107 }
108 r := &claimRestoreObservation{observed: before, box: "box-1", dataDir: f.guard.DataDir, db: filepath.Join(f.guard.DataDir, "state", "data.db")}
109 switch foreign {
110 case "op":
111 after.Claim.Op.Exec = "foreign"
112 case "holder":
113 after.Claim.Holder.App = "foreign"
114 case "session":
115 after.Claim.Holder.Session++
116 case "stamp":
117 after.Claim.Holder.Stamp++
118 case "admission":
119 after.Claim.Holder.Admissions[0].Generation = "foreign"
120 case "other-path":
121 after.Claim.Inventory["box-1"].Paths["foreign"] = current.Stamp
122 case "before-etag":
123 before.ETag = "foreign"
124 case "generation":
125 after.Claim.Gen++
126 }
127 err = r.retag(before, after)
128 if (err == nil) != (foreign == "") {
129 t.Fatalf("foreign %q: %v", foreign, err)
130 }
131 })
132 }
133}
134