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 "os"
6 "strings"
7 "testing"
8
9 "github.com/carlosframework/platform/internal/hostguard"
10 "github.com/carlosframework/platform/internal/rootstate"
11)
12
13func TestPlan14UnitPredecessorHandover(t *testing.T) {
14 for _, attack := range []string{"none", "not retired", "same owner", "shape", "replacement", "lost materialization"} {
15 t.Run(attack, func(t *testing.T) {
16 b, in, shape := plan14UnitBindingFixture(t, "console.service", "", "")
17 shape.Program = strings.Repeat("a", 64)
18 b.canonical = func(context.Context, string) (claimUnitShape, error) { return shape, nil }
19 b.installation = func(context.Context, string) (hostguard.RootInstallation, error) { return in, nil }
20 files := &plan14UnitFiles{}
21 state := &plan14UnitBindingFault{Store: &rollbackMemory{files: map[string][]byte{}}}
22 m := claimUnitMaterializer{idle: func(string) error { return nil }, state: state, read: files.read, create: files.create, replace: files.replace}
23 b.handover = m.handover
24 old, err := b.establish(t.Context(), in.Host)
25 if err != nil {
26 t.Fatal(err)
27 }
28 if err = m.install(t.Context(), old); err != nil {
29 t.Fatal(err)
30 }
31 if attack != "not retired" {
32 if err = b.retire(t.Context(), old, func(claimUnitBinding) error { return m.retire(t.Context(), old, func() error { return nil }) }); err != nil {
33 t.Fatal(err)
34 }
35 }
36 if attack != "same owner" {
37 in.Stamp++
38 }
39 if attack == "shape" {
40 shape.Addr = "127.0.0.1:9999"
41 }
42 if attack == "replacement" {
43 files.id.Inode++
44 }
45 original := m.replace
46 if attack == "lost materialization" {
47 m.replace = func(unit string, id rootstate.FileIdentity, body []byte) error {
48 if err := original(unit, id, body); err != nil {
49 return err
50 }
51 return os.ErrInvalid
52 }
53 b.handover = m.handover
54 }
55 next, err := b.establish(t.Context(), in.Host)
56 if attack != "none" && attack != "lost materialization" {
57 if err == nil {
58 t.Fatal("unsafe handover accepted", next)
59 }
60 return
61 }
62 if attack == "lost materialization" {
63 if err == nil {
64 t.Fatal("lost replacement reported success")
65 }
66 m.replace = original
67 b.handover = m.handover
68 next, err = b.establish(t.Context(), in.Host)
69 }
70 if err != nil {
71 t.Fatal(err)
72 }
73 if next.Owner.Stamp != in.Stamp || next.Retired || next.Retiring {
74 t.Fatal(next)
75 }
76 if err = m.verify(next); err != nil {
77 t.Fatal(err)
78 }
79 if err = b.retire(t.Context(), old, func(claimUnitBinding) error { t.Fatal("predecessor reached successor"); return nil }); err == nil {
80 t.Fatal("stale retirement accepted")
81 }
82 if _, err = b.establish(t.Context(), in.Host); err != nil {
83 t.Fatal("replay", err)
84 }
85 })
86 }
87}
88