github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/cd-service/pkg/argocd/render_test.go (about) 1 /*This file is part of kuberpult. 2 3 Kuberpult is free software: you can redistribute it and/or modify 4 it under the terms of the Expat(MIT) License as published by 5 the Free Software Foundation. 6 7 Kuberpult is distributed in the hope that it will be useful, 8 but WITHOUT ANY WARRANTY; without even the implied warranty of 9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 MIT License for more details. 11 12 You should have received a copy of the MIT License 13 along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>. 14 15 Copyright 2023 freiheit.com*/ 16 17 package argocd 18 19 import ( 20 "testing" 21 22 "github.com/freiheit-com/kuberpult/pkg/ptr" 23 "github.com/freiheit-com/kuberpult/services/cd-service/pkg/argocd/v1alpha1" 24 "github.com/freiheit-com/kuberpult/services/cd-service/pkg/config" 25 "github.com/google/go-cmp/cmp" 26 godebug "github.com/kylelemons/godebug/diff" 27 ) 28 29 func TestRender(t *testing.T) { 30 tcs := []struct { 31 Name string 32 Destination v1alpha1.ApplicationDestination 33 ExpectedResult string 34 }{ 35 { 36 Name: "deploy", 37 Destination: v1alpha1.ApplicationDestination{}, 38 ExpectedResult: `apiVersion: argoproj.io/v1alpha1 39 kind: Application 40 metadata: 41 annotations: 42 argocd.argoproj.io/manifest-generate-paths: /environments/dev/applications/app1/manifests 43 com.freiheit.kuberpult/application: app1 44 com.freiheit.kuberpult/environment: dev 45 com.freiheit.kuberpult/team: "" 46 finalizers: 47 - resources-finalizer.argocd.argoproj.io 48 labels: 49 com.freiheit.kuberpult/team: "" 50 name: dev-app1 51 spec: 52 destination: {} 53 ignoreDifferences: 54 - group: a.b 55 jqPathExpressions: 56 - c 57 - d 58 kind: bar 59 managedFieldsManagers: 60 - e 61 - f 62 name: foo 63 project: dev 64 source: 65 path: environments/dev/applications/app1/manifests 66 repoURL: example.com/github 67 targetRevision: main 68 syncPolicy: 69 automated: 70 allowEmpty: true 71 prune: true 72 selfHeal: true 73 syncOptions: 74 - ApplyOutOfSyncOnly=true 75 `, 76 }, 77 { 78 Name: "undeploy", 79 Destination: v1alpha1.ApplicationDestination{}, 80 ExpectedResult: `apiVersion: argoproj.io/v1alpha1 81 kind: Application 82 metadata: 83 annotations: 84 argocd.argoproj.io/manifest-generate-paths: /environments/dev/applications/app1/manifests 85 com.freiheit.kuberpult/application: app1 86 com.freiheit.kuberpult/environment: dev 87 com.freiheit.kuberpult/team: "" 88 finalizers: 89 - resources-finalizer.argocd.argoproj.io 90 labels: 91 com.freiheit.kuberpult/team: "" 92 name: dev-app1 93 spec: 94 destination: {} 95 ignoreDifferences: 96 - group: a.b 97 jqPathExpressions: 98 - c 99 - d 100 kind: bar 101 managedFieldsManagers: 102 - e 103 - f 104 name: foo 105 project: dev 106 source: 107 path: environments/dev/applications/app1/manifests 108 repoURL: example.com/github 109 targetRevision: main 110 syncPolicy: 111 automated: 112 allowEmpty: true 113 prune: true 114 selfHeal: true 115 syncOptions: 116 - ApplyOutOfSyncOnly=true 117 `, 118 }, 119 { 120 Name: "namespace test", 121 Destination: v1alpha1.ApplicationDestination{ 122 Namespace: "foo", 123 }, 124 ExpectedResult: `apiVersion: argoproj.io/v1alpha1 125 kind: Application 126 metadata: 127 annotations: 128 argocd.argoproj.io/manifest-generate-paths: /environments/dev/applications/app1/manifests 129 com.freiheit.kuberpult/application: app1 130 com.freiheit.kuberpult/environment: dev 131 com.freiheit.kuberpult/team: "" 132 finalizers: 133 - resources-finalizer.argocd.argoproj.io 134 labels: 135 com.freiheit.kuberpult/team: "" 136 name: dev-app1 137 spec: 138 destination: 139 namespace: foo 140 ignoreDifferences: 141 - group: a.b 142 jqPathExpressions: 143 - c 144 - d 145 kind: bar 146 managedFieldsManagers: 147 - e 148 - f 149 name: foo 150 project: dev 151 source: 152 path: environments/dev/applications/app1/manifests 153 repoURL: example.com/github 154 targetRevision: main 155 syncPolicy: 156 automated: 157 allowEmpty: true 158 prune: true 159 selfHeal: true 160 syncOptions: 161 - ApplyOutOfSyncOnly=true 162 `, 163 }, 164 } 165 for _, tc := range tcs { 166 tc := tc 167 t.Run(tc.Name, func(t *testing.T) { 168 t.Parallel() 169 var ( 170 annotations = map[string]string{} 171 ignoreDifferences = []v1alpha1.ResourceIgnoreDifferences{ 172 { 173 Group: "a.b", 174 Kind: "bar", 175 Name: "foo", 176 JqPathExpressions: []string{"c", "d"}, 177 ManagedFieldsManagers: []string{"e", "f"}, 178 }, 179 } 180 destination = tc.Destination 181 GitUrl = "example.com/github" 182 gitBranch = "main" 183 env = "dev" 184 appData = AppData{ 185 AppName: "app1", 186 } 187 syncOptions = []string{"ApplyOutOfSyncOnly=true"} 188 ) 189 190 actualResult, err := RenderAppEnv(GitUrl, gitBranch, annotations, env, appData, destination, ignoreDifferences, syncOptions) 191 if err != nil { 192 t.Fatal(err) 193 } 194 if actualResult != tc.ExpectedResult { 195 t.Fatalf("unexpected argocd manifest:\ndiff:\n%s\n\n", godebug.Diff(tc.ExpectedResult, actualResult)) 196 } 197 }) 198 } 199 } 200 201 func TestRenderV1Alpha1(t *testing.T) { 202 tests := []struct { 203 name string 204 config config.EnvironmentConfig 205 appData []AppData 206 want string 207 wantErr bool 208 }{ 209 { 210 name: "without sync window", 211 config: config.EnvironmentConfig{ 212 ArgoCd: &config.EnvironmentConfigArgoCd{ 213 SyncWindows: nil, 214 }, 215 }, 216 want: `apiVersion: argoproj.io/v1alpha1 217 kind: AppProject 218 metadata: 219 name: test-env 220 spec: 221 description: test-env 222 destinations: 223 - {} 224 sourceRepos: 225 - '*' 226 `, 227 }, 228 { 229 name: "with sync window without apps", 230 config: config.EnvironmentConfig{ 231 ArgoCd: &config.EnvironmentConfigArgoCd{ 232 SyncWindows: []config.ArgoCdSyncWindow{ 233 { 234 Schedule: "not a valid crontab entry", 235 Duration: "invalid duration", 236 Kind: "neither deny nor allow", 237 Apps: nil, 238 }, 239 }, 240 }, 241 }, 242 want: `apiVersion: argoproj.io/v1alpha1 243 kind: AppProject 244 metadata: 245 name: test-env 246 spec: 247 description: test-env 248 destinations: 249 - {} 250 sourceRepos: 251 - '*' 252 syncWindows: 253 - applications: 254 - '*' 255 duration: invalid duration 256 kind: neither deny nor allow 257 manualSync: true 258 schedule: not a valid crontab entry 259 `, 260 }, 261 { 262 name: "with sync window with apps", 263 config: config.EnvironmentConfig{ 264 ArgoCd: &config.EnvironmentConfigArgoCd{ 265 SyncWindows: []config.ArgoCdSyncWindow{ 266 { 267 Schedule: "not a valid crontab entry", 268 Duration: "invalid duration", 269 Kind: "neither deny nor allow", 270 Apps: []string{ 271 "app*", 272 }, 273 }, 274 }, 275 }, 276 }, 277 want: `apiVersion: argoproj.io/v1alpha1 278 kind: AppProject 279 metadata: 280 name: test-env 281 spec: 282 description: test-env 283 destinations: 284 - {} 285 sourceRepos: 286 - '*' 287 syncWindows: 288 - applications: 289 - app* 290 duration: invalid duration 291 kind: neither deny nor allow 292 manualSync: true 293 schedule: not a valid crontab entry 294 `, 295 }, 296 { 297 name: "namespace unset with app", 298 config: config.EnvironmentConfig{ 299 ArgoCd: &config.EnvironmentConfigArgoCd{ 300 Destination: config.ArgoCdDestination{ 301 Namespace: nil, 302 AppProjectNamespace: ptr.FromString("bar1"), 303 ApplicationNamespace: ptr.FromString("bar2"), 304 }, 305 }, 306 }, 307 appData: []AppData{ 308 { 309 AppName: "app1", 310 }, 311 }, 312 want: `apiVersion: argoproj.io/v1alpha1 313 kind: AppProject 314 metadata: 315 name: test-env 316 spec: 317 description: test-env 318 destinations: 319 - namespace: bar1 320 sourceRepos: 321 - '*' 322 --- 323 apiVersion: argoproj.io/v1alpha1 324 kind: Application 325 metadata: 326 annotations: 327 argocd.argoproj.io/manifest-generate-paths: /environments/test-env/applications/app1/manifests 328 com.freiheit.kuberpult/application: app1 329 com.freiheit.kuberpult/environment: test-env 330 com.freiheit.kuberpult/team: "" 331 finalizers: 332 - resources-finalizer.argocd.argoproj.io 333 labels: 334 com.freiheit.kuberpult/team: "" 335 name: test-env-app1 336 spec: 337 destination: 338 namespace: bar2 339 project: test-env 340 source: 341 path: environments/test-env/applications/app1/manifests 342 repoURL: https://git.example.com/ 343 targetRevision: branch-name 344 syncPolicy: 345 automated: 346 allowEmpty: true 347 prune: true 348 selfHeal: true 349 `, 350 }, 351 { 352 name: "only set namespace for appProject", 353 config: config.EnvironmentConfig{ 354 ArgoCd: &config.EnvironmentConfigArgoCd{ 355 Destination: config.ArgoCdDestination{ 356 Namespace: nil, 357 AppProjectNamespace: ptr.FromString("bar1"), 358 ApplicationNamespace: nil, 359 }, 360 }, 361 }, 362 appData: []AppData{ 363 { 364 AppName: "app1", 365 }, 366 }, 367 want: `apiVersion: argoproj.io/v1alpha1 368 kind: AppProject 369 metadata: 370 name: test-env 371 spec: 372 description: test-env 373 destinations: 374 - namespace: bar1 375 sourceRepos: 376 - '*' 377 --- 378 apiVersion: argoproj.io/v1alpha1 379 kind: Application 380 metadata: 381 annotations: 382 argocd.argoproj.io/manifest-generate-paths: /environments/test-env/applications/app1/manifests 383 com.freiheit.kuberpult/application: app1 384 com.freiheit.kuberpult/environment: test-env 385 com.freiheit.kuberpult/team: "" 386 finalizers: 387 - resources-finalizer.argocd.argoproj.io 388 labels: 389 com.freiheit.kuberpult/team: "" 390 name: test-env-app1 391 spec: 392 destination: {} 393 project: test-env 394 source: 395 path: environments/test-env/applications/app1/manifests 396 repoURL: https://git.example.com/ 397 targetRevision: branch-name 398 syncPolicy: 399 automated: 400 allowEmpty: true 401 prune: true 402 selfHeal: true 403 `, 404 }, 405 { 406 name: "namespace unset", 407 config: config.EnvironmentConfig{ 408 ArgoCd: &config.EnvironmentConfigArgoCd{ 409 Destination: config.ArgoCdDestination{ 410 Namespace: nil, 411 AppProjectNamespace: ptr.FromString("bar1"), 412 ApplicationNamespace: ptr.FromString("bar2"), 413 }, 414 }, 415 }, 416 want: `apiVersion: argoproj.io/v1alpha1 417 kind: AppProject 418 metadata: 419 name: test-env 420 spec: 421 description: test-env 422 destinations: 423 - namespace: bar1 424 sourceRepos: 425 - '*' 426 `, 427 }, 428 { 429 name: "namespace precedence", 430 config: config.EnvironmentConfig{ 431 ArgoCd: &config.EnvironmentConfigArgoCd{ 432 Destination: config.ArgoCdDestination{ 433 Namespace: ptr.FromString("foo"), 434 AppProjectNamespace: ptr.FromString("bar1"), 435 ApplicationNamespace: ptr.FromString("bar2"), 436 }, 437 }, 438 }, 439 want: `apiVersion: argoproj.io/v1alpha1 440 kind: AppProject 441 metadata: 442 name: test-env 443 spec: 444 description: test-env 445 destinations: 446 - namespace: foo 447 sourceRepos: 448 - '*' 449 `, 450 }, 451 { 452 name: "only namespace set", 453 config: config.EnvironmentConfig{ 454 ArgoCd: &config.EnvironmentConfigArgoCd{ 455 Destination: config.ArgoCdDestination{ 456 Namespace: ptr.FromString("foo"), 457 AppProjectNamespace: nil, 458 ApplicationNamespace: nil, 459 }, 460 }, 461 }, 462 want: `apiVersion: argoproj.io/v1alpha1 463 kind: AppProject 464 metadata: 465 name: test-env 466 spec: 467 description: test-env 468 destinations: 469 - namespace: foo 470 sourceRepos: 471 - '*' 472 `, 473 }, 474 { 475 name: "with team name", 476 config: config.EnvironmentConfig{ 477 ArgoCd: &config.EnvironmentConfigArgoCd{ 478 Destination: config.ArgoCdDestination{ 479 Namespace: nil, 480 AppProjectNamespace: ptr.FromString("bar1"), 481 ApplicationNamespace: nil, 482 }, 483 }, 484 }, 485 appData: []AppData{ 486 { 487 AppName: "app1", 488 TeamName: "some-team", 489 }, 490 }, 491 want: `apiVersion: argoproj.io/v1alpha1 492 kind: AppProject 493 metadata: 494 name: test-env 495 spec: 496 description: test-env 497 destinations: 498 - namespace: bar1 499 sourceRepos: 500 - '*' 501 --- 502 apiVersion: argoproj.io/v1alpha1 503 kind: Application 504 metadata: 505 annotations: 506 argocd.argoproj.io/manifest-generate-paths: /environments/test-env/applications/app1/manifests 507 com.freiheit.kuberpult/application: app1 508 com.freiheit.kuberpult/environment: test-env 509 com.freiheit.kuberpult/team: some-team 510 finalizers: 511 - resources-finalizer.argocd.argoproj.io 512 labels: 513 com.freiheit.kuberpult/team: some-team 514 name: test-env-app1 515 spec: 516 destination: {} 517 project: test-env 518 source: 519 path: environments/test-env/applications/app1/manifests 520 repoURL: https://git.example.com/ 521 targetRevision: branch-name 522 syncPolicy: 523 automated: 524 allowEmpty: true 525 prune: true 526 selfHeal: true 527 `, 528 }, 529 } 530 for _, tt := range tests { 531 t.Run(tt.name, func(t *testing.T) { 532 const ( 533 gitUrl = "https://git.example.com/" 534 gitBranch = "branch-name" 535 env = "test-env" 536 ) 537 got, err := RenderV1Alpha1(gitUrl, gitBranch, tt.config, env, tt.appData) 538 if (err != nil) != tt.wantErr { 539 t.Errorf("error = %v, wantErr %v", err, tt.wantErr) 540 return 541 } 542 if d := cmp.Diff(tt.want, string(got)); d != "" { 543 t.Errorf("mismatch: %s", d) 544 } 545 }) 546 } 547 }