1/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package versioned
18
19import (
20	"reflect"
21	"testing"
22
23	v1 "k8s.io/api/core/v1"
24	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25)
26
27func TestGeneratePod(t *testing.T) {
28	tests := []struct {
29		name      string
30		params    map[string]interface{}
31		expected  *v1.Pod
32		expectErr bool
33	}{
34		{
35			name: "test1",
36			params: map[string]interface{}{
37				"name":  "foo",
38				"image": "someimage",
39				"port":  "",
40			},
41			expected: &v1.Pod{
42				ObjectMeta: metav1.ObjectMeta{
43					Name:   "foo",
44					Labels: map[string]string{"run": "foo"},
45				},
46				Spec: v1.PodSpec{
47					Containers: []v1.Container{
48						{
49							Name:  "foo",
50							Image: "someimage",
51						},
52					},
53					DNSPolicy:     v1.DNSClusterFirst,
54					RestartPolicy: v1.RestartPolicyAlways,
55				},
56			},
57		},
58		{
59			name: "test2",
60			params: map[string]interface{}{
61				"name":  "foo",
62				"image": "someimage",
63				"env":   []string{"a", "c"},
64			},
65
66			expected:  nil,
67			expectErr: true,
68		},
69		{
70			name: "test3",
71			params: map[string]interface{}{
72				"name":              "foo",
73				"image":             "someimage",
74				"image-pull-policy": "Always",
75				"env":               []string{"a=b", "c=d"},
76			},
77			expected: &v1.Pod{
78				ObjectMeta: metav1.ObjectMeta{
79					Name:   "foo",
80					Labels: map[string]string{"run": "foo"},
81				},
82				Spec: v1.PodSpec{
83					Containers: []v1.Container{
84						{
85							Name:            "foo",
86							Image:           "someimage",
87							ImagePullPolicy: v1.PullAlways,
88							Env: []v1.EnvVar{
89								{
90									Name:  "a",
91									Value: "b",
92								},
93								{
94									Name:  "c",
95									Value: "d",
96								},
97							},
98						},
99					},
100					DNSPolicy:     v1.DNSClusterFirst,
101					RestartPolicy: v1.RestartPolicyAlways,
102				},
103			},
104		},
105		{
106			name: "test4",
107			params: map[string]interface{}{
108				"name":  "foo",
109				"image": "someimage",
110				"port":  "80",
111			},
112			expected: &v1.Pod{
113				ObjectMeta: metav1.ObjectMeta{
114					Name:   "foo",
115					Labels: map[string]string{"run": "foo"},
116				},
117				Spec: v1.PodSpec{
118					Containers: []v1.Container{
119						{
120							Name:  "foo",
121							Image: "someimage",
122							Ports: []v1.ContainerPort{
123								{
124									ContainerPort: 80,
125								},
126							},
127						},
128					},
129					DNSPolicy:     v1.DNSClusterFirst,
130					RestartPolicy: v1.RestartPolicyAlways,
131				},
132			},
133		},
134		{
135			name: "test5",
136			params: map[string]interface{}{
137				"name":     "foo",
138				"image":    "someimage",
139				"port":     "80",
140				"hostport": "80",
141			},
142			expected: &v1.Pod{
143				ObjectMeta: metav1.ObjectMeta{
144					Name:   "foo",
145					Labels: map[string]string{"run": "foo"},
146				},
147				Spec: v1.PodSpec{
148					Containers: []v1.Container{
149						{
150							Name:  "foo",
151							Image: "someimage",
152							Ports: []v1.ContainerPort{
153								{
154									ContainerPort: 80,
155									HostPort:      80,
156								},
157							},
158						},
159					},
160					DNSPolicy:     v1.DNSClusterFirst,
161					RestartPolicy: v1.RestartPolicyAlways,
162				},
163			},
164		},
165		{
166			name: "test6",
167			params: map[string]interface{}{
168				"name":     "foo",
169				"image":    "someimage",
170				"hostport": "80",
171			},
172			expected:  nil,
173			expectErr: true,
174		},
175		{
176			name: "test7",
177			params: map[string]interface{}{
178				"name":     "foo",
179				"image":    "someimage",
180				"replicas": "1",
181				"labels":   "foo=bar,baz=blah",
182			},
183			expected: &v1.Pod{
184				ObjectMeta: metav1.ObjectMeta{
185					Name:   "foo",
186					Labels: map[string]string{"foo": "bar", "baz": "blah"},
187				},
188				Spec: v1.PodSpec{
189					Containers: []v1.Container{
190						{
191							Name:  "foo",
192							Image: "someimage",
193						},
194					},
195					DNSPolicy:     v1.DNSClusterFirst,
196					RestartPolicy: v1.RestartPolicyAlways,
197				},
198			},
199		},
200		{
201			name: "test8",
202			params: map[string]interface{}{
203				"name":     "foo",
204				"image":    "someimage",
205				"replicas": "1",
206				"labels":   "foo=bar,baz=blah",
207				"stdin":    "true",
208			},
209			expected: &v1.Pod{
210				ObjectMeta: metav1.ObjectMeta{
211					Name:   "foo",
212					Labels: map[string]string{"foo": "bar", "baz": "blah"},
213				},
214				Spec: v1.PodSpec{
215					Containers: []v1.Container{
216						{
217							Name:      "foo",
218							Image:     "someimage",
219							Stdin:     true,
220							StdinOnce: true,
221						},
222					},
223					DNSPolicy:     v1.DNSClusterFirst,
224					RestartPolicy: v1.RestartPolicyAlways,
225				},
226			},
227		},
228		{
229			name: "test9",
230			params: map[string]interface{}{
231				"name":             "foo",
232				"image":            "someimage",
233				"replicas":         "1",
234				"labels":           "foo=bar,baz=blah",
235				"stdin":            "true",
236				"leave-stdin-open": "true",
237			},
238			expected: &v1.Pod{
239				ObjectMeta: metav1.ObjectMeta{
240					Name:   "foo",
241					Labels: map[string]string{"foo": "bar", "baz": "blah"},
242				},
243				Spec: v1.PodSpec{
244					Containers: []v1.Container{
245						{
246							Name:      "foo",
247							Image:     "someimage",
248							Stdin:     true,
249							StdinOnce: false,
250						},
251					},
252					DNSPolicy:     v1.DNSClusterFirst,
253					RestartPolicy: v1.RestartPolicyAlways,
254				},
255			},
256		},
257		{
258			name: "test10: privileged mode",
259			params: map[string]interface{}{
260				"name":       "foo",
261				"image":      "someimage",
262				"replicas":   "1",
263				"privileged": "true",
264			},
265			expected: &v1.Pod{
266				ObjectMeta: metav1.ObjectMeta{
267					Name:   "foo",
268					Labels: map[string]string{"run": "foo"},
269				},
270				Spec: v1.PodSpec{
271					Containers: []v1.Container{
272						{
273							Name:            "foo",
274							Image:           "someimage",
275							SecurityContext: securityContextWithPrivilege(true),
276						},
277					},
278					DNSPolicy:     v1.DNSClusterFirst,
279					RestartPolicy: v1.RestartPolicyAlways,
280				},
281			},
282		},
283		{
284			name: "test11: check annotations",
285			params: map[string]interface{}{
286				"name":        "foo",
287				"image":       "someimage",
288				"replicas":    "1",
289				"labels":      "foo=bar,baz=blah",
290				"annotations": []string{"foo=bar1", "baz=blah1"},
291			},
292			expected: &v1.Pod{
293				ObjectMeta: metav1.ObjectMeta{
294					Name:        "foo",
295					Labels:      map[string]string{"foo": "bar", "baz": "blah"},
296					Annotations: map[string]string{"foo": "bar1", "baz": "blah1"},
297				},
298				Spec: v1.PodSpec{
299					Containers: []v1.Container{
300						{
301							Name:  "foo",
302							Image: "someimage",
303						},
304					},
305					DNSPolicy:     v1.DNSClusterFirst,
306					RestartPolicy: v1.RestartPolicyAlways,
307				},
308			},
309		},
310	}
311	generator := BasicPod{}
312	for _, tt := range tests {
313		t.Run(tt.name, func(t *testing.T) {
314			obj, err := generator.Generate(tt.params)
315			if !tt.expectErr && err != nil {
316				t.Errorf("unexpected error: %v", err)
317			}
318			if tt.expectErr && err != nil {
319				return
320			}
321			if !reflect.DeepEqual(obj.(*v1.Pod), tt.expected) {
322				t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", tt.expected, obj.(*v1.Pod))
323			}
324		})
325	}
326}
327
328func TestParseEnv(t *testing.T) {
329	tests := []struct {
330		name      string
331		envArray  []string
332		expected  []v1.EnvVar
333		expectErr bool
334		test      string
335	}{
336		{
337			name: "test1",
338			envArray: []string{
339				"THIS_ENV=isOK",
340				"this.dotted.env=isOKToo",
341				"HAS_COMMAS=foo,bar",
342				"HAS_EQUALS=jJnro54iUu75xNy==",
343			},
344			expected: []v1.EnvVar{
345				{
346					Name:  "THIS_ENV",
347					Value: "isOK",
348				},
349				{
350					Name:  "this.dotted.env",
351					Value: "isOKToo",
352				},
353				{
354					Name:  "HAS_COMMAS",
355					Value: "foo,bar",
356				},
357				{
358					Name:  "HAS_EQUALS",
359					Value: "jJnro54iUu75xNy==",
360				},
361			},
362			expectErr: false,
363			test:      "test case 1",
364		},
365		{
366			name: "test2",
367			envArray: []string{
368				"WITH_OUT_EQUALS",
369			},
370			expected:  []v1.EnvVar{},
371			expectErr: true,
372			test:      "test case 2",
373		},
374		{
375			name: "test3",
376			envArray: []string{
377				"WITH_OUT_VALUES=",
378			},
379			expected: []v1.EnvVar{
380				{
381					Name:  "WITH_OUT_VALUES",
382					Value: "",
383				},
384			},
385			expectErr: false,
386			test:      "test case 3",
387		},
388		{
389			name: "test4",
390			envArray: []string{
391				"=WITH_OUT_NAME",
392			},
393			expected:  []v1.EnvVar{},
394			expectErr: true,
395			test:      "test case 4",
396		},
397	}
398
399	for _, tt := range tests {
400		t.Run(tt.name, func(t *testing.T) {
401			envs, err := parseEnvs(tt.envArray)
402			if !tt.expectErr && err != nil {
403				t.Errorf("unexpected error: %v (%s)", err, tt.test)
404			}
405			if tt.expectErr && err != nil {
406				return
407			}
408			if !reflect.DeepEqual(envs, tt.expected) {
409				t.Errorf("\nexpected:\n%#v\nsaw:\n%#v (%s)", tt.expected, envs, tt.test)
410			}
411		})
412	}
413}
414
415func securityContextWithPrivilege(privileged bool) *v1.SecurityContext {
416	return &v1.SecurityContext{
417		Privileged: &privileged,
418	}
419}
420