github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/utils/utils_test.go (about) 1 package utils 2 3 import ( 4 "crypto/x509" 5 "encoding/json" 6 "os" 7 "path" 8 "testing" 9 "time" 10 11 "github.com/sirupsen/logrus" 12 logtest "github.com/sirupsen/logrus/hooks/test" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 16 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 17 "k8s.io/apimachinery/pkg/runtime" 18 "k8s.io/apimachinery/pkg/types" 19 20 argoappsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" 21 ) 22 23 func TestRenderTemplateParams(t *testing.T) { 24 25 // Believe it or not, this is actually less complex than the equivalent solution using reflection 26 fieldMap := map[string]func(app *argoappsv1.Application) *string{} 27 fieldMap["Path"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.Path } 28 fieldMap["RepoURL"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.RepoURL } 29 fieldMap["TargetRevision"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.TargetRevision } 30 fieldMap["Chart"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.Chart } 31 32 fieldMap["Server"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Server } 33 fieldMap["Namespace"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Namespace } 34 fieldMap["Name"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Name } 35 36 fieldMap["Project"] = func(app *argoappsv1.Application) *string { return &app.Spec.Project } 37 38 emptyApplication := &argoappsv1.Application{ 39 ObjectMeta: metav1.ObjectMeta{ 40 Annotations: map[string]string{"annotation-key": "annotation-value", "annotation-key2": "annotation-value2"}, 41 Labels: map[string]string{"label-key": "label-value", "label-key2": "label-value2"}, 42 CreationTimestamp: metav1.NewTime(time.Now()), 43 UID: types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b"), 44 Name: "application-one", 45 Namespace: "default", 46 }, 47 Spec: argoappsv1.ApplicationSpec{ 48 Source: &argoappsv1.ApplicationSource{ 49 Path: "", 50 RepoURL: "", 51 TargetRevision: "", 52 Chart: "", 53 }, 54 Destination: argoappsv1.ApplicationDestination{ 55 Server: "", 56 Namespace: "", 57 Name: "", 58 }, 59 Project: "", 60 }, 61 } 62 63 tests := []struct { 64 name string 65 fieldVal string 66 params map[string]interface{} 67 expectedVal string 68 }{ 69 { 70 name: "simple substitution", 71 fieldVal: "{{one}}", 72 expectedVal: "two", 73 params: map[string]interface{}{ 74 "one": "two", 75 }, 76 }, 77 { 78 name: "simple substitution with whitespace", 79 fieldVal: "{{ one }}", 80 expectedVal: "two", 81 params: map[string]interface{}{ 82 "one": "two", 83 }, 84 }, 85 86 { 87 name: "template characters but not in a template", 88 fieldVal: "}} {{", 89 expectedVal: "}} {{", 90 params: map[string]interface{}{ 91 "one": "two", 92 }, 93 }, 94 95 { 96 name: "nested template", 97 fieldVal: "{{ }}", 98 expectedVal: "{{ }}", 99 params: map[string]interface{}{ 100 "one": "{{ }}", 101 }, 102 }, 103 { 104 name: "field with whitespace", 105 fieldVal: "{{ }}", 106 expectedVal: "{{ }}", 107 params: map[string]interface{}{ 108 " ": "two", 109 "": "three", 110 }, 111 }, 112 113 { 114 name: "template contains itself, containing itself", 115 fieldVal: "{{one}}", 116 expectedVal: "{{one}}", 117 params: map[string]interface{}{ 118 "{{one}}": "{{one}}", 119 }, 120 }, 121 122 { 123 name: "template contains itself, containing something else", 124 fieldVal: "{{one}}", 125 expectedVal: "{{one}}", 126 params: map[string]interface{}{ 127 "{{one}}": "{{two}}", 128 }, 129 }, 130 131 { 132 name: "templates are case sensitive", 133 fieldVal: "{{ONE}}", 134 expectedVal: "{{ONE}}", 135 params: map[string]interface{}{ 136 "{{one}}": "two", 137 }, 138 }, 139 { 140 name: "multiple on a line", 141 fieldVal: "{{one}}{{one}}", 142 expectedVal: "twotwo", 143 params: map[string]interface{}{ 144 "one": "two", 145 }, 146 }, 147 { 148 name: "multiple different on a line", 149 fieldVal: "{{one}}{{three}}", 150 expectedVal: "twofour", 151 params: map[string]interface{}{ 152 "one": "two", 153 "three": "four", 154 }, 155 }, 156 { 157 name: "multiple different on a line with quote", 158 fieldVal: "{{one}} {{three}}", 159 expectedVal: "\"hello\" world four", 160 params: map[string]interface{}{ 161 "one": "\"hello\" world", 162 "three": "four", 163 }, 164 }, 165 } 166 167 for _, test := range tests { 168 169 t.Run(test.name, func(t *testing.T) { 170 171 for fieldName, getPtrFunc := range fieldMap { 172 173 // Clone the template application 174 application := emptyApplication.DeepCopy() 175 176 // Set the value of the target field, to the test value 177 *getPtrFunc(application) = test.fieldVal 178 179 // Render the cloned application, into a new application 180 render := Render{} 181 newApplication, err := render.RenderTemplateParams(application, nil, test.params, false, nil) 182 183 // Retrieve the value of the target field from the newApplication, then verify that 184 // the target field has been templated into the expected value 185 actualValue := *getPtrFunc(newApplication) 186 assert.Equal(t, test.expectedVal, actualValue, "Field '%s' had an unexpected value. expected: '%s' value: '%s'", fieldName, test.expectedVal, actualValue) 187 assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-key"], "annotation-value") 188 assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-key2"], "annotation-value2") 189 assert.Equal(t, newApplication.ObjectMeta.Labels["label-key"], "label-value") 190 assert.Equal(t, newApplication.ObjectMeta.Labels["label-key2"], "label-value2") 191 assert.Equal(t, newApplication.ObjectMeta.Name, "application-one") 192 assert.Equal(t, newApplication.ObjectMeta.Namespace, "default") 193 assert.Equal(t, newApplication.ObjectMeta.UID, types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b")) 194 assert.Equal(t, newApplication.ObjectMeta.CreationTimestamp, application.ObjectMeta.CreationTimestamp) 195 assert.NoError(t, err) 196 } 197 }) 198 } 199 200 } 201 202 func TestRenderHelmValuesObjectJson(t *testing.T) { 203 204 params := map[string]interface{}{ 205 "test": "Hello world", 206 } 207 208 application := &argoappsv1.Application{ 209 ObjectMeta: metav1.ObjectMeta{ 210 Annotations: map[string]string{"annotation-key": "annotation-value", "annotation-key2": "annotation-value2"}, 211 Labels: map[string]string{"label-key": "label-value", "label-key2": "label-value2"}, 212 CreationTimestamp: metav1.NewTime(time.Now()), 213 UID: types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b"), 214 Name: "application-one", 215 Namespace: "default", 216 }, 217 Spec: argoappsv1.ApplicationSpec{ 218 Source: &argoappsv1.ApplicationSource{ 219 Path: "", 220 RepoURL: "", 221 TargetRevision: "", 222 Chart: "", 223 Helm: &argoappsv1.ApplicationSourceHelm{ 224 ValuesObject: &runtime.RawExtension{ 225 Raw: []byte(`{ 226 "some": { 227 "string": "{{.test}}" 228 } 229 }`), 230 }, 231 }, 232 }, 233 Destination: argoappsv1.ApplicationDestination{ 234 Server: "", 235 Namespace: "", 236 Name: "", 237 }, 238 Project: "", 239 }, 240 } 241 242 // Render the cloned application, into a new application 243 render := Render{} 244 newApplication, err := render.RenderTemplateParams(application, nil, params, true, []string{}) 245 246 assert.NoError(t, err) 247 assert.NotNil(t, newApplication) 248 249 var unmarshaled interface{} 250 err = json.Unmarshal(newApplication.Spec.Source.Helm.ValuesObject.Raw, &unmarshaled) 251 252 assert.NoError(t, err) 253 assert.Equal(t, unmarshaled.(map[string]interface{})["some"].(map[string]interface{})["string"], "Hello world") 254 255 } 256 257 func TestRenderHelmValuesObjectYaml(t *testing.T) { 258 259 params := map[string]interface{}{ 260 "test": "Hello world", 261 } 262 263 application := &argoappsv1.Application{ 264 ObjectMeta: metav1.ObjectMeta{ 265 Annotations: map[string]string{"annotation-key": "annotation-value", "annotation-key2": "annotation-value2"}, 266 Labels: map[string]string{"label-key": "label-value", "label-key2": "label-value2"}, 267 CreationTimestamp: metav1.NewTime(time.Now()), 268 UID: types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b"), 269 Name: "application-one", 270 Namespace: "default", 271 }, 272 Spec: argoappsv1.ApplicationSpec{ 273 Source: &argoappsv1.ApplicationSource{ 274 Path: "", 275 RepoURL: "", 276 TargetRevision: "", 277 Chart: "", 278 Helm: &argoappsv1.ApplicationSourceHelm{ 279 ValuesObject: &runtime.RawExtension{ 280 Raw: []byte(`some: 281 string: "{{.test}}"`), 282 }, 283 }, 284 }, 285 Destination: argoappsv1.ApplicationDestination{ 286 Server: "", 287 Namespace: "", 288 Name: "", 289 }, 290 Project: "", 291 }, 292 } 293 294 // Render the cloned application, into a new application 295 render := Render{} 296 newApplication, err := render.RenderTemplateParams(application, nil, params, true, []string{}) 297 298 assert.NoError(t, err) 299 assert.NotNil(t, newApplication) 300 301 var unmarshaled interface{} 302 err = json.Unmarshal(newApplication.Spec.Source.Helm.ValuesObject.Raw, &unmarshaled) 303 304 assert.NoError(t, err) 305 assert.Equal(t, unmarshaled.(map[string]interface{})["some"].(map[string]interface{})["string"], "Hello world") 306 307 } 308 309 func TestRenderTemplateParamsGoTemplate(t *testing.T) { 310 311 // Believe it or not, this is actually less complex than the equivalent solution using reflection 312 fieldMap := map[string]func(app *argoappsv1.Application) *string{} 313 fieldMap["Path"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.Path } 314 fieldMap["RepoURL"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.RepoURL } 315 fieldMap["TargetRevision"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.TargetRevision } 316 fieldMap["Chart"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.Chart } 317 318 fieldMap["Server"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Server } 319 fieldMap["Namespace"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Namespace } 320 fieldMap["Name"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Name } 321 322 fieldMap["Project"] = func(app *argoappsv1.Application) *string { return &app.Spec.Project } 323 324 emptyApplication := &argoappsv1.Application{ 325 ObjectMeta: metav1.ObjectMeta{ 326 Annotations: map[string]string{"annotation-key": "annotation-value", "annotation-key2": "annotation-value2"}, 327 Labels: map[string]string{"label-key": "label-value", "label-key2": "label-value2"}, 328 CreationTimestamp: metav1.NewTime(time.Now()), 329 UID: types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b"), 330 Name: "application-one", 331 Namespace: "default", 332 }, 333 Spec: argoappsv1.ApplicationSpec{ 334 Source: &argoappsv1.ApplicationSource{ 335 Path: "", 336 RepoURL: "", 337 TargetRevision: "", 338 Chart: "", 339 }, 340 Destination: argoappsv1.ApplicationDestination{ 341 Server: "", 342 Namespace: "", 343 Name: "", 344 }, 345 Project: "", 346 }, 347 } 348 349 tests := []struct { 350 name string 351 fieldVal string 352 params map[string]interface{} 353 expectedVal string 354 errorMessage string 355 templateOptions []string 356 }{ 357 { 358 name: "simple substitution", 359 fieldVal: "{{ .one }}", 360 expectedVal: "two", 361 params: map[string]interface{}{ 362 "one": "two", 363 }, 364 }, 365 { 366 name: "simple substitution with whitespace", 367 fieldVal: "{{ .one }}", 368 expectedVal: "two", 369 params: map[string]interface{}{ 370 "one": "two", 371 }, 372 }, 373 { 374 name: "template contains itself, containing itself", 375 fieldVal: "{{ .one }}", 376 expectedVal: "{{one}}", 377 params: map[string]interface{}{ 378 "one": "{{one}}", 379 }, 380 }, 381 382 { 383 name: "template contains itself, containing something else", 384 fieldVal: "{{ .one }}", 385 expectedVal: "{{two}}", 386 params: map[string]interface{}{ 387 "one": "{{two}}", 388 }, 389 }, 390 { 391 name: "multiple on a line", 392 fieldVal: "{{.one}}{{.one}}", 393 expectedVal: "twotwo", 394 params: map[string]interface{}{ 395 "one": "two", 396 }, 397 }, 398 { 399 name: "multiple different on a line", 400 fieldVal: "{{.one}}{{.three}}", 401 expectedVal: "twofour", 402 params: map[string]interface{}{ 403 "one": "two", 404 "three": "four", 405 }, 406 }, 407 { 408 name: "multiple different on a line with quote", 409 fieldVal: "{{.one}} {{.three}}", 410 expectedVal: "\"hello\" world four", 411 params: map[string]interface{}{ 412 "one": "\"hello\" world", 413 "three": "four", 414 }, 415 }, 416 { 417 name: "depth", 418 fieldVal: "{{ .image.version }}", 419 expectedVal: "latest", 420 params: map[string]interface{}{ 421 "replicas": 3, 422 "image": map[string]interface{}{ 423 "name": "busybox", 424 "version": "latest", 425 }, 426 }, 427 }, 428 { 429 name: "multiple depth", 430 fieldVal: "{{ .image.name }}:{{ .image.version }}", 431 expectedVal: "busybox:latest", 432 params: map[string]interface{}{ 433 "replicas": 3, 434 "image": map[string]interface{}{ 435 "name": "busybox", 436 "version": "latest", 437 }, 438 }, 439 }, 440 { 441 name: "if ok", 442 fieldVal: "{{ if .hpa.enabled }}{{ .hpa.maxReplicas }}{{ else }}{{ .replicas }}{{ end }}", 443 expectedVal: "5", 444 params: map[string]interface{}{ 445 "replicas": 3, 446 "hpa": map[string]interface{}{ 447 "enabled": true, 448 "minReplicas": 1, 449 "maxReplicas": 5, 450 }, 451 }, 452 }, 453 { 454 name: "if not ok", 455 fieldVal: "{{ if .hpa.enabled }}{{ .hpa.maxReplicas }}{{ else }}{{ .replicas }}{{ end }}", 456 expectedVal: "3", 457 params: map[string]interface{}{ 458 "replicas": 3, 459 "hpa": map[string]interface{}{ 460 "enabled": false, 461 "minReplicas": 1, 462 "maxReplicas": 5, 463 }, 464 }, 465 }, 466 { 467 name: "loop", 468 fieldVal: "{{ range .volumes }}[{{ .name }}]{{ end }}", 469 expectedVal: "[volume-one][volume-two]", 470 params: map[string]interface{}{ 471 "replicas": 3, 472 "volumes": []map[string]interface{}{ 473 { 474 "name": "volume-one", 475 "emptyDir": map[string]interface{}{}, 476 }, 477 { 478 "name": "volume-two", 479 "emptyDir": map[string]interface{}{}, 480 }, 481 }, 482 }, 483 }, 484 { 485 name: "Index", 486 fieldVal: `{{ index .admin "admin-ca" }}, {{ index .admin "admin-jks" }}`, 487 expectedVal: "value admin ca, value admin jks", 488 params: map[string]interface{}{ 489 "admin": map[string]interface{}{ 490 "admin-ca": "value admin ca", 491 "admin-jks": "value admin jks", 492 }, 493 }, 494 }, 495 { 496 name: "Index", 497 fieldVal: `{{ index .admin "admin-ca" }}, \\ "Hello world", {{ index .admin "admin-jks" }}`, 498 expectedVal: `value "admin" ca with \, \\ "Hello world", value admin jks`, 499 params: map[string]interface{}{ 500 "admin": map[string]interface{}{ 501 "admin-ca": `value "admin" ca with \`, 502 "admin-jks": "value admin jks", 503 }, 504 }, 505 }, 506 { 507 name: "quote", 508 fieldVal: `{{.quote}}`, 509 expectedVal: `"`, 510 params: map[string]interface{}{ 511 "quote": `"`, 512 }, 513 }, 514 { 515 name: "Test No Data", 516 fieldVal: `{{.data}}`, 517 expectedVal: "{{.data}}", 518 params: map[string]interface{}{}, 519 }, 520 { 521 name: "Test Parse Error", 522 fieldVal: `{{functiondoesnotexist}}`, 523 expectedVal: "", 524 params: map[string]interface{}{ 525 "data": `a data string`, 526 }, 527 errorMessage: `failed to parse template {{functiondoesnotexist}}: template: :1: function "functiondoesnotexist" not defined`, 528 }, 529 { 530 name: "Test template error", 531 fieldVal: `{{.data.test}}`, 532 expectedVal: "", 533 params: map[string]interface{}{ 534 "data": `a data string`, 535 }, 536 errorMessage: `failed to execute go template {{.data.test}}: template: :1:7: executing "" at <.data.test>: can't evaluate field test in type interface {}`, 537 }, 538 { 539 name: "lookup missing value with missingkey=default", 540 fieldVal: `--> {{.doesnotexist}} <--`, 541 expectedVal: `--> <no value> <--`, 542 params: map[string]interface{}{ 543 // if no params are passed then for some reason templating is skipped 544 "unused": "this is not used", 545 }, 546 }, 547 { 548 name: "lookup missing value with missingkey=error", 549 fieldVal: `--> {{.doesnotexist}} <--`, 550 expectedVal: "", 551 params: map[string]interface{}{ 552 // if no params are passed then for some reason templating is skipped 553 "unused": "this is not used", 554 }, 555 templateOptions: []string{"missingkey=error"}, 556 errorMessage: `failed to execute go template --> {{.doesnotexist}} <--: template: :1:6: executing "" at <.doesnotexist>: map has no entry for key "doesnotexist"`, 557 }, 558 { 559 name: "toYaml", 560 fieldVal: `{{ toYaml . | indent 2 }}`, 561 expectedVal: " foo:\n bar:\n bool: true\n number: 2\n str: Hello world", 562 params: map[string]interface{}{ 563 "foo": map[string]interface{}{ 564 "bar": map[string]interface{}{ 565 "bool": true, 566 "number": 2, 567 "str": "Hello world", 568 }, 569 }, 570 }, 571 }, 572 { 573 name: "toYaml Error", 574 fieldVal: `{{ toYaml . | indent 2 }}`, 575 expectedVal: " foo:\n bar:\n bool: true\n number: 2\n str: Hello world", 576 errorMessage: "failed to execute go template {{ toYaml . | indent 2 }}: template: :1:3: executing \"\" at <toYaml .>: error calling toYaml: error marshaling into JSON: json: unsupported type: func(*string)", 577 params: map[string]interface{}{ 578 "foo": func(test *string) { 579 }, 580 }, 581 }, 582 { 583 name: "fromYaml", 584 fieldVal: `{{ get (fromYaml .value) "hello" }}`, 585 expectedVal: "world", 586 params: map[string]interface{}{ 587 "value": "hello: world", 588 }, 589 }, 590 { 591 name: "fromYaml error", 592 fieldVal: `{{ get (fromYaml .value) "hello" }}`, 593 expectedVal: "world", 594 errorMessage: "failed to execute go template {{ get (fromYaml .value) \"hello\" }}: template: :1:8: executing \"\" at <fromYaml .value>: error calling fromYaml: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}", 595 params: map[string]interface{}{ 596 "value": "non\n compliant\n yaml", 597 }, 598 }, 599 { 600 name: "fromYamlArray", 601 fieldVal: `{{ fromYamlArray .value | last }}`, 602 expectedVal: "bonjour tout le monde", 603 params: map[string]interface{}{ 604 "value": "- hello world\n- bonjour tout le monde", 605 }, 606 }, 607 { 608 name: "fromYamlArray error", 609 fieldVal: `{{ fromYamlArray .value | last }}`, 610 expectedVal: "bonjour tout le monde", 611 errorMessage: "failed to execute go template {{ fromYamlArray .value | last }}: template: :1:3: executing \"\" at <fromYamlArray .value>: error calling fromYamlArray: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type []interface {}", 612 params: map[string]interface{}{ 613 "value": "non\n compliant\n yaml", 614 }, 615 }, 616 } 617 618 for _, test := range tests { 619 620 t.Run(test.name, func(t *testing.T) { 621 622 for fieldName, getPtrFunc := range fieldMap { 623 624 // Clone the template application 625 application := emptyApplication.DeepCopy() 626 627 // Set the value of the target field, to the test value 628 *getPtrFunc(application) = test.fieldVal 629 630 // Render the cloned application, into a new application 631 render := Render{} 632 newApplication, err := render.RenderTemplateParams(application, nil, test.params, true, test.templateOptions) 633 634 // Retrieve the value of the target field from the newApplication, then verify that 635 // the target field has been templated into the expected value 636 if test.errorMessage != "" { 637 assert.Error(t, err) 638 assert.Equal(t, test.errorMessage, err.Error()) 639 } else { 640 assert.NoError(t, err) 641 actualValue := *getPtrFunc(newApplication) 642 assert.Equal(t, test.expectedVal, actualValue, "Field '%s' had an unexpected value. expected: '%s' value: '%s'", fieldName, test.expectedVal, actualValue) 643 assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-key"], "annotation-value") 644 assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-key2"], "annotation-value2") 645 assert.Equal(t, newApplication.ObjectMeta.Labels["label-key"], "label-value") 646 assert.Equal(t, newApplication.ObjectMeta.Labels["label-key2"], "label-value2") 647 assert.Equal(t, newApplication.ObjectMeta.Name, "application-one") 648 assert.Equal(t, newApplication.ObjectMeta.Namespace, "default") 649 assert.Equal(t, newApplication.ObjectMeta.UID, types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b")) 650 assert.Equal(t, newApplication.ObjectMeta.CreationTimestamp, application.ObjectMeta.CreationTimestamp) 651 } 652 } 653 }) 654 } 655 } 656 657 func TestRenderGeneratorParams_does_not_panic(t *testing.T) { 658 // This test verifies that the RenderGeneratorParams function does not panic when the value in a map is a non- 659 // nillable type. This is a regression test. 660 render := Render{} 661 params := map[string]interface{}{ 662 "branch": "master", 663 } 664 generator := &argoappsv1.ApplicationSetGenerator{ 665 Plugin: &argoappsv1.PluginGenerator{ 666 ConfigMapRef: argoappsv1.PluginConfigMapRef{ 667 Name: "cm-plugin", 668 }, 669 Input: argoappsv1.PluginInput{ 670 Parameters: map[string]apiextensionsv1.JSON{ 671 "branch": { 672 Raw: []byte(`"{{.branch}}"`), 673 }, 674 "repo": { 675 Raw: []byte(`"argo-test"`), 676 }, 677 }, 678 }, 679 }, 680 } 681 _, err := render.RenderGeneratorParams(generator, params, true, []string{}) 682 assert.NoError(t, err) 683 } 684 685 func TestRenderTemplateKeys(t *testing.T) { 686 t.Run("fasttemplate", func(t *testing.T) { 687 application := &argoappsv1.Application{ 688 ObjectMeta: metav1.ObjectMeta{ 689 Annotations: map[string]string{ 690 "annotation-{{key}}": "annotation-{{value}}", 691 }, 692 }, 693 } 694 695 params := map[string]interface{}{ 696 "key": "some-key", 697 "value": "some-value", 698 } 699 700 render := Render{} 701 newApplication, err := render.RenderTemplateParams(application, nil, params, false, nil) 702 require.NoError(t, err) 703 require.Contains(t, newApplication.ObjectMeta.Annotations, "annotation-some-key") 704 assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-some-key"], "annotation-some-value") 705 }) 706 t.Run("gotemplate", func(t *testing.T) { 707 application := &argoappsv1.Application{ 708 ObjectMeta: metav1.ObjectMeta{ 709 Annotations: map[string]string{ 710 "annotation-{{ .key }}": "annotation-{{ .value }}", 711 }, 712 }, 713 } 714 715 params := map[string]interface{}{ 716 "key": "some-key", 717 "value": "some-value", 718 } 719 720 render := Render{} 721 newApplication, err := render.RenderTemplateParams(application, nil, params, true, nil) 722 require.NoError(t, err) 723 require.Contains(t, newApplication.ObjectMeta.Annotations, "annotation-some-key") 724 assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-some-key"], "annotation-some-value") 725 }) 726 } 727 728 func Test_Render_Replace_no_panic_on_missing_closing_brace(t *testing.T) { 729 r := &Render{} 730 assert.NotPanics(t, func() { 731 _, err := r.Replace("{{properly.closed}} {{improperly.closed}", nil, false, []string{}) 732 assert.Error(t, err) 733 }) 734 } 735 736 func TestRenderTemplateParamsFinalizers(t *testing.T) { 737 738 emptyApplication := &argoappsv1.Application{ 739 Spec: argoappsv1.ApplicationSpec{ 740 Source: &argoappsv1.ApplicationSource{ 741 Path: "", 742 RepoURL: "", 743 TargetRevision: "", 744 Chart: "", 745 }, 746 Destination: argoappsv1.ApplicationDestination{ 747 Server: "", 748 Namespace: "", 749 Name: "", 750 }, 751 Project: "", 752 }, 753 } 754 755 for _, c := range []struct { 756 testName string 757 syncPolicy *argoappsv1.ApplicationSetSyncPolicy 758 existingFinalizers []string 759 expectedFinalizers []string 760 }{ 761 { 762 testName: "existing finalizer should be preserved", 763 existingFinalizers: []string{"existing-finalizer"}, 764 syncPolicy: nil, 765 expectedFinalizers: []string{"existing-finalizer"}, 766 }, 767 { 768 testName: "background finalizer should be preserved", 769 existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, 770 syncPolicy: nil, 771 expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, 772 }, 773 774 { 775 testName: "empty finalizer and empty sync should use standard finalizer", 776 existingFinalizers: nil, 777 syncPolicy: nil, 778 expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, 779 }, 780 781 { 782 testName: "standard finalizer should be preserved", 783 existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, 784 syncPolicy: nil, 785 expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, 786 }, 787 { 788 testName: "empty array finalizers should use standard finalizer", 789 existingFinalizers: []string{}, 790 syncPolicy: nil, 791 expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, 792 }, 793 { 794 testName: "non-nil sync policy should use standard finalizer", 795 existingFinalizers: nil, 796 syncPolicy: &argoappsv1.ApplicationSetSyncPolicy{}, 797 expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, 798 }, 799 { 800 testName: "preserveResourcesOnDeletion should not have a finalizer", 801 existingFinalizers: nil, 802 syncPolicy: &argoappsv1.ApplicationSetSyncPolicy{ 803 PreserveResourcesOnDeletion: true, 804 }, 805 expectedFinalizers: nil, 806 }, 807 { 808 testName: "user-specified finalizer should overwrite preserveResourcesOnDeletion", 809 existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, 810 syncPolicy: &argoappsv1.ApplicationSetSyncPolicy{ 811 PreserveResourcesOnDeletion: true, 812 }, 813 expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, 814 }, 815 } { 816 817 t.Run(c.testName, func(t *testing.T) { 818 819 // Clone the template application 820 application := emptyApplication.DeepCopy() 821 application.Finalizers = c.existingFinalizers 822 823 params := map[string]interface{}{ 824 "one": "two", 825 } 826 827 // Render the cloned application, into a new application 828 render := Render{} 829 830 res, err := render.RenderTemplateParams(application, c.syncPolicy, params, true, nil) 831 assert.Nil(t, err) 832 833 assert.ElementsMatch(t, res.Finalizers, c.expectedFinalizers) 834 835 }) 836 837 } 838 839 } 840 841 func TestCheckInvalidGenerators(t *testing.T) { 842 843 scheme := runtime.NewScheme() 844 err := argoappsv1.AddToScheme(scheme) 845 assert.Nil(t, err) 846 err = argoappsv1.AddToScheme(scheme) 847 assert.Nil(t, err) 848 849 for _, c := range []struct { 850 testName string 851 appSet argoappsv1.ApplicationSet 852 expectedMsg string 853 }{ 854 { 855 testName: "invalid generator, without annotation", 856 appSet: argoappsv1.ApplicationSet{ 857 ObjectMeta: metav1.ObjectMeta{ 858 Name: "test-app-set", 859 Namespace: "namespace", 860 }, 861 Spec: argoappsv1.ApplicationSetSpec{ 862 Generators: []argoappsv1.ApplicationSetGenerator{ 863 { 864 List: &argoappsv1.ListGenerator{}, 865 Clusters: nil, 866 Git: nil, 867 }, 868 { 869 List: nil, 870 Clusters: nil, 871 Git: nil, 872 }, 873 { 874 List: nil, 875 Clusters: nil, 876 Git: &argoappsv1.GitGenerator{}, 877 }, 878 }, 879 }, 880 }, 881 expectedMsg: "ApplicationSet test-app-set contains unrecognized generators", 882 }, 883 { 884 testName: "invalid generator, with annotation", 885 appSet: argoappsv1.ApplicationSet{ 886 ObjectMeta: metav1.ObjectMeta{ 887 Name: "test-app-set", 888 Namespace: "namespace", 889 Annotations: map[string]string{ 890 "kubectl.kubernetes.io/last-applied-configuration": `{ 891 "spec":{ 892 "generators":[ 893 {"list":{}}, 894 {"bbb":{}}, 895 {"git":{}}, 896 {"aaa":{}} 897 ] 898 } 899 }`, 900 }, 901 }, 902 Spec: argoappsv1.ApplicationSetSpec{ 903 Generators: []argoappsv1.ApplicationSetGenerator{ 904 { 905 List: &argoappsv1.ListGenerator{}, 906 Clusters: nil, 907 Git: nil, 908 }, 909 { 910 List: nil, 911 Clusters: nil, 912 Git: nil, 913 }, 914 { 915 List: nil, 916 Clusters: nil, 917 Git: &argoappsv1.GitGenerator{}, 918 }, 919 { 920 List: nil, 921 Clusters: nil, 922 Git: nil, 923 }, 924 }, 925 }, 926 }, 927 expectedMsg: "ApplicationSet test-app-set contains unrecognized generators: aaa, bbb", 928 }, 929 } { 930 oldhooks := logrus.StandardLogger().ReplaceHooks(logrus.LevelHooks{}) 931 defer logrus.StandardLogger().ReplaceHooks(oldhooks) 932 hook := logtest.NewGlobal() 933 934 _ = CheckInvalidGenerators(&c.appSet) 935 assert.True(t, len(hook.Entries) >= 1, c.testName) 936 assert.NotNil(t, hook.LastEntry(), c.testName) 937 if hook.LastEntry() != nil { 938 assert.Equal(t, logrus.WarnLevel, hook.LastEntry().Level, c.testName) 939 assert.Equal(t, c.expectedMsg, hook.LastEntry().Message, c.testName) 940 } 941 hook.Reset() 942 } 943 } 944 945 func TestInvalidGenerators(t *testing.T) { 946 947 scheme := runtime.NewScheme() 948 err := argoappsv1.AddToScheme(scheme) 949 assert.Nil(t, err) 950 err = argoappsv1.AddToScheme(scheme) 951 assert.Nil(t, err) 952 953 for _, c := range []struct { 954 testName string 955 appSet argoappsv1.ApplicationSet 956 expectedInvalid bool 957 expectedNames map[string]bool 958 }{ 959 { 960 testName: "valid generators, with annotation", 961 appSet: argoappsv1.ApplicationSet{ 962 ObjectMeta: metav1.ObjectMeta{ 963 Name: "name", 964 Namespace: "namespace", 965 Annotations: map[string]string{ 966 "kubectl.kubernetes.io/last-applied-configuration": `{ 967 "spec":{ 968 "generators":[ 969 {"list":{}}, 970 {"cluster":{}}, 971 {"git":{}} 972 ] 973 } 974 }`, 975 }, 976 }, 977 Spec: argoappsv1.ApplicationSetSpec{ 978 Generators: []argoappsv1.ApplicationSetGenerator{ 979 { 980 List: &argoappsv1.ListGenerator{}, 981 Clusters: nil, 982 Git: nil, 983 }, 984 { 985 List: nil, 986 Clusters: &argoappsv1.ClusterGenerator{}, 987 Git: nil, 988 }, 989 { 990 List: nil, 991 Clusters: nil, 992 Git: &argoappsv1.GitGenerator{}, 993 }, 994 }, 995 }, 996 }, 997 expectedInvalid: false, 998 expectedNames: map[string]bool{}, 999 }, 1000 { 1001 testName: "invalid generators, no annotation", 1002 appSet: argoappsv1.ApplicationSet{ 1003 ObjectMeta: metav1.ObjectMeta{ 1004 Name: "name", 1005 Namespace: "namespace", 1006 }, 1007 Spec: argoappsv1.ApplicationSetSpec{ 1008 Generators: []argoappsv1.ApplicationSetGenerator{ 1009 { 1010 List: nil, 1011 Clusters: nil, 1012 Git: nil, 1013 }, 1014 { 1015 List: nil, 1016 Clusters: nil, 1017 Git: nil, 1018 }, 1019 }, 1020 }, 1021 }, 1022 expectedInvalid: true, 1023 expectedNames: map[string]bool{}, 1024 }, 1025 { 1026 testName: "valid and invalid generators, no annotation", 1027 appSet: argoappsv1.ApplicationSet{ 1028 ObjectMeta: metav1.ObjectMeta{ 1029 Name: "name", 1030 Namespace: "namespace", 1031 }, 1032 Spec: argoappsv1.ApplicationSetSpec{ 1033 Generators: []argoappsv1.ApplicationSetGenerator{ 1034 { 1035 List: nil, 1036 Clusters: &argoappsv1.ClusterGenerator{}, 1037 Git: nil, 1038 }, 1039 { 1040 List: nil, 1041 Clusters: nil, 1042 Git: nil, 1043 }, 1044 { 1045 List: nil, 1046 Clusters: nil, 1047 Git: &argoappsv1.GitGenerator{}, 1048 }, 1049 }, 1050 }, 1051 }, 1052 expectedInvalid: true, 1053 expectedNames: map[string]bool{}, 1054 }, 1055 { 1056 testName: "valid and invalid generators, with annotation", 1057 appSet: argoappsv1.ApplicationSet{ 1058 ObjectMeta: metav1.ObjectMeta{ 1059 Name: "name", 1060 Namespace: "namespace", 1061 Annotations: map[string]string{ 1062 "kubectl.kubernetes.io/last-applied-configuration": `{ 1063 "spec":{ 1064 "generators":[ 1065 {"cluster":{}}, 1066 {"bbb":{}}, 1067 {"git":{}}, 1068 {"aaa":{}} 1069 ] 1070 } 1071 }`, 1072 }, 1073 }, 1074 Spec: argoappsv1.ApplicationSetSpec{ 1075 Generators: []argoappsv1.ApplicationSetGenerator{ 1076 { 1077 List: nil, 1078 Clusters: &argoappsv1.ClusterGenerator{}, 1079 Git: nil, 1080 }, 1081 { 1082 List: nil, 1083 Clusters: nil, 1084 Git: nil, 1085 }, 1086 { 1087 List: nil, 1088 Clusters: nil, 1089 Git: &argoappsv1.GitGenerator{}, 1090 }, 1091 { 1092 List: nil, 1093 Clusters: nil, 1094 Git: nil, 1095 }, 1096 }, 1097 }, 1098 }, 1099 expectedInvalid: true, 1100 expectedNames: map[string]bool{ 1101 "aaa": true, 1102 "bbb": true, 1103 }, 1104 }, 1105 { 1106 testName: "invalid generator, annotation with missing spec", 1107 appSet: argoappsv1.ApplicationSet{ 1108 ObjectMeta: metav1.ObjectMeta{ 1109 Name: "name", 1110 Namespace: "namespace", 1111 Annotations: map[string]string{ 1112 "kubectl.kubernetes.io/last-applied-configuration": `{ 1113 }`, 1114 }, 1115 }, 1116 Spec: argoappsv1.ApplicationSetSpec{ 1117 Generators: []argoappsv1.ApplicationSetGenerator{ 1118 { 1119 List: nil, 1120 Clusters: nil, 1121 Git: nil, 1122 }, 1123 }, 1124 }, 1125 }, 1126 expectedInvalid: true, 1127 expectedNames: map[string]bool{}, 1128 }, 1129 { 1130 testName: "invalid generator, annotation with missing generators array", 1131 appSet: argoappsv1.ApplicationSet{ 1132 ObjectMeta: metav1.ObjectMeta{ 1133 Name: "name", 1134 Namespace: "namespace", 1135 Annotations: map[string]string{ 1136 "kubectl.kubernetes.io/last-applied-configuration": `{ 1137 "spec":{ 1138 } 1139 }`, 1140 }, 1141 }, 1142 Spec: argoappsv1.ApplicationSetSpec{ 1143 Generators: []argoappsv1.ApplicationSetGenerator{ 1144 { 1145 List: nil, 1146 Clusters: nil, 1147 Git: nil, 1148 }, 1149 }, 1150 }, 1151 }, 1152 expectedInvalid: true, 1153 expectedNames: map[string]bool{}, 1154 }, 1155 { 1156 testName: "invalid generator, annotation with empty generators array", 1157 appSet: argoappsv1.ApplicationSet{ 1158 ObjectMeta: metav1.ObjectMeta{ 1159 Name: "name", 1160 Namespace: "namespace", 1161 Annotations: map[string]string{ 1162 "kubectl.kubernetes.io/last-applied-configuration": `{ 1163 "spec":{ 1164 "generators":[ 1165 ] 1166 } 1167 }`, 1168 }, 1169 }, 1170 Spec: argoappsv1.ApplicationSetSpec{ 1171 Generators: []argoappsv1.ApplicationSetGenerator{ 1172 { 1173 List: nil, 1174 Clusters: nil, 1175 Git: nil, 1176 }, 1177 }, 1178 }, 1179 }, 1180 expectedInvalid: true, 1181 expectedNames: map[string]bool{}, 1182 }, 1183 { 1184 testName: "invalid generator, annotation with empty generator", 1185 appSet: argoappsv1.ApplicationSet{ 1186 ObjectMeta: metav1.ObjectMeta{ 1187 Name: "name", 1188 Namespace: "namespace", 1189 Annotations: map[string]string{ 1190 "kubectl.kubernetes.io/last-applied-configuration": `{ 1191 "spec":{ 1192 "generators":[ 1193 {} 1194 ] 1195 } 1196 }`, 1197 }, 1198 }, 1199 Spec: argoappsv1.ApplicationSetSpec{ 1200 Generators: []argoappsv1.ApplicationSetGenerator{ 1201 { 1202 List: nil, 1203 Clusters: nil, 1204 Git: nil, 1205 }, 1206 }, 1207 }, 1208 }, 1209 expectedInvalid: true, 1210 expectedNames: map[string]bool{}, 1211 }, 1212 } { 1213 hasInvalid, names := invalidGenerators(&c.appSet) 1214 assert.Equal(t, c.expectedInvalid, hasInvalid, c.testName) 1215 assert.Equal(t, c.expectedNames, names, c.testName) 1216 } 1217 } 1218 1219 func TestNormalizeBitbucketBasePath(t *testing.T) { 1220 for _, c := range []struct { 1221 testName string 1222 basePath string 1223 expectedBasePath string 1224 }{ 1225 { 1226 testName: "default api url", 1227 basePath: "https://company.bitbucket.com", 1228 expectedBasePath: "https://company.bitbucket.com/rest", 1229 }, 1230 { 1231 testName: "with /rest suffix", 1232 basePath: "https://company.bitbucket.com/rest", 1233 expectedBasePath: "https://company.bitbucket.com/rest", 1234 }, 1235 { 1236 testName: "with /rest/ suffix", 1237 basePath: "https://company.bitbucket.com/rest/", 1238 expectedBasePath: "https://company.bitbucket.com/rest", 1239 }, 1240 } { 1241 result := NormalizeBitbucketBasePath(c.basePath) 1242 assert.Equal(t, c.expectedBasePath, result, c.testName) 1243 } 1244 } 1245 1246 func TestSlugify(t *testing.T) { 1247 for _, c := range []struct { 1248 branch string 1249 smartTruncate bool 1250 length int 1251 expectedBasePath string 1252 }{ 1253 { 1254 branch: "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", 1255 smartTruncate: false, 1256 length: 50, 1257 expectedBasePath: "feat-a-really-long-pull-request-name-to-test-argo", 1258 }, 1259 { 1260 branch: "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", 1261 smartTruncate: true, 1262 length: 53, 1263 expectedBasePath: "feat-a-really-long-pull-request-name-to-test-argo", 1264 }, 1265 { 1266 branch: "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature", 1267 smartTruncate: true, 1268 length: 50, 1269 expectedBasePath: "feat", 1270 }, 1271 { 1272 branch: "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature", 1273 smartTruncate: false, 1274 length: 50, 1275 expectedBasePath: "feat-areallylongpullrequestnametotestargoslugifica", 1276 }, 1277 } { 1278 result := SlugifyName(c.length, c.smartTruncate, c.branch) 1279 assert.Equal(t, c.expectedBasePath, result, c.branch) 1280 } 1281 } 1282 1283 func TestGetTLSConfig(t *testing.T) { 1284 // certParsed, err := tls.X509KeyPair(test.Cert, test.PrivateKey) 1285 // require.NoError(t, err) 1286 1287 temppath := t.TempDir() 1288 cert := ` 1289 -----BEGIN CERTIFICATE----- 1290 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 1321 -----END CERTIFICATE----- 1322 ` 1323 1324 rootCAPath := path.Join(temppath, "foo.example.com") 1325 err := os.WriteFile(rootCAPath, []byte(cert), 0666) 1326 if err != nil { 1327 panic(err) 1328 } 1329 1330 certPool := x509.NewCertPool() 1331 ok := certPool.AppendCertsFromPEM([]byte(cert)) 1332 assert.True(t, ok) 1333 1334 testCases := []struct { 1335 name string 1336 scmRootCAPath string 1337 insecure bool 1338 validateCertInTlsConfig bool 1339 }{ 1340 { 1341 name: "Insecure mode configured, SCM Root CA Path not set", 1342 scmRootCAPath: "", 1343 insecure: true, 1344 validateCertInTlsConfig: false, 1345 }, 1346 { 1347 name: "SCM Root CA Path set, Insecure mode set to false", 1348 scmRootCAPath: rootCAPath, 1349 insecure: false, 1350 validateCertInTlsConfig: true, 1351 }, 1352 { 1353 name: "SCM Root CA Path set, Insecure mode set to true", 1354 scmRootCAPath: rootCAPath, 1355 insecure: true, 1356 validateCertInTlsConfig: true, 1357 }, 1358 } 1359 1360 for _, testCase := range testCases { 1361 t.Run(testCase.name, func(t *testing.T) { 1362 tlsConfig := GetTlsConfig(testCase.scmRootCAPath, testCase.insecure) 1363 assert.Equal(t, testCase.insecure, tlsConfig.InsecureSkipVerify) 1364 if testCase.validateCertInTlsConfig { 1365 assert.NotNil(t, tlsConfig) 1366 assert.True(t, tlsConfig.RootCAs.Equal(certPool)) 1367 } 1368 }) 1369 } 1370 }