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 "errors"
5 "github.com/carlosframework/platform/internal/hostclaim"
6 "github.com/carlosframework/platform/internal/lease"
7 "github.com/carlosframework/platform/internal/park"
8 "strings"
9 "testing"
10 "time"
11)
12
13func plan12Retired(t *testing.T) hostclaim.Observed {
14 t.Helper()
15 t.Setenv("CARLOS_HOST_CLAIM_RETIRED_LOCATIONS", "1")
16 f := newRecoveryFixture(t)
17 o := f.read()
18 var err error
19 o, err = hostclaim.Update(t.Context(), f.claims, o, func(c *hostclaim.Claim) error {
20 c.Holder.Location = "instances/" + o.Host
21 c.Touched = hostclaim.Touched{Complete: true}
22 return hostclaim.BeginDelete("delete", "console", "record", f.now, nil, nil, "")(c)
23 })
24 if err != nil {
25 t.Fatal(err)
26 }
27 o, err = hostclaim.Update(t.Context(), f.claims, o, hostclaim.ToParking("delete", nil, nil, f.newID))
28 if err != nil {
29 t.Fatal(err)
30 }
31 o, err = hostclaim.Update(t.Context(), f.claims, o, hostclaim.FreeAfterPark("delete"))
32 if err != nil {
33 t.Fatal(err)
34 }
35 return o
36}
37func TestPlan12ArchivedIncarnationCensus(t *testing.T) {
38 for _, mode := range []string{"legacy", "old-incarnation", "missing-history", "qualified-beyond-history", "ambiguous-legacy"} {
39 t.Run(mode, func(t *testing.T) {
40 o := plan12Retired(t)
41 inc := o.Claim.RetiredIncarnations[0]
42 loc := "instances/" + o.Host
43 if mode == "old-incarnation" {
44 loc += "/" + inc
45 }
46 if mode == "missing-history" {
47 o.Claim.RetiredLocations = nil
48 }
49 if mode == "qualified-beyond-history" {
50 loc += "/" + strings.Repeat("b", 64)
51 }
52 if mode == "ambiguous-legacy" {
53 other := strings.Repeat("b", 64)
54 o.Claim.RetiredIncarnations = append(o.Claim.RetiredIncarnations, other)
55 o.Claim.RetiredLocations[other] = loc
56 }
57 versions := []lease.ObjectVersion{{Key: loc + "/0000/db", VersionID: "v1"}}
58 labels, err := ClaimRetirementCensus(o, versions)
59 if mode == "qualified-beyond-history" {
60 inc = strings.Repeat("b", 64)
61 }
62 if mode == "legacy" || mode == "old-incarnation" || mode == "qualified-beyond-history" {
63 if err != nil || labels[loc] != inc {
64 t.Fatal(labels, err)
65 }
66 } else {
67 var dependency *ClaimDependencyError
68 if !errors.As(err, &dependency) {
69 t.Fatal("not a typed dependency", err)
70 }
71 }
72 })
73 }
74}
75func TestPlan12LegacyAndMovesHaveIndependentLabels(t *testing.T) {
76 o := plan12Retired(t)
77 legacy := o.Claim.RetiredIncarnations[0]
78 move := strings.Repeat("c", 64)
79 versions := []lease.ObjectVersion{{Key: "instances/" + o.Host + "/0000/db", VersionID: "v1"}, {Key: "moves/" + o.Host + "/op/replica/db", VersionID: "v2"}}
80 view := park.View{ClaimETag: o.ETag, Region: "ie", ArchivedIncarnations: claimArchivedLocations(o.Claim)}
81 d, err := park.Decide(o, view, versions, move)
82 if err != nil {
83 t.Fatal(err)
84 }
85 if len(d.Candidates) != 2 {
86 t.Fatal(d)
87 }
88 for _, c := range d.Candidates {
89 want := move
90 if strings.HasPrefix(c.Location, "instances/") {
91 want = legacy
92 }
93 if c.Incarnation != want {
94 t.Fatal(c)
95 }
96 }
97 p := productionClaimRegional{Now: func() time.Time { return time.Unix(100, 0) }}
98 label, at, err := p.retirement(t.Context(), o, versions[:1])
99 if err == nil || label != "" || !at.IsZero() {
100 t.Fatal(label, at, err)
101 }
102}
103
104func TestPlan12HolderResidueInOtherRegion(t *testing.T) {
105 t.Parallel()
106 f := newRecoveryFixture(t)
107 o := f.read()
108 c := o.Claim
109 c.Holder.Location = "instances/" + o.Host
110 c.Holder.Generation = "live"
111 loc := c.Holder.Location
112 versions := []lease.ObjectVersion{{Key: loc + "/live/db", VersionID: "v1"}}
113 labels, err := ClaimRetirementCensus(o, versions)
114 if err != nil || labels[loc] != c.Holder.Incarnation {
115 t.Fatal(labels, err)
116 }
117 view := park.View{ClaimETag: o.ETag, Region: "uk", AuthoritativeRegion: "ie", ArchivedIncarnations: labels}
118 d, err := park.Decide(o, view, versions, "")
119 if err != nil || len(d.Candidates) != 1 || d.Candidates[0].Incarnation != c.Holder.Incarnation {
120 t.Fatal(d, err)
121 }
122 view.Region = "ie"
123 view.MarkerKnown = true
124 view.MarkerGeneration = "live"
125 view.GenerationOf = func(park.Ref) (string, bool) { return "live", true }
126 d, err = park.Decide(o, view, versions, "")
127 if err != nil || len(d.Candidates) != 0 {
128 t.Fatal("live generation swept", d, err)
129 }
130}
131func TestPlan12CensusNamespacesAndFreeLanes(t *testing.T) {
132 o := plan12Retired(t)
133 o.Claim.QuietAfter = map[string]time.Time{"ie": time.Unix(10, 0), "uk": time.Unix(20, 0)}
134 proof, err := claimFreeMoveProof(o)
135 if err != nil || proof.Check(o, o.Claim.RetiredIncarnations[0], time.Unix(21, 0)) != nil {
136 t.Fatal(proof, err)
137 }
138 if proof.Check(o, proof.Incarnation, time.Unix(20, 0)) == nil {
139 t.Fatal("accepted listing before retirement")
140 }
141 delete(o.Claim.RetiredLocations, o.Claim.RetiredIncarnations[0])
142 v := []lease.ObjectVersion{{Key: "instances/" + o.Host + "/0000/db", VersionID: "one"}, {Key: "moves/" + o.Host + "/move/db", VersionID: "two"}}
143 p := productionClaimRegional{Now: func() time.Time { return time.Unix(30, 0) }}
144 label, _, err := p.retirement(t.Context(), o, v)
145 if err != nil || label != proof.Incarnation {
146 t.Fatal("legacy refusal blocked lanes", err)
147 }
148 view := park.View{ClaimETag: o.ETag, Region: "ie", RefusedLocations: map[string]error{"instances/" + o.Host: claimRetirementDependency()}}
149 d, err := park.Decide(o, view, v, label)
150 if err != nil || len(d.Candidates) != 1 || d.Candidates[0].Location != "moves/"+o.Host {
151 t.Fatal(d, err)
152 }
153 o.Claim.QuietAfter = nil
154 if _, err := claimFreeMoveProof(o); err == nil {
155 t.Fatal("invented retirement bound")
156 }
157}
158func TestPlan12QualifiedIdentityBeyondHistoryCap(t *testing.T) {
159 o := plan12Retired(t)
160 loc := "instances/" + o.Host + "/" + strings.Repeat("e", 64)
161 labels, err := ClaimRetirementCensus(o, []lease.ObjectVersion{{Key: loc + "/g/db", VersionID: "v"}})
162 if err != nil || labels[loc] != strings.Repeat("e", 64) {
163 t.Fatal(labels, err)
164 }
165}
166