Merge branch 'jk/repack-leakfix'
[git.git] / t / t7519-status-fsmonitor.sh
blob8348e3ae7db70d9c6a65606c3b400c485a3a8719
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 test_hook --setup --clobber 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 : >tracked &&
92 : >modified &&
93 mkdir dir1 &&
94 : >dir1/tracked &&
95 : >dir1/modified &&
96 mkdir dir2 &&
97 : >dir2/tracked &&
98 : >dir2/modified &&
99 git -c core.fsmonitor= add . &&
100 git -c core.fsmonitor= commit -m initial &&
101 git config core.fsmonitor .git/hooks/fsmonitor-test &&
102 cat >.gitignore <<-\EOF
103 .gitignore
104 expect*
105 actual*
106 marker*
107 trace2*
111 # test that the fsmonitor extension is off by default
112 test_expect_success 'fsmonitor extension is off by default' '
113 test-tool dump-fsmonitor >actual &&
114 grep "^no fsmonitor" actual
117 # test that "update-index --fsmonitor" adds the fsmonitor extension
118 test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' '
119 git update-index --fsmonitor &&
120 test-tool dump-fsmonitor >actual &&
121 grep "^fsmonitor last update" actual
124 # test that "update-index --no-fsmonitor" removes the fsmonitor extension
125 test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' '
126 git update-index --no-fsmonitor &&
127 test-tool dump-fsmonitor >actual &&
128 grep "^no fsmonitor" actual
131 cat >expect <<EOF &&
132 h dir1/modified
133 H dir1/tracked
134 h dir2/modified
135 H dir2/tracked
136 h modified
137 H tracked
140 # test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
141 test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
142 test_hook fsmonitor-test<<-\EOF &&
143 printf "last_update_token\0"
145 git update-index --fsmonitor &&
146 git update-index --fsmonitor-valid dir1/modified &&
147 git update-index --fsmonitor-valid dir2/modified &&
148 git update-index --fsmonitor-valid modified &&
149 git ls-files -f >actual &&
150 test_cmp expect actual
153 cat >expect <<EOF &&
154 H dir1/modified
155 H dir1/tracked
156 H dir2/modified
157 H dir2/tracked
158 H modified
159 H tracked
162 # test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
163 test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor valid bit' '
164 git update-index --no-fsmonitor-valid dir1/modified &&
165 git update-index --no-fsmonitor-valid dir2/modified &&
166 git update-index --no-fsmonitor-valid modified &&
167 git ls-files -f >actual &&
168 test_cmp expect actual
171 cat >expect <<EOF &&
172 H dir1/modified
173 H dir1/tracked
174 H dir2/modified
175 H dir2/tracked
176 H modified
177 H tracked
180 # test that all files returned by the script get flagged as invalid
181 test_expect_success 'all files returned by integration script get flagged as invalid' '
182 write_integration_script &&
183 dirty_repo &&
184 git update-index --fsmonitor &&
185 git ls-files -f >actual &&
186 test_cmp expect actual
189 cat >expect <<EOF &&
190 H dir1/modified
191 h dir1/new
192 H dir1/tracked
193 H dir2/modified
194 h dir2/new
195 H dir2/tracked
196 H modified
197 h new
198 H tracked
201 # test that newly added files are marked valid
202 test_expect_success 'newly added files are marked valid' '
203 test_hook --setup --clobber fsmonitor-test<<-\EOF &&
204 printf "last_update_token\0"
206 git add new &&
207 git add dir1/new &&
208 git add dir2/new &&
209 git ls-files -f >actual &&
210 test_cmp expect actual
213 cat >expect <<EOF &&
214 H dir1/modified
215 h dir1/new
216 h dir1/tracked
217 H dir2/modified
218 h dir2/new
219 h dir2/tracked
220 H modified
221 h new
222 h tracked
225 # test that all unmodified files get marked valid
226 test_expect_success 'all unmodified files get marked valid' '
227 # modified files result in update-index returning 1
228 test_must_fail git update-index --refresh --force-write-index &&
229 git ls-files -f >actual &&
230 test_cmp expect actual
233 cat >expect <<EOF &&
234 H dir1/modified
235 h dir1/tracked
236 h dir2/modified
237 h dir2/tracked
238 h modified
239 h tracked
242 # test that *only* files returned by the integration script get flagged as invalid
243 test_expect_success '*only* files returned by the integration script get flagged as invalid' '
244 test_hook --clobber fsmonitor-test<<-\EOF &&
245 printf "last_update_token\0"
246 printf "dir1/modified\0"
248 clean_repo &&
249 git update-index --refresh --force-write-index &&
250 echo 1 >modified &&
251 echo 2 >dir1/modified &&
252 echo 3 >dir2/modified &&
253 test_must_fail git update-index --refresh --force-write-index &&
254 git ls-files -f >actual &&
255 test_cmp expect actual
258 # Ensure commands that call refresh_index() to move the index back in time
259 # properly invalidate the fsmonitor cache
260 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
261 clean_repo &&
262 dirty_repo &&
263 write_integration_script &&
264 git add . &&
265 test_hook --clobber fsmonitor-test<<-\EOF &&
267 git commit -m "to reset" &&
268 git reset HEAD~1 &&
269 git status >actual &&
270 git -c core.fsmonitor= status >expect &&
271 test_cmp expect actual
274 # test fsmonitor with and without preloadIndex
275 preload_values="false true"
276 for preload_val in $preload_values
278 test_expect_success "setup preloadIndex to $preload_val" '
279 git config core.preloadIndex $preload_val &&
280 if test $preload_val = true
281 then
282 GIT_TEST_PRELOAD_INDEX=$preload_val && export GIT_TEST_PRELOAD_INDEX
283 else
284 sane_unset GIT_TEST_PRELOAD_INDEX
288 # test fsmonitor with and without the untracked cache (if available)
289 uc_values="false"
290 test_have_prereq UNTRACKED_CACHE && uc_values="false true"
291 for uc_val in $uc_values
293 test_expect_success "setup untracked cache to $uc_val" '
294 git config core.untrackedcache $uc_val
297 # Status is well tested elsewhere so we'll just ensure that the results are
298 # the same when using core.fsmonitor.
299 test_expect_success 'compare status with and without fsmonitor' '
300 write_integration_script &&
301 clean_repo &&
302 dirty_repo &&
303 git add new &&
304 git add dir1/new &&
305 git add dir2/new &&
306 git status >actual &&
307 git -c core.fsmonitor= status >expect &&
308 test_cmp expect actual
311 # Make sure it's actually skipping the check for modified and untracked
312 # (if enabled) files unless it is told about them.
313 test_expect_success "status doesn't detect unreported modifications" '
314 test_hook --clobber fsmonitor-test<<-\EOF &&
315 printf "last_update_token\0"
316 :>marker
318 clean_repo &&
319 git status &&
320 test_path_is_file marker &&
321 dirty_repo &&
322 rm -f marker &&
323 git status >actual &&
324 test_path_is_file marker &&
325 test_i18ngrep ! "Changes not staged for commit:" actual &&
326 if test $uc_val = true
327 then
328 test_i18ngrep ! "Untracked files:" actual
329 fi &&
330 if test $uc_val = false
331 then
332 test_i18ngrep "Untracked files:" actual
333 fi &&
334 rm -f marker
336 done
337 done
339 # test that splitting the index doesn't interfere
340 test_expect_success 'splitting the index results in the same state' '
341 write_integration_script &&
342 dirty_repo &&
343 git update-index --fsmonitor &&
344 git ls-files -f >expect &&
345 test-tool dump-fsmonitor >&2 && echo &&
346 git update-index --fsmonitor --split-index &&
347 test-tool dump-fsmonitor >&2 && echo &&
348 git ls-files -f >actual &&
349 test_cmp expect actual
352 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
353 test_create_repo dot-git &&
355 cd dot-git &&
356 : >tracked &&
357 test-tool chmtime =-60 tracked &&
358 : >modified &&
359 test-tool chmtime =-60 modified &&
360 mkdir dir1 &&
361 : >dir1/tracked &&
362 test-tool chmtime =-60 dir1/tracked &&
363 : >dir1/modified &&
364 test-tool chmtime =-60 dir1/modified &&
365 mkdir dir2 &&
366 : >dir2/tracked &&
367 test-tool chmtime =-60 dir2/tracked &&
368 : >dir2/modified &&
369 test-tool chmtime =-60 dir2/modified &&
370 write_integration_script &&
371 git config core.fsmonitor .git/hooks/fsmonitor-test &&
372 git update-index --untracked-cache &&
373 git update-index --fsmonitor &&
374 git status &&
375 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \
376 git status &&
377 test-tool dump-untracked-cache >../before
378 ) &&
379 cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
380 printf ".git\0"
381 printf ".git/index\0"
382 printf "dir1/.git\0"
383 printf "dir1/.git/index\0"
386 cd dot-git &&
387 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-after" \
388 git status &&
389 test-tool dump-untracked-cache >../after
390 ) &&
391 grep "directory-invalidation" trace-before | cut -d"|" -f 9 >>before &&
392 grep "directory-invalidation" trace-after | cut -d"|" -f 9 >>after &&
393 # UNTR extension unchanged, dir invalidation count unchanged
394 test_cmp before after
397 test_expect_success 'discard_index() also discards fsmonitor info' '
398 test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" &&
399 test_might_fail git update-index --refresh &&
400 test-tool read-cache --print-and-refresh=tracked 2 >actual &&
401 printf "tracked is%s up to date\n" "" " not" >expect &&
402 test_cmp expect actual
405 # Test unstaging entries that:
406 # - Are not flagged with CE_FSMONITOR_VALID
407 # - Have a position in the index >= the number of entries present in the index
408 # after unstaging.
409 test_expect_success 'status succeeds after staging/unstaging' '
410 test_create_repo fsmonitor-stage-unstage &&
412 cd fsmonitor-stage-unstage &&
413 test_commit initial &&
414 git update-index --fsmonitor &&
415 removed=$(test_seq 1 100 | sed "s/^/z/") &&
416 touch $removed &&
417 git add $removed &&
418 git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
419 FSMONITOR_LIST="$removed" git restore -S $removed &&
420 FSMONITOR_LIST="$removed" git status
424 # Usage:
425 # check_sparse_index_behavior [!]
426 # If "!" is supplied, then we verify that we do not call ensure_full_index
427 # during a call to 'git status'. Otherwise, we verify that we _do_ call it.
428 check_sparse_index_behavior () {
429 git -C full status --porcelain=v2 >expect &&
430 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
431 git -C sparse status --porcelain=v2 >actual &&
432 test_region $1 index ensure_full_index trace2.txt &&
433 test_region fsm_hook query trace2.txt &&
434 test_cmp expect actual &&
435 rm trace2.txt
438 test_expect_success 'status succeeds with sparse index' '
440 sane_unset GIT_TEST_SPLIT_INDEX &&
442 git clone . full &&
443 git clone --sparse . sparse &&
444 git -C sparse sparse-checkout init --cone --sparse-index &&
445 git -C sparse sparse-checkout set dir1 dir2 &&
447 test_hook --clobber fsmonitor-test <<-\EOF &&
448 printf "last_update_token\0"
450 git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&
451 git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&
452 check_sparse_index_behavior ! &&
454 test_hook --clobber fsmonitor-test <<-\EOF &&
455 printf "last_update_token\0"
456 printf "dir1/modified\0"
458 check_sparse_index_behavior ! &&
460 git -C sparse sparse-checkout add dir1a &&
462 for repo in full sparse
464 cp -r $repo/dir1 $repo/dir1a &&
465 git -C $repo add dir1a &&
466 git -C $repo commit -m "add dir1a" || return 1
467 done &&
468 git -C sparse sparse-checkout set dir1 dir2 &&
470 # This one modifies outside the sparse-checkout definition
471 # and hence we expect to expand the sparse-index.
472 test_hook --clobber fsmonitor-test <<-\EOF &&
473 printf "last_update_token\0"
474 printf "dir1a/modified\0"
476 check_sparse_index_behavior
480 test_done