Merge branch 'es/worktree-repair'
[git] / t / t7519-status-fsmonitor.sh
1 #!/bin/sh
2
3 test_description='git status with file system watcher'
4
5 . ./test-lib.sh
6
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.
10
11 clean_repo () {
12         git reset --hard HEAD &&
13         git clean -fd
14 }
15
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
26 }
27
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
34         fi
35         if test "$1" != 2
36         then
37                 echo "Unsupported core.fsmonitor hook version." >&2
38                 exit 1
39         fi
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
51 }
52
53 test_lazy_prereq UNTRACKED_CACHE '
54         { git update-index --test-untracked-cache; ret=$?; } &&
55         test $ret -ne 1
56 '
57
58 test_expect_success 'setup' '
59         mkdir -p .git/hooks &&
60         : >tracked &&
61         : >modified &&
62         mkdir dir1 &&
63         : >dir1/tracked &&
64         : >dir1/modified &&
65         mkdir dir2 &&
66         : >dir2/tracked &&
67         : >dir2/modified &&
68         git -c core.fsmonitor= add . &&
69         git -c core.fsmonitor= commit -m initial &&
70         git config core.fsmonitor .git/hooks/fsmonitor-test &&
71         cat >.gitignore <<-\EOF
72         .gitignore
73         expect*
74         actual*
75         marker*
76         EOF
77 '
78
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
83 '
84
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
90 '
91
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
97 '
98
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
106 EOF
107
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         write_script .git/hooks/fsmonitor-test<<-\EOF &&
111                 printf "last_update_token\0"
112         EOF
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
119 '
120
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
128 EOF
129
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
137 '
138
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
146 EOF
147
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
155 '
156
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
167 EOF
168
169 # test that newly added files are marked valid
170 test_expect_success 'newly added files are marked valid' '
171         write_script .git/hooks/fsmonitor-test<<-\EOF &&
172                 printf "last_update_token\0"
173         EOF
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
179 '
180
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
191 EOF
192
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
199 '
200
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
208 EOF
209
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         write_script .git/hooks/fsmonitor-test<<-\EOF &&
213         printf "last_update_token\0"
214         printf "dir1/modified\0"
215         EOF
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
224 '
225
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         write_script .git/hooks/fsmonitor-test<<-\EOF &&
234         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_i18ncmp expect actual
240 '
241
242 # test fsmonitor with and without preloadIndex
243 preload_values="false true"
244 for preload_val in $preload_values
245 do
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
253                 fi
254         '
255
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
260         do
261                 test_expect_success "setup untracked cache to $uc_val" '
262                         git config core.untrackedcache $uc_val
263                 '
264
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_i18ncmp expect actual
277                 '
278
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                         write_script .git/hooks/fsmonitor-test<<-\EOF &&
283                         printf "last_update_token\0"
284                         :>marker
285                         EOF
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
303                 '
304         done
305 done
306
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
318 '
319
320 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
321         test_create_repo dot-git &&
322         (
323                 cd dot-git &&
324                 mkdir -p .git/hooks &&
325                 : >tracked &&
326                 : >modified &&
327                 mkdir dir1 &&
328                 : >dir1/tracked &&
329                 : >dir1/modified &&
330                 mkdir dir2 &&
331                 : >dir2/tracked &&
332                 : >dir2/modified &&
333                 write_integration_script &&
334                 git config core.fsmonitor .git/hooks/fsmonitor-test &&
335                 git update-index --untracked-cache &&
336                 git update-index --fsmonitor &&
337                 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \
338                 git status &&
339                 test-tool dump-untracked-cache >../before
340         ) &&
341         cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
342         printf ".git\0"
343         printf ".git/index\0"
344         printf "dir1/.git\0"
345         printf "dir1/.git/index\0"
346         EOF
347         (
348                 cd dot-git &&
349                 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \
350                 git status &&
351                 test-tool dump-untracked-cache >../after
352         ) &&
353         grep "directory invalidation" trace-before >>before &&
354         grep "directory invalidation" trace-after >>after &&
355         # UNTR extension unchanged, dir invalidation count unchanged
356         test_cmp before after
357 '
358
359 test_expect_success 'discard_index() also discards fsmonitor info' '
360         test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" &&
361         test_might_fail git update-index --refresh &&
362         test-tool read-cache --print-and-refresh=tracked 2 >actual &&
363         printf "tracked is%s up to date\n" "" " not" >expect &&
364         test_cmp expect actual
365 '
366
367 # Test unstaging entries that:
368 #  - Are not flagged with CE_FSMONITOR_VALID
369 #  - Have a position in the index >= the number of entries present in the index
370 #    after unstaging.
371 test_expect_success 'status succeeds after staging/unstaging' '
372         test_create_repo fsmonitor-stage-unstage &&
373         (
374                 cd fsmonitor-stage-unstage &&
375                 test_commit initial &&
376                 git update-index --fsmonitor &&
377                 removed=$(test_seq 1 100 | sed "s/^/z/") &&
378                 touch $removed &&
379                 git add $removed &&
380                 git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
381                 FSMONITOR_LIST="$removed" git restore -S $removed &&
382                 FSMONITOR_LIST="$removed" git status
383         )
384 '
385
386 test_done