| 1 | //go:build unix |
| 2 | |
| 3 | package hostbox |
| 4 | |
| 5 | import ( |
| 6 | "context" |
| 7 | "errors" |
| 8 | "github.com/carlosframework/platform/internal/hostclaim" |
| 9 | "github.com/carlosframework/platform/internal/hostwrite" |
| 10 | "github.com/carlosframework/platform/internal/lease" |
| 11 | "github.com/carlosframework/platform/internal/lease/leasetest" |
| 12 | "github.com/carlosframework/platform/internal/park" |
| 13 | "github.com/carlosframework/platform/internal/release" |
| 14 | "testing" |
| 15 | "time" |
| 16 | ) |
| 17 | |
| 18 | func TestPlan13HomeQuietWindow(t *testing.T) { |
| 19 | for _, home := range []string{"ie", ""} { |
| 20 | t.Run("home="+home, func(t *testing.T) { |
| 21 | source, store, obs := workFixture(t) |
| 22 | source.HomeRegion = home |
| 23 | _, err := hostclaim.Update(t.Context(), store, obs, func(c *hostclaim.Claim) error { |
| 24 | c.QuietAfter = map[string]time.Time{park.HomeRegion: time.Unix(200, 0)} |
| 25 | return nil |
| 26 | }) |
| 27 | if err != nil { |
| 28 | t.Fatal(err) |
| 29 | } |
| 30 | work, err := source.Select(t.Context(), obs.Host, "probe") |
| 31 | if err != nil { |
| 32 | t.Fatal(err) |
| 33 | } |
| 34 | ran := false |
| 35 | err = work.With(t.Context(), hostwrite.Identity{}, func() error { ran = true; return nil }) |
| 36 | if home != "" && (!errors.Is(err, ErrChanged) || ran) { |
| 37 | t.Fatalf("home: %v %v", ran, err) |
| 38 | } |
| 39 | if home == "" && err != nil { |
| 40 | t.Fatalf("named: %v", err) |
| 41 | } |
| 42 | h := obs.Claim.Holder |
| 43 | selected := RecordSelection{Host: obs.Host, Key: h.Key, Incarnation: h.Incarnation, Family: h.Family, ETag: "record"} |
| 44 | r := Reconciler{HomeRegion: home, Claims: store, Box: "box", Region: "ie", Now: source.Now, CheckRecord: func(context.Context, RecordSelection) error { return nil }, CheckLocal: func(context.Context, hostclaim.Observed, RecordSelection) error { return nil }} |
| 45 | current, err := hostclaim.Read(t.Context(), store, obs.Host) |
| 46 | if err != nil { |
| 47 | t.Fatal(err) |
| 48 | } |
| 49 | err = r.check(t.Context(), current, selected) |
| 50 | if (err != nil) != (home != "") { |
| 51 | t.Fatalf("reconcile home=%q: %v", home, err) |
| 52 | } |
| 53 | }) |
| 54 | } |
| 55 | } |
| 56 | func TestPlan13RegionalHomeAcknowledgesBothNames(t *testing.T) { |
| 57 | for _, region := range []string{park.HomeRegion, "ie", "uk"} { |
| 58 | t.Run(region, func(t *testing.T) { |
| 59 | claims := release.NewDirStore(t.TempDir()) |
| 60 | bucket := leasetest.NewVersionedBucket() |
| 61 | bucket.AddBucket("data") |
| 62 | now := time.Unix(2000, 0).UTC() |
| 63 | host := "home.example" |
| 64 | inc, err := hostclaim.Incarnation("bab", "app", host, now) |
| 65 | if err != nil { |
| 66 | t.Fatal(err) |
| 67 | } |
| 68 | _, err = hostclaim.Update(t.Context(), claims, hostclaim.Observed{Host: host, Absent: true}, func(c *hostclaim.Claim) error { |
| 69 | c.Holder = &hostclaim.Holder{Family: "instance", Key: "apps/bab/app/instances/" + host + ".json", Account: "bab", App: "app", Incarnation: inc, CreatedAt: now, Location: "instances/" + host + "/" + inc, Stamp: 1} |
| 70 | c.Op = hostclaim.Op{Kind: hostclaim.KindParking, ID: "op"} |
| 71 | c.Obligations = []hostclaim.Obligation{{ID: "id", Op: "op", Kind: "park-replica", Region: region, Owner: "region:" + region, Retirement: "ret", Park: &hostclaim.ParkScope{Location: c.Holder.Location, Incarnation: inc, EvidenceAt: time.Unix(1, 0).UTC(), RequestLimit: RequestLimit}}} |
| 72 | c.Touched = hostclaim.Touched{Complete: true, Regions: []string{region}} |
| 73 | return nil |
| 74 | }) |
| 75 | if err != nil { |
| 76 | t.Fatal(err) |
| 77 | } |
| 78 | e := park.Engine{HomeRegion: "ie", Claims: claims, Store: bucket, Bucket: "data", Region: "ie", Leases: workerLeases{}, Now: func() time.Time { return now }, NewID: func() string { return "id2" }, Authorize: func(context.Context, hostclaim.Observed, hostclaim.Obligation) error { return nil }, View: func(_ context.Context, o hostclaim.Observed) (park.View, error) { |
| 79 | return park.View{ClaimETag: o.ETag, Region: park.HomeRegion}, nil |
| 80 | }} |
| 81 | w := RegionalWorker{Regional: Regional{Engine: e, Owner: func(context.Context, hostclaim.Observed) error { return nil }}, Enrollment: enrollmentFunc(func(context.Context, string, string, time.Duration) error { return nil }), Evidence: evidenceFunc(func(context.Context, hostclaim.Observed, []lease.ObjectVersion) (string, time.Time, error) { |
| 82 | return "", now, nil |
| 83 | })} |
| 84 | hosts, err := w.Census(t.Context()) |
| 85 | if err != nil { |
| 86 | t.Fatal(err) |
| 87 | } |
| 88 | if (len(hosts) == 1) != (region != "uk") { |
| 89 | t.Fatalf("census %v", hosts) |
| 90 | } |
| 91 | if err = w.Run(t.Context()); err != nil { |
| 92 | t.Fatal(err) |
| 93 | } |
| 94 | o, err := hostclaim.Read(t.Context(), claims, host) |
| 95 | if err != nil { |
| 96 | t.Fatal(err) |
| 97 | } |
| 98 | if (len(o.Claim.Obligations) == 0) != (region != "uk") { |
| 99 | t.Fatalf("obligations %+v", o.Claim.Obligations) |
| 100 | } |
| 101 | }) |
| 102 | } |
| 103 | } |
| 104 | |