carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package hostrelocate
2
3import (
4 "context"
5 "errors"
6 "slices"
7 "testing"
8 "time"
9
10 "github.com/carlosframework/platform/internal/boxchoice"
11 "github.com/carlosframework/platform/internal/hostclaim"
12 "github.com/carlosframework/platform/internal/hostops"
13)
14
15// scopedChooser plugs create's chooser into the fixture's worker, scoped
16// to namespace, with every fixture box fresh and eligible on its edges
17// file, equally roomy under spec 2's policy (§7), and spa the most loaded.
18func scopedChooser(f *fixture, namespace string) RegionChooser {
19 yes := true
20 snap := boxchoice.Snapshot{Complete: true}
21 generation := f.w.Now().Add(-time.Minute).UTC().Format(time.RFC3339)
22 for _, ref := range []string{"src", "dst", "spa", "sp2"} {
23 snap.Boxes = append(snap.Boxes, boxchoice.Box{BoxID: ref, EIP: "203.0.113.1", Region: "eu-west-1", Placement: "ie", Fresh: true,
24 HibernationConfigured: &yes, ServesSharedPool: &yes, AcceptsInbound: &yes, SecretsKeyFP: "fp", Capabilities: []string{boxchoice.Capability},
25 Headroom: &boxchoice.Headroom{MemFreeMiB: 4000, MemTotalMiB: 8000, DiskFreeMiB: 50000, DiskTotalMiB: 100000},
26 Generation: generation})
27 }
28 loads := map[string]boxchoice.Load{"spa": {Hosts: 9, Apps: map[string]int{"bab/jam": 3}}}
29 return RegionChooser{Records: f.s, Namespace: namespace, Region: "ie",
30 Executors: hostops.ExecutorChooser{Directory: f.w.Directory, SecretsKeyFP: "fp", Now: f.w.Now,
31 Edges: func(context.Context) (boxchoice.Snapshot, error) { return snap, nil },
32 Loads: func(context.Context) (map[string]boxchoice.Load, error) { return loads, nil }}}
33}
34
35// Task 2's fix: the chooser chooses only within claim Plan 5's scope, and
36// an unscoped one chooses nothing. With the scope set from the worker's
37// namespace and the record's pool, the worker picks a target: never the
38// source (the least loaded box, so the chooser alone would name it), never
39// the dead target, never a box of another namespace.
40func TestWorkerChoosesATargetWithinTheHostsScope(t *testing.T) {
41 f := newFixture(t)
42 ctx := context.Background()
43 body := `{"host":"` + host + `","account":"bab","app":"jam","region":"ie","created_at":"2026-10-04T01:00:00Z"}`
44 if _, err := f.s.Put(ctx, f.claim().Claim.Holder.Key, []byte(body), ""); err != nil {
45 t.Fatal(err)
46 }
47 b := f.roster.Boxes["sp2"]
48 b.Namespace = "other"
49 f.roster.Boxes["sp2"] = b
50 f.roster.Revision++
51 f.writeRoster()
52
53 unscoped := scopedChooser(f, "")
54 f.w.Choose, f.w.Eligible = unscoped.Choose, unscoped.Eligible
55 before := f.claim().ETag
56 if _, err := f.w.Start(ctx, host, Request{Reason: hostclaim.ReasonDrain, Source: "src", Target: "dst"}); !errors.Is(err, ErrUnsupported) {
57 t.Fatalf("an unscoped chooser admitted a target: %v", err)
58 }
59
60 scoped := scopedChooser(f, "platform")
61 f.w.Choose, f.w.Eligible = scoped.Choose, scoped.Eligible
62 if _, err := f.w.Start(ctx, host, Request{Reason: hostclaim.ReasonDrain, Source: "src", Target: "sp2"}); !errors.Is(err, hostops.ErrNoEligibleBox) {
63 t.Fatalf("started on a box of another namespace: %v", err)
64 }
65 if f.claim().ETag != before {
66 t.Fatal("a refused start wrote the claim")
67 }
68 if _, err := f.w.Start(ctx, host, Request{Reason: hostclaim.ReasonDrain, Source: "src", Target: "dst"}); err != nil {
69 t.Fatal(err)
70 }
71 f.terminate("dst")
72 o := f.worker(nil)
73 if o.Claim.Op.Intent["target_box"] != "spa" || o.Claim.Op.Intent["target_enrollment"] != enrollment("spa") || !slices.Contains(o.Claim.Lost, "dst") {
74 t.Fatalf("replacement: %+v lost %v", o.Claim.Op.Intent, o.Claim.Lost)
75 }
76}
77