1
16
17 package flag
18
19 import (
20 "fmt"
21 "reflect"
22 "strings"
23 "testing"
24
25 "github.com/spf13/pflag"
26
27 v1 "k8s.io/api/core/v1"
28 apiequality "k8s.io/apimachinery/pkg/api/equality"
29 "k8s.io/apimachinery/pkg/api/resource"
30 kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
31 )
32
33 func TestIPVar(t *testing.T) {
34 defaultIP := "0.0.0.0"
35 testCases := []struct {
36 argc string
37 expectErr bool
38 expectVal string
39 }{
40
41 {
42 argc: "blah --ip=1.2.3.4",
43 expectVal: "1.2.3.4",
44 },
45 {
46 argc: "blah --ip=1.2.3.4a",
47 expectErr: true,
48 expectVal: defaultIP,
49 },
50 }
51 for _, tc := range testCases {
52 fs := pflag.NewFlagSet("blah", pflag.PanicOnError)
53 ip := defaultIP
54 fs.Var(&IPVar{&ip}, "ip", "the ip")
55
56 var err error
57 func() {
58 defer func() {
59 if r := recover(); r != nil {
60 err = r.(error)
61 }
62 }()
63 fs.Parse(strings.Split(tc.argc, " "))
64 }()
65
66 if tc.expectErr && err == nil {
67 t.Errorf("did not observe an expected error")
68 continue
69 }
70 if !tc.expectErr && err != nil {
71 t.Errorf("observed an unexpected error: %v", err)
72 continue
73 }
74 if tc.expectVal != ip {
75 t.Errorf("unexpected ip: expected %q, saw %q", tc.expectVal, ip)
76 }
77 }
78 }
79
80 func TestIPPortVar(t *testing.T) {
81 defaultIPPort := "0.0.0.0:8080"
82 testCases := []struct {
83 desc string
84 argc string
85 expectErr bool
86 expectVal string
87 }{
88
89 {
90 desc: "valid ipv4 1",
91 argc: "blah --ipport=0.0.0.0",
92 expectVal: "0.0.0.0",
93 },
94 {
95 desc: "valid ipv4 2",
96 argc: "blah --ipport=127.0.0.1",
97 expectVal: "127.0.0.1",
98 },
99
100 {
101 desc: "invalid IP",
102 argc: "blah --ipport=invalidip",
103 expectErr: true,
104 expectVal: defaultIPPort,
105 },
106 {
107 desc: "valid ipv4 with port",
108 argc: "blah --ipport=0.0.0.0:8080",
109 expectVal: "0.0.0.0:8080",
110 },
111 {
112 desc: "invalid ipv4 with invalid port",
113 argc: "blah --ipport=0.0.0.0:invalidport",
114 expectErr: true,
115 expectVal: defaultIPPort,
116 },
117 {
118 desc: "invalid IP with port",
119 argc: "blah --ipport=invalidip:8080",
120 expectErr: true,
121 expectVal: defaultIPPort,
122 },
123 {
124 desc: "valid ipv6 1",
125 argc: "blah --ipport=::1",
126 expectVal: "::1",
127 },
128 {
129 desc: "valid ipv6 2",
130 argc: "blah --ipport=::",
131 expectVal: "::",
132 },
133 {
134 desc: "valid ipv6 with port",
135 argc: "blah --ipport=[::1]:8080",
136 expectVal: "[::1]:8080",
137 },
138 {
139 desc: "invalid ipv6 with port without bracket",
140 argc: "blah --ipport=fd00:f00d:600d:f00d:8080",
141 expectErr: true,
142 expectVal: defaultIPPort,
143 },
144 }
145 for _, tc := range testCases {
146 fs := pflag.NewFlagSet("blah", pflag.PanicOnError)
147 ipport := defaultIPPort
148 fs.Var(&IPPortVar{&ipport}, "ipport", "the ip:port")
149
150 var err error
151 func() {
152 defer func() {
153 if r := recover(); r != nil {
154 err = r.(error)
155 }
156 }()
157 fs.Parse(strings.Split(tc.argc, " "))
158 }()
159
160 if tc.expectErr && err == nil {
161 t.Errorf("%q: Did not observe an expected error", tc.desc)
162 continue
163 }
164 if !tc.expectErr && err != nil {
165 t.Errorf("%q: Observed an unexpected error: %v", tc.desc, err)
166 continue
167 }
168 if tc.expectVal != ipport {
169 t.Errorf("%q: Unexpected ipport: expected %q, saw %q", tc.desc, tc.expectVal, ipport)
170 }
171 }
172 }
173
174 func TestReservedMemoryVar(t *testing.T) {
175 resourceNameHugepages1Gi := v1.ResourceName(fmt.Sprintf("%s1Gi", v1.ResourceHugePagesPrefix))
176 memory1Gi := resource.MustParse("1Gi")
177 testCases := []struct {
178 desc string
179 argc string
180 expectErr bool
181 expectVal []kubeletconfig.MemoryReservation
182 }{
183 {
184 desc: "valid input",
185 argc: "blah --reserved-memory=0:memory=1Gi",
186 expectVal: []kubeletconfig.MemoryReservation{
187 {
188 NumaNode: 0,
189 Limits: v1.ResourceList{
190 v1.ResourceMemory: memory1Gi,
191 },
192 },
193 },
194 },
195 {
196 desc: "valid input with multiple memory types",
197 argc: "blah --reserved-memory=0:memory=1Gi,hugepages-1Gi=1Gi",
198 expectVal: []kubeletconfig.MemoryReservation{
199 {
200 NumaNode: 0,
201 Limits: v1.ResourceList{
202 v1.ResourceMemory: memory1Gi,
203 resourceNameHugepages1Gi: memory1Gi,
204 },
205 },
206 },
207 },
208 {
209 desc: "valid input with multiple reserved-memory arguments",
210 argc: "blah --reserved-memory=0:memory=1Gi,hugepages-1Gi=1Gi --reserved-memory=1:memory=1Gi",
211 expectVal: []kubeletconfig.MemoryReservation{
212 {
213 NumaNode: 0,
214 Limits: v1.ResourceList{
215 v1.ResourceMemory: memory1Gi,
216 resourceNameHugepages1Gi: memory1Gi,
217 },
218 },
219 {
220 NumaNode: 1,
221 Limits: v1.ResourceList{
222 v1.ResourceMemory: memory1Gi,
223 },
224 },
225 },
226 },
227 {
228 desc: "valid input with ';' as separator for multiple reserved-memory arguments",
229 argc: "blah --reserved-memory=0:memory=1Gi,hugepages-1Gi=1Gi;1:memory=1Gi",
230 expectVal: []kubeletconfig.MemoryReservation{
231 {
232 NumaNode: 0,
233 Limits: v1.ResourceList{
234 v1.ResourceMemory: memory1Gi,
235 resourceNameHugepages1Gi: memory1Gi,
236 },
237 },
238 {
239 NumaNode: 1,
240 Limits: v1.ResourceList{
241 v1.ResourceMemory: memory1Gi,
242 },
243 },
244 },
245 },
246 {
247 desc: "invalid input",
248 argc: "blah --reserved-memory=bad-input",
249 expectVal: nil,
250 expectErr: true,
251 },
252 {
253 desc: "invalid input without memory types",
254 argc: "blah --reserved-memory=0:",
255 expectVal: nil,
256 expectErr: true,
257 },
258 {
259 desc: "invalid input with non-integer NUMA node",
260 argc: "blah --reserved-memory=a:memory=1Gi",
261 expectVal: nil,
262 expectErr: true,
263 },
264 {
265 desc: "invalid input with invalid limit",
266 argc: "blah --reserved-memory=0:memory=",
267 expectVal: nil,
268 expectErr: true,
269 },
270 {
271 desc: "invalid input with invalid memory type",
272 argc: "blah --reserved-memory=0:type=1Gi",
273 expectVal: nil,
274 expectErr: true,
275 },
276 {
277 desc: "invalid input with invalid quantity",
278 argc: "blah --reserved-memory=0:memory=1Be",
279 expectVal: nil,
280 expectErr: true,
281 },
282 }
283 for _, tc := range testCases {
284 fs := pflag.NewFlagSet("blah", pflag.PanicOnError)
285
286 var reservedMemory []kubeletconfig.MemoryReservation
287 fs.Var(&ReservedMemoryVar{Value: &reservedMemory}, "reserved-memory", "--reserved-memory 0:memory=1Gi,hugepages-1M=2Gi")
288
289 var err error
290 func() {
291 defer func() {
292 if r := recover(); r != nil {
293 err = r.(error)
294 }
295 }()
296 fs.Parse(strings.Split(tc.argc, " "))
297 }()
298
299 if tc.expectErr && err == nil {
300 t.Fatalf("%q: Did not observe an expected error", tc.desc)
301 }
302 if !tc.expectErr && err != nil {
303 t.Fatalf("%q: Observed an unexpected error: %v", tc.desc, err)
304 }
305 if !apiequality.Semantic.DeepEqual(reservedMemory, tc.expectVal) {
306 t.Fatalf("%q: Unexpected reserved-error: expected %v, saw %v", tc.desc, tc.expectVal, reservedMemory)
307 }
308 }
309 }
310
311 func TestTaintsVar(t *testing.T) {
312 cases := []struct {
313 f string
314 err bool
315 t []v1.Taint
316 }{
317 {
318 f: "",
319 t: []v1.Taint(nil),
320 },
321 {
322 f: "--t=foo=bar:NoSchedule",
323 t: []v1.Taint{{Key: "foo", Value: "bar", Effect: "NoSchedule"}},
324 },
325 {
326 f: "--t=baz:NoSchedule",
327 t: []v1.Taint{{Key: "baz", Value: "", Effect: "NoSchedule"}},
328 },
329 {
330 f: "--t=foo=bar:NoSchedule,baz:NoSchedule,bing=bang:PreferNoSchedule,qux=:NoSchedule",
331 t: []v1.Taint{
332 {Key: "foo", Value: "bar", Effect: v1.TaintEffectNoSchedule},
333 {Key: "baz", Value: "", Effect: "NoSchedule"},
334 {Key: "bing", Value: "bang", Effect: v1.TaintEffectPreferNoSchedule},
335 {Key: "qux", Value: "", Effect: "NoSchedule"},
336 },
337 },
338 {
339 f: "--t=dedicated-for=user1:NoExecute,baz:NoSchedule,foo-bar=:NoSchedule",
340 t: []v1.Taint{
341 {Key: "dedicated-for", Value: "user1", Effect: "NoExecute"},
342 {Key: "baz", Value: "", Effect: "NoSchedule"},
343 {Key: "foo-bar", Value: "", Effect: "NoSchedule"},
344 },
345 },
346 }
347
348 for i, c := range cases {
349 args := append([]string{"test"}, strings.Fields(c.f)...)
350 cli := pflag.NewFlagSet("test", pflag.ContinueOnError)
351 var taints []v1.Taint
352 cli.Var(RegisterWithTaintsVar{Value: &taints}, "t", "bar")
353
354 err := cli.Parse(args)
355 if err == nil && c.err {
356 t.Errorf("[%v] expected error", i)
357 continue
358 }
359 if err != nil && !c.err {
360 t.Errorf("[%v] unexpected error: %v", i, err)
361 continue
362 }
363 if !reflect.DeepEqual(c.t, taints) {
364 t.Errorf("[%v] unexpected taints:\n\texpected:\n\t\t%#v\n\tgot:\n\t\t%#v", i, c.t, taints)
365 }
366 }
367
368 }
369
View as plain text