1 package lift
2
3 import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "github.com/bazelbuild/rules_go/go/tools/bazel"
9 "github.com/stretchr/testify/assert"
10 "gopkg.in/yaml.v3"
11
12 "edge-infra.dev/pkg/lib/cli/sh"
13 )
14
15 var (
16 dummyInfraCfg = CapabilityConfig{
17 "fake/infra-package",
18 ResourceMatcher{
19 APIGroups: []string{"fake.apigroup.u"},
20 },
21 }
22 dummyRuntimeCfg = CapabilityConfig{
23 "prometheus",
24 ResourceMatcher{
25 APIGroups: []string{"prometheus.real.apigroup.io"},
26 },
27 }
28 dummyRuntimeCfg2 = CapabilityConfig{
29 "linkerd",
30 ResourceMatcher{
31 APIGroups: []string{"linkerd.real.apigroup.io"},
32 },
33 }
34
35 infraOnlyCfg = Config{
36 Infrastructure: dummyInfraCfg,
37 }
38
39 dummyParameters1 = []Parameter{
40 {"special_thing_i_must_parameterize", 64, "simply got to have it"},
41 {"config_isnt_my_forte", 32, "at least im honest"},
42 }
43 dummyParameters2 = []Parameter{
44 {"foobie", 12, "foobie brothers"},
45 {"scooby", 48, "snacks"},
46 }
47 )
48
49 func TestConfig_New(t *testing.T) {
50 dir := bazel.TestTmpDir()
51 defer os.RemoveAll(dir)
52
53 cfg := &Config{Infrastructure: dummyInfraCfg}
54 cfgpath := filepath.Join(dir, "warehouse.yaml")
55 writeCfg(t, cfg, cfgpath)
56
57 t.Run("Environment variables", func(t *testing.T) {
58 whpath := "/test/path"
59 t.Setenv("WAREHOUSE_PATH", whpath)
60 cachepath := "test/cache"
61 t.Setenv("WAREHOUSE_CACHE", cachepath)
62 repo := "us-east1-docker.pkg.dev"
63 t.Setenv("WAREHOUSE_REPO", repo)
64
65 t.Setenv("WAREHOUSE_CONFIG", cfgpath)
66 actual, err := NewConfig()
67 assert.NoError(t, err)
68 assert.Equal(t, "/test/path", actual.WAREHOUSEPATH)
69 assert.Equal(t, "test/cache", actual.Cache)
70 assert.Equal(t, "us-east1-docker.pkg.dev", actual.Repo)
71
72
73 cfg := &Config{
74 WAREHOUSEPATH: "/should/be/ignored",
75 Cache: "should/be/ignored",
76 Repo: "ignored.pkg.dev",
77 Infrastructure: dummyInfraCfg,
78 }
79 writeCfg(t, cfg, cfgpath)
80
81 actual, err = NewConfig()
82 assert.NoError(t, err)
83 assert.Equal(t, "/test/path", actual.WAREHOUSEPATH)
84 assert.Equal(t, "test/cache", actual.Cache)
85 assert.Equal(t, "us-east1-docker.pkg.dev", actual.Repo)
86 })
87
88 t.Run("Cache falls back to HOME", func(t *testing.T) {
89 writeCfg(t, &Config{
90 Infrastructure: dummyInfraCfg, WAREHOUSEPATH: "/empty",
91 }, cfgpath)
92 t.Setenv("WAREHOUSE_CONFIG", cfgpath)
93
94 t.Setenv("HOME", "fake/home/for/fake/user")
95
96 actual, err := NewConfig()
97 assert.NoError(t, err)
98 assert.Equal(t, "fake/home/for/fake/user/.cache/warehouse", actual.Cache)
99 })
100
101 t.Run("WAREHOUSE_PATH falls back to repo root", func(t *testing.T) {
102 repo := createTestGitRepo(t, dir)
103 assert.NoError(t, os.Chdir(repo))
104
105 writeCfg(t, &Config{Infrastructure: dummyInfraCfg, Cache: "empty"}, cfgpath)
106 t.Setenv("WAREHOUSE_CONFIG", cfgpath)
107
108 actual, err := NewConfig()
109 assert.NoError(t, err)
110 assert.Equal(t, repo, actual.WAREHOUSEPATH)
111 })
112
113 t.Run("Config file falls back to root of WAREHOUSE_PATH", func(t *testing.T) {
114 cfgpath := filepath.Join(dir, ConfigFile)
115 writeCfg(t, &Config{Cache: "empty", Infrastructure: dummyInfraCfg}, cfgpath)
116
117 t.Setenv("WAREHOUSE_PATH", dir)
118
119 _, err := NewConfig()
120
121
122 assert.NoError(t, err)
123 })
124
125 t.Run("Config file is loaded from inferred WAREHOUSE_PATH", func(t *testing.T) {
126 repo := createTestGitRepo(t, dir)
127 assert.NoError(t, os.Chdir(repo))
128
129 writeCfg(t, &Config{
130 WAREHOUSEPATH: repo,
131 Infrastructure: dummyInfraCfg,
132 Cache: "empty",
133 }, filepath.Join(repo, ConfigFile))
134
135 actual, err := NewConfig()
136 assert.NoError(t, err)
137 assert.Equal(t, "empty", actual.Cache)
138 })
139 }
140
141 func TestConfig_Validate(t *testing.T) {
142 tcs := map[string]struct {
143 cfg Config
144 err bool
145 }{
146 "minimal": {
147 cfg: Config{WAREHOUSEPATH: "/any", Infrastructure: dummyInfraCfg},
148 err: false,
149 },
150 "empty": {
151 cfg: Config{},
152 err: true,
153 },
154 "no path": {
155 cfg: Config{Infrastructure: dummyInfraCfg},
156 err: true,
157 },
158 "relative path": {
159 cfg: Config{WAREHOUSEPATH: "any", Infrastructure: dummyInfraCfg},
160 err: true,
161 },
162 }
163
164 for name, tc := range tcs {
165 t.Run(name, func(t *testing.T) {
166 actual := tc.cfg.Validate()
167 if tc.err && actual == nil {
168 t.Error("expected error")
169 }
170 if !tc.err && actual != nil {
171 t.Error("unexpected error", actual)
172 }
173 })
174 }
175 }
176
177 func TestConfig_WithRuntime(t *testing.T) {
178 tcs := map[string]struct {
179 src Config
180 input Runtime
181 expected Config
182 err bool
183 }{
184 "empty input": {
185 infraOnlyCfg,
186 Runtime{},
187 infraOnlyCfg,
188 false,
189 },
190 "source is empty": {
191 Config{},
192 Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}},
193 Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}}},
194 false,
195 },
196 "source is not empty": {
197 Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg2}}},
198 Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}},
199 Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg2, dummyRuntimeCfg}}},
200 false,
201 },
202 "conflict": {
203 Config{Runtime: Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}}},
204 Runtime{Capabilities: []CapabilityConfig{dummyRuntimeCfg}},
205 Config{},
206 true,
207 },
208 }
209
210 for name, tc := range tcs {
211 t.Run(name, func(t *testing.T) {
212 actual, err := tc.src.WithRuntime(tc.input)
213 if err != nil && tc.err == false {
214 t.Error("unexpected error", err)
215 }
216 if err == nil && tc.err == true {
217 t.Error("expected error but got nil")
218 }
219 assert.Equal(t, tc.expected, actual)
220 })
221 }
222 }
223
224 func TestConfig_WithParameters(t *testing.T) {
225 tcs := map[string]struct {
226 src Config
227 input []Parameter
228 expected Config
229 err bool
230 }{
231 "empty input": {
232 infraOnlyCfg,
233 nil,
234 infraOnlyCfg,
235 false,
236 },
237 "source is empty": {
238 Config{},
239 dummyParameters1,
240 Config{Parameters: dummyParameters1},
241 false,
242 },
243 "source is not empty": {
244 Config{Parameters: dummyParameters2},
245 dummyParameters1,
246 Config{Parameters: append(dummyParameters2, dummyParameters1...)},
247 false,
248 },
249 "conflict": {
250 Config{Parameters: dummyParameters1},
251 dummyParameters1,
252 Config{},
253 true,
254 },
255 }
256
257 for name, tc := range tcs {
258 t.Run(name, func(t *testing.T) {
259 actual, err := tc.src.WithParameters(tc.input)
260 if err != nil && tc.err == false {
261 t.Error("unexpected error", err)
262 }
263 if err == nil && tc.err == true {
264 t.Error("expected error but got nil")
265 }
266 assert.Equal(t, tc.expected, actual)
267 })
268 }
269 }
270
271 func writeCfg(t *testing.T, cfg *Config, path string) {
272 t.Helper()
273
274 data, err := yaml.Marshal(cfg)
275 assert.NoError(t, err)
276
277 assert.NoError(t, os.WriteFile(path, data, 0644))
278 }
279
280 func createTestGitRepo(t *testing.T, dir string) string {
281 t.Helper()
282
283 repo, err := os.MkdirTemp(dir, "git_test-*")
284 assert.NoError(t, err)
285 t.Log("test repo dir", repo)
286
287 shell := sh.NewInDir(repo)
288 for _, c := range []string{
289 "git init -q",
290 "git config user.name \"testbot\"",
291 "git config user.email \"testmail@testworld.com\"",
292 "git checkout -b test",
293 } {
294 assert.NoError(t, shell.RunE(c))
295 }
296
297 return repo
298 }
299
View as plain text