1
16
17 package util
18
19 import (
20 "reflect"
21 "sort"
22 "testing"
23
24 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
25 )
26
27 func TestArgumentsToCommand(t *testing.T) {
28 var tests = []struct {
29 name string
30 base []kubeadmapi.Arg
31 overrides []kubeadmapi.Arg
32 expected []string
33 }{
34 {
35 name: "override an argument from the base",
36 base: []kubeadmapi.Arg{
37 {Name: "admission-control", Value: "NamespaceLifecycle"},
38 {Name: "allow-privileged", Value: "true"},
39 },
40 overrides: []kubeadmapi.Arg{
41 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
42 },
43 expected: []string{
44 "--admission-control=NamespaceLifecycle,LimitRanger",
45 "--allow-privileged=true",
46 },
47 },
48 {
49 name: "override an argument from the base and add duplicate",
50 base: []kubeadmapi.Arg{
51 {Name: "token-auth-file", Value: "/token"},
52 {Name: "tls-sni-cert-key", Value: "/some/path/"},
53 },
54 overrides: []kubeadmapi.Arg{
55 {Name: "tls-sni-cert-key", Value: "/some/new/path"},
56 {Name: "tls-sni-cert-key", Value: "/some/new/path/subpath"},
57 },
58 expected: []string{
59 "--tls-sni-cert-key=/some/new/path",
60 "--tls-sni-cert-key=/some/new/path/subpath",
61 "--token-auth-file=/token",
62 },
63 },
64 {
65 name: "override all duplicate arguments from base",
66 base: []kubeadmapi.Arg{
67 {Name: "token-auth-file", Value: "/token"},
68 {Name: "tls-sni-cert-key", Value: "foo"},
69 {Name: "tls-sni-cert-key", Value: "bar"},
70 },
71 overrides: []kubeadmapi.Arg{
72 {Name: "tls-sni-cert-key", Value: "/some/new/path"},
73 },
74 expected: []string{
75 "--tls-sni-cert-key=/some/new/path",
76 "--token-auth-file=/token",
77 },
78 },
79 {
80 name: "add an argument that is not in base",
81 base: []kubeadmapi.Arg{
82 {Name: "allow-privileged", Value: "true"},
83 },
84 overrides: []kubeadmapi.Arg{
85 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
86 },
87 expected: []string{
88 "--admission-control=NamespaceLifecycle,LimitRanger",
89 "--allow-privileged=true",
90 },
91 },
92 {
93 name: "allow empty strings in base",
94 base: []kubeadmapi.Arg{
95 {Name: "allow-privileged", Value: "true"},
96 {Name: "something-that-allows-empty-string", Value: ""},
97 },
98 overrides: []kubeadmapi.Arg{
99 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
100 },
101 expected: []string{
102 "--admission-control=NamespaceLifecycle,LimitRanger",
103 "--allow-privileged=true",
104 "--something-that-allows-empty-string=",
105 },
106 },
107 {
108 name: "allow empty strings in overrides",
109 base: []kubeadmapi.Arg{
110 {Name: "allow-privileged", Value: "true"},
111 {Name: "something-that-allows-empty-string", Value: "foo"},
112 },
113 overrides: []kubeadmapi.Arg{
114 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
115 {Name: "something-that-allows-empty-string", Value: ""},
116 },
117 expected: []string{
118 "--admission-control=NamespaceLifecycle,LimitRanger",
119 "--allow-privileged=true",
120 "--something-that-allows-empty-string=",
121 },
122 },
123 }
124
125 for _, rt := range tests {
126 t.Run(rt.name, func(t *testing.T) {
127 actual := ArgumentsToCommand(rt.base, rt.overrides)
128 if !reflect.DeepEqual(actual, rt.expected) {
129 t.Errorf("failed ArgumentsToCommand:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
130 }
131 })
132 }
133 }
134
135 func TestArgumentsFromCommand(t *testing.T) {
136 var tests = []struct {
137 name string
138 args []string
139 expected []kubeadmapi.Arg
140 }{
141 {
142 name: "normal case",
143 args: []string{
144 "--admission-control=NamespaceLifecycle,LimitRanger",
145 "--allow-privileged=true",
146 },
147 expected: []kubeadmapi.Arg{
148 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
149 {Name: "allow-privileged", Value: "true"},
150 },
151 },
152 {
153 name: "test that feature-gates is working",
154 args: []string{
155 "--admission-control=NamespaceLifecycle,LimitRanger",
156 "--allow-privileged=true",
157 "--feature-gates=EnableFoo=true,EnableBar=false",
158 },
159 expected: []kubeadmapi.Arg{
160 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
161 {Name: "allow-privileged", Value: "true"},
162 {Name: "feature-gates", Value: "EnableFoo=true,EnableBar=false"},
163 },
164 },
165 {
166 name: "test that a binary can be the first arg",
167 args: []string{
168 "kube-apiserver",
169 "--admission-control=NamespaceLifecycle,LimitRanger",
170 "--allow-privileged=true",
171 "--feature-gates=EnableFoo=true,EnableBar=false",
172 },
173 expected: []kubeadmapi.Arg{
174 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
175 {Name: "allow-privileged", Value: "true"},
176 {Name: "feature-gates", Value: "EnableFoo=true,EnableBar=false"},
177 },
178 },
179 {
180 name: "allow duplicate args",
181 args: []string{
182 "--admission-control=NamespaceLifecycle,LimitRanger",
183 "--tls-sni-cert-key=/some/path",
184 "--tls-sni-cert-key=/some/path/subpath",
185 },
186 expected: []kubeadmapi.Arg{
187 {Name: "admission-control", Value: "NamespaceLifecycle,LimitRanger"},
188 {Name: "tls-sni-cert-key", Value: "/some/path"},
189 {Name: "tls-sni-cert-key", Value: "/some/path/subpath"},
190 },
191 },
192 }
193
194 for _, rt := range tests {
195 t.Run(rt.name, func(t *testing.T) {
196 actual := ArgumentsFromCommand(rt.args)
197 if !reflect.DeepEqual(actual, rt.expected) {
198 t.Errorf("failed ArgumentsFromCommand:\nexpected:\n%v\nsaw:\n%v", rt.expected, actual)
199 }
200 })
201 }
202 }
203
204 func TestRoundtrip(t *testing.T) {
205 var tests = []struct {
206 name string
207 args []string
208 }{
209 {
210 name: "normal case",
211 args: []string{
212 "--admission-control=NamespaceLifecycle,LimitRanger",
213 "--allow-privileged=true",
214 },
215 },
216 {
217 name: "test that feature-gates is working",
218 args: []string{
219 "--admission-control=NamespaceLifecycle,LimitRanger",
220 "--allow-privileged=true",
221 "--feature-gates=EnableFoo=true,EnableBar=false",
222 },
223 },
224 }
225
226 for _, rt := range tests {
227 t.Run(rt.name, func(t *testing.T) {
228
229 actual := ArgumentsToCommand(ArgumentsFromCommand(rt.args), []kubeadmapi.Arg{})
230 sort.Strings(actual)
231 sort.Strings(rt.args)
232
233 if !reflect.DeepEqual(actual, rt.args) {
234 t.Errorf("failed TestRoundtrip:\nexpected:\n%v\nsaw:\n%v", rt.args, actual)
235 }
236 })
237 }
238 }
239
240 func TestParseArgument(t *testing.T) {
241 var tests = []struct {
242 name string
243 arg string
244 expectedKey string
245 expectedVal string
246 expectedErr bool
247 }{
248 {
249 name: "arg cannot be empty",
250 arg: "",
251 expectedErr: true,
252 },
253 {
254 name: "arg must contain -- and =",
255 arg: "a",
256 expectedErr: true,
257 },
258 {
259 name: "arg must contain -- and =",
260 arg: "a-z",
261 expectedErr: true,
262 },
263 {
264 name: "arg must contain --",
265 arg: "a=b",
266 expectedErr: true,
267 },
268 {
269 name: "arg must contain a key",
270 arg: "--=b",
271 expectedErr: true,
272 },
273 {
274 name: "arg can contain key but no value",
275 arg: "--a=",
276 expectedKey: "a",
277 expectedVal: "",
278 expectedErr: false,
279 },
280 {
281 name: "simple case",
282 arg: "--a=b",
283 expectedKey: "a",
284 expectedVal: "b",
285 expectedErr: false,
286 },
287 {
288 name: "keys/values with '-' should be supported",
289 arg: "--very-long-flag-name=some-value",
290 expectedKey: "very-long-flag-name",
291 expectedVal: "some-value",
292 expectedErr: false,
293 },
294 {
295 name: "numbers should be handled correctly",
296 arg: "--some-number=0.2",
297 expectedKey: "some-number",
298 expectedVal: "0.2",
299 expectedErr: false,
300 },
301 {
302 name: "lists should be handled correctly",
303 arg: "--admission-control=foo,bar,baz",
304 expectedKey: "admission-control",
305 expectedVal: "foo,bar,baz",
306 expectedErr: false,
307 },
308 {
309 name: "more than one '=' should be allowed",
310 arg: "--feature-gates=EnableFoo=true,EnableBar=false",
311 expectedKey: "feature-gates",
312 expectedVal: "EnableFoo=true,EnableBar=false",
313 expectedErr: false,
314 },
315 }
316
317 for _, rt := range tests {
318 t.Run(rt.name, func(t *testing.T) {
319 key, val, actual := parseArgument(rt.arg)
320 if (actual != nil) != rt.expectedErr {
321 t.Errorf("failed parseArgument:\nexpected error:\n%t\nsaw error:\n%v", rt.expectedErr, actual)
322 }
323 if (key != rt.expectedKey) || (val != rt.expectedVal) {
324 t.Errorf("failed parseArgument:\nexpected key: %s\nsaw key: %s\nexpected value: %s\nsaw value: %s", rt.expectedKey, key, rt.expectedVal, val)
325 }
326 })
327 }
328 }
329
View as plain text