github.com/abayer/test-infra@v0.0.5/mungegithub/github/github_test.go (about) 1 /* 2 Copyright 2015 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 github 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net/http" 23 "strconv" 24 "testing" 25 "time" 26 27 github_test "k8s.io/test-infra/mungegithub/github/testing" 28 29 "github.com/google/go-github/github" 30 ) 31 32 func timePtr(val time.Time) *time.Time { return &val } 33 func intPtr(val int) *int { return &val } 34 35 func TestHasLabel(t *testing.T) { 36 tests := []struct { 37 obj MungeObject 38 label string 39 hasLabel bool 40 }{ 41 { 42 obj: MungeObject{ 43 Issue: github_test.Issue("", 1, []string{"foo"}, true), 44 }, 45 label: "foo", 46 hasLabel: true, 47 }, 48 { 49 obj: MungeObject{ 50 Issue: github_test.Issue("", 1, []string{"bar"}, true), 51 }, 52 label: "foo", 53 hasLabel: false, 54 }, 55 { 56 obj: MungeObject{ 57 Issue: github_test.Issue("", 1, []string{"bar", "foo"}, true), 58 }, 59 label: "foo", 60 hasLabel: true, 61 }, 62 { 63 obj: MungeObject{ 64 Issue: github_test.Issue("", 1, []string{"bar", "baz"}, true), 65 }, 66 label: "foo", 67 hasLabel: false, 68 }, 69 } 70 71 for _, test := range tests { 72 if test.hasLabel != test.obj.HasLabel(test.label) { 73 t.Errorf("Unexpected output: %v", test) 74 } 75 } 76 } 77 78 func TestHasLabels(t *testing.T) { 79 tests := []struct { 80 obj MungeObject 81 seekLabels []string 82 hasLabel bool 83 }{ 84 { 85 obj: MungeObject{ 86 Issue: github_test.Issue("", 1, []string{"foo"}, true), 87 }, 88 seekLabels: []string{"foo"}, 89 hasLabel: true, 90 }, 91 { 92 obj: MungeObject{ 93 Issue: github_test.Issue("", 1, []string{"bar"}, true), 94 }, 95 seekLabels: []string{"foo"}, 96 hasLabel: false, 97 }, 98 { 99 obj: MungeObject{ 100 Issue: github_test.Issue("", 1, []string{"bar", "foo"}, true), 101 }, 102 seekLabels: []string{"foo"}, 103 hasLabel: true, 104 }, 105 { 106 obj: MungeObject{ 107 Issue: github_test.Issue("", 1, []string{"bar", "baz"}, true), 108 }, 109 seekLabels: []string{"foo"}, 110 hasLabel: false, 111 }, 112 { 113 obj: MungeObject{ 114 Issue: github_test.Issue("", 1, []string{"foo"}, true), 115 }, 116 seekLabels: []string{"foo", "bar"}, 117 hasLabel: false, 118 }, 119 } 120 121 for _, test := range tests { 122 if test.hasLabel != test.obj.HasLabels(test.seekLabels) { 123 t.Errorf("Unexpected output: %v", test) 124 } 125 } 126 } 127 128 func TestForEachIssueDo(t *testing.T) { 129 issue1 := github_test.Issue("bob", 1, nil, true) 130 issue5 := github_test.Issue("bob", 5, nil, true) 131 issue6 := github_test.Issue("bob", 6, nil, true) 132 issue7 := github_test.Issue("bob", 7, nil, true) 133 issue20 := github_test.Issue("bob", 20, nil, true) 134 135 user := github.User{Login: stringPtr("bob")} 136 tests := []struct { 137 Issues [][]github.Issue 138 Pages []int 139 ValidIssues int 140 }{ 141 { 142 Issues: [][]github.Issue{ 143 {*issue5}, 144 }, 145 Pages: []int{0}, 146 ValidIssues: 1, 147 }, 148 { 149 Issues: [][]github.Issue{ 150 {*issue5}, 151 {*issue6}, 152 {*issue7}, 153 { 154 { 155 Number: intPtr(8), 156 // no User, invalid 157 }, 158 }, 159 }, 160 Pages: []int{4, 4, 4, 0}, 161 ValidIssues: 3, 162 }, 163 { 164 Issues: [][]github.Issue{ 165 // Invalid 1 < MinPRNumber 166 // Invalid 20 > MaxPRNumber 167 {*issue1, *issue20}, 168 // two valid issues 169 {*issue5, *issue6}, 170 { 171 { 172 // no Number, invalid 173 User: &user, 174 }, 175 }, 176 }, 177 Pages: []int{3, 3, 0}, 178 ValidIssues: 2, 179 }, 180 } 181 182 for i, test := range tests { 183 client, server, mux := github_test.InitServer(t, nil, nil, nil, nil, nil, nil, nil) 184 config := &Config{ 185 client: client, 186 Org: "foo", 187 Project: "bar", 188 MinPRNumber: 5, 189 MaxPRNumber: 15, 190 } 191 count := 0 192 mux.HandleFunc("/repos/foo/bar/issues", func(w http.ResponseWriter, r *http.Request) { 193 if r.Method != "GET" { 194 t.Errorf("Unexpected method: %s", r.Method) 195 } 196 // this means page 0, return page 1 197 page := r.URL.Query().Get("page") 198 if page == "" { 199 t.Errorf("Should not get page 0, start with page 1") 200 } 201 if page != strconv.Itoa(count+1) { 202 t.Errorf("Unexpected page: %s", r.URL.Query().Get("page")) 203 } 204 if r.URL.Query().Get("sort") != "created" { 205 t.Errorf("Unexpected sort: %s", r.URL.Query().Get("sort")) 206 } 207 if r.URL.Query().Get("per_page") != "100" { 208 t.Errorf("Unexpected per_page: %s", r.URL.Query().Get("per_page")) 209 } 210 w.Header().Add("Link", 211 fmt.Sprintf("<https://api.github.com/?page=%d>; rel=\"last\"", test.Pages[count])) 212 w.WriteHeader(http.StatusOK) 213 data, err := json.Marshal(test.Issues[count]) 214 if err != nil { 215 t.Errorf("Unexpected error: %v", err) 216 } 217 218 w.Write(data) 219 count++ 220 }) 221 objects := []*MungeObject{} 222 handle := func(obj *MungeObject) error { 223 objects = append(objects, obj) 224 return nil 225 } 226 err := config.ForEachIssueDo(handle) 227 if err != nil { 228 t.Errorf("unexpected error: %v", err) 229 } 230 if len(objects) != test.ValidIssues { 231 t.Errorf("Test: %d Unexpected output %d vs %d", i, len(objects), test.ValidIssues) 232 } 233 234 if count != len(test.Issues) { 235 t.Errorf("Test: %d Unexpected number of fetches: %d", i, count) 236 } 237 server.Close() 238 } 239 } 240 241 func TestComputeStatus(t *testing.T) { 242 contextS := []string{"context"} 243 otherS := []string{"other context"} 244 bothS := []string{"context", "other context"} 245 firstS := []string{"context", "crap"} 246 247 tests := []struct { 248 combinedStatus *github.CombinedStatus 249 requiredContexts []string 250 expected string 251 }{ 252 // test no context specified 253 { 254 combinedStatus: github_test.Status("mysha", nil, nil, nil, nil), 255 expected: "success", 256 }, 257 { 258 combinedStatus: &github.CombinedStatus{ 259 State: stringPtr("pending"), 260 SHA: stringPtr("mysha"), 261 }, 262 expected: "pending", 263 }, 264 { 265 combinedStatus: &github.CombinedStatus{ 266 State: stringPtr("failure"), 267 SHA: stringPtr("mysha"), 268 }, 269 expected: "failure", 270 }, 271 { 272 combinedStatus: &github.CombinedStatus{ 273 State: stringPtr("error"), 274 SHA: stringPtr("mysha"), 275 }, 276 expected: "error", 277 }, 278 // test missing subcontext requested but missing 279 { 280 combinedStatus: github_test.Status("mysha", otherS, nil, nil, nil), 281 requiredContexts: contextS, 282 expected: "incomplete", 283 }, 284 { 285 combinedStatus: github_test.Status("mysha", nil, otherS, nil, nil), 286 requiredContexts: contextS, 287 expected: "incomplete", 288 }, 289 { 290 combinedStatus: github_test.Status("mysha", nil, nil, otherS, nil), 291 requiredContexts: contextS, 292 expected: "incomplete", 293 }, 294 { 295 combinedStatus: github_test.Status("mysha", nil, nil, nil, otherS), 296 requiredContexts: contextS, 297 expected: "incomplete", 298 }, 299 // test subcontext present and requested 300 { 301 combinedStatus: github_test.Status("mysha", contextS, nil, nil, nil), 302 requiredContexts: contextS, 303 expected: "success", 304 }, 305 { 306 combinedStatus: github_test.Status("mysha", nil, nil, contextS, nil), 307 requiredContexts: contextS, 308 expected: "pending", 309 }, 310 { 311 combinedStatus: github_test.Status("mysha", nil, nil, nil, contextS), 312 requiredContexts: contextS, 313 expected: "error", 314 }, 315 { 316 combinedStatus: github_test.Status("mysha", nil, contextS, nil, nil), 317 requiredContexts: contextS, 318 expected: "failure", 319 }, 320 // test failed PR but the one we care about is passed 321 { 322 combinedStatus: github_test.Status("mysha", contextS, otherS, nil, nil), 323 requiredContexts: contextS, 324 expected: "success", 325 }, 326 // test failed because we need both, but one is failed 327 { 328 combinedStatus: github_test.Status("mysha", contextS, otherS, nil, nil), 329 requiredContexts: bothS, 330 expected: "failure", 331 }, 332 // test failed because we need both, bot one isn't present 333 { 334 combinedStatus: github_test.Status("mysha", firstS, nil, nil, nil), 335 requiredContexts: bothS, 336 expected: "incomplete", 337 }, 338 } 339 340 for _, test := range tests { 341 // ease of use, reduce boilerplate in test cases 342 if test.requiredContexts == nil { 343 test.requiredContexts = []string{} 344 } 345 status := computeStatus(test.combinedStatus, test.requiredContexts) 346 if test.expected != status { 347 t.Errorf("expected: %s, saw %s for %v", test.expected, status, test.combinedStatus) 348 } 349 } 350 } 351 352 func TestGetLastModified(t *testing.T) { 353 tests := []struct { 354 commits []*github.RepositoryCommit 355 expectedTime *time.Time 356 }{ 357 { 358 commits: github_test.Commits(1, 10), 359 expectedTime: timePtr(time.Unix(10, 0)), 360 }, 361 { 362 // remember the order of github_test.Commits() is non-deterministic 363 commits: github_test.Commits(3, 10), 364 expectedTime: timePtr(time.Unix(12, 0)), 365 }, 366 { 367 // so this is probably not quite the same test... 368 commits: github_test.Commits(3, 8), 369 expectedTime: timePtr(time.Unix(10, 0)), 370 }, 371 { 372 // We can't represent the same time in 2 commits using github_test.Commits() 373 commits: []*github.RepositoryCommit{ 374 { 375 SHA: stringPtr("mysha1"), 376 Commit: &github.Commit{ 377 SHA: stringPtr("mysha1"), 378 Committer: &github.CommitAuthor{ 379 Date: timePtr(time.Unix(9, 0)), 380 }, 381 }, 382 }, 383 { 384 SHA: stringPtr("mysha2"), 385 Commit: &github.Commit{ 386 SHA: stringPtr("mysha2"), 387 Committer: &github.CommitAuthor{ 388 Date: timePtr(time.Unix(10, 0)), 389 }, 390 }, 391 }, 392 { 393 SHA: stringPtr("mysha3"), 394 Commit: &github.Commit{ 395 SHA: stringPtr("mysha3"), 396 Committer: &github.CommitAuthor{ 397 Date: timePtr(time.Unix(9, 0)), 398 }, 399 }, 400 }, 401 }, 402 expectedTime: timePtr(time.Unix(10, 0)), 403 }, 404 } 405 for _, test := range tests { 406 client, server, _ := github_test.InitServer(t, nil, nil, nil, test.commits, nil, nil, nil) 407 config := &Config{ 408 client: client, 409 Org: "o", 410 Project: "r", 411 } 412 413 obj := &MungeObject{ 414 config: config, 415 Issue: github_test.Issue("bob", 1, nil, true), 416 } 417 ts, ok := obj.LastModifiedTime() 418 if !ok || !ts.Equal(*test.expectedTime) { 419 t.Errorf("expected: %v, saw: %v for: %v", test.expectedTime, ts, test) 420 } 421 server.Close() 422 } 423 } 424 425 func TestRemoveLabel(t *testing.T) { 426 tests := []struct { 427 issue *github.Issue 428 remove string 429 expected []string 430 }{ 431 { 432 issue: github_test.Issue("", 1, []string{"label1"}, false), 433 remove: "label1", 434 expected: []string{}, 435 }, 436 { 437 issue: github_test.Issue("", 1, []string{"label2", "label1"}, false), 438 remove: "label1", 439 expected: []string{"label2"}, 440 }, 441 { 442 issue: github_test.Issue("", 1, []string{"label2"}, false), 443 remove: "label1", 444 expected: []string{"label2"}, 445 }, 446 { 447 issue: github_test.Issue("", 1, []string{}, false), 448 remove: "label1", 449 expected: []string{}, 450 }, 451 } 452 for testNum, test := range tests { 453 client, server, mux := github_test.InitServer(t, test.issue, nil, nil, nil, nil, nil, nil) 454 config := &Config{ 455 client: client, 456 Org: "o", 457 Project: "r", 458 } 459 mux.HandleFunc(fmt.Sprintf("/repos/o/r/issues/1/labels/%s", test.remove), func(w http.ResponseWriter, r *http.Request) { 460 w.WriteHeader(http.StatusOK) 461 }) 462 463 obj, err := config.GetObject(*test.issue.Number) 464 if err != nil { 465 t.Fatalf("%d: unable to get issue: %v", testNum, *test.issue.Number) 466 } 467 obj.RemoveLabel(test.remove) 468 if len(test.expected) != len(obj.Issue.Labels) { 469 t.Errorf("%d: len(labels) not equal, expected labels: %v but got labels: %v", testNum, test.expected, obj.Issue.Labels) 470 return 471 } 472 for i, l := range test.expected { 473 if l != *obj.Issue.Labels[i].Name { 474 t.Errorf("%d: expected labels: %v but got labels: %v", testNum, test.expected, obj.Issue.Labels) 475 } 476 } 477 server.Close() 478 } 479 } 480 481 func TestPRGetFixesList(t *testing.T) { 482 tests := []struct { 483 issue *github.Issue 484 body string 485 expected []int 486 }{ 487 { 488 issue: github_test.Issue("", 1, []string{"label1"}, false), 489 body: `bla resolve 490 this pr closes #45545 and also fixes #679 491 bla, some more bla with close here and there. 492 some suggest that it resolved #5643`, 493 expected: []int{45545, 679, 5643}, 494 }, 495 { 496 issue: github_test.Issue("", 2, []string{"label1"}, false), 497 body: `bla resolve 345 498 some suggest that it also closes #892`, 499 expected: []int{892}, 500 }, 501 { 502 issue: github_test.Issue("", 3, []string{"label1"}, false), 503 body: `bla resolve 504 this pr closes and fixes nothing`, 505 expected: nil, 506 }, 507 { 508 issue: github_test.Issue("", 4, []string{"label1"}, false), 509 body: `bla bla 510 this pr Fixes #23 and FIXES #45 but not fixxx #99`, 511 expected: []int{23, 45}, 512 }, 513 } 514 for testNum, test := range tests { 515 client, server, _ := github_test.InitServer(t, test.issue, nil, nil, nil, nil, nil, nil) 516 config := &Config{ 517 client: client, 518 Org: "o", 519 Project: "r", 520 } 521 522 obj, err := config.GetObject(*test.issue.Number) 523 if err != nil { 524 t.Fatalf("%d: unable to get issue: %v", testNum, *test.issue.Number) 525 } 526 obj.Issue.Body = &test.body 527 fixes := obj.GetPRFixesList() 528 if len(test.expected) != len(fixes) { 529 t.Errorf("%d: len(fixes) not equal, expected: %v but got: %v", testNum, test.expected, fixes) 530 return 531 } 532 for i, n := range test.expected { 533 if n != fixes[i] { 534 t.Errorf("%d: expected fixes: %v but got fixes: %v", testNum, test.expected, fixes) 535 } 536 } 537 server.Close() 538 } 539 } 540 541 func TestCleanIssueBody(t *testing.T) { 542 tests := []struct { 543 body, expected string 544 }{ 545 {"foo", "foo"}, 546 {" bar ", "bar"}, 547 { 548 `Some message 549 550 <!-- Reviewable:start --> 551 gratuitous href 552 <!-- Reviewable:end -->`, 553 "Some message", 554 }, 555 { 556 `Merge pull request #1234 from user/master 557 558 Automatic merge from submit-queue (batch tested with PRs 1, 2, 1234, 57) 559 560 [Part 2] Adding s390x cross-compilation support for gcr.io images in this repo 561 562 <!-- Thanks for sending a pull request! Here are some tips for you: 563 1. If this is your first time, read our contributor guidelines https://github.com/kubernetes/kubernetes/blob/master/CONTRIBUTING.md and developer guide https://github.com/kubernetes/kubernetes/blob/master/docs/devel/development.md 564 2. If you want *faster* PR reviews, read how: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md 565 3. Follow the instructions for writing a release note: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/pull-requests.md#release-notes 566 --> 567 568 **What this PR does / why we need it**: This PR enables s390x support. 569 570 **Which issue this PR fixes #34328 571 572 **Special notes for your reviewer**: I am enabling cross compilation for s390x. 573 574 **Release note**: 575 <!-- Steps to write your release note: 576 1. Use the release-note-* labels to set the release note state (if you have access) 577 2. Enter your extended release note in the below block; leaving it blank means using the PR title as the release note. If no release note is required, just write` + 578 " `NONE`.\n-->\n```\nAllows cross compilation of Kubernetes on x86 host for s390x also enables s390x support to kube-dns , pause, addon-manager, etcd, hyperkube, kube-discovery etc\n```\n", 579 `Merge pull request #1234 from user/master 580 581 Automatic merge from submit-queue (batch tested with PRs 1, 2, 1234, 57) 582 583 [Part 2] Adding s390x cross-compilation support for gcr.io images in this repo 584 585 586 **What this PR does / why we need it**: This PR enables s390x support. 587 588 **Which issue this PR fixes #34328 589 590 **Special notes for your reviewer**: I am enabling cross compilation for s390x. 591 592 **Release note**: 593 ` + "```\nAllows cross compilation of Kubernetes on x86 host for s390x also enables s390x support to kube-dns , pause, addon-manager, etcd, hyperkube, kube-discovery etc\n```", 594 }, 595 } 596 for testNum, test := range tests { 597 body := cleanIssueBody(test.body) 598 if body != test.expected { 599 t.Errorf("%d: cleanIssueBody(%#v) == %#v != %#v", 600 testNum, test.body, body, test.expected) 601 } 602 } 603 } 604 605 func TestClearMilestone(t *testing.T) { 606 issue := github_test.Issue("", 1, []string{}, false) 607 issue.Milestone = &github.Milestone{Title: stringPtr("v1.2"), Number: intPtr(1)} 608 609 client, server, _ := github_test.InitServer(t, issue, nil, nil, nil, nil, nil, nil) 610 config := &Config{ 611 client: client, 612 Org: "o", 613 Project: "r", 614 } 615 616 obj, err := config.GetObject(*issue.Number) 617 if err != nil { 618 t.Fatalf("Unable to get issue") 619 } 620 621 if !obj.ClearMilestone() || obj.Issue.Milestone != nil { 622 t.Fatalf("Unable to clear milestone for issue") 623 } 624 625 server.Close() 626 }