blob: 0210d2ac8e1b8d5fae2cb0a28f17434ab2482080 [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"
Jeff Gastonb629e182017-08-14 16:49:18 -070024 "testing"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070025
Colin Cross8d6395c2017-12-21 15:46:01 -080026 "android/soong/finder/fs"
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070027)
28
29// some utils for tests to use
30func newFs() *fs.MockFs {
31 return fs.NewMockFs(map[string][]byte{})
32}
33
34func newFinder(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams) *Finder {
Jeff Gastond3119522017-08-22 14:11:15 -070035 return newFinderWithNumThreads(t, filesystem, cacheParams, 2)
36}
37
38func newFinderWithNumThreads(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) *Finder {
39 f, err := newFinderAndErr(t, filesystem, cacheParams, numThreads)
Jeff Gastonb629e182017-08-14 16:49:18 -070040 if err != nil {
Colin Cross7f8aa392020-06-29 23:00:12 -070041 t.Fatal(err.Error())
Jeff Gastonb629e182017-08-14 16:49:18 -070042 }
43 return f
44}
45
Jeff Gastond3119522017-08-22 14:11:15 -070046func newFinderAndErr(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) (*Finder, error) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070047 cachePath := "/finder/finder-db"
48 cacheDir := filepath.Dir(cachePath)
49 filesystem.MkDirs(cacheDir)
50 if cacheParams.WorkingDirectory == "" {
51 cacheParams.WorkingDirectory = "/cwd"
52 }
53
54 logger := log.New(ioutil.Discard, "", 0)
Jeff Gastond3119522017-08-22 14:11:15 -070055 f, err := newImpl(cacheParams, filesystem, logger, cachePath, numThreads)
Jeff Gastonb629e182017-08-14 16:49:18 -070056 return f, err
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070057}
58
59func finderWithSameParams(t *testing.T, original *Finder) *Finder {
Jeff Gastonb629e182017-08-14 16:49:18 -070060 f, err := finderAndErrorWithSameParams(t, original)
61 if err != nil {
Colin Cross7f8aa392020-06-29 23:00:12 -070062 t.Fatal(err.Error())
Jeff Gastonb629e182017-08-14 16:49:18 -070063 }
64 return f
65}
66
67func finderAndErrorWithSameParams(t *testing.T, original *Finder) (*Finder, error) {
Jeff Gastond3119522017-08-22 14:11:15 -070068 f, err := newImpl(
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070069 original.cacheMetadata.Config.CacheParams,
70 original.filesystem,
71 original.logger,
Jeff Gastond3119522017-08-22 14:11:15 -070072 original.DbPath,
73 original.numDbLoadingThreads,
74 )
Jeff Gastonb629e182017-08-14 16:49:18 -070075 return f, err
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070076}
77
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070078// runSimpleTests creates a few files, searches for findme.txt, and checks for the expected matches
79func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []string) {
80 filesystem := newFs()
81 root := "/tmp"
82 filesystem.MkDirs(root)
83 for _, path := range existentPaths {
Colin Cross7f8aa392020-06-29 23:00:12 -070084 fs.Create(t, filepath.Join(root, path), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070085 }
86
87 finder := newFinder(t,
88 filesystem,
89 CacheParams{
90 "/cwd",
91 []string{root},
92 nil,
93 nil,
94 []string{"findme.txt", "skipme.txt"},
95 },
96 )
97 defer finder.Shutdown()
98
99 foundPaths := finder.FindNamedAt(root, "findme.txt")
100 absoluteMatches := []string{}
101 for i := range expectedMatches {
102 absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
103 }
Colin Cross7f8aa392020-06-29 23:00:12 -0700104 fs.AssertSameResponse(t, foundPaths, absoluteMatches)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700105}
106
Jeff Gastond3119522017-08-22 14:11:15 -0700107// testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
108func testAgainstSeveralThreadcounts(t *testing.T, tester func(t *testing.T, numThreads int)) {
109 // test singlethreaded, multithreaded, and also using the same number of threads as
110 // will be used on the current system
111 threadCounts := []int{1, 2, defaultNumThreads}
112 for _, numThreads := range threadCounts {
113 testName := fmt.Sprintf("%v threads", numThreads)
114 // store numThreads in a new variable to prevent numThreads from changing in each loop
115 localNumThreads := numThreads
116 t.Run(testName, func(t *testing.T) {
117 tester(t, localNumThreads)
118 })
119 }
120}
121
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700122// end of utils, start of individual tests
123
124func TestSingleFile(t *testing.T) {
125 runSimpleTest(t,
126 []string{"findme.txt"},
127 []string{"findme.txt"},
128 )
129}
130
131func TestIncludeFiles(t *testing.T) {
132 runSimpleTest(t,
133 []string{"findme.txt", "skipme.txt"},
134 []string{"findme.txt"},
135 )
136}
137
138func TestNestedDirectories(t *testing.T) {
139 runSimpleTest(t,
140 []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt"},
141 []string{"findme.txt", "subdir/findme.txt"},
142 )
143}
144
145func TestEmptyDirectory(t *testing.T) {
146 runSimpleTest(t,
147 []string{},
148 []string{},
149 )
150}
151
152func TestEmptyPath(t *testing.T) {
153 filesystem := newFs()
154 root := "/tmp"
Colin Cross7f8aa392020-06-29 23:00:12 -0700155 fs.Create(t, filepath.Join(root, "findme.txt"), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700156
157 finder := newFinder(
158 t,
159 filesystem,
160 CacheParams{
161 RootDirs: []string{root},
162 IncludeFiles: []string{"findme.txt", "skipme.txt"},
163 },
164 )
165 defer finder.Shutdown()
166
167 foundPaths := finder.FindNamedAt("", "findme.txt")
168
Colin Cross7f8aa392020-06-29 23:00:12 -0700169 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700170}
171
172func TestFilesystemRoot(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700173
Jeff Gastond3119522017-08-22 14:11:15 -0700174 testWithNumThreads := func(t *testing.T, numThreads int) {
175 filesystem := newFs()
176 root := "/"
177 createdPath := "/findme.txt"
Colin Cross7f8aa392020-06-29 23:00:12 -0700178 fs.Create(t, createdPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700179
Jeff Gastond3119522017-08-22 14:11:15 -0700180 finder := newFinderWithNumThreads(
181 t,
182 filesystem,
183 CacheParams{
184 RootDirs: []string{root},
185 IncludeFiles: []string{"findme.txt", "skipme.txt"},
186 },
187 numThreads,
188 )
189 defer finder.Shutdown()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700190
Jeff Gastond3119522017-08-22 14:11:15 -0700191 foundPaths := finder.FindNamedAt(root, "findme.txt")
192
Colin Cross7f8aa392020-06-29 23:00:12 -0700193 fs.AssertSameResponse(t, foundPaths, []string{createdPath})
Jeff Gastond3119522017-08-22 14:11:15 -0700194 }
195
196 testAgainstSeveralThreadcounts(t, testWithNumThreads)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700197}
198
Jeff Gastonb629e182017-08-14 16:49:18 -0700199func TestNonexistentDir(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700200 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700201 fs.Create(t, "/tmp/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700202
Jeff Gastonb629e182017-08-14 16:49:18 -0700203 _, err := newFinderAndErr(
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700204 t,
205 filesystem,
206 CacheParams{
207 RootDirs: []string{"/tmp/IDontExist"},
208 IncludeFiles: []string{"findme.txt", "skipme.txt"},
209 },
Jeff Gastond3119522017-08-22 14:11:15 -0700210 1,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700211 )
Jeff Gastonb629e182017-08-14 16:49:18 -0700212 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -0700213 t.Fatal("Did not fail when given a nonexistent root directory")
Jeff Gastonb629e182017-08-14 16:49:18 -0700214 }
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700215}
216
217func TestExcludeDirs(t *testing.T) {
218 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700219 fs.Create(t, "/tmp/exclude/findme.txt", filesystem)
220 fs.Create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
221 fs.Create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
222 fs.Create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
223 fs.Create(t, "/tmp/subdir/findme.txt", filesystem)
224 fs.Create(t, "/tmp/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700225
226 finder := newFinder(
227 t,
228 filesystem,
229 CacheParams{
230 RootDirs: []string{"/tmp"},
231 ExcludeDirs: []string{"exclude"},
232 IncludeFiles: []string{"findme.txt", "skipme.txt"},
233 },
234 )
235 defer finder.Shutdown()
236
237 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
238
Colin Cross7f8aa392020-06-29 23:00:12 -0700239 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700240 []string{"/tmp/findme.txt",
241 "/tmp/subdir/findme.txt",
242 "/tmp/subdir/subdir/findme.txt"})
243}
244
245func TestPruneFiles(t *testing.T) {
246 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700247 fs.Create(t, "/tmp/out/findme.txt", filesystem)
248 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
249 fs.Create(t, "/tmp/out/child/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700250
Colin Cross7f8aa392020-06-29 23:00:12 -0700251 fs.Create(t, "/tmp/out2/.ignore-out-dir", filesystem)
252 fs.Create(t, "/tmp/out2/sub/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700253
Colin Cross7f8aa392020-06-29 23:00:12 -0700254 fs.Create(t, "/tmp/findme.txt", filesystem)
255 fs.Create(t, "/tmp/include/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700256
257 finder := newFinder(
258 t,
259 filesystem,
260 CacheParams{
261 RootDirs: []string{"/tmp"},
262 PruneFiles: []string{".ignore-out-dir"},
263 IncludeFiles: []string{"findme.txt"},
264 },
265 )
266 defer finder.Shutdown()
267
268 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
269
Colin Cross7f8aa392020-06-29 23:00:12 -0700270 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700271 []string{"/tmp/findme.txt",
272 "/tmp/include/findme.txt"})
273}
274
Jeff Gastond3119522017-08-22 14:11:15 -0700275// TestRootDir tests that the value of RootDirs is used
276// tests of the filesystem root are in TestFilesystemRoot
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700277func TestRootDir(t *testing.T) {
278 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700279 fs.Create(t, "/tmp/a/findme.txt", filesystem)
280 fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
281 fs.Create(t, "/tmp/b/findme.txt", filesystem)
282 fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700283
284 finder := newFinder(
285 t,
286 filesystem,
287 CacheParams{
288 RootDirs: []string{"/tmp/a"},
289 IncludeFiles: []string{"findme.txt"},
290 },
291 )
292 defer finder.Shutdown()
293
294 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
295
Colin Cross7f8aa392020-06-29 23:00:12 -0700296 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700297 []string{"/tmp/a/findme.txt",
298 "/tmp/a/subdir/findme.txt"})
299}
300
301func TestUncachedDir(t *testing.T) {
302 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700303 fs.Create(t, "/tmp/a/findme.txt", filesystem)
304 fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
305 fs.Create(t, "/tmp/b/findme.txt", filesystem)
306 fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700307
308 finder := newFinder(
309 t,
310 filesystem,
311 CacheParams{
Jeff Gastonb629e182017-08-14 16:49:18 -0700312 RootDirs: []string{"/tmp/b"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700313 IncludeFiles: []string{"findme.txt"},
314 },
315 )
316
317 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
318 // If the caller queries for a file that is in the cache, then computing the
319 // correct answer won't be fast, and it would be easy for the caller to
320 // fail to notice its slowness. Instead, we only ever search the cache for files
321 // to return, which enforces that we can determine which files will be
322 // interesting upfront.
Colin Cross7f8aa392020-06-29 23:00:12 -0700323 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700324
325 finder.Shutdown()
326}
327
328func TestSearchingForFilesExcludedFromCache(t *testing.T) {
329 // setup filesystem
330 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700331 fs.Create(t, "/tmp/findme.txt", filesystem)
332 fs.Create(t, "/tmp/a/findme.txt", filesystem)
333 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700334
335 // set up the finder and run it
336 finder := newFinder(
337 t,
338 filesystem,
339 CacheParams{
340 RootDirs: []string{"/tmp"},
341 IncludeFiles: []string{"findme.txt"},
342 },
343 )
344 foundPaths := finder.FindNamedAt("/tmp", "misc.txt")
345 // If the caller queries for a file that is in the cache, then computing the
346 // correct answer won't be fast, and it would be easy for the caller to
347 // fail to notice its slowness. Instead, we only ever search the cache for files
348 // to return, which enforces that we can determine which files will be
349 // interesting upfront.
Colin Cross7f8aa392020-06-29 23:00:12 -0700350 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700351
352 finder.Shutdown()
353}
354
355func TestRelativeFilePaths(t *testing.T) {
356 filesystem := newFs()
357
Colin Cross7f8aa392020-06-29 23:00:12 -0700358 fs.Create(t, "/tmp/ignore/hi.txt", filesystem)
359 fs.Create(t, "/tmp/include/hi.txt", filesystem)
360 fs.Create(t, "/cwd/hi.txt", filesystem)
361 fs.Create(t, "/cwd/a/hi.txt", filesystem)
362 fs.Create(t, "/cwd/a/a/hi.txt", filesystem)
363 fs.Create(t, "/rel/a/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700364
365 finder := newFinder(
366 t,
367 filesystem,
368 CacheParams{
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700369 RootDirs: []string{"/cwd", "../rel", "/tmp/include"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700370 IncludeFiles: []string{"hi.txt"},
371 },
372 )
373 defer finder.Shutdown()
374
375 foundPaths := finder.FindNamedAt("a", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700376 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700377 []string{"a/hi.txt",
378 "a/a/hi.txt"})
379
380 foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700381 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700382
383 foundPaths = finder.FindNamedAt(".", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700384 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700385 []string{"hi.txt",
386 "a/hi.txt",
387 "a/a/hi.txt"})
388
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700389 foundPaths = finder.FindNamedAt("/rel", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700390 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700391 []string{"/rel/a/hi.txt"})
392
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700393 foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700394 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700395}
396
397// have to run this test with the race-detector (`go test -race src/android/soong/finder/*.go`)
398// for there to be much chance of the test actually detecting any error that may be present
399func TestRootDirsContainedInOtherRootDirs(t *testing.T) {
400 filesystem := newFs()
401
Colin Cross7f8aa392020-06-29 23:00:12 -0700402 fs.Create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700403
404 finder := newFinder(
405 t,
406 filesystem,
407 CacheParams{
Jeff Gastonb629e182017-08-14 16:49:18 -0700408 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 -0700409 IncludeFiles: []string{"findme.txt"},
410 },
411 )
412 defer finder.Shutdown()
413
414 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
415
Colin Cross7f8aa392020-06-29 23:00:12 -0700416 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700417 []string{"/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt"})
418}
419
420func TestFindFirst(t *testing.T) {
421 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700422 fs.Create(t, "/tmp/a/hi.txt", filesystem)
423 fs.Create(t, "/tmp/b/hi.txt", filesystem)
424 fs.Create(t, "/tmp/b/a/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700425
426 finder := newFinder(
427 t,
428 filesystem,
429 CacheParams{
430 RootDirs: []string{"/tmp"},
431 IncludeFiles: []string{"hi.txt"},
432 },
433 )
434 defer finder.Shutdown()
435
436 foundPaths := finder.FindFirstNamed("hi.txt")
437
Colin Cross7f8aa392020-06-29 23:00:12 -0700438 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700439 []string{"/tmp/a/hi.txt",
440 "/tmp/b/hi.txt"},
441 )
442}
443
444func TestConcurrentFindSameDirectory(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700445
Jeff Gastond3119522017-08-22 14:11:15 -0700446 testWithNumThreads := func(t *testing.T, numThreads int) {
447 filesystem := newFs()
448
449 // create a bunch of files and directories
450 paths := []string{}
451 for i := 0; i < 10; i++ {
452 parentDir := fmt.Sprintf("/tmp/%v", i)
453 for j := 0; j < 10; j++ {
454 filePath := filepath.Join(parentDir, fmt.Sprintf("%v/findme.txt", j))
455 paths = append(paths, filePath)
456 }
457 }
458 sort.Strings(paths)
459 for _, path := range paths {
Colin Cross7f8aa392020-06-29 23:00:12 -0700460 fs.Create(t, path, filesystem)
Jeff Gastond3119522017-08-22 14:11:15 -0700461 }
462
463 // set up a finder
464 finder := newFinderWithNumThreads(
465 t,
466 filesystem,
467 CacheParams{
468 RootDirs: []string{"/tmp"},
469 IncludeFiles: []string{"findme.txt"},
470 },
471 numThreads,
472 )
473 defer finder.Shutdown()
474
475 numTests := 20
476 results := make(chan []string, numTests)
477 // make several parallel calls to the finder
478 for i := 0; i < numTests; i++ {
479 go func() {
480 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
481 results <- foundPaths
482 }()
483 }
484
485 // check that each response was correct
486 for i := 0; i < numTests; i++ {
487 foundPaths := <-results
Colin Cross7f8aa392020-06-29 23:00:12 -0700488 fs.AssertSameResponse(t, foundPaths, paths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700489 }
490 }
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700491
Jeff Gastond3119522017-08-22 14:11:15 -0700492 testAgainstSeveralThreadcounts(t, testWithNumThreads)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700493}
494
495func TestConcurrentFindDifferentDirectories(t *testing.T) {
496 filesystem := newFs()
497
498 // create a bunch of files and directories
499 allFiles := []string{}
500 numSubdirs := 10
501 rootPaths := []string{}
502 queryAnswers := [][]string{}
503 for i := 0; i < numSubdirs; i++ {
504 parentDir := fmt.Sprintf("/tmp/%v", i)
505 rootPaths = append(rootPaths, parentDir)
506 queryAnswers = append(queryAnswers, []string{})
507 for j := 0; j < 10; j++ {
508 filePath := filepath.Join(parentDir, fmt.Sprintf("%v/findme.txt", j))
509 queryAnswers[i] = append(queryAnswers[i], filePath)
510 allFiles = append(allFiles, filePath)
511 }
512 sort.Strings(queryAnswers[i])
513 }
514 sort.Strings(allFiles)
515 for _, path := range allFiles {
Colin Cross7f8aa392020-06-29 23:00:12 -0700516 fs.Create(t, path, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700517 }
518
519 // set up a finder
520 finder := newFinder(
521 t,
522 filesystem,
523
524 CacheParams{
525 RootDirs: []string{"/tmp"},
526 IncludeFiles: []string{"findme.txt"},
527 },
528 )
529 defer finder.Shutdown()
530
531 type testRun struct {
532 path string
533 foundMatches []string
534 correctMatches []string
535 }
536
537 numTests := numSubdirs + 1
538 testRuns := make(chan testRun, numTests)
539
540 searchAt := func(path string, correctMatches []string) {
541 foundPaths := finder.FindNamedAt(path, "findme.txt")
542 testRuns <- testRun{path, foundPaths, correctMatches}
543 }
544
545 // make several parallel calls to the finder
546 go searchAt("/tmp", allFiles)
547 for i := 0; i < len(rootPaths); i++ {
548 go searchAt(rootPaths[i], queryAnswers[i])
549 }
550
551 // check that each response was correct
552 for i := 0; i < numTests; i++ {
553 testRun := <-testRuns
Colin Cross7f8aa392020-06-29 23:00:12 -0700554 fs.AssertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700555 }
556}
557
558func TestStrangelyFormattedPaths(t *testing.T) {
559 filesystem := newFs()
560
Colin Cross7f8aa392020-06-29 23:00:12 -0700561 fs.Create(t, "/tmp/findme.txt", filesystem)
562 fs.Create(t, "/tmp/a/findme.txt", filesystem)
563 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700564
565 finder := newFinder(
566 t,
567 filesystem,
568 CacheParams{
569 RootDirs: []string{"//tmp//a//.."},
570 IncludeFiles: []string{"findme.txt"},
571 },
572 )
573 defer finder.Shutdown()
574
575 foundPaths := finder.FindNamedAt("//tmp//a//..", "findme.txt")
576
Colin Cross7f8aa392020-06-29 23:00:12 -0700577 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700578 []string{"/tmp/a/findme.txt",
579 "/tmp/b/findme.txt",
580 "/tmp/findme.txt"})
581}
582
583func TestCorruptedCacheHeader(t *testing.T) {
584 filesystem := newFs()
585
Colin Cross7f8aa392020-06-29 23:00:12 -0700586 fs.Create(t, "/tmp/findme.txt", filesystem)
587 fs.Create(t, "/tmp/a/findme.txt", filesystem)
588 fs.Write(t, "/finder/finder-db", "sample header", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700589
590 finder := newFinder(
591 t,
592 filesystem,
593 CacheParams{
594 RootDirs: []string{"/tmp"},
595 IncludeFiles: []string{"findme.txt"},
596 },
597 )
598 defer finder.Shutdown()
599
600 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
601
Colin Cross7f8aa392020-06-29 23:00:12 -0700602 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700603 []string{"/tmp/a/findme.txt",
604 "/tmp/findme.txt"})
605}
606
607func TestCanUseCache(t *testing.T) {
608 // setup filesystem
609 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700610 fs.Create(t, "/tmp/findme.txt", filesystem)
611 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700612
613 // run the first finder
614 finder := newFinder(
615 t,
616 filesystem,
617 CacheParams{
618 RootDirs: []string{"/tmp"},
619 IncludeFiles: []string{"findme.txt"},
620 },
621 )
622 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
623 // check the response of the first finder
624 correctResponse := []string{"/tmp/a/findme.txt",
625 "/tmp/findme.txt"}
Colin Cross7f8aa392020-06-29 23:00:12 -0700626 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700627 finder.Shutdown()
628
629 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700630 cacheText := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700631 if len(cacheText) < 1 {
632 t.Fatalf("saved cache db is empty\n")
633 }
634 if len(filesystem.StatCalls) == 0 {
635 t.Fatal("No Stat calls recorded by mock filesystem")
636 }
637 if len(filesystem.ReadDirCalls) == 0 {
638 t.Fatal("No ReadDir calls recorded by filesystem")
639 }
640 statCalls := filesystem.StatCalls
641 filesystem.ClearMetrics()
642
643 // run the second finder
644 finder2 := finderWithSameParams(t, finder)
645 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
646 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700647 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
648 fs.AssertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700649
650 finder2.Shutdown()
651}
652
653func TestCorruptedCacheBody(t *testing.T) {
654 // setup filesystem
655 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700656 fs.Create(t, "/tmp/findme.txt", filesystem)
657 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700658
659 // run the first finder
660 finder := newFinder(
661 t,
662 filesystem,
663 CacheParams{
664 RootDirs: []string{"/tmp"},
665 IncludeFiles: []string{"findme.txt"},
666 },
667 )
668 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
669 finder.Shutdown()
670
671 // check the response of the first finder
672 correctResponse := []string{"/tmp/a/findme.txt",
673 "/tmp/findme.txt"}
Colin Cross7f8aa392020-06-29 23:00:12 -0700674 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700675 numStatCalls := len(filesystem.StatCalls)
676 numReadDirCalls := len(filesystem.ReadDirCalls)
677
678 // load the cache file, corrupt it, and save it
679 cacheReader, err := filesystem.Open(finder.DbPath)
680 if err != nil {
681 t.Fatal(err)
682 }
683 cacheData, err := ioutil.ReadAll(cacheReader)
684 if err != nil {
685 t.Fatal(err)
686 }
687 cacheData = append(cacheData, []byte("DontMindMe")...)
688 filesystem.WriteFile(finder.DbPath, cacheData, 0777)
689 filesystem.ClearMetrics()
690
691 // run the second finder
692 finder2 := finderWithSameParams(t, finder)
693 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
694 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700695 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700696 numNewStatCalls := len(filesystem.StatCalls)
697 numNewReadDirCalls := len(filesystem.ReadDirCalls)
698 // It's permissable to make more Stat calls with a corrupted cache because
699 // the Finder may restart once it detects corruption.
700 // However, it may have already issued many Stat calls.
701 // Because a corrupted db is not expected to be a common (or even a supported case),
702 // we don't care to optimize it and don't cache the already-issued Stat calls
703 if numNewReadDirCalls < numReadDirCalls {
704 t.Fatalf(
705 "Finder made fewer ReadDir calls with a corrupted cache (%v calls) than with no cache"+
706 " (%v calls)",
707 numNewReadDirCalls, numReadDirCalls)
708 }
709 if numNewStatCalls < numStatCalls {
710 t.Fatalf(
711 "Finder made fewer Stat calls with a corrupted cache (%v calls) than with no cache (%v calls)",
712 numNewStatCalls, numStatCalls)
713 }
714 finder2.Shutdown()
715}
716
717func TestStatCalls(t *testing.T) {
718 // setup filesystem
719 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700720 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700721
722 // run finder
723 finder := newFinder(
724 t,
725 filesystem,
726 CacheParams{
727 RootDirs: []string{"/tmp"},
728 IncludeFiles: []string{"findme.txt"},
729 },
730 )
731 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
732 finder.Shutdown()
733
734 // check response
Colin Cross7f8aa392020-06-29 23:00:12 -0700735 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
736 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
737 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700738}
739
740func TestFileAdded(t *testing.T) {
741 // setup filesystem
742 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700743 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
744 fs.Create(t, "/tmp/a/findme.txt", filesystem)
745 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
746 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
747 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700748
749 // run the first finder
750 finder := newFinder(
751 t,
752 filesystem,
753 CacheParams{
754 RootDirs: []string{"/tmp"},
755 IncludeFiles: []string{"findme.txt"},
756 },
757 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700758 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -0700759 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700760 finder.Shutdown()
761 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700762 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700763
764 // modify the filesystem
765 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700766 fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700767 filesystem.Clock.Tick()
768 filesystem.ClearMetrics()
769
770 // run the second finder
771 finder2 := finderWithSameParams(t, finder)
772 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
773
774 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700775 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
776 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
777 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700778 finder2.Shutdown()
779
780}
781
782func TestDirectoriesAdded(t *testing.T) {
783 // setup filesystem
784 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700785 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
786 fs.Create(t, "/tmp/a/findme.txt", filesystem)
787 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
788 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
789 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700790
791 // run the first finder
792 finder := newFinder(
793 t,
794 filesystem,
795 CacheParams{
796 RootDirs: []string{"/tmp"},
797 IncludeFiles: []string{"findme.txt"},
798 },
799 )
800 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
801 finder.Shutdown()
802 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700803 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700804
805 // modify the filesystem
806 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700807 fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
808 fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
809 fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700810 filesystem.ClearMetrics()
811
812 // run the second finder
813 finder2 := finderWithSameParams(t, finder)
814 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
815
816 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700817 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700818 []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 -0700819 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700820 []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 -0700821 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 -0700822
823 finder2.Shutdown()
824}
825
826func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
827 // setup filesystem
828 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700829 fs.Create(t, "/tmp/hi1.txt", filesystem)
830 fs.Create(t, "/tmp/a/hi1.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700831
832 // run the first finder
833 finder := newFinder(
834 t,
835 filesystem,
836 CacheParams{
837 RootDirs: []string{"/tmp"},
838 IncludeFiles: []string{"hi1.txt", "hi2.txt"},
839 },
840 )
841 foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
842 finder.Shutdown()
843 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700844 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700845
846 // modify the filesystem
847 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700848 fs.Create(t, "/tmp/hi2.txt", filesystem)
849 fs.Create(t, "/tmp/a/hi2.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700850 filesystem.ClearMetrics()
851
852 // run the second finder
853 finder2 := finderWithSameParams(t, finder)
854 foundPaths = finder2.FindAll()
855
856 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700857 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700858 []string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700859 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700860 []string{"/tmp", "/tmp/a"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700861 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700862
863 finder2.Shutdown()
864}
865
866func TestFileDeleted(t *testing.T) {
867 // setup filesystem
868 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700869 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
870 fs.Create(t, "/tmp/a/findme.txt", filesystem)
871 fs.Create(t, "/tmp/b/findme.txt", filesystem)
872 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
873 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700874
875 // run the first finder
876 finder := newFinder(
877 t,
878 filesystem,
879 CacheParams{
880 RootDirs: []string{"/tmp"},
881 IncludeFiles: []string{"findme.txt"},
882 },
883 )
884 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
885 finder.Shutdown()
886 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700887 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700888
889 // modify the filesystem
890 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700891 fs.Delete(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700892 filesystem.ClearMetrics()
893
894 // run the second finder
895 finder2 := finderWithSameParams(t, finder)
896 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
897
898 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700899 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
900 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
901 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700902
903 finder2.Shutdown()
904}
905
906func TestDirectoriesDeleted(t *testing.T) {
907 // setup filesystem
908 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700909 fs.Create(t, "/tmp/findme.txt", filesystem)
910 fs.Create(t, "/tmp/a/findme.txt", filesystem)
911 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
912 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
913 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700914
915 // run the first finder
916 finder := newFinder(
917 t,
918 filesystem,
919 CacheParams{
920 RootDirs: []string{"/tmp"},
921 IncludeFiles: []string{"findme.txt"},
922 },
923 )
924 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
925 finder.Shutdown()
926 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700927 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700928 []string{"/tmp/findme.txt",
929 "/tmp/a/findme.txt",
930 "/tmp/a/1/findme.txt",
931 "/tmp/a/1/2/findme.txt",
932 "/tmp/b/findme.txt"})
933
934 // modify the filesystem
935 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700936 fs.RemoveAll(t, "/tmp/a/1", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700937 filesystem.ClearMetrics()
938
939 // run the second finder
940 finder2 := finderWithSameParams(t, finder)
941 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
942
943 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700944 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700945 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/findme.txt"})
946 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
947 // if the Finder detects the nonexistence of /tmp/a/1
948 // However, when resuming from cache, we don't want the Finder to necessarily wait
949 // to stat a directory until after statting its parent.
950 // So here we just include /tmp/a/1/2 in the list.
951 // The Finder is currently implemented to always restat every dir and
952 // to not short-circuit due to nonexistence of parents (but it will remove
953 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -0700954 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700955 []string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700956 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700957
958 finder2.Shutdown()
959}
960
961func TestDirectoriesMoved(t *testing.T) {
962 // setup filesystem
963 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700964 fs.Create(t, "/tmp/findme.txt", filesystem)
965 fs.Create(t, "/tmp/a/findme.txt", filesystem)
966 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
967 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
968 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700969
970 // run the first finder
971 finder := newFinder(
972 t,
973 filesystem,
974 CacheParams{
975 RootDirs: []string{"/tmp"},
976 IncludeFiles: []string{"findme.txt"},
977 },
978 )
979 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
980 finder.Shutdown()
981 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700982 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700983 []string{"/tmp/findme.txt",
984 "/tmp/a/findme.txt",
985 "/tmp/a/1/findme.txt",
986 "/tmp/a/1/2/findme.txt",
987 "/tmp/b/findme.txt"})
988
989 // modify the filesystem
990 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700991 fs.Move(t, "/tmp/a", "/tmp/c", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700992 filesystem.ClearMetrics()
993
994 // run the second finder
995 finder2 := finderWithSameParams(t, finder)
996 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
997
998 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700999 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001000 []string{"/tmp/findme.txt",
1001 "/tmp/b/findme.txt",
1002 "/tmp/c/findme.txt",
1003 "/tmp/c/1/findme.txt",
1004 "/tmp/c/1/2/findme.txt"})
1005 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1006 // if the Finder detects the nonexistence of /tmp/a/1
1007 // However, when resuming from cache, we don't want the Finder to necessarily wait
1008 // to stat a directory until after statting its parent.
1009 // So here we just include /tmp/a/1/2 in the list.
1010 // The Finder is currently implemented to always restat every dir and
1011 // to not short-circuit due to nonexistence of parents (but it will remove
1012 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001013 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001014 []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 -07001015 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001016 finder2.Shutdown()
1017}
1018
1019func TestDirectoriesSwapped(t *testing.T) {
1020 // setup filesystem
1021 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001022 fs.Create(t, "/tmp/findme.txt", filesystem)
1023 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1024 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
1025 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
1026 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001027
1028 // run the first finder
1029 finder := newFinder(
1030 t,
1031 filesystem,
1032 CacheParams{
1033 RootDirs: []string{"/tmp"},
1034 IncludeFiles: []string{"findme.txt"},
1035 },
1036 )
1037 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1038 finder.Shutdown()
1039 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001040 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001041 []string{"/tmp/findme.txt",
1042 "/tmp/a/findme.txt",
1043 "/tmp/a/1/findme.txt",
1044 "/tmp/a/1/2/findme.txt",
1045 "/tmp/b/findme.txt"})
1046
1047 // modify the filesystem
1048 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001049 fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
1050 fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
1051 fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001052 filesystem.ClearMetrics()
1053
1054 // run the second finder
1055 finder2 := finderWithSameParams(t, finder)
1056 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1057
1058 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001059 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001060 []string{"/tmp/findme.txt",
1061 "/tmp/a/findme.txt",
1062 "/tmp/b/findme.txt",
1063 "/tmp/b/1/findme.txt",
1064 "/tmp/b/1/2/findme.txt"})
1065 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1066 // if the Finder detects the nonexistence of /tmp/a/1
1067 // However, when resuming from cache, we don't want the Finder to necessarily wait
1068 // to stat a directory until after statting its parent.
1069 // So here we just include /tmp/a/1/2 in the list.
1070 // The Finder is currently implemented to always restat every dir and
1071 // to not short-circuit due to nonexistence of parents (but it will remove
1072 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001073 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001074 []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 -07001075 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 -07001076 finder2.Shutdown()
1077}
1078
1079// runFsReplacementTest tests a change modifying properties of the filesystem itself:
1080// runFsReplacementTest tests changing the user, the hostname, or the device number
1081// runFsReplacementTest is a helper method called by other tests
1082func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
1083 // setup fs1
Colin Cross7f8aa392020-06-29 23:00:12 -07001084 fs.Create(t, "/tmp/findme.txt", fs1)
1085 fs.Create(t, "/tmp/a/findme.txt", fs1)
1086 fs.Create(t, "/tmp/a/a/findme.txt", fs1)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001087
1088 // setup fs2 to have the same directories but different files
Colin Cross7f8aa392020-06-29 23:00:12 -07001089 fs.Create(t, "/tmp/findme.txt", fs2)
1090 fs.Create(t, "/tmp/a/findme.txt", fs2)
1091 fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
1092 fs.Create(t, "/tmp/a/b/findme.txt", fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001093
1094 // run the first finder
1095 finder := newFinder(
1096 t,
1097 fs1,
1098 CacheParams{
1099 RootDirs: []string{"/tmp"},
1100 IncludeFiles: []string{"findme.txt"},
1101 },
1102 )
1103 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1104 finder.Shutdown()
1105 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001106 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001107 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
1108
1109 // copy the cache data from the first filesystem to the second
Colin Cross7f8aa392020-06-29 23:00:12 -07001110 cacheContent := fs.Read(t, finder.DbPath, fs1)
1111 fs.Write(t, finder.DbPath, cacheContent, fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001112
1113 // run the second finder, with the same config and same cache contents but a different filesystem
1114 finder2 := newFinder(
1115 t,
1116 fs2,
1117 CacheParams{
1118 RootDirs: []string{"/tmp"},
1119 IncludeFiles: []string{"findme.txt"},
1120 },
1121 )
1122 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1123
1124 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001125 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001126 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001127 fs.AssertSameStatCalls(t, fs2.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001128 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001129 fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001130 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
1131 finder2.Shutdown()
1132}
1133
1134func TestChangeOfDevice(t *testing.T) {
1135 fs1 := newFs()
1136 // not as fine-grained mounting controls as a real filesystem, but should be adequate
1137 fs1.SetDeviceNumber(0)
1138
1139 fs2 := newFs()
1140 fs2.SetDeviceNumber(1)
1141
1142 runFsReplacementTest(t, fs1, fs2)
1143}
1144
1145func TestChangeOfUserOrHost(t *testing.T) {
1146 fs1 := newFs()
1147 fs1.SetViewId("me@here")
1148
1149 fs2 := newFs()
1150 fs2.SetViewId("you@there")
1151
1152 runFsReplacementTest(t, fs1, fs2)
1153}
1154
1155func TestConsistentCacheOrdering(t *testing.T) {
1156 // setup filesystem
1157 filesystem := newFs()
1158 for i := 0; i < 5; i++ {
Colin Cross7f8aa392020-06-29 23:00:12 -07001159 fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001160 }
1161
1162 // run the first finder
1163 finder := newFinder(
1164 t,
1165 filesystem,
1166 CacheParams{
1167 RootDirs: []string{"/tmp"},
1168 IncludeFiles: []string{"findme.txt"},
1169 },
1170 )
1171 finder.FindNamedAt("/tmp", "findme.txt")
1172 finder.Shutdown()
1173
1174 // read db file
Colin Cross7f8aa392020-06-29 23:00:12 -07001175 string1 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001176
1177 err := filesystem.Remove(finder.DbPath)
1178 if err != nil {
1179 t.Fatal(err)
1180 }
1181
1182 // run another finder
1183 finder2 := finderWithSameParams(t, finder)
1184 finder2.FindNamedAt("/tmp", "findme.txt")
1185 finder2.Shutdown()
1186
Colin Cross7f8aa392020-06-29 23:00:12 -07001187 string2 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001188
1189 if string1 != string2 {
1190 t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
1191 "Content of first file:\n"+
1192 "\n"+
1193 "%v"+
1194 "\n"+
1195 "\n"+
1196 "Content of second file:\n"+
1197 "\n"+
1198 "%v\n"+
1199 "\n",
1200 string1,
1201 string2,
1202 )
1203 }
1204
1205}
1206
1207func TestNumSyscallsOfSecondFind(t *testing.T) {
1208 // setup filesystem
1209 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001210 fs.Create(t, "/tmp/findme.txt", filesystem)
1211 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1212 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001213
1214 // set up the finder and run it once
1215 finder := newFinder(
1216 t,
1217 filesystem,
1218 CacheParams{
1219 RootDirs: []string{"/tmp"},
1220 IncludeFiles: []string{"findme.txt"},
1221 },
1222 )
1223 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001224 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001225
1226 filesystem.ClearMetrics()
1227
1228 // run the finder again and confirm it doesn't check the filesystem
1229 refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001230 fs.AssertSameResponse(t, refoundPaths, foundPaths)
1231 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1232 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001233
1234 finder.Shutdown()
1235}
1236
1237func TestChangingParamsOfSecondFind(t *testing.T) {
1238 // setup filesystem
1239 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001240 fs.Create(t, "/tmp/findme.txt", filesystem)
1241 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1242 fs.Create(t, "/tmp/a/metoo.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001243
1244 // set up the finder and run it once
1245 finder := newFinder(
1246 t,
1247 filesystem,
1248 CacheParams{
1249 RootDirs: []string{"/tmp"},
1250 IncludeFiles: []string{"findme.txt", "metoo.txt"},
1251 },
1252 )
1253 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001254 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001255
1256 filesystem.ClearMetrics()
1257
1258 // run the finder again and confirm it gets the right answer without asking the filesystem
1259 refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001260 fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
1261 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1262 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001263
1264 finder.Shutdown()
1265}
1266
1267func TestSymlinkPointingToFile(t *testing.T) {
1268 // setup filesystem
1269 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001270 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1271 fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
1272 fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
1273 fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
1274 fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
1275 fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
1276 fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
1277 fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
1278 fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001279
1280 // set up the finder and run it once
1281 finder := newFinder(
1282 t,
1283 filesystem,
1284 CacheParams{
1285 RootDirs: []string{"/tmp"},
1286 IncludeFiles: []string{"hi.txt"},
1287 },
1288 )
1289 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1290 // should search based on the name of the link rather than the destination or validity of the link
1291 correctResponse := []string{
1292 "/tmp/a/hi.txt",
1293 "/tmp/hi.txt",
1294 "/tmp/b/hi.txt",
1295 "/tmp/c/hi.txt",
1296 "/tmp/d/hi.txt",
1297 "/tmp/f/hi.txt",
1298 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001299 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001300
1301}
1302
1303func TestSymlinkPointingToDirectory(t *testing.T) {
1304 // setup filesystem
1305 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001306 fs.Create(t, "/tmp/dir/hi.txt", filesystem)
1307 fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001308
Colin Cross7f8aa392020-06-29 23:00:12 -07001309 fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
1310 fs.Link(t, "/tmp/links/link", "../dir", filesystem)
1311 fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
1312 fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001313
1314 // set up the finder and run it once
1315 finder := newFinder(
1316 t,
1317 filesystem,
1318 CacheParams{
1319 RootDirs: []string{"/tmp"},
1320 IncludeFiles: []string{"hi.txt"},
1321 },
1322 )
1323
1324 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1325
1326 // should completely ignore symlinks that point to directories
1327 correctResponse := []string{
1328 "/tmp/dir/hi.txt",
1329 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001330 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001331
1332}
1333
1334// TestAddPruneFile confirms that adding a prune-file (into a directory for which we
1335// already had a cache) causes the directory to be ignored
1336func TestAddPruneFile(t *testing.T) {
1337 // setup filesystem
1338 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001339 fs.Create(t, "/tmp/out/hi.txt", filesystem)
1340 fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
1341 fs.Create(t, "/tmp/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001342
1343 // do find
1344 finder := newFinder(
1345 t,
1346 filesystem,
1347 CacheParams{
1348 RootDirs: []string{"/tmp"},
1349 PruneFiles: []string{".ignore-out-dir"},
1350 IncludeFiles: []string{"hi.txt"},
1351 },
1352 )
1353
1354 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1355
1356 // check result
Colin Cross7f8aa392020-06-29 23:00:12 -07001357 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001358 []string{"/tmp/hi.txt",
1359 "/tmp/out/hi.txt",
1360 "/tmp/out/a/hi.txt"},
1361 )
1362 finder.Shutdown()
1363
1364 // modify filesystem
1365 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001366 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001367 // run another find and check its result
1368 finder2 := finderWithSameParams(t, finder)
1369 foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001370 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001371 finder2.Shutdown()
1372}
1373
1374func TestUpdatingDbIffChanged(t *testing.T) {
1375 // setup filesystem
1376 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001377 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1378 fs.Create(t, "/tmp/b/bye.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001379
1380 // run the first finder
1381 finder := newFinder(
1382 t,
1383 filesystem,
1384 CacheParams{
1385 RootDirs: []string{"/tmp"},
1386 IncludeFiles: []string{"hi.txt"},
1387 },
1388 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001389 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001390 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001391 finder.Shutdown()
1392 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001393 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001394
1395 // modify the filesystem
1396 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001397 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001398 filesystem.Clock.Tick()
1399 filesystem.ClearMetrics()
1400
1401 // run the second finder
1402 finder2 := finderWithSameParams(t, finder)
1403 foundPaths = finder2.FindAll()
1404 finder2.Shutdown()
1405 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001406 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1407 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001408 expectedDbWriteTime := filesystem.Clock.Time()
Colin Cross7f8aa392020-06-29 23:00:12 -07001409 actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001410 if actualDbWriteTime != expectedDbWriteTime {
1411 t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
1412 expectedDbWriteTime, actualDbWriteTime)
1413 }
1414
1415 // reset metrics
1416 filesystem.ClearMetrics()
1417
1418 // run the third finder
1419 finder3 := finderWithSameParams(t, finder2)
1420 foundPaths = finder3.FindAll()
1421
1422 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001423 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1424 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001425 finder3.Shutdown()
Colin Cross7f8aa392020-06-29 23:00:12 -07001426 actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001427 if actualDbWriteTime != expectedDbWriteTime {
1428 t.Fatalf("Re-wrote db even when contents did not change")
1429 }
1430
1431}
1432
1433func TestDirectoryNotPermitted(t *testing.T) {
1434 // setup filesystem
1435 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001436 fs.Create(t, "/tmp/hi.txt", filesystem)
1437 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1438 fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
1439 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001440
1441 // run the first finder
1442 finder := newFinder(
1443 t,
1444 filesystem,
1445 CacheParams{
1446 RootDirs: []string{"/tmp"},
1447 IncludeFiles: []string{"hi.txt"},
1448 },
1449 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001450 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001451 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001452 finder.Shutdown()
1453 allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
1454 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001455 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001456
1457 // modify the filesystem
1458 filesystem.Clock.Tick()
1459
Colin Cross7f8aa392020-06-29 23:00:12 -07001460 fs.SetReadable(t, "/tmp/a", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001461 filesystem.Clock.Tick()
1462
1463 // run the second finder
1464 finder2 := finderWithSameParams(t, finder)
1465 foundPaths = finder2.FindAll()
1466 finder2.Shutdown()
1467 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001468 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001469
1470 // modify the filesystem back
Colin Cross7f8aa392020-06-29 23:00:12 -07001471 fs.SetReadable(t, "/tmp/a", true, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001472
1473 // run the third finder
1474 finder3 := finderWithSameParams(t, finder2)
1475 foundPaths = finder3.FindAll()
1476 finder3.Shutdown()
1477 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001478 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001479}
1480
1481func TestFileNotPermitted(t *testing.T) {
1482 // setup filesystem
1483 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001484 fs.Create(t, "/tmp/hi.txt", filesystem)
1485 fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001486
1487 // run the first finder
1488 finder := newFinder(
1489 t,
1490 filesystem,
1491 CacheParams{
1492 RootDirs: []string{"/tmp"},
1493 IncludeFiles: []string{"hi.txt"},
1494 },
1495 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001496 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001497 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001498 finder.Shutdown()
1499 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001500 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001501}
Jeff Gastonb629e182017-08-14 16:49:18 -07001502
1503func TestCacheEntryPathUnexpectedError(t *testing.T) {
1504 // setup filesystem
1505 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001506 fs.Create(t, "/tmp/a/hi.txt", filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001507
1508 // run the first finder
1509 finder := newFinder(
1510 t,
1511 filesystem,
1512 CacheParams{
1513 RootDirs: []string{"/tmp"},
1514 IncludeFiles: []string{"hi.txt"},
1515 },
1516 )
Jeff Gastonb629e182017-08-14 16:49:18 -07001517 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001518 foundPaths := finder.FindAll()
Jeff Gastonb629e182017-08-14 16:49:18 -07001519 finder.Shutdown()
1520 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001521 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonb629e182017-08-14 16:49:18 -07001522
1523 // make the directory not readable
Colin Cross7f8aa392020-06-29 23:00:12 -07001524 fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001525
1526 // run the second finder
1527 _, err := finderAndErrorWithSameParams(t, finder)
1528 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -07001529 t.Fatal("Failed to detect unexpected filesystem error")
Jeff Gastonb629e182017-08-14 16:49:18 -07001530 }
1531}