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

Configure Feed

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

1// Copyright 2016 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 zoekt // import "github.com/sourcegraph/zoekt" 16 17import ( 18 "bytes" 19 _ "embed" 20 "encoding/gob" 21 "fmt" 22 "math/rand" 23 "reflect" 24 "testing" 25 "testing/quick" 26 "time" 27 28 "github.com/google/go-cmp/cmp" 29 "github.com/google/go-cmp/cmp/cmpopts" 30 "google.golang.org/protobuf/proto" 31 32 v1 "github.com/sourcegraph/zoekt/grpc/v1" 33) 34 35func TestProtoRoundtrip(t *testing.T) { 36 t.Run("FileMatch", func(t *testing.T) { 37 f := func(f1 FileMatch) bool { 38 p1 := f1.ToProto() 39 f2 := FileMatchFromProto(p1) 40 return reflect.DeepEqual(f1, f2) 41 } 42 if err := quick.Check(f, nil); err != nil { 43 t.Fatal(err) 44 } 45 }) 46 47 t.Run("ChunkMatch", func(t *testing.T) { 48 f := func(f1 ChunkMatch) bool { 49 p1 := f1.ToProto() 50 f2 := ChunkMatchFromProto(p1) 51 return reflect.DeepEqual(f1, f2) 52 } 53 if err := quick.Check(f, nil); err != nil { 54 t.Fatal(err) 55 } 56 }) 57 58 t.Run("Range", func(t *testing.T) { 59 f := func(f1 Range) bool { 60 p1 := f1.ToProto() 61 f2 := RangeFromProto(p1) 62 return reflect.DeepEqual(f1, f2) 63 } 64 if err := quick.Check(f, nil); err != nil { 65 t.Fatal(err) 66 } 67 }) 68 69 t.Run("Location", func(t *testing.T) { 70 f := func(f1 Range) bool { 71 p1 := f1.ToProto() 72 f2 := RangeFromProto(p1) 73 return reflect.DeepEqual(f1, f2) 74 } 75 if err := quick.Check(f, nil); err != nil { 76 t.Fatal(err) 77 } 78 }) 79 80 t.Run("LineMatch", func(t *testing.T) { 81 f := func(f1 LineMatch) bool { 82 p1 := f1.ToProto() 83 f2 := LineMatchFromProto(p1) 84 return reflect.DeepEqual(f1, f2) 85 } 86 if err := quick.Check(f, nil); err != nil { 87 t.Fatal(err) 88 } 89 }) 90 91 t.Run("Symbol", func(t *testing.T) { 92 f := func(f1 *Symbol) bool { 93 p1 := f1.ToProto() 94 f2 := SymbolFromProto(p1) 95 return reflect.DeepEqual(f1, f2) 96 } 97 if err := quick.Check(f, nil); err != nil { 98 t.Fatal(err) 99 } 100 }) 101 102 t.Run("FlushReson", func(t *testing.T) { 103 f := func(f1 FlushReason) bool { 104 p1 := f1.ToProto() 105 f2 := FlushReasonFromProto(p1) 106 return reflect.DeepEqual(f1.String(), f2.String()) 107 } 108 if err := quick.Check(f, nil); err != nil { 109 t.Fatal(err) 110 } 111 }) 112 113 t.Run("Stats", func(t *testing.T) { 114 f := func(f1 Stats) bool { 115 p1 := f1.ToProto() 116 f2 := StatsFromProto(p1) 117 return reflect.DeepEqual(f1, f2) 118 } 119 if err := quick.Check(f, nil); err != nil { 120 t.Fatal(err) 121 } 122 }) 123 124 t.Run("Progress", func(t *testing.T) { 125 f := func(f1 Progress) bool { 126 p1 := f1.ToProto() 127 f2 := ProgressFromProto(p1) 128 return reflect.DeepEqual(f1, f2) 129 } 130 if err := quick.Check(f, nil); err != nil { 131 t.Fatal(err) 132 } 133 }) 134 135 t.Run("SearchResult", func(t *testing.T) { 136 f := func(f1 *SearchResult) bool { 137 var repoURLs map[string]string 138 var lineFragments map[string]string 139 140 if f1 != nil { 141 repoURLs = f1.RepoURLs 142 lineFragments = f1.LineFragments 143 } 144 145 p1 := f1.ToProto() 146 f2 := SearchResultFromProto(p1, repoURLs, lineFragments) 147 148 return reflect.DeepEqual(f1, f2) 149 } 150 if err := quick.Check(f, nil); err != nil { 151 t.Fatal(err) 152 } 153 }) 154 155 t.Run("Repository", func(t *testing.T) { 156 f := func(f1 *Repository) bool { 157 p1 := f1.ToProto() 158 f2 := RepositoryFromProto(p1) 159 if diff := cmp.Diff(f1, &f2, cmpopts.IgnoreUnexported(Repository{})); diff != "" { 160 fmt.Printf("got diff: %s", diff) 161 return false 162 } 163 return true 164 } 165 if err := quick.Check(f, nil); err != nil { 166 t.Fatal(err) 167 } 168 }) 169 170 t.Run("IndexMetadata", func(t *testing.T) { 171 f := func(f1 *IndexMetadata) bool { 172 p1 := f1.ToProto() 173 f2 := IndexMetadataFromProto(p1) 174 if diff := cmp.Diff(f1, &f2); diff != "" { 175 fmt.Printf("got diff: %s", diff) 176 return false 177 } 178 return true 179 } 180 if err := quick.Check(f, nil); err != nil { 181 t.Fatal(err) 182 } 183 }) 184 185 t.Run("RepoStats", func(t *testing.T) { 186 f := func(f1 RepoStats) bool { 187 p1 := f1.ToProto() 188 f2 := RepoStatsFromProto(p1) 189 if diff := cmp.Diff(f1, f2); diff != "" { 190 fmt.Printf("got diff: %s", diff) 191 return false 192 } 193 return true 194 } 195 if err := quick.Check(f, nil); err != nil { 196 t.Fatal(err) 197 } 198 }) 199 200 t.Run("RepoListEntry", func(t *testing.T) { 201 r1 := &RepoListEntry{ 202 Repository: Repository{ 203 ID: 1, 204 Name: "test", 205 URL: "testurl", 206 Source: "testsource", 207 Branches: []RepositoryBranch{{ 208 Name: "branch", 209 Version: "version", 210 }}, 211 SubRepoMap: map[string]*Repository{ 212 "test": { 213 ID: 2, 214 Name: "subrepo", 215 Branches: []RepositoryBranch{}, 216 SubRepoMap: map[string]*Repository{}, 217 FileTombstones: map[string]struct{}{}, 218 }, 219 }, 220 CommitURLTemplate: "committemplate", 221 FileURLTemplate: "fileurltemplate", 222 LineFragmentTemplate: "linefragmenttemplate", 223 priority: 10, 224 RawConfig: map[string]string{ 225 "a": "b", 226 }, 227 Rank: 32, 228 IndexOptions: "indexoptions", 229 HasSymbols: true, 230 Tombstone: false, 231 LatestCommitDate: time.Now(), 232 FileTombstones: map[string]struct{}{ 233 "test1": {}, 234 }, 235 }, 236 IndexMetadata: IndexMetadata{ 237 IndexFormatVersion: 32, 238 IndexFeatureVersion: 42, 239 IndexMinReaderVersion: 52, 240 IndexTime: time.Now(), 241 PlainASCII: true, 242 LanguageMap: map[string]uint16{ 243 "go": 1, 244 }, 245 ZoektVersion: "32", 246 ID: "52", 247 }, 248 Stats: RepoStats{ 249 Repos: 3, 250 Shards: 4, 251 Documents: 5, 252 IndexBytes: 6, 253 ContentBytes: 7, 254 NewLinesCount: 8, 255 DefaultBranchNewLinesCount: 9, 256 OtherBranchesNewLinesCount: 10, 257 }, 258 } 259 260 p1 := r1.ToProto() 261 r2 := RepoListEntryFromProto(p1) 262 if diff := cmp.Diff(r1, r2, cmpopts.IgnoreUnexported(Repository{})); diff != "" { 263 t.Fatalf("got diff: %s", diff) 264 } 265 }) 266 267 t.Run("RepositoryBranch", func(t *testing.T) { 268 f := func(f1 RepositoryBranch) bool { 269 p1 := f1.ToProto() 270 f2 := RepositoryBranchFromProto(p1) 271 if diff := cmp.Diff(f1, f2); diff != "" { 272 fmt.Printf("got diff: %s", diff) 273 return false 274 } 275 return true 276 } 277 if err := quick.Check(f, nil); err != nil { 278 t.Fatal(err) 279 } 280 }) 281 282 t.Run("MinimalRepoListEntry", func(t *testing.T) { 283 f := func(f1 MinimalRepoListEntry) bool { 284 p1 := f1.ToProto() 285 f2 := MinimalRepoListEntryFromProto(p1) 286 if diff := cmp.Diff(f1, f2); diff != "" { 287 fmt.Printf("got diff: %s", diff) 288 return false 289 } 290 return true 291 } 292 if err := quick.Check(f, nil); err != nil { 293 t.Fatal(err) 294 } 295 }) 296 297 t.Run("ListOptions", func(t *testing.T) { 298 f := func(f1 *ListOptions) bool { 299 p1 := f1.ToProto() 300 f2 := ListOptionsFromProto(p1) 301 if diff := cmp.Diff(f1, f2); diff != "" { 302 fmt.Printf("got diff: %s", diff) 303 return false 304 } 305 return true 306 } 307 if err := quick.Check(f, nil); err != nil { 308 t.Fatal(err) 309 } 310 }) 311 312 t.Run("SearchOptions", func(t *testing.T) { 313 f := func(f1 *SearchOptions) bool { 314 if f1 != nil { 315 // Ignore deprecated and unimplemented fields 316 f1.ShardMaxImportantMatch = 0 317 f1.TotalMaxImportantMatch = 0 318 f1.SpanContext = nil 319 } 320 p1 := f1.ToProto() 321 f2 := SearchOptionsFromProto(p1) 322 if diff := cmp.Diff(f1, f2); diff != "" { 323 fmt.Printf("got diff: %s", diff) 324 return false 325 } 326 return true 327 } 328 if err := quick.Check(f, nil); err != nil { 329 t.Fatal(err) 330 } 331 }) 332} 333 334func (*IndexMetadata) Generate(r *rand.Rand, _ int) reflect.Value { 335 indexTime := time.Now().Add(time.Duration(r.Int63n(1000)) * time.Hour) 336 var i IndexMetadata 337 i.IndexFormatVersion = gen(i.IndexFormatVersion, r) 338 i.IndexFeatureVersion = gen(i.IndexFeatureVersion, r) 339 i.IndexMinReaderVersion = gen(i.IndexMinReaderVersion, r) 340 i.IndexTime = indexTime 341 i.PlainASCII = gen(i.PlainASCII, r) 342 i.LanguageMap = gen(i.LanguageMap, r) 343 i.ZoektVersion = gen(i.ZoektVersion, r) 344 i.ID = gen(i.ID, r) 345 return reflect.ValueOf(&i) 346} 347 348func (*Repository) Generate(rng *rand.Rand, _ int) reflect.Value { 349 latestCommitDate := time.Now().Add(time.Duration(rng.Int63n(1000)) * time.Hour) 350 var r Repository 351 v := &Repository{ 352 ID: gen(r.ID, rng), 353 Name: gen(r.Name, rng), 354 URL: gen(r.URL, rng), 355 Source: gen(r.Source, rng), 356 Branches: gen(r.Branches, rng), 357 SubRepoMap: map[string]*Repository{}, 358 CommitURLTemplate: gen(r.CommitURLTemplate, rng), 359 FileURLTemplate: gen(r.FileURLTemplate, rng), 360 LineFragmentTemplate: gen(r.LineFragmentTemplate, rng), 361 priority: gen(r.priority, rng), 362 RawConfig: gen(r.RawConfig, rng), 363 Rank: gen(r.Rank, rng), 364 IndexOptions: gen(r.IndexOptions, rng), 365 HasSymbols: gen(r.HasSymbols, rng), 366 Tombstone: gen(r.Tombstone, rng), 367 LatestCommitDate: latestCommitDate, 368 FileTombstones: gen(r.FileTombstones, rng), 369 } 370 return reflect.ValueOf(v) 371} 372 373func (RepoListField) Generate(rng *rand.Rand, _ int) reflect.Value { 374 switch rng.Int() % 3 { 375 case 0: 376 return reflect.ValueOf(RepoListField(RepoListFieldRepos)) 377 case 1: 378 return reflect.ValueOf(RepoListField(RepoListFieldMinimal)) 379 default: 380 return reflect.ValueOf(RepoListField(RepoListFieldReposMap)) 381 } 382} 383 384func gen[T any](sample T, r *rand.Rand) T { 385 var t T 386 v, _ := quick.Value(reflect.TypeOf(t), r) 387 return v.Interface().(T) 388} 389 390// This is a real search result that is intended to be a reasonable representative 391// for serialization benchmarks. 392// Generated by modifying the code to dump the proto to a file, then running a 393// fairly broadly-matching search. 394var ( 395 //go:embed testdata/search_result_1.pb 396 exampleSearchResultBytes []byte 397 398 // The proto struct representation of the search result 399 exampleSearchResultProto = func() *v1.SearchResponse { 400 sr := new(v1.SearchResponse) 401 err := proto.Unmarshal(exampleSearchResultBytes, sr) 402 if err != nil { 403 panic(err) 404 } 405 return sr 406 }() 407 408 // The non-proto struct representation of the search result 409 exampleSearchResultGo = SearchResultFromProto(exampleSearchResultProto, nil, nil) 410) 411 412func BenchmarkGobRoundtrip(b *testing.B) { 413 for _, count := range []int{1, 100, 1000, 10000} { 414 b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) { 415 for i := 0; i < b.N; i++ { 416 var buf bytes.Buffer 417 enc := gob.NewEncoder(&buf) 418 419 for i := 0; i < count; i++ { 420 err := enc.Encode(exampleSearchResultGo) 421 if err != nil { 422 panic(err) 423 } 424 425 } 426 427 dec := gob.NewDecoder(&buf) 428 for i := 0; i < count; i++ { 429 var res SearchResult 430 err := dec.Decode(&res) 431 if err != nil { 432 panic(err) 433 } 434 } 435 } 436 }) 437 } 438} 439 440func BenchmarkProtoRoundtrip(b *testing.B) { 441 for _, count := range []int{1, 100, 1000, 10000} { 442 b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) { 443 for i := 0; i < b.N; i++ { 444 buffers := make([][]byte, 0, count) 445 for i := 0; i < count; i++ { 446 buf, err := proto.Marshal(exampleSearchResultProto) 447 if err != nil { 448 b.Fatal(err) 449 } 450 buffers = append(buffers, buf) 451 } 452 453 for _, buf := range buffers { 454 res := new(v1.SearchResponse) 455 err := proto.Unmarshal(buf, res) 456 if err != nil { 457 b.Fatal(err) 458 } 459 } 460 } 461 }) 462 } 463}