1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package pod
17
18 import (
19 "context"
20 "testing"
21
22 . "github.com/onsi/gomega"
23 v1 "k8s.io/api/core/v1"
24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 "sigs.k8s.io/controller-runtime/pkg/client"
26 "sigs.k8s.io/controller-runtime/pkg/client/fake"
27
28 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
29 . "github.com/chaos-mesh/chaos-mesh/pkg/testutils"
30 )
31
32 func TestSelectPods(t *testing.T) {
33 g := NewGomegaWithT(t)
34
35 objects, pods := GenerateNPods("p", 5, PodArg{Labels: map[string]string{"l1": "l1"}, Nodename: "az1-node1"})
36 objects2, pods2 := GenerateNPods("s", 2, PodArg{Namespace: "test-s", Labels: map[string]string{"l2": "l2"}, Nodename: "az2-node1"})
37
38 objects3, _ := GenerateNNodes("az1-node", 3, map[string]string{"disktype": "ssd", "zone": "az1"})
39 objects4, _ := GenerateNNodes("az2-node", 2, map[string]string{"disktype": "hdd", "zone": "az2"})
40
41 objects = append(objects, objects2...)
42 objects = append(objects, objects3...)
43 objects = append(objects, objects4...)
44
45 pods = append(pods, pods2...)
46
47 c := fake.NewClientBuilder().
48 WithRuntimeObjects(objects...).
49 Build()
50 var r client.Reader
51
52 type TestCase struct {
53 name string
54 selector v1alpha1.PodSelectorSpec
55 expectedPods []v1.Pod
56 }
57
58 tcs := []TestCase{
59 {
60 name: "filter specified pods",
61 selector: v1alpha1.PodSelectorSpec{
62 Pods: map[string][]string{
63 metav1.NamespaceDefault: {"p3", "p4"},
64 "test-s": {"s1"},
65 },
66 },
67 expectedPods: []v1.Pod{pods[3], pods[4], pods[6]},
68 },
69 {
70 name: "filter labels pods",
71 selector: v1alpha1.PodSelectorSpec{
72 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
73 LabelSelectors: map[string]string{"l2": "l2"},
74 },
75 },
76 expectedPods: []v1.Pod{pods[5], pods[6]},
77 },
78 {
79 name: "filter pods by label expressions",
80 selector: v1alpha1.PodSelectorSpec{
81 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
82 ExpressionSelectors: []metav1.LabelSelectorRequirement{
83 {
84 Key: "l2",
85 Operator: metav1.LabelSelectorOpIn,
86 Values: []string{"l2"},
87 },
88 },
89 },
90 },
91 expectedPods: []v1.Pod{pods[5], pods[6]},
92 },
93 {
94 name: "filter pods by label selectors and expression selectors",
95 selector: v1alpha1.PodSelectorSpec{
96 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
97 LabelSelectors: map[string]string{"l1": "l1"},
98 ExpressionSelectors: []metav1.LabelSelectorRequirement{
99 {
100 Key: "l2",
101 Operator: metav1.LabelSelectorOpIn,
102 Values: []string{"l2"},
103 },
104 },
105 },
106 },
107 expectedPods: nil,
108 },
109 {
110 name: "filter namespace and labels",
111 selector: v1alpha1.PodSelectorSpec{
112 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
113 Namespaces: []string{"test-s"},
114 LabelSelectors: map[string]string{"l2": "l2"},
115 },
116 },
117 expectedPods: []v1.Pod{pods[5], pods[6]},
118 },
119 {
120 name: "filter namespace and labels",
121 selector: v1alpha1.PodSelectorSpec{
122 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
123 Namespaces: []string{metav1.NamespaceDefault},
124 LabelSelectors: map[string]string{"l2": "l2"},
125 },
126 },
127 expectedPods: nil,
128 },
129 {
130 name: "filter by specified node",
131 selector: v1alpha1.PodSelectorSpec{
132 Nodes: []string{"az1-node1"},
133 },
134 expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4]},
135 },
136 {
137 name: "filter node and labels",
138 selector: v1alpha1.PodSelectorSpec{
139 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
140 LabelSelectors: map[string]string{"l1": "l1"},
141 },
142 Nodes: []string{"az2-node1"},
143 },
144 expectedPods: nil,
145 },
146 {
147 name: "filter pods by nodeSelector",
148 selector: v1alpha1.PodSelectorSpec{
149 NodeSelectors: map[string]string{"disktype": "hdd"},
150 },
151 expectedPods: []v1.Pod{pods[5], pods[6]},
152 },
153 {
154 name: "filter pods by node and nodeSelector",
155 selector: v1alpha1.PodSelectorSpec{
156 NodeSelectors: map[string]string{"zone": "az1"},
157 Nodes: []string{"az2-node1"},
158 },
159 expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4], pods[5], pods[6]},
160 },
161 }
162
163 var (
164 testCfgClusterScoped = true
165 testCfgTargetNamespace = ""
166 )
167
168 for _, tc := range tcs {
169 filteredPods, err := SelectPods(context.Background(), c, r, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, false)
170 g.Expect(err).ShouldNot(HaveOccurred(), tc.name)
171 g.Expect(len(filteredPods)).To(Equal(len(tc.expectedPods)), tc.name)
172 }
173 }
174
175 func TestCheckPodMeetSelector(t *testing.T) {
176 g := NewGomegaWithT(t)
177
178 objects, _ := GenerateNNodes("az1-node", 3, map[string]string{"disktype": "ssd", "zone": "az1"})
179 objects2, _ := GenerateNNodes("az2-node", 2, map[string]string{"disktype": "hdd", "zone": "az2"})
180 objects = append(objects, objects2...)
181
182 c := fake.NewClientBuilder().WithRuntimeObjects(objects...).Build()
183
184 type TestCase struct {
185 name string
186 selector v1alpha1.PodSelectorSpec
187 pod v1.Pod
188 expectedValue bool
189 }
190
191 tcs := []TestCase{
192 {
193 name: "meet label",
194 pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}),
195 selector: v1alpha1.PodSelectorSpec{
196 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
197 LabelSelectors: map[string]string{"app": "tikv"},
198 },
199 },
200 expectedValue: true,
201 },
202 {
203 name: "not meet label",
204 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb", "ss": "t1"}}),
205 selector: v1alpha1.PodSelectorSpec{
206 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
207 LabelSelectors: map[string]string{"app": "tikv"},
208 },
209 },
210 expectedValue: false,
211 },
212 {
213 name: "pod labels is empty",
214 pod: NewPod(PodArg{Name: "t1"}),
215 selector: v1alpha1.PodSelectorSpec{
216 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
217 LabelSelectors: map[string]string{"app": "tikv"},
218 },
219 },
220 expectedValue: false,
221 },
222 {
223 name: "selector is empty",
224 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
225 selector: v1alpha1.PodSelectorSpec{},
226 expectedValue: true,
227 },
228 {
229 name: "meet labels and meet expressions",
230 pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}),
231 selector: v1alpha1.PodSelectorSpec{
232 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
233 LabelSelectors: map[string]string{"app": "tikv"},
234 ExpressionSelectors: []metav1.LabelSelectorRequirement{
235 {
236 Key: "ss",
237 Operator: metav1.LabelSelectorOpExists,
238 },
239 },
240 },
241 },
242 expectedValue: true,
243 },
244 {
245 name: "meet labels and not meet expressions",
246 pod: NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}),
247 selector: v1alpha1.PodSelectorSpec{
248 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
249 LabelSelectors: map[string]string{"app": "tikv"},
250 ExpressionSelectors: []metav1.LabelSelectorRequirement{
251 {
252 Key: "ss",
253 Operator: metav1.LabelSelectorOpNotIn,
254 Values: []string{"t1"},
255 },
256 },
257 },
258 },
259 expectedValue: false,
260 },
261 {
262 name: "meet namespace",
263 pod: NewPod(PodArg{Name: "t1"}),
264 selector: v1alpha1.PodSelectorSpec{
265 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
266 Namespaces: []string{metav1.NamespaceDefault},
267 },
268 },
269 expectedValue: true,
270 },
271 {
272 name: "meet namespace and meet labels",
273 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tikv"}}),
274 selector: v1alpha1.PodSelectorSpec{
275 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
276 Namespaces: []string{metav1.NamespaceDefault},
277 LabelSelectors: map[string]string{"app": "tikv"},
278 },
279 },
280 expectedValue: true,
281 },
282 {
283 name: "meet namespace and not meet labels",
284 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
285 selector: v1alpha1.PodSelectorSpec{
286 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
287 Namespaces: []string{metav1.NamespaceDefault},
288 LabelSelectors: map[string]string{"app": "tikv"},
289 },
290 },
291 expectedValue: false,
292 },
293 {
294 name: "meet pods",
295 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
296 selector: v1alpha1.PodSelectorSpec{
297 Pods: map[string][]string{
298 metav1.NamespaceDefault: {"t1"},
299 },
300 },
301 expectedValue: true,
302 },
303 {
304 name: "meet annotation",
305 pod: NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1", "an2": "n2"}, Labels: map[string]string{"app": "tidb"}}),
306 selector: v1alpha1.PodSelectorSpec{
307 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
308 Namespaces: []string{metav1.NamespaceDefault},
309 AnnotationSelectors: map[string]string{
310 "an": "n1",
311 },
312 },
313 },
314 expectedValue: true,
315 },
316 {
317 name: "not meet annotation",
318 pod: NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1"}, Labels: map[string]string{"app": "tidb"}}),
319 selector: v1alpha1.PodSelectorSpec{
320 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
321 Namespaces: []string{metav1.NamespaceDefault},
322 AnnotationSelectors: map[string]string{
323 "an": "n2",
324 },
325 },
326 },
327 expectedValue: false,
328 },
329 {
330 name: "meet field",
331 pod: NewPod(PodArg{Name: "t1"}),
332 selector: v1alpha1.PodSelectorSpec{
333 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
334 FieldSelectors: map[string]string{"metadata.name": "t1"},
335 },
336 },
337 expectedValue: true,
338 },
339 {
340 name: "not meet field",
341 pod: NewPod(PodArg{Name: "t2"}),
342 selector: v1alpha1.PodSelectorSpec{
343 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
344 FieldSelectors: map[string]string{"metadata.name": "t1"},
345 },
346 },
347 expectedValue: false,
348 },
349 {
350 name: "meet node",
351 pod: NewPod(PodArg{Name: "t1", Nodename: "az1-node1"}),
352 selector: v1alpha1.PodSelectorSpec{
353 Nodes: []string{"az1-node0", "az1-node1"},
354 },
355 expectedValue: true,
356 },
357 {
358 name: "not meet node",
359 pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}),
360 selector: v1alpha1.PodSelectorSpec{
361 Nodes: []string{"az1-node0", "az1-node1"},
362 },
363 expectedValue: false,
364 },
365 {
366 name: "meet node selector",
367 pod: NewPod(PodArg{Name: "t1", Nodename: "az1-node1"}),
368 selector: v1alpha1.PodSelectorSpec{
369 NodeSelectors: map[string]string{"disktype": "ssd"},
370 },
371 expectedValue: true,
372 },
373 {
374 name: "not meet node selector",
375 pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}),
376 selector: v1alpha1.PodSelectorSpec{
377 NodeSelectors: map[string]string{"disktype": "ssd"},
378 },
379 expectedValue: false,
380 }, {
381 name: "meet node selector or node name",
382 pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}),
383 selector: v1alpha1.PodSelectorSpec{
384 Nodes: []string{"az2-node1"},
385 NodeSelectors: map[string]string{"disktype": "ssd"},
386 },
387 expectedValue: true,
388 },
389 {
390 name: "not meet node selector and node name",
391 pod: NewPod(PodArg{Name: "t1", Nodename: "az2-node1"}),
392 selector: v1alpha1.PodSelectorSpec{
393 Nodes: []string{"az2-node0"},
394 NodeSelectors: map[string]string{"disktype": "ssd"},
395 },
396 expectedValue: false,
397 },
398 {
399 name: "meet pod selector",
400 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
401 selector: v1alpha1.PodSelectorSpec{
402 Pods: map[string][]string{
403 metav1.NamespaceDefault: {"t1", "t2"},
404 },
405 },
406 expectedValue: true,
407 },
408 {
409 name: "not meet pod selector",
410 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
411 selector: v1alpha1.PodSelectorSpec{
412 Pods: map[string][]string{
413 metav1.NamespaceDefault: {"t2"},
414 },
415 },
416 expectedValue: false,
417 },
418 {
419 name: "meet pod selector and not meet labels",
420 pod: NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
421 selector: v1alpha1.PodSelectorSpec{
422 Pods: map[string][]string{
423 metav1.NamespaceDefault: {"t1", "t2"},
424 },
425 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
426 LabelSelectors: map[string]string{"app": "tikv"},
427 },
428 },
429 expectedValue: false,
430 },
431 }
432
433 var (
434 testCfgClusterScoped = true
435 testCfgTargetNamespace = ""
436 )
437
438 for _, tc := range tcs {
439 meet, err := CheckPodMeetSelector(context.Background(), c, tc.pod, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, false)
440 g.Expect(err).ShouldNot(HaveOccurred(), tc.name)
441 g.Expect(meet).To(Equal(tc.expectedValue), tc.name)
442 }
443 }
444