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