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/base64"
6 "net"
7 "os"
8 "path/filepath"
9 "testing"
10
11 "github.com/carlosframework/platform/internal/hostclaim"
12 "github.com/carlosframework/platform/internal/hostguard"
13 "github.com/carlosframework/platform/internal/provision"
14 "github.com/carlosframework/platform/internal/registry"
15 "github.com/carlosframework/platform/internal/release"
16 "github.com/carlosframework/platform/internal/rootstate"
17)
18
19func generationHeldProductionSource(t *testing.T, f *hrFixture) generationPinSource {
20 t.Helper()
21 reg, err := registry.Open(filepath.Join(t.TempDir(), "registry.db"))
22 if err != nil {
23 t.Fatal(err)
24 }
25 t.Cleanup(func() { reg.Close() })
26 a := &ClaimAssembly{Guard: hostguard.Guard{DataDir: f.data, Root: hostguard.NewRootAuthority(&rollbackDisk{dir: t.TempDir()})}, ManagedRoots: map[string]string{"opt": f.opt}}
27 ctx := context.WithValue(t.Context(), claimEntryKey{}, claimEntry{Assembly: a, Store: f.s})
28 root := ClaimRootWithLaunch{Root: ClaimRootHTTP{Stop: ClaimStopHTTP{Authenticate: func(context.Context, net.Conn) (StopPeer, error) { return hrPeer, nil }}}}
29 h, err := WithProductionMovesHeldRelease(ctx, root, reg, func(key string) string {
30 switch key {
31 case "CARLOS_MOVES_PHASE1":
32 return "1"
33 case "CARLOS_RELEASE_PUBKEY":
34 return base64.StdEncoding.EncodeToString(hsPub)
35 }
36 return ""
37 })
38 if err != nil {
39 t.Fatal(err)
40 }
41 held, ok := h.(ClaimRootWithLaunch).HeldRelease.(*movesHeldReleaseRoot)
42 if !ok {
43 t.Fatal("held root was not assembled")
44 }
45 source, ok := held.generationPins.(generationPinSource)
46 if !ok {
47 t.Fatal("held root has no production generation source")
48 }
49 return source
50}
51
52func TestPlan14GenerationHeldStage(t *testing.T) {
53 for _, action := range []string{heldReleaseStage, heldReleasePublish} {
54 for _, mode := range []string{"pinned", "unknown", "legacy", "legacy-flag", "fresh"} {
55 t.Run(action+"/"+mode, func(t *testing.T) {
56 f := newHRFixture(t)
57 source := generationHeldProductionSource(t, f)
58 lock := &plan14ReleaseStore{}
59 f.root.OpenRelease = func() (rootstate.Store, error) { return lock, nil }
60 if action == heldReleaseStage {
61 f.set(func(f *hrFixture) {
62 f.claim.Op = hostclaim.Op{Kind: hostclaim.KindMoving, ID: p1ID, Exec: "ie-box", Participants: []string{"ie-box", "uk-box"}, Intent: map[string]string{"source": "ie-box", "target": "uk-box", "to": "uk"}}
63 f.rec.Move.State, f.rec.Move.LandingPhase, f.rec.Move.Inputs = provision.MoveReady, "", nil
64 f.row = nil
65 })
66 }
67 path := release.VersionPath(f.opt, "bab", "v7", "app")
68 if mode != "fresh" {
69 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
70 t.Fatal(err)
71 }
72 }
73 reads, opens := 0, 0
74 f.root.generationPins = release.PinSourceFunc(func(context.Context, string) (release.StagedPaths, error) {
75 if !lock.held {
76 t.Fatal("pin read outside release exclusion")
77 }
78 if _, err := os.Lstat(filepath.Join(f.data, ".moves", heldStageLockFile(p1Host))); !os.IsNotExist(err) {
79 t.Fatalf("pin reader runs inside held-stage leaf lock: %v", err)
80 }
81 reads++
82 if mode == "pinned" {
83 return release.StagedPaths{filepath.Dir(path): true}, nil
84 }
85 return nil, os.ErrPermission
86 })
87 if mode == "legacy" || mode == "legacy-flag" {
88 if mode == "legacy-flag" {
89 t.Setenv("CARLOS_HOST_CLAIM", "1")
90 } else {
91 t.Setenv("CARLOS_HOST_CLAIM", "")
92 }
93 source.legacy = func() (bool, error) { return true, nil }
94 source.open = func() (rootstate.Store, error) { opens++; return nil, os.ErrPermission }
95 f.root.generationPins = source
96 }
97 _, err := f.root.Serve(t.Context(), hrPeer, f.request(action))
98 if mode == "pinned" || mode == "unknown" {
99 if err == nil || reads == 0 {
100 t.Fatalf("held write bypassed reservations: %v reads=%d", err, reads)
101 }
102 if _, err := os.Stat(path); !os.IsNotExist(err) {
103 t.Fatalf("protected path written: %v", err)
104 }
105 if _, err := os.Lstat(release.LiveLink(f.opt, p1Host)); !os.IsNotExist(err) {
106 t.Fatalf("held release published: %v", err)
107 }
108 if entries, err := os.ReadDir(f.receipts); err != nil || len(entries) != 0 {
109 t.Fatalf("refused release receipted: %v %v", entries, err)
110 }
111 } else {
112 if err != nil || opens != 0 || reads != 0 {
113 t.Fatalf("permitted held stage refused: %v opens=%d reads=%d", err, opens, reads)
114 }
115 if _, err := os.Stat(path); err != nil {
116 t.Fatal(err)
117 }
118 live, liveErr := release.LiveVersion(f.opt, p1Host)
119 if liveErr != nil {
120 t.Fatal(liveErr)
121 }
122 if action == heldReleasePublish && live != "v7" || action == heldReleaseStage && live != "" {
123 t.Fatalf("wrong live effect: %q", live)
124 }
125 entries, err := os.ReadDir(f.receipts)
126 if err != nil || action == heldReleasePublish && len(entries) != 1 || action == heldReleaseStage && len(entries) != 0 {
127 t.Fatalf("wrong receipt effect: %v %v", entries, err)
128 }
129 if _, err := os.Stat(release.StagedManifestPath(f.opt, "bab", "v7", "app")); err != nil {
130 t.Fatal(err)
131 }
132 }
133 })
134 }
135 }
136}
137