1
2
3
4 package starlark
5
6 import (
7 "bytes"
8 "fmt"
9 "os"
10 "strings"
11 "testing"
12
13 "github.com/go-errors/errors"
14 "github.com/stretchr/testify/assert"
15 "sigs.k8s.io/kustomize/kyaml/kio"
16 "sigs.k8s.io/kustomize/kyaml/yaml"
17 )
18
19 func TestFilter_Filter(t *testing.T) {
20 var tests = []struct {
21 name string
22 input string
23 functionConfig string
24 script string
25 expected string
26 expectedFunctionConfig string
27 env map[string]string
28 }{
29 {
30 name: "add_annotation",
31 input: `
32 apiVersion: apps/v1
33 kind: Deployment
34 metadata:
35 name: nginx-deployment
36 spec:
37 template:
38 spec:
39 containers:
40 - name: nginx
41 # head comment
42 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
43 `,
44 script: `
45 # set the foo annotation on each resource
46 def run(r):
47 for resource in r:
48 resource["metadata"]["annotations"]["foo"] = "bar"
49
50 run(ctx.resource_list["items"])
51 `,
52 expected: `
53 apiVersion: apps/v1
54 kind: Deployment
55 metadata:
56 name: nginx-deployment
57 annotations:
58 foo: bar
59 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
60 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
61 spec:
62 template:
63 spec:
64 containers:
65 - name: nginx
66 # head comment
67 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
68 `,
69 },
70 {
71 name: "add_annotation_from_env",
72 input: `
73 apiVersion: apps/v1
74 kind: Deployment
75 metadata:
76 name: nginx-deployment
77 spec:
78 template:
79 spec:
80 containers:
81 - name: nginx
82 # head comment
83 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
84 `,
85 script: `
86 def run(r):
87 for resource in r:
88 resource["metadata"]["annotations"]["foo"] = ctx.environment["ANNOTATION"]
89
90 run(ctx.resource_list["items"])
91 `,
92 env: map[string]string{"ANNOTATION": "annotation-value"},
93 expected: `
94 apiVersion: apps/v1
95 kind: Deployment
96 metadata:
97 name: nginx-deployment
98 annotations:
99 foo: annotation-value
100 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
101 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
102 spec:
103 template:
104 spec:
105 containers:
106 - name: nginx
107 # head comment
108 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
109 `,
110 },
111 {
112 name: "add_annotation_from_open_api",
113 input: `
114 apiVersion: apps/v1
115 kind: Deployment
116 metadata:
117 name: nginx-deployment
118 spec:
119 template:
120 spec:
121 containers:
122 - name: nginx
123 # head comment
124 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
125 `,
126 script: `
127 def run(r):
128 for resource in r:
129 resource["metadata"]["annotations"]["foo"] = ctx.open_api["definitions"]["io.k8s.api.apps.v1.Deployment"]["description"]
130
131 run(ctx.resource_list["items"])
132 `,
133 expected: `
134 apiVersion: apps/v1
135 kind: Deployment
136 metadata:
137 name: nginx-deployment
138 annotations:
139 foo: Deployment enables declarative updates for Pods and ReplicaSets.
140 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
141 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
142 spec:
143 template:
144 spec:
145 containers:
146 - name: nginx
147 # head comment
148 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
149 `,
150 },
151 {
152 name: "update_annotation",
153 input: `
154 apiVersion: apps/v1
155 kind: Deployment
156 metadata:
157 name: nginx-deployment
158 annotations:
159 foo: baz
160 spec:
161 template:
162 spec:
163 containers:
164 - name: nginx
165 # head comment
166 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
167 `,
168 script: `
169 # set the foo annotation on each resource
170 def run(r):
171 for resource in r:
172 resource["metadata"]["annotations"]["foo"] = "bar"
173
174 run(ctx.resource_list["items"])
175 `,
176 expected: `
177 apiVersion: apps/v1
178 kind: Deployment
179 metadata:
180 name: nginx-deployment
181 annotations:
182 foo: bar
183 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
184 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
185 spec:
186 template:
187 spec:
188 containers:
189 - name: nginx
190 # head comment
191 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
192 `,
193 },
194 {
195 name: "delete_annotation",
196 input: `
197 apiVersion: apps/v1
198 kind: Deployment
199 metadata:
200 name: nginx-deployment
201 annotations:
202 foo: baz
203 spec:
204 template:
205 spec:
206 containers:
207 - name: nginx
208 # head comment
209 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
210 `,
211 script: `
212 # set the foo annotation on each resource
213 def run(r):
214 for resource in r:
215 resource["metadata"]["annotations"].pop("foo")
216
217 run(ctx.resource_list["items"])
218 `,
219 expected: `
220 apiVersion: apps/v1
221 kind: Deployment
222 metadata:
223 name: nginx-deployment
224 annotations:
225 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
226 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
227 spec:
228 template:
229 spec:
230 containers:
231 - name: nginx
232 # head comment
233 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
234 `,
235 },
236 {
237 name: "update_annotation_multiple",
238 input: `
239 apiVersion: apps/v1
240 kind: Deployment
241 metadata:
242 name: nginx-deployment-1
243 annotations:
244 foo: baz
245 spec:
246 template:
247 spec:
248 containers:
249 - name: nginx
250 # head comment
251 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
252 ---
253 apiVersion: apps/v1
254 kind: Deployment
255 metadata:
256 name: nginx-deployment-2
257 spec:
258 template:
259 spec:
260 containers:
261 - name: nginx
262 # head comment
263 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
264 `,
265 script: `
266 # set the foo annotation on each resource
267 def run(r):
268 for resource in r:
269 resource["metadata"]["annotations"]["foo"] = "bar"
270
271 run(ctx.resource_list["items"])
272 `,
273 expected: `
274 apiVersion: apps/v1
275 kind: Deployment
276 metadata:
277 name: nginx-deployment-1
278 annotations:
279 foo: bar
280 internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
281 config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
282 spec:
283 template:
284 spec:
285 containers:
286 - name: nginx
287 # head comment
288 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
289 ---
290 apiVersion: apps/v1
291 kind: Deployment
292 metadata:
293 name: nginx-deployment-2
294 annotations:
295 foo: bar
296 internal.config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
297 config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
298 spec:
299 template:
300 spec:
301 containers:
302 - name: nginx
303 # head comment
304 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`,
305 },
306 {
307 name: "add_resource",
308 input: `
309 apiVersion: apps/v1
310 kind: Deployment
311 metadata:
312 name: nginx-deployment-1
313 spec:
314 template:
315 spec:
316 containers:
317 - name: nginx
318 # head comment
319 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
320 `,
321 script: `
322 def run(r):
323 d = {
324 "apiVersion": "apps/v1",
325 "kind": "Deployment",
326 "metadata": {
327 "name": "nginx-deployment-2",
328 },
329 }
330 r.append(d)
331 run(ctx.resource_list["items"])
332 `,
333 expected: `
334 apiVersion: apps/v1
335 kind: Deployment
336 metadata:
337 name: nginx-deployment-1
338 annotations:
339 internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
340 config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
341 spec:
342 template:
343 spec:
344 containers:
345 - name: nginx
346 # head comment
347 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
348 ---
349 apiVersion: apps/v1
350 kind: Deployment
351 metadata:
352 name: nginx-deployment-2
353 annotations:
354 internal.config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
355 config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
356 `,
357 },
358 {
359 name: "remove_resource",
360 input: `
361 apiVersion: apps/v1
362 kind: Deployment
363 metadata:
364 name: nginx-deployment-1
365 ---
366 apiVersion: apps/v1
367 kind: Deployment
368 metadata:
369 name: nginx-deployment-2
370 `,
371 script: `
372 def run(r):
373 r.pop()
374 run(ctx.resource_list["items"])
375 `,
376 expected: `
377 apiVersion: apps/v1
378 kind: Deployment
379 metadata:
380 name: nginx-deployment-1
381 annotations:
382 internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
383 config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
384 `,
385 },
386 {
387 name: "functionConfig",
388 input: `
389 apiVersion: apps/v1
390 kind: Deployment
391 metadata:
392 name: nginx-deployment
393 spec:
394 template:
395 spec:
396 containers:
397 - name: nginx
398 # head comment
399 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
400 `,
401 functionConfig: `
402 kind: Script
403 spec:
404 value: "hello world"
405 `,
406 script: `
407 # set the foo annotation on each resource
408 def run(r, an):
409 for resource in r:
410 resource["metadata"]["annotations"]["foo"] = an
411
412 an = ctx.resource_list["functionConfig"]["spec"]["value"]
413 run(ctx.resource_list["items"], an)
414 `,
415 expected: `
416 apiVersion: apps/v1
417 kind: Deployment
418 metadata:
419 name: nginx-deployment
420 annotations:
421 foo: hello world
422 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
423 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
424 spec:
425 template:
426 spec:
427 containers:
428 - name: nginx
429 # head comment
430 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
431 `,
432 expectedFunctionConfig: `
433 kind: Script
434 spec:
435 value: "hello world"
436 `,
437 },
438
439 {
440 name: "functionConfig_update_functionConfig",
441 input: `
442 apiVersion: apps/v1
443 kind: Deployment
444 metadata:
445 name: nginx-deployment
446 spec:
447 template:
448 spec:
449 containers:
450 - name: nginx
451 # head comment
452 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
453 `,
454 functionConfig: `
455 kind: Script
456 spec:
457 value: "hello world"
458 `,
459 script: `
460 # set the foo annotation on each resource
461 def run(r, an):
462 for resource in r:
463 resource["metadata"]["annotations"]["foo"] = an
464
465 an = ctx.resource_list["functionConfig"]["spec"]["value"]
466 run(ctx.resource_list["items"], an)
467 ctx.resource_list["functionConfig"]["spec"]["value"] = "updated"
468 `,
469 expected: `
470 apiVersion: apps/v1
471 kind: Deployment
472 metadata:
473 name: nginx-deployment
474 annotations:
475 foo: hello world
476 internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
477 config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
478 spec:
479 template:
480 spec:
481 containers:
482 - name: nginx
483 # head comment
484 image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
485 `,
486 expectedFunctionConfig: `
487 kind: Script
488 spec:
489 value: "hello world"
490 `,
491 },
492 }
493 for i := range tests {
494 test := tests[i]
495 t.Run(test.name, func(t *testing.T) {
496 for k, v := range test.env {
497 os.Setenv(k, v)
498 }
499 f := &Filter{Name: test.name, Program: test.script}
500
501 if test.functionConfig != "" {
502 fc, err := yaml.Parse(test.functionConfig)
503 if !assert.NoError(t, err) {
504 t.FailNow()
505 }
506 f.FunctionConfig = fc
507 }
508
509 r := &kio.ByteReader{Reader: bytes.NewBufferString(test.input)}
510 o := &bytes.Buffer{}
511 w := &kio.ByteWriter{Writer: o}
512 p := kio.Pipeline{
513 Inputs: []kio.Reader{r},
514 Filters: []kio.Filter{f},
515 Outputs: []kio.Writer{w},
516 }
517 err := p.Execute()
518 if !assert.NoError(t, err) {
519 if e, ok := err.(*errors.Error); ok {
520 fmt.Fprintf(os.Stderr, "%s\n", e.Stack())
521 }
522 t.FailNow()
523 }
524 if !assert.Equal(t, strings.TrimSpace(test.expected), strings.TrimSpace(o.String())) {
525 t.FailNow()
526 }
527
528 if test.expectedFunctionConfig != "" {
529 if !assert.Equal(t,
530 strings.TrimSpace(test.expectedFunctionConfig),
531 strings.TrimSpace(f.FunctionConfig.MustString())) {
532 t.FailNow()
533 }
534 }
535 })
536 }
537 }
538
View as plain text