Merge branch 'jc/doc-single-h-is-for-help' into maint
[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" != 1
36         then
37                 echo "Unsupported core.fsmonitor hook version." >&2
38                 exit 1
39         fi
40         printf "untracked\0"
41         printf "dir1/untracked\0"
42         printf "dir2/untracked\0"
43         printf "modified\0"
44         printf "dir1/modified\0"
45         printf "dir2/modified\0"
46         printf "new\0"
47         printf "dir1/new\0"
48         printf "dir2/new\0"
49         EOF
50 }
51
52 test_lazy_prereq UNTRACKED_CACHE '
53         { git update-index --test-untracked-cache; ret=$?; } &&
54         test $ret -ne 1
55 '
56
57 test_expect_success 'setup' '
58         mkdir -p .git/hooks &&
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         EOF
76 '
77
78 # test that the fsmonitor extension is off by default
79 test_expect_success 'fsmonitor extension is off by default' '
80         test-tool dump-fsmonitor >actual &&
81         grep "^no fsmonitor" actual
82 '
83
84 # test that "update-index --fsmonitor" adds the fsmonitor extension
85 test_expect_success 'update-index --fsmonitor" adds the fsmonitor extension' '
86         git update-index --fsmonitor &&
87         test-tool dump-fsmonitor >actual &&
88         grep "^fsmonitor last update" actual
89 '
90
91 # test that "update-index --no-fsmonitor" removes the fsmonitor extension
92 test_expect_success 'update-index --no-fsmonitor" removes the fsmonitor extension' '
93         git update-index --no-fsmonitor &&
94         test-tool dump-fsmonitor >actual &&
95         grep "^no fsmonitor" actual
96 '
97
98 cat >expect <<EOF &&
99 h dir1/modified
100 H dir1/tracked
101 h dir2/modified
102 H dir2/tracked
103 h modified
104 H tracked
105 EOF
106
107 # test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
108 test_expect_success 'update-index --fsmonitor-valid" sets the fsmonitor valid bit' '
109         write_script .git/hooks/fsmonitor-test<<-\EOF &&
110         EOF
111         git update-index --fsmonitor &&
112         git update-index --fsmonitor-valid dir1/modified &&
113         git update-index --fsmonitor-valid dir2/modified &&
114         git update-index --fsmonitor-valid modified &&
115         git ls-files -f >actual &&
116         test_cmp expect actual
117 '
118
119 cat >expect <<EOF &&
120 H dir1/modified
121 H dir1/tracked
122 H dir2/modified
123 H dir2/tracked
124 H modified
125 H tracked
126 EOF
127
128 # test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
129 test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor valid bit' '
130         git update-index --no-fsmonitor-valid dir1/modified &&
131         git update-index --no-fsmonitor-valid dir2/modified &&
132         git update-index --no-fsmonitor-valid modified &&
133         git ls-files -f >actual &&
134         test_cmp expect actual
135 '
136
137 cat >expect <<EOF &&
138 H dir1/modified
139 H dir1/tracked
140 H dir2/modified
141 H dir2/tracked
142 H modified
143 H tracked
144 EOF
145
146 # test that all files returned by the script get flagged as invalid
147 test_expect_success 'all files returned by integration script get flagged as invalid' '
148         write_integration_script &&
149         dirty_repo &&
150         git update-index --fsmonitor &&
151         git ls-files -f >actual &&
152         test_cmp expect actual
153 '
154
155 cat >expect <<EOF &&
156 H dir1/modified
157 h dir1/new
158 H dir1/tracked
159 H dir2/modified
160 h dir2/new
161 H dir2/tracked
162 H modified
163 h new
164 H tracked
165 EOF
166
167 # test that newly added files are marked valid
168 test_expect_success 'newly added files are marked valid' '
169         write_script .git/hooks/fsmonitor-test<<-\EOF &&
170         EOF
171         git add new &&
172         git add dir1/new &&
173         git add dir2/new &&
174         git ls-files -f >actual &&
175         test_cmp expect actual
176 '
177
178 cat >expect <<EOF &&
179 H dir1/modified
180 h dir1/new
181 h dir1/tracked
182 H dir2/modified
183 h dir2/new
184 h dir2/tracked
185 H modified
186 h new
187 h tracked
188 EOF
189
190 # test that all unmodified files get marked valid
191 test_expect_success 'all unmodified files get marked valid' '
192         # modified files result in update-index returning 1
193         test_must_fail git update-index --refresh --force-write-index &&
194         git ls-files -f >actual &&
195         test_cmp expect actual
196 '
197
198 cat >expect <<EOF &&
199 H dir1/modified
200 h dir1/tracked
201 h dir2/modified
202 h dir2/tracked
203 h modified
204 h tracked
205 EOF
206
207 # test that *only* files returned by the integration script get flagged as invalid
208 test_expect_success '*only* files returned by the integration script get flagged as invalid' '
209         write_script .git/hooks/fsmonitor-test<<-\EOF &&
210         printf "dir1/modified\0"
211         EOF
212         clean_repo &&
213         git update-index --refresh --force-write-index &&
214         echo 1 >modified &&
215         echo 2 >dir1/modified &&
216         echo 3 >dir2/modified &&
217         test_must_fail git update-index --refresh --force-write-index &&
218         git ls-files -f >actual &&
219         test_cmp expect actual
220 '
221
222 # Ensure commands that call refresh_index() to move the index back in time
223 # properly invalidate the fsmonitor cache
224 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
225         clean_repo &&
226         dirty_repo &&
227         write_integration_script &&
228         git add . &&
229         write_script .git/hooks/fsmonitor-test<<-\EOF &&
230         EOF
231         git commit -m "to reset" &&
232         git reset HEAD~1 &&
233         git status >actual &&
234         git -c core.fsmonitor= status >expect &&
235         test_i18ncmp expect actual
236 '
237
238 # test fsmonitor with and without preloadIndex
239 preload_values="false true"
240 for preload_val in $preload_values
241 do
242         test_expect_success "setup preloadIndex to $preload_val" '
243                 git config core.preloadIndex $preload_val &&
244                 if test $preload_val = true
245                 then
246                         GIT_TEST_PRELOAD_INDEX=$preload_val; export GIT_TEST_PRELOAD_INDEX
247                 else
248                         sane_unset GIT_TEST_PRELOAD_INDEX
249                 fi
250         '
251
252         # test fsmonitor with and without the untracked cache (if available)
253         uc_values="false"
254         test_have_prereq UNTRACKED_CACHE && uc_values="false true"
255         for uc_val in $uc_values
256         do
257                 test_expect_success "setup untracked cache to $uc_val" '
258                         git config core.untrackedcache $uc_val
259                 '
260
261                 # Status is well tested elsewhere so we'll just ensure that the results are
262                 # the same when using core.fsmonitor.
263                 test_expect_success 'compare status with and without fsmonitor' '
264                         write_integration_script &&
265                         clean_repo &&
266                         dirty_repo &&
267                         git add new &&
268                         git add dir1/new &&
269                         git add dir2/new &&
270                         git status >actual &&
271                         git -c core.fsmonitor= status >expect &&
272                         test_i18ncmp expect actual
273                 '
274
275                 # Make sure it's actually skipping the check for modified and untracked
276                 # (if enabled) files unless it is told about them.
277                 test_expect_success "status doesn't detect unreported modifications" '
278                         write_script .git/hooks/fsmonitor-test<<-\EOF &&
279                         :>marker
280                         EOF
281                         clean_repo &&
282                         git status &&
283                         test_path_is_file marker &&
284                         dirty_repo &&
285                         rm -f marker &&
286                         git status >actual &&
287                         test_path_is_file marker &&
288                         test_i18ngrep ! "Changes not staged for commit:" actual &&
289                         if test $uc_val = true
290                         then
291                                 test_i18ngrep ! "Untracked files:" actual
292                         fi &&
293                         if test $uc_val = false
294                         then
295                                 test_i18ngrep "Untracked files:" actual
296                         fi &&
297                         rm -f marker
298                 '
299         done
300 done
301
302 # test that splitting the index doesn't interfere
303 test_expect_success 'splitting the index results in the same state' '
304         write_integration_script &&
305         dirty_repo &&
306         git update-index --fsmonitor  &&
307         git ls-files -f >expect &&
308         test-tool dump-fsmonitor >&2 && echo &&
309         git update-index --fsmonitor --split-index &&
310         test-tool dump-fsmonitor >&2 && echo &&
311         git ls-files -f >actual &&
312         test_cmp expect actual
313 '
314
315 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
316         test_create_repo dot-git &&
317         (
318                 cd dot-git &&
319                 mkdir -p .git/hooks &&
320                 : >tracked &&
321                 : >modified &&
322                 mkdir dir1 &&
323                 : >dir1/tracked &&
324                 : >dir1/modified &&
325                 mkdir dir2 &&
326                 : >dir2/tracked &&
327                 : >dir2/modified &&
328                 write_integration_script &&
329                 git config core.fsmonitor .git/hooks/fsmonitor-test &&
330                 git update-index --untracked-cache &&
331                 git update-index --fsmonitor &&
332                 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \
333                 git status &&
334                 test-tool dump-untracked-cache >../before
335         ) &&
336         cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
337         printf ".git\0"
338         printf ".git/index\0"
339         printf "dir1/.git\0"
340         printf "dir1/.git/index\0"
341         EOF
342         (
343                 cd dot-git &&
344                 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \
345                 git status &&
346                 test-tool dump-untracked-cache >../after
347         ) &&
348         grep "directory invalidation" trace-before >>before &&
349         grep "directory invalidation" trace-after >>after &&
350         # UNTR extension unchanged, dir invalidation count unchanged
351         test_cmp before after
352 '
353
354 test_expect_success 'discard_index() also discards fsmonitor info' '
355         test_config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-all" &&
356         test_might_fail git update-index --refresh &&
357         test-tool read-cache --print-and-refresh=tracked 2 >actual &&
358         printf "tracked is%s up to date\n" "" " not" >expect &&
359         test_cmp expect actual
360 '
361
362 # Test unstaging entries that:
363 #  - Are not flagged with CE_FSMONITOR_VALID
364 #  - Have a position in the index >= the number of entries present in the index
365 #    after unstaging.
366 test_expect_success 'status succeeds after staging/unstaging' '
367         test_create_repo fsmonitor-stage-unstage &&
368         (
369                 cd fsmonitor-stage-unstage &&
370                 test_commit initial &&
371                 git update-index --fsmonitor &&
372                 removed=$(test_seq 1 100 | sed "s/^/z/") &&
373                 touch $removed &&
374                 git add $removed &&
375                 git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" &&
376                 FSMONITOR_LIST="$removed" git restore -S $removed &&
377                 FSMONITOR_LIST="$removed" git status
378         )
379 '
380
381 test_done