...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/selector/pod/selector_test.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/selector/pod

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package pod
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  
    22  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    23  
    24  	. "github.com/onsi/gomega"
    25  
    26  	"github.com/chaos-mesh/chaos-mesh/pkg/label"
    27  	. "github.com/chaos-mesh/chaos-mesh/pkg/testutils"
    28  
    29  	v1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/labels"
    32  
    33  	"sigs.k8s.io/controller-runtime/pkg/client"
    34  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    35  )
    36  
    37  func TestSelectPods(t *testing.T) {
    38  	g := NewGomegaWithT(t)
    39  
    40  	objects, pods := GenerateNPods("p", 5, PodArg{Labels: map[string]string{"l1": "l1"}, Nodename: "az1-node1"})
    41  	objects2, pods2 := GenerateNPods("s", 2, PodArg{Namespace: "test-s", Labels: map[string]string{"l2": "l2"}, Nodename: "az2-node1"})
    42  
    43  	objects3, _ := GenerateNNodes("az1-node", 3, map[string]string{"disktype": "ssd", "zone": "az1"})
    44  	objects4, _ := GenerateNNodes("az2-node", 2, map[string]string{"disktype": "hdd", "zone": "az2"})
    45  
    46  	objects = append(objects, objects2...)
    47  	objects = append(objects, objects3...)
    48  	objects = append(objects, objects4...)
    49  
    50  	pods = append(pods, pods2...)
    51  
    52  	c := fake.NewClientBuilder().WithRuntimeObjects(objects...).Build()
    53  	var r client.Reader
    54  
    55  	type TestCase struct {
    56  		name         string
    57  		selector     v1alpha1.PodSelectorSpec
    58  		expectedPods []v1.Pod
    59  	}
    60  
    61  	tcs := []TestCase{
    62  		{
    63  			name: "filter specified pods",
    64  			selector: v1alpha1.PodSelectorSpec{
    65  				Pods: map[string][]string{
    66  					metav1.NamespaceDefault: {"p3", "p4"},
    67  					"test-s":                {"s1"},
    68  				},
    69  			},
    70  			expectedPods: []v1.Pod{pods[3], pods[4], pods[6]},
    71  		},
    72  		{
    73  			name: "filter labels pods",
    74  			selector: v1alpha1.PodSelectorSpec{
    75  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
    76  					LabelSelectors: map[string]string{"l2": "l2"},
    77  				},
    78  			},
    79  			expectedPods: []v1.Pod{pods[5], pods[6]},
    80  		},
    81  		{
    82  			name: "filter pods by label expressions",
    83  			selector: v1alpha1.PodSelectorSpec{
    84  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
    85  					ExpressionSelectors: []metav1.LabelSelectorRequirement{
    86  						{
    87  							Key:      "l2",
    88  							Operator: metav1.LabelSelectorOpIn,
    89  							Values:   []string{"l2"},
    90  						},
    91  					},
    92  				},
    93  			},
    94  			expectedPods: []v1.Pod{pods[5], pods[6]},
    95  		},
    96  		{
    97  			name: "filter pods by label selectors and expression selectors",
    98  			selector: v1alpha1.PodSelectorSpec{
    99  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   100  					LabelSelectors: map[string]string{"l1": "l1"},
   101  					ExpressionSelectors: []metav1.LabelSelectorRequirement{
   102  						{
   103  							Key:      "l2",
   104  							Operator: metav1.LabelSelectorOpIn,
   105  							Values:   []string{"l2"},
   106  						},
   107  					},
   108  				},
   109  			},
   110  			expectedPods: nil,
   111  		},
   112  		{
   113  			name: "filter namespace and labels",
   114  			selector: v1alpha1.PodSelectorSpec{
   115  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   116  					Namespaces:     []string{"test-s"},
   117  					LabelSelectors: map[string]string{"l2": "l2"},
   118  				},
   119  			},
   120  			expectedPods: []v1.Pod{pods[5], pods[6]},
   121  		},
   122  		{
   123  			name: "filter namespace and labels",
   124  			selector: v1alpha1.PodSelectorSpec{
   125  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   126  					Namespaces:     []string{metav1.NamespaceDefault},
   127  					LabelSelectors: map[string]string{"l2": "l2"},
   128  				},
   129  			},
   130  			expectedPods: nil,
   131  		},
   132  		{
   133  			name: "filter by specified node",
   134  			selector: v1alpha1.PodSelectorSpec{
   135  				Nodes: []string{"az1-node1"},
   136  			},
   137  			expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4]},
   138  		},
   139  		{
   140  			name: "filter node and labels",
   141  			selector: v1alpha1.PodSelectorSpec{
   142  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   143  					LabelSelectors: map[string]string{"l1": "l1"},
   144  				},
   145  				Nodes: []string{"az2-node1"},
   146  			},
   147  			expectedPods: nil,
   148  		},
   149  		{
   150  			name: "filter pods by nodeSelector",
   151  			selector: v1alpha1.PodSelectorSpec{
   152  				NodeSelectors: map[string]string{"disktype": "hdd"},
   153  			},
   154  			expectedPods: []v1.Pod{pods[5], pods[6]},
   155  		},
   156  		{
   157  			name: "filter pods by node and nodeSelector",
   158  			selector: v1alpha1.PodSelectorSpec{
   159  				NodeSelectors: map[string]string{"zone": "az1"},
   160  				Nodes:         []string{"az2-node1"},
   161  			},
   162  			expectedPods: []v1.Pod{pods[0], pods[1], pods[2], pods[3], pods[4], pods[5], pods[6]},
   163  		},
   164  	}
   165  
   166  	var (
   167  		testCfgClusterScoped   = true
   168  		testCfgTargetNamespace = ""
   169  	)
   170  
   171  	for _, tc := range tcs {
   172  		filteredPods, err := SelectPods(context.Background(), c, r, tc.selector, testCfgClusterScoped, testCfgTargetNamespace, false)
   173  		g.Expect(err).ShouldNot(HaveOccurred(), tc.name)
   174  		g.Expect(len(filteredPods)).To(Equal(len(tc.expectedPods)), tc.name)
   175  	}
   176  }
   177  
   178  func TestCheckPodMeetSelector(t *testing.T) {
   179  	g := NewGomegaWithT(t)
   180  
   181  	type TestCase struct {
   182  		name          string
   183  		selector      v1alpha1.PodSelectorSpec
   184  		pod           v1.Pod
   185  		expectedValue bool
   186  	}
   187  
   188  	tcs := []TestCase{
   189  		{
   190  			name: "meet label",
   191  			pod:  NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}),
   192  			selector: v1alpha1.PodSelectorSpec{
   193  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   194  					LabelSelectors: map[string]string{"app": "tikv"},
   195  				},
   196  			},
   197  			expectedValue: true,
   198  		},
   199  		{
   200  			name: "not meet label",
   201  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb", "ss": "t1"}}),
   202  			selector: v1alpha1.PodSelectorSpec{
   203  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   204  					LabelSelectors: map[string]string{"app": "tikv"},
   205  				},
   206  			},
   207  			expectedValue: false,
   208  		},
   209  		{
   210  			name: "pod labels is empty",
   211  			pod:  NewPod(PodArg{Name: "t1"}),
   212  			selector: v1alpha1.PodSelectorSpec{
   213  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   214  					LabelSelectors: map[string]string{"app": "tikv"},
   215  				},
   216  			},
   217  			expectedValue: false,
   218  		},
   219  		{
   220  			name:          "selector is empty",
   221  			pod:           NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
   222  			selector:      v1alpha1.PodSelectorSpec{},
   223  			expectedValue: true,
   224  		},
   225  		{
   226  			name: "meet labels and meet expressions",
   227  			pod:  NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}),
   228  			selector: v1alpha1.PodSelectorSpec{
   229  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   230  					LabelSelectors: map[string]string{"app": "tikv"},
   231  					ExpressionSelectors: []metav1.LabelSelectorRequirement{
   232  						{
   233  							Key:      "ss",
   234  							Operator: metav1.LabelSelectorOpExists,
   235  						},
   236  					},
   237  				},
   238  			},
   239  			expectedValue: true,
   240  		},
   241  		{
   242  			name: "meet labels and not meet expressions",
   243  			pod:  NewPod(PodArg{Name: "t1", Status: v1.PodPending, Labels: map[string]string{"app": "tikv", "ss": "t1"}}),
   244  			selector: v1alpha1.PodSelectorSpec{
   245  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   246  					LabelSelectors: map[string]string{"app": "tikv"},
   247  					ExpressionSelectors: []metav1.LabelSelectorRequirement{
   248  						{
   249  							Key:      "ss",
   250  							Operator: metav1.LabelSelectorOpNotIn,
   251  							Values:   []string{"t1"},
   252  						},
   253  					},
   254  				},
   255  			},
   256  			expectedValue: false,
   257  		},
   258  		{
   259  			name: "meet namespace",
   260  			pod:  NewPod(PodArg{Name: "t1"}),
   261  			selector: v1alpha1.PodSelectorSpec{
   262  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   263  					Namespaces: []string{metav1.NamespaceDefault},
   264  				},
   265  			},
   266  			expectedValue: true,
   267  		},
   268  		{
   269  			name: "meet namespace and meet labels",
   270  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tikv"}}),
   271  			selector: v1alpha1.PodSelectorSpec{
   272  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   273  					Namespaces:     []string{metav1.NamespaceDefault},
   274  					LabelSelectors: map[string]string{"app": "tikv"},
   275  				},
   276  			},
   277  			expectedValue: true,
   278  		},
   279  		{
   280  			name: "meet namespace and not meet labels",
   281  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
   282  			selector: v1alpha1.PodSelectorSpec{
   283  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   284  					Namespaces:     []string{metav1.NamespaceDefault},
   285  					LabelSelectors: map[string]string{"app": "tikv"},
   286  				},
   287  			},
   288  			expectedValue: false,
   289  		},
   290  		{
   291  			name: "meet pods",
   292  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
   293  			selector: v1alpha1.PodSelectorSpec{
   294  				Pods: map[string][]string{
   295  					metav1.NamespaceDefault: {"t1"},
   296  				},
   297  			},
   298  			expectedValue: true,
   299  		},
   300  		{
   301  			name: "meet annotation",
   302  			pod:  NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1", "an2": "n2"}, Labels: map[string]string{"app": "tidb"}}),
   303  			selector: v1alpha1.PodSelectorSpec{
   304  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   305  					Namespaces: []string{metav1.NamespaceDefault},
   306  					AnnotationSelectors: map[string]string{
   307  						"an": "n1",
   308  					},
   309  				},
   310  			},
   311  			expectedValue: true,
   312  		},
   313  		{
   314  			name: "not meet annotation",
   315  			pod:  NewPod(PodArg{Name: "t1", Ans: map[string]string{"an": "n1"}, Labels: map[string]string{"app": "tidb"}}),
   316  			selector: v1alpha1.PodSelectorSpec{
   317  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   318  					Namespaces: []string{metav1.NamespaceDefault},
   319  					AnnotationSelectors: map[string]string{
   320  						"an": "n2",
   321  					},
   322  				},
   323  			},
   324  			expectedValue: false,
   325  		},
   326  		{
   327  			name: "meet pod selector",
   328  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
   329  			selector: v1alpha1.PodSelectorSpec{
   330  				Pods: map[string][]string{
   331  					metav1.NamespaceDefault: {"t1", "t2"},
   332  				},
   333  			},
   334  			expectedValue: true,
   335  		},
   336  		{
   337  			name: "not meet pod selector",
   338  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
   339  			selector: v1alpha1.PodSelectorSpec{
   340  				Pods: map[string][]string{
   341  					metav1.NamespaceDefault: {"t2"},
   342  				},
   343  			},
   344  			expectedValue: false,
   345  		},
   346  		{
   347  			name: "meet pod selector and not meet labels",
   348  			pod:  NewPod(PodArg{Name: "t1", Labels: map[string]string{"app": "tidb"}}),
   349  			selector: v1alpha1.PodSelectorSpec{
   350  				Pods: map[string][]string{
   351  					metav1.NamespaceDefault: {"t1", "t2"},
   352  				},
   353  				GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
   354  					LabelSelectors: map[string]string{"app": "tikv"},
   355  				},
   356  			},
   357  			expectedValue: false,
   358  		},
   359  	}
   360  
   361  	for _, tc := range tcs {
   362  		meet, err := CheckPodMeetSelector(tc.pod, tc.selector)
   363  		g.Expect(err).ShouldNot(HaveOccurred(), tc.name)
   364  		g.Expect(meet).To(Equal(tc.expectedValue), tc.name)
   365  	}
   366  }
   367  
   368  func TestRandomFixedIndexes(t *testing.T) {
   369  	g := NewGomegaWithT(t)
   370  
   371  	type TestCase struct {
   372  		name              string
   373  		start             uint
   374  		end               uint
   375  		count             uint
   376  		expectedOutputLen int
   377  	}
   378  
   379  	tcs := []TestCase{
   380  		{
   381  			name:              "start 0, end 10, count 3",
   382  			start:             0,
   383  			end:               10,
   384  			count:             3,
   385  			expectedOutputLen: 3,
   386  		},
   387  		{
   388  			name:              "start 0, end 10, count 12",
   389  			start:             0,
   390  			end:               10,
   391  			count:             12,
   392  			expectedOutputLen: 10,
   393  		},
   394  		{
   395  			name:              "start 5, end 10, count 3",
   396  			start:             5,
   397  			end:               10,
   398  			count:             3,
   399  			expectedOutputLen: 3,
   400  		},
   401  	}
   402  
   403  	for _, tc := range tcs {
   404  		values := RandomFixedIndexes(tc.start, tc.end, tc.count)
   405  		g.Expect(len(values)).To(Equal(tc.expectedOutputLen), tc.name)
   406  
   407  		for _, v := range values {
   408  			g.Expect(v).Should(BeNumerically(">=", tc.start), tc.name)
   409  			g.Expect(v).Should(BeNumerically("<", tc.end), tc.name)
   410  		}
   411  	}
   412  }
   413  
   414  func TestFilterByPhaseSelector(t *testing.T) {
   415  	g := NewGomegaWithT(t)
   416  
   417  	type TestCase struct {
   418  		name           string
   419  		pods           []v1.Pod
   420  		filterSelector labels.Selector
   421  		filteredPods   []v1.Pod
   422  	}
   423  
   424  	pods := []v1.Pod{
   425  		NewPod(PodArg{Name: "p1", Status: v1.PodRunning}),
   426  		NewPod(PodArg{Name: "p2", Status: v1.PodRunning}),
   427  		NewPod(PodArg{Name: "p3", Status: v1.PodPending}),
   428  		NewPod(PodArg{Name: "p4", Status: v1.PodFailed}),
   429  	}
   430  
   431  	var tcs []TestCase
   432  
   433  	runningSelector, err := parseSelector(string(pods[1].Status.Phase))
   434  	g.Expect(err).ShouldNot(HaveOccurred())
   435  
   436  	tcs = append(tcs, TestCase{
   437  		name:           "filter n2",
   438  		pods:           pods,
   439  		filterSelector: runningSelector,
   440  		filteredPods:   []v1.Pod{pods[0], pods[1]},
   441  	})
   442  
   443  	emptySelector, err := parseSelector("")
   444  	g.Expect(err).ShouldNot(HaveOccurred())
   445  	tcs = append(tcs, TestCase{
   446  		name:           "filter empty selector",
   447  		pods:           pods,
   448  		filterSelector: emptySelector,
   449  		filteredPods:   pods,
   450  	})
   451  
   452  	tcs = append(tcs, TestCase{
   453  		name:           "filter no pods",
   454  		pods:           []v1.Pod{},
   455  		filterSelector: runningSelector,
   456  		filteredPods:   nil,
   457  	})
   458  
   459  	runningAndPendingSelector, err := parseSelector("Running,Pending")
   460  	g.Expect(err).ShouldNot(HaveOccurred())
   461  
   462  	tcs = append(tcs, TestCase{
   463  		name:           "filter running and pending",
   464  		pods:           pods,
   465  		filterSelector: runningAndPendingSelector,
   466  		filteredPods:   []v1.Pod{pods[0], pods[1], pods[2]},
   467  	})
   468  
   469  	failedSelector, err := parseSelector("Failed")
   470  	g.Expect(err).ShouldNot(HaveOccurred())
   471  
   472  	tcs = append(tcs, TestCase{
   473  		name:           "filter failed",
   474  		pods:           pods,
   475  		filterSelector: failedSelector,
   476  		filteredPods:   []v1.Pod{pods[3]},
   477  	})
   478  
   479  	unknownSelector, err := parseSelector("Unknown")
   480  	g.Expect(err).ShouldNot(HaveOccurred())
   481  	tcs = append(tcs, TestCase{
   482  		name:           "filter Unknown",
   483  		pods:           pods,
   484  		filterSelector: unknownSelector,
   485  		filteredPods:   nil,
   486  	})
   487  
   488  	for _, tc := range tcs {
   489  		g.Expect(filterByPhaseSelector(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name)
   490  	}
   491  }
   492  
   493  func TestFilterByAnnotations(t *testing.T) {
   494  	g := NewGomegaWithT(t)
   495  
   496  	type TestCase struct {
   497  		name           string
   498  		pods           []v1.Pod
   499  		filterSelector labels.Selector
   500  		filteredPods   []v1.Pod
   501  	}
   502  
   503  	pods := []v1.Pod{
   504  		NewPod(PodArg{Name: "p1", Ans: map[string]string{"p1": "p1"}}),
   505  		NewPod(PodArg{Name: "p2", Ans: map[string]string{"p2": "p2"}}),
   506  		NewPod(PodArg{Name: "p3", Ans: map[string]string{"t": "t"}}),
   507  		NewPod(PodArg{Name: "p4", Ans: map[string]string{"t": "t"}}),
   508  	}
   509  
   510  	var tcs []TestCase
   511  	p2Selector, err := parseSelector(label.Label(pods[1].Annotations).String())
   512  	g.Expect(err).ShouldNot(HaveOccurred())
   513  
   514  	tcs = append(tcs, TestCase{
   515  		name:           "filter p2",
   516  		pods:           pods,
   517  		filterSelector: p2Selector,
   518  		filteredPods:   []v1.Pod{pods[1]},
   519  	})
   520  
   521  	emptySelector, err := parseSelector(label.Label(map[string]string{}).String())
   522  	g.Expect(err).ShouldNot(HaveOccurred())
   523  	tcs = append(tcs, TestCase{
   524  		name:           "filter empty selector",
   525  		pods:           pods,
   526  		filterSelector: emptySelector,
   527  		filteredPods:   pods,
   528  	})
   529  
   530  	tcs = append(tcs, TestCase{
   531  		name:           "filter no pods",
   532  		pods:           []v1.Pod{},
   533  		filterSelector: p2Selector,
   534  		filteredPods:   nil,
   535  	})
   536  
   537  	for _, tc := range tcs {
   538  		g.Expect(filterByAnnotations(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name)
   539  	}
   540  }
   541  
   542  func TestFilterNamespaceSelector(t *testing.T) {
   543  	g := NewGomegaWithT(t)
   544  
   545  	type TestCase struct {
   546  		name           string
   547  		pods           []v1.Pod
   548  		filterSelector labels.Selector
   549  		filteredPods   []v1.Pod
   550  	}
   551  
   552  	pods := []v1.Pod{
   553  		NewPod(PodArg{Name: "p1", Namespace: "n1"}),
   554  		NewPod(PodArg{Name: "p2", Namespace: "n2"}),
   555  		NewPod(PodArg{Name: "p3", Namespace: "n2"}),
   556  		NewPod(PodArg{Name: "p4", Namespace: "n4"}),
   557  	}
   558  
   559  	var tcs []TestCase
   560  	n2Selector, err := parseSelector(pods[1].Namespace)
   561  	g.Expect(err).ShouldNot(HaveOccurred())
   562  
   563  	tcs = append(tcs, TestCase{
   564  		name:           "filter n2",
   565  		pods:           pods,
   566  		filterSelector: n2Selector,
   567  		filteredPods:   []v1.Pod{pods[1], pods[2]},
   568  	})
   569  
   570  	emptySelector, err := parseSelector("")
   571  	g.Expect(err).ShouldNot(HaveOccurred())
   572  	tcs = append(tcs, TestCase{
   573  		name:           "filter empty selector",
   574  		pods:           pods,
   575  		filterSelector: emptySelector,
   576  		filteredPods:   pods,
   577  	})
   578  
   579  	tcs = append(tcs, TestCase{
   580  		name:           "filter no pods",
   581  		pods:           []v1.Pod{},
   582  		filterSelector: n2Selector,
   583  		filteredPods:   nil,
   584  	})
   585  
   586  	n2AndN3Selector, err := parseSelector("n2,n3")
   587  	g.Expect(err).ShouldNot(HaveOccurred())
   588  
   589  	tcs = append(tcs, TestCase{
   590  		name:           "filter n2 and n3",
   591  		pods:           pods,
   592  		filterSelector: n2AndN3Selector,
   593  		filteredPods:   []v1.Pod{pods[1], pods[2]},
   594  	})
   595  
   596  	n2AndN4Selector, err := parseSelector("n2,n4")
   597  	g.Expect(err).ShouldNot(HaveOccurred())
   598  
   599  	tcs = append(tcs, TestCase{
   600  		name:           "filter n2 and n4",
   601  		pods:           pods,
   602  		filterSelector: n2AndN4Selector,
   603  		filteredPods:   []v1.Pod{pods[1], pods[2], pods[3]},
   604  	})
   605  
   606  	for _, tc := range tcs {
   607  		g.Expect(filterByNamespaceSelector(tc.pods, tc.filterSelector)).To(Equal(tc.filteredPods), tc.name)
   608  	}
   609  }
   610  
   611  func TestFilterPodByNode(t *testing.T) {
   612  	g := NewGomegaWithT(t)
   613  
   614  	type TestCase struct {
   615  		name         string
   616  		pods         []v1.Pod
   617  		nodes        []v1.Node
   618  		filteredPods []v1.Pod
   619  	}
   620  
   621  	var tcs []TestCase
   622  
   623  	pods := []v1.Pod{
   624  		NewPod(PodArg{Name: "p1", Namespace: "n1", Nodename: "node1"}),
   625  		NewPod(PodArg{Name: "p2", Namespace: "n2", Nodename: "node1"}),
   626  		NewPod(PodArg{Name: "p3", Namespace: "n2", Nodename: "node2"}),
   627  		NewPod(PodArg{Name: "p4", Namespace: "n4", Nodename: "node3"}),
   628  	}
   629  
   630  	nodes := []v1.Node{
   631  		NewNode("node1", map[string]string{"disktype": "ssd", "zone": "az1"}),
   632  		NewNode("node2", map[string]string{"disktype": "hdd", "zone": "az1"}),
   633  	}
   634  
   635  	tcs = append(tcs, TestCase{
   636  		name:         "filter pods from node1 and node2",
   637  		pods:         pods,
   638  		nodes:        nodes,
   639  		filteredPods: []v1.Pod{pods[0], pods[1], pods[2]},
   640  	})
   641  
   642  	tcs = append(tcs, TestCase{
   643  		name:         "filter no nodes",
   644  		pods:         pods,
   645  		nodes:        []v1.Node{},
   646  		filteredPods: nil,
   647  	})
   648  
   649  	for _, tc := range tcs {
   650  		g.Expect(filterPodByNode(tc.pods, tc.nodes)).To(Equal(tc.filteredPods), tc.name)
   651  	}
   652  
   653  }
   654