Merge branch 'ds/reachable'
[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         git update-index --fsmonitor &&
110         git update-index --fsmonitor-valid dir1/modified &&
111         git update-index --fsmonitor-valid dir2/modified &&
112         git update-index --fsmonitor-valid modified &&
113         git ls-files -f >actual &&
114         test_cmp expect actual
115 '
116
117 cat >expect <<EOF &&
118 H dir1/modified
119 H dir1/tracked
120 H dir2/modified
121 H dir2/tracked
122 H modified
123 H tracked
124 EOF
125
126 # test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
127 test_expect_success 'update-index --no-fsmonitor-valid" clears the fsmonitor valid bit' '
128         git update-index --no-fsmonitor-valid dir1/modified &&
129         git update-index --no-fsmonitor-valid dir2/modified &&
130         git update-index --no-fsmonitor-valid modified &&
131         git ls-files -f >actual &&
132         test_cmp expect actual
133 '
134
135 cat >expect <<EOF &&
136 H dir1/modified
137 H dir1/tracked
138 H dir2/modified
139 H dir2/tracked
140 H modified
141 H tracked
142 EOF
143
144 # test that all files returned by the script get flagged as invalid
145 test_expect_success 'all files returned by integration script get flagged as invalid' '
146         write_integration_script &&
147         dirty_repo &&
148         git update-index --fsmonitor &&
149         git ls-files -f >actual &&
150         test_cmp expect actual
151 '
152
153 cat >expect <<EOF &&
154 H dir1/modified
155 h dir1/new
156 H dir1/tracked
157 H dir2/modified
158 h dir2/new
159 H dir2/tracked
160 H modified
161 h new
162 H tracked
163 EOF
164
165 # test that newly added files are marked valid
166 test_expect_success 'newly added files are marked valid' '
167         git add new &&
168         git add dir1/new &&
169         git add dir2/new &&
170         git ls-files -f >actual &&
171         test_cmp expect actual
172 '
173
174 cat >expect <<EOF &&
175 H dir1/modified
176 h dir1/new
177 h dir1/tracked
178 H dir2/modified
179 h dir2/new
180 h dir2/tracked
181 H modified
182 h new
183 h tracked
184 EOF
185
186 # test that all unmodified files get marked valid
187 test_expect_success 'all unmodified files get marked valid' '
188         # modified files result in update-index returning 1
189         test_must_fail git update-index --refresh --force-write-index &&
190         git ls-files -f >actual &&
191         test_cmp expect actual
192 '
193
194 cat >expect <<EOF &&
195 H dir1/modified
196 h dir1/tracked
197 h dir2/modified
198 h dir2/tracked
199 h modified
200 h tracked
201 EOF
202
203 # test that *only* files returned by the integration script get flagged as invalid
204 test_expect_success '*only* files returned by the integration script get flagged as invalid' '
205         write_script .git/hooks/fsmonitor-test<<-\EOF &&
206         printf "dir1/modified\0"
207         EOF
208         clean_repo &&
209         git update-index --refresh --force-write-index &&
210         echo 1 >modified &&
211         echo 2 >dir1/modified &&
212         echo 3 >dir2/modified &&
213         test_must_fail git update-index --refresh --force-write-index &&
214         git ls-files -f >actual &&
215         test_cmp expect actual
216 '
217
218 # Ensure commands that call refresh_index() to move the index back in time
219 # properly invalidate the fsmonitor cache
220 test_expect_success 'refresh_index() invalidates fsmonitor cache' '
221         write_script .git/hooks/fsmonitor-test<<-\EOF &&
222         EOF
223         clean_repo &&
224         dirty_repo &&
225         git add . &&
226         git commit -m "to reset" &&
227         git reset HEAD~1 &&
228         git status >actual &&
229         git -c core.fsmonitor= status >expect &&
230         test_i18ncmp expect actual
231 '
232
233 # test fsmonitor with and without preloadIndex
234 preload_values="false true"
235 for preload_val in $preload_values
236 do
237         test_expect_success "setup preloadIndex to $preload_val" '
238                 git config core.preloadIndex $preload_val &&
239                 if test $preload_val = true
240                 then
241                         GIT_TEST_PRELOAD_INDEX=$preload_val; export GIT_TEST_PRELOAD_INDEX
242                 else
243                         sane_unset GIT_TEST_PRELOAD_INDEX
244                 fi
245         '
246
247         # test fsmonitor with and without the untracked cache (if available)
248         uc_values="false"
249         test_have_prereq UNTRACKED_CACHE && uc_values="false true"
250         for uc_val in $uc_values
251         do
252                 test_expect_success "setup untracked cache to $uc_val" '
253                         git config core.untrackedcache $uc_val
254                 '
255
256                 # Status is well tested elsewhere so we'll just ensure that the results are
257                 # the same when using core.fsmonitor.
258                 test_expect_success 'compare status with and without fsmonitor' '
259                         write_integration_script &&
260                         clean_repo &&
261                         dirty_repo &&
262                         git add new &&
263                         git add dir1/new &&
264                         git add dir2/new &&
265                         git status >actual &&
266                         git -c core.fsmonitor= status >expect &&
267                         test_i18ncmp expect actual
268                 '
269
270                 # Make sure it's actually skipping the check for modified and untracked
271                 # (if enabled) files unless it is told about them.
272                 test_expect_success "status doesn't detect unreported modifications" '
273                         write_script .git/hooks/fsmonitor-test<<-\EOF &&
274                         :>marker
275                         EOF
276                         clean_repo &&
277                         git status &&
278                         test_path_is_file marker &&
279                         dirty_repo &&
280                         rm -f marker &&
281                         git status >actual &&
282                         test_path_is_file marker &&
283                         test_i18ngrep ! "Changes not staged for commit:" actual &&
284                         if test $uc_val = true
285                         then
286                                 test_i18ngrep ! "Untracked files:" actual
287                         fi &&
288                         if test $uc_val = false
289                         then
290                                 test_i18ngrep "Untracked files:" actual
291                         fi &&
292                         rm -f marker
293                 '
294         done
295 done
296
297 # test that splitting the index dosn't interfere
298 test_expect_success 'splitting the index results in the same state' '
299         write_integration_script &&
300         dirty_repo &&
301         git update-index --fsmonitor  &&
302         git ls-files -f >expect &&
303         test-tool dump-fsmonitor >&2 && echo &&
304         git update-index --fsmonitor --split-index &&
305         test-tool dump-fsmonitor >&2 && echo &&
306         git ls-files -f >actual &&
307         test_cmp expect actual
308 '
309
310 test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' '
311         test_create_repo dot-git &&
312         (
313                 cd dot-git &&
314                 mkdir -p .git/hooks &&
315                 : >tracked &&
316                 : >modified &&
317                 mkdir dir1 &&
318                 : >dir1/tracked &&
319                 : >dir1/modified &&
320                 mkdir dir2 &&
321                 : >dir2/tracked &&
322                 : >dir2/modified &&
323                 write_integration_script &&
324                 git config core.fsmonitor .git/hooks/fsmonitor-test &&
325                 git update-index --untracked-cache &&
326                 git update-index --fsmonitor &&
327                 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \
328                 git status &&
329                 test-tool dump-untracked-cache >../before
330         ) &&
331         cat >>dot-git/.git/hooks/fsmonitor-test <<-\EOF &&
332         printf ".git\0"
333         printf ".git/index\0"
334         printf "dir1/.git\0"
335         printf "dir1/.git/index\0"
336         EOF
337         (
338                 cd dot-git &&
339                 GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \
340                 git status &&
341                 test-tool dump-untracked-cache >../after
342         ) &&
343         grep "directory invalidation" trace-before >>before &&
344         grep "directory invalidation" trace-after >>after &&
345         # UNTR extension unchanged, dir invalidation count unchanged
346         test_cmp before after
347 '
348
349 test_done