blob: be22d13b6f05b55d075e8ea95d2ddb2cc6aef836 [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},
Lukacs T. Berkie3487c82022-05-02 10:13:19 +020093 false,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070094 nil,
95 nil,
96 []string{"findme.txt", "skipme.txt"},
Chris Parsonsa798d962020-10-12 23:44:08 -040097 nil,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -070098 },
99 )
100 defer finder.Shutdown()
101
102 foundPaths := finder.FindNamedAt(root, "findme.txt")
103 absoluteMatches := []string{}
104 for i := range expectedMatches {
105 absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
106 }
Colin Cross7f8aa392020-06-29 23:00:12 -0700107 fs.AssertSameResponse(t, foundPaths, absoluteMatches)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700108}
109
Chris Parsonsa798d962020-10-12 23:44:08 -0400110// runTestWithSuffixes creates a few files, searches for findme.txt or any file
111// with suffix `.findme_ext` and checks for the expected matches
112func runTestWithSuffixes(t *testing.T, existentPaths []string, expectedMatches []string) {
113 filesystem := newFs()
114 root := "/tmp"
115 filesystem.MkDirs(root)
116 for _, path := range existentPaths {
117 fs.Create(t, filepath.Join(root, path), filesystem)
118 }
119
120 finder := newFinder(t,
121 filesystem,
122 CacheParams{
123 "/cwd",
124 []string{root},
Lukacs T. Berkie3487c82022-05-02 10:13:19 +0200125 false,
Chris Parsonsa798d962020-10-12 23:44:08 -0400126 nil,
127 nil,
128 []string{"findme.txt", "skipme.txt"},
129 []string{".findme_ext"},
130 },
131 )
132 defer finder.Shutdown()
133
134 foundPaths := finder.FindMatching(root,
135 func(entries DirEntries) (dirs []string, files []string) {
136 matches := []string{}
137 for _, foundName := range entries.FileNames {
138 if foundName == "findme.txt" || strings.HasSuffix(foundName, ".findme_ext") {
139 matches = append(matches, foundName)
140 }
141 }
142 return entries.DirNames, matches
143 })
144 absoluteMatches := []string{}
145 for i := range expectedMatches {
146 absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
147 }
148 fs.AssertSameResponse(t, foundPaths, absoluteMatches)
149}
150
Jeff Gastond3119522017-08-22 14:11:15 -0700151// testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
152func testAgainstSeveralThreadcounts(t *testing.T, tester func(t *testing.T, numThreads int)) {
153 // test singlethreaded, multithreaded, and also using the same number of threads as
154 // will be used on the current system
155 threadCounts := []int{1, 2, defaultNumThreads}
156 for _, numThreads := range threadCounts {
157 testName := fmt.Sprintf("%v threads", numThreads)
158 // store numThreads in a new variable to prevent numThreads from changing in each loop
159 localNumThreads := numThreads
160 t.Run(testName, func(t *testing.T) {
161 tester(t, localNumThreads)
162 })
163 }
164}
165
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700166// end of utils, start of individual tests
167
168func TestSingleFile(t *testing.T) {
169 runSimpleTest(t,
170 []string{"findme.txt"},
171 []string{"findme.txt"},
172 )
173}
174
175func TestIncludeFiles(t *testing.T) {
176 runSimpleTest(t,
177 []string{"findme.txt", "skipme.txt"},
178 []string{"findme.txt"},
179 )
180}
181
Chris Parsonsa798d962020-10-12 23:44:08 -0400182func TestIncludeFilesAndSuffixes(t *testing.T) {
183 runTestWithSuffixes(t,
184 []string{"findme.txt", "skipme.txt", "alsome.findme_ext"},
185 []string{"findme.txt", "alsome.findme_ext"},
186 )
187}
188
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700189func TestNestedDirectories(t *testing.T) {
190 runSimpleTest(t,
191 []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt"},
192 []string{"findme.txt", "subdir/findme.txt"},
193 )
194}
195
Chris Parsonsa798d962020-10-12 23:44:08 -0400196func TestNestedDirectoriesWithSuffixes(t *testing.T) {
197 runTestWithSuffixes(t,
198 []string{"findme.txt", "skipme.txt", "subdir/findme.txt", "subdir/skipme.txt", "subdir/alsome.findme_ext"},
199 []string{"findme.txt", "subdir/findme.txt", "subdir/alsome.findme_ext"},
200 )
201}
202
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700203func TestEmptyDirectory(t *testing.T) {
204 runSimpleTest(t,
205 []string{},
206 []string{},
207 )
208}
209
210func TestEmptyPath(t *testing.T) {
211 filesystem := newFs()
212 root := "/tmp"
Colin Cross7f8aa392020-06-29 23:00:12 -0700213 fs.Create(t, filepath.Join(root, "findme.txt"), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700214
215 finder := newFinder(
216 t,
217 filesystem,
218 CacheParams{
219 RootDirs: []string{root},
220 IncludeFiles: []string{"findme.txt", "skipme.txt"},
221 },
222 )
223 defer finder.Shutdown()
224
225 foundPaths := finder.FindNamedAt("", "findme.txt")
226
Colin Cross7f8aa392020-06-29 23:00:12 -0700227 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700228}
229
230func TestFilesystemRoot(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700231
Jeff Gastond3119522017-08-22 14:11:15 -0700232 testWithNumThreads := func(t *testing.T, numThreads int) {
233 filesystem := newFs()
234 root := "/"
235 createdPath := "/findme.txt"
Colin Cross7f8aa392020-06-29 23:00:12 -0700236 fs.Create(t, createdPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700237
Jeff Gastond3119522017-08-22 14:11:15 -0700238 finder := newFinderWithNumThreads(
239 t,
240 filesystem,
241 CacheParams{
242 RootDirs: []string{root},
243 IncludeFiles: []string{"findme.txt", "skipme.txt"},
244 },
245 numThreads,
246 )
247 defer finder.Shutdown()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700248
Jeff Gastond3119522017-08-22 14:11:15 -0700249 foundPaths := finder.FindNamedAt(root, "findme.txt")
250
Colin Cross7f8aa392020-06-29 23:00:12 -0700251 fs.AssertSameResponse(t, foundPaths, []string{createdPath})
Jeff Gastond3119522017-08-22 14:11:15 -0700252 }
253
254 testAgainstSeveralThreadcounts(t, testWithNumThreads)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700255}
256
Jeff Gastonb629e182017-08-14 16:49:18 -0700257func TestNonexistentDir(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700258 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700259 fs.Create(t, "/tmp/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700260
Jeff Gastonb629e182017-08-14 16:49:18 -0700261 _, err := newFinderAndErr(
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700262 t,
263 filesystem,
264 CacheParams{
265 RootDirs: []string{"/tmp/IDontExist"},
266 IncludeFiles: []string{"findme.txt", "skipme.txt"},
267 },
Jeff Gastond3119522017-08-22 14:11:15 -0700268 1,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700269 )
Jeff Gastonb629e182017-08-14 16:49:18 -0700270 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -0700271 t.Fatal("Did not fail when given a nonexistent root directory")
Jeff Gastonb629e182017-08-14 16:49:18 -0700272 }
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700273}
274
275func TestExcludeDirs(t *testing.T) {
276 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700277 fs.Create(t, "/tmp/exclude/findme.txt", filesystem)
278 fs.Create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
279 fs.Create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
280 fs.Create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
281 fs.Create(t, "/tmp/subdir/findme.txt", filesystem)
282 fs.Create(t, "/tmp/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700283
284 finder := newFinder(
285 t,
286 filesystem,
287 CacheParams{
288 RootDirs: []string{"/tmp"},
289 ExcludeDirs: []string{"exclude"},
290 IncludeFiles: []string{"findme.txt", "skipme.txt"},
291 },
292 )
293 defer finder.Shutdown()
294
295 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
296
Colin Cross7f8aa392020-06-29 23:00:12 -0700297 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700298 []string{"/tmp/findme.txt",
299 "/tmp/subdir/findme.txt",
300 "/tmp/subdir/subdir/findme.txt"})
301}
302
303func TestPruneFiles(t *testing.T) {
304 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700305 fs.Create(t, "/tmp/out/findme.txt", filesystem)
306 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
307 fs.Create(t, "/tmp/out/child/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700308
Colin Cross7f8aa392020-06-29 23:00:12 -0700309 fs.Create(t, "/tmp/out2/.ignore-out-dir", filesystem)
310 fs.Create(t, "/tmp/out2/sub/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700311
Colin Cross7f8aa392020-06-29 23:00:12 -0700312 fs.Create(t, "/tmp/findme.txt", filesystem)
313 fs.Create(t, "/tmp/include/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700314
315 finder := newFinder(
316 t,
317 filesystem,
318 CacheParams{
319 RootDirs: []string{"/tmp"},
320 PruneFiles: []string{".ignore-out-dir"},
321 IncludeFiles: []string{"findme.txt"},
322 },
323 )
324 defer finder.Shutdown()
325
326 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
327
Colin Cross7f8aa392020-06-29 23:00:12 -0700328 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700329 []string{"/tmp/findme.txt",
330 "/tmp/include/findme.txt"})
331}
332
Jeff Gastond3119522017-08-22 14:11:15 -0700333// TestRootDir tests that the value of RootDirs is used
334// tests of the filesystem root are in TestFilesystemRoot
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700335func TestRootDir(t *testing.T) {
336 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700337 fs.Create(t, "/tmp/a/findme.txt", filesystem)
338 fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
339 fs.Create(t, "/tmp/b/findme.txt", filesystem)
340 fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700341
342 finder := newFinder(
343 t,
344 filesystem,
345 CacheParams{
346 RootDirs: []string{"/tmp/a"},
347 IncludeFiles: []string{"findme.txt"},
348 },
349 )
350 defer finder.Shutdown()
351
352 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
353
Colin Cross7f8aa392020-06-29 23:00:12 -0700354 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700355 []string{"/tmp/a/findme.txt",
356 "/tmp/a/subdir/findme.txt"})
357}
358
359func TestUncachedDir(t *testing.T) {
360 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700361 fs.Create(t, "/tmp/a/findme.txt", filesystem)
362 fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
363 fs.Create(t, "/tmp/b/findme.txt", filesystem)
364 fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700365
366 finder := newFinder(
367 t,
368 filesystem,
369 CacheParams{
Jeff Gastonb629e182017-08-14 16:49:18 -0700370 RootDirs: []string{"/tmp/b"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700371 IncludeFiles: []string{"findme.txt"},
372 },
373 )
374
375 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
376 // If the caller queries for a file that is in the cache, then computing the
377 // correct answer won't be fast, and it would be easy for the caller to
378 // fail to notice its slowness. Instead, we only ever search the cache for files
379 // to return, which enforces that we can determine which files will be
380 // interesting upfront.
Colin Cross7f8aa392020-06-29 23:00:12 -0700381 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700382
383 finder.Shutdown()
384}
385
386func TestSearchingForFilesExcludedFromCache(t *testing.T) {
387 // setup filesystem
388 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700389 fs.Create(t, "/tmp/findme.txt", filesystem)
390 fs.Create(t, "/tmp/a/findme.txt", filesystem)
391 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700392
393 // set up the finder and run it
394 finder := newFinder(
395 t,
396 filesystem,
397 CacheParams{
398 RootDirs: []string{"/tmp"},
399 IncludeFiles: []string{"findme.txt"},
400 },
401 )
402 foundPaths := finder.FindNamedAt("/tmp", "misc.txt")
403 // If the caller queries for a file that is in the cache, then computing the
404 // correct answer won't be fast, and it would be easy for the caller to
405 // fail to notice its slowness. Instead, we only ever search the cache for files
406 // to return, which enforces that we can determine which files will be
407 // interesting upfront.
Colin Cross7f8aa392020-06-29 23:00:12 -0700408 fs.AssertSameResponse(t, foundPaths, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700409
410 finder.Shutdown()
411}
412
413func TestRelativeFilePaths(t *testing.T) {
414 filesystem := newFs()
415
Colin Cross7f8aa392020-06-29 23:00:12 -0700416 fs.Create(t, "/tmp/ignore/hi.txt", filesystem)
417 fs.Create(t, "/tmp/include/hi.txt", filesystem)
418 fs.Create(t, "/cwd/hi.txt", filesystem)
419 fs.Create(t, "/cwd/a/hi.txt", filesystem)
420 fs.Create(t, "/cwd/a/a/hi.txt", filesystem)
421 fs.Create(t, "/rel/a/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700422
423 finder := newFinder(
424 t,
425 filesystem,
426 CacheParams{
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700427 RootDirs: []string{"/cwd", "../rel", "/tmp/include"},
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700428 IncludeFiles: []string{"hi.txt"},
429 },
430 )
431 defer finder.Shutdown()
432
433 foundPaths := finder.FindNamedAt("a", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700434 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700435 []string{"a/hi.txt",
436 "a/a/hi.txt"})
437
438 foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700439 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700440
441 foundPaths = finder.FindNamedAt(".", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700442 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700443 []string{"hi.txt",
444 "a/hi.txt",
445 "a/a/hi.txt"})
446
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700447 foundPaths = finder.FindNamedAt("/rel", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700448 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700449 []string{"/rel/a/hi.txt"})
450
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700451 foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -0700452 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700453}
454
455// have to run this test with the race-detector (`go test -race src/android/soong/finder/*.go`)
456// for there to be much chance of the test actually detecting any error that may be present
457func TestRootDirsContainedInOtherRootDirs(t *testing.T) {
458 filesystem := newFs()
459
Colin Cross7f8aa392020-06-29 23:00:12 -0700460 fs.Create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700461
462 finder := newFinder(
463 t,
464 filesystem,
465 CacheParams{
Jeff Gastonb629e182017-08-14 16:49:18 -0700466 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 -0700467 IncludeFiles: []string{"findme.txt"},
468 },
469 )
470 defer finder.Shutdown()
471
472 foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
473
Colin Cross7f8aa392020-06-29 23:00:12 -0700474 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700475 []string{"/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt"})
476}
477
478func TestFindFirst(t *testing.T) {
479 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700480 fs.Create(t, "/tmp/a/hi.txt", filesystem)
481 fs.Create(t, "/tmp/b/hi.txt", filesystem)
482 fs.Create(t, "/tmp/b/a/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700483
484 finder := newFinder(
485 t,
486 filesystem,
487 CacheParams{
488 RootDirs: []string{"/tmp"},
489 IncludeFiles: []string{"hi.txt"},
490 },
491 )
492 defer finder.Shutdown()
493
494 foundPaths := finder.FindFirstNamed("hi.txt")
495
Colin Cross7f8aa392020-06-29 23:00:12 -0700496 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700497 []string{"/tmp/a/hi.txt",
498 "/tmp/b/hi.txt"},
499 )
500}
501
502func TestConcurrentFindSameDirectory(t *testing.T) {
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700503
Jeff Gastond3119522017-08-22 14:11:15 -0700504 testWithNumThreads := func(t *testing.T, numThreads int) {
505 filesystem := newFs()
506
507 // create a bunch of files and directories
508 paths := []string{}
509 for i := 0; i < 10; i++ {
510 parentDir := fmt.Sprintf("/tmp/%v", i)
511 for j := 0; j < 10; j++ {
512 filePath := filepath.Join(parentDir, fmt.Sprintf("%v/findme.txt", j))
513 paths = append(paths, filePath)
514 }
515 }
516 sort.Strings(paths)
517 for _, path := range paths {
Colin Cross7f8aa392020-06-29 23:00:12 -0700518 fs.Create(t, path, filesystem)
Jeff Gastond3119522017-08-22 14:11:15 -0700519 }
520
521 // set up a finder
522 finder := newFinderWithNumThreads(
523 t,
524 filesystem,
525 CacheParams{
526 RootDirs: []string{"/tmp"},
527 IncludeFiles: []string{"findme.txt"},
528 },
529 numThreads,
530 )
531 defer finder.Shutdown()
532
533 numTests := 20
534 results := make(chan []string, numTests)
535 // make several parallel calls to the finder
536 for i := 0; i < numTests; i++ {
537 go func() {
538 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
539 results <- foundPaths
540 }()
541 }
542
543 // check that each response was correct
544 for i := 0; i < numTests; i++ {
545 foundPaths := <-results
Colin Cross7f8aa392020-06-29 23:00:12 -0700546 fs.AssertSameResponse(t, foundPaths, paths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700547 }
548 }
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700549
Jeff Gastond3119522017-08-22 14:11:15 -0700550 testAgainstSeveralThreadcounts(t, testWithNumThreads)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700551}
552
553func TestConcurrentFindDifferentDirectories(t *testing.T) {
554 filesystem := newFs()
555
556 // create a bunch of files and directories
557 allFiles := []string{}
558 numSubdirs := 10
559 rootPaths := []string{}
560 queryAnswers := [][]string{}
561 for i := 0; i < numSubdirs; i++ {
562 parentDir := fmt.Sprintf("/tmp/%v", i)
563 rootPaths = append(rootPaths, parentDir)
564 queryAnswers = append(queryAnswers, []string{})
565 for j := 0; j < 10; j++ {
566 filePath := filepath.Join(parentDir, fmt.Sprintf("%v/findme.txt", j))
567 queryAnswers[i] = append(queryAnswers[i], filePath)
568 allFiles = append(allFiles, filePath)
569 }
570 sort.Strings(queryAnswers[i])
571 }
572 sort.Strings(allFiles)
573 for _, path := range allFiles {
Colin Cross7f8aa392020-06-29 23:00:12 -0700574 fs.Create(t, path, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700575 }
576
577 // set up a finder
578 finder := newFinder(
579 t,
580 filesystem,
581
582 CacheParams{
583 RootDirs: []string{"/tmp"},
584 IncludeFiles: []string{"findme.txt"},
585 },
586 )
587 defer finder.Shutdown()
588
589 type testRun struct {
590 path string
591 foundMatches []string
592 correctMatches []string
593 }
594
595 numTests := numSubdirs + 1
596 testRuns := make(chan testRun, numTests)
597
598 searchAt := func(path string, correctMatches []string) {
599 foundPaths := finder.FindNamedAt(path, "findme.txt")
600 testRuns <- testRun{path, foundPaths, correctMatches}
601 }
602
603 // make several parallel calls to the finder
604 go searchAt("/tmp", allFiles)
605 for i := 0; i < len(rootPaths); i++ {
606 go searchAt(rootPaths[i], queryAnswers[i])
607 }
608
609 // check that each response was correct
610 for i := 0; i < numTests; i++ {
611 testRun := <-testRuns
Colin Cross7f8aa392020-06-29 23:00:12 -0700612 fs.AssertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700613 }
614}
615
616func TestStrangelyFormattedPaths(t *testing.T) {
617 filesystem := newFs()
618
Colin Cross7f8aa392020-06-29 23:00:12 -0700619 fs.Create(t, "/tmp/findme.txt", filesystem)
620 fs.Create(t, "/tmp/a/findme.txt", filesystem)
621 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700622
623 finder := newFinder(
624 t,
625 filesystem,
626 CacheParams{
627 RootDirs: []string{"//tmp//a//.."},
628 IncludeFiles: []string{"findme.txt"},
629 },
630 )
631 defer finder.Shutdown()
632
633 foundPaths := finder.FindNamedAt("//tmp//a//..", "findme.txt")
634
Colin Cross7f8aa392020-06-29 23:00:12 -0700635 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700636 []string{"/tmp/a/findme.txt",
637 "/tmp/b/findme.txt",
638 "/tmp/findme.txt"})
639}
640
641func TestCorruptedCacheHeader(t *testing.T) {
642 filesystem := newFs()
643
Colin Cross7f8aa392020-06-29 23:00:12 -0700644 fs.Create(t, "/tmp/findme.txt", filesystem)
645 fs.Create(t, "/tmp/a/findme.txt", filesystem)
646 fs.Write(t, "/finder/finder-db", "sample header", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700647
648 finder := newFinder(
649 t,
650 filesystem,
651 CacheParams{
652 RootDirs: []string{"/tmp"},
653 IncludeFiles: []string{"findme.txt"},
654 },
655 )
656 defer finder.Shutdown()
657
658 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
659
Colin Cross7f8aa392020-06-29 23:00:12 -0700660 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700661 []string{"/tmp/a/findme.txt",
662 "/tmp/findme.txt"})
663}
664
665func TestCanUseCache(t *testing.T) {
666 // setup filesystem
667 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700668 fs.Create(t, "/tmp/findme.txt", filesystem)
669 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700670
671 // run the first finder
672 finder := newFinder(
673 t,
674 filesystem,
675 CacheParams{
676 RootDirs: []string{"/tmp"},
677 IncludeFiles: []string{"findme.txt"},
678 },
679 )
680 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
681 // check the response of the first finder
682 correctResponse := []string{"/tmp/a/findme.txt",
683 "/tmp/findme.txt"}
Colin Cross7f8aa392020-06-29 23:00:12 -0700684 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700685 finder.Shutdown()
686
687 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700688 cacheText := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700689 if len(cacheText) < 1 {
690 t.Fatalf("saved cache db is empty\n")
691 }
692 if len(filesystem.StatCalls) == 0 {
693 t.Fatal("No Stat calls recorded by mock filesystem")
694 }
695 if len(filesystem.ReadDirCalls) == 0 {
696 t.Fatal("No ReadDir calls recorded by filesystem")
697 }
698 statCalls := filesystem.StatCalls
699 filesystem.ClearMetrics()
700
701 // run the second finder
702 finder2 := finderWithSameParams(t, finder)
703 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
704 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700705 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
706 fs.AssertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700707
708 finder2.Shutdown()
709}
710
711func TestCorruptedCacheBody(t *testing.T) {
712 // setup filesystem
713 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700714 fs.Create(t, "/tmp/findme.txt", filesystem)
715 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700716
717 // run the first finder
718 finder := newFinder(
719 t,
720 filesystem,
721 CacheParams{
722 RootDirs: []string{"/tmp"},
723 IncludeFiles: []string{"findme.txt"},
724 },
725 )
726 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
727 finder.Shutdown()
728
729 // check the response of the first finder
730 correctResponse := []string{"/tmp/a/findme.txt",
731 "/tmp/findme.txt"}
Colin Cross7f8aa392020-06-29 23:00:12 -0700732 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700733 numStatCalls := len(filesystem.StatCalls)
734 numReadDirCalls := len(filesystem.ReadDirCalls)
735
736 // load the cache file, corrupt it, and save it
737 cacheReader, err := filesystem.Open(finder.DbPath)
738 if err != nil {
739 t.Fatal(err)
740 }
741 cacheData, err := ioutil.ReadAll(cacheReader)
742 if err != nil {
743 t.Fatal(err)
744 }
745 cacheData = append(cacheData, []byte("DontMindMe")...)
746 filesystem.WriteFile(finder.DbPath, cacheData, 0777)
747 filesystem.ClearMetrics()
748
749 // run the second finder
750 finder2 := finderWithSameParams(t, finder)
751 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
752 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700753 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700754 numNewStatCalls := len(filesystem.StatCalls)
755 numNewReadDirCalls := len(filesystem.ReadDirCalls)
756 // It's permissable to make more Stat calls with a corrupted cache because
757 // the Finder may restart once it detects corruption.
758 // However, it may have already issued many Stat calls.
759 // Because a corrupted db is not expected to be a common (or even a supported case),
760 // we don't care to optimize it and don't cache the already-issued Stat calls
761 if numNewReadDirCalls < numReadDirCalls {
762 t.Fatalf(
763 "Finder made fewer ReadDir calls with a corrupted cache (%v calls) than with no cache"+
764 " (%v calls)",
765 numNewReadDirCalls, numReadDirCalls)
766 }
767 if numNewStatCalls < numStatCalls {
768 t.Fatalf(
769 "Finder made fewer Stat calls with a corrupted cache (%v calls) than with no cache (%v calls)",
770 numNewStatCalls, numStatCalls)
771 }
772 finder2.Shutdown()
773}
774
775func TestStatCalls(t *testing.T) {
776 // setup filesystem
777 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700778 fs.Create(t, "/tmp/a/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700779
780 // run finder
781 finder := newFinder(
782 t,
783 filesystem,
784 CacheParams{
785 RootDirs: []string{"/tmp"},
786 IncludeFiles: []string{"findme.txt"},
787 },
788 )
789 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
790 finder.Shutdown()
791
792 // check response
Colin Cross7f8aa392020-06-29 23:00:12 -0700793 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
794 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
795 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700796}
797
798func TestFileAdded(t *testing.T) {
799 // setup filesystem
800 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700801 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
802 fs.Create(t, "/tmp/a/findme.txt", filesystem)
803 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
804 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
805 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700806
807 // run the first finder
808 finder := newFinder(
809 t,
810 filesystem,
811 CacheParams{
812 RootDirs: []string{"/tmp"},
813 IncludeFiles: []string{"findme.txt"},
814 },
815 )
Colin Crossb8282132024-01-17 14:57:59 -0800816 finder.WaitForDbDump()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700817 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -0700818 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700819 finder.Shutdown()
820 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700821 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700822
823 // modify the filesystem
824 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700825 fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700826 filesystem.Clock.Tick()
827 filesystem.ClearMetrics()
828
829 // run the second finder
830 finder2 := finderWithSameParams(t, finder)
831 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
832
833 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700834 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
835 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
836 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700837 finder2.Shutdown()
838
839}
840
841func TestDirectoriesAdded(t *testing.T) {
842 // setup filesystem
843 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700844 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
845 fs.Create(t, "/tmp/a/findme.txt", filesystem)
846 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
847 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
848 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700849
850 // run the first finder
851 finder := newFinder(
852 t,
853 filesystem,
854 CacheParams{
855 RootDirs: []string{"/tmp"},
856 IncludeFiles: []string{"findme.txt"},
857 },
858 )
859 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
860 finder.Shutdown()
861 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700862 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700863
864 // modify the filesystem
865 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700866 fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
867 fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
868 fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700869 filesystem.ClearMetrics()
870
871 // run the second finder
872 finder2 := finderWithSameParams(t, finder)
873 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
874
875 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700876 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700877 []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 -0700878 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700879 []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 -0700880 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 -0700881
882 finder2.Shutdown()
883}
884
885func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
886 // setup filesystem
887 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700888 fs.Create(t, "/tmp/hi1.txt", filesystem)
889 fs.Create(t, "/tmp/a/hi1.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700890
891 // run the first finder
892 finder := newFinder(
893 t,
894 filesystem,
895 CacheParams{
896 RootDirs: []string{"/tmp"},
897 IncludeFiles: []string{"hi1.txt", "hi2.txt"},
898 },
899 )
900 foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
901 finder.Shutdown()
902 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700903 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700904
905 // modify the filesystem
906 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700907 fs.Create(t, "/tmp/hi2.txt", filesystem)
908 fs.Create(t, "/tmp/a/hi2.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700909 filesystem.ClearMetrics()
910
911 // run the second finder
912 finder2 := finderWithSameParams(t, finder)
913 foundPaths = finder2.FindAll()
914
915 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700916 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700917 []string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700918 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700919 []string{"/tmp", "/tmp/a"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700920 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700921
922 finder2.Shutdown()
923}
924
925func TestFileDeleted(t *testing.T) {
926 // setup filesystem
927 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700928 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
929 fs.Create(t, "/tmp/a/findme.txt", filesystem)
930 fs.Create(t, "/tmp/b/findme.txt", filesystem)
931 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
932 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700933
934 // run the first finder
935 finder := newFinder(
936 t,
937 filesystem,
938 CacheParams{
939 RootDirs: []string{"/tmp"},
940 IncludeFiles: []string{"findme.txt"},
941 },
942 )
943 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
944 finder.Shutdown()
945 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700946 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700947
948 // modify the filesystem
949 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700950 fs.Delete(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700951 filesystem.ClearMetrics()
952
953 // run the second finder
954 finder2 := finderWithSameParams(t, finder)
955 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
956
957 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700958 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
959 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
960 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700961
962 finder2.Shutdown()
963}
964
965func TestDirectoriesDeleted(t *testing.T) {
966 // setup filesystem
967 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700968 fs.Create(t, "/tmp/findme.txt", filesystem)
969 fs.Create(t, "/tmp/a/findme.txt", filesystem)
970 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
971 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
972 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700973
974 // run the first finder
975 finder := newFinder(
976 t,
977 filesystem,
978 CacheParams{
979 RootDirs: []string{"/tmp"},
980 IncludeFiles: []string{"findme.txt"},
981 },
982 )
983 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
984 finder.Shutdown()
985 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700986 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700987 []string{"/tmp/findme.txt",
988 "/tmp/a/findme.txt",
989 "/tmp/a/1/findme.txt",
990 "/tmp/a/1/2/findme.txt",
991 "/tmp/b/findme.txt"})
992
993 // modify the filesystem
994 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700995 fs.RemoveAll(t, "/tmp/a/1", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700996 filesystem.ClearMetrics()
997
998 // run the second finder
999 finder2 := finderWithSameParams(t, finder)
1000 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1001
1002 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001003 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001004 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/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"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001015 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001016
1017 finder2.Shutdown()
1018}
1019
1020func TestDirectoriesMoved(t *testing.T) {
1021 // setup filesystem
1022 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001023 fs.Create(t, "/tmp/findme.txt", filesystem)
1024 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1025 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
1026 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
1027 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001028
1029 // run the first finder
1030 finder := newFinder(
1031 t,
1032 filesystem,
1033 CacheParams{
1034 RootDirs: []string{"/tmp"},
1035 IncludeFiles: []string{"findme.txt"},
1036 },
1037 )
1038 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1039 finder.Shutdown()
1040 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001041 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001042 []string{"/tmp/findme.txt",
1043 "/tmp/a/findme.txt",
1044 "/tmp/a/1/findme.txt",
1045 "/tmp/a/1/2/findme.txt",
1046 "/tmp/b/findme.txt"})
1047
1048 // modify the filesystem
1049 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001050 fs.Move(t, "/tmp/a", "/tmp/c", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001051 filesystem.ClearMetrics()
1052
1053 // run the second finder
1054 finder2 := finderWithSameParams(t, finder)
1055 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1056
1057 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001058 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001059 []string{"/tmp/findme.txt",
1060 "/tmp/b/findme.txt",
1061 "/tmp/c/findme.txt",
1062 "/tmp/c/1/findme.txt",
1063 "/tmp/c/1/2/findme.txt"})
1064 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1065 // if the Finder detects the nonexistence of /tmp/a/1
1066 // However, when resuming from cache, we don't want the Finder to necessarily wait
1067 // to stat a directory until after statting its parent.
1068 // So here we just include /tmp/a/1/2 in the list.
1069 // The Finder is currently implemented to always restat every dir and
1070 // to not short-circuit due to nonexistence of parents (but it will remove
1071 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001072 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001073 []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 -07001074 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001075 finder2.Shutdown()
1076}
1077
1078func TestDirectoriesSwapped(t *testing.T) {
1079 // setup filesystem
1080 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001081 fs.Create(t, "/tmp/findme.txt", filesystem)
1082 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1083 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
1084 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
1085 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001086
1087 // run the first finder
1088 finder := newFinder(
1089 t,
1090 filesystem,
1091 CacheParams{
1092 RootDirs: []string{"/tmp"},
1093 IncludeFiles: []string{"findme.txt"},
1094 },
1095 )
1096 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1097 finder.Shutdown()
1098 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001099 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001100 []string{"/tmp/findme.txt",
1101 "/tmp/a/findme.txt",
1102 "/tmp/a/1/findme.txt",
1103 "/tmp/a/1/2/findme.txt",
1104 "/tmp/b/findme.txt"})
1105
1106 // modify the filesystem
1107 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001108 fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
1109 fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
1110 fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001111 filesystem.ClearMetrics()
1112
1113 // run the second finder
1114 finder2 := finderWithSameParams(t, finder)
1115 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1116
1117 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001118 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001119 []string{"/tmp/findme.txt",
1120 "/tmp/a/findme.txt",
1121 "/tmp/b/findme.txt",
1122 "/tmp/b/1/findme.txt",
1123 "/tmp/b/1/2/findme.txt"})
1124 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1125 // if the Finder detects the nonexistence of /tmp/a/1
1126 // However, when resuming from cache, we don't want the Finder to necessarily wait
1127 // to stat a directory until after statting its parent.
1128 // So here we just include /tmp/a/1/2 in the list.
1129 // The Finder is currently implemented to always restat every dir and
1130 // to not short-circuit due to nonexistence of parents (but it will remove
1131 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001132 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001133 []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 -07001134 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 -07001135 finder2.Shutdown()
1136}
1137
1138// runFsReplacementTest tests a change modifying properties of the filesystem itself:
1139// runFsReplacementTest tests changing the user, the hostname, or the device number
1140// runFsReplacementTest is a helper method called by other tests
1141func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
1142 // setup fs1
Colin Cross7f8aa392020-06-29 23:00:12 -07001143 fs.Create(t, "/tmp/findme.txt", fs1)
1144 fs.Create(t, "/tmp/a/findme.txt", fs1)
1145 fs.Create(t, "/tmp/a/a/findme.txt", fs1)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001146
1147 // setup fs2 to have the same directories but different files
Colin Cross7f8aa392020-06-29 23:00:12 -07001148 fs.Create(t, "/tmp/findme.txt", fs2)
1149 fs.Create(t, "/tmp/a/findme.txt", fs2)
1150 fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
1151 fs.Create(t, "/tmp/a/b/findme.txt", fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001152
1153 // run the first finder
1154 finder := newFinder(
1155 t,
1156 fs1,
1157 CacheParams{
1158 RootDirs: []string{"/tmp"},
1159 IncludeFiles: []string{"findme.txt"},
1160 },
1161 )
1162 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1163 finder.Shutdown()
1164 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001165 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001166 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
1167
1168 // copy the cache data from the first filesystem to the second
Colin Cross7f8aa392020-06-29 23:00:12 -07001169 cacheContent := fs.Read(t, finder.DbPath, fs1)
1170 fs.Write(t, finder.DbPath, cacheContent, fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001171
1172 // run the second finder, with the same config and same cache contents but a different filesystem
1173 finder2 := newFinder(
1174 t,
1175 fs2,
1176 CacheParams{
1177 RootDirs: []string{"/tmp"},
1178 IncludeFiles: []string{"findme.txt"},
1179 },
1180 )
1181 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1182
1183 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001184 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001185 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001186 fs.AssertSameStatCalls(t, fs2.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001187 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001188 fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001189 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
1190 finder2.Shutdown()
1191}
1192
1193func TestChangeOfDevice(t *testing.T) {
1194 fs1 := newFs()
1195 // not as fine-grained mounting controls as a real filesystem, but should be adequate
1196 fs1.SetDeviceNumber(0)
1197
1198 fs2 := newFs()
1199 fs2.SetDeviceNumber(1)
1200
1201 runFsReplacementTest(t, fs1, fs2)
1202}
1203
1204func TestChangeOfUserOrHost(t *testing.T) {
1205 fs1 := newFs()
1206 fs1.SetViewId("me@here")
1207
1208 fs2 := newFs()
1209 fs2.SetViewId("you@there")
1210
1211 runFsReplacementTest(t, fs1, fs2)
1212}
1213
1214func TestConsistentCacheOrdering(t *testing.T) {
1215 // setup filesystem
1216 filesystem := newFs()
1217 for i := 0; i < 5; i++ {
Colin Cross7f8aa392020-06-29 23:00:12 -07001218 fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001219 }
1220
1221 // run the first finder
1222 finder := newFinder(
1223 t,
1224 filesystem,
1225 CacheParams{
1226 RootDirs: []string{"/tmp"},
1227 IncludeFiles: []string{"findme.txt"},
1228 },
1229 )
1230 finder.FindNamedAt("/tmp", "findme.txt")
1231 finder.Shutdown()
1232
1233 // read db file
Colin Cross7f8aa392020-06-29 23:00:12 -07001234 string1 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001235
1236 err := filesystem.Remove(finder.DbPath)
1237 if err != nil {
1238 t.Fatal(err)
1239 }
1240
1241 // run another finder
1242 finder2 := finderWithSameParams(t, finder)
1243 finder2.FindNamedAt("/tmp", "findme.txt")
1244 finder2.Shutdown()
1245
Colin Cross7f8aa392020-06-29 23:00:12 -07001246 string2 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001247
1248 if string1 != string2 {
1249 t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
1250 "Content of first file:\n"+
1251 "\n"+
1252 "%v"+
1253 "\n"+
1254 "\n"+
1255 "Content of second file:\n"+
1256 "\n"+
1257 "%v\n"+
1258 "\n",
1259 string1,
1260 string2,
1261 )
1262 }
1263
1264}
1265
1266func TestNumSyscallsOfSecondFind(t *testing.T) {
1267 // setup filesystem
1268 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001269 fs.Create(t, "/tmp/findme.txt", filesystem)
1270 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1271 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001272
1273 // set up the finder and run it once
1274 finder := newFinder(
1275 t,
1276 filesystem,
1277 CacheParams{
1278 RootDirs: []string{"/tmp"},
1279 IncludeFiles: []string{"findme.txt"},
1280 },
1281 )
1282 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001283 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001284
1285 filesystem.ClearMetrics()
1286
1287 // run the finder again and confirm it doesn't check the filesystem
1288 refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001289 fs.AssertSameResponse(t, refoundPaths, foundPaths)
1290 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1291 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001292
1293 finder.Shutdown()
1294}
1295
1296func TestChangingParamsOfSecondFind(t *testing.T) {
1297 // setup filesystem
1298 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001299 fs.Create(t, "/tmp/findme.txt", filesystem)
1300 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1301 fs.Create(t, "/tmp/a/metoo.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001302
1303 // set up the finder and run it once
1304 finder := newFinder(
1305 t,
1306 filesystem,
1307 CacheParams{
1308 RootDirs: []string{"/tmp"},
1309 IncludeFiles: []string{"findme.txt", "metoo.txt"},
1310 },
1311 )
1312 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001313 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001314
1315 filesystem.ClearMetrics()
1316
1317 // run the finder again and confirm it gets the right answer without asking the filesystem
1318 refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001319 fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
1320 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1321 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001322
1323 finder.Shutdown()
1324}
1325
1326func TestSymlinkPointingToFile(t *testing.T) {
1327 // setup filesystem
1328 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001329 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1330 fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
1331 fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
1332 fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
1333 fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
1334 fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
1335 fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
1336 fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
1337 fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001338
1339 // set up the finder and run it once
1340 finder := newFinder(
1341 t,
1342 filesystem,
1343 CacheParams{
1344 RootDirs: []string{"/tmp"},
1345 IncludeFiles: []string{"hi.txt"},
1346 },
1347 )
1348 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1349 // should search based on the name of the link rather than the destination or validity of the link
1350 correctResponse := []string{
1351 "/tmp/a/hi.txt",
1352 "/tmp/hi.txt",
1353 "/tmp/b/hi.txt",
1354 "/tmp/c/hi.txt",
1355 "/tmp/d/hi.txt",
1356 "/tmp/f/hi.txt",
1357 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001358 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001359
1360}
1361
1362func TestSymlinkPointingToDirectory(t *testing.T) {
1363 // setup filesystem
1364 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001365 fs.Create(t, "/tmp/dir/hi.txt", filesystem)
1366 fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001367
Colin Cross7f8aa392020-06-29 23:00:12 -07001368 fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
1369 fs.Link(t, "/tmp/links/link", "../dir", filesystem)
Colin Cross25fd7732020-06-29 23:11:55 -07001370 fs.Link(t, "/tmp/links/hi.txt", "../dir", filesystem)
Colin Cross7f8aa392020-06-29 23:00:12 -07001371 fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
1372 fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001373
1374 // set up the finder and run it once
1375 finder := newFinder(
1376 t,
1377 filesystem,
1378 CacheParams{
1379 RootDirs: []string{"/tmp"},
1380 IncludeFiles: []string{"hi.txt"},
1381 },
1382 )
1383
1384 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1385
1386 // should completely ignore symlinks that point to directories
1387 correctResponse := []string{
1388 "/tmp/dir/hi.txt",
1389 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001390 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001391
1392}
1393
1394// TestAddPruneFile confirms that adding a prune-file (into a directory for which we
1395// already had a cache) causes the directory to be ignored
1396func TestAddPruneFile(t *testing.T) {
1397 // setup filesystem
1398 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001399 fs.Create(t, "/tmp/out/hi.txt", filesystem)
1400 fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
1401 fs.Create(t, "/tmp/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001402
1403 // do find
1404 finder := newFinder(
1405 t,
1406 filesystem,
1407 CacheParams{
1408 RootDirs: []string{"/tmp"},
1409 PruneFiles: []string{".ignore-out-dir"},
1410 IncludeFiles: []string{"hi.txt"},
1411 },
1412 )
1413
1414 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1415
1416 // check result
Colin Cross7f8aa392020-06-29 23:00:12 -07001417 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001418 []string{"/tmp/hi.txt",
1419 "/tmp/out/hi.txt",
1420 "/tmp/out/a/hi.txt"},
1421 )
1422 finder.Shutdown()
1423
1424 // modify filesystem
1425 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001426 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001427 // run another find and check its result
1428 finder2 := finderWithSameParams(t, finder)
1429 foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001430 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001431 finder2.Shutdown()
1432}
1433
1434func TestUpdatingDbIffChanged(t *testing.T) {
1435 // setup filesystem
1436 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001437 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1438 fs.Create(t, "/tmp/b/bye.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001439
1440 // run the first finder
1441 finder := newFinder(
1442 t,
1443 filesystem,
1444 CacheParams{
1445 RootDirs: []string{"/tmp"},
1446 IncludeFiles: []string{"hi.txt"},
1447 },
1448 )
Colin Crossb8282132024-01-17 14:57:59 -08001449 finder.WaitForDbDump()
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 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001454 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001455
1456 // modify the filesystem
1457 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001458 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001459 filesystem.Clock.Tick()
1460 filesystem.ClearMetrics()
1461
1462 // run the second finder
1463 finder2 := finderWithSameParams(t, finder)
1464 foundPaths = finder2.FindAll()
1465 finder2.Shutdown()
1466 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001467 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1468 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001469 expectedDbWriteTime := filesystem.Clock.Time()
Colin Cross7f8aa392020-06-29 23:00:12 -07001470 actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001471 if actualDbWriteTime != expectedDbWriteTime {
1472 t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
1473 expectedDbWriteTime, actualDbWriteTime)
1474 }
1475
1476 // reset metrics
1477 filesystem.ClearMetrics()
1478
1479 // run the third finder
1480 finder3 := finderWithSameParams(t, finder2)
1481 foundPaths = finder3.FindAll()
1482
1483 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001484 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1485 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001486 finder3.Shutdown()
Colin Cross7f8aa392020-06-29 23:00:12 -07001487 actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001488 if actualDbWriteTime != expectedDbWriteTime {
1489 t.Fatalf("Re-wrote db even when contents did not change")
1490 }
1491
1492}
1493
1494func TestDirectoryNotPermitted(t *testing.T) {
1495 // setup filesystem
1496 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001497 fs.Create(t, "/tmp/hi.txt", filesystem)
1498 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1499 fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
1500 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001501
1502 // run the first finder
1503 finder := newFinder(
1504 t,
1505 filesystem,
1506 CacheParams{
1507 RootDirs: []string{"/tmp"},
1508 IncludeFiles: []string{"hi.txt"},
1509 },
1510 )
Colin Crossb8282132024-01-17 14:57:59 -08001511 finder.WaitForDbDump()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001512 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001513 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001514 finder.Shutdown()
1515 allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
1516 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001517 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001518
1519 // modify the filesystem
1520 filesystem.Clock.Tick()
1521
Colin Cross7f8aa392020-06-29 23:00:12 -07001522 fs.SetReadable(t, "/tmp/a", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001523 filesystem.Clock.Tick()
1524
1525 // run the second finder
1526 finder2 := finderWithSameParams(t, finder)
1527 foundPaths = finder2.FindAll()
1528 finder2.Shutdown()
1529 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001530 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001531
1532 // modify the filesystem back
Colin Cross7f8aa392020-06-29 23:00:12 -07001533 fs.SetReadable(t, "/tmp/a", true, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001534
1535 // run the third finder
1536 finder3 := finderWithSameParams(t, finder2)
1537 foundPaths = finder3.FindAll()
1538 finder3.Shutdown()
1539 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001540 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001541}
1542
1543func TestFileNotPermitted(t *testing.T) {
1544 // setup filesystem
1545 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001546 fs.Create(t, "/tmp/hi.txt", filesystem)
1547 fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001548
1549 // run the first finder
1550 finder := newFinder(
1551 t,
1552 filesystem,
1553 CacheParams{
1554 RootDirs: []string{"/tmp"},
1555 IncludeFiles: []string{"hi.txt"},
1556 },
1557 )
Colin Crossb8282132024-01-17 14:57:59 -08001558 finder.WaitForDbDump()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001559 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001560 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001561 finder.Shutdown()
1562 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001563 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001564}
Jeff Gastonb629e182017-08-14 16:49:18 -07001565
1566func TestCacheEntryPathUnexpectedError(t *testing.T) {
1567 // setup filesystem
1568 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001569 fs.Create(t, "/tmp/a/hi.txt", filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001570
1571 // run the first finder
1572 finder := newFinder(
1573 t,
1574 filesystem,
1575 CacheParams{
1576 RootDirs: []string{"/tmp"},
1577 IncludeFiles: []string{"hi.txt"},
1578 },
1579 )
Colin Crossb8282132024-01-17 14:57:59 -08001580 finder.WaitForDbDump()
Jeff Gastonb629e182017-08-14 16:49:18 -07001581 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001582 foundPaths := finder.FindAll()
Jeff Gastonb629e182017-08-14 16:49:18 -07001583 finder.Shutdown()
1584 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001585 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonb629e182017-08-14 16:49:18 -07001586
1587 // make the directory not readable
Colin Cross7f8aa392020-06-29 23:00:12 -07001588 fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001589
1590 // run the second finder
1591 _, err := finderAndErrorWithSameParams(t, finder)
1592 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -07001593 t.Fatal("Failed to detect unexpected filesystem error")
Jeff Gastonb629e182017-08-14 16:49:18 -07001594 }
1595}