carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package host
4
5import (
6 "context"
7 "encoding/json"
8 "testing"
9
10 "github.com/carlosframework/platform/internal/hostbox"
11 "github.com/carlosframework/platform/internal/hostguard"
12 "github.com/carlosframework/platform/internal/instancectl"
13)
14
15func TestServingParkRequiresRootObservedTenantStart(t *testing.T) {
16 t.Parallel()
17 for _, state := range []string{"prelaunch", "intended", "started", "settled-unobserved", "settled-started", "tombstoned", "cancelled", "missing", "remote"} {
18 for _, database := range []bool{true, false} {
19 t.Run(state+map[bool]string{true: "/database", false: "/no-database"}[database], func(t *testing.T) {
20 f, _, _, in := servingRetirementFixture(t)
21 admitted := servingAdmit(t, f, &in, "G")
22 receipt := servingStop(t, f, admitted)
23 target := receipt.Target
24 if state != "missing" {
25 if err := f.journal.Prelaunch(t.Context(), hostbox.LaunchInventory{Target: target, ControllerPID: 77, ProcessStart: "controller-start", NoState: true, Groups: []hostbox.LaunchGroup{{RelativePath: "carlos/parent", Device: 1, Inode: 2}}}); err != nil {
26 t.Fatal(err)
27 }
28 }
29 reservation := hostbox.LaunchReservation{ID: "attempt:main", Role: "main", InvocationID: "attempt-invocation", Inputs: "inputs", Target: target, Group: hostbox.LaunchGroup{RelativePath: instancectl.ClaimUnitControlGroup(target.Host)}, Executable: hostbox.LaunchFile{Device: 1, Inode: 3}}
30 switch state {
31 case "intended", "started", "settled-unobserved", "settled-started":
32 if err := f.journal.IntendUnit(t.Context(), reservation); err != nil {
33 t.Fatal(err)
34 }
35 case "tombstoned", "cancelled":
36 if err := f.journal.TombstoneUnit(t.Context(), reservation); err != nil {
37 t.Fatal(err)
38 }
39 }
40 if state == "started" || state == "settled-started" {
41 group := hostbox.LaunchGroup{RelativePath: reservation.Group.RelativePath, Device: 1, Inode: 4, InvocationID: "unit-invocation"}
42 if err := f.journal.StartedUnit(t.Context(), reservation, group, 99, "tenant-start"); err != nil {
43 t.Fatal(err)
44 }
45 }
46 if state == "settled-started" || state == "settled-unobserved" {
47 if err := f.journal.SettleUnit(t.Context(), target, reservation.ID); err != nil {
48 t.Fatal(err)
49 }
50 }
51 if state == "cancelled" {
52 if err := f.journal.CloseWriters(t.Context(), target); err != nil {
53 t.Fatal(err)
54 }
55 }
56 journal := f.journal
57 remoteCalls := 0
58 if state == "remote" {
59 journal, _ = hostbox.RemoteJournals(func(context.Context, hostbox.JournalRequest) (hostbox.JournalResponse, error) {
60 remoteCalls++
61 return hostbox.JournalResponse{}, nil
62 })
63 }
64 prior, err := servingWriterIdentity(admitted, "box-1", "ie")
65 if err != nil {
66 t.Fatal(err)
67 }
68 receipts := []hostguard.FenceReceipt{receipt}
69 if state == "cancelled" {
70 recovered := receipt
71 recovered.Target.ControllerID = "recovery-controller"
72 recovered.Target.FenceID = "recovery-fence"
73 var proof StopReceipt
74 if err := json.Unmarshal(receipt.Bytes, &proof); err != nil {
75 t.Fatal(err)
76 }
77 proof.ControllerID, proof.FenceID = recovered.Target.ControllerID, recovered.Target.FenceID
78 recovered.Bytes = mustMarshalStopReceipt(proof)
79 receipts = append([]hostguard.FenceReceipt{recovered}, receipts...)
80 }
81 got, err := servingGenerationParkDisposition(t.Context(), journal, prior, receipts, database)
82 want := servingParkRefuse
83 if !database {
84 want = servingParkArtifactFree
85 } else if state == "prelaunch" || state == "cancelled" {
86 want = servingParkDiscard
87 } else if state == "settled-started" {
88 want = servingParkRetain
89 }
90 if got != want || (err != nil) != (want == servingParkRefuse) {
91 t.Fatalf("got %v,%v want %v", got, err, want)
92 }
93 if remoteCalls != 0 {
94 t.Fatal("root retirement trusted agent journal")
95 }
96 })
97 }
98 }
99}
100