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