fork of https://github.com/sourcegraph/zoekt
1package index
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "github.com/google/go-cmp/cmp"
9
10 "github.com/sourcegraph/zoekt"
11)
12
13func TestMergePreservesStoredCategoryForSkippedGeneratedFile(t *testing.T) {
14 sb, err := NewShardBuilder(&zoekt.Repository{Name: "repo"})
15 if err != nil {
16 t.Fatalf("NewShardBuilder: %v", err)
17 }
18
19 err = sb.Add(Document{
20 Name: "generated.go",
21 Content: []byte("// Code generated by protoc-gen-go. DO NOT EDIT.\npackage generated\n"),
22 SkipReason: SkipReasonTooManyTrigrams,
23 })
24 if err != nil {
25 t.Fatalf("Add: %v", err)
26 }
27
28 tmpDir := t.TempDir()
29 inputPath := filepath.Join(tmpDir, "input.zoekt")
30 if err := builderWriteAll(inputPath, sb); err != nil {
31 t.Fatalf("builderWriteAll: %v", err)
32 }
33
34 inputFile, err := os.Open(inputPath)
35 if err != nil {
36 t.Fatalf("Open: %v", err)
37 }
38 defer inputFile.Close()
39
40 indexFile, err := NewIndexFile(inputFile)
41 if err != nil {
42 t.Fatalf("NewIndexFile: %v", err)
43 }
44 defer indexFile.Close()
45
46 tmpName, dstName, err := Merge(tmpDir, indexFile)
47 if err != nil {
48 t.Fatalf("Merge: %v", err)
49 }
50 if err := os.Rename(tmpName, dstName); err != nil {
51 t.Fatalf("Rename: %v", err)
52 }
53
54 mergedFile, err := os.Open(dstName)
55 if err != nil {
56 t.Fatalf("Open merged shard: %v", err)
57 }
58 defer mergedFile.Close()
59
60 mergedIndexFile, err := NewIndexFile(mergedFile)
61 if err != nil {
62 t.Fatalf("NewIndexFile merged shard: %v", err)
63 }
64 defer mergedIndexFile.Close()
65
66 searcher, err := NewSearcher(mergedIndexFile)
67 if err != nil {
68 t.Fatalf("NewSearcher: %v", err)
69 }
70 defer searcher.Close()
71
72 data := searcher.(*indexData)
73 if got := data.getCategory(0); got != FileCategoryGenerated {
74 t.Fatalf("got category %v, want %v", got, FileCategoryGenerated)
75 }
76}
77
78// We compare 2 simple shards before and after the transformation
79// explode(merge(shard1, shard2)). We expect the input and output shards to be
80// identical.
81func TestExplode(t *testing.T) {
82 simpleShards := []string{
83 ".././testdata/shards/repo_v16.00000.zoekt",
84 ".././testdata/shards/repo2_v16.00000.zoekt",
85 }
86
87 // repo name -> IndexMetadata
88 m := make(map[string]*zoekt.IndexMetadata, 2)
89
90 // merge
91 var files []IndexFile
92 for _, fn := range simpleShards {
93 f, err := os.Open(fn)
94 if err != nil {
95 t.Fatal(err)
96 }
97 defer f.Close()
98
99 indexFile, err := NewIndexFile(f)
100 if err != nil {
101 t.Fatal(err)
102 }
103 defer indexFile.Close()
104
105 // We save indexMeta because the fields ID and IndexTime are the 2 sources of
106 // non-determinism when building a new shard.
107 repoMeta, indexMeta, err := ReadMetadata(indexFile)
108 if err != nil {
109 t.Fatal(err)
110 }
111 if len(repoMeta) != 1 {
112 t.Fatal("this test assumes that indexFile contains only 1 repo")
113 }
114 m[repoMeta[0].Name] = indexMeta
115
116 files = append(files, indexFile)
117 }
118
119 tmpDir := t.TempDir()
120 tmpName, dstName, err := Merge(tmpDir, files...)
121 if err != nil {
122 t.Fatal(err)
123 }
124 err = os.Rename(tmpName, dstName)
125 if err != nil {
126 t.Fatal(err)
127 }
128
129 // explode
130 f, err := os.Open(dstName)
131 if err != nil {
132 t.Fatal(err)
133 }
134 defer f.Close()
135
136 indexFile, err := NewIndexFile(f)
137 if err != nil {
138 t.Fatal(err)
139 }
140 defer indexFile.Close()
141
142 overwriteIndexTimeAndID := func(ib *ShardBuilder) {
143 ib.ID = m[ib.repoList[0].Name].ID
144 ib.IndexTime = m[ib.repoList[0].Name].IndexTime
145 }
146 exploded, err := explode(tmpDir, indexFile, overwriteIndexTimeAndID)
147 if err != nil {
148 t.Fatal(err)
149 }
150 for tmp, final := range exploded {
151 err = os.Rename(tmp, final)
152 if err != nil {
153 t.Fatal(err)
154 }
155 }
156
157 for _, s := range simpleShards {
158 checkSameShards(t, s, filepath.Join(tmpDir, filepath.Base(s)))
159 }
160}
161
162// checkSameShards compares 2 shards byte by byte. The shards are expected to be
163// small enough to be read in all at once.
164func checkSameShards(t *testing.T, shard1, shard2 string) {
165 t.Helper()
166 b1, err := os.ReadFile(shard1)
167 if err != nil {
168 t.Fatal(err)
169 }
170
171 b2, err := os.ReadFile(shard2)
172 if err != nil {
173 t.Fatal(err)
174 }
175
176 // We could also use bytes.Equal, but the output of cmd.Diff is very helpful for
177 // differences in metadata.
178 d := cmp.Diff(b1, b2)
179 if d == "" {
180 return
181 }
182
183 if *update {
184 t.Logf("updating %s", shard1)
185 err := os.WriteFile(shard1, b2, 0o600)
186 if err != nil {
187 t.Fatal(err)
188 }
189 return
190 }
191
192 t.Fatalf("-%s\n+%s:\n%s", shard1, shard2, d)
193}