...

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