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

Configure Feed

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

1// Copyright 2018 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 search 16 17import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "testing" 22 "time" 23 24 "github.com/sourcegraph/zoekt/index" 25) 26 27type loggingLoader struct { 28 loads chan string 29 drops chan string 30} 31 32func (l *loggingLoader) load(keys ...string) { 33 for _, key := range keys { 34 l.loads <- key 35 } 36} 37 38func (l *loggingLoader) drop(keys ...string) { 39 for _, key := range keys { 40 l.drops <- key 41 } 42} 43 44func advanceFS() { 45 time.Sleep(10 * time.Millisecond) 46} 47 48func TestDirWatcherUnloadOnce(t *testing.T) { 49 dir := t.TempDir() 50 51 logger := &loggingLoader{ 52 loads: make(chan string, 10), 53 drops: make(chan string, 10), 54 } 55 // Upstream fails if empty. Sourcegraph does not 56 // _, err := NewDirectoryWatcher(dir, logger) 57 // if err == nil || !strings.Contains(err.Error(), "empty") { 58 // t.Fatalf("got %v, want 'empty'", err) 59 // } 60 61 shard := filepath.Join(dir, "foo.zoekt") 62 if err := os.WriteFile(shard, []byte("hello"), 0o644); err != nil { 63 t.Fatalf("WriteFile: %v", err) 64 } 65 66 dw, err := newDirectoryWatcher(dir, logger) 67 if err != nil { 68 t.Fatalf("NewDirectoryWatcher: %v", err) 69 } 70 defer dw.Stop() 71 72 if got := <-logger.loads; got != shard { 73 t.Fatalf("got load event %v, want %v", got, shard) 74 } 75 76 // Must sleep because of FS timestamp resolution. 77 advanceFS() 78 if err := os.WriteFile(shard, []byte("changed"), 0o644); err != nil { 79 t.Fatalf("WriteFile: %v", err) 80 } 81 82 if got := <-logger.loads; got != shard { 83 t.Fatalf("got load event %v, want %v", got, shard) 84 } 85 86 advanceFS() 87 if err := os.Remove(shard); err != nil { 88 t.Fatalf("Remove: %v", err) 89 } 90 91 if got := <-logger.drops; got != shard { 92 t.Fatalf("got drops event %v, want %v", got, shard) 93 } 94 95 advanceFS() 96 if err := os.WriteFile(shard+".bla", []byte("changed"), 0o644); err != nil { 97 t.Fatalf("WriteFile: %v", err) 98 } 99 100 dw.Stop() 101 102 // fsnotify can produce multiple events for a single write, which can lead to 103 // extra queued load notifications by the time we stop. Drain them and only 104 // assert we don't drop the same shard again. 105 for len(logger.loads) > 0 { 106 <-logger.loads 107 } 108 109 select { 110 case k := <-logger.drops: 111 t.Errorf("spurious drops of %q", k) 112 default: 113 } 114} 115 116func TestDirWatcherLoadEmpty(t *testing.T) { 117 dir := t.TempDir() 118 119 logger := &loggingLoader{ 120 loads: make(chan string, 10), 121 drops: make(chan string, 10), 122 } 123 dw, err := newDirectoryWatcher(dir, logger) 124 if err != nil { 125 t.Fatal(err) 126 } 127 advanceFS() 128 dw.Stop() 129 130 select { 131 case k := <-logger.loads: 132 t.Errorf("spurious load of %q", k) 133 case k := <-logger.drops: 134 t.Errorf("spurious drops of %q", k) 135 default: 136 } 137} 138 139func TestVersionFromPath(t *testing.T) { 140 cases := map[string]struct { 141 name string 142 version int 143 }{ 144 "github.com%2Fgoogle%2Fzoekt_v16.00000.zoekt": { 145 name: "github.com%2Fgoogle%2Fzoekt", 146 version: 16, 147 }, 148 "github.com%2Fgoogle%2Fsre_yield_v15.00000.zoekt": { 149 name: "github.com%2Fgoogle%2Fsre_yield", 150 version: 15, 151 }, 152 "repos/github.com%2Fgoogle%2Fsre_yield_v15.00000.zoekt": { 153 name: "repos/github.com%2Fgoogle%2Fsre_yield", 154 version: 15, 155 }, 156 "foo": { 157 name: "foo", 158 version: 0, 159 }, 160 "foo_bar": { 161 name: "foo_bar", 162 version: 0, 163 }, 164 "github.com%2Fgoogle%2Fzoekt_vfoo.00000.zoekt": { 165 name: "github.com%2Fgoogle%2Fzoekt_vfoo.00000.zoekt", 166 version: 0, 167 }, 168 } 169 for path, tc := range cases { 170 name, version := versionFromPath(path) 171 if name != tc.name || version != tc.version { 172 t.Errorf("%s: got name %s and version %d, want name %s and version %d", path, name, version, tc.name, tc.version) 173 } 174 } 175} 176 177func TestDirWatcherLoadLatest(t *testing.T) { 178 dir := t.TempDir() 179 180 logger := &loggingLoader{ 181 loads: make(chan string, 10), 182 drops: make(chan string, 10), 183 } 184 // Upstream fails if empty. Sourcegraph does not 185 // _, err := NewDirectoryWatcher(dir, logger) 186 // if err == nil || !strings.Contains(err.Error(), "empty") { 187 // t.Fatalf("got %v, want 'empty'", err) 188 // } 189 190 want := index.NextIndexFormatVersion 191 shardLatest := filepath.Join(dir, fmt.Sprintf("foo_v%d.00000.zoekt", want)) 192 193 for delta := -1; delta <= 1; delta++ { 194 repo := fmt.Sprintf("foo_v%d.00000.zoekt", want+delta) 195 shard := filepath.Join(dir, repo) 196 if err := os.WriteFile(shard, []byte("hello"), 0o644); err != nil { 197 t.Fatalf("WriteFile: %v", err) 198 } 199 } 200 201 dw, err := newDirectoryWatcher(dir, logger) 202 if err != nil { 203 t.Fatalf("NewDirectoryWatcher: %v", err) 204 } 205 defer dw.Stop() 206 207 if got := <-logger.loads; got != shardLatest { 208 t.Fatalf("got load event %v, want %v", got, shardLatest) 209 } 210 211 advanceFS() 212 dw.Stop() 213 214 select { 215 case k := <-logger.loads: 216 t.Errorf("spurious load of %q", k) 217 case k := <-logger.drops: 218 t.Errorf("spurious drops of %q", k) 219 default: 220 } 221} 222 223func TestHumanTruncateList(t *testing.T) { 224 paths := []string{ 225 "dir/1", 226 "dir/2", 227 "dir/3", 228 "dir/4", 229 } 230 231 assert := func(max int, want string) { 232 got := humanTruncateList(paths, max) 233 if got != want { 234 t.Errorf("unexpected humanTruncateList max=%d.\ngot: %s\nwant: %s", max, got, want) 235 } 236 } 237 238 assert(1, "1... 3 more") 239 assert(2, "1, 2... 2 more") 240 assert(3, "1, 2, 3... 1 more") 241 assert(4, "1, 2, 3, 4") 242 assert(5, "1, 2, 3, 4") 243}