github.com/abayer/test-infra@v0.0.5/prow/plugins/updateconfig/updateconfig_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package updateconfig 18 19 import ( 20 "fmt" 21 "strings" 22 "testing" 23 24 "github.com/sirupsen/logrus" 25 "k8s.io/apimachinery/pkg/api/equality" 26 "k8s.io/apimachinery/pkg/util/diff" 27 28 "k8s.io/test-infra/prow/github" 29 "k8s.io/test-infra/prow/github/fakegithub" 30 "k8s.io/test-infra/prow/kube" 31 "k8s.io/test-infra/prow/plugins" 32 ) 33 34 const defaultNamespace = "default" 35 36 type fakeKubeClient struct { 37 maps map[string]kube.ConfigMap 38 updatedMaps []string 39 } 40 41 func (c *fakeKubeClient) GetConfigMap(name, namespace string) (kube.ConfigMap, error) { 42 return c.maps[name], nil 43 } 44 45 func (c *fakeKubeClient) ReplaceConfigMap(name string, config kube.ConfigMap) (kube.ConfigMap, error) { 46 if config.ObjectMeta.Name != name { 47 return kube.ConfigMap{}, fmt.Errorf("name %s does not match configmap name %s", name, config.ObjectMeta.Name) 48 } 49 if config.Namespace == "" { 50 config.Namespace = defaultNamespace 51 } 52 c.maps[name] = config 53 c.updatedMaps = append(c.updatedMaps, name) 54 return c.maps[name], nil 55 } 56 57 func TestUpdateConfig(t *testing.T) { 58 basicPR := github.PullRequest{ 59 Number: 1, 60 Base: github.PullRequestBranch{ 61 Repo: github.Repo{ 62 Owner: github.User{ 63 Login: "kubernetes", 64 }, 65 Name: "kubernetes", 66 }, 67 }, 68 User: github.User{ 69 Login: "foo", 70 }, 71 } 72 73 testcases := []struct { 74 name string 75 prAction github.PullRequestEventAction 76 merged bool 77 mergeCommit string 78 changes []github.PullRequestChange 79 existConfigMaps map[string]kube.ConfigMap 80 expectedConfigMaps map[string]kube.ConfigMap 81 }{ 82 { 83 name: "Opened PR, no update", 84 prAction: github.PullRequestActionOpened, 85 merged: false, 86 changes: []github.PullRequestChange{ 87 { 88 Filename: "prow/config.yaml", 89 Additions: 1, 90 }, 91 }, 92 existConfigMaps: map[string]kube.ConfigMap{}, 93 }, 94 { 95 name: "Opened PR, not merged, no update", 96 merged: false, 97 changes: []github.PullRequestChange{ 98 { 99 Filename: "prow/config.yaml", 100 Additions: 1, 101 }, 102 }, 103 existConfigMaps: map[string]kube.ConfigMap{}, 104 }, 105 { 106 name: "Closed PR, no prow changes, no update", 107 prAction: github.PullRequestActionClosed, 108 merged: false, 109 changes: []github.PullRequestChange{ 110 { 111 Filename: "foo.txt", 112 Additions: 1, 113 }, 114 }, 115 existConfigMaps: map[string]kube.ConfigMap{}, 116 }, 117 { 118 name: "For whatever reason no merge commit SHA", 119 prAction: github.PullRequestActionClosed, 120 merged: true, 121 changes: []github.PullRequestChange{ 122 { 123 Filename: "prow/config.yaml", 124 Additions: 1, 125 }, 126 }, 127 existConfigMaps: map[string]kube.ConfigMap{}, 128 }, 129 { 130 name: "changed config.yaml, 1 update", 131 prAction: github.PullRequestActionClosed, 132 merged: true, 133 mergeCommit: "12345", 134 changes: []github.PullRequestChange{ 135 { 136 Filename: "prow/config.yaml", 137 Additions: 1, 138 }, 139 }, 140 existConfigMaps: map[string]kube.ConfigMap{}, 141 expectedConfigMaps: map[string]kube.ConfigMap{ 142 "config": { 143 ObjectMeta: kube.ObjectMeta{ 144 Name: "config", 145 Namespace: defaultNamespace, 146 }, 147 Data: map[string]string{ 148 "config.yaml": "new-config", 149 }, 150 }, 151 }, 152 }, 153 { 154 name: "changed config.yaml, existed configmap, 1 update", 155 prAction: github.PullRequestActionClosed, 156 merged: true, 157 mergeCommit: "12345", 158 changes: []github.PullRequestChange{ 159 { 160 Filename: "prow/config.yaml", 161 Additions: 1, 162 }, 163 }, 164 existConfigMaps: map[string]kube.ConfigMap{ 165 "config": { 166 ObjectMeta: kube.ObjectMeta{ 167 Name: "config", 168 Namespace: defaultNamespace, 169 }, 170 Data: map[string]string{ 171 "config.yaml": "old-config", 172 }, 173 }, 174 }, 175 expectedConfigMaps: map[string]kube.ConfigMap{ 176 "config": { 177 ObjectMeta: kube.ObjectMeta{ 178 Name: "config", 179 Namespace: defaultNamespace, 180 }, 181 Data: map[string]string{ 182 "config.yaml": "new-config", 183 }, 184 }, 185 }, 186 }, 187 { 188 name: "changed plugins.yaml, 1 update with custom key", 189 prAction: github.PullRequestActionClosed, 190 merged: true, 191 mergeCommit: "12345", 192 changes: []github.PullRequestChange{ 193 { 194 Filename: "prow/plugins.yaml", 195 Additions: 1, 196 }, 197 }, 198 existConfigMaps: map[string]kube.ConfigMap{}, 199 expectedConfigMaps: map[string]kube.ConfigMap{ 200 "plugins": { 201 ObjectMeta: kube.ObjectMeta{ 202 Name: "plugins", 203 Namespace: defaultNamespace, 204 }, 205 Data: map[string]string{ 206 "test-key": "new-plugins", 207 }, 208 }, 209 }, 210 }, 211 { 212 name: "changed resources.yaml, 1 update with custom namespace", 213 prAction: github.PullRequestActionClosed, 214 merged: true, 215 mergeCommit: "12345", 216 changes: []github.PullRequestChange{ 217 { 218 Filename: "boskos/resources.yaml", 219 Additions: 1, 220 }, 221 }, 222 existConfigMaps: map[string]kube.ConfigMap{}, 223 expectedConfigMaps: map[string]kube.ConfigMap{ 224 "boskos-config": { 225 ObjectMeta: kube.ObjectMeta{ 226 Name: "boskos-config", 227 Namespace: "boskos", 228 }, 229 Data: map[string]string{ 230 "resources.yaml": "new-boskos-config", 231 }, 232 }, 233 }, 234 }, 235 { 236 name: "changed config.yaml, plugins.yaml and resources.yaml, 3 update", 237 prAction: github.PullRequestActionClosed, 238 merged: true, 239 mergeCommit: "12345", 240 changes: []github.PullRequestChange{ 241 { 242 Filename: "prow/plugins.yaml", 243 Additions: 1, 244 }, 245 { 246 Filename: "prow/config.yaml", 247 Additions: 1, 248 }, 249 { 250 Filename: "boskos/resources.yaml", 251 Additions: 1, 252 }, 253 }, 254 existConfigMaps: map[string]kube.ConfigMap{}, 255 expectedConfigMaps: map[string]kube.ConfigMap{ 256 "config": { 257 ObjectMeta: kube.ObjectMeta{ 258 Name: "config", 259 Namespace: defaultNamespace, 260 }, 261 Data: map[string]string{ 262 "config.yaml": "new-config", 263 }, 264 }, 265 "plugins": { 266 ObjectMeta: kube.ObjectMeta{ 267 Name: "plugins", 268 Namespace: defaultNamespace, 269 }, 270 Data: map[string]string{ 271 "test-key": "new-plugins", 272 }, 273 }, 274 "boskos-config": { 275 ObjectMeta: kube.ObjectMeta{ 276 Name: "boskos-config", 277 Namespace: "boskos", 278 }, 279 Data: map[string]string{ 280 "resources.yaml": "new-boskos-config", 281 }, 282 }, 283 }, 284 }, 285 { 286 name: "edited both config/foo.yaml and config/bar.yaml, 2 update", 287 prAction: github.PullRequestActionClosed, 288 merged: true, 289 mergeCommit: "12345", 290 changes: []github.PullRequestChange{ 291 { 292 Filename: "config/foo.yaml", 293 Additions: 1, 294 }, 295 { 296 Filename: "config/bar.yaml", 297 Additions: 1, 298 }, 299 }, 300 existConfigMaps: map[string]kube.ConfigMap{ 301 "multikey-config": { 302 ObjectMeta: kube.ObjectMeta{ 303 Name: "multikey-config", 304 Namespace: defaultNamespace, 305 }, 306 Data: map[string]string{ 307 "foo.yaml": "old-foo-config", 308 "bar.yaml": "old-bar-config", 309 }, 310 }, 311 }, 312 expectedConfigMaps: map[string]kube.ConfigMap{ 313 "multikey-config": { 314 ObjectMeta: kube.ObjectMeta{ 315 Name: "multikey-config", 316 Namespace: defaultNamespace, 317 }, 318 Data: map[string]string{ 319 "foo.yaml": "new-foo-config", 320 "bar.yaml": "new-bar-config", 321 }, 322 }, 323 }, 324 }, 325 { 326 name: "edited config/foo.yaml, 1 update", 327 prAction: github.PullRequestActionClosed, 328 merged: true, 329 mergeCommit: "12345", 330 changes: []github.PullRequestChange{ 331 { 332 Filename: "config/foo.yaml", 333 Status: "modified", 334 Additions: 1, 335 }, 336 }, 337 existConfigMaps: map[string]kube.ConfigMap{ 338 "unaffected-config": { 339 ObjectMeta: kube.ObjectMeta{ 340 Name: "unaffected-config", 341 Namespace: defaultNamespace, 342 }, 343 Data: map[string]string{ 344 "config.yaml": "old-config", 345 }, 346 }, 347 "multikey-config": { 348 ObjectMeta: kube.ObjectMeta{ 349 Name: "multikey-config", 350 Namespace: defaultNamespace, 351 }, 352 Data: map[string]string{ 353 "foo.yaml": "old-foo-config", 354 "bar.yaml": "old-bar-config", 355 }, 356 }, 357 }, 358 expectedConfigMaps: map[string]kube.ConfigMap{ 359 "unaffected-config": { 360 ObjectMeta: kube.ObjectMeta{ 361 Name: "unaffected-config", 362 Namespace: defaultNamespace, 363 }, 364 Data: map[string]string{ 365 "config.yaml": "old-config", 366 }, 367 }, 368 "multikey-config": { 369 ObjectMeta: kube.ObjectMeta{ 370 Name: "multikey-config", 371 Namespace: defaultNamespace, 372 }, 373 Data: map[string]string{ 374 "foo.yaml": "new-foo-config", 375 "bar.yaml": "old-bar-config", 376 }, 377 }, 378 }, 379 }, 380 { 381 name: "remove config/foo.yaml, 1 update", 382 prAction: github.PullRequestActionClosed, 383 merged: true, 384 mergeCommit: "12345", 385 changes: []github.PullRequestChange{ 386 { 387 Filename: "config/foo.yaml", 388 Status: "removed", 389 }, 390 }, 391 existConfigMaps: map[string]kube.ConfigMap{ 392 "multikey-config": { 393 ObjectMeta: kube.ObjectMeta{ 394 Name: "multikey-config", 395 Namespace: defaultNamespace, 396 }, 397 Data: map[string]string{ 398 "foo.yaml": "old-foo-config", 399 "bar.yaml": "old-bar-config", 400 }, 401 }, 402 }, 403 expectedConfigMaps: map[string]kube.ConfigMap{ 404 "multikey-config": { 405 ObjectMeta: kube.ObjectMeta{ 406 Name: "multikey-config", 407 Namespace: defaultNamespace, 408 }, 409 Data: map[string]string{ 410 "bar.yaml": "old-bar-config", 411 }, 412 }, 413 }, 414 }, 415 { 416 name: "edited dir/subdir/fejtaverse/krzyzacy.yaml, 1 update", 417 prAction: github.PullRequestActionClosed, 418 merged: true, 419 mergeCommit: "12345", 420 changes: []github.PullRequestChange{ 421 { 422 Filename: "dir/subdir/fejtaverse/krzyzacy.yaml", 423 Status: "modified", 424 Additions: 1, 425 }, 426 }, 427 existConfigMaps: map[string]kube.ConfigMap{ 428 "glob-config": { 429 ObjectMeta: kube.ObjectMeta{ 430 Name: "glob-config", 431 Namespace: defaultNamespace, 432 }, 433 Data: map[string]string{ 434 "fejta.yaml": "old-fejta-config", 435 "krzyzacy.yaml": "old-krzyzacy-config", 436 }, 437 }, 438 }, 439 expectedConfigMaps: map[string]kube.ConfigMap{ 440 "glob-config": { 441 ObjectMeta: kube.ObjectMeta{ 442 Name: "glob-config", 443 Namespace: defaultNamespace, 444 }, 445 Data: map[string]string{ 446 "fejta.yaml": "old-fejta-config", 447 "krzyzacy.yaml": "new-krzyzacy-config", 448 }, 449 }, 450 }, 451 }, 452 { 453 name: "add delete edit glob config, 3 update", 454 prAction: github.PullRequestActionClosed, 455 merged: true, 456 mergeCommit: "12345", 457 changes: []github.PullRequestChange{ 458 { 459 Filename: "dir/subdir/fejta.yaml", 460 Status: "modified", 461 Additions: 1, 462 }, 463 { 464 Filename: "dir/subdir/fejtaverse/sig-foo/added.yaml", 465 Status: "added", 466 Additions: 1, 467 }, 468 { 469 Filename: "dir/subdir/fejtaverse/sig-bar/removed.yaml", 470 Status: "removed", 471 }, 472 }, 473 existConfigMaps: map[string]kube.ConfigMap{ 474 "glob-config": { 475 ObjectMeta: kube.ObjectMeta{ 476 Name: "glob-config", 477 Namespace: defaultNamespace, 478 }, 479 Data: map[string]string{ 480 "fejta.yaml": "old-fejta-config", 481 "krzyzacy.yaml": "old-krzyzacy-config", 482 "removed.yaml": "old-removed-config", 483 }, 484 }, 485 }, 486 expectedConfigMaps: map[string]kube.ConfigMap{ 487 "glob-config": { 488 ObjectMeta: kube.ObjectMeta{ 489 Name: "glob-config", 490 Namespace: defaultNamespace, 491 }, 492 Data: map[string]string{ 493 "fejta.yaml": "new-fejta-config", 494 "krzyzacy.yaml": "old-krzyzacy-config", 495 "added.yaml": "new-added-config", 496 }, 497 }, 498 }, 499 }, 500 } 501 502 for _, tc := range testcases { 503 log := logrus.WithField("plugin", pluginName) 504 event := github.PullRequestEvent{ 505 Action: tc.prAction, 506 Number: basicPR.Number, 507 PullRequest: basicPR, 508 } 509 event.PullRequest.Merged = tc.merged 510 if tc.mergeCommit != "" { 511 event.PullRequest.MergeSHA = &tc.mergeCommit 512 } 513 514 fgc := &fakegithub.FakeClient{ 515 PullRequests: map[int]*github.PullRequest{ 516 basicPR.Number: &basicPR, 517 }, 518 PullRequestChanges: map[int][]github.PullRequestChange{ 519 basicPR.Number: tc.changes, 520 }, 521 IssueComments: map[int][]github.IssueComment{}, 522 RemoteFiles: map[string]map[string]string{ 523 "prow/config.yaml": { 524 "master": "old-config", 525 "12345": "new-config", 526 }, 527 "prow/plugins.yaml": { 528 "master": "old-plugins", 529 "12345": "new-plugins", 530 }, 531 "boskos/resources.yaml": { 532 "master": "old-boskos-config", 533 "12345": "new-boskos-config", 534 }, 535 "config/foo.yaml": { 536 "master": "old-foo-config", 537 "12345": "new-foo-config", 538 }, 539 "config/bar.yaml": { 540 "master": "old-bar-config", 541 "12345": "new-bar-config", 542 }, 543 "dir/subdir/fejta.yaml": { 544 "master": "old-fejta-config", 545 "12345": "new-fejta-config", 546 }, 547 "dir/subdir/fejtaverse/krzyzacy.yaml": { 548 "master": "old-krzyzacy-config", 549 "12345": "new-krzyzacy-config", 550 }, 551 "dir/subdir/fejtaverse/sig-foo/added.yaml": { 552 "12345": "new-added-config", 553 }, 554 "dir/subdir/fejtaverse/sig-bar/removed.yaml": { 555 "master": "old-removed-config", 556 }, 557 }, 558 } 559 fkc := &fakeKubeClient{ 560 maps: tc.existConfigMaps, 561 } 562 563 m := map[string]plugins.ConfigMapSpec{ 564 "prow/config.yaml": { 565 Name: "config", 566 }, 567 "prow/plugins.yaml": { 568 Name: "plugins", 569 Key: "test-key", 570 }, 571 "boskos/resources.yaml": { 572 Name: "boskos-config", 573 Namespace: "boskos", 574 }, 575 "config/foo.yaml": { 576 Name: "multikey-config", 577 }, 578 "config/bar.yaml": { 579 Name: "multikey-config", 580 }, 581 "dir/subdir/**/*.yaml": { 582 Name: "glob-config", 583 }, 584 } 585 586 if err := handle(fgc, fkc, log, event, m); err != nil { 587 t.Fatalf("tc: %s, err: %s", tc.name, err) 588 } 589 590 if tc.expectedConfigMaps != nil { 591 if len(fgc.IssueComments[basicPR.Number]) != 1 { 592 t.Fatalf("tc %s : Expect 1 comment, actually got %d", tc.name, len(fgc.IssueComments[basicPR.Number])) 593 } 594 595 comment := fgc.IssueComments[basicPR.Number][0].Body 596 if !strings.Contains(comment, "Updated the") { 597 t.Errorf("%s: missing Updated the from %s", tc.name, comment) 598 } 599 for configName := range tc.expectedConfigMaps { 600 found := false 601 for _, name := range fkc.updatedMaps { 602 if name == configName { 603 if !strings.Contains(comment, configName) { 604 t.Errorf("%s: missing %s from %s", tc.name, configName, comment) 605 } 606 found = true 607 } 608 } 609 610 if !found { 611 if strings.Contains(comment, configName) { 612 t.Errorf("%s: should not contain %s in %s", tc.name, configName, comment) 613 } 614 } 615 } 616 } 617 618 for _, name := range fkc.updatedMaps { 619 found := false 620 for expected := range tc.expectedConfigMaps { 621 if name == expected { 622 found = true 623 } 624 } 625 626 if !found { 627 t.Errorf("%s: should not update unexpected configmap %s", tc.name, name) 628 } 629 } 630 631 for configName := range tc.expectedConfigMaps { 632 if config, ok := fkc.maps[configName]; !ok { 633 t.Errorf("tc %s : Should have updated configmap for '%s'", tc.name, configName) 634 } else if expected, actual := tc.expectedConfigMaps[configName], config; !equality.Semantic.DeepEqual(expected, actual) { 635 t.Errorf("%s: incorrect ConfigMap state after update: %v", tc.name, diff.ObjectReflectDiff(expected, actual)) 636 } 637 } 638 } 639 }