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 "context"
5 "path/filepath"
6 "testing"
7)
8
9// Region HA ruling 31: "relocating" is a hold status. The edge never
10// serves it and ticks refuse it (IsHold); SetHold accepts it; the hold is
11// released only under its own op.
12func TestRelocatingIsAHoldStatus(t *testing.T) {
13 if !IsHold("relocating") {
14 t.Fatal("relocating is not a hold")
15 }
16 reg, err := Open(filepath.Join(t.TempDir(), "registry.db"))
17 if err != nil {
18 t.Fatal(err)
19 }
20 defer reg.Close()
21 if err := reg.Upsert(Route{Host: "shop.example", Status: "ready", Socket: "/run/shop.sock"}); err != nil {
22 t.Fatal(err)
23 }
24 if err := reg.SetHold("shop.example", "relocating", "op-1"); err != nil {
25 t.Fatal(err)
26 }
27 if changed, err := reg.ReleaseHold("shop.example", "op-2"); err != nil || changed {
28 t.Fatalf("another op released the hold: %v %v", changed, err)
29 }
30 row, err := reg.Get("shop.example")
31 if err != nil || row.Status != "relocating" || row.HoldOp != "op-1" {
32 t.Fatalf("row %+v %v", row, err)
33 }
34 if changed, err := reg.ReleaseHold("shop.example", "op-1"); err != nil || !changed {
35 t.Fatalf("its own op did not release the hold: %v %v", changed, err)
36 }
37 if row, _ := reg.Get("shop.example"); row.Status != "ready" || row.HoldOp != "" {
38 t.Fatalf("after release: %+v", row)
39 }
40}
41
42// Region HA Task 10b (R5-3): the source's row is held with SetHoldIf
43// expecting it unheld. That write never takes a row another op holds, a
44// replay of it matches nothing and changes nothing, it mints no row, and
45// it leaves the row's claim ownership as it was, so the source's
46// park-local retires the held row by ownership (RetireClaimRows), which
47// ends the hold.
48func TestSetHoldIfRelocatingNeverTakesAnotherOpsRow(t *testing.T) {
49 ctx := context.Background()
50 reg, err := Open(filepath.Join(t.TempDir(), "registry.db"))
51 if err != nil {
52 t.Fatal(err)
53 }
54 defer reg.Close()
55 owner := ClaimOwnership{ClaimIncarnation: "inc-1", ClaimStamp: 7, ClaimOwner: "owner-1", ClaimRowID: "row-1"}
56 if err := reg.Upsert(Route{Host: "shop.example", Status: "ready", Socket: "/run/shop.sock", ClaimOwnership: owner}); err != nil {
57 t.Fatal(err)
58 }
59 if held, err := reg.SetHoldIf("shop.example", "relocating", "rel-1", ""); err != nil || !held {
60 t.Fatalf("the hold: %v %v", held, err)
61 }
62 held, err := reg.Get("shop.example")
63 if err != nil || held.Status != "relocating" || held.HoldOp != "rel-1" || held.ClaimOwnership != owner {
64 t.Fatalf("held row %+v %v", held, err)
65 }
66 // A replay matches nothing and changes nothing.
67 if again, err := reg.SetHoldIf("shop.example", "relocating", "rel-1", ""); err != nil || again {
68 t.Fatalf("a replay wrote: %v %v", again, err)
69 }
70 // Another op neither takes the hold expecting an unheld row nor by
71 // naming the holder.
72 if took, err := reg.SetHoldIf("shop.example", "relocating", "rel-2", ""); err != nil || took {
73 t.Fatalf("another op took the row: %v %v", took, err)
74 }
75 if took, err := reg.SetHoldIf("shop.example", "relocating", "rel-2", "rel-1"); err == nil || took {
76 t.Fatalf("a takeover was accepted: %v %v", took, err)
77 }
78 if now, err := reg.Get("shop.example"); err != nil || *now != *held {
79 t.Fatalf("the row changed: %+v (was %+v) %v", now, held, err)
80 }
81 // No row: nothing matches and nothing is minted.
82 if minted, err := reg.SetHoldIf("absent.example", "relocating", "rel-1", ""); err != nil || minted {
83 t.Fatalf("a missing row: %v %v", minted, err)
84 }
85 if row, err := reg.Get("absent.example"); err != nil || row != nil {
86 t.Fatalf("a row was minted: %+v %v", row, err)
87 }
88 // The park-local's retirement deletes the held row by its ownership.
89 target := []ClaimRow{{Kind: "route", Host: "shop.example", Ownership: owner}}
90 if err := reg.RetireClaimRows(ctx, "retire-1", target, func([]ClaimRowArchive) error { return nil }); err != nil {
91 t.Fatalf("the park-local's retirement of the held row: %v", err)
92 }
93 if row, err := reg.Get("shop.example"); err != nil || row != nil {
94 t.Fatalf("after the retirement: %+v %v", row, err)
95 }
96}
97