github.com/redhat-appstudio/release-service@v0.0.0-20240507143925-083712697924/controllers/utils/predicates/predicates_test.go (about) 1 /* 2 Copyright 2023 Red Hat 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 predicates 18 19 import ( 20 "time" 21 22 . "github.com/onsi/ginkgo/v2" 23 . "github.com/onsi/gomega" 24 25 "github.com/redhat-appstudio/release-service/api/v1alpha1" 26 "github.com/redhat-appstudio/release-service/metadata" 27 tektonutils "github.com/redhat-appstudio/release-service/tekton/utils" 28 corev1 "k8s.io/api/core/v1" 29 "sigs.k8s.io/controller-runtime/pkg/event" 30 "sigs.k8s.io/controller-runtime/pkg/predicate" 31 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 ) 34 35 var _ = Describe("Predicates", Ordered, func() { 36 37 const ( 38 namespace = "default" 39 namespace2 = "other" 40 applicationName = "test-application" 41 ) 42 43 Context("Working with ReleasePlans and ReleasePlanAdmissions", func() { 44 var releasePlan, releasePlanDiffApp, releasePlanDiffLabel, 45 releasePlanDiffTarget, releasePlanDiffStatus *v1alpha1.ReleasePlan 46 var releasePlanAdmission, releasePlanAdmissionDiffApps, releasePlanAdmissionDiffOrigin, 47 releasePlanAdmissionDiffStatus *v1alpha1.ReleasePlanAdmission 48 var instance predicate.Predicate 49 50 BeforeAll(func() { 51 releasePlan = &v1alpha1.ReleasePlan{ 52 ObjectMeta: metav1.ObjectMeta{ 53 Name: "releaseplan", 54 Namespace: namespace, 55 Labels: map[string]string{ 56 metadata.AutoReleaseLabel: "true", 57 }, 58 }, 59 Spec: v1alpha1.ReleasePlanSpec{ 60 Application: applicationName, 61 Target: namespace2, 62 }, 63 } 64 releasePlanDiffApp = &v1alpha1.ReleasePlan{ 65 ObjectMeta: metav1.ObjectMeta{ 66 Name: "releaseplan-app", 67 Namespace: namespace, 68 Labels: map[string]string{ 69 metadata.AutoReleaseLabel: "true", 70 }, 71 }, 72 Spec: v1alpha1.ReleasePlanSpec{ 73 Application: "diff", 74 Target: namespace2, 75 }, 76 } 77 releasePlanDiffLabel = &v1alpha1.ReleasePlan{ 78 ObjectMeta: metav1.ObjectMeta{ 79 Name: "releaseplan-label", 80 Namespace: namespace, 81 Labels: map[string]string{ 82 metadata.AutoReleaseLabel: "false", 83 }, 84 }, 85 Spec: v1alpha1.ReleasePlanSpec{ 86 Application: applicationName, 87 Target: namespace2, 88 }, 89 } 90 releasePlanDiffTarget = &v1alpha1.ReleasePlan{ 91 ObjectMeta: metav1.ObjectMeta{ 92 Name: "releaseplan-target", 93 Namespace: namespace, 94 Labels: map[string]string{ 95 metadata.AutoReleaseLabel: "true", 96 }, 97 }, 98 Spec: v1alpha1.ReleasePlanSpec{ 99 Application: applicationName, 100 Target: "diff", 101 }, 102 } 103 releasePlanDiffStatus = &v1alpha1.ReleasePlan{ 104 ObjectMeta: metav1.ObjectMeta{ 105 Name: "releaseplan-status", 106 Namespace: namespace, 107 Labels: map[string]string{ 108 metadata.AutoReleaseLabel: "true", 109 }, 110 }, 111 Spec: v1alpha1.ReleasePlanSpec{ 112 Application: applicationName, 113 Target: namespace2, 114 }, 115 } 116 releasePlanDiffStatus.MarkMatched(&v1alpha1.ReleasePlanAdmission{}) 117 118 releasePlanAdmission = &v1alpha1.ReleasePlanAdmission{ 119 ObjectMeta: metav1.ObjectMeta{ 120 Name: "releaseplanadmission", 121 Namespace: namespace, 122 Labels: map[string]string{ 123 metadata.AutoReleaseLabel: "true", 124 }, 125 }, 126 Spec: v1alpha1.ReleasePlanAdmissionSpec{ 127 Applications: []string{ 128 applicationName, 129 }, 130 Origin: namespace2, 131 Pipeline: &tektonutils.Pipeline{ 132 PipelineRef: tektonutils.PipelineRef{ 133 Resolver: "bundles", 134 Params: []tektonutils.Param{ 135 {Name: "bundle", Value: "quay.io/some/bundle"}, 136 {Name: "name", Value: "release-pipeline"}, 137 {Name: "kind", Value: "pipeline"}, 138 }, 139 }, 140 }, 141 Policy: "policy", 142 }, 143 } 144 releasePlanAdmissionDiffApps = &v1alpha1.ReleasePlanAdmission{ 145 ObjectMeta: metav1.ObjectMeta{ 146 Name: "releaseplanadmission-app", 147 Namespace: namespace, 148 Labels: map[string]string{ 149 metadata.AutoReleaseLabel: "true", 150 }, 151 }, 152 Spec: v1alpha1.ReleasePlanAdmissionSpec{ 153 Applications: []string{ 154 "diff", 155 }, 156 Origin: namespace2, 157 Pipeline: &tektonutils.Pipeline{ 158 PipelineRef: tektonutils.PipelineRef{ 159 Resolver: "bundles", 160 Params: []tektonutils.Param{ 161 {Name: "bundle", Value: "quay.io/some/bundle"}, 162 {Name: "name", Value: "release-pipeline"}, 163 {Name: "kind", Value: "pipeline"}, 164 }, 165 }, 166 }, 167 Policy: "policy", 168 }, 169 } 170 releasePlanAdmissionDiffOrigin = &v1alpha1.ReleasePlanAdmission{ 171 ObjectMeta: metav1.ObjectMeta{ 172 Name: "releaseplanadmission-origin", 173 Namespace: namespace, 174 Labels: map[string]string{ 175 metadata.AutoReleaseLabel: "true", 176 }, 177 }, 178 Spec: v1alpha1.ReleasePlanAdmissionSpec{ 179 Applications: []string{ 180 applicationName, 181 }, 182 Origin: "diff", 183 Pipeline: &tektonutils.Pipeline{ 184 PipelineRef: tektonutils.PipelineRef{ 185 Resolver: "bundles", 186 Params: []tektonutils.Param{ 187 {Name: "bundle", Value: "quay.io/some/bundle"}, 188 {Name: "name", Value: "release-pipeline"}, 189 {Name: "kind", Value: "pipeline"}, 190 }, 191 }, 192 }, 193 Policy: "policy", 194 }, 195 } 196 releasePlanAdmissionDiffStatus = &v1alpha1.ReleasePlanAdmission{ 197 ObjectMeta: metav1.ObjectMeta{ 198 Name: "releaseplanadmission-status", 199 Namespace: namespace, 200 Labels: map[string]string{ 201 metadata.AutoReleaseLabel: "true", 202 }, 203 }, 204 Spec: v1alpha1.ReleasePlanAdmissionSpec{ 205 Applications: []string{ 206 applicationName, 207 }, 208 Origin: namespace2, 209 Pipeline: &tektonutils.Pipeline{ 210 PipelineRef: tektonutils.PipelineRef{ 211 Resolver: "bundles", 212 Params: []tektonutils.Param{ 213 {Name: "bundle", Value: "quay.io/some/bundle"}, 214 {Name: "name", Value: "release-pipeline"}, 215 {Name: "kind", Value: "pipeline"}, 216 }, 217 }, 218 }, 219 Policy: "policy", 220 }, 221 } 222 releasePlanAdmissionDiffStatus.MarkMatched(&v1alpha1.ReleasePlan{}) 223 224 instance = MatchPredicate() 225 }) 226 227 When("calling MatchPredicate", func() { 228 It("returns true for creating events", func() { 229 contextEvent := event.CreateEvent{ 230 Object: releasePlan, 231 } 232 Expect(instance.Create(contextEvent)).To(BeTrue()) 233 }) 234 235 It("returns true for deleting events", func() { 236 contextEvent := event.DeleteEvent{ 237 Object: releasePlan, 238 } 239 Expect(instance.Delete(contextEvent)).To(BeTrue()) 240 }) 241 242 It("should ignore generic events", func() { 243 contextEvent := event.GenericEvent{ 244 Object: releasePlan, 245 } 246 Expect(instance.Generic(contextEvent)).To(BeFalse()) 247 }) 248 249 It("returns true when the application changes between ReleasePlans", func() { 250 contextEvent := event.UpdateEvent{ 251 ObjectOld: releasePlan, 252 ObjectNew: releasePlanDiffApp, 253 } 254 Expect(instance.Update(contextEvent)).To(BeTrue()) 255 }) 256 257 It("returns true when the applications change between ReleasePlanAdmissions", func() { 258 contextEvent := event.UpdateEvent{ 259 ObjectOld: releasePlanAdmission, 260 ObjectNew: releasePlanAdmissionDiffApps, 261 } 262 Expect(instance.Update(contextEvent)).To(BeTrue()) 263 }) 264 265 It("returns true when the auto-release label changes", func() { 266 contextEvent := event.UpdateEvent{ 267 ObjectOld: releasePlan, 268 ObjectNew: releasePlanDiffLabel, 269 } 270 Expect(instance.Update(contextEvent)).To(BeTrue()) 271 }) 272 273 It("returns true when the target changes between ReleasePlans", func() { 274 contextEvent := event.UpdateEvent{ 275 ObjectOld: releasePlan, 276 ObjectNew: releasePlanDiffTarget, 277 } 278 Expect(instance.Update(contextEvent)).To(BeTrue()) 279 }) 280 281 It("returns true when the origin changes between ReleasePlanAdmissions", func() { 282 contextEvent := event.UpdateEvent{ 283 ObjectOld: releasePlanAdmission, 284 ObjectNew: releasePlanAdmissionDiffOrigin, 285 } 286 Expect(instance.Update(contextEvent)).To(BeTrue()) 287 }) 288 289 It("returns true when the matched condition in the status changes", func() { 290 contextEvent := event.UpdateEvent{ 291 ObjectOld: releasePlan, 292 ObjectNew: releasePlanDiffStatus, 293 } 294 Expect(instance.Update(contextEvent)).To(BeTrue()) 295 }) 296 }) 297 298 When("calling haveApplicationsChanged", func() { 299 It("returns true when the application has changed between ReleasePlans", func() { 300 Expect(haveApplicationsChanged(releasePlan, releasePlanDiffApp)).To(BeTrue()) 301 }) 302 303 It("returns true when the applications have changed between ReleasePlanAdmissions", func() { 304 Expect(haveApplicationsChanged(releasePlanAdmission, releasePlanAdmissionDiffApps)).To(BeTrue()) 305 }) 306 307 It("returns false when the application has not changed between ReleasePlans", func() { 308 Expect(haveApplicationsChanged(releasePlan, releasePlanDiffTarget)).To(BeFalse()) 309 }) 310 311 It("returns false when the applications have not changed between ReleasePlanAdmissions", func() { 312 Expect(haveApplicationsChanged(releasePlanAdmission, releasePlanAdmissionDiffOrigin)).To(BeFalse()) 313 }) 314 }) 315 316 When("calling hasSourceChanged", func() { 317 It("returns true when the target has changed between ReleasePlans", func() { 318 Expect(hasSourceChanged(releasePlan, releasePlanDiffTarget)).To(BeTrue()) 319 }) 320 321 It("returns true when the origin has changed between ReleasePlanAdmissions", func() { 322 Expect(hasSourceChanged(releasePlanAdmission, releasePlanAdmissionDiffOrigin)).To(BeTrue()) 323 }) 324 325 It("returns false when the target has not changed between ReleasePlans", func() { 326 Expect(hasSourceChanged(releasePlan, releasePlanDiffApp)).To(BeFalse()) 327 }) 328 329 It("returns false when the target has not changed between ReleasePlanAdmissions", func() { 330 Expect(hasSourceChanged(releasePlanAdmission, releasePlanAdmissionDiffApps)).To(BeFalse()) 331 }) 332 }) 333 334 When("calling hasMatchConditionChanged", func() { 335 It("returns true when the ReleasePlans with differing lastTransitionTimes are passed", func() { 336 Expect(hasMatchConditionChanged(releasePlan, releasePlanDiffStatus)).To(BeTrue()) 337 }) 338 339 It("returns true when the ReleasePlanAdmissions with differing lastTransitionTimes are passed", func() { 340 Expect(hasMatchConditionChanged(releasePlanAdmission, releasePlanAdmissionDiffStatus)).To(BeTrue()) 341 }) 342 343 It("returns false when the ReleasePlans with the same lastTransitionTimes are passed", func() { 344 Expect(hasMatchConditionChanged(releasePlanDiffStatus, releasePlanDiffStatus)).To(BeFalse()) 345 }) 346 347 It("returns false when the ReleasePlanAdmissions with the same lastTransitionTimes are passed", func() { 348 Expect(hasMatchConditionChanged(releasePlanAdmissionDiffStatus, releasePlanAdmissionDiffStatus)).To(BeFalse()) 349 }) 350 351 It("returns false when objects of different types are passed", func() { 352 Expect(hasMatchConditionChanged(releasePlanDiffStatus, releasePlanAdmissionDiffStatus)).To(BeFalse()) 353 }) 354 }) 355 }) 356 357 When("calling hasConditionChanged", func() { 358 It("returns false when both conditions are nil", func() { 359 Expect(hasConditionChanged(nil, nil)).To(BeFalse()) 360 }) 361 362 It("returns true when just the first condition is nil", func() { 363 condition := &metav1.Condition{} 364 Expect(hasConditionChanged(condition, nil)).To(BeTrue()) 365 }) 366 367 It("returns true when just the second condition is nil", func() { 368 condition := &metav1.Condition{} 369 Expect(hasConditionChanged(nil, condition)).To(BeTrue()) 370 }) 371 372 It("returns false when the conditions have the same lastTransitionTime", func() { 373 transitionTime := metav1.Time{Time: time.Now()} 374 condition1 := &metav1.Condition{LastTransitionTime: transitionTime} 375 condition2 := &metav1.Condition{LastTransitionTime: transitionTime} 376 Expect(hasConditionChanged(condition1, condition2)).To(BeFalse()) 377 }) 378 379 It("returns true when the conditions have different lastTransitionTimes", func() { 380 transitionTime := metav1.Time{Time: time.Now()} 381 condition1 := &metav1.Condition{LastTransitionTime: transitionTime} 382 condition2 := &metav1.Condition{LastTransitionTime: metav1.Time{Time: transitionTime.Add(time.Minute)}} 383 Expect(hasConditionChanged(condition1, condition2)).To(BeTrue()) 384 }) 385 }) 386 387 When("calling hasAutoReleaseLabelChanged", func() { 388 var podTrue, podFalse, podMissing *corev1.Pod 389 390 BeforeAll(func() { 391 podTrue = &corev1.Pod{ 392 ObjectMeta: metav1.ObjectMeta{ 393 Annotations: nil, 394 Labels: map[string]string{ 395 metadata.AutoReleaseLabel: "true", 396 }, 397 }, 398 } 399 podFalse = &corev1.Pod{ 400 ObjectMeta: metav1.ObjectMeta{ 401 Annotations: nil, 402 Labels: map[string]string{ 403 metadata.AutoReleaseLabel: "false", 404 }, 405 }, 406 } 407 podMissing = &corev1.Pod{ 408 ObjectMeta: metav1.ObjectMeta{ 409 Annotations: nil, 410 Labels: nil, 411 }, 412 } 413 }) 414 415 It("returns true when the first object has no labels", func() { 416 Expect(hasAutoReleaseLabelChanged(podMissing, podTrue)).To(BeTrue()) 417 }) 418 419 It("returns true when the second object has no labels", func() { 420 Expect(hasAutoReleaseLabelChanged(podTrue, podFalse)).To(BeTrue()) 421 }) 422 423 It("returns true when the first object has a true label and second has a false label", func() { 424 Expect(hasAutoReleaseLabelChanged(podTrue, podFalse)).To(BeTrue()) 425 }) 426 427 It("returns true when the first object has a false label and second has a true label", func() { 428 Expect(hasAutoReleaseLabelChanged(podFalse, podTrue)).To(BeTrue()) 429 }) 430 431 It("returns false when the both objects have the label set to false", func() { 432 Expect(hasAutoReleaseLabelChanged(podFalse, podFalse)).To(BeFalse()) 433 }) 434 435 It("returns false when the both objects have the label set to true", func() { 436 Expect(hasAutoReleaseLabelChanged(podTrue, podTrue)).To(BeFalse()) 437 }) 438 439 It("returns false when the both objects are missing the label", func() { 440 Expect(hasAutoReleaseLabelChanged(podMissing, podMissing)).To(BeFalse()) 441 }) 442 }) 443 })