Merge branch 'gc/submodule-update-part2' into maint
[alt-git.git] / t / t7519-status-fsmonitor.sh
blobd4f9c6a837b18075a3bff10a7c87e7932e4e46fe
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_expect_success 'setup' '
59 : >tracked &&
60 : >modified &&
61 mkdir dir1 &&
62 : >dir1/tracked &&
63 : >dir1/modified &&
64 mkdir dir2 &&
65 : >dir2/tracked &&
66 : >dir2/modified &&
67 git -c core.fsmonitor= add . &&
68 git -c core.fsmonitor= commit -m initial &&
69 git config core.fsmonitor .git/hooks/fsmonitor-test &&
70 cat >.gitignore <<-\EOF
71 .gitignore
72 expect*
73 actual*
74 marker*
75 trace2*
76 EOF
79 # test that the fsmonitor extension is off by default
80 test_expect_success 'fsmonitor extension is off by default' '
81 test-tool dump-fsmonitor >actual &&
82 grep "^no fsmonitor" actual
85 # test that "update-index --fsmonitor" adds the fsmonitor extension
86 test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' '
87 git update-index --fsmonitor &&
88 test-tool dump-fsmonitor >actual &&
89 grep "^fsmonitor last update" actual
92 # test that "update-index --no-fsmonitor" removes the fsmonitor extension
93 test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' '
94 git update-index --no-fsmonitor &&
95 test-tool dump-fsmonitor >actual &&
96 grep "^no fsmonitor" actual
99 cat >expect <<EOF &&
100 h dir1/modified
101 H dir1/tracked
102 h dir2/modified
103 H dir2/tracked
104 h modified
105 H tracked
108 # test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
109 test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
110 test_hook fsmonitor-test<<-\EOF &&
111 printf "last_update_token\0"
113 git update-index --fsmonitor &&
114 git update-index --fsmonitor-valid dir1/modified &&
115 git update-index --fsmonitor-valid dir2/modified &&
116 git update-index --fsmonitor-valid modified &&
117 git ls-files -f >actual &&
118 test_cmp expect actual
121 cat >expect <<EOF &&
122 H dir1/modified
123 H dir1/tracked
124 H dir2/modified
125 H dir2/tracked
126 H modified
127 H tracked
130 # test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
131 test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor valid bit' '
132 git update-index --no-fsmonitor-valid dir1/modified &&
133 git update-index --no-fsmonitor-valid dir2/modified &&
134 git update-index --no-fsmonitor-valid modified &&
135 git ls-files -f >actual &&
136 test_cmp expect actual
139 cat >expect <<EOF &&
140 H dir1/modified
141 H dir1/tracked
142 H dir2/modified
143 H dir2/tracked
144 H modified
145 H tracked
148 # test that all files returned by the script get flagged as invalid
149 test_expect_success 'all files returned by integration script get flagged as invalid' '
150 write_integration_script &&
151 dirty_repo &&
152 git update-index --fsmonitor &&
153 git ls-files -f >actual &&
154 test_cmp expect actual
157 cat >expect <<EOF &&
158 H dir1/modified
159 h dir1/new
160 H dir1/tracked
161 H dir2/modified
162 h dir2/new
163 H dir2/tracked
164 H modified
165 h new
166 H tracked
169 # test that newly added files are marked valid
170 test_expect_success 'newly added files are marked valid' '
171 test_hook --setup --clobber fsmonitor-test<<-\EOF &&
172 printf "last_update_token\0"
174 git add new &&
175 git add dir1/new &&
176 git add dir2/new &&
177 git ls-files -f >actual &&
178 test_cmp expect actual
181 cat >expect <<EOF &&
182 H dir1/modified
183 h dir1/new
184 h dir1/tracked
185 H dir2/modified
186 h dir2/new
187 h dir2/tracked
188 H modified
189 h new
190 h tracked
193 # test that all unmodified files get marked valid
194 test_expect_success 'all unmodified files get marked valid' '
195 # modified files result in update-index returning 1
196 test_must_fail git update-index --refresh --force-write-index &&
197 git ls-files -f >actual &&
198 test_cmp expect actual
201 cat >expect <<EOF &&
202 H dir1/modified
203 h dir1/tracked
204 h dir2/modified
205 h dir2/tracked
206 h modified
207 h tracked
210 # test that *only* files returned by the integration script get flagged as invalid
211 test_expect_success '*only* files returned by the integration script get flagged as invalid' '
212 test_hook --clobber fsmonitor-test<<-\EOF &&
213 printf "last_update_token\0"
214 printf "dir1/modified\0"
216 clean_repo &&
217 git update-index --refresh --force-write-index &&
218 echo 1 >modified &&
219 echo 2 >dir1/modified &&
220 echo 3 >dir2/modified &&
221 test_must_fail git update-index --refresh --force-write-index &&
222 git ls-files -f >actual &&
223 test_cmp expect actual
226 # Ensure commands that call refresh_index() to move the index back in time
227 # properly invalidate the fsmonitor cache
228 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
229 clean_repo &&
230 dirty_repo &&
231 write_integration_script &&
232 git add . &&
233 test_hook --clobber fsmonitor-test<<-\EOF &&
235 git commit -m "to reset" &&
236 git reset HEAD~1 &&
237 git status >actual &&
238 git -c core.fsmonitor= status >expect &&
239 test_cmp expect actual
242 # test fsmonitor with and without preloadIndex
243 preload_values="false true"
244 for preload_val in $preload_values
246 test_expect_success "setup preloadIndex to $preload_val" '
247 git config core.preloadIndex $preload_val &&
248 if test $preload_val = true
249 then
250 GIT_TEST_PRELOAD_INDEX=$preload_val && export GIT_TEST_PRELOAD_INDEX
251 else
252 sane_unset GIT_TEST_PRELOAD_INDEX
256 # test fsmonitor with and without the untracked cache (if available)
257 uc_values="false"
258 test_have_prereq UNTRACKED_CACHE && uc_values="false true"
259 for uc_val in $uc_values
261 test_expect_success "setup untracked cache to $uc_val" '
262 git config core.untrackedcache $uc_val
265 # Status is well tested elsewhere so we'll just ensure that the results are
266 # the same when using core.fsmonitor.
267 test_expect_success 'compare status with and without fsmonitor' '
268 write_integration_script &&
269 clean_repo &&
270 dirty_repo &&
271 git add new &&
272 git add dir1/new &&
273 git add dir2/new &&
274 git status >actual &&
275 git -c core.fsmonitor= status >expect &&
276 test_cmp expect actual
279 # Make sure it's actually skipping the check for modified and untracked
280 # (if enabled) files unless it is told about them.
281 test_expect_success "status doesn't detect unreported modifications" '
282 test_hook --clobber fsmonitor-test<<-\EOF &&
283 printf "last_update_token\0"
284 :>marker
286 clean_repo &&
287 git status &&
288 test_path_is_file marker &&
289 dirty_repo &&
290 rm -f marker &&
291 git status >actual &&
292 test_path_is_file marker &&
293 test_i18ngrep ! "Changes not staged for commit:" actual &&
294 if test $uc_val = true
295 then
296 test_i18ngrep ! "Untracked files:" actual
297 fi &&
298 if test $uc_val = false
299 then
300 test_i18ngrep "Untracked files:" actual
301 fi &&
302 rm -f marker
304 done
305 done
307 # test that splitting the index doesn't interfere
308 test_expect_success 'splitting the index results in the same state' '
309 write_integration_script &&
310 dirty_repo &&
311 git update-index --fsmonitor &&
312 git ls-files -f >expect &&
313 test-tool dump-fsmonitor >&2 && echo &&
314 git update-index --fsmonitor --split-index &&
315 test-tool dump-fsmonitor >&2 && echo &&
316 git ls-files -f >actual &&
317 test_cmp expect actual
320 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
321 test_create_repo dot-git &&
323 cd dot-git &&
324 : >tracked &&
325 test-tool chmtime =-60 tracked &&
326 : >modified &&
327 test-tool chmtime =-60 modified &&
328 mkdir dir1 &&
329 : >dir1/tracked &&
330 test-tool chmtime =-60 dir1/tracked &&
331 : >dir1/modified &&
332 test-tool chmtime =-60 dir1/modified &&
333 mkdir dir2 &&
334 : >dir2/tracked &&
335 test-tool chmtime =-60 dir2/tracked &&
336 : >dir2/modified &&
337 test-tool chmtime =-60 dir2/modified &&
338 write_integration_script &&
339 git config core.fsmonitor .git/hooks/fsmonitor-test &&
340 git update-index --untracked-cache &&
341 git update-index --fsmonitor &&
342 git status &&
343 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \
344 git status &&
345 test-tool dump-untracked-cache >../before
346 ) &&
347 cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
348 printf ".git\0"
349 printf ".git/index\0"
350 printf "dir1/.git\0"
351 printf "dir1/.git/index\0"
354 cd dot-git &&
355 GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-after" \
356 git status &&
357 test-tool dump-untracked-cache >../after
358 ) &&
359 grep "directory-invalidation" trace-before | cut -d"|" -f 9 >>before &&
360 grep "directory-invalidation" trace-after | cut -d"|" -f 9 >>after &&
361 # UNTR extension unchanged, dir invalidation count unchanged
362 test_cmp before after
365 test_expect_success 'discard_index() also discards fsmonitor info' '
366 test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" &&
367 test_might_fail git update-index --refresh &&
368 test-tool read-cache --print-and-refresh=tracked 2 >actual &&
369 printf "tracked is%s up to date\n" "" " not" >expect &&
370 test_cmp expect actual
373 # Test unstaging entries that:
374 # - Are not flagged with CE_FSMONITOR_VALID
375 # - Have a position in the index >= the number of entries present in the index
376 # after unstaging.
377 test_expect_success 'status succeeds after staging/unstaging' '
378 test_create_repo fsmonitor-stage-unstage &&
380 cd fsmonitor-stage-unstage &&
381 test_commit initial &&
382 git update-index --fsmonitor &&
383 removed=$(test_seq 1 100 | sed "s/^/z/") &&
384 touch $removed &&
385 git add $removed &&
386 git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
387 FSMONITOR_LIST="$removed" git restore -S $removed &&
388 FSMONITOR_LIST="$removed" git status
392 # Usage:
393 # check_sparse_index_behavior [!]
394 # If "!" is supplied, then we verify that we do not call ensure_full_index
395 # during a call to 'git status'. Otherwise, we verify that we _do_ call it.
396 check_sparse_index_behavior () {
397 git -C full status --porcelain=v2 >expect &&
398 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
399 git -C sparse status --porcelain=v2 >actual &&
400 test_region $1 index ensure_full_index trace2.txt &&
401 test_region fsm_hook query trace2.txt &&
402 test_cmp expect actual &&
403 rm trace2.txt
406 test_expect_success 'status succeeds with sparse index' '
408 sane_unset GIT_TEST_SPLIT_INDEX &&
410 git clone . full &&
411 git clone --sparse . sparse &&
412 git -C sparse sparse-checkout init --cone --sparse-index &&
413 git -C sparse sparse-checkout set dir1 dir2 &&
415 test_hook --clobber fsmonitor-test <<-\EOF &&
416 printf "last_update_token\0"
418 git -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&
419 git -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&
420 check_sparse_index_behavior ! &&
422 test_hook --clobber fsmonitor-test <<-\EOF &&
423 printf "last_update_token\0"
424 printf "dir1/modified\0"
426 check_sparse_index_behavior ! &&
428 git -C sparse sparse-checkout add dir1a &&
430 for repo in full sparse
432 cp -r $repo/dir1 $repo/dir1a &&
433 git -C $repo add dir1a &&
434 git -C $repo commit -m "add dir1a" || return 1
435 done &&
436 git -C sparse sparse-checkout set dir1 dir2 &&
438 # This one modifies outside the sparse-checkout definition
439 # and hence we expect to expand the sparse-index.
440 test_hook --clobber fsmonitor-test <<-\EOF &&
441 printf "last_update_token\0"
442 printf "dir1a/modified\0"
444 check_sparse_index_behavior
448 test_done