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 "errors"
5 "os"
6 "path/filepath"
7 "testing"
8
9 "github.com/carlosframework/platform/internal/hostbox"
10 "github.com/carlosframework/platform/internal/provision"
11 "github.com/carlosframework/platform/internal/registry"
12)
13
14// flatClaimEnvFile is a test's env file resolver: every host's env file
15// flat under dir, as the fixtures that predate the row's layout place it.
16func flatClaimEnvFile(dir string) func(host, dbPath string) (claimEnvFile, error) {
17 return func(host, _ string) (claimEnvFile, error) { return claimEnvFile{Dir: dir, Name: host + ".env"}, nil }
18}
19
20// envFileOf adapts a moves FilesDir to the provider's resolver: the env
21// path it names, flat.
22func envFileOf(filesDir func(string) (string, string)) func(host, dbPath string) (claimEnvFile, error) {
23 return func(host, _ string) (claimEnvFile, error) {
24 _, env := filesDir(host)
25 return claimEnvFile{Dir: filepath.Dir(env), Name: filepath.Base(env)}, nil
26 }
27}
28
29// testClaimRoutes is a registry's rows by host; err answers every read.
30type testClaimRoutes struct {
31 rows map[string]registry.Route
32 err error
33}
34
35func (r testClaimRoutes) Get(host string) (*registry.Route, error) {
36 if r.err != nil {
37 return nil, r.err
38 }
39 rt, ok := r.rows[host]
40 if !ok {
41 return nil, nil
42 }
43 return &rt, nil
44}
45
46func (r testClaimRoutes) List() ([]registry.Route, error) {
47 if r.err != nil {
48 return nil, r.err
49 }
50 var out []registry.Route
51 for _, rt := range r.rows {
52 out = append(out, rt)
53 }
54 return out, nil
55}
56
57// Merge round 6, finding 2: the provider finds a host's env file through
58// its row, as the launch source does. A nested row's is in its instance
59// directory, a flat or foreign row's is flat; no row, a row that cannot be
60// read, a row that is not the wake's, and a layout migration in flight
61// each refuse, never a guess at the flat path.
62func TestClaimEnvFileFollowsTheRowsLayout(t *testing.T) {
63 dataDir := t.TempDir()
64 const host = "shop.example.com"
65 nested := registry.Route{Host: host, Kind: "instance", Hibernate: true, DBPath: provision.NestedDBPath(dataDir, host), Socket: provision.NestedSocket(host)}
66 flat := registry.Route{Host: host, Kind: "instance", Hibernate: true, DBPath: provision.DefaultDBPath(dataDir, host), Socket: filepath.Join(provision.SocketDir, host+".sock")}
67 foreign := registry.Route{Host: host, Kind: "instance", Hibernate: true, DBPath: filepath.Join(dataDir, "elsewhere", host+".db"), Socket: "/run/other.sock"}
68 resolve := func(rt registry.Route) func(string, string) (claimEnvFile, error) {
69 return claimEnvFileFor(dataDir, testClaimRoutes{rows: map[string]registry.Route{host: rt}})
70 }
71 got, err := resolve(nested)(host, nested.DBPath)
72 if err != nil || got != (claimEnvFile{Dir: provision.InstanceDir(dataDir, host), Name: host + ".env", Nested: true}) {
73 t.Fatalf("nested: %+v %v", got, err)
74 }
75 for name, rt := range map[string]registry.Route{"flat": flat, "foreign": foreign} {
76 got, err := resolve(rt)(host, rt.DBPath)
77 if err != nil || got != (claimEnvFile{Dir: dataDir, Name: host + ".env"}) {
78 t.Fatalf("%s: %+v %v", name, got, err)
79 }
80 }
81 // The wake's row must be the row: another database path is a row that
82 // moved since the wake selected it.
83 if _, err := resolve(nested)(host, flat.DBPath); !errors.Is(err, hostbox.ErrChanged) {
84 t.Fatalf("a row that moved: %v", err)
85 }
86 if _, err := resolve(nested)(host, ""); !errors.Is(err, hostbox.ErrChanged) {
87 t.Fatalf("no database path: %v", err)
88 }
89 if _, err := claimEnvFileFor(dataDir, testClaimRoutes{})(host, nested.DBPath); !errors.Is(err, hostbox.ErrChanged) {
90 t.Fatalf("no row: %v", err)
91 }
92 unreadable := errors.New("registry: disk I/O error")
93 if _, err := claimEnvFileFor(dataDir, testClaimRoutes{err: unreadable})(host, nested.DBPath); !errors.Is(err, unreadable) {
94 t.Fatalf("an unreadable registry: %v", err)
95 }
96 // A layout migration in flight: the env file may be at either path.
97 journal := provision.LayoutJournalPath(dataDir, host)
98 if err := os.MkdirAll(filepath.Dir(journal), 0o700); err != nil {
99 t.Fatal(err)
100 }
101 if err := os.WriteFile(journal, []byte("{}"), 0o600); err != nil {
102 t.Fatal(err)
103 }
104 for name, rt := range map[string]registry.Route{"nested": nested, "flat": flat} {
105 if _, err := resolve(rt)(host, rt.DBPath); !errors.Is(err, hostbox.ErrChanged) {
106 t.Fatalf("%s under a layout journal: %v", name, err)
107 }
108 }
109}
110