github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/gerrit/client/client_test.go (about) 1 /* 2 Copyright 2018 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 client 18 19 import ( 20 "context" 21 "path/filepath" 22 "reflect" 23 "strings" 24 "sync" 25 "testing" 26 "time" 27 28 gerrit "github.com/andygrunwald/go-gerrit" 29 "github.com/google/go-cmp/cmp" 30 "github.com/sirupsen/logrus" 31 "k8s.io/apimachinery/pkg/util/sets" 32 "sigs.k8s.io/prow/pkg/config" 33 "sigs.k8s.io/prow/pkg/io" 34 ) 35 36 type fgc struct { 37 instance string 38 changes map[string][]gerrit.ChangeInfo 39 comments map[string]map[string][]gerrit.CommentInfo 40 } 41 42 func (f *fgc) GetRelatedChanges(changeID string, revisionID string) (*gerrit.RelatedChangesInfo, *gerrit.Response, error) { 43 return &gerrit.RelatedChangesInfo{}, nil, nil 44 } 45 46 func (f *fgc) ListChangeComments(id string) (*map[string][]gerrit.CommentInfo, *gerrit.Response, error) { 47 comments := map[string][]gerrit.CommentInfo{} 48 49 val, ok := f.comments[id] 50 if !ok { 51 return &comments, nil, nil 52 } 53 54 for path, retComments := range val { 55 comments[path] = append(comments[path], retComments...) 56 } 57 58 return &comments, nil, nil 59 } 60 61 func (f *fgc) SubmitChange(changeID string, input *gerrit.SubmitInput) (*ChangeInfo, *gerrit.Response, error) { 62 return nil, nil, nil 63 } 64 65 func TestApplyGlobalConfigOnce(t *testing.T) { 66 dir := t.TempDir() 67 path := filepath.Join(dir, "value.txt") 68 // Empty opener so *syncTime won't panic. 69 opener, err := io.NewOpener(context.Background(), "", "") 70 if err != nil { 71 t.Fatalf("Failed to create opener: %v", err) 72 } 73 74 // Fixed org/repo, as this test doesn't check the output. 75 cfg := config.Config{ 76 ProwConfig: config.ProwConfig{ 77 Gerrit: config.Gerrit{ 78 OrgReposConfig: &config.GerritOrgRepoConfigs{ 79 { 80 Org: "foo1", 81 Repos: []string{"bar1"}, 82 }, 83 }, 84 }, 85 }, 86 } 87 88 // A thread safe map for checking additionalFunc. 89 var mux sync.RWMutex 90 records := make(map[string]string) 91 setRecond := func(key, val string) { 92 mux.Lock() 93 defer mux.Unlock() 94 records[key] = val 95 } 96 getRecord := func(key string) string { 97 mux.RLock() 98 defer mux.RUnlock() 99 return records[key] 100 } 101 102 tests := []struct { 103 name string 104 orgRepoConfigGetter func() *config.GerritOrgRepoConfigs 105 lastSyncTracker *SyncTime 106 additionalFunc func() 107 expect func(t *testing.T) 108 }{ 109 { 110 name: "base", 111 orgRepoConfigGetter: func() *config.GerritOrgRepoConfigs { 112 return cfg.Gerrit.OrgReposConfig 113 }, 114 lastSyncTracker: NewSyncTime(path, opener, context.Background()), 115 additionalFunc: func() { 116 setRecond("base", "base") 117 }, 118 expect: func(t *testing.T) { 119 if got, want := getRecord("base"), "base"; got != want { 120 t.Fatalf("Output mismatch. Want: %s, got: %s", want, got) 121 } 122 }, 123 }, 124 { 125 name: "nil-lastsynctracker", 126 orgRepoConfigGetter: func() *config.GerritOrgRepoConfigs { 127 return cfg.Gerrit.OrgReposConfig 128 }, 129 additionalFunc: func() { 130 setRecond("nil-lastsynctracker", "nil-lastsynctracker") 131 }, 132 expect: func(t *testing.T) { 133 if got, want := getRecord("nil-lastsynctracker"), "nil-lastsynctracker"; got != want { 134 t.Fatalf("Output mismatch. Want: %s, got: %s", want, got) 135 } 136 }, 137 }, 138 { 139 name: "empty-addtionalfunc", 140 orgRepoConfigGetter: func() *config.GerritOrgRepoConfigs { 141 return cfg.Gerrit.OrgReposConfig 142 }, 143 additionalFunc: func() {}, 144 expect: func(t *testing.T) { 145 // additionalFunc is nil, there is nothing expected 146 }, 147 }, 148 { 149 name: "nil-addtionalfunc", 150 orgRepoConfigGetter: func() *config.GerritOrgRepoConfigs { 151 return cfg.Gerrit.OrgReposConfig 152 }, 153 additionalFunc: nil, 154 expect: func(t *testing.T) { 155 // additionalFunc is nil, there is nothing expected 156 }, 157 }, 158 } 159 160 for _, tc := range tests { 161 tc := tc 162 t.Run(tc.name, func(t *testing.T) { 163 fc := &Client{} 164 fc.applyGlobalConfigOnce(tc.orgRepoConfigGetter, tc.lastSyncTracker, "", "", tc.additionalFunc) 165 if tc.expect != nil { 166 tc.expect(t) 167 } 168 }) 169 } 170 } 171 172 func TestQueryStringsFromQueryFilter(t *testing.T) { 173 t.Parallel() 174 tests := []struct { 175 name string 176 filters *config.GerritQueryFilter 177 expected []string 178 }{ 179 { 180 name: "nil", 181 }, 182 { 183 name: "single-branch", 184 filters: &config.GerritQueryFilter{ 185 Branches: []string{"foo"}, 186 }, 187 expected: []string{"(branch:foo)"}, 188 }, 189 { 190 name: "multiple-branches", 191 filters: &config.GerritQueryFilter{ 192 Branches: []string{"foo1", "foo2", "foo3"}, 193 }, 194 expected: []string{"(branch:foo1+OR+branch:foo2+OR+branch:foo3)"}, 195 }, 196 { 197 name: "branches-and-excluded", 198 filters: &config.GerritQueryFilter{ 199 Branches: []string{"foo1", "foo2", "foo3"}, 200 ExcludedBranches: []string{"bar1", "bar2", "bar3"}, 201 }, 202 expected: []string{ 203 "(branch:foo1+OR+branch:foo2+OR+branch:foo3)", 204 "(-branch:bar1+AND+-branch:bar2+AND+-branch:bar3)", 205 }, 206 }, 207 } 208 209 for _, tc := range tests { 210 tc := tc 211 t.Run(tc.name, func(t *testing.T) { 212 t.Parallel() 213 if diff := cmp.Diff(tc.expected, queryStringsFromQueryFilter(tc.filters)); diff != "" { 214 t.Fatalf("Output mismatch. Want(-), got(+):\n%s", diff) 215 } 216 }) 217 } 218 } 219 220 func (f *fgc) QueryChanges(opt *gerrit.QueryChangeOptions) (*[]gerrit.ChangeInfo, *gerrit.Response, error) { 221 changes := []gerrit.ChangeInfo{} 222 223 changeInfos, ok := f.changes[f.instance] 224 if !ok { 225 return &changes, nil, nil 226 } 227 228 project := "" 229 for _, query := range opt.Query { 230 for _, q := range strings.Split(query, "+") { 231 if strings.HasPrefix(q, "project:") { 232 project = q[8:] 233 } 234 } 235 } 236 237 for idx, change := range changeInfos { 238 if idx >= opt.Start && len(changes) <= opt.Limit { 239 if project == change.Project { 240 changes = append(changes, change) 241 } 242 } 243 } 244 245 return &changes, nil, nil 246 } 247 248 func (f *fgc) SetReview(changeID, revisionID string, input *gerrit.ReviewInput) (*gerrit.ReviewResult, *gerrit.Response, error) { 249 return nil, nil, nil 250 } 251 252 func (f *fgc) GetChange(changeId string, opt *gerrit.ChangeOptions) (*ChangeInfo, *gerrit.Response, error) { 253 return nil, nil, nil 254 } 255 256 func makeStamp(t time.Time) gerrit.Timestamp { 257 return gerrit.Timestamp{Time: t} 258 } 259 260 func newStamp(t time.Time) *gerrit.Timestamp { 261 gt := makeStamp(t) 262 return > 263 } 264 265 func TestUpdateClients(t *testing.T) { 266 tests := []struct { 267 name string 268 existingInstances map[string]map[string]*config.GerritQueryFilter 269 newInstances map[string]map[string]*config.GerritQueryFilter 270 wantInstances map[string]map[string]*config.GerritQueryFilter 271 }{ 272 { 273 name: "normal", 274 existingInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar1": nil}}, 275 newInstances: map[string]map[string]*config.GerritQueryFilter{"foo2": {"bar2": nil}}, 276 wantInstances: map[string]map[string]*config.GerritQueryFilter{"foo2": {"bar2": nil}}, 277 }, 278 { 279 name: "same instance", 280 existingInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar1": nil}}, 281 newInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar2": nil}}, 282 wantInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar2": nil}}, 283 }, 284 { 285 name: "delete", 286 existingInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar1": nil}, "foo2": {"bar2": nil}}, 287 newInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar1": nil}}, 288 wantInstances: map[string]map[string]*config.GerritQueryFilter{"foo1": {"bar1": nil}}, 289 }, 290 } 291 292 for _, tc := range tests { 293 t.Run(tc.name, func(t *testing.T) { 294 client := &Client{ 295 handlers: make(map[string]*gerritInstanceHandler), 296 } 297 for instance, projects := range tc.existingInstances { 298 client.handlers[instance] = &gerritInstanceHandler{ 299 instance: instance, 300 projects: projects, 301 } 302 } 303 304 if err := client.UpdateClients(tc.newInstances); err != nil { 305 t.Fatal(err) 306 } 307 gotInstances := make(map[string]map[string]*config.GerritQueryFilter) 308 for instance, handler := range client.handlers { 309 gotInstances[instance] = handler.projects 310 } 311 if diff := cmp.Diff(tc.wantInstances, gotInstances); diff != "" { 312 t.Fatalf("mismatch. got(+), want(-):\n%s", diff) 313 } 314 }) 315 } 316 } 317 318 func TestDedupeIntoResult(t *testing.T) { 319 var testcases = []struct { 320 name string 321 input []gerrit.ChangeInfo 322 want []gerrit.ChangeInfo 323 }{ 324 { 325 name: "no changes", 326 input: []gerrit.ChangeInfo{}, 327 want: []gerrit.ChangeInfo{}, 328 }, 329 { 330 name: "no dupes", 331 input: []gerrit.ChangeInfo{ 332 { 333 Number: 1, 334 CurrentRevision: "1-1", 335 }, 336 { 337 Number: 2, 338 CurrentRevision: "2-1", 339 }, 340 }, 341 want: []gerrit.ChangeInfo{ 342 { 343 Number: 1, 344 CurrentRevision: "1-1", 345 }, 346 { 347 Number: 2, 348 CurrentRevision: "2-1", 349 }, 350 }, 351 }, 352 { 353 name: "single dupe", 354 input: []gerrit.ChangeInfo{ 355 { 356 Number: 1, 357 CurrentRevision: "1-1", 358 }, 359 { 360 Number: 2, 361 CurrentRevision: "2-1", 362 }, 363 { 364 Number: 1, 365 CurrentRevision: "1-2", 366 }, 367 }, 368 want: []gerrit.ChangeInfo{ 369 { 370 Number: 2, 371 CurrentRevision: "2-1", 372 }, 373 { 374 Number: 1, 375 CurrentRevision: "1-2", 376 }, 377 }, 378 }, 379 { 380 name: "many dupes", 381 input: []gerrit.ChangeInfo{ 382 { 383 Number: 1, 384 CurrentRevision: "1-1", 385 }, 386 { 387 Number: 2, 388 CurrentRevision: "2-1", 389 }, 390 { 391 Number: 1, 392 CurrentRevision: "1-2", 393 }, 394 { 395 Number: 2, 396 CurrentRevision: "2-2", 397 }, 398 { 399 Number: 1, 400 CurrentRevision: "1-3", 401 }, 402 { 403 Number: 1, 404 CurrentRevision: "1-4", 405 }, 406 { 407 Number: 3, 408 CurrentRevision: "3-1", 409 }, 410 }, 411 want: []gerrit.ChangeInfo{ 412 { 413 Number: 2, 414 CurrentRevision: "2-2", 415 }, 416 { 417 Number: 1, 418 CurrentRevision: "1-4", 419 }, 420 { 421 Number: 3, 422 CurrentRevision: "3-1", 423 }, 424 }, 425 }, 426 } 427 428 for _, tc := range testcases { 429 deduper := &deduper{ 430 result: []gerrit.ChangeInfo{}, 431 seenPos: make(map[int]int), 432 } 433 434 for _, ci := range tc.input { 435 deduper.dedupeIntoResult(ci) 436 } 437 438 if diff := cmp.Diff(tc.want, deduper.result); diff != "" { 439 t.Fatalf("Output mismatch. Want(-), got(+):\n%s", diff) 440 } 441 } 442 } 443 444 func TestQueryChange(t *testing.T) { 445 now := time.Now().UTC() 446 447 var testcases = []struct { 448 name string 449 lastUpdate map[string]time.Time 450 changes map[string][]gerrit.ChangeInfo 451 comments map[string]map[string][]gerrit.CommentInfo 452 // expected 453 revisions map[string][]string 454 messages map[string][]gerrit.ChangeMessageInfo 455 }{ 456 { 457 name: "no changes", 458 lastUpdate: map[string]time.Time{ 459 "bar": now.Add(-time.Minute), 460 }, 461 revisions: map[string][]string{}, 462 }, 463 { 464 name: "one outdated change", 465 lastUpdate: map[string]time.Time{ 466 "bar": now.Add(-time.Minute), 467 }, 468 changes: map[string][]gerrit.ChangeInfo{ 469 "foo": { 470 { 471 Project: "bar", 472 ID: "1", 473 Number: 1, 474 CurrentRevision: "1-1", 475 Updated: makeStamp(now.Add(-time.Hour)), 476 Revisions: map[string]gerrit.RevisionInfo{ 477 "1-1": { 478 Created: makeStamp(now.Add(-time.Hour)), 479 }, 480 }, 481 Status: "NEW", 482 }, 483 }, 484 }, 485 revisions: map[string][]string{}, 486 }, 487 { 488 name: "find comments in special patchset file", 489 lastUpdate: map[string]time.Time{ 490 "bar": now.Add(-time.Minute), 491 }, 492 changes: map[string][]gerrit.ChangeInfo{ 493 "foo": { 494 { 495 Project: "bar", 496 ID: "bar~branch~random-string", 497 Number: 1, 498 ChangeID: "random-string", 499 CurrentRevision: "1-1", 500 Updated: makeStamp(now), 501 Revisions: map[string]gerrit.RevisionInfo{ 502 "1-1": { 503 Created: makeStamp(now.Add(-time.Hour)), 504 Number: 1, 505 }, 506 }, 507 Status: "NEW", 508 Messages: []gerrit.ChangeMessageInfo{ 509 { 510 Date: makeStamp(now), 511 Message: "first", 512 RevisionNumber: 1, 513 }, 514 { 515 Date: makeStamp(now.Add(2 * time.Second)), 516 Message: "second", 517 RevisionNumber: 1, 518 }, 519 }, 520 }, 521 }, 522 }, 523 comments: map[string]map[string][]gerrit.CommentInfo{ 524 "bar~branch~random-string": { 525 "/PATCHSET_LEVEL": { 526 { 527 Message: "before", 528 Updated: newStamp(now.Add(-time.Second)), 529 PatchSet: 1, 530 }, 531 { 532 Message: "after", 533 Updated: newStamp(now.Add(time.Second)), 534 PatchSet: 1, 535 }, 536 }, 537 "random.yaml": { 538 { 539 Message: "ignore this file", 540 Updated: newStamp(now.Add(-time.Second)), 541 PatchSet: 1, 542 }, 543 }, 544 }, 545 }, 546 revisions: map[string][]string{"foo": {"1-1"}}, 547 messages: map[string][]gerrit.ChangeMessageInfo{ 548 "random-string": { 549 { 550 Date: makeStamp(now.Add(-time.Second)), 551 Message: "before", 552 RevisionNumber: 1, 553 }, 554 { 555 Date: makeStamp(now), 556 Message: "first", 557 RevisionNumber: 1, 558 }, 559 { 560 Date: makeStamp(now.Add(time.Second)), 561 Message: "after", 562 RevisionNumber: 1, 563 }, 564 { 565 Date: makeStamp(now.Add(2 * time.Second)), 566 Message: "second", 567 RevisionNumber: 1, 568 }, 569 }, 570 }, 571 }, 572 { 573 name: "one outdated change, but there's a new message", 574 lastUpdate: map[string]time.Time{ 575 "bar": now.Add(-time.Minute), 576 }, 577 changes: map[string][]gerrit.ChangeInfo{ 578 "foo": { 579 { 580 Project: "bar", 581 ID: "100", 582 Number: 100, 583 CurrentRevision: "1-1", 584 Updated: makeStamp(now), 585 Revisions: map[string]gerrit.RevisionInfo{ 586 "1-1": { 587 Created: makeStamp(now.Add(-time.Hour)), 588 Number: 1, 589 }, 590 }, 591 Status: "NEW", 592 Messages: []gerrit.ChangeMessageInfo{ 593 { 594 Date: makeStamp(now), 595 Message: "some message", 596 RevisionNumber: 1, 597 }, 598 }, 599 }, 600 }, 601 }, 602 revisions: map[string][]string{"foo": {"1-1"}}, 603 }, 604 { 605 name: "one up-to-date change", 606 lastUpdate: map[string]time.Time{ 607 "bar": now.Add(-time.Minute), 608 }, 609 changes: map[string][]gerrit.ChangeInfo{ 610 "foo": { 611 { 612 Project: "bar", 613 ID: "1", 614 Number: 1, 615 CurrentRevision: "1-1", 616 Updated: makeStamp(now), 617 Revisions: map[string]gerrit.RevisionInfo{ 618 "1-1": { 619 Created: makeStamp(now), 620 }, 621 }, 622 Status: "NEW", 623 }, 624 }, 625 }, 626 revisions: map[string][]string{ 627 "foo": {"1-1"}, 628 }, 629 }, 630 { 631 name: "one up-to-date change, same timestamp", 632 lastUpdate: map[string]time.Time{ 633 "bar": now.Add(-time.Minute), 634 }, 635 changes: map[string][]gerrit.ChangeInfo{ 636 "foo": { 637 { 638 Project: "bar", 639 ID: "1", 640 Number: 1, 641 CurrentRevision: "1-1", 642 Updated: makeStamp(now), 643 Revisions: map[string]gerrit.RevisionInfo{ 644 "1-1": { 645 Created: makeStamp(now), 646 }, 647 }, 648 Status: "NEW", 649 }, 650 }, 651 }, 652 revisions: map[string][]string{ 653 "foo": {"1-1"}, 654 }, 655 }, 656 { 657 name: "one up-to-date change but stale commit", 658 lastUpdate: map[string]time.Time{ 659 "bar": now.Add(-time.Minute), 660 }, 661 changes: map[string][]gerrit.ChangeInfo{ 662 "foo": { 663 { 664 Project: "bar", 665 ID: "1", 666 Number: 1, 667 CurrentRevision: "1-1", 668 Updated: makeStamp(now), 669 Revisions: map[string]gerrit.RevisionInfo{ 670 "1-1": { 671 Created: makeStamp(now.Add(-time.Hour)), 672 }, 673 }, 674 Status: "NEW", 675 }, 676 }, 677 }, 678 revisions: map[string][]string{}, 679 }, 680 { 681 name: "one up-to-date change, wrong instance", 682 lastUpdate: map[string]time.Time{ 683 "bar": now.Add(-time.Minute), 684 }, 685 changes: map[string][]gerrit.ChangeInfo{ 686 "evil": { 687 { 688 Project: "bar", 689 ID: "1", 690 Number: 1, 691 CurrentRevision: "1-1", 692 Updated: makeStamp(now), 693 Revisions: map[string]gerrit.RevisionInfo{ 694 "1-1": { 695 Created: makeStamp(now), 696 }, 697 }, 698 Status: "NEW", 699 }, 700 }, 701 }, 702 revisions: map[string][]string{}, 703 }, 704 { 705 name: "one up-to-date change, wrong project", 706 lastUpdate: map[string]time.Time{ 707 "bar": now.Add(-time.Minute), 708 }, 709 changes: map[string][]gerrit.ChangeInfo{ 710 "foo": { 711 { 712 Project: "evil", 713 ID: "1", 714 Number: 1, 715 CurrentRevision: "1-1", 716 Updated: makeStamp(now), 717 Revisions: map[string]gerrit.RevisionInfo{ 718 "1-1": { 719 Created: makeStamp(now), 720 }, 721 }, 722 Status: "NEW", 723 }, 724 }, 725 }, 726 revisions: map[string][]string{}, 727 }, 728 { 729 name: "two up-to-date changes, two projects", 730 lastUpdate: map[string]time.Time{ 731 "bar": now.Add(-time.Minute), 732 }, 733 changes: map[string][]gerrit.ChangeInfo{ 734 "foo": { 735 { 736 Project: "bar", 737 ID: "1", 738 Number: 1, 739 CurrentRevision: "1-1", 740 Updated: makeStamp(now), 741 Revisions: map[string]gerrit.RevisionInfo{ 742 "1-1": { 743 Created: makeStamp(now), 744 }, 745 }, 746 Status: "NEW", 747 }, 748 { 749 Project: "bar", 750 ID: "2", 751 Number: 2, 752 CurrentRevision: "2-1", 753 Updated: makeStamp(now), 754 Revisions: map[string]gerrit.RevisionInfo{ 755 "2-1": { 756 Created: makeStamp(now), 757 }, 758 }, 759 Status: "NEW", 760 }, 761 }, 762 }, 763 revisions: map[string][]string{ 764 "foo": {"1-1", "2-1"}, 765 }, 766 }, 767 { 768 name: "one good one bad", 769 lastUpdate: map[string]time.Time{ 770 "bar": now.Add(-time.Minute), 771 }, 772 changes: map[string][]gerrit.ChangeInfo{ 773 "foo": { 774 { 775 Project: "bar", 776 ID: "1", 777 Number: 1, 778 CurrentRevision: "1-1", 779 Updated: makeStamp(now), 780 Revisions: map[string]gerrit.RevisionInfo{ 781 "1-1": { 782 Created: makeStamp(now), 783 }, 784 }, 785 Status: "NEW", 786 }, 787 { 788 Project: "bar", 789 ID: "2", 790 Number: 2, 791 CurrentRevision: "2-1", 792 Updated: makeStamp(now.Add(-time.Hour)), 793 Revisions: map[string]gerrit.RevisionInfo{ 794 "2-1": { 795 Created: makeStamp(now.Add(-time.Hour)), 796 }, 797 }, 798 Status: "NEW", 799 }, 800 }, 801 }, 802 revisions: map[string][]string{ 803 "foo": {"1-1"}, 804 }, 805 }, 806 { 807 name: "multiple up-to-date changes", 808 lastUpdate: map[string]time.Time{ 809 "bar": now.Add(-time.Minute), 810 "boo": now.Add(-time.Minute), 811 }, 812 changes: map[string][]gerrit.ChangeInfo{ 813 "foo": { 814 { 815 Project: "bar", 816 ID: "1", 817 Number: 1, 818 CurrentRevision: "1-1", 819 Updated: makeStamp(now), 820 Revisions: map[string]gerrit.RevisionInfo{ 821 "1-1": { 822 Created: makeStamp(now), 823 }, 824 }, 825 Status: "NEW", 826 }, 827 { 828 Project: "bar", 829 ID: "2", 830 Number: 2, 831 CurrentRevision: "2-1", 832 Updated: makeStamp(now), 833 Revisions: map[string]gerrit.RevisionInfo{ 834 "2-1": { 835 Created: makeStamp(now), 836 }, 837 }, 838 Status: "NEW", 839 }, 840 }, 841 "baz": { 842 { 843 Project: "boo", 844 ID: "3", 845 Number: 3, 846 CurrentRevision: "3-2", 847 Updated: makeStamp(now), 848 Revisions: map[string]gerrit.RevisionInfo{ 849 "3-2": { 850 Created: makeStamp(now), 851 }, 852 "3-1": { 853 Created: makeStamp(now), 854 }, 855 }, 856 Status: "NEW", 857 }, 858 { 859 Project: "evil", 860 ID: "4", 861 Number: 4, 862 CurrentRevision: "4-1", 863 Updated: makeStamp(now.Add(-time.Hour)), 864 Revisions: map[string]gerrit.RevisionInfo{ 865 "4-1": { 866 Created: makeStamp(now.Add(-time.Hour)), 867 }, 868 }, 869 Status: "NEW", 870 }, 871 }, 872 }, 873 revisions: map[string][]string{ 874 "foo": {"1-1", "2-1"}, 875 "baz": {"3-2"}, 876 }, 877 }, 878 { 879 name: "one up-to-date merged change", 880 lastUpdate: map[string]time.Time{ 881 "bar": now.Add(-time.Minute), 882 }, 883 changes: map[string][]gerrit.ChangeInfo{ 884 "foo": { 885 { 886 Project: "bar", 887 ID: "1", 888 Number: 1, 889 CurrentRevision: "1-1", 890 Updated: makeStamp(now), 891 Submitted: newStamp(now), 892 Status: "MERGED", 893 }, 894 }, 895 }, 896 revisions: map[string][]string{ 897 "foo": {"1-1"}, 898 }, 899 }, 900 { 901 name: "one up-to-date abandoned change", 902 lastUpdate: map[string]time.Time{ 903 "bar": now.Add(-time.Minute), 904 }, 905 changes: map[string][]gerrit.ChangeInfo{ 906 "foo": { 907 { 908 Project: "bar", 909 ID: "1", 910 Number: 1, 911 CurrentRevision: "1-1", 912 Updated: makeStamp(now), 913 Submitted: newStamp(now), 914 Status: "ABANDONED", 915 }, 916 }, 917 }, 918 revisions: map[string][]string{}, 919 }, 920 { 921 name: "merged change recently updated but submitted before last update", 922 lastUpdate: map[string]time.Time{ 923 "bar": now.Add(-time.Minute), 924 }, 925 changes: map[string][]gerrit.ChangeInfo{ 926 "foo": { 927 { 928 Project: "bar", 929 ID: "1", 930 Number: 1, 931 CurrentRevision: "1-1", 932 Updated: makeStamp(now), 933 Submitted: newStamp(now.Add(-2 * time.Minute)), 934 Status: "MERGED", 935 }, 936 }, 937 }, 938 revisions: map[string][]string{}, 939 }, 940 { 941 name: "one abandoned, one merged", 942 lastUpdate: map[string]time.Time{ 943 "bar": now.Add(-time.Minute), 944 }, 945 changes: map[string][]gerrit.ChangeInfo{ 946 "foo": { 947 { 948 Project: "bar", 949 ID: "1", 950 Number: 1, 951 CurrentRevision: "1-1", 952 Updated: makeStamp(now), 953 Status: "ABANDONED", 954 }, 955 { 956 Project: "bar", 957 ID: "2", 958 CurrentRevision: "2-1", 959 Updated: makeStamp(now), 960 Submitted: newStamp(now), 961 Status: "MERGED", 962 }, 963 }, 964 }, 965 revisions: map[string][]string{ 966 "foo": {"2-1"}, 967 }, 968 }, 969 { 970 name: "merged change with new message, should ignore", 971 lastUpdate: map[string]time.Time{ 972 "bar": now.Add(-time.Minute), 973 }, 974 changes: map[string][]gerrit.ChangeInfo{ 975 "foo": { 976 { 977 Project: "bar", 978 ID: "2", 979 Number: 2, 980 CurrentRevision: "2-1", 981 Updated: makeStamp(now), 982 Submitted: newStamp(now.Add(-time.Hour)), 983 Status: "MERGED", 984 Messages: []gerrit.ChangeMessageInfo{ 985 { 986 Date: makeStamp(now), 987 Message: "some message", 988 RevisionNumber: 1, 989 }, 990 }, 991 }, 992 }, 993 }, 994 revisions: map[string][]string{}, 995 }, 996 { 997 name: "one up-to-date change found twice due to pagination. Duplicate should be removed", 998 lastUpdate: map[string]time.Time{ 999 "bar": now.Add(-time.Hour), 1000 }, 1001 changes: map[string][]gerrit.ChangeInfo{ 1002 "foo": { 1003 { 1004 Project: "bar", 1005 ID: "1", 1006 Number: 1, 1007 CurrentRevision: "1-1", 1008 Updated: makeStamp(now.Add(-time.Minute)), 1009 Revisions: map[string]gerrit.RevisionInfo{ 1010 "1-1": { 1011 Created: makeStamp(now.Add(-time.Minute)), 1012 }, 1013 }, 1014 Status: "NEW", 1015 }, 1016 { 1017 Project: "bar", 1018 ID: "2", 1019 Number: 2, 1020 CurrentRevision: "2-1", 1021 Updated: makeStamp(now.Add(-time.Minute)), 1022 Revisions: map[string]gerrit.RevisionInfo{ 1023 "2-1": { 1024 Created: makeStamp(now.Add(-time.Minute)), 1025 }, 1026 }, 1027 Status: "NEW", 1028 }, 1029 { 1030 Project: "bar", 1031 ID: "1", 1032 Number: 1, 1033 CurrentRevision: "1-2", 1034 Updated: makeStamp(now), 1035 Revisions: map[string]gerrit.RevisionInfo{ 1036 "1-1": { 1037 Created: makeStamp(now.Add(-time.Minute)), 1038 }, 1039 "1-2": { 1040 Created: makeStamp(now), 1041 }, 1042 }, 1043 Status: "NEW", 1044 }, 1045 }, 1046 }, 1047 revisions: map[string][]string{ 1048 "foo": {"2-1", "1-2"}, 1049 }, 1050 }, 1051 } 1052 1053 for _, tc := range testcases { 1054 client := &Client{ 1055 handlers: map[string]*gerritInstanceHandler{ 1056 "foo": { 1057 instance: "foo", 1058 projects: map[string]*config.GerritQueryFilter{"bar": nil}, 1059 changeService: &fgc{ 1060 changes: tc.changes, 1061 instance: "foo", 1062 comments: tc.comments, 1063 }, 1064 log: logrus.WithField("host", "foo"), 1065 }, 1066 "baz": { 1067 instance: "baz", 1068 projects: map[string]*config.GerritQueryFilter{"boo": nil}, 1069 changeService: &fgc{ 1070 changes: tc.changes, 1071 instance: "baz", 1072 }, 1073 log: logrus.WithField("host", "baz"), 1074 }, 1075 }, 1076 } 1077 1078 testLastSync := LastSyncState{"foo": tc.lastUpdate, "baz": tc.lastUpdate} 1079 changes := client.QueryChanges(testLastSync, 2) 1080 1081 revisions := map[string][]string{} 1082 messages := map[string][]gerrit.ChangeMessageInfo{} 1083 seen := sets.NewInt() 1084 for instance, changes := range changes { 1085 revisions[instance] = []string{} 1086 for _, change := range changes { 1087 if seen.Has(change.Number) { 1088 t.Errorf("Change number %d appears multiple times in the query results.", change.Number) 1089 } 1090 seen.Insert(change.Number) 1091 revisions[instance] = append(revisions[instance], change.CurrentRevision) 1092 messages[change.ChangeID] = append(messages[change.ChangeID], change.Messages...) 1093 } 1094 } 1095 1096 if !reflect.DeepEqual(revisions, tc.revisions) { 1097 t.Errorf("tc %s - wrong revisions: got %#v, expect %#v", tc.name, revisions, tc.revisions) 1098 } 1099 1100 if tc.messages != nil && !reflect.DeepEqual(messages, tc.messages) { 1101 t.Errorf("tc %s - wrong messages:\nhave %#v,\nwant %#v", tc.name, messages, tc.messages) 1102 } 1103 } 1104 }