| 1 | package activator |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "errors" |
| 6 | "github.com/carlosframework/platform/internal/hostclaim" |
| 7 | "github.com/carlosframework/platform/internal/hostwrite" |
| 8 | "github.com/carlosframework/platform/internal/registry" |
| 9 | "testing" |
| 10 | "time" |
| 11 | ) |
| 12 | |
| 13 | type claimRoutes struct{ called *bool } |
| 14 | |
| 15 | func (r claimRoutes) Get(string) (*registry.Route, error) { |
| 16 | *r.called = true |
| 17 | return nil, errors.New("unexpected registry read") |
| 18 | } |
| 19 | func TestClaimK6StopsBeforeRegistryOrAdmission(t *testing.T) { |
| 20 | stopped, readRoute, admitted := false, false, false |
| 21 | a := &Service{cfg: Config{HostWrites: hostwrite.Config{Enabled: true}, Claims: &ClaimRuntime{ |
| 22 | Box: "here", Read: func(context.Context, string) (hostclaim.Observed, error) { |
| 23 | return hostclaim.Observed{Claim: &hostclaim.Claim{Op: hostclaim.Op{Exec: "elsewhere"}}}, nil |
| 24 | }, |
| 25 | StopForeign: func(context.Context, string) error { stopped = true; return nil }, |
| 26 | Admit: func(context.Context, registry.Route, hostclaim.Observed, startPolicy) (hostclaim.Observed, error) { |
| 27 | admitted = true |
| 28 | return hostclaim.Observed{}, nil |
| 29 | }, |
| 30 | }}, Routes: claimRoutes{&readRoute}} |
| 31 | if _, err := a.doWake(context.Background(), &actEntry{host: "x.example"}); err == nil { |
| 32 | t.Fatal("foreign wake") |
| 33 | } |
| 34 | if !stopped || readRoute || admitted { |
| 35 | t.Fatalf("stop %v route %v admit %v", stopped, readRoute, admitted) |
| 36 | } |
| 37 | } |
| 38 | func TestClaimReadFailureDoesNotInventForeignAuthority(t *testing.T) { |
| 39 | stopped := false |
| 40 | a := &Service{cfg: Config{HostWrites: hostwrite.Config{Enabled: true}, Claims: &ClaimRuntime{Box: "box", Read: func(context.Context, string) (hostclaim.Observed, error) { |
| 41 | return hostclaim.Observed{}, errors.New("offline") |
| 42 | }, StopForeign: func(context.Context, string) error { stopped = true; return nil }}}} |
| 43 | if _, err := a.doWake(context.Background(), &actEntry{host: "x.example"}); err == nil || stopped { |
| 44 | t.Fatal(err, stopped) |
| 45 | } |
| 46 | } |
| 47 | func TestStartAdmittedRejectsMovedObservationBeforeRestore(t *testing.T) { |
| 48 | prepared := false |
| 49 | obs := hostclaim.Observed{Host: "x.example", ETag: "old", Claim: &hostclaim.Claim{Holder: &hostclaim.Holder{Session: 1, Generation: "g"}, Op: hostclaim.Op{Kind: "landing", ID: "op", Phase: "probing", Exec: "box"}}} |
| 50 | a := &Service{cfg: Config{HostWrites: hostwrite.Config{Enabled: true}, Claims: &ClaimRuntime{Box: "box", Read: func(context.Context, string) (hostclaim.Observed, error) { n := obs; n.ETag = "new"; return n, nil }, Prepare: func(context.Context, registry.Route, hostclaim.Observed, startPolicy) (ClaimStart, error) { |
| 51 | prepared = true |
| 52 | return ClaimStart{}, nil |
| 53 | }}}} |
| 54 | err := a.startAdmitted(context.Background(), &actEntry{host: obs.Host}, obs, startPolicy{MaxStarts: 5, Window: 30 * time.Second, Probe: true}) |
| 55 | if err == nil || prepared { |
| 56 | t.Fatal(err, prepared) |
| 57 | } |
| 58 | } |
| 59 | func TestSameAdmissionAllowsBookkeepingButRefusesSessionChange(t *testing.T) { |
| 60 | h := &hostclaim.Holder{Incarnation: "i", Stamp: 2, Session: 2, Generation: "g"} |
| 61 | a := hostclaim.Observed{Host: "x.example", ETag: "a", Claim: &hostclaim.Claim{Holder: h, Op: hostclaim.Op{Kind: "serving", Exec: "box"}}} |
| 62 | b := a |
| 63 | b.ETag = "b" |
| 64 | if !sameAdmission(a, b) { |
| 65 | t.Fatal("bookkeeping") |
| 66 | } |
| 67 | c := *a.Claim |
| 68 | holder := *h |
| 69 | holder.Session++ |
| 70 | c.Holder = &holder |
| 71 | b.Claim = &c |
| 72 | if sameAdmission(a, b) { |
| 73 | t.Fatal("session") |
| 74 | } |
| 75 | } |
| 76 | |