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 "encoding/json"
5 "os"
6 "path/filepath"
7 "sort"
8 "strings"
9 "testing"
10
11 "github.com/carlosframework/platform/internal/hostclaim"
12)
13
14// retirementsByOp is how F3 finds a host's local retirements by op, one rule
15// for both receipts a retirement can carry (K20): park.Local's .journal.json
16// (Op) and the moves-owned rename's moves-retirement.json (op), each in the
17// event directory .parked/<incarnation>/<host>/<retirement>/. It returns the
18// retirement ids whose receipt names op, and those with no readable receipt.
19// This is the one copy of the rule; internal/park's test checks only that
20// park.Local's journal carries Op.
21func retirementsByOp(t *testing.T, dataDir, incarnation, host, op string) (found, unreadable []string) {
22 t.Helper()
23 dir := filepath.Join(dataDir, ".parked", incarnation, host)
24 es, err := os.ReadDir(dir)
25 if err != nil {
26 t.Fatal(err)
27 }
28 for _, e := range es {
29 var engine struct{ Op string }
30 var owned struct {
31 Op string `json:"op"`
32 }
33 named := ""
34 if b, err := os.ReadFile(filepath.Join(dir, e.Name(), ".journal.json")); err == nil && json.Unmarshal(b, &engine) == nil {
35 named = engine.Op
36 } else if b, err := os.ReadFile(filepath.Join(dir, e.Name(), localParkReceiptName)); err == nil && json.Unmarshal(b, &owned) == nil {
37 named = owned.Op
38 } else {
39 unreadable = append(unreadable, e.Name())
40 continue
41 }
42 if named == op {
43 found = append(found, e.Name())
44 }
45 }
46 sort.Strings(found)
47 return found, unreadable
48}
49
50// TestMoveLocalRetirementsAreFindableByOp (moves spec §6.4, D6, K20): a
51// move leaves two local receipts, not one. A registered source's
52// finalization retires its installation through park.Local (.journal.json)
53// and parks what the inventory does not list by the moves-owned rename
54// (moves-retirement.json), each in its own retirement under the engine's
55// layout. Both name the move's op, and nothing under the host's
56// incarnation lacks a receipt, so F3 finds every local retirement of the
57// move by op with one rule.
58func TestMoveLocalRetirementsAreFindableByOp(t *testing.T) {
59 t.Parallel()
60 h := newFinalHarness(t)
61 dd := h.cfg.DataDir
62 for _, d := range []string{"hostguard", ".parked"} {
63 if err := os.MkdirAll(filepath.Join(dd, d), 0o770); err != nil {
64 t.Fatal(err)
65 }
66 }
67 rec := `{"v":1,"host":"` + p1Host + `","incarnation":"` + h.inc + `","active_stamp":1,"retired_stamps":[]}`
68 if err := os.WriteFile(filepath.Join(dd, "hostguard", p1Host+".json"), []byte(rec), 0o660); err != nil {
69 t.Fatal(err)
70 }
71 rewriteP1Claim(t, h.s, func(c *hostclaim.Claim) {
72 if c.Inventory == nil {
73 c.Inventory = map[string]hostclaim.InventoryEntry{}
74 }
75 c.Inventory["ie-box"] = hostclaim.InventoryEntry{Layout: "flat", Paths: map[string]uint64{p1Host + ".db": 1, p1Host + ".db.gen": 1, p1Host: 1, p1Host + ".env": 1}}
76 })
77 h.commit(t)
78 var chore hostclaim.Obligation
79 for _, o := range h.claim(t).Obligations {
80 if o.Kind == "park-local" {
81 chore = o
82 }
83 }
84 if chore.Op != p1ID {
85 t.Fatalf("the commit queued no park-local of the move: %+v", h.claim(t).Obligations)
86 }
87 h.sourcePass(t)
88 owned := h.parkedJournal(t).Steps[finalStepLocal]
89 if owned == "" || owned == chore.Retirement {
90 t.Fatalf("the moves-owned retirement %q, park.Local's %q", owned, chore.Retirement)
91 }
92 for _, receipt := range []string{filepath.Join(chore.Retirement, ".journal.json"), filepath.Join(owned, localParkReceiptName)} {
93 if _, err := os.Stat(filepath.Join(dd, ".parked", h.inc, p1Host, receipt)); err != nil {
94 t.Fatalf("the receipt %s: %v", receipt, err)
95 }
96 }
97 found, unreadable := retirementsByOp(t, dd, h.inc, p1Host, p1ID)
98 want := []string{chore.Retirement, owned}
99 sort.Strings(want)
100 if strings.Join(found, " ") != strings.Join(want, " ") || len(unreadable) != 0 {
101 t.Fatalf("by op %s: found %v (want %v), no receipt %v", p1ID, found, want, unreadable)
102 }
103 if other, _ := retirementsByOp(t, dd, h.inc, p1Host, "mv_zzzzzzzzzzzzzzzzzzzzzzzzzz"); len(other) != 0 {
104 t.Fatalf("another op found the move's retirements: %v", other)
105 }
106}
107