github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/cd-service/pkg/mapper/environments_config_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 mapper 18 19 import ( 20 api "github.com/freiheit-com/kuberpult/pkg/api/v1" 21 "github.com/google/go-cmp/cmp/cmpopts" 22 23 "testing" 24 25 "github.com/freiheit-com/kuberpult/services/cd-service/pkg/config" 26 "github.com/google/go-cmp/cmp" 27 ) 28 29 func makeUpstreamLatest() *api.EnvironmentConfig_Upstream { 30 f := true 31 return &api.EnvironmentConfig_Upstream{ 32 Latest: &f, 33 } 34 } 35 36 func makeUpstreamEnvironment(env string) *api.EnvironmentConfig_Upstream { 37 return &api.EnvironmentConfig_Upstream{ 38 Environment: &env, 39 } 40 } 41 42 var nameStagingDe = "staging-de" 43 var nameOtherDe = "other-de" 44 var nameDevDe = "dev-de" 45 var nameCanaryDe = "canary-de" 46 var nameProdDe = "prod-de" 47 var nameWhoKnowsDe = "whoknows-de" 48 var nameTestDe = "test-de" 49 50 var nameStagingFr = "staging-fr" 51 var nameDevFr = "dev-fr" 52 var nameProdFr = "prod-fr" 53 var nameWhoKnowsFr = "whoknows-fr" 54 var nameTestFr = "test-fr" 55 56 var nameStagingUS = "staging-us" 57 58 var nameDevGlobal = "dev-global" 59 var nameTestGlobal = "test-global" 60 61 var nameStaging = "staging" 62 var nameDev = "dev" 63 var nameProd = "prod" 64 var nameWhoKnows = "whoknows" 65 var nameTest = "test" 66 var nameCanary = "canary" 67 68 func makeEnv(envName string, groupName string, upstream *api.EnvironmentConfig_Upstream, distanceToUpstream uint32, priority api.Priority) *api.Environment { 69 return &api.Environment{ 70 Name: envName, 71 Config: &api.EnvironmentConfig{ 72 Upstream: upstream, 73 EnvironmentGroup: &groupName, 74 }, 75 Locks: map[string]*api.Lock{}, 76 Applications: map[string]*api.Environment_Application{}, 77 DistanceToUpstream: distanceToUpstream, 78 Priority: priority, // we are 1 away from prod, hence pre-prod 79 } 80 } 81 82 func TestMapEnvironmentsToGroup(t *testing.T) { 83 tcs := []struct { 84 Name string 85 InputEnvs map[string]config.EnvironmentConfig 86 ExpectedResult []*api.EnvironmentGroup 87 }{ 88 { 89 Name: "One Environment is one Group", 90 InputEnvs: map[string]config.EnvironmentConfig{ 91 nameDevDe: { 92 Upstream: &config.EnvironmentConfigUpstream{ 93 Environment: "", 94 Latest: true, 95 }, 96 ArgoCd: nil, 97 EnvironmentGroup: &nameDevDe, 98 }, 99 }, 100 ExpectedResult: []*api.EnvironmentGroup{ 101 { 102 EnvironmentGroupName: nameDevDe, 103 Environments: []*api.Environment{ 104 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_YOLO), 105 }, 106 DistanceToUpstream: 0, 107 Priority: api.Priority_YOLO, 108 }, 109 }, 110 }, 111 { 112 Name: "Two Environments are two Groups", 113 InputEnvs: map[string]config.EnvironmentConfig{ 114 nameDevDe: { 115 Upstream: &config.EnvironmentConfigUpstream{ 116 Latest: true, 117 }, 118 ArgoCd: nil, 119 }, 120 nameStagingDe: { 121 Upstream: &config.EnvironmentConfigUpstream{ 122 Environment: nameDevDe, 123 }, 124 ArgoCd: nil, 125 }, 126 }, 127 ExpectedResult: []*api.EnvironmentGroup{ 128 { 129 EnvironmentGroupName: nameDevDe, 130 Environments: []*api.Environment{ 131 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 132 }, 133 DistanceToUpstream: 0, 134 Priority: api.Priority_UPSTREAM, 135 }, 136 { 137 EnvironmentGroupName: nameStagingDe, 138 Environments: []*api.Environment{ 139 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameDevDe), 1, api.Priority_PROD), 140 }, 141 DistanceToUpstream: 1, 142 Priority: api.Priority_PROD, 143 }, 144 }, 145 }, 146 { 147 // note that this is not a realistic example, we just want to make sure it does not crash! 148 // some outputs may be nonsensical (like distanceToUpstream), but that's fine as long as it's stable! 149 Name: "Two Environments with a loop", 150 InputEnvs: map[string]config.EnvironmentConfig{ 151 nameDevDe: { 152 Upstream: &config.EnvironmentConfigUpstream{ 153 Environment: nameStagingDe, 154 }, 155 ArgoCd: nil, 156 }, 157 nameStagingDe: { 158 Upstream: &config.EnvironmentConfigUpstream{ 159 Environment: nameDevDe, 160 }, 161 ArgoCd: nil, 162 }, 163 }, 164 ExpectedResult: []*api.EnvironmentGroup{ 165 { 166 EnvironmentGroupName: nameDevDe, 167 Environments: []*api.Environment{ 168 makeEnv(nameDevDe, nameDevDe, makeUpstreamEnvironment(nameStagingDe), 667, api.Priority_OTHER), 169 }, 170 DistanceToUpstream: 667, 171 Priority: api.Priority_CANARY, // set according to observed output, again, we just want to make sure it doesn't crash 172 }, 173 { 174 EnvironmentGroupName: nameStagingDe, 175 Environments: []*api.Environment{ 176 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameDevDe), 668, api.Priority_OTHER), 177 }, 178 Priority: api.Priority_PROD, // set according to observed output, again, we just want to make sure it doesn't crash 179 DistanceToUpstream: 668, 180 }, 181 }, 182 }, 183 { 184 // note that this is not a realistic example, we just want to make sure it does not crash! 185 // some outputs may be nonsensical (like distanceToUpstream), but that's fine as long as it's stable! 186 Name: "Two Environments with non exists upstream", 187 InputEnvs: map[string]config.EnvironmentConfig{ 188 nameDevDe: { 189 Upstream: &config.EnvironmentConfigUpstream{ 190 Latest: true, 191 }, 192 ArgoCd: nil, 193 }, 194 nameStagingDe: { 195 Upstream: &config.EnvironmentConfigUpstream{ 196 Environment: nameWhoKnows, 197 }, 198 ArgoCd: nil, 199 }, 200 }, 201 ExpectedResult: []*api.EnvironmentGroup{ 202 { 203 EnvironmentGroupName: nameDevDe, 204 Environments: []*api.Environment{ 205 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_YOLO), 206 }, 207 DistanceToUpstream: 0, 208 Priority: api.Priority_UPSTREAM, // set according to observed output, again, we just want to make sure it doesn't crash 209 }, 210 { 211 EnvironmentGroupName: nameStagingDe, 212 Environments: []*api.Environment{ 213 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameWhoKnows), 667, api.Priority_PROD), 214 }, 215 DistanceToUpstream: 667, 216 Priority: api.Priority_PROD, 217 }, 218 }, 219 }, 220 { 221 Name: "Three Environments are three Groups", 222 InputEnvs: map[string]config.EnvironmentConfig{ 223 nameDevDe: { 224 Upstream: &config.EnvironmentConfigUpstream{ 225 Latest: true, 226 }, 227 ArgoCd: nil, 228 }, 229 nameStagingDe: { 230 Upstream: &config.EnvironmentConfigUpstream{ 231 Environment: nameDevDe, 232 }, 233 ArgoCd: nil, 234 }, 235 nameProdDe: { 236 Upstream: &config.EnvironmentConfigUpstream{ 237 Environment: nameStagingDe, 238 }, 239 ArgoCd: nil, 240 }, 241 }, 242 ExpectedResult: []*api.EnvironmentGroup{ 243 { 244 EnvironmentGroupName: nameDevDe, 245 Environments: []*api.Environment{ 246 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 247 }, 248 DistanceToUpstream: 0, 249 Priority: api.Priority_UPSTREAM, 250 }, 251 { 252 EnvironmentGroupName: nameStagingDe, 253 Environments: []*api.Environment{ 254 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameDevDe), 1, api.Priority_PRE_PROD), 255 }, 256 DistanceToUpstream: 1, 257 Priority: api.Priority_PRE_PROD, 258 }, 259 { 260 EnvironmentGroupName: nameProdDe, 261 Environments: []*api.Environment{ 262 makeEnv(nameProdDe, nameProdDe, makeUpstreamEnvironment(nameStagingDe), 2, api.Priority_PROD), 263 }, 264 DistanceToUpstream: 2, 265 Priority: api.Priority_PROD, 266 }, 267 }, 268 }, 269 { 270 Name: "Four Environments in a row to ensure that Priority_UPSTREAM works", 271 InputEnvs: map[string]config.EnvironmentConfig{ 272 nameDevDe: { 273 Upstream: &config.EnvironmentConfigUpstream{ 274 Latest: true, 275 }, 276 }, 277 nameStagingDe: { 278 Upstream: &config.EnvironmentConfigUpstream{ 279 Environment: nameDevDe, 280 }, 281 }, 282 nameProdDe: { 283 Upstream: &config.EnvironmentConfigUpstream{ 284 Environment: nameStagingDe, 285 }, 286 }, 287 nameWhoKnowsDe: { 288 Upstream: &config.EnvironmentConfigUpstream{ 289 Environment: nameProdDe, 290 }, 291 }, 292 }, 293 ExpectedResult: []*api.EnvironmentGroup{ 294 { 295 EnvironmentGroupName: nameDevDe, 296 Environments: []*api.Environment{ 297 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 298 }, 299 DistanceToUpstream: 0, 300 Priority: api.Priority_UPSTREAM, 301 }, 302 { 303 EnvironmentGroupName: nameStagingDe, 304 Environments: []*api.Environment{ 305 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameDevDe), 1, api.Priority_PRE_PROD), 306 }, 307 DistanceToUpstream: 1, 308 Priority: api.Priority_PRE_PROD, 309 }, 310 { 311 EnvironmentGroupName: nameProdDe, 312 Environments: []*api.Environment{ 313 makeEnv(nameProdDe, nameProdDe, makeUpstreamEnvironment(nameStagingDe), 2, api.Priority_CANARY), 314 }, 315 DistanceToUpstream: 2, 316 Priority: api.Priority_CANARY, 317 }, 318 { 319 EnvironmentGroupName: nameWhoKnowsDe, 320 Environments: []*api.Environment{ 321 makeEnv(nameWhoKnowsDe, nameWhoKnowsDe, makeUpstreamEnvironment(nameProdDe), 3, api.Priority_PROD), 322 }, 323 DistanceToUpstream: 3, 324 Priority: api.Priority_PROD, 325 }, 326 }, 327 }, 328 { 329 Name: "five in a chain should be u->o->pp->c->p", 330 InputEnvs: map[string]config.EnvironmentConfig{ 331 nameDevDe: { 332 Upstream: &config.EnvironmentConfigUpstream{ 333 Latest: true, 334 }, 335 }, 336 nameOtherDe: { 337 Upstream: &config.EnvironmentConfigUpstream{ 338 Environment: nameDevDe, 339 }, 340 }, 341 nameStagingDe: { 342 Upstream: &config.EnvironmentConfigUpstream{ 343 Environment: nameOtherDe, 344 }, 345 }, 346 nameCanaryDe: { 347 Upstream: &config.EnvironmentConfigUpstream{ 348 Environment: nameStagingDe, 349 }, 350 }, 351 nameProdDe: { 352 Upstream: &config.EnvironmentConfigUpstream{ 353 Environment: nameCanaryDe, 354 }, 355 }, 356 }, 357 ExpectedResult: []*api.EnvironmentGroup{ 358 { 359 EnvironmentGroupName: nameDevDe, 360 Environments: []*api.Environment{ 361 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 362 }, 363 DistanceToUpstream: 0, 364 Priority: api.Priority_UPSTREAM, 365 }, 366 { 367 EnvironmentGroupName: nameOtherDe, 368 Environments: []*api.Environment{ 369 makeEnv(nameOtherDe, nameOtherDe, makeUpstreamEnvironment(nameDevDe), 1, api.Priority_OTHER), 370 }, 371 DistanceToUpstream: 1, 372 Priority: api.Priority_OTHER, 373 }, 374 { 375 EnvironmentGroupName: nameStagingDe, 376 Environments: []*api.Environment{ 377 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameOtherDe), 2, api.Priority_PRE_PROD), 378 }, 379 DistanceToUpstream: 2, 380 Priority: api.Priority_PRE_PROD, 381 }, 382 { 383 EnvironmentGroupName: nameCanaryDe, 384 Environments: []*api.Environment{ 385 makeEnv(nameCanaryDe, nameCanaryDe, makeUpstreamEnvironment(nameStagingDe), 3, api.Priority_CANARY), 386 }, 387 DistanceToUpstream: 3, 388 Priority: api.Priority_CANARY, 389 }, 390 { 391 EnvironmentGroupName: nameProdDe, 392 Environments: []*api.Environment{ 393 makeEnv(nameProdDe, nameProdDe, makeUpstreamEnvironment(nameCanaryDe), 4, api.Priority_PROD), 394 }, 395 DistanceToUpstream: 4, 396 Priority: api.Priority_PROD, 397 }, 398 }, 399 }, 400 { 401 Name: "Two chains of environments, one d->s->c->p and one d->s->p should have both p as prod and both s as staging", 402 InputEnvs: map[string]config.EnvironmentConfig{ 403 nameDevDe: { 404 Upstream: &config.EnvironmentConfigUpstream{ 405 Latest: true, 406 }, 407 }, 408 nameDevFr: { 409 Upstream: &config.EnvironmentConfigUpstream{ 410 Latest: true, 411 }, 412 }, 413 nameStagingDe: { 414 Upstream: &config.EnvironmentConfigUpstream{ 415 Environment: nameDevDe, 416 }, 417 }, 418 nameStagingFr: { 419 Upstream: &config.EnvironmentConfigUpstream{ 420 Environment: nameDevFr, 421 }, 422 }, 423 nameCanaryDe: { 424 Upstream: &config.EnvironmentConfigUpstream{ 425 Environment: nameStagingDe, 426 }, 427 }, 428 nameProdDe: { 429 Upstream: &config.EnvironmentConfigUpstream{ 430 Environment: nameCanaryDe, 431 }, 432 }, 433 nameProdFr: { 434 Upstream: &config.EnvironmentConfigUpstream{ 435 Environment: nameStagingFr, 436 }, 437 }, 438 }, 439 ExpectedResult: []*api.EnvironmentGroup{ 440 { 441 EnvironmentGroupName: nameDevDe, 442 Environments: []*api.Environment{ 443 makeEnv(nameDevDe, nameDevDe, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 444 }, 445 DistanceToUpstream: 0, 446 Priority: api.Priority_UPSTREAM, 447 }, 448 { 449 EnvironmentGroupName: nameDevFr, 450 Environments: []*api.Environment{ 451 makeEnv(nameDevFr, nameDevFr, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 452 }, 453 DistanceToUpstream: 0, 454 Priority: api.Priority_UPSTREAM, 455 }, 456 { 457 EnvironmentGroupName: nameStagingDe, 458 Environments: []*api.Environment{ 459 makeEnv(nameStagingDe, nameStagingDe, makeUpstreamEnvironment(nameDevDe), 1, api.Priority_PRE_PROD), 460 }, 461 DistanceToUpstream: 1, 462 Priority: api.Priority_PRE_PROD, 463 }, 464 { 465 EnvironmentGroupName: nameStagingFr, 466 Environments: []*api.Environment{ 467 makeEnv(nameStagingFr, nameStagingFr, makeUpstreamEnvironment(nameDevFr), 1, api.Priority_PRE_PROD), 468 }, 469 DistanceToUpstream: 1, 470 Priority: api.Priority_PRE_PROD, 471 }, 472 { 473 EnvironmentGroupName: nameCanaryDe, 474 Environments: []*api.Environment{ 475 makeEnv(nameCanaryDe, nameCanaryDe, makeUpstreamEnvironment(nameStagingDe), 2, api.Priority_CANARY), 476 }, 477 DistanceToUpstream: 2, 478 Priority: api.Priority_CANARY, 479 }, 480 { 481 EnvironmentGroupName: nameProdFr, 482 Environments: []*api.Environment{ 483 makeEnv(nameProdFr, nameProdFr, makeUpstreamEnvironment(nameStagingFr), 2, api.Priority_PROD), 484 }, 485 DistanceToUpstream: 2, 486 487 Priority: api.Priority_CANARY, 488 }, 489 { 490 EnvironmentGroupName: nameProdDe, 491 Environments: []*api.Environment{ 492 makeEnv(nameProdDe, nameProdDe, makeUpstreamEnvironment(nameCanaryDe), 3, api.Priority_PROD), 493 }, 494 DistanceToUpstream: 3, 495 Priority: api.Priority_PROD, 496 }, 497 }, 498 }, 499 { 500 // this is a realistic example 501 Name: "Three Groups with 2 envs each", 502 InputEnvs: map[string]config.EnvironmentConfig{ 503 nameDevDe: { 504 Upstream: &config.EnvironmentConfigUpstream{ 505 Latest: true, 506 }, 507 EnvironmentGroup: &nameDev, 508 }, 509 nameDevFr: { 510 Upstream: &config.EnvironmentConfigUpstream{ 511 Latest: true, 512 }, 513 EnvironmentGroup: &nameDev, 514 }, 515 nameStagingDe: { 516 Upstream: &config.EnvironmentConfigUpstream{ 517 Environment: nameDevDe, 518 }, 519 EnvironmentGroup: &nameStaging, 520 }, 521 nameStagingFr: { 522 Upstream: &config.EnvironmentConfigUpstream{ 523 Environment: nameDevFr, 524 }, 525 EnvironmentGroup: &nameStaging, 526 }, 527 nameProdDe: { 528 Upstream: &config.EnvironmentConfigUpstream{ 529 Environment: nameStagingDe, 530 }, 531 EnvironmentGroup: &nameProd, 532 }, 533 nameProdFr: { 534 Upstream: &config.EnvironmentConfigUpstream{ 535 Environment: nameStagingFr, 536 }, 537 EnvironmentGroup: &nameProd, 538 }, 539 }, 540 ExpectedResult: []*api.EnvironmentGroup{ 541 { 542 EnvironmentGroupName: nameDev, 543 Environments: []*api.Environment{ 544 makeEnv(nameDevDe, nameDev, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 545 makeEnv(nameDevFr, nameDev, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 546 }, 547 DistanceToUpstream: 0, 548 Priority: api.Priority_UPSTREAM, 549 }, 550 { 551 EnvironmentGroupName: nameStaging, 552 Environments: []*api.Environment{ 553 makeEnv(nameStagingDe, nameStaging, makeUpstreamEnvironment(nameDevDe), 1, api.Priority_PRE_PROD), 554 makeEnv(nameStagingFr, nameStaging, makeUpstreamEnvironment(nameDevFr), 1, api.Priority_PRE_PROD), 555 }, 556 DistanceToUpstream: 1, 557 Priority: api.Priority_PRE_PROD, 558 }, 559 { 560 EnvironmentGroupName: nameProd, 561 Environments: []*api.Environment{ 562 makeEnv(nameProdDe, nameProd, makeUpstreamEnvironment(nameStagingDe), 2, api.Priority_PROD), 563 makeEnv(nameProdFr, nameProd, makeUpstreamEnvironment(nameStagingFr), 2, api.Priority_PROD), 564 }, 565 DistanceToUpstream: 2, 566 Priority: api.Priority_PROD, 567 }, 568 }, 569 }, 570 { 571 Name: "Environments with different environment priorities", 572 /* 573 dev-global <--- test-global <--- staging-de <--- canary-de <--- prod-de 574 | 575 -- staging-fr <--- prod-fr 576 577 ^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^ 578 dev test staging canary prod 579 prio: u prio: o prio: pp prio: c prio: p 580 581 */ 582 InputEnvs: map[string]config.EnvironmentConfig{ 583 nameDevGlobal: { 584 Upstream: &config.EnvironmentConfigUpstream{ 585 Latest: true, 586 }, 587 EnvironmentGroup: &nameDev, 588 }, 589 nameTestGlobal: { 590 Upstream: &config.EnvironmentConfigUpstream{ 591 Environment: nameDevGlobal, 592 }, 593 EnvironmentGroup: &nameTest, 594 }, 595 nameStagingDe: { 596 Upstream: &config.EnvironmentConfigUpstream{ 597 Environment: nameTestGlobal, 598 }, 599 EnvironmentGroup: &nameStaging, 600 }, 601 nameStagingFr: { 602 Upstream: &config.EnvironmentConfigUpstream{ 603 Environment: nameTestGlobal, 604 }, 605 EnvironmentGroup: &nameStaging, 606 }, 607 nameCanaryDe: { 608 Upstream: &config.EnvironmentConfigUpstream{ 609 Environment: nameStagingDe, 610 }, 611 EnvironmentGroup: &nameCanary, 612 }, 613 nameProdDe: { 614 Upstream: &config.EnvironmentConfigUpstream{ 615 Environment: nameCanaryDe, 616 }, 617 EnvironmentGroup: &nameProd, 618 }, 619 nameProdFr: { 620 Upstream: &config.EnvironmentConfigUpstream{ 621 Environment: nameStagingFr, 622 }, 623 EnvironmentGroup: &nameCanary, 624 }, 625 }, 626 ExpectedResult: []*api.EnvironmentGroup{ 627 { 628 EnvironmentGroupName: nameDev, 629 Environments: []*api.Environment{ 630 makeEnv(nameDevGlobal, nameDev, makeUpstreamLatest(), 0, api.Priority_UPSTREAM), 631 }, 632 DistanceToUpstream: 0, 633 Priority: api.Priority_UPSTREAM, 634 }, 635 { 636 EnvironmentGroupName: nameTest, 637 Environments: []*api.Environment{ 638 makeEnv(nameTestGlobal, nameTest, makeUpstreamEnvironment(nameDevGlobal), 1, api.Priority_PRE_PROD), 639 }, 640 DistanceToUpstream: 1, 641 Priority: api.Priority_OTHER, 642 }, 643 { 644 EnvironmentGroupName: nameStaging, 645 Environments: []*api.Environment{ 646 makeEnv(nameStagingDe, nameStaging, makeUpstreamEnvironment(nameTestGlobal), 2, api.Priority_PRE_PROD), 647 makeEnv(nameStagingFr, nameStaging, makeUpstreamEnvironment(nameTestGlobal), 2, api.Priority_CANARY), 648 }, 649 DistanceToUpstream: 2, 650 Priority: api.Priority_PRE_PROD, 651 }, 652 { 653 EnvironmentGroupName: nameCanary, 654 Environments: []*api.Environment{ 655 makeEnv(nameCanaryDe, nameCanary, makeUpstreamEnvironment(nameStagingDe), 3, api.Priority_CANARY), 656 makeEnv(nameProdFr, nameCanary, makeUpstreamEnvironment(nameStagingFr), 3, api.Priority_PROD), 657 }, 658 DistanceToUpstream: 3, 659 Priority: api.Priority_CANARY, 660 }, 661 { 662 EnvironmentGroupName: nameProd, 663 Environments: []*api.Environment{ 664 makeEnv(nameProdDe, nameProd, makeUpstreamEnvironment(nameCanaryDe), 4, api.Priority_PROD), 665 }, 666 DistanceToUpstream: 4, 667 Priority: api.Priority_PROD, 668 }, 669 }, 670 }, 671 } 672 for _, tc := range tcs { 673 opts := cmpopts.IgnoreUnexported(api.EnvironmentGroup{}, api.Environment{}, api.EnvironmentConfig{}, api.EnvironmentConfig_Upstream{}) 674 t.Run(tc.Name, func(t *testing.T) { 675 actualResult := MapEnvironmentsToGroups(tc.InputEnvs) 676 if !cmp.Equal(tc.ExpectedResult, actualResult, opts) { 677 t.Fatal("Output mismatch (-want +got):\n", cmp.Diff(tc.ExpectedResult, actualResult, opts)) 678 } 679 }) 680 } 681 }