github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/controllers/clustereventhandler_test.go (about) 1 package controllers 2 3 import ( 4 "testing" 5 6 log "github.com/sirupsen/logrus" 7 "github.com/stretchr/testify/assert" 8 corev1 "k8s.io/api/core/v1" 9 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 10 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "k8s.io/apimachinery/pkg/runtime" 12 "k8s.io/apimachinery/pkg/types" 13 ctrl "sigs.k8s.io/controller-runtime" 14 "sigs.k8s.io/controller-runtime/pkg/client/fake" 15 "sigs.k8s.io/controller-runtime/pkg/reconcile" 16 17 "github.com/argoproj/argo-cd/v2/applicationset/generators" 18 argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" 19 ) 20 21 func TestClusterEventHandler(t *testing.T) { 22 23 scheme := runtime.NewScheme() 24 err := argov1alpha1.AddToScheme(scheme) 25 assert.Nil(t, err) 26 27 err = argov1alpha1.AddToScheme(scheme) 28 assert.Nil(t, err) 29 30 tests := []struct { 31 name string 32 items []argov1alpha1.ApplicationSet 33 secret corev1.Secret 34 expectedRequests []ctrl.Request 35 }{ 36 { 37 name: "no application sets should mean no requests", 38 items: []argov1alpha1.ApplicationSet{}, 39 secret: corev1.Secret{ 40 ObjectMeta: v1.ObjectMeta{ 41 Namespace: "argocd", 42 Name: "my-secret", 43 Labels: map[string]string{ 44 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 45 }, 46 }, 47 }, 48 expectedRequests: []reconcile.Request{}, 49 }, 50 { 51 name: "a cluster generator should produce a request", 52 items: []argov1alpha1.ApplicationSet{ 53 { 54 ObjectMeta: v1.ObjectMeta{ 55 Name: "my-app-set", 56 Namespace: "argocd", 57 }, 58 Spec: argov1alpha1.ApplicationSetSpec{ 59 Generators: []argov1alpha1.ApplicationSetGenerator{ 60 { 61 Clusters: &argov1alpha1.ClusterGenerator{}, 62 }, 63 }, 64 }, 65 }, 66 }, 67 secret: corev1.Secret{ 68 ObjectMeta: v1.ObjectMeta{ 69 Namespace: "argocd", 70 Name: "my-secret", 71 Labels: map[string]string{ 72 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 73 }, 74 }, 75 }, 76 expectedRequests: []reconcile.Request{{ 77 NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, 78 }}, 79 }, 80 { 81 name: "multiple cluster generators should produce multiple requests", 82 items: []argov1alpha1.ApplicationSet{ 83 { 84 ObjectMeta: v1.ObjectMeta{ 85 Name: "my-app-set", 86 Namespace: "argocd", 87 }, 88 Spec: argov1alpha1.ApplicationSetSpec{ 89 Generators: []argov1alpha1.ApplicationSetGenerator{ 90 { 91 Clusters: &argov1alpha1.ClusterGenerator{}, 92 }, 93 }, 94 }, 95 }, 96 { 97 ObjectMeta: v1.ObjectMeta{ 98 Name: "my-app-set2", 99 Namespace: "argocd", 100 }, 101 Spec: argov1alpha1.ApplicationSetSpec{ 102 Generators: []argov1alpha1.ApplicationSetGenerator{ 103 { 104 Clusters: &argov1alpha1.ClusterGenerator{}, 105 }, 106 }, 107 }, 108 }, 109 }, 110 secret: corev1.Secret{ 111 ObjectMeta: v1.ObjectMeta{ 112 Namespace: "argocd", 113 Name: "my-secret", 114 Labels: map[string]string{ 115 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 116 }, 117 }, 118 }, 119 expectedRequests: []reconcile.Request{ 120 {NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}}, 121 {NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set2"}}, 122 }, 123 }, 124 { 125 name: "non-cluster generator should not match", 126 items: []argov1alpha1.ApplicationSet{ 127 { 128 ObjectMeta: v1.ObjectMeta{ 129 Name: "my-app-set", 130 Namespace: "another-namespace", 131 }, 132 Spec: argov1alpha1.ApplicationSetSpec{ 133 Generators: []argov1alpha1.ApplicationSetGenerator{ 134 { 135 Clusters: &argov1alpha1.ClusterGenerator{}, 136 }, 137 }, 138 }, 139 }, 140 { 141 ObjectMeta: v1.ObjectMeta{ 142 Name: "app-set-non-cluster", 143 Namespace: "argocd", 144 }, 145 Spec: argov1alpha1.ApplicationSetSpec{ 146 Generators: []argov1alpha1.ApplicationSetGenerator{ 147 { 148 List: &argov1alpha1.ListGenerator{}, 149 }, 150 }, 151 }, 152 }, 153 }, 154 secret: corev1.Secret{ 155 ObjectMeta: v1.ObjectMeta{ 156 Namespace: "argocd", 157 Name: "my-secret", 158 Labels: map[string]string{ 159 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 160 }, 161 }, 162 }, 163 expectedRequests: []reconcile.Request{ 164 {NamespacedName: types.NamespacedName{Namespace: "another-namespace", Name: "my-app-set"}}, 165 }, 166 }, 167 { 168 name: "non-argo cd secret should not match", 169 items: []argov1alpha1.ApplicationSet{ 170 { 171 ObjectMeta: v1.ObjectMeta{ 172 Name: "my-app-set", 173 Namespace: "another-namespace", 174 }, 175 Spec: argov1alpha1.ApplicationSetSpec{ 176 Generators: []argov1alpha1.ApplicationSetGenerator{ 177 { 178 Clusters: &argov1alpha1.ClusterGenerator{}, 179 }, 180 }, 181 }, 182 }, 183 }, 184 secret: corev1.Secret{ 185 ObjectMeta: v1.ObjectMeta{ 186 Namespace: "argocd", 187 Name: "my-non-argocd-secret", 188 }, 189 }, 190 expectedRequests: []reconcile.Request{}, 191 }, 192 { 193 name: "a matrix generator with a cluster generator should produce a request", 194 items: []argov1alpha1.ApplicationSet{ 195 { 196 ObjectMeta: v1.ObjectMeta{ 197 Name: "my-app-set", 198 Namespace: "argocd", 199 }, 200 Spec: argov1alpha1.ApplicationSetSpec{ 201 Generators: []argov1alpha1.ApplicationSetGenerator{ 202 { 203 Matrix: &argov1alpha1.MatrixGenerator{ 204 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 205 { 206 Clusters: &argov1alpha1.ClusterGenerator{}, 207 }, 208 }, 209 }, 210 }, 211 }, 212 }, 213 }, 214 }, 215 secret: corev1.Secret{ 216 ObjectMeta: v1.ObjectMeta{ 217 Namespace: "argocd", 218 Name: "my-secret", 219 Labels: map[string]string{ 220 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 221 }, 222 }, 223 }, 224 expectedRequests: []reconcile.Request{{ 225 NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, 226 }}, 227 }, 228 { 229 name: "a matrix generator with non cluster generator should not match", 230 items: []argov1alpha1.ApplicationSet{ 231 { 232 ObjectMeta: v1.ObjectMeta{ 233 Name: "my-app-set", 234 Namespace: "argocd", 235 }, 236 Spec: argov1alpha1.ApplicationSetSpec{ 237 Generators: []argov1alpha1.ApplicationSetGenerator{ 238 { 239 Matrix: &argov1alpha1.MatrixGenerator{ 240 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 241 { 242 List: &argov1alpha1.ListGenerator{}, 243 }, 244 }, 245 }, 246 }, 247 }, 248 }, 249 }, 250 }, 251 secret: corev1.Secret{ 252 ObjectMeta: v1.ObjectMeta{ 253 Namespace: "argocd", 254 Name: "my-secret", 255 Labels: map[string]string{ 256 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 257 }, 258 }, 259 }, 260 expectedRequests: []reconcile.Request{}, 261 }, 262 { 263 name: "a matrix generator with a nested matrix generator containing a cluster generator should produce a request", 264 items: []argov1alpha1.ApplicationSet{ 265 { 266 ObjectMeta: v1.ObjectMeta{ 267 Name: "my-app-set", 268 Namespace: "argocd", 269 }, 270 Spec: argov1alpha1.ApplicationSetSpec{ 271 Generators: []argov1alpha1.ApplicationSetGenerator{ 272 { 273 Matrix: &argov1alpha1.MatrixGenerator{ 274 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 275 { 276 Matrix: &apiextensionsv1.JSON{ 277 Raw: []byte( 278 `{ 279 "generators": [ 280 { 281 "clusters": { 282 "selector": { 283 "matchLabels": { 284 "argocd.argoproj.io/secret-type": "cluster" 285 } 286 } 287 } 288 } 289 ] 290 }`, 291 ), 292 }, 293 }, 294 }, 295 }, 296 }, 297 }, 298 }, 299 }, 300 }, 301 secret: corev1.Secret{ 302 ObjectMeta: v1.ObjectMeta{ 303 Namespace: "argocd", 304 Name: "my-secret", 305 Labels: map[string]string{ 306 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 307 }, 308 }, 309 }, 310 expectedRequests: []reconcile.Request{{ 311 NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, 312 }}, 313 }, 314 { 315 name: "a matrix generator with a nested matrix generator containing non cluster generator should not match", 316 items: []argov1alpha1.ApplicationSet{ 317 { 318 ObjectMeta: v1.ObjectMeta{ 319 Name: "my-app-set", 320 Namespace: "argocd", 321 }, 322 Spec: argov1alpha1.ApplicationSetSpec{ 323 Generators: []argov1alpha1.ApplicationSetGenerator{ 324 { 325 Matrix: &argov1alpha1.MatrixGenerator{ 326 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 327 { 328 Matrix: &apiextensionsv1.JSON{ 329 Raw: []byte( 330 `{ 331 "generators": [ 332 { 333 "list": { 334 "elements": [ 335 "a", 336 "b" 337 ] 338 } 339 } 340 ] 341 }`, 342 ), 343 }, 344 }, 345 }, 346 }, 347 }, 348 }, 349 }, 350 }, 351 }, 352 secret: corev1.Secret{ 353 ObjectMeta: v1.ObjectMeta{ 354 Namespace: "argocd", 355 Name: "my-secret", 356 Labels: map[string]string{ 357 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 358 }, 359 }, 360 }, 361 expectedRequests: []reconcile.Request{}, 362 }, 363 { 364 name: "a merge generator with a cluster generator should produce a request", 365 items: []argov1alpha1.ApplicationSet{ 366 { 367 ObjectMeta: v1.ObjectMeta{ 368 Name: "my-app-set", 369 Namespace: "argocd", 370 }, 371 Spec: argov1alpha1.ApplicationSetSpec{ 372 Generators: []argov1alpha1.ApplicationSetGenerator{ 373 { 374 Merge: &argov1alpha1.MergeGenerator{ 375 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 376 { 377 Clusters: &argov1alpha1.ClusterGenerator{}, 378 }, 379 }, 380 }, 381 }, 382 }, 383 }, 384 }, 385 }, 386 secret: corev1.Secret{ 387 ObjectMeta: v1.ObjectMeta{ 388 Namespace: "argocd", 389 Name: "my-secret", 390 Labels: map[string]string{ 391 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 392 }, 393 }, 394 }, 395 expectedRequests: []reconcile.Request{{ 396 NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, 397 }}, 398 }, 399 { 400 name: "a matrix generator with non cluster generator should not match", 401 items: []argov1alpha1.ApplicationSet{ 402 { 403 ObjectMeta: v1.ObjectMeta{ 404 Name: "my-app-set", 405 Namespace: "argocd", 406 }, 407 Spec: argov1alpha1.ApplicationSetSpec{ 408 Generators: []argov1alpha1.ApplicationSetGenerator{ 409 { 410 Merge: &argov1alpha1.MergeGenerator{ 411 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 412 { 413 List: &argov1alpha1.ListGenerator{}, 414 }, 415 }, 416 }, 417 }, 418 }, 419 }, 420 }, 421 }, 422 secret: corev1.Secret{ 423 ObjectMeta: v1.ObjectMeta{ 424 Namespace: "argocd", 425 Name: "my-secret", 426 Labels: map[string]string{ 427 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 428 }, 429 }, 430 }, 431 expectedRequests: []reconcile.Request{}, 432 }, 433 { 434 name: "a merge generator with a nested merge generator containing a cluster generator should produce a request", 435 items: []argov1alpha1.ApplicationSet{ 436 { 437 ObjectMeta: v1.ObjectMeta{ 438 Name: "my-app-set", 439 Namespace: "argocd", 440 }, 441 Spec: argov1alpha1.ApplicationSetSpec{ 442 Generators: []argov1alpha1.ApplicationSetGenerator{ 443 { 444 Merge: &argov1alpha1.MergeGenerator{ 445 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 446 { 447 Merge: &apiextensionsv1.JSON{ 448 Raw: []byte( 449 `{ 450 "generators": [ 451 { 452 "clusters": { 453 "selector": { 454 "matchLabels": { 455 "argocd.argoproj.io/secret-type": "cluster" 456 } 457 } 458 } 459 } 460 ] 461 }`, 462 ), 463 }, 464 }, 465 }, 466 }, 467 }, 468 }, 469 }, 470 }, 471 }, 472 secret: corev1.Secret{ 473 ObjectMeta: v1.ObjectMeta{ 474 Namespace: "argocd", 475 Name: "my-secret", 476 Labels: map[string]string{ 477 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 478 }, 479 }, 480 }, 481 expectedRequests: []reconcile.Request{{ 482 NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, 483 }}, 484 }, 485 { 486 name: "a merge generator with a nested merge generator containing non cluster generator should not match", 487 items: []argov1alpha1.ApplicationSet{ 488 { 489 ObjectMeta: v1.ObjectMeta{ 490 Name: "my-app-set", 491 Namespace: "argocd", 492 }, 493 Spec: argov1alpha1.ApplicationSetSpec{ 494 Generators: []argov1alpha1.ApplicationSetGenerator{ 495 { 496 Merge: &argov1alpha1.MergeGenerator{ 497 Generators: []argov1alpha1.ApplicationSetNestedGenerator{ 498 { 499 Merge: &apiextensionsv1.JSON{ 500 Raw: []byte( 501 `{ 502 "generators": [ 503 { 504 "list": { 505 "elements": [ 506 "a", 507 "b" 508 ] 509 } 510 } 511 ] 512 }`, 513 ), 514 }, 515 }, 516 }, 517 }, 518 }, 519 }, 520 }, 521 }, 522 }, 523 secret: corev1.Secret{ 524 ObjectMeta: v1.ObjectMeta{ 525 Namespace: "argocd", 526 Name: "my-secret", 527 Labels: map[string]string{ 528 generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, 529 }, 530 }, 531 }, 532 expectedRequests: []reconcile.Request{}, 533 }, 534 } 535 536 for _, test := range tests { 537 538 t.Run(test.name, func(t *testing.T) { 539 540 appSetList := argov1alpha1.ApplicationSetList{ 541 Items: test.items, 542 } 543 544 fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithLists(&appSetList).Build() 545 546 handler := &clusterSecretEventHandler{ 547 Client: fakeClient, 548 Log: log.WithField("type", "createSecretEventHandler"), 549 } 550 551 mockAddRateLimitingInterface := mockAddRateLimitingInterface{} 552 553 handler.queueRelatedAppGenerators(&mockAddRateLimitingInterface, &test.secret) 554 555 assert.False(t, mockAddRateLimitingInterface.errorOccurred) 556 assert.ElementsMatch(t, mockAddRateLimitingInterface.addedItems, test.expectedRequests) 557 558 }) 559 } 560 561 } 562 563 // Add checks the type, and adds it to the internal list of received additions 564 func (obj *mockAddRateLimitingInterface) Add(item interface{}) { 565 if req, ok := item.(ctrl.Request); ok { 566 obj.addedItems = append(obj.addedItems, req) 567 } else { 568 obj.errorOccurred = true 569 } 570 } 571 572 type mockAddRateLimitingInterface struct { 573 errorOccurred bool 574 addedItems []ctrl.Request 575 } 576 577 func TestNestedGeneratorHasClusterGenerator_NestedClusterGenerator(t *testing.T) { 578 nested := argov1alpha1.ApplicationSetNestedGenerator{ 579 Clusters: &argov1alpha1.ClusterGenerator{}, 580 } 581 582 hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested) 583 584 assert.Nil(t, err) 585 assert.True(t, hasClusterGenerator) 586 } 587 588 func TestNestedGeneratorHasClusterGenerator_NestedMergeGenerator(t *testing.T) { 589 nested := argov1alpha1.ApplicationSetNestedGenerator{ 590 Merge: &apiextensionsv1.JSON{ 591 Raw: []byte( 592 `{ 593 "generators": [ 594 { 595 "clusters": { 596 "selector": { 597 "matchLabels": { 598 "argocd.argoproj.io/secret-type": "cluster" 599 } 600 } 601 } 602 } 603 ] 604 }`, 605 ), 606 }, 607 } 608 609 hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested) 610 611 assert.Nil(t, err) 612 assert.True(t, hasClusterGenerator) 613 } 614 615 func TestNestedGeneratorHasClusterGenerator_NestedMergeGeneratorWithInvalidJSON(t *testing.T) { 616 nested := argov1alpha1.ApplicationSetNestedGenerator{ 617 Merge: &apiextensionsv1.JSON{ 618 Raw: []byte( 619 `{ 620 "generators": [ 621 { 622 "clusters": { 623 "selector": { 624 "matchLabels": { 625 "argocd.argoproj.io/secret-type": "cluster" 626 } 627 } 628 } 629 } 630 ] 631 `, 632 ), 633 }, 634 } 635 636 hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested) 637 638 assert.NotNil(t, err) 639 assert.False(t, hasClusterGenerator) 640 }