1
16
17 package create
18
19 import (
20 "os"
21 "testing"
22
23 "github.com/stretchr/testify/require"
24
25 corev1 "k8s.io/api/core/v1"
26 apiequality "k8s.io/apimachinery/pkg/api/equality"
27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28 )
29
30 func TestCreateConfigMap(t *testing.T) {
31 tests := map[string]struct {
32 configMapName string
33 configMapType string
34 appendHash bool
35 fromLiteral []string
36 fromFile []string
37 fromEnvFile []string
38 setup func(t *testing.T, configMapOptions *ConfigMapOptions) func()
39
40 expected *corev1.ConfigMap
41 expectErr string
42 }{
43 "create_foo_configmap": {
44 configMapName: "foo",
45 expected: &corev1.ConfigMap{
46 TypeMeta: metav1.TypeMeta{
47 APIVersion: corev1.SchemeGroupVersion.String(),
48 Kind: "ConfigMap",
49 },
50 ObjectMeta: metav1.ObjectMeta{
51 Name: "foo",
52 },
53 Data: map[string]string{},
54 BinaryData: map[string][]byte{},
55 },
56 },
57 "create_foo_hash_configmap": {
58 configMapName: "foo",
59 appendHash: true,
60 expected: &corev1.ConfigMap{
61 TypeMeta: metav1.TypeMeta{
62 APIVersion: corev1.SchemeGroupVersion.String(),
63 Kind: "ConfigMap",
64 },
65 ObjectMeta: metav1.ObjectMeta{
66 Name: "foo-867km9574f",
67 },
68 Data: map[string]string{},
69 BinaryData: map[string][]byte{},
70 },
71 },
72 "create_foo_type_configmap": {
73 configMapName: "foo",
74 configMapType: "my-type",
75 expected: &corev1.ConfigMap{
76 TypeMeta: metav1.TypeMeta{
77 APIVersion: corev1.SchemeGroupVersion.String(),
78 Kind: "ConfigMap",
79 },
80 ObjectMeta: metav1.ObjectMeta{
81 Name: "foo",
82 },
83 Data: map[string]string{},
84 BinaryData: map[string][]byte{},
85 },
86 },
87 "create_foo_type_hash_configmap": {
88 configMapName: "foo",
89 configMapType: "my-type",
90 appendHash: true,
91 expected: &corev1.ConfigMap{
92 TypeMeta: metav1.TypeMeta{
93 APIVersion: corev1.SchemeGroupVersion.String(),
94 Kind: "ConfigMap",
95 },
96 ObjectMeta: metav1.ObjectMeta{
97 Name: "foo-867km9574f",
98 },
99 Data: map[string]string{},
100 BinaryData: map[string][]byte{},
101 },
102 },
103 "create_foo_two_literal_configmap": {
104 configMapName: "foo",
105 fromLiteral: []string{"key1=value1", "key2=value2"},
106 expected: &corev1.ConfigMap{
107 TypeMeta: metav1.TypeMeta{
108 APIVersion: corev1.SchemeGroupVersion.String(),
109 Kind: "ConfigMap",
110 },
111 ObjectMeta: metav1.ObjectMeta{
112 Name: "foo",
113 },
114 Data: map[string]string{
115 "key1": "value1",
116 "key2": "value2",
117 },
118 BinaryData: map[string][]byte{},
119 },
120 },
121 "create_foo_two_literal_hash_configmap": {
122 configMapName: "foo",
123 fromLiteral: []string{"key1=value1", "key2=value2"},
124 appendHash: true,
125 expected: &corev1.ConfigMap{
126 TypeMeta: metav1.TypeMeta{
127 APIVersion: corev1.SchemeGroupVersion.String(),
128 Kind: "ConfigMap",
129 },
130 ObjectMeta: metav1.ObjectMeta{
131 Name: "foo-gcb75dd9gb",
132 },
133 Data: map[string]string{
134 "key1": "value1",
135 "key2": "value2",
136 },
137 BinaryData: map[string][]byte{},
138 },
139 },
140 "create_foo_key1_=value1_configmap": {
141 configMapName: "foo",
142 fromLiteral: []string{"key1==value1"},
143 expected: &corev1.ConfigMap{
144 TypeMeta: metav1.TypeMeta{
145 APIVersion: corev1.SchemeGroupVersion.String(),
146 Kind: "ConfigMap",
147 },
148 ObjectMeta: metav1.ObjectMeta{
149 Name: "foo",
150 },
151 Data: map[string]string{
152 "key1": "=value1",
153 },
154 BinaryData: map[string][]byte{},
155 },
156 },
157 "create_foo_key1_=value1_hash_configmap": {
158 configMapName: "foo",
159 fromLiteral: []string{"key1==value1"},
160 appendHash: true,
161 expected: &corev1.ConfigMap{
162 TypeMeta: metav1.TypeMeta{
163 APIVersion: corev1.SchemeGroupVersion.String(),
164 Kind: "ConfigMap",
165 },
166 ObjectMeta: metav1.ObjectMeta{
167 Name: "foo-bdgk9ttt7m",
168 },
169 Data: map[string]string{
170 "key1": "=value1",
171 },
172 BinaryData: map[string][]byte{},
173 },
174 },
175 "create_foo_from_file_foo1_foo2_configmap": {
176 configMapName: "foo",
177 setup: setupBinaryFile([]byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}),
178 fromFile: []string{"foo1", "foo2"},
179 expected: &corev1.ConfigMap{
180 TypeMeta: metav1.TypeMeta{
181 APIVersion: corev1.SchemeGroupVersion.String(),
182 Kind: "ConfigMap",
183 },
184 ObjectMeta: metav1.ObjectMeta{
185 Name: "foo",
186 },
187 Data: map[string]string{
188 "foo1": "hello world",
189 "foo2": "hello world",
190 },
191 BinaryData: map[string][]byte{},
192 },
193 },
194 "create_foo_from_file_foo1_foo2_and_configmap": {
195 configMapName: "foo",
196 setup: setupBinaryFile([]byte{0xff, 0xfd}),
197 fromFile: []string{"foo1", "foo2"},
198 expected: &corev1.ConfigMap{
199 TypeMeta: metav1.TypeMeta{
200 APIVersion: corev1.SchemeGroupVersion.String(),
201 Kind: "ConfigMap",
202 },
203 ObjectMeta: metav1.ObjectMeta{
204 Name: "foo",
205 },
206 Data: map[string]string{},
207 BinaryData: map[string][]byte{
208 "foo1": {0xff, 0xfd},
209 "foo2": {0xff, 0xfd},
210 },
211 },
212 },
213 "create_valid_env_from_env_file_configmap": {
214 configMapName: "valid_env",
215 setup: setupEnvFile([][]string{{"key1=value1", "#", "", "key2=value2"}}),
216 fromEnvFile: []string{"file.env"},
217 expected: &corev1.ConfigMap{
218 TypeMeta: metav1.TypeMeta{
219 APIVersion: corev1.SchemeGroupVersion.String(),
220 Kind: "ConfigMap",
221 },
222 ObjectMeta: metav1.ObjectMeta{
223 Name: "valid_env",
224 },
225 Data: map[string]string{
226 "key1": "value1",
227 "key2": "value2",
228 },
229 BinaryData: map[string][]byte{},
230 },
231 },
232 "create_two_valid_env_from_env_file_configmap": {
233 configMapName: "two_valid_env",
234 setup: setupEnvFile([][]string{{"key1=value1", "#", "", "key2=value2"}, {"key3=value3"}}),
235 fromEnvFile: []string{"file1.env", "file2.env"},
236 expected: &corev1.ConfigMap{
237 TypeMeta: metav1.TypeMeta{
238 APIVersion: corev1.SchemeGroupVersion.String(),
239 Kind: "ConfigMap",
240 },
241 ObjectMeta: metav1.ObjectMeta{
242 Name: "two_valid_env",
243 },
244 Data: map[string]string{
245 "key1": "value1",
246 "key2": "value2",
247 "key3": "value3",
248 },
249 BinaryData: map[string][]byte{},
250 },
251 },
252 "create_valid_env_from_env_file_hash_configmap": {
253 configMapName: "valid_env",
254 setup: setupEnvFile([][]string{{"key1=value1", "#", "", "key2=value2"}}),
255 fromEnvFile: []string{"file.env"},
256 appendHash: true,
257 expected: &corev1.ConfigMap{
258 TypeMeta: metav1.TypeMeta{
259 APIVersion: corev1.SchemeGroupVersion.String(),
260 Kind: "ConfigMap",
261 },
262 ObjectMeta: metav1.ObjectMeta{
263 Name: "valid_env-2cgh8552ch",
264 },
265 Data: map[string]string{
266 "key1": "value1",
267 "key2": "value2",
268 },
269 BinaryData: map[string][]byte{},
270 },
271 },
272 "create_two_valid_env_from_env_file_hash_configmap": {
273 configMapName: "two_valid_env",
274 setup: setupEnvFile([][]string{{"key1=value1", "#", "", "key2=value2"}, {"key3=value3"}}),
275 fromEnvFile: []string{"file1.env", "file2.env"},
276 appendHash: true,
277 expected: &corev1.ConfigMap{
278 TypeMeta: metav1.TypeMeta{
279 APIVersion: corev1.SchemeGroupVersion.String(),
280 Kind: "ConfigMap",
281 },
282 ObjectMeta: metav1.ObjectMeta{
283 Name: "two_valid_env-2m5tm82522",
284 },
285 Data: map[string]string{
286 "key1": "value1",
287 "key2": "value2",
288 "key3": "value3",
289 },
290 BinaryData: map[string][]byte{},
291 },
292 },
293 "create_get_env_from_env_file_configmap": {
294 configMapName: "get_env",
295 setup: func() func(t *testing.T, configMapOptions *ConfigMapOptions) func() {
296 t.Setenv("g_key1", "1")
297 t.Setenv("g_key2", "2")
298 return setupEnvFile([][]string{{"g_key1", "g_key2="}})
299 }(),
300 fromEnvFile: []string{"file.env"},
301 expected: &corev1.ConfigMap{
302 TypeMeta: metav1.TypeMeta{
303 APIVersion: corev1.SchemeGroupVersion.String(),
304 Kind: "ConfigMap",
305 },
306 ObjectMeta: metav1.ObjectMeta{
307 Name: "get_env",
308 },
309 Data: map[string]string{
310 "g_key1": "1",
311 "g_key2": "",
312 },
313 BinaryData: map[string][]byte{},
314 },
315 },
316 "create_get_env_from_env_file_hash_configmap": {
317 configMapName: "get_env",
318 setup: func() func(t *testing.T, configMapOptions *ConfigMapOptions) func() {
319 t.Setenv("g_key1", "1")
320 t.Setenv("g_key2", "2")
321 return setupEnvFile([][]string{{"g_key1", "g_key2="}})
322 }(),
323 fromEnvFile: []string{"file.env"},
324 appendHash: true,
325 expected: &corev1.ConfigMap{
326 TypeMeta: metav1.TypeMeta{
327 APIVersion: corev1.SchemeGroupVersion.String(),
328 Kind: "ConfigMap",
329 },
330 ObjectMeta: metav1.ObjectMeta{
331 Name: "get_env-54k882kkd2",
332 },
333 Data: map[string]string{
334 "g_key1": "1",
335 "g_key2": "",
336 },
337 BinaryData: map[string][]byte{},
338 },
339 },
340 "create_value_with_space_from_env_file_configmap": {
341 configMapName: "value_with_space",
342 setup: setupEnvFile([][]string{{"key1= value1"}}),
343 fromEnvFile: []string{"file.env"},
344 expected: &corev1.ConfigMap{
345 TypeMeta: metav1.TypeMeta{
346 APIVersion: corev1.SchemeGroupVersion.String(),
347 Kind: "ConfigMap",
348 },
349 ObjectMeta: metav1.ObjectMeta{
350 Name: "value_with_space",
351 },
352 Data: map[string]string{
353 "key1": " value1",
354 },
355 BinaryData: map[string][]byte{},
356 },
357 },
358 "create_value_with_space_from_env_file_hash_configmap": {
359 configMapName: "valid_with_space",
360 setup: setupEnvFile([][]string{{"key1= value1"}}),
361 fromEnvFile: []string{"file.env"},
362 appendHash: true,
363 expected: &corev1.ConfigMap{
364 TypeMeta: metav1.TypeMeta{
365 APIVersion: corev1.SchemeGroupVersion.String(),
366 Kind: "ConfigMap",
367 },
368 ObjectMeta: metav1.ObjectMeta{
369 Name: "valid_with_space-b4448m7gdm",
370 },
371 Data: map[string]string{
372 "key1": " value1",
373 },
374 BinaryData: map[string][]byte{},
375 },
376 },
377 "create_invalid_configmap_filepath_contains_=": {
378 configMapName: "foo",
379 fromFile: []string{"key1=/file=2"},
380 expectErr: `key names or file paths cannot contain '='`,
381 },
382 "create_invalid_configmap_filepath_key_contains_=": {
383 configMapName: "foo",
384 fromFile: []string{"=key=/file1"},
385 expectErr: `key names or file paths cannot contain '='`,
386 },
387 "create_invalid_configmap_literal_key_contains_=": {
388 configMapName: "foo",
389 fromFile: []string{"=key=value1"},
390 expectErr: `key names or file paths cannot contain '='`,
391 },
392 "create_invalid_configmap_duplicate_key1": {
393 configMapName: "foo",
394 fromLiteral: []string{"key1=value1", "key1=value2"},
395 expectErr: `cannot add key "key1", another key by that name already exists in Data for ConfigMap "foo"`,
396 },
397 "create_invalid_configmap_no_file": {
398 configMapName: "foo",
399 fromFile: []string{"key1=/file1"},
400 expectErr: `error reading /file1: no such file or directory`,
401 },
402 "create_invalid_configmap_invalid_literal": {
403 configMapName: "foo",
404 fromLiteral: []string{"key1value1"},
405 expectErr: `invalid literal source key1value1, expected key=value`,
406 },
407 "create_invalid_configmap_invalid_filepath": {
408 configMapName: "foo",
409 fromFile: []string{"key1==file1"},
410 expectErr: `key names or file paths cannot contain '='`,
411 },
412 "create_invalid_configmap_too_many_args": {
413 configMapName: "too_many_args",
414 fromFile: []string{"key1=/file1"},
415 fromEnvFile: []string{"file.env"},
416 expectErr: `from-env-file cannot be combined with from-file or from-literal`,
417 },
418 "create_invalid_configmap_too_many_args_1": {
419 configMapName: "too_many_args_1",
420 fromLiteral: []string{"key1=value1"},
421 fromEnvFile: []string{"file.env"},
422 expectErr: `from-env-file cannot be combined with from-file or from-literal`,
423 },
424 }
425
426
427 for name, test := range tests {
428 t.Run(name, func(t *testing.T) {
429 var configMap *corev1.ConfigMap = nil
430 configMapOptions := ConfigMapOptions{
431 Name: test.configMapName,
432 Type: test.configMapType,
433 AppendHash: test.appendHash,
434 FileSources: test.fromFile,
435 LiteralSources: test.fromLiteral,
436 EnvFileSources: test.fromEnvFile,
437 }
438
439 if test.setup != nil {
440 if teardown := test.setup(t, &configMapOptions); teardown != nil {
441 defer teardown()
442 }
443 }
444 err := configMapOptions.Validate()
445
446 if err == nil {
447 configMap, err = configMapOptions.createConfigMap()
448 }
449 if test.expectErr == "" {
450 require.NoError(t, err)
451 if !apiequality.Semantic.DeepEqual(configMap, test.expected) {
452 t.Errorf("\nexpected:\n%#v\ngot:\n%#v", test.expected, configMap)
453 }
454 } else {
455 require.Error(t, err)
456 require.EqualError(t, err, test.expectErr)
457 }
458 })
459 }
460 }
461
462 func setupEnvFile(lines [][]string) func(*testing.T, *ConfigMapOptions) func() {
463 return func(t *testing.T, configMapOptions *ConfigMapOptions) func() {
464 files := []*os.File{}
465 filenames := configMapOptions.EnvFileSources
466 for _, filename := range filenames {
467 file, err := os.CreateTemp("", filename)
468 if err != nil {
469 t.Errorf("unexpected error: %v", err)
470 }
471 files = append(files, file)
472 }
473 for i, f := range files {
474 for _, l := range lines[i] {
475 f.WriteString(l)
476 f.WriteString("\r\n")
477 }
478 f.Close()
479 configMapOptions.EnvFileSources[i] = f.Name()
480 }
481 return func() {
482 for _, f := range files {
483 os.Remove(f.Name())
484 }
485 }
486 }
487 }
488
489 func setupBinaryFile(data []byte) func(*testing.T, *ConfigMapOptions) func() {
490 return func(t *testing.T, configMapOptions *ConfigMapOptions) func() {
491 tmp, _ := os.MkdirTemp("", "")
492 files := configMapOptions.FileSources
493 for i, file := range files {
494 f := tmp + "/" + file
495 os.WriteFile(f, data, 0644)
496 configMapOptions.FileSources[i] = f
497 }
498 return func() {
499 for _, file := range files {
500 f := tmp + "/" + file
501 os.Remove(f)
502 }
503 }
504 }
505 }
506
View as plain text