fsmonitor--daemon: cd out of worktree root
[alt-git.git] / t / t7519-status-fsmonitor.sh
blob156895f943747017dd249954913bc8baf6c7d803
1 #!/bin/sh
3 test_description='git status with file system watcher'
5 . ./test-lib.sh
7 # Note, after "git reset --hard HEAD" no extensions exist other than 'TREE'
8 # "git update-index --fsmonitor" can be used to get the extension written
9 # before testing the results.
11 clean_repo () {
12 git reset --hard HEAD &&
13 git clean -fd
16 dirty_repo () {
17 : >untracked &&
18 : >dir1/untracked &&
19 : >dir2/untracked &&
20 echo 1 >modified &&
21 echo 2 >dir1/modified &&
22 echo 3 >dir2/modified &&
23 echo 4 >new &&
24 echo 5 >dir1/new &&
25 echo 6 >dir2/new
28 write_integration_script () {
29 write_script .git/hooks/fsmonitor-test<<-\EOF
30 if test "$#" -ne 2
31 then
32 echo "$0: exactly 2 arguments expected"
33 exit 2
35 if test "$1" != 2
36 then
37 echo "Unsupported core.fsmonitor hook version." >&2
38 exit 1
40 printf "last_update_token\0"
41 printf "untracked\0"
42 printf "dir1/untracked\0"
43 printf "dir2/untracked\0"
44 printf "modified\0"
45 printf "dir1/modified\0"
46 printf "dir2/modified\0"
47 printf "new\0"
48 printf "dir1/new\0"
49 printf "dir2/new\0"
50 EOF
53 test_lazy_prereq UNTRACKED_CACHE '
54 { git update-index --test-untracked-cache; ret=$?; } &&
55 test $ret -ne 1
58 # Test that we detect and disallow repos that are incompatible with FSMonitor.
59 test_expect_success 'incompatible bare repo' '
60 test_when_finished "rm -rf ./bare-clone actual expect" &&
61 git init --bare bare-clone &&
63 test_must_fail \
64 git -C ./bare-clone -c core.fsmonitor=foo \
65 update-index --fsmonitor 2>actual &&
66 grep "bare repository .* is incompatible with fsmonitor" actual &&
68 test_must_fail \
69 git -C ./bare-clone -c core.fsmonitor=true \
70 update-index --fsmonitor 2>actual &&
71 grep "bare repository .* is incompatible with fsmonitor" actual
74 test_expect_success FSMONITOR_DAEMON 'run fsmonitor-daemon in bare repo' '
75 test_when_finished "rm -rf ./bare-clone actual" &&
76 git init --bare bare-clone &&
77 test_must_fail git -C ./bare-clone fsmonitor--daemon run 2>actual &&
78 grep "bare repository .* is incompatible with fsmonitor" actual
81 test_expect_success MINGW,FSMONITOR_DAEMON 'run fsmonitor-daemon in virtual repo' '
82 test_when_finished "rm -rf ./fake-virtual-clone actual" &&
83 git init fake-virtual-clone &&
84 test_must_fail git -C ./fake-virtual-clone \
85 -c core.virtualfilesystem=true \
86 fsmonitor--daemon run 2>actual &&
87 grep "virtual repository .* is incompatible with fsmonitor" actual
90 test_expect_success 'setup' '
91 mkdir -p .git/hooks &&
92 : >tracked &&
93 : >modified &&
94 mkdir dir1 &&
95 : >dir1/tracked &&
96 : >dir1/modified &&
97 mkdir dir2 &&
98 : >dir2/tracked &&
99 : >dir2/modified &&
100 git -c core.fsmonitor= add . &&
101 git -c core.fsmonitor= commit -m initial &&
102 git config core.fsmonitor .git/hooks/fsmonitor-test &&
103 cat >.gitignore <<-\EOF
104 .gitignore
105 expect*
106 actual*
107 marker*
108 trace2*
112 # test that the fsmonitor extension is off by default
113 test_expect_success 'fsmonitor extension is off by default' '
114 test-tool dump-fsmonitor >actual &&
115 grep "^no fsmonitor" actual
118 # test that "update-index --fsmonitor" adds the fsmonitor extension
119 test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' '
120 git update-index --fsmonitor &&
121 test-tool dump-fsmonitor >actual &&
122 grep "^fsmonitor last update" actual
125 # test that "update-index --no-fsmonitor" removes the fsmonitor extension
126 test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' '
127 git update-index --no-fsmonitor &&
128 test-tool dump-fsmonitor >actual &&
129 grep "^no fsmonitor" actual
132 cat >expect <<EOF &&
133 h dir1/modified
134 H dir1/tracked
135 h dir2/modified
136 H dir2/tracked
137 h modified
138 H tracked
141 # test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
142 test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
143 write_script .git/hooks/fsmonitor-test<<-\EOF &&
144 printf "last_update_token\0"
146 git update-index --fsmonitor &&
147 git update-index --fsmonitor-valid dir1/modified &&
148 git update-index --fsmonitor-valid dir2/modified &&
149 git update-index --fsmonitor-valid modified &&
150 git ls-files -f >actual &&
151 test_cmp expect actual
154 cat >expect <<EOF &&
155 H dir1/modified
156 H dir1/tracked
157 H dir2/modified
158 H dir2/tracked
159 H modified
160 H tracked
163 # test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
164 test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor valid bit' '
165 git update-index --no-fsmonitor-valid dir1/modified &&
166 git update-index --no-fsmonitor-valid dir2/modified &&
167 git update-index --no-fsmonitor-valid modified &&
168 git ls-files -f >actual &&
169 test_cmp expect actual
172 cat >expect <<EOF &&
173 H dir1/modified
174 H dir1/tracked
175 H dir2/modified
176 H dir2/tracked
177 H modified
178 H tracked
181 # test that all files returned by the script get flagged as invalid
182 test_expect_success 'all files returned by integration script get flagged as invalid' '
183 write_integration_script &&
184 dirty_repo &&
185 git update-index --fsmonitor &&
186 git ls-files -f >actual &&
187 test_cmp expect actual
190 cat >expect <<EOF &&
191 H dir1/modified
192 h dir1/new
193 H dir1/tracked
194 H dir2/modified
195 h dir2/new
196 H dir2/tracked
197 H modified
198 h new
199 H tracked
202 # test that newly added files are marked valid
203 test_expect_success 'newly added files are marked valid' '
204 write_script .git/hooks/fsmonitor-test<<-\EOF &&
205 printf "last_update_token\0"
207 git add new &&
208 git add dir1/new &&
209 git add dir2/new &&
210 git ls-files -f >actual &&
211 test_cmp expect actual
214 cat >expect <<EOF &&
215 H dir1/modified
216 h dir1/new
217 h dir1/tracked
218 H dir2/modified
219 h dir2/new
220 h dir2/tracked
221 H modified
222 h new
223 h tracked
226 # test that all unmodified files get marked valid
227 test_expect_success 'all unmodified files get marked valid' '
228 # modified files result in update-index returning 1
229 test_must_fail git update-index --refresh --force-write-index &&
230 git ls-files -f >actual &&
231 test_cmp expect actual
234 cat >expect <<EOF &&
235 H dir1/modified
236 h dir1/tracked
237 h dir2/modified
238 h dir2/tracked
239 h modified
240 h tracked
243 # test that *only* files returned by the integration script get flagged as invalid
244 test_expect_success '*only* files returned by the integration script get flagged as invalid' '
245 write_script .git/hooks/fsmonitor-test<<-\EOF &&
246 printf "last_update_token\0"
247 printf "dir1/modified\0"
249 clean_repo &&
250 git update-index --refresh --force-write-index &&
251 echo 1 >modified &&
252 echo 2 >dir1/modified &&
253 echo 3 >dir2/modified &&
254 test_must_fail git update-index --refresh --force-write-index &&
255 git ls-files -f >actual &&
256 test_cmp expect actual
259 # Ensure commands that call refresh_index() to move the index back in time
260 # properly invalidate the fsmonitor cache
261 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
262 clean_repo &&
263 dirty_repo &&
264 write_integration_script &&
265 git add . &&
266 write_script .git/hooks/fsmonitor-test<<-\EOF &&
268 git commit -m "to reset" &&
269 git reset HEAD~1 &&
270 git status >actual &&
271 git -c core.fsmonitor= status >expect &&
272 test_cmp expect actual
275 # test fsmonitor with and without preloadIndex
276 preload_values="false true"
277 for preload_val in $preload_values
279 test_expect_success "setup preloadIndex to $preload_val" '
280 git config core.preloadIndex $preload_val &&
281 if test $preload_val = true
282 then
283 GIT_TEST_PRELOAD_INDEX=$preload_val && export GIT_TEST_PRELOAD_INDEX
284 else
285 sane_unset GIT_TEST_PRELOAD_INDEX
289 # test fsmonitor with and without the untracked cache (if available)
290 uc_values="false"
291 test_have_prereq UNTRACKED_CACHE && uc_values="false true"
292 for uc_val in $uc_values
294 test_expect_success "setup untracked cache to $uc_val" '
295 git config core.untrackedcache $uc_val
298 # Status is well tested elsewhere so we'll just ensure that the results are
299 # the same when using core.fsmonitor.
300 test_expect_success 'compare status with and without fsmonitor' '
301 write_integration_script &&
302 clean_repo &&
303 dirty_repo &&
304 git add new &&
305 git add dir1/new &&
306 git add dir2/new &&
307 git status >actual &&
308 git -c core.fsmonitor= status >expect &&
309 test_cmp expect actual
312 # Make sure it's actually skipping the check for modified and untracked
313 # (if enabled) files unless it is told about them.
314 test_expect_success "status doesn't detect unreported modifications" '
315 write_script .git/hooks/fsmonitor-test<<-\EOF &&
316 printf "last_update_token\0"
317 :>marker
319 clean_repo &&
320 git status &&
321 test_path_is_file marker &&
322 dirty_repo &&
323 rm -f marker &&
324 git status >actual &&
325 test_path_is_file marker &&
326 test_i18ngrep ! "Changes not staged for commit:" actual &&
327 if test $uc_val = true
328 then
329 test_i18ngrep ! "Untracked files:" actual
330 fi &&
331 if test $uc_val = false
332 then
333 test_i18ngrep "Untracked files:" actual
334 fi &&
335 rm -f marker
337 done
338 done
340 # test that splitting the index doesn't interfere
341 test_expect_success 'splitting the index results in the same state' '
342 write_integration_script &&
343 dirty_repo &&
344 git update-index --fsmonitor &&
345 git ls-files -f >expect &&
346 test-tool dump-fsmonitor >&2 && echo &&
347 git update-index --fsmonitor --split-index &&
348 test-tool dump-fsmonitor >&2 && echo &&
349 git ls-files -f >actual &&
350 test_cmp expect actual
353 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
354 test_create_repo dot-git &&
356 cd dot-git &&
357 mkdir -p .git/hooks &&
358 : >tracked &&
359 : >modified &&
360 mkdir dir1 &&
361 : >dir1/tracked &&
362 : >dir1/modified &&
363 mkdir dir2 &&
364 : >dir2/tracked &&
365 : >dir2/modified &&
366 write_integration_script &&
367 git config core.fsmonitor .git/hooks/fsmonitor-test &&
368 git update-index --untracked-cache &&
369 git update-index --fsmonitor &&
370 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \
371 git status &&
372 test-tool dump-untracked-cache >../before
373 ) &&
374 cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
375 printf ".git\0"
376 printf ".git/index\0"
377 printf "dir1/.git\0"
378 printf "dir1/.git/index\0"
381 cd dot-git &&
382 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-after" \
383 git status &&
384 test-tool dump-untracked-cache >../after
385 ) &&
386 grep "directory-invalidation" trace-before | cut -d"|" -f 9 >>before &&
387 grep "directory-invalidation" trace-after | cut -d"|" -f 9 >>after &&
388 # UNTR extension unchanged, dir invalidation count unchanged
389 test_cmp before after
392 test_expect_success 'discard_index() also discards fsmonitor info' '
393 test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" &&
394 test_might_fail git update-index --refresh &&
395 test-tool read-cache --print-and-refresh=tracked 2 >actual &&
396 printf "tracked is%s up to date\n" "" " not" >expect &&
397 test_cmp expect actual
400 # Test unstaging entries that:
401 # - Are not flagged with CE_FSMONITOR_VALID
402 # - Have a position in the index >= the number of entries present in the index
403 # after unstaging.
404 test_expect_success 'status succeeds after staging/unstaging' '
405 test_create_repo fsmonitor-stage-unstage &&
407 cd fsmonitor-stage-unstage &&
408 test_commit initial &&
409 git update-index --fsmonitor &&
410 removed=$(test_seq 1 100 | sed "s/^/z/") &&
411 touch $removed &&
412 git add $removed &&
413 git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
414 FSMONITOR_LIST="$removed" git restore -S $removed &&
415 FSMONITOR_LIST="$removed" git status
419 # Usage:
420 # check_sparse_index_behavior [!]
421 # If "!" is supplied, then we verify that we do not call ensure_full_index
422 # during a call to 'git status'. Otherwise, we verify that we _do_ call it.
423 check_sparse_index_behavior () {
424 git -C full status --porcelain=v2 >expect &&
425 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
426 git -C sparse status --porcelain=v2 >actual &&
427 test_region $1 index ensure_full_index trace2.txt &&
428 test_region fsm_hook query trace2.txt &&
429 test_cmp expect actual &&
430 rm trace2.txt
433 test_expect_success 'status succeeds with sparse index' '
435 sane_unset GIT_TEST_SPLIT_INDEX &&
437 git clone . full &&
438 git clone --sparse . sparse &&
439 git -C sparse sparse-checkout init --cone --sparse-index &&
440 git -C sparse sparse-checkout set dir1 dir2 &&
442 write_script .git/hooks/fsmonitor-test <<-\EOF &&
443 printf "last_update_token\0"
445 git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&
446 git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&
447 check_sparse_index_behavior ! &&
449 write_script .git/hooks/fsmonitor-test <<-\EOF &&
450 printf "last_update_token\0"
451 printf "dir1/modified\0"
453 check_sparse_index_behavior ! &&
455 git -C sparse sparse-checkout add dir1a &&
457 for repo in full sparse
459 cp -r $repo/dir1 $repo/dir1a &&
460 git -C $repo add dir1a &&
461 git -C $repo commit -m "add dir1a" || return 1
462 done &&
463 git -C sparse sparse-checkout set dir1 dir2 &&
465 # This one modifies outside the sparse-checkout definition
466 # and hence we expect to expand the sparse-index.
467 write_script .git/hooks/fsmonitor-test <<-\EOF &&
468 printf "last_update_token\0"
469 printf "dir1a/modified\0"
471 check_sparse_index_behavior
475 test_done