carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package hostops
2
3import (
4 "context"
5 "encoding/json"
6 "errors"
7 "testing"
8 "time"
9
10 "github.com/carlosframework/platform/internal/hostclaim"
11 "github.com/carlosframework/platform/internal/provision"
12 "github.com/carlosframework/platform/internal/release"
13)
14
15func TestJ17ReviewSidecarCannotBecomeInstanceRecord(t *testing.T) {
16 ctx := t.Context()
17 w := newJ17World(t, nil)
18 c := w.claim(t).Claim
19 host := provision.SidecarHost("worker", "app", "bab")
20 key := provision.SidecarRecordKey("bab", "app", "worker")
21 inc, err := hostclaim.Incarnation("bab", "app", host, w.now)
22 if err != nil {
23 t.Fatal(err)
24 }
25 c.Host = host
26 c.Holder.Family = "sidecar"
27 c.Holder.Name = "worker"
28 c.Holder.Key = key
29 c.Holder.Incarnation = inc
30 c.Holder.Location = "instances/" + host
31 if err := c.Validate(); err != nil {
32 t.Fatal(err)
33 }
34 body, _ := json.Marshal(c)
35 ck, _ := hostclaim.Key(host)
36 ctag, err := w.raw.Put(ctx, ck, body, "")
37 if err != nil {
38 t.Fatal(err)
39 }
40 rec, _ := j17Record(t, w)
41 rec.Host = host
42 rec.Move.Incarnation = inc
43 body, _ = json.Marshal(rec)
44 var fields map[string]any
45 if err := json.Unmarshal(body, &fields); err != nil {
46 t.Fatal(err)
47 }
48 fields["name"] = "worker"
49 body, _ = json.Marshal(fields)
50 tag, err := w.raw.Put(ctx, key, body, "")
51 if err != nil {
52 t.Fatal(err)
53 }
54 a, err := ReadAdmission(ctx, w.raw, "bab", "app", "canonical")
55 if err != nil {
56 t.Fatal(err)
57 }
58 reg := a.Value.Registrations["move"]
59 reg.Host, reg.Incarnation = host, inc
60 a.Value.Registrations["move"] = reg
61 ab, _ := json.Marshal(a.Value)
62 if _, err := w.raw.Put(ctx, a.Key, ab, a.ETag); err != nil {
63 t.Fatal(err)
64 }
65 if _, err := ObserveConsoleMove(ctx, w.raw, "bab", "app", host); !errors.Is(err, ErrIdentity) {
66 t.Fatalf("sidecar observation: %v", err)
67 }
68 o := ConsoleMoveObservation{Account: "bab", App: "app", AppID: "canonical", Host: host, Incarnation: inc, OpID: "move", ClaimETag: ctag, RecordETag: tag}
69 if _, err := w.control.ConsoleMove(ctx, o, ConsoleMoveAbort); !errors.Is(err, ErrIdentity) {
70 t.Fatalf("sidecar action: %v", err)
71 }
72 after, afterTag, err := w.raw.Get(ctx, key)
73 if err != nil || afterTag != tag || string(after) != string(body) {
74 t.Fatal("sidecar record rewritten", err)
75 }
76}
77
78type j17ClaimReadHook struct {
79 release.Store
80 key string
81 reads int
82 beforeSecond func()
83}
84
85func (s *j17ClaimReadHook) Get(ctx context.Context, key string) ([]byte, string, error) {
86 if key == s.key {
87 s.reads++
88 if s.reads == 2 {
89 s.beforeSecond()
90 }
91 }
92 return s.Store.Get(ctx, key)
93}
94func TestJ17ReviewClaimCheckedAtTheFinalWrite(t *testing.T) {
95 ctx := t.Context()
96 w := newJ17World(t, nil)
97 o := j17Observe(t, w)
98 key, _ := hostclaim.Key(w.host)
99 hook := &j17ClaimReadHook{Store: w.raw, key: key, beforeSecond: func() {
100 if _, err := hostclaim.Update(ctx, w.raw, w.claim(t), func(*hostclaim.Claim) error { return nil }); err != nil {
101 t.Fatal(err)
102 }
103 }}
104 cw, err := NewControlWriter(hook, w.pub, func() time.Time { return w.clock })
105 if err != nil {
106 t.Fatal(err)
107 }
108 _, tag := j17Record(t, w)
109 if _, err := cw.ConsoleMove(ctx, o, ConsoleMoveAbort); !errors.Is(err, hostclaim.ErrConflict) {
110 t.Fatal(err)
111 }
112 if _, after := j17Record(t, w); after != tag {
113 t.Fatal("stale claim wrote the record")
114 }
115}
116