fork of https://github.com/sourcegraph/zoekt
1package main
2
3import (
4 "context"
5 "io"
6 "os"
7 "path/filepath"
8 "sort"
9 "testing"
10
11 "github.com/sourcegraph/zoekt"
12 "github.com/sourcegraph/zoekt/query"
13 "github.com/sourcegraph/zoekt/shards"
14)
15
16func TestMerge(t *testing.T) {
17 v16Shards, err := filepath.Glob("../../testdata/shards/*_v16.*.zoekt")
18 if err != nil {
19 t.Fatal(err)
20 }
21 sort.Strings(v16Shards)
22
23 testShards, err := copyTestShards(t.TempDir(), v16Shards)
24 if err != nil {
25 t.Fatal(err)
26 }
27 t.Log(testShards)
28
29 dir := t.TempDir()
30 err = merge(dir, testShards)
31 if err != nil {
32 t.Fatal(err)
33 }
34
35 ss, err := shards.NewDirectorySearcher(dir)
36 if err != nil {
37 t.Fatalf("NewDirectorySearcher(%s): %v", dir, err)
38 }
39 defer ss.Close()
40
41 q, err := query.Parse("hello")
42 if err != nil {
43 t.Fatalf("Parse(hello): %v", err)
44 }
45
46 var sOpts zoekt.SearchOptions
47 ctx := context.Background()
48 result, err := ss.Search(ctx, q, &sOpts)
49 if err != nil {
50 t.Fatalf("Search(%v): %v", q, err)
51 }
52
53 // we are merging the same shard twice, so we expect the same file twice.
54 if len(result.Files) != 2 {
55 t.Errorf("got %v, want 2 files.", result.Files)
56 }
57}
58
59// Merge 2 simple shards and then explode them.
60func TestExplode(t *testing.T) {
61 v16Shards, err := filepath.Glob("../../testdata/shards/repo*_v16.*.zoekt")
62 if err != nil {
63 t.Fatal(err)
64 }
65 sort.Strings(v16Shards)
66
67 testShards, err := copyTestShards(t.TempDir(), v16Shards)
68 if err != nil {
69 t.Fatal(err)
70 }
71 t.Log(testShards)
72
73 dir := t.TempDir()
74 err = merge(dir, testShards)
75 if err != nil {
76 t.Fatal(err)
77 }
78
79 cs, err := filepath.Glob(filepath.Join(dir, "compound-*.zoekt"))
80 if err != nil {
81 t.Fatal(err)
82 }
83 err = explode(dir, cs[0])
84 if err != nil {
85 t.Fatal(err)
86 }
87
88 cs, err = filepath.Glob(filepath.Join(dir, "compound-*.zoekt"))
89 if err != nil {
90 t.Fatal(err)
91 }
92 if len(cs) != 0 {
93 t.Fatalf("explode should have deleted the compound shard if it returned without error")
94 }
95
96 exploded, err := filepath.Glob(filepath.Join(dir, "*.zoekt"))
97 if err != nil {
98 t.Fatal(err)
99 }
100
101 if len(exploded) != len(testShards) {
102 t.Fatalf("the number of simple shards before %d and after %d should be the same", len(testShards), len(exploded))
103 }
104
105 ss, err := shards.NewDirectorySearcher(dir)
106 if err != nil {
107 t.Fatalf("NewDirectorySearcher(%s): %v", dir, err)
108 }
109 defer ss.Close()
110
111 var sOpts zoekt.SearchOptions
112 ctx := context.Background()
113
114 cases := []struct {
115 searchLiteral string
116 wantResults int
117 }{
118 {
119 searchLiteral: "apple",
120 wantResults: 1,
121 },
122 {
123 searchLiteral: "hello",
124 wantResults: 1,
125 },
126 {
127 searchLiteral: "main",
128 wantResults: 2,
129 },
130 }
131
132 for _, c := range cases {
133 t.Run(c.searchLiteral, func(t *testing.T) {
134 q, err := query.Parse(c.searchLiteral)
135 if err != nil {
136 t.Fatalf("Parse(%s): %v", c.searchLiteral, err)
137 }
138 result, err := ss.Search(ctx, q, &sOpts)
139 if err != nil {
140 t.Fatalf("Search(%v): %v", q, err)
141 }
142 if got := len(result.Files); got != c.wantResults {
143 t.Fatalf("wanted %d results, got %d", c.wantResults, got)
144 }
145 })
146 }
147}
148
149func copyTestShards(dstDir string, srcShards []string) ([]string, error) {
150 var tmpShards []string
151 for _, s := range srcShards {
152 dst := filepath.Join(dstDir, filepath.Base(s))
153 tmpShards = append(tmpShards, dst)
154 if err := copyFile(s, dst); err != nil {
155 return nil, err
156 }
157 }
158 return tmpShards, nil
159}
160
161func copyFile(src, dst string) (err error) {
162 s, err := os.Open(src)
163 if err != nil {
164 return err
165 }
166 defer s.Close()
167
168 d, err := os.Create(dst)
169 if err != nil {
170 return err
171 }
172 if _, err := io.Copy(d, s); err != nil {
173 d.Close()
174 return err
175 }
176 return d.Close()
177}