github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/deck/pr_history_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 main 18 19 import ( 20 "context" 21 "fmt" 22 "net/url" 23 "reflect" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/fsouza/fake-gcs-server/fakestorage" 29 30 "sigs.k8s.io/prow/pkg/io" 31 32 "github.com/google/go-cmp/cmp" 33 "k8s.io/apimachinery/pkg/util/sets" 34 35 prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 36 "sigs.k8s.io/prow/pkg/config" 37 "sigs.k8s.io/prow/pkg/github" 38 "sigs.k8s.io/prow/pkg/github/fakegithub" 39 "sigs.k8s.io/prow/pkg/io/providers" 40 ) 41 42 type fakeBucket struct { 43 name string 44 storageProvider string 45 objects map[string]string 46 } 47 48 func (bucket fakeBucket) getName() string { 49 return bucket.name 50 } 51 52 func (bucket fakeBucket) getStorageProvider() string { 53 return bucket.storageProvider 54 } 55 56 func (bucket fakeBucket) listSubDirs(_ context.Context, prefix string) ([]string, error) { 57 dirs := sets.Set[string]{} 58 for k := range bucket.objects { 59 if !strings.HasPrefix(k, prefix) { 60 continue 61 } 62 suffix := strings.TrimPrefix(k, prefix) 63 dir := strings.Split(suffix, "/")[0] 64 dirs.Insert(dir) 65 } 66 return sets.List(dirs), nil 67 } 68 69 func (bucket fakeBucket) listAll(_ context.Context, prefix string) ([]string, error) { 70 keys := []string{} 71 for k := range bucket.objects { 72 if !strings.HasPrefix(k, prefix) { 73 continue 74 } 75 keys = append(keys, k) 76 } 77 return keys, nil 78 } 79 80 func (bucket fakeBucket) readObject(_ context.Context, key string) ([]byte, error) { 81 if obj, ok := bucket.objects[key]; ok { 82 return []byte(obj), nil 83 } 84 return []byte{}, fmt.Errorf("object %s not found", key) 85 } 86 87 func TestUpdateCommitData(t *testing.T) { 88 cases := []struct { 89 name string 90 hash string 91 buildTime time.Time 92 width int 93 before map[string]*commitData 94 after map[string]*commitData 95 }{ 96 { 97 name: "new commit", 98 hash: "d0c3cd182cffb3e722b14322fd1ca854a8bf62b0", 99 width: 1, 100 buildTime: time.Unix(1543534799, 0), 101 before: make(map[string]*commitData), 102 after: map[string]*commitData{ 103 "d0c3cd182cffb3e722b14322fd1ca854a8bf62b0": { 104 HashPrefix: "d0c3cd1", 105 MaxWidth: 1, 106 Link: "https://github.com/kubernetes/test-infra/commit/d0c3cd182cffb3e722b14322fd1ca854a8bf62b0", 107 latest: time.Unix(1543534799, 0), 108 }, 109 }, 110 }, 111 { 112 name: "update existing commit", 113 hash: "d0c3cd182cffb3e722b14322fd1ca854a8bf62b0", 114 width: 3, 115 buildTime: time.Unix(320630400, 0), 116 before: map[string]*commitData{ 117 "d0c3cd182cffb3e722b14322fd1ca854a8bf62b0": { 118 HashPrefix: "d0c3cd1", 119 MaxWidth: 5, 120 Link: "https://github.com/kubernetes/test-infra/commit/d0c3cd182cffb3e722b14322fd1ca854a8bf62b0", 121 latest: time.Unix(0, 0), 122 }, 123 }, 124 after: map[string]*commitData{ 125 "d0c3cd182cffb3e722b14322fd1ca854a8bf62b0": { 126 HashPrefix: "d0c3cd1", 127 MaxWidth: 5, 128 Link: "https://github.com/kubernetes/test-infra/commit/d0c3cd182cffb3e722b14322fd1ca854a8bf62b0", 129 latest: time.Unix(320630400, 0), 130 }, 131 }, 132 }, 133 { 134 name: "unknown commit has no link", 135 hash: "unknown", 136 width: 1, 137 before: make(map[string]*commitData), 138 after: map[string]*commitData{ 139 "unknown": { 140 HashPrefix: "unknown", 141 MaxWidth: 1, 142 Link: "", 143 }, 144 }, 145 }, 146 } 147 org := "kubernetes" 148 repo := "test-infra" 149 for _, tc := range cases { 150 updateCommitData(tc.before, "github.com", org, repo, tc.hash, tc.buildTime, tc.width) 151 for hash, expCommit := range tc.after { 152 if commit, ok := tc.before[hash]; ok { 153 if commit.HashPrefix != expCommit.HashPrefix { 154 t.Errorf("%s: expected commit hash prefix to be %s, got %s", tc.name, expCommit.HashPrefix, commit.HashPrefix) 155 } 156 if commit.Link != expCommit.Link { 157 t.Errorf("%s: expected commit link to be %s, got %s", tc.name, expCommit.Link, commit.Link) 158 } 159 if commit.MaxWidth != expCommit.MaxWidth { 160 t.Errorf("%s: expected commit width to be %d, got %d", tc.name, expCommit.MaxWidth, commit.MaxWidth) 161 } 162 if commit.latest != expCommit.latest { 163 t.Errorf("%s: expected commit time to be %v, got %v", tc.name, expCommit.latest, commit.latest) 164 } 165 } else { 166 t.Errorf("%s: expected commit %s not found", tc.name, hash) 167 } 168 } 169 } 170 } 171 172 func TestGetPullCommitHash(t *testing.T) { 173 cases := []struct { 174 pull string 175 commitHash string 176 expErr bool 177 }{ 178 { 179 pull: "main:4fe6d226e0455ef3d16c1f639a4010d699d0d097,21354:6cf03d53a14f6287d2175b0e9f3fbb31d91981a7", 180 commitHash: "6cf03d53a14f6287d2175b0e9f3fbb31d91981a7", 181 }, 182 { 183 pull: "release45-v8.0:5b30685f6bbf7a0bfef3fa8f2ebe2626ec1df391,54884:d1e309d8d10388000a34b1f705fd78c648ea5faa", 184 commitHash: "d1e309d8d10388000a34b1f705fd78c648ea5faa", 185 }, 186 { 187 pull: "main:6c1db48d6911675873b25457dbe61adca0d428a0,pullre:4905771e4f06c00385d7b1ac3c6de76f173e0212", 188 expErr: true, 189 }, 190 { 191 pull: "23545", 192 expErr: true, 193 }, 194 { 195 pull: "main:6c1db48d6911675873b25457dbe61adca0d428a0,12354:548461", 196 expErr: true, 197 }, 198 { 199 pull: "main:6c1db48d6,12354:e3e9d3eaa3a43f0a4fac47eccd379f077bee6789", 200 expErr: true, 201 }, 202 } 203 204 for _, tc := range cases { 205 commitHash, err := getPullCommitHash(tc.pull) 206 if (err != nil) != tc.expErr { 207 t.Errorf("%q: unexpected error: %v", tc.pull, err) 208 continue 209 } 210 if commitHash != tc.commitHash { 211 t.Errorf("%s: expected commit hash to be '%s', got '%s'", tc.pull, tc.commitHash, commitHash) 212 } 213 } 214 } 215 216 func TestParsePullURL(t *testing.T) { 217 cases := []struct { 218 name string 219 addr string 220 org string 221 repo string 222 pr int 223 expErr bool 224 }{ 225 { 226 name: "simple org/repo", 227 addr: "https://prow.k8s.io/pr-history?org=kubernetes&repo=test-infra&pr=10169", 228 org: "kubernetes", 229 repo: "test-infra", 230 pr: 10169, 231 }, 232 { 233 name: "Gerrit org/repo", 234 addr: "https://prow.k8s.io/pr-history?org=http://theponyapi.com&repo=test/ponies&pr=12345", 235 org: "http://theponyapi.com", 236 repo: "test/ponies", 237 pr: 12345, 238 }, 239 { 240 name: "PR needs to be an int", 241 addr: "https://prow.k8s.io/pr-history?org=kubernetes&repo=test-infra&pr=alpha", 242 expErr: true, 243 }, 244 { 245 name: "missing org", 246 addr: "https://prow.k8s.io/pr-history?repo=test-infra&pr=10169", 247 expErr: true, 248 }, 249 { 250 name: "missing repo", 251 addr: "https://prow.k8s.io/pr-history?org=kubernetes&pr=10169", 252 expErr: true, 253 }, 254 { 255 name: "missing pr", 256 addr: "https://prow.k8s.io/pr-history?org=kubernetes&repo=test-infra", 257 expErr: true, 258 }, 259 } 260 for _, tc := range cases { 261 u, err := url.Parse(tc.addr) 262 if err != nil { 263 t.Errorf("bad test URL %s: %v", tc.addr, err) 264 continue 265 } 266 org, repo, pr, err := parsePullURL(u) 267 if (err != nil) != tc.expErr { 268 t.Errorf("%q: unexpected error: %v", tc.name, err) 269 } 270 if org != tc.org || repo != tc.repo || pr != tc.pr { 271 t.Errorf("%q: expected %s, %s, %d; got %s, %s, %d", tc.name, tc.org, tc.repo, tc.pr, org, repo, pr) 272 } 273 } 274 } 275 276 var testBucket = fakeBucket{ 277 name: "chum-bucket", 278 storageProvider: providers.GS, 279 objects: map[string]string{ 280 "pr-logs/pull/123/build-snowman/456/started.json": `{ 281 "timestamp": 55555 282 }`, 283 "pr-logs/pull/123/build-snowman/456/finished.json": `{ 284 "timestamp": 66666, 285 "result": "SUCCESS", 286 "revision": "1244ee66517bbe603d899bbd24458ebc0e185fd9" 287 }`, 288 "pr-logs/pull/123/build-snowman/789/started.json": `{ 289 "timestamp": 98765, 290 "pull": "master:d0c3cd182cffb3e722b14322fd1ca854a8bf62b0,69848:bbdebedaf24c03f9e2eeb88e8ea4bb10c9e1fbfc" 291 }`, 292 "pr-logs/pull/765/eat-bread/999/started.json": `{ 293 "timestamp": 12345, 294 "pull": "not-master:21ebe05079a1aeb5f6dae23a2d8c106b4af8c363,12345:52252bcc81712c96940fca1d3c913dd76af3d2a2" 295 }`, 296 }, 297 } 298 299 func TestListJobBuilds(t *testing.T) { 300 jobPrefixes := []string{"pr-logs/pull/123/build-snowman/", "pr-logs/pull/765/eat-bread/"} 301 expected := map[string]sets.Set[string]{ 302 "build-snowman": {"456": {}, "789": {}}, 303 "eat-bread": {"999": {}}, 304 } 305 jobs := listJobBuilds(context.Background(), testBucket, jobPrefixes) 306 if len(jobs) != len(expected) { 307 t.Errorf("expected %d jobs, got %d", len(expected), len(jobs)) 308 } 309 for _, job := range jobs { 310 if expBuilds, ok := expected[job.name]; ok { 311 if len(job.buildPrefixes) != len(expBuilds) { 312 t.Errorf("expected %d builds for %q, found %d", len(expBuilds), job.name, len(job.buildPrefixes)) 313 } 314 for _, build := range job.buildPrefixes { 315 if !expBuilds.Has(build) { 316 t.Errorf("found unexpected build for %q: %q", job.name, build) 317 } 318 } 319 } else { 320 t.Errorf("found unexpected job %q", job.name) 321 } 322 } 323 } 324 325 func TestGetPRBuildData(t *testing.T) { 326 jobs := []jobBuilds{ 327 { 328 name: "build-snowman", 329 buildPrefixes: []string{ 330 "pr-logs/pull/123/build-snowman/456", 331 "pr-logs/pull/123/build-snowman/789", 332 }, 333 }, 334 { 335 name: "eat-bread", 336 buildPrefixes: []string{ 337 "pr-logs/pull/765/eat-bread/999", 338 }, 339 }, 340 } 341 expected := map[string]struct { 342 fixedDuration bool 343 buildData buildData 344 }{ 345 "pr-logs/pull/123/build-snowman/456": { 346 fixedDuration: true, 347 buildData: buildData{ 348 prefix: "pr-logs/pull/123/build-snowman/456", 349 jobName: "build-snowman", 350 index: 0, 351 ID: "456", 352 SpyglassLink: "/view/gs/chum-bucket/pr-logs/pull/123/build-snowman/456", 353 Started: time.Unix(55555, 0), 354 Duration: time.Unix(66666, 0).Sub(time.Unix(55555, 0)), 355 Result: "SUCCESS", 356 commitHash: "1244ee66517bbe603d899bbd24458ebc0e185fd9", 357 }, 358 }, 359 "pr-logs/pull/123/build-snowman/789": { 360 buildData: buildData{ 361 prefix: "pr-logs/pull/123/build-snowman/789", 362 jobName: "build-snowman", 363 index: 1, 364 ID: "789", 365 SpyglassLink: "/view/gs/chum-bucket/pr-logs/pull/123/build-snowman/789", 366 Started: time.Unix(98765, 0), 367 Result: "Pending", 368 commitHash: "bbdebedaf24c03f9e2eeb88e8ea4bb10c9e1fbfc", 369 }, 370 }, 371 "pr-logs/pull/765/eat-bread/999": { 372 buildData: buildData{ 373 prefix: "pr-logs/pull/765/eat-bread/999", 374 jobName: "eat-bread", 375 index: 0, 376 ID: "999", 377 SpyglassLink: "/view/gs/chum-bucket/pr-logs/pull/765/eat-bread/999", 378 Started: time.Unix(12345, 0), 379 Result: "Pending", 380 commitHash: "52252bcc81712c96940fca1d3c913dd76af3d2a2", 381 }, 382 }, 383 } 384 builds := getPRBuildData(context.Background(), testBucket, jobs) 385 if len(builds) != len(expected) { 386 t.Errorf("expected %d builds, found %d", len(expected), len(builds)) 387 } 388 cmpOption := cmp.AllowUnexported(buildData{}) 389 for _, build := range builds { 390 if exp, ok := expected[build.prefix]; ok { 391 if !exp.fixedDuration { 392 build.Duration = 0 393 } 394 395 if diff := cmp.Diff(build, exp.buildData, cmpOption); diff != "" { 396 t.Errorf("build %s mismatch (-got, +want):\n%s", build.prefix, diff) 397 } 398 } else { 399 t.Errorf("found unexpected build %s", build.prefix) 400 } 401 } 402 } 403 404 func TestGetGCSDirsForPR(t *testing.T) { 405 cases := []struct { 406 name string 407 expected map[string][]string 408 config *config.Config 409 org string 410 repo string 411 pr int 412 expErr bool 413 }{ 414 { 415 name: "no presubmits", 416 org: "kubernetes", 417 repo: "fizzbuzz", 418 pr: 123, 419 config: &config.Config{}, 420 expErr: true, 421 }, 422 { 423 name: "multiple buckets", 424 expected: map[string][]string{ 425 "gs://chum-bucket": { 426 "pr-logs/pull/prow/123/", 427 }, 428 "gs://krusty-krab": { 429 "pr-logs/pull/prow/123/", 430 }, 431 }, 432 org: "kubernetes", 433 repo: "prow", // someday 434 pr: 123, 435 config: &config.Config{ 436 ProwConfig: config.ProwConfig{ 437 Plank: config.Plank{ 438 DefaultDecorationConfigs: config.DefaultDecorationMapToSliceTesting( 439 map[string]*prowapi.DecorationConfig{ 440 "*": { 441 GCSConfiguration: &prowapi.GCSConfiguration{ 442 Bucket: "krusty-krab", 443 PathStrategy: "legacy", 444 DefaultOrg: "kubernetes", 445 DefaultRepo: "kubernetes", 446 }, 447 }, 448 }), 449 }, 450 }, 451 JobConfig: config.JobConfig{ 452 PresubmitsStatic: map[string][]config.Presubmit{ 453 "kubernetes/prow": { 454 { 455 JobBase: config.JobBase{ 456 Name: "fum-is-chum", 457 UtilityConfig: config.UtilityConfig{ 458 DecorationConfig: &prowapi.DecorationConfig{ 459 GCSConfiguration: &prowapi.GCSConfiguration{ 460 Bucket: "chum-bucket", 461 PathStrategy: "legacy", 462 DefaultOrg: "kubernetes", 463 DefaultRepo: "kubernetes", 464 }, 465 }, 466 }, 467 }, 468 }, 469 { 470 JobBase: config.JobBase{ 471 Name: "protect-formula", 472 // undecorated 473 }, 474 }, 475 }, 476 }, 477 }, 478 }, 479 }, 480 } 481 for _, tc := range cases { 482 gitHubClient := fakegithub.NewFakeClient() 483 gitHubClient.PullRequests = map[int]*github.PullRequest{ 484 123: {Number: 123}, 485 } 486 toSearch, err := getStorageDirsForPR(tc.config, gitHubClient, nil, tc.org, tc.repo, "", tc.pr) 487 if (err != nil) != tc.expErr { 488 t.Errorf("%s: unexpected error %v", tc.name, err) 489 } 490 for bucket, expDirs := range tc.expected { 491 if dirs, ok := toSearch[bucket]; ok { 492 if len(dirs) != len(expDirs) { 493 t.Errorf("expected to find %d dirs in bucket %s, found %d", len(expDirs), bucket, len(dirs)) 494 } 495 for _, expDir := range tc.expected[bucket] { 496 if !dirs.Has(expDir) { 497 t.Errorf("couldn't find expected dir %s in bucket %s", expDir, bucket) 498 } 499 } 500 } else { 501 t.Errorf("expected to find %d dirs in bucket %s, found none", len(expDirs), bucket) 502 } 503 } 504 } 505 } 506 507 func Test_getPRHistory(t *testing.T) { 508 c := &config.Config{ 509 JobConfig: config.JobConfig{ 510 PresubmitsStatic: map[string][]config.Presubmit{ 511 "kubernetes/test-infra": { 512 { 513 JobBase: config.JobBase{ 514 Name: "pull-test-infra-bazel", 515 UtilityConfig: config.UtilityConfig{ 516 DecorationConfig: &prowapi.DecorationConfig{ 517 GCSConfiguration: &prowapi.GCSConfiguration{ 518 Bucket: "kubernetes-jenkins", 519 PathStrategy: prowapi.PathStrategyLegacy, 520 DefaultOrg: "kubernetes", 521 }, 522 }, 523 }, 524 }, 525 }, 526 { 527 JobBase: config.JobBase{ 528 Name: "pull-test-infra-yamllint", 529 }, 530 }, 531 }, 532 }, 533 }, 534 ProwConfig: config.ProwConfig{ 535 Plank: config.Plank{ 536 DefaultDecorationConfigs: config.DefaultDecorationMapToSliceTesting( 537 map[string]*prowapi.DecorationConfig{ 538 "*": { 539 GCSConfiguration: &prowapi.GCSConfiguration{ 540 Bucket: "gs://kubernetes-jenkins", 541 PathStrategy: prowapi.PathStrategyLegacy, 542 DefaultOrg: "kubernetes", 543 }, 544 }, 545 }), 546 }, 547 Deck: config.Deck{ 548 AllKnownStorageBuckets: sets.New[string]("kubernetes-jenkins"), 549 }, 550 }, 551 } 552 objects := []fakestorage.Object{ 553 { 554 BucketName: "kubernetes-jenkins", 555 Name: "pr-logs/pull/test-infra/17183/pull-test-infra-bazel/1254406011708510210/started.json", 556 Content: []byte("{\"timestamp\": 1587908709,\"pull\": \"17183\",\"repos\": {\"kubernetes/test-infra\": \"master:48192e9a938ed25edb646de2ee9b4ec096c02732,17183:664ba002bc2155e7438b810a1bb7473c55dc1c6a\"},\"metadata\": {\"resultstore\": \"https://source.cloud.google.com/results/invocations/8edcebc7-11f3-4c4e-a7c3-cae6d26bd117/targets/test\"},\"repo-version\": \"a31d10b2924182638acad0f4b759f53e73b5f817\",\"Pending\": false}"), 557 }, 558 { 559 BucketName: "kubernetes-jenkins", 560 Name: "pr-logs/pull/test-infra/17183/pull-test-infra-bazel/1254406011708510210/finished.json", 561 Content: []byte("{\"timestamp\": 1587909145,\"passed\": true,\"result\": \"SUCCESS\",\"revision\": \"664ba002bc2155e7438b810a1bb7473c55dc1c6a\"}"), 562 }, 563 { 564 BucketName: "kubernetes-jenkins", 565 Name: "pr-logs/pull/test-infra/17183/pull-test-infra-yamllint/1254406011708510208/started.json", 566 Content: []byte("{\"timestamp\": 1587908749,\"pull\": \"17183\",\"repos\": {\"kubernetes/test-infra\": \"master:48192e9a938ed25edb646de2ee9b4ec096c02732,17183:664ba002bc2155e7438b810a1bb7473c55dc1c6a\"},\"metadata\": {\"resultstore\": \"https://source.cloud.google.com/results/invocations/af70141d-0990-4e63-9ebf-db874391865e/targets/test\"},\"repo-version\": \"a31d10b2924182638acad0f4b759f53e73b5f817\",\"Pending\": false}"), 567 }, 568 { 569 BucketName: "kubernetes-jenkins", 570 Name: "pr-logs/pull/test-infra/17183/pull-test-infra-yamllint/1254406011708510208/finished.json", 571 Content: []byte("{\"timestamp\": 1587908767,\"passed\": true,\"result\": \"SUCCESS\",\"revision\": \"664ba002bc2155e7438b810a1bb7473c55dc1c6a\"}"), 572 }, 573 } 574 gcsServer := fakestorage.NewServer(objects) 575 defer gcsServer.Stop() 576 577 fakeGCSClient := gcsServer.Client() 578 579 wantedPRHistory := prHistoryTemplate{ 580 Link: "https://github.com/kubernetes/test-infra/pull/17183", 581 Name: "kubernetes/test-infra #17183", 582 Jobs: []prJobData{ 583 { 584 Name: "pull-test-infra-bazel", 585 Link: "/job-history/gs/kubernetes-jenkins/pr-logs/directory/pull-test-infra-bazel", 586 Builds: []buildData{ 587 { 588 index: 0, 589 jobName: "pull-test-infra-bazel", 590 prefix: "pr-logs/pull/test-infra/17183/pull-test-infra-bazel/1254406011708510210/", 591 SpyglassLink: "/view/gs/kubernetes-jenkins/pr-logs/pull/test-infra/17183/pull-test-infra-bazel/1254406011708510210", 592 ID: "1254406011708510210", 593 Started: time.Unix(1587908709, 0), 594 Duration: 436000000000, 595 Result: "SUCCESS", 596 commitHash: "664ba002bc2155e7438b810a1bb7473c55dc1c6a", 597 }, 598 }, 599 }, 600 { 601 Name: "pull-test-infra-yamllint", 602 Link: "/job-history/gs/kubernetes-jenkins/pr-logs/directory/pull-test-infra-yamllint", 603 Builds: []buildData{ 604 { 605 index: 0, 606 jobName: "pull-test-infra-yamllint", 607 prefix: "pr-logs/pull/test-infra/17183/pull-test-infra-yamllint/1254406011708510208/", 608 SpyglassLink: "/view/gs/kubernetes-jenkins/pr-logs/pull/test-infra/17183/pull-test-infra-yamllint/1254406011708510208", 609 ID: "1254406011708510208", 610 Started: time.Unix(1587908749, 0), 611 Duration: 18000000000, 612 Result: "SUCCESS", 613 commitHash: "664ba002bc2155e7438b810a1bb7473c55dc1c6a", 614 }, 615 }, 616 }, 617 }, 618 Commits: []commitData{ 619 { 620 Hash: "664ba002bc2155e7438b810a1bb7473c55dc1c6a", 621 HashPrefix: "664ba00", 622 Link: "https://github.com/kubernetes/test-infra/commit/664ba002bc2155e7438b810a1bb7473c55dc1c6a", 623 MaxWidth: 1, 624 latest: time.Unix(1587908749, 0), 625 }, 626 }, 627 } 628 629 type args struct { 630 url string 631 } 632 tests := []struct { 633 name string 634 args args 635 want prHistoryTemplate 636 wantErr bool 637 }{ 638 { 639 name: "get pr history", 640 args: args{ 641 url: "https://prow.k8s.io/pr-history/?org=kubernetes&repo=test-infra&pr=17183", 642 }, 643 want: wantedPRHistory, 644 }, 645 } 646 for _, tt := range tests { 647 t.Run(tt.name, func(t *testing.T) { 648 prHistoryURL, _ := url.Parse(tt.args.url) 649 got, err := getPRHistory(context.Background(), prHistoryURL, c, io.NewGCSOpener(fakeGCSClient), nil, nil, "github.com") 650 if (err != nil) != tt.wantErr { 651 t.Errorf("getPRHistory() error = %v, wantErr %v", err, tt.wantErr) 652 return 653 } 654 if !reflect.DeepEqual(got, tt.want) { 655 t.Errorf("getPRHistory() got = %v, want %v", got, tt.want) 656 } 657 }) 658 } 659 }