blob: 788dbdd3575951c0006859581f1421036b26a2c5 [file] [log] [blame]
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001// Copyright 2017 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 finder
16
17import (
18 "fmt"
Jeff Gastonb629e182017-08-14 16:49:18 -070019 "io/ioutil"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070020 "log"
Jeff Gastonb629e182017-08-14 16:49:18 -070021 "os"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070022 "path/filepath"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070023 "sort"
Chris Parsonsa798d962020-10-12 23:44:08 -040024 "strings"
Jeff Gastonb629e182017-08-14 16:49:18 -070025 "testing"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070026
Colin Cross8d6395c2017-12-21 15:46:01 -080027 "android/soong/finder/fs"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070028)
29
30// some utils for tests to use
31func newFs() *fs.MockFs {
32 return fs.NewMockFs(map[string][]byte{})
33}
34
35func newFinder(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams) *Finder {
Jeff Gastond3119522017-08-22 14:11:15 -070036 return newFinderWithNumThreads(t, filesystem, cacheParams, 2)
37}
38
39func newFinderWithNumThreads(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) *Finder {
40 f, err := newFinderAndErr(t, filesystem, cacheParams, numThreads)
Jeff Gastonb629e182017-08-14 16:49:18 -070041 if err != nil {
Colin Cross7f8aa392020-06-29 23:00:12 -070042 t.Fatal(err.Error())
Jeff Gastonb629e182017-08-14 16:49:18 -070043 }
44 return f
45}
46
Jeff Gastond3119522017-08-22 14:11:15 -070047func newFinderAndErr(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) (*Finder, error) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070048 cachePath := "/finder/finder-db"
49 cacheDir := filepath.Dir(cachePath)
50 filesystem.MkDirs(cacheDir)
51 if cacheParams.WorkingDirectory == "" {
52 cacheParams.WorkingDirectory = "/cwd"
53 }
54
55 logger := log.New(ioutil.Discard, "", 0)
Jeff Gastond3119522017-08-22 14:11:15 -070056 f, err := newImpl(cacheParams, filesystem, logger, cachePath, numThreads)
Jeff Gastonb629e182017-08-14 16:49:18 -070057 return f, err
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070058}
59
60func finderWithSameParams(t *testing.T, original *Finder) *Finder {
Jeff Gastonb629e182017-08-14 16:49:18 -070061 f, err := finderAndErrorWithSameParams(t, original)
62 if err != nil {
Colin Cross7f8aa392020-06-29 23:00:12 -070063 t.Fatal(err.Error())
Jeff Gastonb629e182017-08-14 16:49:18 -070064 }
65 return f
66}
67
68func finderAndErrorWithSameParams(t *testing.T, original *Finder) (*Finder, error) {
Jeff Gastond3119522017-08-22 14:11:15 -070069 f, err := newImpl(
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070070 original.cacheMetadata.Config.CacheParams,
71 original.filesystem,
72 original.logger,
Jeff Gastond3119522017-08-22 14:11:15 -070073 original.DbPath,
74 original.numDbLoadingThreads,
75 )
Jeff Gastonb629e182017-08-14 16:49:18 -070076 return f, err
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070077}
78
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070079// runSimpleTests creates a few files, searches for findme.txt, and checks for the expected matches
80func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []string) {
81 filesystem := newFs()
82 root := "/tmp"
83 filesystem.MkDirs(root)
84 for _, path := range existentPaths {
Colin Cross7f8aa392020-06-29 23:00:12 -070085 fs.Create(t, filepath.Join(root, path), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070086 }
87
88 finder := newFinder(t,
89 filesystem,
90 CacheParams{
91 "/cwd",
92 []string{root},
93 nil,
94 nil,
95 []string{"findme.txt", "skipme.txt"},
Chris Parsonsa798d962020-10-12 23:44:08 -040096 nil,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070097 },
98 )
99 defer finder.Shutdown()
100
101 foundPaths := finder.FindNamedAt(root, "findme.txt")
102 absoluteMatches := []string{}
103 for i := range expectedMatches {
104 absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
105 }
Colin Cross7f8aa392020-06-29 23:00:12 -0700106 fs.AssertSameResponse(t, foundPaths, absoluteMatches)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700107}
108
Chris Parsonsa798d962020-10-12 23:44:08 -0400109// runTestWithSuffixes creates a few files, searches for findme.txt or any file
110// with suffix `.findme_ext` and checks for the expected matches
111func runTestWithSuffixes(t *testing.T, existentPaths []string, expectedMatches []string) {
112 filesystem := newFs()
113 root := "/tmp"
114 filesystem.MkDirs(root)
115 for _, path := range existentPaths {
116 fs.Create(t, filepath.Join(root, path), filesystem)
117 }
118
119 finder := newFinder(t,
120 filesystem,
121 CacheParams{
122 "/cwd",
123 []string{root},
124 nil,
125 nil,
126 []string{"findme.txt", "skipme.txt"},
127 []string{".findme_ext"},
128 },
129 )
130 defer finder.Shutdown()
131
132 foundPaths := finder.FindMatching(root,
133 func(entries DirEntries) (dirs []string, files []string) {
134 matches := []string{}
135 for _, foundName := range entries.FileNames {
136 if foundName == "findme.txt" || strings.HasSuffix(foundName, ".findme_ext") {
137 matches = append(matches, foundName)
138 }
139 }
140 return entries.DirNames, matches
141 })
142 absoluteMatches := []string{}
143 for i := range expectedMatches {
144 absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
145 }
146 fs.AssertSameResponse(t, foundPaths, absoluteMatches)
147}
148
Jeff Gastond3119522017-08-22 14:11:15 -0700149// testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
150func testAgainstSeveralThreadcounts(t *testing.T, tester func(t *testing.T, numThreads int)) {
151 // test singlethreaded, multithreaded, and also using the same number of threads as
152 // will be used on the current system
153 threadCounts := []int{1, 2, defaultNumThreads}
154 for _, numThreads := range threadCounts {
155 testName := fmt.Sprintf("%v threads", numThreads)
156 // store numThreads in a new variable to prevent numThreads from changing in each loop
157 localNumThreads := numThreads
158 t.Run(testName, func(t *testing.T) {
159 tester(t, localNumThreads)
160 })
161 }
162}
163
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700164// end of utils, start of individual tests
165
166func TestSingleFile(t *testing.T) {
167 runSimpleTest(t,
168 []string{"findme.txt"},
169 []string{"findme.txt"},
170 )
171}
172
173func TestIncludeFiles(t *testing.T) {
174 runSimpleTest(t,
175 []string{"findme.txt", "skipme.txt"},
176 []string{"findme.txt"},
177 )
178}
179
Chris Parsonsa798d962020-10-12 23:44:08 -0400180func TestIncludeFilesAndSuffixes(t *testing.T) {
181 runTestWithSuffixes(t,
182 []string{"findme.txt", "skipme.txt", "alsome.findme_ext"},
183 []string{"findme.txt", "alsome.findme_ext"},
184 )
185}
186
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700187func TestNestedDirectories(t *testing.T) {
188 runSimpleTest(t,
189 []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt"},
190 []string{"findme.txt", "subdir/findme.txt"},
191 )
192}
193
Chris Parsonsa798d962020-10-12 23:44:08 -0400194func TestNestedDirectoriesWithSuffixes(t *testing.T) {
195 runTestWithSuffixes(t,
196 []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt", "subdir/alsome.findme_ext"},
197 []string{"findme.txt", "subdir/findme.txt", "subdir/alsome.findme_ext"},
198 )
199}
200
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700201func TestEmptyDirectory(t *testing.T) {
202 runSimpleTest(t,
203 []string{},
204 []string{},
205 )
206}
207
208func TestEmptyPath(t *testing.T) {
209 filesystem := newFs()
210 root := "/tmp"
Colin Cross7f8aa392020-06-29 23:00:12 -0700211 fs.Create(t, filepath.Join(root, "findme.txt"), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700212
213 finder := newFinder(
214 t,
215 filesystem,
216 CacheParams{
217 RootDirs: []string{root},
218 IncludeFiles: []string{"findme.txt", "skipme.txt"},
219 },
220 )
221 defer finder.Shutdown()
222
223 foundPaths := finder.FindNamedAt("", "findme.txt")
224
Colin Cross7f8aa392020-06-29 23:00:12 -0700225 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700226}
227
228func TestFilesystemRoot(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700229
Jeff Gastond3119522017-08-22 14:11:15 -0700230 testWithNumThreads := func(t *testing.T, numThreads int) {
231 filesystem := newFs()
232 root := "/"
233 createdPath := "/findme.txt"
Colin Cross7f8aa392020-06-29 23:00:12 -0700234 fs.Create(t, createdPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700235
Jeff Gastond3119522017-08-22 14:11:15 -0700236 finder := newFinderWithNumThreads(
237 t,
238 filesystem,
239 CacheParams{
240 RootDirs: []string{root},
241 IncludeFiles: []string{"findme.txt", "skipme.txt"},
242 },
243 numThreads,
244 )
245 defer finder.Shutdown()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700246
Jeff Gastond3119522017-08-22 14:11:15 -0700247 foundPaths := finder.FindNamedAt(root, "findme.txt")
248
Colin Cross7f8aa392020-06-29 23:00:12 -0700249 fs.AssertSameResponse(t, foundPaths, []string{createdPath})
Jeff Gastond3119522017-08-22 14:11:15 -0700250 }
251
252 testAgainstSeveralThreadcounts(t, testWithNumThreads)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700253}
254
Jeff Gastonb629e182017-08-14 16:49:18 -0700255func TestNonexistentDir(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700256 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700257 fs.Create(t, "/tmp/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700258
Jeff Gastonb629e182017-08-14 16:49:18 -0700259 _, err := newFinderAndErr(
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700260 t,
261 filesystem,
262 CacheParams{
263 RootDirs: []string{"/tmp/IDontExist"},
264 IncludeFiles: []string{"findme.txt", "skipme.txt"},
265 },
Jeff Gastond3119522017-08-22 14:11:15 -0700266 1,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700267 )
Jeff Gastonb629e182017-08-14 16:49:18 -0700268 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -0700269 t.Fatal("Did not fail when given a nonexistent root directory")
Jeff Gastonb629e182017-08-14 16:49:18 -0700270 }
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700271}
272
273func TestExcludeDirs(t *testing.T) {
274 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700275 fs.Create(t, "/tmp/exclude/findme.txt", filesystem)
276 fs.Create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
277 fs.Create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
278 fs.Create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
279 fs.Create(t, "/tmp/subdir/findme.txt", filesystem)
280 fs.Create(t, "/tmp/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700281
282 finder := newFinder(
283 t,
284 filesystem,
285 CacheParams{
286 RootDirs: []string{"/tmp"},
287 ExcludeDirs: []string{"exclude"},
288 IncludeFiles: []string{"findme.txt", "skipme.txt"},
289 },
290 )
291 defer finder.Shutdown()
292
293 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
294
Colin Cross7f8aa392020-06-29 23:00:12 -0700295 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700296 []string{"/tmp/findme.txt",
297 "/tmp/subdir/findme.txt",
298 "/tmp/subdir/subdir/findme.txt"})
299}
300
301func TestPruneFiles(t *testing.T) {
302 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700303 fs.Create(t, "/tmp/out/findme.txt", filesystem)
304 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
305 fs.Create(t, "/tmp/out/child/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700306
Colin Cross7f8aa392020-06-29 23:00:12 -0700307 fs.Create(t, "/tmp/out2/.ignore-out-dir", filesystem)
308 fs.Create(t, "/tmp/out2/sub/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700309
Colin Cross7f8aa392020-06-29 23:00:12 -0700310 fs.Create(t, "/tmp/findme.txt", filesystem)
311 fs.Create(t, "/tmp/include/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700312
313 finder := newFinder(
314 t,
315 filesystem,
316 CacheParams{
317 RootDirs: []string{"/tmp"},
318 PruneFiles: []string{".ignore-out-dir"},
319 IncludeFiles: []string{"findme.txt"},
320 },
321 )
322 defer finder.Shutdown()
323
324 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
325
Colin Cross7f8aa392020-06-29 23:00:12 -0700326 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700327 []string{"/tmp/findme.txt",
328 "/tmp/include/findme.txt"})
329}
330
Jeff Gastond3119522017-08-22 14:11:15 -0700331// TestRootDir tests that the value of RootDirs is used
332// tests of the filesystem root are in TestFilesystemRoot
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700333func TestRootDir(t *testing.T) {
334 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700335 fs.Create(t, "/tmp/a/findme.txt", filesystem)
336 fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
337 fs.Create(t, "/tmp/b/findme.txt", filesystem)
338 fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700339
340 finder := newFinder(
341 t,
342 filesystem,
343 CacheParams{
344 RootDirs: []string{"/tmp/a"},
345 IncludeFiles: []string{"findme.txt"},
346 },
347 )
348 defer finder.Shutdown()
349
350 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
351
Colin Cross7f8aa392020-06-29 23:00:12 -0700352 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700353 []string{"/tmp/a/findme.txt",
354 "/tmp/a/subdir/findme.txt"})
355}
356
357func TestUncachedDir(t *testing.T) {
358 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700359 fs.Create(t, "/tmp/a/findme.txt", filesystem)
360 fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
361 fs.Create(t, "/tmp/b/findme.txt", filesystem)
362 fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700363
364 finder := newFinder(
365 t,
366 filesystem,
367 CacheParams{
Jeff Gastonb629e182017-08-14 16:49:18 -0700368 RootDirs: []string{"/tmp/b"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700369 IncludeFiles: []string{"findme.txt"},
370 },
371 )
372
373 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
374 // If the caller queries for a file that is in the cache, then computing the
375 // correct answer won't be fast, and it would be easy for the caller to
376 // fail to notice its slowness. Instead, we only ever search the cache for files
377 // to return, which enforces that we can determine which files will be
378 // interesting upfront.
Colin Cross7f8aa392020-06-29 23:00:12 -0700379 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700380
381 finder.Shutdown()
382}
383
384func TestSearchingForFilesExcludedFromCache(t *testing.T) {
385 // setup filesystem
386 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700387 fs.Create(t, "/tmp/findme.txt", filesystem)
388 fs.Create(t, "/tmp/a/findme.txt", filesystem)
389 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700390
391 // set up the finder and run it
392 finder := newFinder(
393 t,
394 filesystem,
395 CacheParams{
396 RootDirs: []string{"/tmp"},
397 IncludeFiles: []string{"findme.txt"},
398 },
399 )
400 foundPaths := finder.FindNamedAt("/tmp", "misc.txt")
401 // If the caller queries for a file that is in the cache, then computing the
402 // correct answer won't be fast, and it would be easy for the caller to
403 // fail to notice its slowness. Instead, we only ever search the cache for files
404 // to return, which enforces that we can determine which files will be
405 // interesting upfront.
Colin Cross7f8aa392020-06-29 23:00:12 -0700406 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700407
408 finder.Shutdown()
409}
410
411func TestRelativeFilePaths(t *testing.T) {
412 filesystem := newFs()
413
Colin Cross7f8aa392020-06-29 23:00:12 -0700414 fs.Create(t, "/tmp/ignore/hi.txt", filesystem)
415 fs.Create(t, "/tmp/include/hi.txt", filesystem)
416 fs.Create(t, "/cwd/hi.txt", filesystem)
417 fs.Create(t, "/cwd/a/hi.txt", filesystem)
418 fs.Create(t, "/cwd/a/a/hi.txt", filesystem)
419 fs.Create(t, "/rel/a/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700420
421 finder := newFinder(
422 t,
423 filesystem,
424 CacheParams{
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700425 RootDirs: []string{"/cwd", "../rel", "/tmp/include"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700426 IncludeFiles: []string{"hi.txt"},
427 },
428 )
429 defer finder.Shutdown()
430
431 foundPaths := finder.FindNamedAt("a", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700432 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700433 []string{"a/hi.txt",
434 "a/a/hi.txt"})
435
436 foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700437 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700438
439 foundPaths = finder.FindNamedAt(".", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700440 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700441 []string{"hi.txt",
442 "a/hi.txt",
443 "a/a/hi.txt"})
444
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700445 foundPaths = finder.FindNamedAt("/rel", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700446 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700447 []string{"/rel/a/hi.txt"})
448
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700449 foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700450 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700451}
452
453// have to run this test with the race-detector (`go test -race src/android/soong/finder/*.go`)
454// for there to be much chance of the test actually detecting any error that may be present
455func TestRootDirsContainedInOtherRootDirs(t *testing.T) {
456 filesystem := newFs()
457
Colin Cross7f8aa392020-06-29 23:00:12 -0700458 fs.Create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700459
460 finder := newFinder(
461 t,
462 filesystem,
463 CacheParams{
Jeff Gastonb629e182017-08-14 16:49:18 -0700464 RootDirs: []string{"/", "/tmp/a/b/c", "/tmp/a/b/c/d/e/f", "/tmp/a/b/c/d/e/f/g/h/i"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700465 IncludeFiles: []string{"findme.txt"},
466 },
467 )
468 defer finder.Shutdown()
469
470 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
471
Colin Cross7f8aa392020-06-29 23:00:12 -0700472 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700473 []string{"/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt"})
474}
475
476func TestFindFirst(t *testing.T) {
477 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700478 fs.Create(t, "/tmp/a/hi.txt", filesystem)
479 fs.Create(t, "/tmp/b/hi.txt", filesystem)
480 fs.Create(t, "/tmp/b/a/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700481
482 finder := newFinder(
483 t,
484 filesystem,
485 CacheParams{
486 RootDirs: []string{"/tmp"},
487 IncludeFiles: []string{"hi.txt"},
488 },
489 )
490 defer finder.Shutdown()
491
492 foundPaths := finder.FindFirstNamed("hi.txt")
493
Colin Cross7f8aa392020-06-29 23:00:12 -0700494 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700495 []string{"/tmp/a/hi.txt",
496 "/tmp/b/hi.txt"},
497 )
498}
499
500func TestConcurrentFindSameDirectory(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700501
Jeff Gastond3119522017-08-22 14:11:15 -0700502 testWithNumThreads := func(t *testing.T, numThreads int) {
503 filesystem := newFs()
504
505 // create a bunch of files and directories
506 paths := []string{}
507 for i := 0; i < 10; i++ {
508 parentDir := fmt.Sprintf("/tmp/%v", i)
509 for j := 0; j < 10; j++ {
510 filePath := filepath.Join(parentDir, fmt.Sprintf("%v/findme.txt", j))
511 paths = append(paths, filePath)
512 }
513 }
514 sort.Strings(paths)
515 for _, path := range paths {
Colin Cross7f8aa392020-06-29 23:00:12 -0700516 fs.Create(t, path, filesystem)
Jeff Gastond3119522017-08-22 14:11:15 -0700517 }
518
519 // set up a finder
520 finder := newFinderWithNumThreads(
521 t,
522 filesystem,
523 CacheParams{
524 RootDirs: []string{"/tmp"},
525 IncludeFiles: []string{"findme.txt"},
526 },
527 numThreads,
528 )
529 defer finder.Shutdown()
530
531 numTests := 20
532 results := make(chan []string, numTests)
533 // make several parallel calls to the finder
534 for i := 0; i < numTests; i++ {
535 go func() {
536 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
537 results <- foundPaths
538 }()
539 }
540
541 // check that each response was correct
542 for i := 0; i < numTests; i++ {
543 foundPaths := <-results
Colin Cross7f8aa392020-06-29 23:00:12 -0700544 fs.AssertSameResponse(t, foundPaths, paths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700545 }
546 }
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700547
Jeff Gastond3119522017-08-22 14:11:15 -0700548 testAgainstSeveralThreadcounts(t, testWithNumThreads)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700549}
550
551func TestConcurrentFindDifferentDirectories(t *testing.T) {
552 filesystem := newFs()
553
554 // create a bunch of files and directories
555 allFiles := []string{}
556 numSubdirs := 10
557 rootPaths := []string{}
558 queryAnswers := [][]string{}
559 for i := 0; i < numSubdirs; i++ {
560 parentDir := fmt.Sprintf("/tmp/%v", i)
561 rootPaths = append(rootPaths, parentDir)
562 queryAnswers = append(queryAnswers, []string{})
563 for j := 0; j < 10; j++ {
564 filePath := filepath.Join(parentDir, fmt.Sprintf("%v/findme.txt", j))
565 queryAnswers[i] = append(queryAnswers[i], filePath)
566 allFiles = append(allFiles, filePath)
567 }
568 sort.Strings(queryAnswers[i])
569 }
570 sort.Strings(allFiles)
571 for _, path := range allFiles {
Colin Cross7f8aa392020-06-29 23:00:12 -0700572 fs.Create(t, path, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700573 }
574
575 // set up a finder
576 finder := newFinder(
577 t,
578 filesystem,
579
580 CacheParams{
581 RootDirs: []string{"/tmp"},
582 IncludeFiles: []string{"findme.txt"},
583 },
584 )
585 defer finder.Shutdown()
586
587 type testRun struct {
588 path string
589 foundMatches []string
590 correctMatches []string
591 }
592
593 numTests := numSubdirs + 1
594 testRuns := make(chan testRun, numTests)
595
596 searchAt := func(path string, correctMatches []string) {
597 foundPaths := finder.FindNamedAt(path, "findme.txt")
598 testRuns <- testRun{path, foundPaths, correctMatches}
599 }
600
601 // make several parallel calls to the finder
602 go searchAt("/tmp", allFiles)
603 for i := 0; i < len(rootPaths); i++ {
604 go searchAt(rootPaths[i], queryAnswers[i])
605 }
606
607 // check that each response was correct
608 for i := 0; i < numTests; i++ {
609 testRun := <-testRuns
Colin Cross7f8aa392020-06-29 23:00:12 -0700610 fs.AssertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700611 }
612}
613
614func TestStrangelyFormattedPaths(t *testing.T) {
615 filesystem := newFs()
616
Colin Cross7f8aa392020-06-29 23:00:12 -0700617 fs.Create(t, "/tmp/findme.txt", filesystem)
618 fs.Create(t, "/tmp/a/findme.txt", filesystem)
619 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700620
621 finder := newFinder(
622 t,
623 filesystem,
624 CacheParams{
625 RootDirs: []string{"//tmp//a//.."},
626 IncludeFiles: []string{"findme.txt"},
627 },
628 )
629 defer finder.Shutdown()
630
631 foundPaths := finder.FindNamedAt("//tmp//a//..", "findme.txt")
632
Colin Cross7f8aa392020-06-29 23:00:12 -0700633 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700634 []string{"/tmp/a/findme.txt",
635 "/tmp/b/findme.txt",
636 "/tmp/findme.txt"})
637}
638
639func TestCorruptedCacheHeader(t *testing.T) {
640 filesystem := newFs()
641
Colin Cross7f8aa392020-06-29 23:00:12 -0700642 fs.Create(t, "/tmp/findme.txt", filesystem)
643 fs.Create(t, "/tmp/a/findme.txt", filesystem)
644 fs.Write(t, "/finder/finder-db", "sample header", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700645
646 finder := newFinder(
647 t,
648 filesystem,
649 CacheParams{
650 RootDirs: []string{"/tmp"},
651 IncludeFiles: []string{"findme.txt"},
652 },
653 )
654 defer finder.Shutdown()
655
656 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
657
Colin Cross7f8aa392020-06-29 23:00:12 -0700658 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700659 []string{"/tmp/a/findme.txt",
660 "/tmp/findme.txt"})
661}
662
663func TestCanUseCache(t *testing.T) {
664 // setup filesystem
665 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700666 fs.Create(t, "/tmp/findme.txt", filesystem)
667 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700668
669 // run the first finder
670 finder := newFinder(
671 t,
672 filesystem,
673 CacheParams{
674 RootDirs: []string{"/tmp"},
675 IncludeFiles: []string{"findme.txt"},
676 },
677 )
678 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
679 // check the response of the first finder
680 correctResponse := []string{"/tmp/a/findme.txt",
681 "/tmp/findme.txt"}
Colin Cross7f8aa392020-06-29 23:00:12 -0700682 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700683 finder.Shutdown()
684
685 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700686 cacheText := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700687 if len(cacheText) < 1 {
688 t.Fatalf("saved cache db is empty\n")
689 }
690 if len(filesystem.StatCalls) == 0 {
691 t.Fatal("No Stat calls recorded by mock filesystem")
692 }
693 if len(filesystem.ReadDirCalls) == 0 {
694 t.Fatal("No ReadDir calls recorded by filesystem")
695 }
696 statCalls := filesystem.StatCalls
697 filesystem.ClearMetrics()
698
699 // run the second finder
700 finder2 := finderWithSameParams(t, finder)
701 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
702 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700703 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
704 fs.AssertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700705
706 finder2.Shutdown()
707}
708
709func TestCorruptedCacheBody(t *testing.T) {
710 // setup filesystem
711 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700712 fs.Create(t, "/tmp/findme.txt", filesystem)
713 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700714
715 // run the first finder
716 finder := newFinder(
717 t,
718 filesystem,
719 CacheParams{
720 RootDirs: []string{"/tmp"},
721 IncludeFiles: []string{"findme.txt"},
722 },
723 )
724 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
725 finder.Shutdown()
726
727 // check the response of the first finder
728 correctResponse := []string{"/tmp/a/findme.txt",
729 "/tmp/findme.txt"}
Colin Cross7f8aa392020-06-29 23:00:12 -0700730 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700731 numStatCalls := len(filesystem.StatCalls)
732 numReadDirCalls := len(filesystem.ReadDirCalls)
733
734 // load the cache file, corrupt it, and save it
735 cacheReader, err := filesystem.Open(finder.DbPath)
736 if err != nil {
737 t.Fatal(err)
738 }
739 cacheData, err := ioutil.ReadAll(cacheReader)
740 if err != nil {
741 t.Fatal(err)
742 }
743 cacheData = append(cacheData, []byte("DontMindMe")...)
744 filesystem.WriteFile(finder.DbPath, cacheData, 0777)
745 filesystem.ClearMetrics()
746
747 // run the second finder
748 finder2 := finderWithSameParams(t, finder)
749 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
750 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700751 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700752 numNewStatCalls := len(filesystem.StatCalls)
753 numNewReadDirCalls := len(filesystem.ReadDirCalls)
754 // It's permissable to make more Stat calls with a corrupted cache because
755 // the Finder may restart once it detects corruption.
756 // However, it may have already issued many Stat calls.
757 // Because a corrupted db is not expected to be a common (or even a supported case),
758 // we don't care to optimize it and don't cache the already-issued Stat calls
759 if numNewReadDirCalls < numReadDirCalls {
760 t.Fatalf(
761 "Finder made fewer ReadDir calls with a corrupted cache (%v calls) than with no cache"+
762 " (%v calls)",
763 numNewReadDirCalls, numReadDirCalls)
764 }
765 if numNewStatCalls < numStatCalls {
766 t.Fatalf(
767 "Finder made fewer Stat calls with a corrupted cache (%v calls) than with no cache (%v calls)",
768 numNewStatCalls, numStatCalls)
769 }
770 finder2.Shutdown()
771}
772
773func TestStatCalls(t *testing.T) {
774 // setup filesystem
775 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700776 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700777
778 // run finder
779 finder := newFinder(
780 t,
781 filesystem,
782 CacheParams{
783 RootDirs: []string{"/tmp"},
784 IncludeFiles: []string{"findme.txt"},
785 },
786 )
787 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
788 finder.Shutdown()
789
790 // check response
Colin Cross7f8aa392020-06-29 23:00:12 -0700791 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
792 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
793 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700794}
795
796func TestFileAdded(t *testing.T) {
797 // setup filesystem
798 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700799 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
800 fs.Create(t, "/tmp/a/findme.txt", filesystem)
801 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
802 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
803 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700804
805 // run the first finder
806 finder := newFinder(
807 t,
808 filesystem,
809 CacheParams{
810 RootDirs: []string{"/tmp"},
811 IncludeFiles: []string{"findme.txt"},
812 },
813 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700814 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -0700815 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700816 finder.Shutdown()
817 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700818 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700819
820 // modify the filesystem
821 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700822 fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700823 filesystem.Clock.Tick()
824 filesystem.ClearMetrics()
825
826 // run the second finder
827 finder2 := finderWithSameParams(t, finder)
828 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
829
830 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700831 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
832 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
833 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700834 finder2.Shutdown()
835
836}
837
838func TestDirectoriesAdded(t *testing.T) {
839 // setup filesystem
840 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700841 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
842 fs.Create(t, "/tmp/a/findme.txt", filesystem)
843 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
844 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
845 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700846
847 // run the first finder
848 finder := newFinder(
849 t,
850 filesystem,
851 CacheParams{
852 RootDirs: []string{"/tmp"},
853 IncludeFiles: []string{"findme.txt"},
854 },
855 )
856 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
857 finder.Shutdown()
858 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700859 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700860
861 // modify the filesystem
862 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700863 fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
864 fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
865 fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700866 filesystem.ClearMetrics()
867
868 // run the second finder
869 finder2 := finderWithSameParams(t, finder)
870 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
871
872 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700873 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700874 []string{"/tmp/a/findme.txt", "/tmp/b/c/new/findme.txt", "/tmp/b/c/new/new2/findme.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700875 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700876 []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700877 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700878
879 finder2.Shutdown()
880}
881
882func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
883 // setup filesystem
884 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700885 fs.Create(t, "/tmp/hi1.txt", filesystem)
886 fs.Create(t, "/tmp/a/hi1.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700887
888 // run the first finder
889 finder := newFinder(
890 t,
891 filesystem,
892 CacheParams{
893 RootDirs: []string{"/tmp"},
894 IncludeFiles: []string{"hi1.txt", "hi2.txt"},
895 },
896 )
897 foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
898 finder.Shutdown()
899 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700900 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700901
902 // modify the filesystem
903 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700904 fs.Create(t, "/tmp/hi2.txt", filesystem)
905 fs.Create(t, "/tmp/a/hi2.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700906 filesystem.ClearMetrics()
907
908 // run the second finder
909 finder2 := finderWithSameParams(t, finder)
910 foundPaths = finder2.FindAll()
911
912 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700913 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700914 []string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700915 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700916 []string{"/tmp", "/tmp/a"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700917 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700918
919 finder2.Shutdown()
920}
921
922func TestFileDeleted(t *testing.T) {
923 // setup filesystem
924 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700925 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
926 fs.Create(t, "/tmp/a/findme.txt", filesystem)
927 fs.Create(t, "/tmp/b/findme.txt", filesystem)
928 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
929 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700930
931 // run the first finder
932 finder := newFinder(
933 t,
934 filesystem,
935 CacheParams{
936 RootDirs: []string{"/tmp"},
937 IncludeFiles: []string{"findme.txt"},
938 },
939 )
940 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
941 finder.Shutdown()
942 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700943 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700944
945 // modify the filesystem
946 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700947 fs.Delete(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700948 filesystem.ClearMetrics()
949
950 // run the second finder
951 finder2 := finderWithSameParams(t, finder)
952 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
953
954 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700955 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
956 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
957 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700958
959 finder2.Shutdown()
960}
961
962func TestDirectoriesDeleted(t *testing.T) {
963 // setup filesystem
964 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700965 fs.Create(t, "/tmp/findme.txt", filesystem)
966 fs.Create(t, "/tmp/a/findme.txt", filesystem)
967 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
968 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
969 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700970
971 // run the first finder
972 finder := newFinder(
973 t,
974 filesystem,
975 CacheParams{
976 RootDirs: []string{"/tmp"},
977 IncludeFiles: []string{"findme.txt"},
978 },
979 )
980 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
981 finder.Shutdown()
982 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700983 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700984 []string{"/tmp/findme.txt",
985 "/tmp/a/findme.txt",
986 "/tmp/a/1/findme.txt",
987 "/tmp/a/1/2/findme.txt",
988 "/tmp/b/findme.txt"})
989
990 // modify the filesystem
991 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700992 fs.RemoveAll(t, "/tmp/a/1", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700993 filesystem.ClearMetrics()
994
995 // run the second finder
996 finder2 := finderWithSameParams(t, finder)
997 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
998
999 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001000 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001001 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/findme.txt"})
1002 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1003 // if the Finder detects the nonexistence of /tmp/a/1
1004 // However, when resuming from cache, we don't want the Finder to necessarily wait
1005 // to stat a directory until after statting its parent.
1006 // So here we just include /tmp/a/1/2 in the list.
1007 // The Finder is currently implemented to always restat every dir and
1008 // to not short-circuit due to nonexistence of parents (but it will remove
1009 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001010 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001011 []string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001012 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001013
1014 finder2.Shutdown()
1015}
1016
1017func TestDirectoriesMoved(t *testing.T) {
1018 // setup filesystem
1019 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001020 fs.Create(t, "/tmp/findme.txt", filesystem)
1021 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1022 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
1023 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
1024 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001025
1026 // run the first finder
1027 finder := newFinder(
1028 t,
1029 filesystem,
1030 CacheParams{
1031 RootDirs: []string{"/tmp"},
1032 IncludeFiles: []string{"findme.txt"},
1033 },
1034 )
1035 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1036 finder.Shutdown()
1037 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001038 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001039 []string{"/tmp/findme.txt",
1040 "/tmp/a/findme.txt",
1041 "/tmp/a/1/findme.txt",
1042 "/tmp/a/1/2/findme.txt",
1043 "/tmp/b/findme.txt"})
1044
1045 // modify the filesystem
1046 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001047 fs.Move(t, "/tmp/a", "/tmp/c", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001048 filesystem.ClearMetrics()
1049
1050 // run the second finder
1051 finder2 := finderWithSameParams(t, finder)
1052 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1053
1054 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001055 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001056 []string{"/tmp/findme.txt",
1057 "/tmp/b/findme.txt",
1058 "/tmp/c/findme.txt",
1059 "/tmp/c/1/findme.txt",
1060 "/tmp/c/1/2/findme.txt"})
1061 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1062 // if the Finder detects the nonexistence of /tmp/a/1
1063 // However, when resuming from cache, we don't want the Finder to necessarily wait
1064 // to stat a directory until after statting its parent.
1065 // So here we just include /tmp/a/1/2 in the list.
1066 // The Finder is currently implemented to always restat every dir and
1067 // to not short-circuit due to nonexistence of parents (but it will remove
1068 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001069 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001070 []string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001071 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001072 finder2.Shutdown()
1073}
1074
1075func TestDirectoriesSwapped(t *testing.T) {
1076 // setup filesystem
1077 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001078 fs.Create(t, "/tmp/findme.txt", filesystem)
1079 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1080 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
1081 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
1082 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001083
1084 // run the first finder
1085 finder := newFinder(
1086 t,
1087 filesystem,
1088 CacheParams{
1089 RootDirs: []string{"/tmp"},
1090 IncludeFiles: []string{"findme.txt"},
1091 },
1092 )
1093 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1094 finder.Shutdown()
1095 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001096 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001097 []string{"/tmp/findme.txt",
1098 "/tmp/a/findme.txt",
1099 "/tmp/a/1/findme.txt",
1100 "/tmp/a/1/2/findme.txt",
1101 "/tmp/b/findme.txt"})
1102
1103 // modify the filesystem
1104 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001105 fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
1106 fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
1107 fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001108 filesystem.ClearMetrics()
1109
1110 // run the second finder
1111 finder2 := finderWithSameParams(t, finder)
1112 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1113
1114 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001115 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001116 []string{"/tmp/findme.txt",
1117 "/tmp/a/findme.txt",
1118 "/tmp/b/findme.txt",
1119 "/tmp/b/1/findme.txt",
1120 "/tmp/b/1/2/findme.txt"})
1121 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1122 // if the Finder detects the nonexistence of /tmp/a/1
1123 // However, when resuming from cache, we don't want the Finder to necessarily wait
1124 // to stat a directory until after statting its parent.
1125 // So here we just include /tmp/a/1/2 in the list.
1126 // The Finder is currently implemented to always restat every dir and
1127 // to not short-circuit due to nonexistence of parents (but it will remove
1128 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001129 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001130 []string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001131 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001132 finder2.Shutdown()
1133}
1134
1135// runFsReplacementTest tests a change modifying properties of the filesystem itself:
1136// runFsReplacementTest tests changing the user, the hostname, or the device number
1137// runFsReplacementTest is a helper method called by other tests
1138func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
1139 // setup fs1
Colin Cross7f8aa392020-06-29 23:00:12 -07001140 fs.Create(t, "/tmp/findme.txt", fs1)
1141 fs.Create(t, "/tmp/a/findme.txt", fs1)
1142 fs.Create(t, "/tmp/a/a/findme.txt", fs1)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001143
1144 // setup fs2 to have the same directories but different files
Colin Cross7f8aa392020-06-29 23:00:12 -07001145 fs.Create(t, "/tmp/findme.txt", fs2)
1146 fs.Create(t, "/tmp/a/findme.txt", fs2)
1147 fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
1148 fs.Create(t, "/tmp/a/b/findme.txt", fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001149
1150 // run the first finder
1151 finder := newFinder(
1152 t,
1153 fs1,
1154 CacheParams{
1155 RootDirs: []string{"/tmp"},
1156 IncludeFiles: []string{"findme.txt"},
1157 },
1158 )
1159 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1160 finder.Shutdown()
1161 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001162 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001163 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
1164
1165 // copy the cache data from the first filesystem to the second
Colin Cross7f8aa392020-06-29 23:00:12 -07001166 cacheContent := fs.Read(t, finder.DbPath, fs1)
1167 fs.Write(t, finder.DbPath, cacheContent, fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001168
1169 // run the second finder, with the same config and same cache contents but a different filesystem
1170 finder2 := newFinder(
1171 t,
1172 fs2,
1173 CacheParams{
1174 RootDirs: []string{"/tmp"},
1175 IncludeFiles: []string{"findme.txt"},
1176 },
1177 )
1178 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1179
1180 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001181 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001182 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001183 fs.AssertSameStatCalls(t, fs2.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001184 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001185 fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001186 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
1187 finder2.Shutdown()
1188}
1189
1190func TestChangeOfDevice(t *testing.T) {
1191 fs1 := newFs()
1192 // not as fine-grained mounting controls as a real filesystem, but should be adequate
1193 fs1.SetDeviceNumber(0)
1194
1195 fs2 := newFs()
1196 fs2.SetDeviceNumber(1)
1197
1198 runFsReplacementTest(t, fs1, fs2)
1199}
1200
1201func TestChangeOfUserOrHost(t *testing.T) {
1202 fs1 := newFs()
1203 fs1.SetViewId("me@here")
1204
1205 fs2 := newFs()
1206 fs2.SetViewId("you@there")
1207
1208 runFsReplacementTest(t, fs1, fs2)
1209}
1210
1211func TestConsistentCacheOrdering(t *testing.T) {
1212 // setup filesystem
1213 filesystem := newFs()
1214 for i := 0; i < 5; i++ {
Colin Cross7f8aa392020-06-29 23:00:12 -07001215 fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001216 }
1217
1218 // run the first finder
1219 finder := newFinder(
1220 t,
1221 filesystem,
1222 CacheParams{
1223 RootDirs: []string{"/tmp"},
1224 IncludeFiles: []string{"findme.txt"},
1225 },
1226 )
1227 finder.FindNamedAt("/tmp", "findme.txt")
1228 finder.Shutdown()
1229
1230 // read db file
Colin Cross7f8aa392020-06-29 23:00:12 -07001231 string1 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001232
1233 err := filesystem.Remove(finder.DbPath)
1234 if err != nil {
1235 t.Fatal(err)
1236 }
1237
1238 // run another finder
1239 finder2 := finderWithSameParams(t, finder)
1240 finder2.FindNamedAt("/tmp", "findme.txt")
1241 finder2.Shutdown()
1242
Colin Cross7f8aa392020-06-29 23:00:12 -07001243 string2 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001244
1245 if string1 != string2 {
1246 t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
1247 "Content of first file:\n"+
1248 "\n"+
1249 "%v"+
1250 "\n"+
1251 "\n"+
1252 "Content of second file:\n"+
1253 "\n"+
1254 "%v\n"+
1255 "\n",
1256 string1,
1257 string2,
1258 )
1259 }
1260
1261}
1262
1263func TestNumSyscallsOfSecondFind(t *testing.T) {
1264 // setup filesystem
1265 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001266 fs.Create(t, "/tmp/findme.txt", filesystem)
1267 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1268 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001269
1270 // set up the finder and run it once
1271 finder := newFinder(
1272 t,
1273 filesystem,
1274 CacheParams{
1275 RootDirs: []string{"/tmp"},
1276 IncludeFiles: []string{"findme.txt"},
1277 },
1278 )
1279 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001280 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001281
1282 filesystem.ClearMetrics()
1283
1284 // run the finder again and confirm it doesn't check the filesystem
1285 refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001286 fs.AssertSameResponse(t, refoundPaths, foundPaths)
1287 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1288 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001289
1290 finder.Shutdown()
1291}
1292
1293func TestChangingParamsOfSecondFind(t *testing.T) {
1294 // setup filesystem
1295 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001296 fs.Create(t, "/tmp/findme.txt", filesystem)
1297 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1298 fs.Create(t, "/tmp/a/metoo.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001299
1300 // set up the finder and run it once
1301 finder := newFinder(
1302 t,
1303 filesystem,
1304 CacheParams{
1305 RootDirs: []string{"/tmp"},
1306 IncludeFiles: []string{"findme.txt", "metoo.txt"},
1307 },
1308 )
1309 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001310 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001311
1312 filesystem.ClearMetrics()
1313
1314 // run the finder again and confirm it gets the right answer without asking the filesystem
1315 refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001316 fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
1317 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1318 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001319
1320 finder.Shutdown()
1321}
1322
1323func TestSymlinkPointingToFile(t *testing.T) {
1324 // setup filesystem
1325 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001326 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1327 fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
1328 fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
1329 fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
1330 fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
1331 fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
1332 fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
1333 fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
1334 fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001335
1336 // set up the finder and run it once
1337 finder := newFinder(
1338 t,
1339 filesystem,
1340 CacheParams{
1341 RootDirs: []string{"/tmp"},
1342 IncludeFiles: []string{"hi.txt"},
1343 },
1344 )
1345 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1346 // should search based on the name of the link rather than the destination or validity of the link
1347 correctResponse := []string{
1348 "/tmp/a/hi.txt",
1349 "/tmp/hi.txt",
1350 "/tmp/b/hi.txt",
1351 "/tmp/c/hi.txt",
1352 "/tmp/d/hi.txt",
1353 "/tmp/f/hi.txt",
1354 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001355 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001356
1357}
1358
1359func TestSymlinkPointingToDirectory(t *testing.T) {
1360 // setup filesystem
1361 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001362 fs.Create(t, "/tmp/dir/hi.txt", filesystem)
1363 fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001364
Colin Cross7f8aa392020-06-29 23:00:12 -07001365 fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
1366 fs.Link(t, "/tmp/links/link", "../dir", filesystem)
Colin Cross25fd7732020-06-29 23:11:55 -07001367 fs.Link(t, "/tmp/links/hi.txt", "../dir", filesystem)
Colin Cross7f8aa392020-06-29 23:00:12 -07001368 fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
1369 fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001370
1371 // set up the finder and run it once
1372 finder := newFinder(
1373 t,
1374 filesystem,
1375 CacheParams{
1376 RootDirs: []string{"/tmp"},
1377 IncludeFiles: []string{"hi.txt"},
1378 },
1379 )
1380
1381 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1382
1383 // should completely ignore symlinks that point to directories
1384 correctResponse := []string{
1385 "/tmp/dir/hi.txt",
1386 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001387 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001388
1389}
1390
1391// TestAddPruneFile confirms that adding a prune-file (into a directory for which we
1392// already had a cache) causes the directory to be ignored
1393func TestAddPruneFile(t *testing.T) {
1394 // setup filesystem
1395 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001396 fs.Create(t, "/tmp/out/hi.txt", filesystem)
1397 fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
1398 fs.Create(t, "/tmp/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001399
1400 // do find
1401 finder := newFinder(
1402 t,
1403 filesystem,
1404 CacheParams{
1405 RootDirs: []string{"/tmp"},
1406 PruneFiles: []string{".ignore-out-dir"},
1407 IncludeFiles: []string{"hi.txt"},
1408 },
1409 )
1410
1411 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1412
1413 // check result
Colin Cross7f8aa392020-06-29 23:00:12 -07001414 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001415 []string{"/tmp/hi.txt",
1416 "/tmp/out/hi.txt",
1417 "/tmp/out/a/hi.txt"},
1418 )
1419 finder.Shutdown()
1420
1421 // modify filesystem
1422 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001423 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001424 // run another find and check its result
1425 finder2 := finderWithSameParams(t, finder)
1426 foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001427 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001428 finder2.Shutdown()
1429}
1430
1431func TestUpdatingDbIffChanged(t *testing.T) {
1432 // setup filesystem
1433 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001434 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1435 fs.Create(t, "/tmp/b/bye.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001436
1437 // run the first finder
1438 finder := newFinder(
1439 t,
1440 filesystem,
1441 CacheParams{
1442 RootDirs: []string{"/tmp"},
1443 IncludeFiles: []string{"hi.txt"},
1444 },
1445 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001446 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001447 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001448 finder.Shutdown()
1449 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001450 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001451
1452 // modify the filesystem
1453 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001454 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001455 filesystem.Clock.Tick()
1456 filesystem.ClearMetrics()
1457
1458 // run the second finder
1459 finder2 := finderWithSameParams(t, finder)
1460 foundPaths = finder2.FindAll()
1461 finder2.Shutdown()
1462 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001463 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1464 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001465 expectedDbWriteTime := filesystem.Clock.Time()
Colin Cross7f8aa392020-06-29 23:00:12 -07001466 actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001467 if actualDbWriteTime != expectedDbWriteTime {
1468 t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
1469 expectedDbWriteTime, actualDbWriteTime)
1470 }
1471
1472 // reset metrics
1473 filesystem.ClearMetrics()
1474
1475 // run the third finder
1476 finder3 := finderWithSameParams(t, finder2)
1477 foundPaths = finder3.FindAll()
1478
1479 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001480 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1481 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001482 finder3.Shutdown()
Colin Cross7f8aa392020-06-29 23:00:12 -07001483 actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001484 if actualDbWriteTime != expectedDbWriteTime {
1485 t.Fatalf("Re-wrote db even when contents did not change")
1486 }
1487
1488}
1489
1490func TestDirectoryNotPermitted(t *testing.T) {
1491 // setup filesystem
1492 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001493 fs.Create(t, "/tmp/hi.txt", filesystem)
1494 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1495 fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
1496 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001497
1498 // run the first finder
1499 finder := newFinder(
1500 t,
1501 filesystem,
1502 CacheParams{
1503 RootDirs: []string{"/tmp"},
1504 IncludeFiles: []string{"hi.txt"},
1505 },
1506 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001507 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001508 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001509 finder.Shutdown()
1510 allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
1511 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001512 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001513
1514 // modify the filesystem
1515 filesystem.Clock.Tick()
1516
Colin Cross7f8aa392020-06-29 23:00:12 -07001517 fs.SetReadable(t, "/tmp/a", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001518 filesystem.Clock.Tick()
1519
1520 // run the second finder
1521 finder2 := finderWithSameParams(t, finder)
1522 foundPaths = finder2.FindAll()
1523 finder2.Shutdown()
1524 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001525 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001526
1527 // modify the filesystem back
Colin Cross7f8aa392020-06-29 23:00:12 -07001528 fs.SetReadable(t, "/tmp/a", true, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001529
1530 // run the third finder
1531 finder3 := finderWithSameParams(t, finder2)
1532 foundPaths = finder3.FindAll()
1533 finder3.Shutdown()
1534 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001535 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001536}
1537
1538func TestFileNotPermitted(t *testing.T) {
1539 // setup filesystem
1540 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001541 fs.Create(t, "/tmp/hi.txt", filesystem)
1542 fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001543
1544 // run the first finder
1545 finder := newFinder(
1546 t,
1547 filesystem,
1548 CacheParams{
1549 RootDirs: []string{"/tmp"},
1550 IncludeFiles: []string{"hi.txt"},
1551 },
1552 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001553 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001554 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001555 finder.Shutdown()
1556 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001557 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001558}
Jeff Gastonb629e182017-08-14 16:49:18 -07001559
1560func TestCacheEntryPathUnexpectedError(t *testing.T) {
1561 // setup filesystem
1562 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001563 fs.Create(t, "/tmp/a/hi.txt", filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001564
1565 // run the first finder
1566 finder := newFinder(
1567 t,
1568 filesystem,
1569 CacheParams{
1570 RootDirs: []string{"/tmp"},
1571 IncludeFiles: []string{"hi.txt"},
1572 },
1573 )
Jeff Gastonb629e182017-08-14 16:49:18 -07001574 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001575 foundPaths := finder.FindAll()
Jeff Gastonb629e182017-08-14 16:49:18 -07001576 finder.Shutdown()
1577 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001578 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonb629e182017-08-14 16:49:18 -07001579
1580 // make the directory not readable
Colin Cross7f8aa392020-06-29 23:00:12 -07001581 fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001582
1583 // run the second finder
1584 _, err := finderAndErrorWithSameParams(t, finder)
1585 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -07001586 t.Fatal("Failed to detect unexpected filesystem error")
Jeff Gastonb629e182017-08-14 16:49:18 -07001587 }
1588}