fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

1// Copyright 2021 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package gitindex 16 17import ( 18 "bytes" 19 "context" 20 "fmt" 21 "os" 22 "os/exec" 23 "path/filepath" 24 "runtime" 25 "sort" 26 "testing" 27 28 "github.com/go-git/go-git/v5" 29 "github.com/go-git/go-git/v5/plumbing" 30 "github.com/google/go-cmp/cmp" 31 "github.com/google/go-cmp/cmp/cmpopts" 32 "github.com/sourcegraph/zoekt" 33 "github.com/sourcegraph/zoekt/build" 34 "github.com/sourcegraph/zoekt/ignore" 35 "github.com/sourcegraph/zoekt/query" 36 "github.com/sourcegraph/zoekt/shards" 37) 38 39func TestIndexEmptyRepo(t *testing.T) { 40 dir := t.TempDir() 41 42 cmd := exec.Command("git", "init", "-b", "master", "repo") 43 cmd.Dir = dir 44 45 if err := cmd.Run(); err != nil { 46 t.Fatalf("cmd.Run: %v", err) 47 } 48 49 desc := zoekt.Repository{ 50 Name: "repo", 51 } 52 opts := Options{ 53 RepoDir: filepath.Join(dir, "repo", ".git"), 54 BuildOptions: build.Options{ 55 RepositoryDescription: desc, 56 IndexDir: dir, 57 }, 58 } 59 60 if _, err := IndexGitRepo(opts); err != nil { 61 t.Fatalf("IndexGitRepo: %v", err) 62 } 63} 64 65func TestIndexDeltaBasic(t *testing.T) { 66 type branchToDocumentMap map[string][]zoekt.Document 67 68 type step struct { 69 name string 70 addedDocuments branchToDocumentMap 71 deletedDocuments branchToDocumentMap 72 optFn func(t *testing.T, options *Options) 73 74 expectedFallbackToNormalBuild bool 75 expectedDocuments []zoekt.Document 76 } 77 78 helloWorld := zoekt.Document{Name: "hello_world.txt", Content: []byte("hello")} 79 80 fruitV1 := zoekt.Document{Name: "best_fruit.txt", Content: []byte("strawberry")} 81 fruitV1InFolder := zoekt.Document{Name: "the_best/best_fruit.txt", Content: fruitV1.Content} 82 fruitV1WithNewName := zoekt.Document{Name: "new_fruit.txt", Content: fruitV1.Content} 83 84 fruitV2 := zoekt.Document{Name: "best_fruit.txt", Content: []byte("grapes")} 85 fruitV2InFolder := zoekt.Document{Name: "the_best/best_fruit.txt", Content: fruitV2.Content} 86 87 fruitV3 := zoekt.Document{Name: "best_fruit.txt", Content: []byte("oranges")} 88 fruitV4 := zoekt.Document{Name: "best_fruit.txt", Content: []byte("apples")} 89 90 foo := zoekt.Document{Name: "foo.txt", Content: []byte("bar")} 91 92 emptySourcegraphIgnore := zoekt.Document{Name: ignore.IgnoreFile} 93 sourcegraphIgnoreWithContent := zoekt.Document{Name: ignore.IgnoreFile, Content: []byte("good_content.txt")} 94 95 for _, test := range []struct { 96 name string 97 branches []string 98 steps []step 99 }{ 100 { 101 name: "modification", 102 branches: []string{"main"}, 103 steps: []step{ 104 { 105 name: "setup", 106 addedDocuments: branchToDocumentMap{ 107 "main": []zoekt.Document{helloWorld, fruitV1}, 108 }, 109 110 expectedDocuments: []zoekt.Document{helloWorld, fruitV1}, 111 }, 112 { 113 name: "add newer version of fruits", 114 addedDocuments: branchToDocumentMap{ 115 "main": []zoekt.Document{fruitV2}, 116 }, 117 optFn: func(t *testing.T, o *Options) { 118 o.BuildOptions.IsDelta = true 119 }, 120 121 expectedDocuments: []zoekt.Document{helloWorld, fruitV2}, 122 }, 123 }, 124 }, 125 { 126 name: "modification only inside nested folder", 127 branches: []string{"main"}, 128 steps: []step{ 129 { 130 name: "setup", 131 addedDocuments: branchToDocumentMap{ 132 "main": []zoekt.Document{foo, fruitV1InFolder}, 133 }, 134 135 expectedDocuments: []zoekt.Document{foo, fruitV1InFolder}, 136 }, 137 { 138 name: "add newer version of fruits inside folder", 139 addedDocuments: branchToDocumentMap{ 140 "main": []zoekt.Document{fruitV2InFolder}, 141 }, 142 optFn: func(t *testing.T, o *Options) { 143 o.BuildOptions.IsDelta = true 144 }, 145 146 expectedDocuments: []zoekt.Document{foo, fruitV2InFolder}, 147 }, 148 }, 149 }, 150 { 151 name: "addition", 152 branches: []string{"main"}, 153 steps: []step{ 154 { 155 name: "setup", 156 addedDocuments: branchToDocumentMap{ 157 "main": []zoekt.Document{helloWorld, fruitV1}, 158 }, 159 160 expectedDocuments: []zoekt.Document{helloWorld, fruitV1}, 161 }, 162 { 163 name: "add new file - foo", 164 addedDocuments: branchToDocumentMap{ 165 "main": []zoekt.Document{foo}, 166 }, 167 optFn: func(t *testing.T, o *Options) { 168 o.BuildOptions.IsDelta = true 169 }, 170 171 expectedDocuments: []zoekt.Document{helloWorld, fruitV1, foo}, 172 }, 173 }, 174 }, 175 { 176 name: "deletion", 177 branches: []string{"main"}, 178 steps: []step{ 179 { 180 name: "setup", 181 addedDocuments: branchToDocumentMap{ 182 "main": []zoekt.Document{helloWorld, fruitV1, foo}, 183 }, 184 185 expectedDocuments: []zoekt.Document{helloWorld, fruitV1, foo}, 186 }, 187 { 188 name: "delete foo file", 189 addedDocuments: nil, 190 deletedDocuments: branchToDocumentMap{ 191 "main": []zoekt.Document{foo}, 192 }, 193 194 optFn: func(t *testing.T, o *Options) { 195 o.BuildOptions.IsDelta = true 196 }, 197 198 expectedDocuments: []zoekt.Document{helloWorld, fruitV1}, 199 }, 200 }, 201 }, 202 { 203 name: "addition and deletion on only one branch", 204 branches: []string{"main", "release", "dev"}, 205 steps: []step{ 206 { 207 name: "setup", 208 addedDocuments: branchToDocumentMap{ 209 "main": []zoekt.Document{fruitV1}, 210 "release": []zoekt.Document{fruitV2}, 211 "dev": []zoekt.Document{fruitV3}, 212 }, 213 214 expectedDocuments: []zoekt.Document{fruitV1, fruitV2, fruitV3}, 215 }, 216 { 217 name: "replace fruits v3 with v4 on 'dev', delete fruits on 'main'", 218 addedDocuments: branchToDocumentMap{ 219 "dev": []zoekt.Document{fruitV4}, 220 }, 221 deletedDocuments: branchToDocumentMap{ 222 "main": []zoekt.Document{fruitV1}, 223 }, 224 225 optFn: func(t *testing.T, o *Options) { 226 o.BuildOptions.IsDelta = true 227 }, 228 229 expectedDocuments: []zoekt.Document{fruitV2, fruitV4}, 230 }, 231 }, 232 }, 233 { 234 name: "rename", 235 branches: []string{"main", "release"}, 236 steps: []step{ 237 { 238 name: "setup", 239 addedDocuments: branchToDocumentMap{ 240 "main": []zoekt.Document{fruitV1}, 241 "release": []zoekt.Document{fruitV2}, 242 }, 243 expectedDocuments: []zoekt.Document{fruitV1, fruitV2}, 244 }, 245 { 246 name: "rename fruits file on 'main' + ensure that unmodified fruits file on 'release' is still searchable", 247 addedDocuments: branchToDocumentMap{ 248 "main": []zoekt.Document{fruitV1WithNewName}, 249 }, 250 deletedDocuments: branchToDocumentMap{ 251 "main": []zoekt.Document{fruitV1}, 252 }, 253 254 optFn: func(t *testing.T, o *Options) { 255 o.BuildOptions.IsDelta = true 256 }, 257 258 expectedDocuments: []zoekt.Document{fruitV1WithNewName, fruitV2}, 259 }, 260 }, 261 }, 262 { 263 name: "modification: update one branch with version of document from another branch (a.k.a. Keegan's test)", 264 branches: []string{"main", "dev"}, 265 steps: []step{ 266 { 267 name: "setup", 268 addedDocuments: branchToDocumentMap{ 269 "main": []zoekt.Document{fruitV1}, 270 "dev": []zoekt.Document{fruitV2}, 271 }, 272 expectedDocuments: []zoekt.Document{fruitV1, fruitV2}, 273 }, 274 { 275 name: "switch main to dev's older version of fruits + bump dev's fruits to new version", 276 addedDocuments: branchToDocumentMap{ 277 "main": []zoekt.Document{fruitV2}, 278 "dev": []zoekt.Document{fruitV3}, 279 }, 280 281 optFn: func(t *testing.T, o *Options) { 282 o.BuildOptions.IsDelta = true 283 }, 284 285 expectedDocuments: []zoekt.Document{fruitV2, fruitV3}, 286 }, 287 }, 288 }, 289 { 290 name: "no-op delta builds (reindexing the same commits)", 291 branches: []string{"main", "dev"}, 292 steps: []step{ 293 { 294 name: "setup", 295 addedDocuments: branchToDocumentMap{ 296 "main": []zoekt.Document{fruitV1, foo}, 297 "dev": []zoekt.Document{helloWorld}, 298 }, 299 expectedDocuments: []zoekt.Document{fruitV1, foo, helloWorld}, 300 }, 301 { 302 name: "first no-op (normal build -> delta build)", 303 optFn: func(t *testing.T, o *Options) { 304 o.BuildOptions.IsDelta = true 305 }, 306 307 expectedDocuments: []zoekt.Document{fruitV1, foo, helloWorld}, 308 }, 309 { 310 name: "second no-op (delta build -> delta build)", 311 optFn: func(t *testing.T, o *Options) { 312 o.BuildOptions.IsDelta = true 313 }, 314 315 expectedDocuments: []zoekt.Document{fruitV1, foo, helloWorld}, 316 }, 317 }, 318 }, 319 { 320 name: "should fallback to normal build if no prior shards exist", 321 branches: []string{"main"}, 322 steps: []step{ 323 { 324 name: "attempt delta build on a repository that hasn't been indexed yet", 325 addedDocuments: branchToDocumentMap{ 326 "main": []zoekt.Document{helloWorld}, 327 }, 328 optFn: func(t *testing.T, o *Options) { 329 o.BuildOptions.IsDelta = true 330 }, 331 332 expectedFallbackToNormalBuild: true, 333 expectedDocuments: []zoekt.Document{helloWorld}, 334 }, 335 }, 336 }, 337 { 338 name: "should fallback to normal build if the set of requested repository branches changes", 339 branches: []string{"main", "release", "dev"}, 340 steps: []step{ 341 { 342 name: "setup", 343 addedDocuments: branchToDocumentMap{ 344 "main": []zoekt.Document{fruitV1}, 345 "release": []zoekt.Document{fruitV2}, 346 "dev": []zoekt.Document{fruitV3}, 347 }, 348 349 expectedDocuments: []zoekt.Document{fruitV1, fruitV2, fruitV3}, 350 }, 351 { 352 name: "try delta build after dropping 'main' branch from index ", 353 addedDocuments: branchToDocumentMap{ 354 "release": []zoekt.Document{fruitV4}, 355 }, 356 optFn: func(t *testing.T, o *Options) { 357 o.Branches = []string{"HEAD", "release", "dev"} // a bit of a hack to override it this way, but it gets the job done 358 o.BuildOptions.IsDelta = true 359 }, 360 361 expectedFallbackToNormalBuild: true, 362 expectedDocuments: []zoekt.Document{fruitV3, fruitV4}, 363 }, 364 }, 365 }, 366 { 367 name: "should fallback to normal build if one or more index options updates requires a full build", 368 branches: []string{"main"}, 369 steps: []step{ 370 { 371 name: "setup", 372 addedDocuments: branchToDocumentMap{ 373 "main": []zoekt.Document{fruitV1}, 374 }, 375 376 expectedDocuments: []zoekt.Document{fruitV1}, 377 }, 378 { 379 name: "try delta build after updating Disable CTags index option", 380 addedDocuments: branchToDocumentMap{ 381 "main": []zoekt.Document{fruitV2}, 382 }, 383 optFn: func(t *testing.T, o *Options) { 384 o.BuildOptions.IsDelta = true 385 o.BuildOptions.DisableCTags = true 386 }, 387 388 expectedFallbackToNormalBuild: true, 389 expectedDocuments: []zoekt.Document{fruitV2}, 390 }, 391 { 392 name: "try delta build after reverting Disable CTags index option", 393 addedDocuments: branchToDocumentMap{ 394 "main": []zoekt.Document{fruitV3}, 395 }, 396 optFn: func(t *testing.T, o *Options) { 397 o.BuildOptions.IsDelta = true 398 o.BuildOptions.DisableCTags = false 399 }, 400 401 expectedFallbackToNormalBuild: true, 402 expectedDocuments: []zoekt.Document{fruitV3}, 403 }, 404 }, 405 }, 406 { 407 name: "should successfully perform multiple delta builds after disabling symbols", 408 branches: []string{"main"}, 409 steps: []step{ 410 { 411 name: "setup", 412 addedDocuments: branchToDocumentMap{ 413 "main": []zoekt.Document{fruitV1}, 414 }, 415 416 expectedDocuments: []zoekt.Document{fruitV1}, 417 }, 418 { 419 name: "try delta build after updating Disable CTags index option", 420 addedDocuments: branchToDocumentMap{ 421 "main": []zoekt.Document{fruitV2}, 422 }, 423 optFn: func(t *testing.T, o *Options) { 424 o.BuildOptions.IsDelta = true 425 o.BuildOptions.DisableCTags = true 426 }, 427 428 expectedFallbackToNormalBuild: true, 429 expectedDocuments: []zoekt.Document{fruitV2}, 430 }, 431 { 432 name: "try another delta build while CTags is still disabled", 433 addedDocuments: branchToDocumentMap{ 434 "main": []zoekt.Document{fruitV3}, 435 }, 436 optFn: func(t *testing.T, o *Options) { 437 o.BuildOptions.IsDelta = true 438 o.BuildOptions.DisableCTags = true 439 }, 440 441 expectedDocuments: []zoekt.Document{fruitV3}, 442 }, 443 }, 444 }, 445 { 446 name: "should fallback to normal build if repository has unsupported Sourcegraph ignore file", 447 branches: []string{"main"}, 448 steps: []step{ 449 { 450 name: "setup", 451 addedDocuments: branchToDocumentMap{ 452 "main": []zoekt.Document{emptySourcegraphIgnore}, 453 }, 454 455 expectedDocuments: []zoekt.Document{emptySourcegraphIgnore}, 456 }, 457 { 458 name: "attempt delta build after modifying ignore file", 459 addedDocuments: branchToDocumentMap{ 460 "main": []zoekt.Document{sourcegraphIgnoreWithContent}, 461 }, 462 optFn: func(t *testing.T, o *Options) { 463 o.BuildOptions.IsDelta = true 464 }, 465 466 expectedFallbackToNormalBuild: true, 467 expectedDocuments: []zoekt.Document{sourcegraphIgnoreWithContent}, 468 }, 469 }, 470 }, 471 { 472 name: "should fallback to a full, normal build if the repository has more than the specified threshold of shards", 473 branches: []string{"main"}, 474 steps: []step{ 475 { 476 name: "setup: first shard", 477 addedDocuments: branchToDocumentMap{ 478 "main": []zoekt.Document{foo}, 479 }, 480 481 expectedDocuments: []zoekt.Document{foo}, 482 }, 483 { 484 name: "setup: second shard (delta)", 485 addedDocuments: branchToDocumentMap{ 486 "main": []zoekt.Document{fruitV1}, 487 }, 488 optFn: func(t *testing.T, o *Options) { 489 o.BuildOptions.IsDelta = true 490 }, 491 492 expectedDocuments: []zoekt.Document{foo, fruitV1}, 493 }, 494 { 495 name: "setup: third shard (delta)", 496 addedDocuments: branchToDocumentMap{ 497 "main": []zoekt.Document{helloWorld}, 498 }, 499 optFn: func(t *testing.T, o *Options) { 500 o.BuildOptions.IsDelta = true 501 }, 502 503 expectedDocuments: []zoekt.Document{foo, fruitV1, helloWorld}, 504 }, 505 { 506 name: "attempt another delta build after we already blew past the shard threshold", 507 addedDocuments: branchToDocumentMap{ 508 "main": []zoekt.Document{fruitV2InFolder}, 509 }, 510 optFn: func(t *testing.T, o *Options) { 511 o.DeltaShardNumberFallbackThreshold = 2 512 o.BuildOptions.IsDelta = true 513 }, 514 515 expectedFallbackToNormalBuild: true, 516 expectedDocuments: []zoekt.Document{foo, fruitV1, helloWorld, fruitV2InFolder}, 517 }, 518 }, 519 }, 520 } { 521 test := test 522 523 t.Run(test.name, func(t *testing.T) { 524 t.Parallel() 525 526 indexDir := t.TempDir() 527 repositoryDir := t.TempDir() 528 529 // setup: initialize the repository and all of its branches 530 runScript(t, repositoryDir, "git init -b master") 531 runScript(t, repositoryDir, fmt.Sprintf("git config user.email %q", "you@example.com")) 532 runScript(t, repositoryDir, fmt.Sprintf("git config user.name %q", "Your Name")) 533 534 for _, b := range test.branches { 535 runScript(t, repositoryDir, fmt.Sprintf("git checkout -b %q", b)) 536 runScript(t, repositoryDir, fmt.Sprintf("git commit --allow-empty -m %q", "empty commit")) 537 } 538 539 for _, step := range test.steps { 540 t.Run(step.name, func(t *testing.T) { 541 for _, b := range test.branches { 542 // setup: for each branch, process any document deletions / additions and commit those changes 543 544 hadChange := false 545 546 runScript(t, repositoryDir, fmt.Sprintf("git checkout %q", b)) 547 548 for _, d := range step.deletedDocuments[b] { 549 hadChange = true 550 551 file := filepath.Join(repositoryDir, d.Name) 552 553 err := os.Remove(file) 554 if err != nil { 555 t.Fatalf("deleting file %q: %s", d.Name, err) 556 } 557 558 runScript(t, repositoryDir, fmt.Sprintf("git add %q", file)) 559 } 560 561 for _, d := range step.addedDocuments[b] { 562 hadChange = true 563 564 file := filepath.Join(repositoryDir, d.Name) 565 566 err := os.MkdirAll(filepath.Dir(file), 0o755) 567 if err != nil { 568 t.Fatalf("ensuring that folders exist for file %q: %s", file, err) 569 } 570 571 err = os.WriteFile(file, d.Content, 0o644) 572 if err != nil { 573 t.Fatalf("writing file %q: %s", d.Name, err) 574 } 575 576 runScript(t, repositoryDir, fmt.Sprintf("git add %q", file)) 577 } 578 579 if !hadChange { 580 continue 581 } 582 583 runScript(t, repositoryDir, fmt.Sprintf("git commit -m %q", step.name)) 584 } 585 586 // setup: prepare indexOptions with given overrides 587 buildOptions := build.Options{ 588 IndexDir: indexDir, 589 RepositoryDescription: zoekt.Repository{ 590 Name: "repository", 591 }, 592 IsDelta: false, 593 } 594 buildOptions.SetDefaults() 595 596 branches := append([]string{"HEAD"}, test.branches...) 597 598 options := Options{ 599 RepoDir: filepath.Join(repositoryDir, ".git"), 600 BuildOptions: buildOptions, 601 Branches: branches, 602 } 603 604 if step.optFn != nil { 605 step.optFn(t, &options) 606 } 607 608 // setup: prepare spy versions of prepare delta / normal build so that we can observe 609 // whether they were called appropriately 610 deltaBuildCalled := false 611 prepareDeltaSpy := func(options Options, repository *git.Repository) (repos map[fileKey]BlobLocation, branchVersions map[string]map[string]plumbing.Hash, changedOrDeletedPaths []string, err error) { 612 deltaBuildCalled = true 613 return prepareDeltaBuild(options, repository) 614 } 615 616 normalBuildCalled := false 617 prepareNormalSpy := func(options Options, repository *git.Repository) (repos map[fileKey]BlobLocation, branchVersions map[string]map[string]plumbing.Hash, err error) { 618 normalBuildCalled = true 619 return prepareNormalBuild(options, repository) 620 } 621 622 // run test 623 _, err := indexGitRepo(options, gitIndexConfig{ 624 prepareDeltaBuild: prepareDeltaSpy, 625 prepareNormalBuild: prepareNormalSpy, 626 }) 627 if err != nil { 628 t.Fatalf("IndexGitRepo: %s", err) 629 } 630 631 if options.BuildOptions.IsDelta != deltaBuildCalled { 632 // We should always try a delta build if we request it in the options. 633 t.Fatalf("expected deltaBuildCalled to be %t, got %t", options.BuildOptions.IsDelta, deltaBuildCalled) 634 } 635 636 if options.BuildOptions.IsDelta && (step.expectedFallbackToNormalBuild != normalBuildCalled) { 637 // We only check the normal spy on delta builds because it's only considered a "fallback" if we 638 // asked for a delta build in the first place. 639 t.Fatalf("expected normalBuildCalled to be %t, got %t", step.expectedFallbackToNormalBuild, normalBuildCalled) 640 } 641 642 // examine outcome: load shards into a searcher instance and run a dummy search query 643 // that returns every document contained in the shards 644 // 645 // then, compare returned set of documents with the expected set for the step and see if they agree 646 647 ss, err := shards.NewDirectorySearcher(indexDir) 648 if err != nil { 649 t.Fatalf("NewDirectorySearcher(%s): %s", indexDir, err) 650 } 651 defer ss.Close() 652 653 searchOpts := &zoekt.SearchOptions{Whole: true} 654 result, err := ss.Search(context.Background(), &query.Const{Value: true}, searchOpts) 655 if err != nil { 656 t.Fatalf("Search: %s", err) 657 } 658 659 var receivedDocuments []zoekt.Document 660 for _, f := range result.Files { 661 receivedDocuments = append(receivedDocuments, zoekt.Document{ 662 Name: f.FileName, 663 Content: f.Content, 664 }) 665 } 666 667 for _, docs := range [][]zoekt.Document{step.expectedDocuments, receivedDocuments} { 668 sort.Slice(docs, func(i, j int) bool { 669 a, b := docs[i], docs[j] 670 671 // first compare names, then fallback to contents if the names are equal 672 673 if a.Name < b.Name { 674 return true 675 } 676 677 if a.Name > b.Name { 678 return false 679 } 680 681 return bytes.Compare(a.Content, b.Content) < 0 682 }) 683 } 684 685 compareOptions := []cmp.Option{ 686 cmpopts.IgnoreFields(zoekt.Document{}, "Branches"), 687 cmpopts.EquateEmpty(), 688 } 689 690 if diff := cmp.Diff(step.expectedDocuments, receivedDocuments, compareOptions...); diff != "" { 691 t.Errorf("diff in received documents (-want +got):%s\n:", diff) 692 } 693 }) 694 } 695 }) 696 } 697} 698 699func TestRepoPathRanks(t *testing.T) { 700 pathRanks := repoPathRanks{ 701 Paths: map[string]float64{ 702 "search.go": 10.23, 703 "internal/index.go": 5.5, 704 "internal/scratch.go": 0.0, 705 "backend/search_test.go": 2.1, 706 }, 707 MeanRank: 3.3, 708 } 709 cases := []struct { 710 name string 711 path string 712 rank float64 713 }{ 714 { 715 name: "rank for standard file", 716 path: "search.go", 717 rank: 10.23, 718 }, 719 { 720 name: "file with rank 0", 721 path: "internal/scratch.go", 722 rank: 0.0, 723 }, 724 { 725 name: "rank for test file", 726 path: "backend/search_test.go", 727 rank: 2.1, 728 }, 729 { 730 name: "file with missing rank", 731 path: "internal/docs.md", 732 rank: 3.3, 733 }, 734 { 735 name: "test file with missing rank", 736 path: "backend/index_test.go", 737 rank: 0.0, 738 }, 739 { 740 name: "third-party file with missing rank", 741 path: "node_modules/search/index.js", 742 rank: 0.0, 743 }, 744 } 745 746 for _, tt := range cases { 747 t.Run(tt.name, func(t *testing.T) { 748 got := pathRanks.rank(tt.path, nil) 749 if got != tt.rank { 750 t.Errorf("expected file '%s' to have rank %f, but got %f", tt.path, tt.rank, got) 751 } 752 }) 753 } 754} 755 756func runScript(t *testing.T, cwd string, script string) { 757 t.Helper() 758 759 err := os.MkdirAll(cwd, 0o755) 760 if err != nil { 761 t.Fatalf("ensuring path %q exists: %s", cwd, err) 762 } 763 764 cmd := exec.Command("sh", "-euxc", script) 765 cmd.Dir = cwd 766 cmd.Env = append([]string{"GIT_CONFIG_GLOBAL=", "GIT_CONFIG_SYSTEM="}, os.Environ()...) 767 768 if out, err := cmd.CombinedOutput(); err != nil { 769 t.Fatalf("execution error: %v, output %s", err, out) 770 } 771} 772 773func TestSetTemplate(t *testing.T) { 774 repositoryDir := t.TempDir() 775 776 // setup: initialize the repository and all of its branches 777 runScript(t, repositoryDir, "git init -b master") 778 runScript(t, repositoryDir, "git config remote.origin.url git@github.com:sourcegraph/zoekt.git") 779 desc := zoekt.Repository{} 780 if err := setTemplatesFromConfig(&desc, repositoryDir); err != nil { 781 t.Fatalf("setTemplatesFromConfig: %v", err) 782 } 783 784 if got, want := desc.FileURLTemplate, "https://github.com/sourcegraph/zoekt/blob/{{.Version}}/{{.Path}}"; got != want { 785 t.Errorf("got %q, want %q", got, want) 786 } 787} 788 789func BenchmarkPrepareNormalBuild(b *testing.B) { 790 // NOTE: To run the benchmark, download a large repo (like github.com/chromium/chromium/) and change this to its path. 791 repoDir := "/path/to/your/repo" 792 repo, err := git.PlainOpen(repoDir) 793 if err != nil { 794 b.Fatalf("Failed to open test repository: %v", err) 795 } 796 797 opts := Options{ 798 RepoDir: repoDir, 799 Submodules: false, 800 BranchPrefix: "refs/heads/", 801 Branches: []string{"main"}, 802 BuildOptions: build.Options{ 803 RepositoryDescription: zoekt.Repository{ 804 Name: "test-repo", 805 URL: "https://github.com/example/test-repo", 806 }, 807 }, 808 } 809 810 b.ReportAllocs() 811 812 repos, branchVersions, err := prepareNormalBuild(opts, repo) 813 if err != nil { 814 b.Fatalf("prepareNormalBuild failed: %v", err) 815 } 816 817 runtime.GC() 818 819 var m runtime.MemStats 820 runtime.ReadMemStats(&m) 821 b.ReportMetric(float64(m.HeapInuse), "heap-used-bytes") 822 b.ReportMetric(float64(m.HeapInuse), "heap-allocated-bytes") 823 824 if len(repos) == 0 || len(branchVersions) == 0 { 825 b.Fatalf("Unexpected empty results") 826 } 827}