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 p1 := f1.ToProto() 138 f2 := SearchResultFromProto(p1) 139 return reflect.DeepEqual(f1, f2) 140 } 141 if err := quick.Check(f, nil); err != nil { 142 t.Fatal(err) 143 } 144 }) 145 146 t.Run("Repository", func(t *testing.T) { 147 f := func(f1 *Repository) bool { 148 p1 := f1.ToProto() 149 f2 := RepositoryFromProto(p1) 150 if diff := cmp.Diff(f1, &f2, cmpopts.IgnoreUnexported(Repository{})); diff != "" { 151 fmt.Printf("got diff: %s", diff) 152 return false 153 } 154 return true 155 } 156 if err := quick.Check(f, nil); err != nil { 157 t.Fatal(err) 158 } 159 }) 160 161 t.Run("IndexMetadata", func(t *testing.T) { 162 f := func(f1 *IndexMetadata) bool { 163 p1 := f1.ToProto() 164 f2 := IndexMetadataFromProto(p1) 165 if diff := cmp.Diff(f1, &f2); diff != "" { 166 fmt.Printf("got diff: %s", diff) 167 return false 168 } 169 return true 170 } 171 if err := quick.Check(f, nil); err != nil { 172 t.Fatal(err) 173 } 174 }) 175 176 t.Run("RepoStats", func(t *testing.T) { 177 f := func(f1 RepoStats) bool { 178 p1 := f1.ToProto() 179 f2 := RepoStatsFromProto(p1) 180 if diff := cmp.Diff(f1, f2); diff != "" { 181 fmt.Printf("got diff: %s", diff) 182 return false 183 } 184 return true 185 } 186 if err := quick.Check(f, nil); err != nil { 187 t.Fatal(err) 188 } 189 }) 190 191 t.Run("RepoListEntry", func(t *testing.T) { 192 r1 := &RepoListEntry{ 193 Repository: Repository{ 194 ID: 1, 195 Name: "test", 196 URL: "testurl", 197 Source: "testsource", 198 Branches: []RepositoryBranch{{ 199 Name: "branch", 200 Version: "version", 201 }}, 202 SubRepoMap: map[string]*Repository{ 203 "test": { 204 ID: 2, 205 Name: "subrepo", 206 Branches: []RepositoryBranch{}, 207 SubRepoMap: map[string]*Repository{}, 208 FileTombstones: map[string]struct{}{}, 209 }, 210 }, 211 CommitURLTemplate: "committemplate", 212 FileURLTemplate: "fileurltemplate", 213 LineFragmentTemplate: "linefragmenttemplate", 214 priority: 10, 215 RawConfig: map[string]string{ 216 "a": "b", 217 }, 218 Rank: 32, 219 IndexOptions: "indexoptions", 220 HasSymbols: true, 221 Tombstone: false, 222 LatestCommitDate: time.Now(), 223 FileTombstones: map[string]struct{}{ 224 "test1": {}, 225 }, 226 }, 227 IndexMetadata: IndexMetadata{ 228 IndexFormatVersion: 32, 229 IndexFeatureVersion: 42, 230 IndexMinReaderVersion: 52, 231 IndexTime: time.Now(), 232 PlainASCII: true, 233 LanguageMap: map[string]uint16{ 234 "go": 1, 235 }, 236 ZoektVersion: "32", 237 ID: "52", 238 }, 239 Stats: RepoStats{ 240 Repos: 3, 241 Shards: 4, 242 Documents: 5, 243 IndexBytes: 6, 244 ContentBytes: 7, 245 NewLinesCount: 8, 246 DefaultBranchNewLinesCount: 9, 247 OtherBranchesNewLinesCount: 10, 248 }, 249 } 250 251 p1 := r1.ToProto() 252 r2 := RepoListEntryFromProto(p1) 253 if diff := cmp.Diff(r1, r2, cmpopts.IgnoreUnexported(Repository{})); diff != "" { 254 t.Fatalf("got diff: %s", diff) 255 } 256 }) 257 258 t.Run("RepositoryBranch", func(t *testing.T) { 259 f := func(f1 RepositoryBranch) bool { 260 p1 := f1.ToProto() 261 f2 := RepositoryBranchFromProto(p1) 262 if diff := cmp.Diff(f1, f2); diff != "" { 263 fmt.Printf("got diff: %s", diff) 264 return false 265 } 266 return true 267 } 268 if err := quick.Check(f, nil); err != nil { 269 t.Fatal(err) 270 } 271 }) 272 273 t.Run("MinimalRepoListEntry", func(t *testing.T) { 274 f := func(f1 MinimalRepoListEntry) bool { 275 p1 := f1.ToProto() 276 f2 := MinimalRepoListEntryFromProto(p1) 277 if diff := cmp.Diff(f1, f2); diff != "" { 278 fmt.Printf("got diff: %s", diff) 279 return false 280 } 281 return true 282 } 283 if err := quick.Check(f, nil); err != nil { 284 t.Fatal(err) 285 } 286 }) 287 288 t.Run("ListOptions", func(t *testing.T) { 289 f := func(f1 *ListOptions) bool { 290 p1 := f1.ToProto() 291 f2 := ListOptionsFromProto(p1) 292 if diff := cmp.Diff(f1, f2); diff != "" { 293 fmt.Printf("got diff: %s", diff) 294 return false 295 } 296 return true 297 } 298 if err := quick.Check(f, nil); err != nil { 299 t.Fatal(err) 300 } 301 }) 302 303 t.Run("SearchOptions", func(t *testing.T) { 304 f := func(f1 *SearchOptions) bool { 305 if f1 != nil { 306 // Ignore deprecated and unimplemented fields 307 f1.ShardMaxImportantMatch = 0 308 f1.TotalMaxImportantMatch = 0 309 f1.SpanContext = nil 310 } 311 p1 := f1.ToProto() 312 f2 := SearchOptionsFromProto(p1) 313 if diff := cmp.Diff(f1, f2); diff != "" { 314 fmt.Printf("got diff: %s", diff) 315 return false 316 } 317 return true 318 } 319 if err := quick.Check(f, nil); err != nil { 320 t.Fatal(err) 321 } 322 }) 323} 324 325func (*IndexMetadata) Generate(r *rand.Rand, _ int) reflect.Value { 326 indexTime := time.Now().Add(time.Duration(r.Int63n(1000)) * time.Hour) 327 var i IndexMetadata 328 i.IndexFormatVersion = gen(i.IndexFormatVersion, r) 329 i.IndexFeatureVersion = gen(i.IndexFeatureVersion, r) 330 i.IndexMinReaderVersion = gen(i.IndexMinReaderVersion, r) 331 i.IndexTime = indexTime 332 i.PlainASCII = gen(i.PlainASCII, r) 333 i.LanguageMap = gen(i.LanguageMap, r) 334 i.ZoektVersion = gen(i.ZoektVersion, r) 335 i.ID = gen(i.ID, r) 336 return reflect.ValueOf(&i) 337} 338 339func (*Repository) Generate(rng *rand.Rand, _ int) reflect.Value { 340 latestCommitDate := time.Now().Add(time.Duration(rng.Int63n(1000)) * time.Hour) 341 var r Repository 342 v := &Repository{ 343 ID: gen(r.ID, rng), 344 Name: gen(r.Name, rng), 345 URL: gen(r.URL, rng), 346 Source: gen(r.Source, rng), 347 Branches: gen(r.Branches, rng), 348 SubRepoMap: map[string]*Repository{}, 349 CommitURLTemplate: gen(r.CommitURLTemplate, rng), 350 FileURLTemplate: gen(r.FileURLTemplate, rng), 351 LineFragmentTemplate: gen(r.LineFragmentTemplate, rng), 352 priority: gen(r.priority, rng), 353 RawConfig: gen(r.RawConfig, rng), 354 Rank: gen(r.Rank, rng), 355 IndexOptions: gen(r.IndexOptions, rng), 356 HasSymbols: gen(r.HasSymbols, rng), 357 Tombstone: gen(r.Tombstone, rng), 358 LatestCommitDate: latestCommitDate, 359 FileTombstones: gen(r.FileTombstones, rng), 360 } 361 return reflect.ValueOf(v) 362} 363 364func (RepoListField) Generate(rng *rand.Rand, _ int) reflect.Value { 365 switch rng.Int() % 3 { 366 case 0: 367 return reflect.ValueOf(RepoListField(RepoListFieldRepos)) 368 case 1: 369 return reflect.ValueOf(RepoListField(RepoListFieldMinimal)) 370 default: 371 return reflect.ValueOf(RepoListField(RepoListFieldReposMap)) 372 } 373} 374 375func gen[T any](sample T, r *rand.Rand) T { 376 var t T 377 v, _ := quick.Value(reflect.TypeOf(t), r) 378 return v.Interface().(T) 379} 380 381// This is a real search result that is intended to be a reasonable representative 382// for serialization benchmarks. 383// Generated by modifying the code to dump the proto to a file, then running a 384// fairly broadly-matching search. 385var ( 386 //go:embed testdata/search_result_1.pb 387 exampleSearchResultBytes []byte 388 389 // The proto struct representation of the search result 390 exampleSearchResultProto = func() *v1.SearchResponse { 391 sr := new(v1.SearchResponse) 392 err := proto.Unmarshal(exampleSearchResultBytes, sr) 393 if err != nil { 394 panic(err) 395 } 396 return sr 397 }() 398 399 // The non-proto struct representation of the search result 400 exampleSearchResultGo = SearchResultFromProto(exampleSearchResultProto) 401) 402 403func BenchmarkGobRoundtrip(b *testing.B) { 404 for _, count := range []int{1, 100, 1000, 10000} { 405 b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) { 406 for i := 0; i < b.N; i++ { 407 var buf bytes.Buffer 408 enc := gob.NewEncoder(&buf) 409 410 for i := 0; i < count; i++ { 411 err := enc.Encode(exampleSearchResultGo) 412 if err != nil { 413 panic(err) 414 } 415 416 } 417 418 dec := gob.NewDecoder(&buf) 419 for i := 0; i < count; i++ { 420 var res SearchResult 421 err := dec.Decode(&res) 422 if err != nil { 423 panic(err) 424 } 425 } 426 } 427 }) 428 } 429} 430 431func BenchmarkProtoRoundtrip(b *testing.B) { 432 for _, count := range []int{1, 100, 1000, 10000} { 433 b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) { 434 for i := 0; i < b.N; i++ { 435 buffers := make([][]byte, 0, count) 436 for i := 0; i < count; i++ { 437 buf, err := proto.Marshal(exampleSearchResultProto) 438 if err != nil { 439 b.Fatal(err) 440 } 441 buffers = append(buffers, buf) 442 } 443 444 for _, buf := range buffers { 445 res := new(v1.SearchResponse) 446 err := proto.Unmarshal(buf, res) 447 if err != nil { 448 b.Fatal(err) 449 } 450 } 451 } 452 }) 453 } 454}