github.com/argoproj/argo-events@v1.9.1/eventsources/sources/resource/start_test.go (about) 1 /* 2 Copyright 2018 BlackRock, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package resource 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "testing" 24 "time" 25 26 "github.com/smartystreets/goconvey/convey" 27 corev1 "k8s.io/api/core/v1" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 30 "k8s.io/apimachinery/pkg/labels" 31 "k8s.io/client-go/kubernetes/fake" 32 33 "github.com/argoproj/argo-events/common/logging" 34 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" 35 ) 36 37 func TestFilter(t *testing.T) { 38 convey.Convey("Given a resource object, apply filter on it", t, func() { 39 resourceEventSource := &v1alpha1.ResourceEventSource{ 40 Namespace: "fake", 41 GroupVersionResource: metav1.GroupVersionResource{ 42 Group: "", 43 Resource: "pods", 44 Version: "v1", 45 }, 46 Filter: &v1alpha1.ResourceFilter{ 47 Labels: []v1alpha1.Selector{ 48 { 49 Key: "workflows.argoproj.io/phase", 50 Operation: "==", 51 Value: "Succeeded", 52 }, 53 { 54 Key: "name", 55 Operation: "==", 56 Value: "my-workflow", 57 }, 58 }, 59 Fields: []v1alpha1.Selector{ 60 { 61 Key: "metadata.name", 62 Operation: "==", 63 Value: "fak*", 64 }, 65 { 66 Key: "status.phase", 67 Operation: "!=", 68 Value: "Error", 69 }, 70 { 71 Key: "spec.serviceAccountName", 72 Operation: "=", 73 Value: "test*", 74 }, 75 }, 76 }, 77 } 78 pod := &corev1.Pod{ 79 ObjectMeta: metav1.ObjectMeta{ 80 Name: "fake", 81 Namespace: "fake", 82 Labels: map[string]string{ 83 "workflows.argoproj.io/phase": "Succeeded", 84 "name": "my-workflow", 85 }, 86 }, 87 Spec: corev1.PodSpec{ 88 ServiceAccountName: "test-sa", 89 }, 90 Status: corev1.PodStatus{ 91 Phase: "Running", 92 }, 93 } 94 pod, err := fake.NewSimpleClientset().CoreV1().Pods("fake").Create(context.TODO(), pod, metav1.CreateOptions{}) 95 convey.So(err, convey.ShouldBeNil) 96 97 outmap := make(map[string]interface{}) 98 jsonData, err := json.Marshal(pod) 99 convey.So(err, convey.ShouldBeNil) 100 err = json.Unmarshal(jsonData, &outmap) 101 convey.So(err, convey.ShouldBeNil) 102 103 pass := passFilters(&InformerEvent{ 104 Obj: &unstructured.Unstructured{Object: outmap}, 105 Type: "ADD", 106 }, resourceEventSource.Filter, time.Now(), logging.NewArgoEventsLogger()) 107 convey.So(pass, convey.ShouldBeTrue) 108 }) 109 } 110 111 func TestLabelSelector(t *testing.T) { 112 // Test equality operators =, == and in 113 for _, op := range []string{"==", "=", "in"} { 114 t.Run(fmt.Sprintf("Test operator %v", op), func(t *testing.T) { 115 r, err := LabelSelector([]v1alpha1.Selector{{ 116 Key: "key", 117 Operation: op, 118 Value: "1", 119 }}) 120 if err != nil { 121 t.Fatal(err) 122 } 123 validL := &labels.Set{"key": "1"} 124 if !r.Matches(validL) { 125 t.Errorf("didnot match %v", validL) 126 } 127 invalidL := &labels.Set{"key": "2"} 128 if r.Matches(invalidL) { 129 t.Errorf("matched %v", invalidL) 130 } 131 }) 132 } 133 // Test inequality operators != and notin 134 for _, op := range []string{"!=", "notin"} { 135 t.Run(fmt.Sprintf("Test operator %v", op), func(t *testing.T) { 136 r, err := LabelSelector([]v1alpha1.Selector{{ 137 Key: "key", 138 Operation: op, 139 Value: "1", 140 }}) 141 if err != nil { 142 t.Fatal(err) 143 } 144 validL := &labels.Set{"key": "2"} 145 if !r.Matches(validL) { 146 t.Errorf("didnot match %v", validL) 147 } 148 invalidL := &labels.Set{"key": "1"} 149 if r.Matches(invalidL) { 150 t.Errorf("matched %v", invalidL) 151 } 152 }) 153 } 154 // Test greater than operator 155 t.Run("Test operator gt", func(t *testing.T) { 156 r, err := LabelSelector([]v1alpha1.Selector{{ 157 Key: "key", 158 Operation: "gt", 159 Value: "1", 160 }}) 161 if err != nil { 162 t.Fatal(err) 163 } 164 validL := &labels.Set{"key": "2"} 165 if !r.Matches(validL) { 166 t.Errorf("didnot match %v", validL) 167 } 168 invalidL := &labels.Set{"key": "1"} 169 if r.Matches(invalidL) { 170 t.Errorf("matched %v", invalidL) 171 } 172 }) 173 // Test lower than operator 174 t.Run("Test operator lt", func(t *testing.T) { 175 r, err := LabelSelector([]v1alpha1.Selector{{ 176 Key: "key", 177 Operation: "lt", 178 Value: "2", 179 }}) 180 if err != nil { 181 t.Fatal(err) 182 } 183 validL := &labels.Set{"key": "1"} 184 if !r.Matches(validL) { 185 t.Errorf("didnot match %v", validL) 186 } 187 invalidL := &labels.Set{"key": "2"} 188 if r.Matches(invalidL) { 189 t.Errorf("matched %v", invalidL) 190 } 191 }) 192 // Test exists operator 193 t.Run("Test operator exists", func(t *testing.T) { 194 r, err := LabelSelector([]v1alpha1.Selector{{ 195 Key: "key", 196 Operation: "exists", 197 }}) 198 if err != nil { 199 t.Fatal(err) 200 } 201 validL := &labels.Set{"key": "something"} 202 if !r.Matches(validL) { 203 t.Errorf("didnot match %v", validL) 204 } 205 invalidL := &labels.Set{"notkey": "something"} 206 if r.Matches(invalidL) { 207 t.Errorf("matched %v", invalidL) 208 } 209 }) 210 // Test doesnot exist operator 211 t.Run("Test operator !", func(t *testing.T) { 212 r, err := LabelSelector([]v1alpha1.Selector{{ 213 Key: "key", 214 Operation: "!", 215 }}) 216 if err != nil { 217 t.Fatal(err) 218 } 219 validL := &labels.Set{"notkey": "something"} 220 if !r.Matches(validL) { 221 t.Errorf("didnot match %v", validL) 222 } 223 invalidL := &labels.Set{"key": "something"} 224 if r.Matches(invalidL) { 225 t.Errorf("matched %v", invalidL) 226 } 227 }) 228 // Test default operator 229 t.Run("Test default operator", func(t *testing.T) { 230 r, err := LabelSelector([]v1alpha1.Selector{{ 231 Key: "key", 232 Operation: "", 233 Value: "something", 234 }}) 235 if err != nil { 236 t.Fatal(err) 237 } 238 validL := &labels.Set{"key": "something"} 239 if !r.Matches(validL) { 240 t.Errorf("didnot match %v", validL) 241 } 242 invalidL := &labels.Set{"key": "not something"} 243 if r.Matches(invalidL) { 244 t.Errorf("matched %v", invalidL) 245 } 246 }) 247 // Test invalid operators <= and >= 248 for _, op := range []string{"<=", ">="} { 249 t.Run(fmt.Sprintf("Invalid operator %v", op), func(t *testing.T) { 250 _, err := LabelSelector([]v1alpha1.Selector{{ 251 Key: "workflows.argoproj.io/phase", 252 Operation: op, 253 Value: "1", 254 }}) 255 if err == nil { 256 t.Errorf("Invalid operator should throw error") 257 } 258 }) 259 } 260 // Test comma separated values for in 261 t.Run("Comma separated values", func(t *testing.T) { 262 r, err := LabelSelector([]v1alpha1.Selector{{ 263 Key: "key", 264 Operation: "in", 265 Value: "a,b,", 266 }}) 267 if err != nil { 268 t.Fatal("valid value threw error, value %w", err) 269 } 270 for _, validL := range []labels.Set{{"key": "a"}, {"key": "b"}, {"key": ""}} { 271 if !r.Matches(validL) { 272 t.Errorf("didnot match %v", validL) 273 } 274 } 275 invalidL := &labels.Set{"key": "c"} 276 if r.Matches(invalidL) { 277 t.Errorf("matched %v", invalidL) 278 } 279 }) 280 }