1#!/bin/sh
2
3test_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
11clean_repo () {
12 git reset --hard HEAD &&
13 git clean -fd
14}
15
16dirty_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
28write_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
52test_lazy_prereq UNTRACKED_CACHE '
53 { git update-index --test-untracked-cache; ret=$?; } &&
54 test $ret -ne 1
55'
56
57test_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
79test_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
85test_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
92test_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
98cat >expect <<EOF &&
99h dir1/modified
100H dir1/tracked
101h dir2/modified
102H dir2/tracked
103h modified
104H tracked
105EOF
106
107# test that "update-index --fsmonitor-valid" sets the fsmonitor valid bit
108test_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
117cat >expect <<EOF &&
118H dir1/modified
119H dir1/tracked
120H dir2/modified
121H dir2/tracked
122H modified
123H tracked
124EOF
125
126# test that "update-index --no-fsmonitor-valid" clears the fsmonitor valid bit
127test_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
135cat >expect <<EOF &&
136H dir1/modified
137H dir1/tracked
138H dir2/modified
139H dir2/tracked
140H modified
141H tracked
142EOF
143
144# test that all files returned by the script get flagged as invalid
145test_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
153cat >expect <<EOF &&
154H dir1/modified
155h dir1/new
156H dir1/tracked
157H dir2/modified
158h dir2/new
159H dir2/tracked
160H modified
161h new
162H tracked
163EOF
164
165# test that newly added files are marked valid
166test_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
174cat >expect <<EOF &&
175H dir1/modified
176h dir1/new
177h dir1/tracked
178H dir2/modified
179h dir2/new
180h dir2/tracked
181H modified
182h new
183h tracked
184EOF
185
186# test that all unmodified files get marked valid
187test_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
194cat >expect <<EOF &&
195H dir1/modified
196h dir1/tracked
197h dir2/modified
198h dir2/tracked
199h modified
200h tracked
201EOF
202
203# test that *only* files returned by the integration script get flagged as invalid
204test_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
220test_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
234preload_values="false true"
235for preload_val in $preload_values
236do
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
295done
296
297# test that splitting the index dosn't interfere
298test_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
310test_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
349test_done