...

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/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