carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package registry
2
3import (
4 "errors"
5 "path/filepath"
6 "testing"
7)
8
9func TestPlan12RebindClaimRows(t *testing.T) {
10 for _, mode := range []string{"ok", "changed-route", "changed-owner", "changed-payload", "extra-timer"} {
11 t.Run(mode, func(t *testing.T) {
12 r, e := Open(filepath.Join(t.TempDir(), "registry.db"))
13 if e != nil {
14 t.Fatal(e)
15 }
16 defer r.Close()
17 row := Route{Host: "app.example", Kind: "instance", ClaimOwnership: ClaimOwnership{"inc", 1, "old", "old-row"}}
18 if e = r.Upsert(row); e != nil {
19 t.Fatal(e)
20 }
21 saved, e := r.Get(row.Host)
22 if e != nil {
23 t.Fatal(e)
24 }
25 old := ColdRows{Route: *saved}
26 next := old
27 next.Route.ClaimOwnership = ClaimOwnership{"inc", 2, "new", "new-row"}
28 switch mode {
29 case "changed-route":
30 r.sql.Exec("UPDATE routes SET version='other' WHERE host=?", row.Host)
31 case "changed-owner":
32 r.sql.Exec("UPDATE routes SET claim_owner='other' WHERE host=?", row.Host)
33 case "changed-payload":
34 next.Route.Version = "other"
35 case "extra-timer":
36 if e = r.UpsertTimer(Timer{Host: row.Host, Name: "extra", Kind: "cron", Spec: "* * * * *"}); e != nil {
37 t.Fatal(e)
38 }
39 }
40 e = r.RebindClaimRows(t.Context(), old, next)
41 if mode != "ok" {
42 if !errors.Is(e, ErrClaimOwnership) {
43 t.Fatal("accepted changed installation", e)
44 }
45 return
46 }
47 if e != nil {
48 t.Fatal(e)
49 }
50 if e = r.RebindClaimRows(t.Context(), old, next); e != nil {
51 t.Fatal("replay", e)
52 }
53 got, e := r.Get(row.Host)
54 if e != nil || *got != next.Route {
55 t.Fatal(got, e)
56 }
57 })
58 }
59}
60
61func TestPlan12RebindRefusesForeignTimerOwnership(t *testing.T) {
62 for _, mode := range []string{"foreign-owner", "stale-incarnation", "stale-stamp"} {
63 t.Run(mode, func(t *testing.T) {
64 r, err := Open(filepath.Join(t.TempDir(), "registry.db"))
65 if err != nil {
66 t.Fatal(err)
67 }
68 defer r.Close()
69 row := Route{Host: "app.example", Kind: "instance", ClaimOwnership: ClaimOwnership{"inc", 1, "old", "row"}}
70 if err = r.Upsert(row); err != nil {
71 t.Fatal(err)
72 }
73 saved, err := r.Get(row.Host)
74 if err != nil {
75 t.Fatal(err)
76 }
77 timer := Timer{Host: row.Host, Name: "extra", Kind: "cron", Spec: "* * * * *", ClaimOwnership: ClaimOwnership{"inc", 1, "old", "timer"}}
78 switch mode {
79 case "foreign-owner":
80 timer.ClaimOwner = "foreign"
81 case "stale-incarnation":
82 timer.ClaimIncarnation = "stale"
83 case "stale-stamp":
84 timer.ClaimStamp = 9
85 }
86 if err = r.UpsertTimer(timer); err != nil {
87 t.Fatal(err)
88 }
89 if _, err = r.sql.Exec("UPDATE timers SET claim_incarnation=?,claim_stamp=?,claim_owner=?,claim_row_id=? WHERE host=?", timer.ClaimIncarnation, timer.ClaimStamp, timer.ClaimOwner, timer.ClaimRowID, row.Host); err != nil {
90 t.Fatal(err)
91 }
92 timers, err := r.TimersFor(row.Host)
93 if err != nil {
94 t.Fatal(err)
95 }
96 old := ColdRows{Route: *saved, Timers: timers}
97 next := ColdRows{Route: *saved, Timers: append([]Timer(nil), timers...)}
98 next.Route.ClaimOwnership = ClaimOwnership{"inc", 2, "new", "new-row"}
99 next.Timers[0].ClaimOwnership = ClaimOwnership{"inc", 2, "new", "new-timer"}
100 if err = r.RebindClaimRows(t.Context(), old, next); !errors.Is(err, ErrClaimOwnership) {
101 t.Fatalf("stole timer: %v", err)
102 }
103 got, err := r.Get(row.Host)
104 if err != nil || *got != *saved {
105 t.Fatal("refusal changed route", err)
106 }
107 })
108 }
109}
110