carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package hostclaim
2
3import (
4 "errors"
5 "reflect"
6 "testing"
7)
8
9func plan9D1Landing(phase string) *Claim {
10 return &Claim{V: schemaVersion, Host: "a.go.example.com", Gen: 12,
11 Holder: &Holder{Family: "instance", Incarnation: "inc", Location: "instances/a.go.example.com", Generation: "m1", Stamp: 10, Session: 11, WriterBox: "uk-box"},
12 Op: Op{Kind: KindLanding, ID: "m1", Phase: phase, Exec: "uk-box", Participants: []string{"ie-box", "uk-box"}, Intent: map[string]string{"to": "uk", "source": "ie-box", "target": "uk-box"}}}
13}
14
15func TestPlan9D1SessionStepsAreForwardOnlyAndPerKind(t *testing.T) {
16 for _, tc := range []struct {
17 kind, from, to string
18 want bool
19 }{
20 {KindLanding, "probing", "probing", true},
21 {KindLanding, "probing", "probed", true},
22 {KindLanding, "probed", "committed", true},
23 {KindLanding, "probing", "committed", false},
24 {KindLanding, "probed", "probing", false},
25 {KindLanding, "committed", "probed", false},
26 {KindLanding, "restored", "probing", false},
27 {KindLanding, "probing", "checking", false},
28 {KindServing, "", "", true},
29 {KindServing, "", "probed", false},
30 {KindMoving, "probing", "probed", false},
31 {KindRelocating, "probing", "serving", true}, // claim Plan 11's relocating row
32 {KindRelocating, "probing", "probe-failed", false},
33 } {
34 if got := SessionContinues(tc.kind, tc.from, tc.to); got != tc.want {
35 t.Errorf("SessionContinues(%s, %q, %q) = %v, want %v", tc.kind, tc.from, tc.to, got, tc.want)
36 }
37 }
38}
39
40func TestPlan9D1KeepWriterSessionGuardsTheCommit(t *testing.T) {
41 commit := func(c *Claim) error { return SetMovePhase("m1", KindLanding, "probed", "committed")(c) }
42 c := plan9D1Landing("probed")
43 if err := KeepWriterSession("m1", commit)(c); err != nil {
44 t.Fatal(err)
45 }
46 if c.Op.Phase != "committed" || c.Holder.Session != 11 || c.Holder.Stamp != 10 || c.Holder.Generation != "m1" {
47 t.Fatalf("commit changed the session: %+v %+v", c.Op, *c.Holder)
48 }
49 for name, fn := range map[string]func(*Claim) error{
50 "generation": func(c *Claim) error { c.Holder.Generation = "fresh"; return commit(c) },
51 "session": func(c *Claim) error { c.Holder.Session++; return commit(c) },
52 "stamp": func(c *Claim) error { c.Holder.Stamp = c.Gen + 1; return commit(c) },
53 "writer": func(c *Claim) error { c.Holder.WriterBox = "ie-box"; return commit(c) },
54 "executor": func(c *Claim) error { c.Op.Exec = ""; return commit(c) },
55 "backward": SetMovePhase("m1", KindLanding, "probed", "probing"),
56 "kind": func(c *Claim) error { c.Op.Kind = KindRestoring; c.Op.Phase = "released"; return nil },
57 "holder": func(c *Claim) error { c.Holder = nil; return nil },
58 } {
59 t.Run(name, func(t *testing.T) {
60 c := plan9D1Landing("probed")
61 if err := KeepWriterSession("m1", fn)(c); !errors.Is(err, ErrWrongState) {
62 t.Fatalf("%s kept the session: %v", name, err)
63 }
64 })
65 }
66 other := plan9D1Landing("probed")
67 before := *other.Holder
68 if err := KeepWriterSession("m2", commit)(other); !errors.Is(err, ErrStaleOp) {
69 t.Fatalf("another op's step: %v", err)
70 }
71 if other.Op.Phase != "probed" || !reflect.DeepEqual(*other.Holder, before) {
72 t.Fatalf("a refused op ran its step: %+v", other.Op)
73 }
74 if err := KeepWriterSession("m1", nil)(plan9D1Landing("probed")); !errors.Is(err, ErrMalformed) {
75 t.Fatalf("nil step: %v", err)
76 }
77}
78
79// M9: a single session-keeping CAS moves one row step at a time. The landing
80// cannot skip from probing straight to committed in one write.
81func TestPlan9M9KeepWriterSessionRefusesASkippedStep(t *testing.T) {
82 for _, tc := range []struct {
83 kind, from, to string
84 want bool
85 }{
86 {KindLanding, "probing", "probing", true},
87 {KindLanding, "probing", "probed", true},
88 {KindLanding, "probed", "committed", true},
89 {KindLanding, "committed", "committed", true},
90 {KindLanding, "probing", "committed", false},
91 {KindLanding, "probed", "probing", false},
92 {KindLanding, "committed", "probed", false},
93 {KindLanding, "restored", "probing", false},
94 {KindServing, "", "", true},
95 {KindServing, "", "probed", false},
96 {KindMoving, "probing", "probed", false},
97 } {
98 if got := SessionContinues(tc.kind, tc.from, tc.to); got != tc.want {
99 t.Errorf("SessionContinues(%s, %q, %q) = %v, want %v", tc.kind, tc.from, tc.to, got, tc.want)
100 }
101 }
102 c := plan9D1Landing("probing")
103 before := *c.Holder
104 skip := SetMovePhase("m1", KindLanding, "probing", "committed")
105 if err := KeepWriterSession("m1", skip)(c); !errors.Is(err, ErrWrongState) {
106 t.Fatalf("a skipped step kept the session: %v", err)
107 }
108 if !reflect.DeepEqual(*c.Holder, before) {
109 t.Fatalf("holder changed: %+v", *c.Holder)
110 }
111 if err := KeepWriterSession("m1", SetMovePhase("m1", KindLanding, "probing", "probed"))(plan9D1Landing("probing")); err != nil {
112 t.Fatalf("adjacent step: %v", err)
113 }
114}
115