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

Configure Feed

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

1package main 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/url" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/google/go-cmp/cmp" 16 "github.com/google/go-cmp/cmp/cmpopts" 17 "github.com/sourcegraph/log/logtest" 18 "github.com/stretchr/testify/require" 19 "google.golang.org/grpc" 20 "google.golang.org/protobuf/testing/protocmp" 21 "google.golang.org/protobuf/types/known/timestamppb" 22 23 "slices" 24 25 "github.com/sourcegraph/zoekt" 26 configv1 "github.com/sourcegraph/zoekt/cmd/zoekt-sourcegraph-indexserver/grpc/protos/sourcegraph/zoekt/configuration/v1" 27 "github.com/sourcegraph/zoekt/internal/ctags" 28) 29 30func TestIterateIndexOptions_Fingerprint(t *testing.T) { 31 fingerprintV0 := &configv1.Fingerprint{ 32 Identifier: 100, 33 GeneratedAt: timestamppb.New(time.Unix(100, 0)), 34 } 35 36 fingerprintV1 := &configv1.Fingerprint{ 37 Identifier: 101, 38 GeneratedAt: timestamppb.New(time.Unix(101, 0)), 39 } 40 41 fingerprintV2 := &configv1.Fingerprint{ 42 Identifier: 102, 43 GeneratedAt: timestamppb.New(time.Unix(102, 0)), 44 } 45 46 mkSearchConfigurationResponse := func(fingerprint *configv1.Fingerprint, repoIDs ...int32) *configv1.SearchConfigurationResponse { 47 repositories := make([]*configv1.ZoektIndexOptions, 0, len(repoIDs)) 48 for _, repoID := range repoIDs { 49 repositories = append(repositories, &configv1.ZoektIndexOptions{ 50 RepoId: repoID, 51 }) 52 } 53 54 return &configv1.SearchConfigurationResponse{ 55 UpdatedOptions: repositories, 56 Fingerprint: fingerprint, 57 } 58 } 59 60 grpcClient := &mockGRPCClient{ 61 mockList: func(_ context.Context, in *configv1.ListRequest, opts ...grpc.CallOption) (*configv1.ListResponse, error) { 62 return &configv1.ListResponse{ 63 RepoIds: []int32{1, 2, 3}, 64 }, nil 65 }, 66 } 67 68 clientOpts := []SourcegraphClientOption{ 69 WithBatchSize(1), 70 } 71 72 testURL := url.URL{Scheme: "http", Host: "does.not.matter", Path: "/"} 73 sg := newSourcegraphClient(&testURL, "", grpcClient, clientOpts...) 74 75 type step struct { 76 name string 77 78 wantFingerprint *configv1.Fingerprint 79 returnFingerprint *configv1.Fingerprint 80 returnErr error 81 skipCheckingRepoIDs bool 82 } 83 84 for _, step := range []step{ 85 { 86 name: "first call", 87 wantFingerprint: nil, 88 returnFingerprint: fingerprintV0, 89 }, 90 { 91 name: "second call (should provide fingerprint from last time)", 92 wantFingerprint: fingerprintV0, 93 returnFingerprint: fingerprintV1, 94 }, 95 { 96 name: "error", 97 wantFingerprint: fingerprintV1, 98 returnFingerprint: fingerprintV2, 99 100 returnErr: fmt.Errorf("boom"), 101 skipCheckingRepoIDs: true, // don't bother checking repoIDs if we expect an error 102 }, 103 { 104 name: "call after error (should ignore fingerprint from last time, and provide the older one)", 105 wantFingerprint: fingerprintV1, 106 returnFingerprint: fingerprintV2, 107 }, 108 } { 109 t.Run(step.name, func(t *testing.T) { 110 called := false 111 grpcClient.mockSearchConfiguration = func(_ context.Context, in *configv1.SearchConfigurationRequest, opts ...grpc.CallOption) (*configv1.SearchConfigurationResponse, error) { 112 called = true 113 114 diff := cmp.Diff(step.wantFingerprint, in.GetFingerprint(), protocmp.Transform()) 115 if diff != "" { 116 t.Fatalf("unexpected fingerprint (-want +got):\n%s", diff) 117 } 118 119 return mkSearchConfigurationResponse(step.returnFingerprint, in.RepoIds...), step.returnErr 120 } 121 122 result, err := sg.List(context.Background(), nil) 123 if err != nil { 124 t.Fatalf("unexpected error from List: %v", err) 125 } 126 127 var iteratedIDs []uint32 128 result.IterateIndexOptions(func(options IndexOptions) { 129 iteratedIDs = append(iteratedIDs, options.RepoID) 130 }) 131 132 if !called { 133 t.Fatal("expected SearchConfiguration to be called") 134 } 135 136 if step.skipCheckingRepoIDs { 137 return 138 } 139 140 slices.Sort(iteratedIDs) 141 142 expectedIDs := []uint32{1, 2, 3} 143 slices.Sort(expectedIDs) 144 145 if diff := cmp.Diff(expectedIDs, iteratedIDs); diff != "" { 146 t.Fatalf("unexpected repo ids (-want +got):\n%s", diff) 147 } 148 }) 149 } 150} 151 152func TestGetIndexOptions(t *testing.T) { 153 154 type testCase struct { 155 name string 156 response *configv1.SearchConfigurationResponse 157 want *IndexOptions 158 wantErr string 159 } 160 161 for _, tc := range []testCase{ 162 { 163 name: "symbols, large files", 164 response: &configv1.SearchConfigurationResponse{ 165 UpdatedOptions: []*configv1.ZoektIndexOptions{ 166 { 167 Symbols: true, 168 LargeFiles: []string{"foo", "bar"}, 169 }, 170 }, 171 }, 172 want: &IndexOptions{ 173 Symbols: true, 174 LargeFiles: []string{"foo", "bar"}, 175 }, 176 }, 177 { 178 name: "no symbols , large files", 179 response: &configv1.SearchConfigurationResponse{ 180 UpdatedOptions: []*configv1.ZoektIndexOptions{ 181 { 182 Symbols: true, 183 LargeFiles: []string{"foo", "bar"}, 184 }, 185 }, 186 }, 187 want: &IndexOptions{ 188 Symbols: true, 189 LargeFiles: []string{"foo", "bar"}, 190 }, 191 }, 192 193 { 194 name: "empty", 195 response: nil, 196 want: nil, 197 }, 198 199 { 200 name: "symbols", 201 response: &configv1.SearchConfigurationResponse{ 202 UpdatedOptions: []*configv1.ZoektIndexOptions{ 203 { 204 Symbols: true, 205 }, 206 }, 207 }, 208 want: &IndexOptions{ 209 Symbols: true, 210 }, 211 }, 212 { 213 name: "repoID", 214 response: &configv1.SearchConfigurationResponse{ 215 UpdatedOptions: []*configv1.ZoektIndexOptions{ 216 { 217 RepoId: 123, 218 }, 219 }, 220 }, 221 want: &IndexOptions{ 222 RepoID: 123, 223 }, 224 }, 225 { 226 name: "error", 227 response: &configv1.SearchConfigurationResponse{ 228 UpdatedOptions: []*configv1.ZoektIndexOptions{ 229 { 230 Error: "boom", 231 }, 232 }, 233 }, 234 want: nil, 235 wantErr: "boom", 236 }, 237 } { 238 called := false 239 mockClient := &mockGRPCClient{ 240 mockSearchConfiguration: func(_ context.Context, _ *configv1.SearchConfigurationRequest, _ ...grpc.CallOption) (*configv1.SearchConfigurationResponse, error) { 241 called = true 242 return tc.response, nil 243 }, 244 } 245 246 testURL := &url.URL{ 247 Scheme: "http", 248 Host: "does.not.matter", 249 Path: "/", 250 } 251 252 sg := newSourcegraphClient( 253 testURL, 254 "", 255 mockClient, 256 ) 257 258 var got IndexOptions 259 var err error 260 sg.ForceIterateIndexOptions(func(o IndexOptions) { 261 got = o 262 }, func(_ uint32, e error) { 263 err = e 264 }, 123) 265 266 if !called { 267 t.Fatal("expected mock to be called") 268 } 269 270 if err != nil { 271 if tc.wantErr == "" || !strings.Contains(err.Error(), tc.wantErr) { 272 t.Fatalf("unexpected error: %v", err) 273 } 274 } 275 276 if tc.want == nil { 277 continue 278 } 279 280 tc.want.CloneURL = sg.getCloneURL(got.Name) 281 282 if diff := cmp.Diff(tc.want, &got, cmpopts.EquateEmpty()); diff != "" { 283 t.Errorf("mismatch (-want +got):\n%s", diff) 284 } 285 } 286 287 // Mimic our fingerprint API, which doesn't return anything if the 288 // repo hasn't changed. 289 t.Run("unchanged", func(t *testing.T) { 290 291 called := false 292 mockClient := &mockGRPCClient{ 293 mockSearchConfiguration: func(_ context.Context, _ *configv1.SearchConfigurationRequest, _ ...grpc.CallOption) (*configv1.SearchConfigurationResponse, error) { 294 called = true 295 return nil, nil 296 }, 297 } 298 299 testURL := &url.URL{ 300 Scheme: "http", 301 Host: "does.not.matter", 302 Path: "/", 303 } 304 305 sg := newSourcegraphClient( 306 testURL, 307 "", 308 mockClient, 309 ) 310 gotAtLeastOneOption := false 311 var err error 312 sg.ForceIterateIndexOptions(func(_ IndexOptions) { 313 gotAtLeastOneOption = true 314 }, func(_ uint32, e error) { 315 err = e 316 }, 123) 317 318 if !called { 319 t.Fatal("expected mock to be called") 320 } 321 322 if err != nil { 323 t.Fatalf("unexpected error: %v", err) 324 } 325 326 if gotAtLeastOneOption { 327 t.Fatalf("expected no options, got %v", gotAtLeastOneOption) 328 } 329 }) 330 331 var response *configv1.SearchConfigurationResponse 332 mockClient := &mockGRPCClient{ 333 mockSearchConfiguration: func(_ context.Context, req *configv1.SearchConfigurationRequest, _ ...grpc.CallOption) (*configv1.SearchConfigurationResponse, error) { 334 if len(req.GetRepoIds()) == 0 || req.GetRepoIds()[0] != 123 { 335 return nil, errors.New("invalid repo id") 336 } 337 return response, nil 338 }, 339 } 340 341 sg := newSourcegraphClient(&url.URL{Path: "/"}, "", mockClient, WithBatchSize(0)) 342 343 cases := []struct { 344 Response *configv1.SearchConfigurationResponse 345 *IndexOptions 346 }{ 347 { 348 Response: &configv1.SearchConfigurationResponse{ 349 UpdatedOptions: []*configv1.ZoektIndexOptions{ 350 { 351 Symbols: true, 352 LargeFiles: []string{"foo", "bar"}, 353 }, 354 }, 355 }, 356 IndexOptions: &IndexOptions{ 357 Symbols: true, 358 LargeFiles: []string{"foo", "bar"}, 359 Branches: []zoekt.RepositoryBranch{}, 360 LanguageMap: map[string]ctags.CTagsParserType{}, 361 }, 362 }, 363 364 { 365 Response: &configv1.SearchConfigurationResponse{ 366 UpdatedOptions: []*configv1.ZoektIndexOptions{ 367 { 368 Symbols: false, 369 LargeFiles: []string{"foo", "bar"}, 370 }, 371 }, 372 }, 373 IndexOptions: &IndexOptions{ 374 LargeFiles: []string{"foo", "bar"}, 375 Branches: []zoekt.RepositoryBranch{}, 376 LanguageMap: map[string]ctags.CTagsParserType{}, 377 }, 378 }, 379 380 { 381 Response: &configv1.SearchConfigurationResponse{}, 382 }, 383 384 { 385 Response: &configv1.SearchConfigurationResponse{ 386 UpdatedOptions: []*configv1.ZoektIndexOptions{ 387 { 388 Symbols: true, 389 }, 390 }, 391 }, 392 IndexOptions: &IndexOptions{ 393 Symbols: true, 394 Branches: []zoekt.RepositoryBranch{}, 395 LanguageMap: map[string]ctags.CTagsParserType{}, 396 }, 397 }, 398 399 { 400 Response: &configv1.SearchConfigurationResponse{ 401 UpdatedOptions: []*configv1.ZoektIndexOptions{ 402 { 403 RepoId: 123, 404 }, 405 }, 406 }, 407 IndexOptions: &IndexOptions{ 408 RepoID: 123, 409 Branches: []zoekt.RepositoryBranch{}, 410 LanguageMap: map[string]ctags.CTagsParserType{}, 411 }, 412 }, 413 414 { 415 Response: &configv1.SearchConfigurationResponse{ 416 UpdatedOptions: []*configv1.ZoektIndexOptions{ 417 { 418 Error: "boom", 419 }, 420 }, 421 }, 422 }, 423 } 424 425 for _, tc := range cases { 426 response = tc.Response 427 428 var got IndexOptions 429 var err error 430 sg.ForceIterateIndexOptions(func(o IndexOptions) { 431 got = o 432 }, func(_ uint32, e error) { 433 err = e 434 }, 123) 435 436 if err != nil && tc.IndexOptions != nil { 437 t.Fatalf("unexpected error: %v", err) 438 } 439 if tc.IndexOptions == nil { 440 continue 441 } 442 443 tc.IndexOptions.CloneURL = sg.getCloneURL(got.Name) 444 445 if d := cmp.Diff(*tc.IndexOptions, got); d != "" { 446 t.Errorf("mismatch (-want +got):\n%s", d) 447 } 448 } 449 450 // Special case our fingerprint API which doesn't return anything if the 451 // repo hasn't changed. 452 t.Run("unchanged", func(t *testing.T) { 453 response = &configv1.SearchConfigurationResponse{} 454 455 got := false 456 var err error 457 sg.ForceIterateIndexOptions(func(_ IndexOptions) { 458 got = true 459 }, func(_ uint32, e error) { 460 err = e 461 }, 123) 462 if err != nil { 463 t.Fatalf("unexpected error: %v", err) 464 } 465 466 if got { 467 t.Fatalf("expected no options, got %v", got) 468 } 469 }) 470} 471 472func TestIndex(t *testing.T) { 473 cases := []struct { 474 name string 475 args indexArgs 476 mockRepositoryMetadata *zoekt.Repository 477 want []string 478 }{{ 479 name: "minimal", 480 args: indexArgs{ 481 IndexOptions: IndexOptions{ 482 Name: "test/repo", 483 CloneURL: "http://api.test/.internal/git/test/repo", 484 Branches: []zoekt.RepositoryBranch{{Name: "HEAD", Version: "deadbeef"}}, 485 TenantID: 42, 486 }, 487 }, 488 want: []string{ 489 "git -c init.defaultBranch=nonExistentBranchBB0FOFCH32 init --bare $TMPDIR/test%2Frepo.git", 490 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Actor-UID: internal", 491 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Tenant-ID: 42", 492 "git -C $TMPDIR/test%2Frepo.git -c protocol.version=2 fetch --depth=1 --no-tags --filter=blob:limit=1048577 http://api.test/.internal/git/test/repo deadbeef", 493 "git -C $TMPDIR/test%2Frepo.git update-ref HEAD deadbeef", 494 "git -C $TMPDIR/test%2Frepo.git config zoekt.archived 0", 495 "git -C $TMPDIR/test%2Frepo.git config zoekt.fork 0", 496 "git -C $TMPDIR/test%2Frepo.git config zoekt.latestCommitDate 1", 497 "git -C $TMPDIR/test%2Frepo.git config zoekt.name test/repo", 498 "git -C $TMPDIR/test%2Frepo.git config zoekt.priority 0", 499 "git -C $TMPDIR/test%2Frepo.git config zoekt.public 0", 500 "git -C $TMPDIR/test%2Frepo.git config zoekt.repoid 0", 501 "git -C $TMPDIR/test%2Frepo.git config zoekt.tenantID 42", 502 "zoekt-git-index -submodules=false -incremental=false -branches HEAD -file_limit 1048576 -disable_ctags $TMPDIR/test%2Frepo.git", 503 }, 504 }, { 505 name: "minimal-id", 506 args: indexArgs{ 507 IndexOptions: IndexOptions{ 508 Name: "test/repo", 509 CloneURL: "http://api.test/.internal/git/test/repo", 510 Branches: []zoekt.RepositoryBranch{{Name: "HEAD", Version: "deadbeef"}}, 511 RepoID: 123, 512 TenantID: 1, 513 }, 514 }, 515 want: []string{ 516 "git -c init.defaultBranch=nonExistentBranchBB0FOFCH32 init --bare $TMPDIR/test%2Frepo.git", 517 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Actor-UID: internal", 518 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Tenant-ID: 1", 519 "git -C $TMPDIR/test%2Frepo.git -c protocol.version=2 fetch --depth=1 --no-tags --filter=blob:limit=1048577 http://api.test/.internal/git/test/repo deadbeef", 520 "git -C $TMPDIR/test%2Frepo.git update-ref HEAD deadbeef", 521 "git -C $TMPDIR/test%2Frepo.git config zoekt.archived 0", 522 "git -C $TMPDIR/test%2Frepo.git config zoekt.fork 0", 523 "git -C $TMPDIR/test%2Frepo.git config zoekt.latestCommitDate 1", 524 "git -C $TMPDIR/test%2Frepo.git config zoekt.name test/repo", 525 "git -C $TMPDIR/test%2Frepo.git config zoekt.priority 0", 526 "git -C $TMPDIR/test%2Frepo.git config zoekt.public 0", 527 "git -C $TMPDIR/test%2Frepo.git config zoekt.repoid 123", 528 "git -C $TMPDIR/test%2Frepo.git config zoekt.tenantID 1", 529 "zoekt-git-index -submodules=false -incremental=false -branches HEAD -file_limit 1048576 -disable_ctags $TMPDIR/test%2Frepo.git", 530 }, 531 }, { 532 name: "all", 533 args: indexArgs{ 534 Incremental: true, 535 IndexDir: "/data/index", 536 Parallelism: 4, 537 IndexOptions: IndexOptions{ 538 Name: "test/repo", 539 CloneURL: "http://api.test/.internal/git/test/repo", 540 LargeFiles: []string{"foo", "bar"}, 541 Symbols: true, 542 Branches: []zoekt.RepositoryBranch{ 543 {Name: "HEAD", Version: "deadbeef"}, 544 {Name: "dev", Version: "feebdaed"}, // ignored for archive 545 }, 546 TenantID: 1, 547 }, 548 }, 549 want: []string{ 550 "git -c init.defaultBranch=nonExistentBranchBB0FOFCH32 init --bare $TMPDIR/test%2Frepo.git", 551 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Actor-UID: internal", 552 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Tenant-ID: 1", 553 "git -C $TMPDIR/test%2Frepo.git -c protocol.version=2 fetch --depth=1 --no-tags http://api.test/.internal/git/test/repo deadbeef feebdaed", 554 "git -C $TMPDIR/test%2Frepo.git update-ref HEAD deadbeef", 555 "git -C $TMPDIR/test%2Frepo.git update-ref refs/heads/dev feebdaed", 556 "git -C $TMPDIR/test%2Frepo.git config zoekt.archived 0", 557 "git -C $TMPDIR/test%2Frepo.git config zoekt.fork 0", 558 "git -C $TMPDIR/test%2Frepo.git config zoekt.latestCommitDate 1", 559 "git -C $TMPDIR/test%2Frepo.git config zoekt.name test/repo", 560 "git -C $TMPDIR/test%2Frepo.git config zoekt.priority 0", 561 "git -C $TMPDIR/test%2Frepo.git config zoekt.public 0", 562 "git -C $TMPDIR/test%2Frepo.git config zoekt.repoid 0", 563 "git -C $TMPDIR/test%2Frepo.git config zoekt.tenantID 1", 564 "zoekt-git-index -submodules=false -incremental=true -branches HEAD,dev " + 565 "-file_limit 1048576 -parallelism 4 -index /data/index -require_ctags -large_file foo -large_file bar " + 566 "$TMPDIR/test%2Frepo.git", 567 }, 568 }, { 569 name: "delta", 570 args: indexArgs{ 571 Incremental: true, 572 IndexDir: "/data/index", 573 Parallelism: 4, 574 UseDelta: true, 575 IndexOptions: IndexOptions{ 576 RepoID: 0, 577 Name: "test/repo", 578 CloneURL: "http://api.test/.internal/git/test/repo", 579 LargeFiles: []string{"foo", "bar"}, 580 Symbols: true, 581 Branches: []zoekt.RepositoryBranch{ 582 {Name: "HEAD", Version: "deadbeef"}, 583 {Name: "dev", Version: "feebdaed"}, 584 {Name: "release", Version: "12345678"}, 585 }, 586 TenantID: 1, 587 }, 588 DeltaShardNumberFallbackThreshold: 22, 589 }, 590 mockRepositoryMetadata: &zoekt.Repository{ 591 ID: 0, 592 Name: "test/repo", 593 Branches: []zoekt.RepositoryBranch{ 594 {Name: "HEAD", Version: "oldhead"}, 595 {Name: "dev", Version: "olddev"}, 596 {Name: "release", Version: "oldrelease"}, 597 }, 598 }, 599 want: []string{ 600 "git -c init.defaultBranch=nonExistentBranchBB0FOFCH32 init --bare $TMPDIR/test%2Frepo.git", 601 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Actor-UID: internal", 602 "git -C $TMPDIR/test%2Frepo.git config --add http.extraHeader X-Sourcegraph-Tenant-ID: 1", 603 "git -C $TMPDIR/test%2Frepo.git -c protocol.version=2 fetch --depth=1 --no-tags http://api.test/.internal/git/test/repo deadbeef feebdaed 12345678 oldhead olddev oldrelease", 604 "git -C $TMPDIR/test%2Frepo.git update-ref HEAD deadbeef", 605 "git -C $TMPDIR/test%2Frepo.git update-ref refs/heads/dev feebdaed", 606 "git -C $TMPDIR/test%2Frepo.git update-ref refs/heads/release 12345678", 607 "git -C $TMPDIR/test%2Frepo.git config zoekt.archived 0", 608 "git -C $TMPDIR/test%2Frepo.git config zoekt.fork 0", 609 "git -C $TMPDIR/test%2Frepo.git config zoekt.latestCommitDate 1", 610 "git -C $TMPDIR/test%2Frepo.git config zoekt.name test/repo", 611 "git -C $TMPDIR/test%2Frepo.git config zoekt.priority 0", 612 "git -C $TMPDIR/test%2Frepo.git config zoekt.public 0", 613 "git -C $TMPDIR/test%2Frepo.git config zoekt.repoid 0", 614 "git -C $TMPDIR/test%2Frepo.git config zoekt.tenantID 1", 615 "zoekt-git-index -submodules=false -incremental=true -branches HEAD,dev,release " + 616 "-delta -delta_threshold 22 -file_limit 1048576 -parallelism 4 -index /data/index -require_ctags -large_file foo -large_file bar " + 617 "$TMPDIR/test%2Frepo.git", 618 }, 619 }} 620 621 for _, tc := range cases { 622 t.Run(tc.name, func(t *testing.T) { 623 var got []string 624 runCmd := func(c *exec.Cmd) error { 625 if c.Env != nil { 626 t.Fatal("expected nil Env for command. Tenant Enforcement relies on us inheritting the parent process environment.") 627 } 628 629 cmd := strings.Join(c.Args, " ") 630 cmd = strings.ReplaceAll(cmd, filepath.Clean(os.TempDir()), "$TMPDIR") 631 got = append(got, cmd) 632 return nil 633 } 634 635 findRepositoryMetadata := func(args *indexArgs) (repository *zoekt.Repository, metadata *zoekt.IndexMetadata, ok bool, err error) { 636 if tc.mockRepositoryMetadata == nil { 637 return args.BuildOptions().FindRepositoryMetadata() 638 } 639 640 return tc.mockRepositoryMetadata, &zoekt.IndexMetadata{}, true, nil 641 } 642 643 c := gitIndexConfig{ 644 runCmd: runCmd, 645 findRepositoryMetadata: findRepositoryMetadata, 646 } 647 648 if err := gitIndex(context.Background(), c, &tc.args, sourcegraphNop{}, logtest.Scoped(t)); err != nil { 649 t.Fatal(err) 650 } 651 if !cmp.Equal(got, tc.want) { 652 t.Errorf("git mismatch (-want +got):\n%s", cmp.Diff(tc.want, got, splitargs)) 653 } 654 }) 655 } 656} 657 658var splitargs = cmpopts.AcyclicTransformer("splitargs", func(cmd string) []string { 659 return strings.Split(cmd, " ") 660}) 661 662type mockGRPCClient struct { 663 mockSearchConfiguration func(context.Context, *configv1.SearchConfigurationRequest, ...grpc.CallOption) (*configv1.SearchConfigurationResponse, error) 664 mockList func(context.Context, *configv1.ListRequest, ...grpc.CallOption) (*configv1.ListResponse, error) 665 mockUpdateIndexStatus func(context.Context, *configv1.UpdateIndexStatusRequest, ...grpc.CallOption) (*configv1.UpdateIndexStatusResponse, error) 666} 667 668func (m *mockGRPCClient) SearchConfiguration(ctx context.Context, in *configv1.SearchConfigurationRequest, opts ...grpc.CallOption) (*configv1.SearchConfigurationResponse, error) { 669 if m.mockSearchConfiguration != nil { 670 return m.mockSearchConfiguration(ctx, in, opts...) 671 } 672 673 return nil, fmt.Errorf("mock RPC SearchConfiguration not implemented") 674} 675 676func (m *mockGRPCClient) List(ctx context.Context, in *configv1.ListRequest, opts ...grpc.CallOption) (*configv1.ListResponse, error) { 677 if m.mockList != nil { 678 return m.mockList(ctx, in, opts...) 679 } 680 681 return nil, fmt.Errorf("mock RPC List not implemented") 682} 683 684func (m *mockGRPCClient) UpdateIndexStatus(ctx context.Context, in *configv1.UpdateIndexStatusRequest, opts ...grpc.CallOption) (*configv1.UpdateIndexStatusResponse, error) { 685 if m.mockUpdateIndexStatus != nil { 686 return m.mockUpdateIndexStatus(ctx, in, opts...) 687 } 688 689 return nil, fmt.Errorf("mock RPC UpdateIndexStatus not implemented") 690} 691 692var _ configv1.ZoektConfigurationServiceClient = &mockGRPCClient{} 693 694// Tests whether we can set git config values without error. 695func TestSetZoektConfig(t *testing.T) { 696 dir := t.TempDir() 697 698 // init git dir 699 script := `mkdir repo 700cd repo 701git init -b main 702` 703 cmd := exec.Command("/bin/sh", "-euxc", script) 704 cmd.Dir = dir 705 _, err := cmd.CombinedOutput() 706 require.NoError(t, err) 707 708 var out []byte 709 c := gitIndexConfig{ 710 runCmd: func(cmd *exec.Cmd) error { 711 var err error 712 out, err = cmd.CombinedOutput() 713 return err 714 }, 715 } 716 717 err = setZoektConfig(context.Background(), filepath.Join(dir, "repo"), &indexArgs{}, c) 718 require.NoError(t, err, string(out)) 719}