carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5 "encoding/json"
6 "errors"
7 "testing"
8
9 "github.com/carlosframework/platform/internal/hostbox"
10 "github.com/carlosframework/platform/internal/hostclaim"
11 "github.com/carlosframework/platform/internal/hostfiles"
12 "github.com/carlosframework/platform/internal/hostguard"
13 "github.com/carlosframework/platform/internal/hostrelocate"
14 "github.com/carlosframework/platform/internal/hostwrite"
15)
16
17// Finding 10, ruling 46: the install policy admits only the install
18// actions of this box's relocating op at installed or probing before P,
19// at the install stamp, with no other op's hold, and refuses a stale
20// capture.
21func TestRelocationInstallPolicyIsTyped(t *testing.T) {
22 hold := ""
23 held := func(context.Context, string) (string, error) { return hold, nil }
24 policy := relocationInstallPolicy(held, relocationPolicy("dst"))
25 c := &hostclaim.Claim{Host: "shop.example", Holder: &hostclaim.Holder{Incarnation: "inc", Stamp: 9},
26 Op: hostclaim.Op{Kind: hostclaim.KindRelocating, ID: "op1", Phase: hostclaim.PhaseInstalled, Exec: "dst", Participants: []string{"src", "dst"}, Journal: map[string]string{"install_stamp": "9", "prepared": "P1"}}}
27 sel := hostbox.Selection{Host: "shop.example", Action: relocationActionInstall, Box: "dst", Op: "op1", Captured: hostguard.Captured{Incarnation: "inc", Stamp: 9}}
28 for _, action := range []string{relocationActionInstall, relocationActionHeldConfig, relocationActionHeldRelease} {
29 s := sel
30 s.Action = action
31 if err := policy(context.Background(), c, s, hostwrite.Identity{}); err != nil {
32 t.Fatalf("%s: %v", action, err)
33 }
34 }
35 hold = "op1"
36 if err := policy(context.Background(), c, sel, hostwrite.Identity{}); err != nil {
37 t.Fatalf("its own hold: %v", err)
38 }
39 for name, tweak := range map[string]func(*hostclaim.Claim, *hostbox.Selection){
40 "a probe action": func(_ *hostclaim.Claim, s *hostbox.Selection) { s.Action = "probe" },
41 "installing": func(c *hostclaim.Claim, _ *hostbox.Selection) { c.Op.Phase = hostclaim.PhaseInstalling },
42 "P opened": func(c *hostclaim.Claim, _ *hostbox.Selection) { c.Op.Journal["prepared_opened"] = "P1" },
43 "another executor": func(c *hostclaim.Claim, _ *hostbox.Selection) { c.Op.Exec = "src" },
44 "a stale capture": func(_ *hostclaim.Claim, s *hostbox.Selection) { s.Captured.Stamp = 8 },
45 "lost": func(c *hostclaim.Claim, _ *hostbox.Selection) { c.Lost = []string{"dst"} },
46 "not a participant": func(c *hostclaim.Claim, _ *hostbox.Selection) {
47 c.Op.Participants = []string{"src"}
48 },
49 "stuck": func(c *hostclaim.Claim, _ *hostbox.Selection) { c.Op.Journal["stuck"] = "x" },
50 } {
51 raw, _ := json.Marshal(c)
52 var copy hostclaim.Claim
53 _ = json.Unmarshal(raw, &copy)
54 s := sel
55 tweak(&copy, &s)
56 if err := policy(context.Background(), &copy, s, hostwrite.Identity{}); err == nil {
57 t.Fatalf("%s: admitted", name)
58 }
59 }
60 hold = "another-op"
61 if err := policy(context.Background(), c, sel, hostwrite.Identity{}); err == nil {
62 t.Fatal("another op's hold admitted")
63 }
64}
65
66// Ruling 68, amended in Task 8c (absence is never evidence): a live
67// platform item is installed; a missing one is "none" only under a pin of
68// a host that never published files (no digest, no retained copy); a
69// missing one under a pin of published files, and a tombstone (which no
70// publisher writes) under either pin, refuse.
71func TestRelocationPlatformItemNeedsEvidenceForNone(t *testing.T) {
72 published := hostrelocate.PinObject{Files: hostrelocate.FilesPin{Prefix: "loc/files/g-g1/", SHA256: "ab", Retained: "retained/ab"}}
73 never := hostrelocate.PinObject{Files: hostrelocate.FilesPin{Prefix: "loc/files/g-g1/"}}
74 live := hostfiles.Manifest{Platform: map[string]hostfiles.Entry{hostfiles.EnvItem: {Object: "o", SHA256: "cd", Size: 1, Seq: 1}}}
75 missing := hostfiles.Manifest{Platform: map[string]hostfiles.Entry{}}
76 tomb := hostfiles.Manifest{Platform: map[string]hostfiles.Entry{hostfiles.EnvItem: {Deleted: true, Seq: 2}}}
77 for _, tc := range []struct {
78 name string
79 pin hostrelocate.PinObject
80 m hostfiles.Manifest
81 want bool
82 err error
83 }{
84 {"a live item", published, live, true, nil},
85 {"a live item, evidence or not", never, live, true, nil},
86 {"missing under published files", published, missing, false, hostrelocate.ErrRefused},
87 {"missing under a host that never published", never, missing, false, nil},
88 {"a tombstone under published files", published, tomb, false, hostrelocate.ErrRefused},
89 {"a tombstone under a host that never published", never, tomb, false, hostrelocate.ErrRefused},
90 } {
91 got, err := relocationPlatformItem(tc.pin, tc.m, hostfiles.EnvItem)
92 if got != tc.want || !errors.Is(err, tc.err) || (tc.err == nil) != (err == nil) {
93 t.Errorf("%s: %v %v, want %v %v", tc.name, got, err, tc.want, tc.err)
94 }
95 }
96}
97