blob: 8f73719a6c161cbe5bcffb94c8b2826ff3bfbe3e [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 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700816 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -0700817 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700818 finder.Shutdown()
819 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700820 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700821
822 // modify the filesystem
823 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700824 fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700825 filesystem.Clock.Tick()
826 filesystem.ClearMetrics()
827
828 // run the second finder
829 finder2 := finderWithSameParams(t, finder)
830 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
831
832 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700833 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
834 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
835 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700836 finder2.Shutdown()
837
838}
839
840func TestDirectoriesAdded(t *testing.T) {
841 // setup filesystem
842 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700843 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
844 fs.Create(t, "/tmp/a/findme.txt", filesystem)
845 fs.Create(t, "/tmp/b/ignore.txt", filesystem)
846 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
847 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700848
849 // run the first finder
850 finder := newFinder(
851 t,
852 filesystem,
853 CacheParams{
854 RootDirs: []string{"/tmp"},
855 IncludeFiles: []string{"findme.txt"},
856 },
857 )
858 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
859 finder.Shutdown()
860 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700861 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700862
863 // modify the filesystem
864 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700865 fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
866 fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
867 fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700868 filesystem.ClearMetrics()
869
870 // run the second finder
871 finder2 := finderWithSameParams(t, finder)
872 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
873
874 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700875 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700876 []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 -0700877 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700878 []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 -0700879 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 -0700880
881 finder2.Shutdown()
882}
883
884func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
885 // setup filesystem
886 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700887 fs.Create(t, "/tmp/hi1.txt", filesystem)
888 fs.Create(t, "/tmp/a/hi1.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700889
890 // run the first finder
891 finder := newFinder(
892 t,
893 filesystem,
894 CacheParams{
895 RootDirs: []string{"/tmp"},
896 IncludeFiles: []string{"hi1.txt", "hi2.txt"},
897 },
898 )
899 foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
900 finder.Shutdown()
901 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700902 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700903
904 // modify the filesystem
905 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700906 fs.Create(t, "/tmp/hi2.txt", filesystem)
907 fs.Create(t, "/tmp/a/hi2.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700908 filesystem.ClearMetrics()
909
910 // run the second finder
911 finder2 := finderWithSameParams(t, finder)
912 foundPaths = finder2.FindAll()
913
914 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700915 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700916 []string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700917 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700918 []string{"/tmp", "/tmp/a"})
Colin Cross7f8aa392020-06-29 23:00:12 -0700919 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700920
921 finder2.Shutdown()
922}
923
924func TestFileDeleted(t *testing.T) {
925 // setup filesystem
926 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700927 fs.Create(t, "/tmp/ignoreme.txt", filesystem)
928 fs.Create(t, "/tmp/a/findme.txt", filesystem)
929 fs.Create(t, "/tmp/b/findme.txt", filesystem)
930 fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
931 fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700932
933 // run the first finder
934 finder := newFinder(
935 t,
936 filesystem,
937 CacheParams{
938 RootDirs: []string{"/tmp"},
939 IncludeFiles: []string{"findme.txt"},
940 },
941 )
942 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
943 finder.Shutdown()
944 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700945 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700946
947 // modify the filesystem
948 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700949 fs.Delete(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700950 filesystem.ClearMetrics()
951
952 // run the second finder
953 finder2 := finderWithSameParams(t, finder)
954 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
955
956 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -0700957 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
958 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
959 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700960
961 finder2.Shutdown()
962}
963
964func TestDirectoriesDeleted(t *testing.T) {
965 // setup filesystem
966 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -0700967 fs.Create(t, "/tmp/findme.txt", filesystem)
968 fs.Create(t, "/tmp/a/findme.txt", filesystem)
969 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
970 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
971 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700972
973 // run the first finder
974 finder := newFinder(
975 t,
976 filesystem,
977 CacheParams{
978 RootDirs: []string{"/tmp"},
979 IncludeFiles: []string{"findme.txt"},
980 },
981 )
982 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
983 finder.Shutdown()
984 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -0700985 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700986 []string{"/tmp/findme.txt",
987 "/tmp/a/findme.txt",
988 "/tmp/a/1/findme.txt",
989 "/tmp/a/1/2/findme.txt",
990 "/tmp/b/findme.txt"})
991
992 // modify the filesystem
993 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -0700994 fs.RemoveAll(t, "/tmp/a/1", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -0700995 filesystem.ClearMetrics()
996
997 // run the second finder
998 finder2 := finderWithSameParams(t, finder)
999 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1000
1001 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001002 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001003 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/findme.txt"})
1004 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1005 // if the Finder detects the nonexistence of /tmp/a/1
1006 // However, when resuming from cache, we don't want the Finder to necessarily wait
1007 // to stat a directory until after statting its parent.
1008 // So here we just include /tmp/a/1/2 in the list.
1009 // The Finder is currently implemented to always restat every dir and
1010 // to not short-circuit due to nonexistence of parents (but it will remove
1011 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001012 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001013 []string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001014 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001015
1016 finder2.Shutdown()
1017}
1018
1019func TestDirectoriesMoved(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/c", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001050 filesystem.ClearMetrics()
1051
1052 // run the second finder
1053 finder2 := finderWithSameParams(t, finder)
1054 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1055
1056 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001057 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001058 []string{"/tmp/findme.txt",
1059 "/tmp/b/findme.txt",
1060 "/tmp/c/findme.txt",
1061 "/tmp/c/1/findme.txt",
1062 "/tmp/c/1/2/findme.txt"})
1063 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1064 // if the Finder detects the nonexistence of /tmp/a/1
1065 // However, when resuming from cache, we don't want the Finder to necessarily wait
1066 // to stat a directory until after statting its parent.
1067 // So here we just include /tmp/a/1/2 in the list.
1068 // The Finder is currently implemented to always restat every dir and
1069 // to not short-circuit due to nonexistence of parents (but it will remove
1070 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001071 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001072 []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 -07001073 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001074 finder2.Shutdown()
1075}
1076
1077func TestDirectoriesSwapped(t *testing.T) {
1078 // setup filesystem
1079 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001080 fs.Create(t, "/tmp/findme.txt", filesystem)
1081 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1082 fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
1083 fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
1084 fs.Create(t, "/tmp/b/findme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001085
1086 // run the first finder
1087 finder := newFinder(
1088 t,
1089 filesystem,
1090 CacheParams{
1091 RootDirs: []string{"/tmp"},
1092 IncludeFiles: []string{"findme.txt"},
1093 },
1094 )
1095 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1096 finder.Shutdown()
1097 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001098 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001099 []string{"/tmp/findme.txt",
1100 "/tmp/a/findme.txt",
1101 "/tmp/a/1/findme.txt",
1102 "/tmp/a/1/2/findme.txt",
1103 "/tmp/b/findme.txt"})
1104
1105 // modify the filesystem
1106 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001107 fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
1108 fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
1109 fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001110 filesystem.ClearMetrics()
1111
1112 // run the second finder
1113 finder2 := finderWithSameParams(t, finder)
1114 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1115
1116 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001117 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001118 []string{"/tmp/findme.txt",
1119 "/tmp/a/findme.txt",
1120 "/tmp/b/findme.txt",
1121 "/tmp/b/1/findme.txt",
1122 "/tmp/b/1/2/findme.txt"})
1123 // Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
1124 // if the Finder detects the nonexistence of /tmp/a/1
1125 // However, when resuming from cache, we don't want the Finder to necessarily wait
1126 // to stat a directory until after statting its parent.
1127 // So here we just include /tmp/a/1/2 in the list.
1128 // The Finder is currently implemented to always restat every dir and
1129 // to not short-circuit due to nonexistence of parents (but it will remove
1130 // missing dirs from the cache for next time)
Colin Cross7f8aa392020-06-29 23:00:12 -07001131 fs.AssertSameStatCalls(t, filesystem.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001132 []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 -07001133 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 -07001134 finder2.Shutdown()
1135}
1136
1137// runFsReplacementTest tests a change modifying properties of the filesystem itself:
1138// runFsReplacementTest tests changing the user, the hostname, or the device number
1139// runFsReplacementTest is a helper method called by other tests
1140func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
1141 // setup fs1
Colin Cross7f8aa392020-06-29 23:00:12 -07001142 fs.Create(t, "/tmp/findme.txt", fs1)
1143 fs.Create(t, "/tmp/a/findme.txt", fs1)
1144 fs.Create(t, "/tmp/a/a/findme.txt", fs1)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001145
1146 // setup fs2 to have the same directories but different files
Colin Cross7f8aa392020-06-29 23:00:12 -07001147 fs.Create(t, "/tmp/findme.txt", fs2)
1148 fs.Create(t, "/tmp/a/findme.txt", fs2)
1149 fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
1150 fs.Create(t, "/tmp/a/b/findme.txt", fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001151
1152 // run the first finder
1153 finder := newFinder(
1154 t,
1155 fs1,
1156 CacheParams{
1157 RootDirs: []string{"/tmp"},
1158 IncludeFiles: []string{"findme.txt"},
1159 },
1160 )
1161 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
1162 finder.Shutdown()
1163 // check the response of the first finder
Colin Cross7f8aa392020-06-29 23:00:12 -07001164 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001165 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
1166
1167 // copy the cache data from the first filesystem to the second
Colin Cross7f8aa392020-06-29 23:00:12 -07001168 cacheContent := fs.Read(t, finder.DbPath, fs1)
1169 fs.Write(t, finder.DbPath, cacheContent, fs2)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001170
1171 // run the second finder, with the same config and same cache contents but a different filesystem
1172 finder2 := newFinder(
1173 t,
1174 fs2,
1175 CacheParams{
1176 RootDirs: []string{"/tmp"},
1177 IncludeFiles: []string{"findme.txt"},
1178 },
1179 )
1180 foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
1181
1182 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001183 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001184 []string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001185 fs.AssertSameStatCalls(t, fs2.StatCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001186 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
Colin Cross7f8aa392020-06-29 23:00:12 -07001187 fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001188 []string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
1189 finder2.Shutdown()
1190}
1191
1192func TestChangeOfDevice(t *testing.T) {
1193 fs1 := newFs()
1194 // not as fine-grained mounting controls as a real filesystem, but should be adequate
1195 fs1.SetDeviceNumber(0)
1196
1197 fs2 := newFs()
1198 fs2.SetDeviceNumber(1)
1199
1200 runFsReplacementTest(t, fs1, fs2)
1201}
1202
1203func TestChangeOfUserOrHost(t *testing.T) {
1204 fs1 := newFs()
1205 fs1.SetViewId("me@here")
1206
1207 fs2 := newFs()
1208 fs2.SetViewId("you@there")
1209
1210 runFsReplacementTest(t, fs1, fs2)
1211}
1212
1213func TestConsistentCacheOrdering(t *testing.T) {
1214 // setup filesystem
1215 filesystem := newFs()
1216 for i := 0; i < 5; i++ {
Colin Cross7f8aa392020-06-29 23:00:12 -07001217 fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001218 }
1219
1220 // run the first finder
1221 finder := newFinder(
1222 t,
1223 filesystem,
1224 CacheParams{
1225 RootDirs: []string{"/tmp"},
1226 IncludeFiles: []string{"findme.txt"},
1227 },
1228 )
1229 finder.FindNamedAt("/tmp", "findme.txt")
1230 finder.Shutdown()
1231
1232 // read db file
Colin Cross7f8aa392020-06-29 23:00:12 -07001233 string1 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001234
1235 err := filesystem.Remove(finder.DbPath)
1236 if err != nil {
1237 t.Fatal(err)
1238 }
1239
1240 // run another finder
1241 finder2 := finderWithSameParams(t, finder)
1242 finder2.FindNamedAt("/tmp", "findme.txt")
1243 finder2.Shutdown()
1244
Colin Cross7f8aa392020-06-29 23:00:12 -07001245 string2 := fs.Read(t, finder.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001246
1247 if string1 != string2 {
1248 t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
1249 "Content of first file:\n"+
1250 "\n"+
1251 "%v"+
1252 "\n"+
1253 "\n"+
1254 "Content of second file:\n"+
1255 "\n"+
1256 "%v\n"+
1257 "\n",
1258 string1,
1259 string2,
1260 )
1261 }
1262
1263}
1264
1265func TestNumSyscallsOfSecondFind(t *testing.T) {
1266 // setup filesystem
1267 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001268 fs.Create(t, "/tmp/findme.txt", filesystem)
1269 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1270 fs.Create(t, "/tmp/a/misc.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001271
1272 // set up the finder and run it once
1273 finder := newFinder(
1274 t,
1275 filesystem,
1276 CacheParams{
1277 RootDirs: []string{"/tmp"},
1278 IncludeFiles: []string{"findme.txt"},
1279 },
1280 )
1281 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001282 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001283
1284 filesystem.ClearMetrics()
1285
1286 // run the finder again and confirm it doesn't check the filesystem
1287 refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001288 fs.AssertSameResponse(t, refoundPaths, foundPaths)
1289 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1290 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001291
1292 finder.Shutdown()
1293}
1294
1295func TestChangingParamsOfSecondFind(t *testing.T) {
1296 // setup filesystem
1297 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001298 fs.Create(t, "/tmp/findme.txt", filesystem)
1299 fs.Create(t, "/tmp/a/findme.txt", filesystem)
1300 fs.Create(t, "/tmp/a/metoo.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001301
1302 // set up the finder and run it once
1303 finder := newFinder(
1304 t,
1305 filesystem,
1306 CacheParams{
1307 RootDirs: []string{"/tmp"},
1308 IncludeFiles: []string{"findme.txt", "metoo.txt"},
1309 },
1310 )
1311 foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001312 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001313
1314 filesystem.ClearMetrics()
1315
1316 // run the finder again and confirm it gets the right answer without asking the filesystem
1317 refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001318 fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
1319 fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
1320 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001321
1322 finder.Shutdown()
1323}
1324
1325func TestSymlinkPointingToFile(t *testing.T) {
1326 // setup filesystem
1327 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001328 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1329 fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
1330 fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
1331 fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
1332 fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
1333 fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
1334 fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
1335 fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
1336 fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001337
1338 // set up the finder and run it once
1339 finder := newFinder(
1340 t,
1341 filesystem,
1342 CacheParams{
1343 RootDirs: []string{"/tmp"},
1344 IncludeFiles: []string{"hi.txt"},
1345 },
1346 )
1347 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1348 // should search based on the name of the link rather than the destination or validity of the link
1349 correctResponse := []string{
1350 "/tmp/a/hi.txt",
1351 "/tmp/hi.txt",
1352 "/tmp/b/hi.txt",
1353 "/tmp/c/hi.txt",
1354 "/tmp/d/hi.txt",
1355 "/tmp/f/hi.txt",
1356 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001357 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001358
1359}
1360
1361func TestSymlinkPointingToDirectory(t *testing.T) {
1362 // setup filesystem
1363 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001364 fs.Create(t, "/tmp/dir/hi.txt", filesystem)
1365 fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001366
Colin Cross7f8aa392020-06-29 23:00:12 -07001367 fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
1368 fs.Link(t, "/tmp/links/link", "../dir", filesystem)
Colin Cross25fd7732020-06-29 23:11:55 -07001369 fs.Link(t, "/tmp/links/hi.txt", "../dir", filesystem)
Colin Cross7f8aa392020-06-29 23:00:12 -07001370 fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
1371 fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001372
1373 // set up the finder and run it once
1374 finder := newFinder(
1375 t,
1376 filesystem,
1377 CacheParams{
1378 RootDirs: []string{"/tmp"},
1379 IncludeFiles: []string{"hi.txt"},
1380 },
1381 )
1382
1383 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1384
1385 // should completely ignore symlinks that point to directories
1386 correctResponse := []string{
1387 "/tmp/dir/hi.txt",
1388 }
Colin Cross7f8aa392020-06-29 23:00:12 -07001389 fs.AssertSameResponse(t, foundPaths, correctResponse)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001390
1391}
1392
1393// TestAddPruneFile confirms that adding a prune-file (into a directory for which we
1394// already had a cache) causes the directory to be ignored
1395func TestAddPruneFile(t *testing.T) {
1396 // setup filesystem
1397 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001398 fs.Create(t, "/tmp/out/hi.txt", filesystem)
1399 fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
1400 fs.Create(t, "/tmp/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001401
1402 // do find
1403 finder := newFinder(
1404 t,
1405 filesystem,
1406 CacheParams{
1407 RootDirs: []string{"/tmp"},
1408 PruneFiles: []string{".ignore-out-dir"},
1409 IncludeFiles: []string{"hi.txt"},
1410 },
1411 )
1412
1413 foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
1414
1415 // check result
Colin Cross7f8aa392020-06-29 23:00:12 -07001416 fs.AssertSameResponse(t, foundPaths,
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001417 []string{"/tmp/hi.txt",
1418 "/tmp/out/hi.txt",
1419 "/tmp/out/a/hi.txt"},
1420 )
1421 finder.Shutdown()
1422
1423 // modify filesystem
1424 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001425 fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001426 // run another find and check its result
1427 finder2 := finderWithSameParams(t, finder)
1428 foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
Colin Cross7f8aa392020-06-29 23:00:12 -07001429 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001430 finder2.Shutdown()
1431}
1432
1433func TestUpdatingDbIffChanged(t *testing.T) {
1434 // setup filesystem
1435 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001436 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1437 fs.Create(t, "/tmp/b/bye.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001438
1439 // run the first finder
1440 finder := newFinder(
1441 t,
1442 filesystem,
1443 CacheParams{
1444 RootDirs: []string{"/tmp"},
1445 IncludeFiles: []string{"hi.txt"},
1446 },
1447 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001448 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001449 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001450 finder.Shutdown()
1451 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001452 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001453
1454 // modify the filesystem
1455 filesystem.Clock.Tick()
Colin Cross7f8aa392020-06-29 23:00:12 -07001456 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001457 filesystem.Clock.Tick()
1458 filesystem.ClearMetrics()
1459
1460 // run the second finder
1461 finder2 := finderWithSameParams(t, finder)
1462 foundPaths = finder2.FindAll()
1463 finder2.Shutdown()
1464 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001465 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1466 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001467 expectedDbWriteTime := filesystem.Clock.Time()
Colin Cross7f8aa392020-06-29 23:00:12 -07001468 actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001469 if actualDbWriteTime != expectedDbWriteTime {
1470 t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
1471 expectedDbWriteTime, actualDbWriteTime)
1472 }
1473
1474 // reset metrics
1475 filesystem.ClearMetrics()
1476
1477 // run the third finder
1478 finder3 := finderWithSameParams(t, finder2)
1479 foundPaths = finder3.FindAll()
1480
1481 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001482 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
1483 fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001484 finder3.Shutdown()
Colin Cross7f8aa392020-06-29 23:00:12 -07001485 actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001486 if actualDbWriteTime != expectedDbWriteTime {
1487 t.Fatalf("Re-wrote db even when contents did not change")
1488 }
1489
1490}
1491
1492func TestDirectoryNotPermitted(t *testing.T) {
1493 // setup filesystem
1494 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001495 fs.Create(t, "/tmp/hi.txt", filesystem)
1496 fs.Create(t, "/tmp/a/hi.txt", filesystem)
1497 fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
1498 fs.Create(t, "/tmp/b/hi.txt", filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001499
1500 // run the first finder
1501 finder := newFinder(
1502 t,
1503 filesystem,
1504 CacheParams{
1505 RootDirs: []string{"/tmp"},
1506 IncludeFiles: []string{"hi.txt"},
1507 },
1508 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001509 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001510 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001511 finder.Shutdown()
1512 allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
1513 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001514 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001515
1516 // modify the filesystem
1517 filesystem.Clock.Tick()
1518
Colin Cross7f8aa392020-06-29 23:00:12 -07001519 fs.SetReadable(t, "/tmp/a", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001520 filesystem.Clock.Tick()
1521
1522 // run the second finder
1523 finder2 := finderWithSameParams(t, finder)
1524 foundPaths = finder2.FindAll()
1525 finder2.Shutdown()
1526 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001527 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001528
1529 // modify the filesystem back
Colin Cross7f8aa392020-06-29 23:00:12 -07001530 fs.SetReadable(t, "/tmp/a", true, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001531
1532 // run the third finder
1533 finder3 := finderWithSameParams(t, finder2)
1534 foundPaths = finder3.FindAll()
1535 finder3.Shutdown()
1536 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001537 fs.AssertSameResponse(t, foundPaths, allPaths)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001538}
1539
1540func TestFileNotPermitted(t *testing.T) {
1541 // setup filesystem
1542 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001543 fs.Create(t, "/tmp/hi.txt", filesystem)
1544 fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001545
1546 // run the first finder
1547 finder := newFinder(
1548 t,
1549 filesystem,
1550 CacheParams{
1551 RootDirs: []string{"/tmp"},
1552 IncludeFiles: []string{"hi.txt"},
1553 },
1554 )
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001555 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001556 foundPaths := finder.FindAll()
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001557 finder.Shutdown()
1558 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001559 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
Jeff Gastonf1fd45e2017-08-09 18:25:28 -07001560}
Jeff Gastonb629e182017-08-14 16:49:18 -07001561
1562func TestCacheEntryPathUnexpectedError(t *testing.T) {
1563 // setup filesystem
1564 filesystem := newFs()
Colin Cross7f8aa392020-06-29 23:00:12 -07001565 fs.Create(t, "/tmp/a/hi.txt", filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001566
1567 // run the first finder
1568 finder := newFinder(
1569 t,
1570 filesystem,
1571 CacheParams{
1572 RootDirs: []string{"/tmp"},
1573 IncludeFiles: []string{"hi.txt"},
1574 },
1575 )
Jeff Gastonb629e182017-08-14 16:49:18 -07001576 filesystem.Clock.Tick()
Colin Cross2f5a4842019-06-20 14:13:05 -07001577 foundPaths := finder.FindAll()
Jeff Gastonb629e182017-08-14 16:49:18 -07001578 finder.Shutdown()
1579 // check results
Colin Cross7f8aa392020-06-29 23:00:12 -07001580 fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
Jeff Gastonb629e182017-08-14 16:49:18 -07001581
1582 // make the directory not readable
Colin Cross7f8aa392020-06-29 23:00:12 -07001583 fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
Jeff Gastonb629e182017-08-14 16:49:18 -07001584
1585 // run the second finder
1586 _, err := finderAndErrorWithSameParams(t, finder)
1587 if err == nil {
Colin Cross7f8aa392020-06-29 23:00:12 -07001588 t.Fatal("Failed to detect unexpected filesystem error")
Jeff Gastonb629e182017-08-14 16:49:18 -07001589 }
1590}