]>
Commit | Line | Data |
---|---|---|
a00cdff8 JH |
1 | #!/bin/sh |
2 | ||
3 | test_description='built-in file system watcher' | |
4 | ||
5 | . ./test-lib.sh | |
6 | ||
7 | if ! test_have_prereq FSMONITOR_DAEMON | |
8 | then | |
9 | skip_all="fsmonitor--daemon is not supported on this platform" | |
10 | test_done | |
11 | fi | |
12 | ||
13 | stop_daemon_delete_repo () { | |
14 | r=$1 && | |
15 | test_might_fail git -C $r fsmonitor--daemon stop && | |
16 | rm -rf $1 | |
17 | } | |
18 | ||
19 | start_daemon () { | |
20 | r= tf= t2= tk= && | |
21 | ||
22 | while test "$#" -ne 0 | |
23 | do | |
24 | case "$1" in | |
25 | -C) | |
26 | r="-C ${2?}" | |
27 | shift | |
28 | ;; | |
29 | --tf) | |
30 | tf="${2?}" | |
31 | shift | |
32 | ;; | |
33 | --t2) | |
34 | t2="${2?}" | |
35 | shift | |
36 | ;; | |
37 | --tk) | |
38 | tk="${2?}" | |
39 | shift | |
40 | ;; | |
41 | -*) | |
42 | BUG "error: unknown option: '$1'" | |
43 | ;; | |
44 | *) | |
45 | BUG "error: unbound argument: '$1'" | |
46 | ;; | |
47 | esac | |
48 | shift | |
49 | done && | |
50 | ||
51 | ( | |
52 | if test -n "$tf" | |
53 | then | |
54 | GIT_TRACE_FSMONITOR="$tf" | |
55 | export GIT_TRACE_FSMONITOR | |
56 | fi && | |
57 | ||
58 | if test -n "$t2" | |
59 | then | |
60 | GIT_TRACE2_PERF="$t2" | |
61 | export GIT_TRACE2_PERF | |
62 | fi && | |
63 | ||
64 | if test -n "$tk" | |
65 | then | |
66 | GIT_TEST_FSMONITOR_TOKEN="$tk" | |
67 | export GIT_TEST_FSMONITOR_TOKEN | |
68 | fi && | |
69 | ||
70 | git $r fsmonitor--daemon start && | |
71 | git $r fsmonitor--daemon status | |
72 | ) | |
73 | } | |
74 | ||
75 | # Is a Trace2 data event present with the given catetory and key? | |
76 | # We do not care what the value is. | |
77 | # | |
78 | have_t2_data_event () { | |
79 | c=$1 && | |
80 | k=$2 && | |
81 | ||
82 | grep -e '"event":"data".*"category":"'"$c"'".*"key":"'"$k"'"' | |
83 | } | |
84 | ||
85 | test_expect_success 'explicit daemon start and stop' ' | |
86 | test_when_finished "stop_daemon_delete_repo test_explicit" && | |
87 | ||
88 | git init test_explicit && | |
89 | start_daemon -C test_explicit && | |
90 | ||
91 | git -C test_explicit fsmonitor--daemon stop && | |
92 | test_must_fail git -C test_explicit fsmonitor--daemon status | |
93 | ' | |
94 | ||
95 | test_expect_success 'implicit daemon start' ' | |
96 | test_when_finished "stop_daemon_delete_repo test_implicit" && | |
97 | ||
98 | git init test_implicit && | |
99 | test_must_fail git -C test_implicit fsmonitor--daemon status && | |
100 | ||
101 | # query will implicitly start the daemon. | |
102 | # | |
103 | # for test-script simplicity, we send a V1 timestamp rather than | |
104 | # a V2 token. either way, the daemon response to any query contains | |
105 | # a new V2 token. (the daemon may complain that we sent a V1 request, | |
106 | # but this test case is only concerned with whether the daemon was | |
107 | # implicitly started.) | |
108 | ||
109 | GIT_TRACE2_EVENT="$PWD/.git/trace" \ | |
110 | test-tool -C test_implicit fsmonitor-client query --token 0 >actual && | |
111 | nul_to_q <actual >actual.filtered && | |
112 | grep "builtin:" actual.filtered && | |
113 | ||
114 | # confirm that a daemon was started in the background. | |
115 | # | |
116 | # since the mechanism for starting the background daemon is platform | |
117 | # dependent, just confirm that the foreground command received a | |
118 | # response from the daemon. | |
119 | ||
120 | have_t2_data_event fsm_client query/response-length <.git/trace && | |
121 | ||
122 | git -C test_implicit fsmonitor--daemon status && | |
123 | git -C test_implicit fsmonitor--daemon stop && | |
124 | test_must_fail git -C test_implicit fsmonitor--daemon status | |
125 | ' | |
126 | ||
3294ca61 JH |
127 | # Verify that the daemon has shutdown. Spin a few seconds to |
128 | # make the test a little more robust during CI testing. | |
129 | # | |
130 | # We're looking for an implicit shutdown, such as when we delete or | |
131 | # rename the ".git" directory. Our delete/rename will cause a file | |
132 | # system event that the daemon will see and the daemon will | |
133 | # auto-shutdown as soon as it sees it. But this is racy with our `git | |
134 | # fsmonitor--daemon status` commands (and we cannot use a cookie file | |
135 | # here to help us). So spin a little and give the daemon a chance to | |
136 | # see the event. (This is primarily for underpowered CI build/test | |
137 | # machines (where it might take a moment to wake and reschedule the | |
138 | # daemon process) to avoid false alarms during test runs.) | |
139 | # | |
140 | IMPLICIT_TIMEOUT=5 | |
141 | ||
142 | verify_implicit_shutdown () { | |
143 | r=$1 && | |
144 | ||
145 | k=0 && | |
146 | while test "$k" -lt $IMPLICIT_TIMEOUT | |
147 | do | |
148 | git -C $r fsmonitor--daemon status || return 0 | |
149 | ||
150 | sleep 1 | |
151 | k=$(( $k + 1 )) | |
152 | done && | |
153 | ||
154 | return 1 | |
155 | } | |
156 | ||
a00cdff8 JH |
157 | test_expect_success 'implicit daemon stop (delete .git)' ' |
158 | test_when_finished "stop_daemon_delete_repo test_implicit_1" && | |
159 | ||
160 | git init test_implicit_1 && | |
161 | ||
162 | start_daemon -C test_implicit_1 && | |
163 | ||
164 | # deleting the .git directory will implicitly stop the daemon. | |
165 | rm -rf test_implicit_1/.git && | |
166 | ||
167 | # [1] Create an empty .git directory so that the following Git | |
168 | # command will stay relative to the `-C` directory. | |
169 | # | |
170 | # Without this, the Git command will override the requested | |
171 | # -C argument and crawl out to the containing Git source tree. | |
172 | # This would make the test result dependent upon whether we | |
173 | # were using fsmonitor on our development worktree. | |
174 | # | |
a00cdff8 JH |
175 | mkdir test_implicit_1/.git && |
176 | ||
3294ca61 | 177 | verify_implicit_shutdown test_implicit_1 |
a00cdff8 JH |
178 | ' |
179 | ||
180 | test_expect_success 'implicit daemon stop (rename .git)' ' | |
181 | test_when_finished "stop_daemon_delete_repo test_implicit_2" && | |
182 | ||
183 | git init test_implicit_2 && | |
184 | ||
185 | start_daemon -C test_implicit_2 && | |
186 | ||
187 | # renaming the .git directory will implicitly stop the daemon. | |
188 | mv test_implicit_2/.git test_implicit_2/.xxx && | |
189 | ||
190 | # See [1] above. | |
191 | # | |
a00cdff8 JH |
192 | mkdir test_implicit_2/.git && |
193 | ||
3294ca61 | 194 | verify_implicit_shutdown test_implicit_2 |
a00cdff8 JH |
195 | ' |
196 | ||
40f865dc JH |
197 | # File systems on Windows may or may not have shortnames. |
198 | # This is a volume-specific setting on modern systems. | |
199 | # "C:/" drives are required to have them enabled. Other | |
200 | # hard drives default to disabled. | |
201 | # | |
202 | # This is a crude test to see if shortnames are enabled | |
203 | # on the volume containing the test directory. It is | |
204 | # crude, but it does not require elevation like `fsutil`. | |
205 | # | |
206 | test_lazy_prereq SHORTNAMES ' | |
207 | mkdir .foo && | |
208 | test -d "FOO~1" | |
209 | ' | |
210 | ||
211 | # Here we assume that the shortname of ".git" is "GIT~1". | |
212 | test_expect_success MINGW,SHORTNAMES 'implicit daemon stop (rename GIT~1)' ' | |
213 | test_when_finished "stop_daemon_delete_repo test_implicit_1s" && | |
214 | ||
215 | git init test_implicit_1s && | |
216 | ||
217 | start_daemon -C test_implicit_1s && | |
218 | ||
219 | # renaming the .git directory will implicitly stop the daemon. | |
220 | # this moves {.git, GIT~1} to {.gitxyz, GITXYZ~1}. | |
221 | # the rename-from FS Event will contain the shortname. | |
222 | # | |
223 | mv test_implicit_1s/GIT~1 test_implicit_1s/.gitxyz && | |
224 | ||
3294ca61 | 225 | # See [1] above. |
40f865dc JH |
226 | # this moves {.gitxyz, GITXYZ~1} to {.git, GIT~1}. |
227 | mv test_implicit_1s/.gitxyz test_implicit_1s/.git && | |
228 | ||
3294ca61 | 229 | verify_implicit_shutdown test_implicit_1s |
40f865dc JH |
230 | ' |
231 | ||
232 | # Here we first create a file with LONGNAME of "GIT~1" before | |
233 | # we create the repo. This will cause the shortname of ".git" | |
234 | # to be "GIT~2". | |
235 | test_expect_success MINGW,SHORTNAMES 'implicit daemon stop (rename GIT~2)' ' | |
236 | test_when_finished "stop_daemon_delete_repo test_implicit_1s2" && | |
237 | ||
238 | mkdir test_implicit_1s2 && | |
239 | echo HELLO >test_implicit_1s2/GIT~1 && | |
240 | git init test_implicit_1s2 && | |
241 | ||
242 | test_path_is_file test_implicit_1s2/GIT~1 && | |
243 | test_path_is_dir test_implicit_1s2/GIT~2 && | |
244 | ||
245 | start_daemon -C test_implicit_1s2 && | |
246 | ||
247 | # renaming the .git directory will implicitly stop the daemon. | |
248 | # the rename-from FS Event will contain the shortname. | |
249 | # | |
250 | mv test_implicit_1s2/GIT~2 test_implicit_1s2/.gitxyz && | |
251 | ||
3294ca61 | 252 | # See [1] above. |
40f865dc JH |
253 | mv test_implicit_1s2/.gitxyz test_implicit_1s2/.git && |
254 | ||
3294ca61 | 255 | verify_implicit_shutdown test_implicit_1s2 |
40f865dc JH |
256 | ' |
257 | ||
a00cdff8 JH |
258 | test_expect_success 'cannot start multiple daemons' ' |
259 | test_when_finished "stop_daemon_delete_repo test_multiple" && | |
260 | ||
261 | git init test_multiple && | |
262 | ||
263 | start_daemon -C test_multiple && | |
264 | ||
265 | test_must_fail git -C test_multiple fsmonitor--daemon start 2>actual && | |
266 | grep "fsmonitor--daemon is already running" actual && | |
267 | ||
268 | git -C test_multiple fsmonitor--daemon stop && | |
269 | test_must_fail git -C test_multiple fsmonitor--daemon status | |
270 | ' | |
271 | ||
272 | # These tests use the main repo in the trash directory | |
273 | ||
274 | test_expect_success 'setup' ' | |
275 | >tracked && | |
276 | >modified && | |
277 | >delete && | |
278 | >rename && | |
279 | mkdir dir1 && | |
280 | >dir1/tracked && | |
281 | >dir1/modified && | |
282 | >dir1/delete && | |
283 | >dir1/rename && | |
284 | mkdir dir2 && | |
285 | >dir2/tracked && | |
286 | >dir2/modified && | |
287 | >dir2/delete && | |
288 | >dir2/rename && | |
289 | mkdir dirtorename && | |
290 | >dirtorename/a && | |
291 | >dirtorename/b && | |
292 | ||
293 | cat >.gitignore <<-\EOF && | |
294 | .gitignore | |
295 | expect* | |
296 | actual* | |
a3dfe97f JH |
297 | flush* |
298 | trace* | |
a00cdff8 JH |
299 | EOF |
300 | ||
b5337082 JH |
301 | mkdir -p T1/T2/T3/T4 && |
302 | echo 1 >T1/F1 && | |
303 | echo 1 >T1/T2/F1 && | |
304 | echo 1 >T1/T2/T3/F1 && | |
305 | echo 1 >T1/T2/T3/T4/F1 && | |
306 | echo 2 >T1/F2 && | |
307 | echo 2 >T1/T2/F2 && | |
308 | echo 2 >T1/T2/T3/F2 && | |
309 | echo 2 >T1/T2/T3/T4/F2 && | |
310 | ||
a00cdff8 JH |
311 | git -c core.fsmonitor=false add . && |
312 | test_tick && | |
313 | git -c core.fsmonitor=false commit -m initial && | |
314 | ||
315 | git config core.fsmonitor true | |
316 | ' | |
317 | ||
318 | # The test already explicitly stopped (or tried to stop) the daemon. | |
319 | # This is here in case something else fails first. | |
320 | # | |
321 | redundant_stop_daemon () { | |
322 | test_might_fail git fsmonitor--daemon stop | |
323 | } | |
324 | ||
325 | test_expect_success 'update-index implicitly starts daemon' ' | |
326 | test_when_finished redundant_stop_daemon && | |
327 | ||
328 | test_must_fail git fsmonitor--daemon status && | |
329 | ||
330 | GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_1" \ | |
331 | git update-index --fsmonitor && | |
332 | ||
333 | git fsmonitor--daemon status && | |
334 | test_might_fail git fsmonitor--daemon stop && | |
335 | ||
336 | # Confirm that the trace2 log contains a record of the | |
337 | # daemon starting. | |
338 | test_subcommand git fsmonitor--daemon start <.git/trace_implicit_1 | |
339 | ' | |
340 | ||
341 | test_expect_success 'status implicitly starts daemon' ' | |
342 | test_when_finished redundant_stop_daemon && | |
343 | ||
344 | test_must_fail git fsmonitor--daemon status && | |
345 | ||
346 | GIT_TRACE2_EVENT="$PWD/.git/trace_implicit_2" \ | |
347 | git status >actual && | |
348 | ||
349 | git fsmonitor--daemon status && | |
350 | test_might_fail git fsmonitor--daemon stop && | |
351 | ||
352 | # Confirm that the trace2 log contains a record of the | |
353 | # daemon starting. | |
354 | test_subcommand git fsmonitor--daemon start <.git/trace_implicit_2 | |
355 | ' | |
356 | ||
357 | edit_files () { | |
358 | echo 1 >modified && | |
359 | echo 2 >dir1/modified && | |
360 | echo 3 >dir2/modified && | |
361 | >dir1/untracked | |
362 | } | |
363 | ||
364 | delete_files () { | |
365 | rm -f delete && | |
366 | rm -f dir1/delete && | |
367 | rm -f dir2/delete | |
368 | } | |
369 | ||
370 | create_files () { | |
371 | echo 1 >new && | |
372 | echo 2 >dir1/new && | |
373 | echo 3 >dir2/new | |
374 | } | |
375 | ||
376 | rename_files () { | |
377 | mv rename renamed && | |
378 | mv dir1/rename dir1/renamed && | |
379 | mv dir2/rename dir2/renamed | |
380 | } | |
381 | ||
382 | file_to_directory () { | |
383 | rm -f delete && | |
384 | mkdir delete && | |
385 | echo 1 >delete/new | |
386 | } | |
387 | ||
388 | directory_to_file () { | |
389 | rm -rf dir1 && | |
390 | echo 1 >dir1 | |
391 | } | |
392 | ||
b5337082 JH |
393 | move_directory_contents_deeper() { |
394 | mkdir T1/_new_ && | |
395 | mv T1/[A-Z]* T1/_new_ | |
396 | } | |
397 | ||
398 | move_directory_up() { | |
399 | mv T1/T2/T3 T1 | |
400 | } | |
401 | ||
402 | move_directory() { | |
403 | mv T1/T2/T3 T1/T2/NewT3 | |
404 | } | |
405 | ||
a00cdff8 JH |
406 | # The next few test cases confirm that our fsmonitor daemon sees each type |
407 | # of OS filesystem notification that we care about. At this layer we just | |
408 | # ensure we are getting the OS notifications and do not try to confirm what | |
409 | # is reported by `git status`. | |
410 | # | |
411 | # We run a simple query after modifying the filesystem just to introduce | |
412 | # a bit of a delay so that the trace logging from the daemon has time to | |
413 | # get flushed to disk. | |
414 | # | |
415 | # We `reset` and `clean` at the bottom of each test (and before stopping the | |
416 | # daemon) because these commands might implicitly restart the daemon. | |
417 | ||
418 | clean_up_repo_and_stop_daemon () { | |
419 | git reset --hard HEAD && | |
420 | git clean -fd && | |
421 | test_might_fail git fsmonitor--daemon stop && | |
422 | rm -f .git/trace | |
423 | } | |
424 | ||
425 | test_expect_success 'edit some files' ' | |
426 | test_when_finished clean_up_repo_and_stop_daemon && | |
427 | ||
428 | start_daemon --tf "$PWD/.git/trace" && | |
429 | ||
430 | edit_files && | |
431 | ||
432 | test-tool fsmonitor-client query --token 0 && | |
433 | ||
434 | grep "^event: dir1/modified$" .git/trace && | |
435 | grep "^event: dir2/modified$" .git/trace && | |
436 | grep "^event: modified$" .git/trace && | |
437 | grep "^event: dir1/untracked$" .git/trace | |
438 | ' | |
439 | ||
440 | test_expect_success 'create some files' ' | |
441 | test_when_finished clean_up_repo_and_stop_daemon && | |
442 | ||
443 | start_daemon --tf "$PWD/.git/trace" && | |
444 | ||
445 | create_files && | |
446 | ||
447 | test-tool fsmonitor-client query --token 0 && | |
448 | ||
449 | grep "^event: dir1/new$" .git/trace && | |
450 | grep "^event: dir2/new$" .git/trace && | |
451 | grep "^event: new$" .git/trace | |
452 | ' | |
453 | ||
454 | test_expect_success 'delete some files' ' | |
455 | test_when_finished clean_up_repo_and_stop_daemon && | |
456 | ||
457 | start_daemon --tf "$PWD/.git/trace" && | |
458 | ||
459 | delete_files && | |
460 | ||
461 | test-tool fsmonitor-client query --token 0 && | |
462 | ||
463 | grep "^event: dir1/delete$" .git/trace && | |
464 | grep "^event: dir2/delete$" .git/trace && | |
465 | grep "^event: delete$" .git/trace | |
466 | ' | |
467 | ||
468 | test_expect_success 'rename some files' ' | |
469 | test_when_finished clean_up_repo_and_stop_daemon && | |
470 | ||
471 | start_daemon --tf "$PWD/.git/trace" && | |
472 | ||
473 | rename_files && | |
474 | ||
475 | test-tool fsmonitor-client query --token 0 && | |
476 | ||
477 | grep "^event: dir1/rename$" .git/trace && | |
478 | grep "^event: dir2/rename$" .git/trace && | |
479 | grep "^event: rename$" .git/trace && | |
480 | grep "^event: dir1/renamed$" .git/trace && | |
481 | grep "^event: dir2/renamed$" .git/trace && | |
482 | grep "^event: renamed$" .git/trace | |
483 | ' | |
484 | ||
485 | test_expect_success 'rename directory' ' | |
486 | test_when_finished clean_up_repo_and_stop_daemon && | |
487 | ||
488 | start_daemon --tf "$PWD/.git/trace" && | |
489 | ||
490 | mv dirtorename dirrenamed && | |
491 | ||
492 | test-tool fsmonitor-client query --token 0 && | |
493 | ||
494 | grep "^event: dirtorename/*$" .git/trace && | |
495 | grep "^event: dirrenamed/*$" .git/trace | |
496 | ' | |
497 | ||
498 | test_expect_success 'file changes to directory' ' | |
499 | test_when_finished clean_up_repo_and_stop_daemon && | |
500 | ||
501 | start_daemon --tf "$PWD/.git/trace" && | |
502 | ||
503 | file_to_directory && | |
504 | ||
505 | test-tool fsmonitor-client query --token 0 && | |
506 | ||
507 | grep "^event: delete$" .git/trace && | |
508 | grep "^event: delete/new$" .git/trace | |
509 | ' | |
510 | ||
511 | test_expect_success 'directory changes to a file' ' | |
512 | test_when_finished clean_up_repo_and_stop_daemon && | |
513 | ||
514 | start_daemon --tf "$PWD/.git/trace" && | |
515 | ||
516 | directory_to_file && | |
517 | ||
518 | test-tool fsmonitor-client query --token 0 && | |
519 | ||
520 | grep "^event: dir1$" .git/trace | |
521 | ' | |
522 | ||
523 | # The next few test cases exercise the token-resync code. When filesystem | |
524 | # drops events (because of filesystem velocity or because the daemon isn't | |
525 | # polling fast enough), we need to discard the cached data (relative to the | |
526 | # current token) and start collecting events under a new token. | |
527 | # | |
528 | # the 'test-tool fsmonitor-client flush' command can be used to send a | |
529 | # "flush" message to a running daemon and ask it to do a flush/resync. | |
530 | ||
531 | test_expect_success 'flush cached data' ' | |
532 | test_when_finished "stop_daemon_delete_repo test_flush" && | |
533 | ||
534 | git init test_flush && | |
535 | ||
536 | start_daemon -C test_flush --tf "$PWD/.git/trace_daemon" --tk true && | |
537 | ||
538 | # The daemon should have an initial token with no events in _0 and | |
539 | # then a few (probably platform-specific number of) events in _1. | |
540 | # These should both have the same <token_id>. | |
541 | ||
542 | test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_0 && | |
543 | nul_to_q <actual_0 >actual_q0 && | |
544 | ||
545 | >test_flush/file_1 && | |
546 | >test_flush/file_2 && | |
547 | ||
548 | test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000001:0" >actual_1 && | |
549 | nul_to_q <actual_1 >actual_q1 && | |
550 | ||
551 | grep "file_1" actual_q1 && | |
552 | ||
553 | # Force a flush. This will change the <token_id>, reset the <seq_nr>, and | |
554 | # flush the file data. Then create some events and ensure that the file | |
555 | # again appears in the cache. It should have the new <token_id>. | |
556 | ||
557 | test-tool -C test_flush fsmonitor-client flush >flush_0 && | |
558 | nul_to_q <flush_0 >flush_q0 && | |
559 | grep "^builtin:test_00000002:0Q/Q$" flush_q0 && | |
560 | ||
561 | test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_2 && | |
562 | nul_to_q <actual_2 >actual_q2 && | |
563 | ||
564 | grep "^builtin:test_00000002:0Q$" actual_q2 && | |
565 | ||
566 | >test_flush/file_3 && | |
567 | ||
568 | test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_3 && | |
569 | nul_to_q <actual_3 >actual_q3 && | |
570 | ||
571 | grep "file_3" actual_q3 | |
572 | ' | |
573 | ||
574 | # The next few test cases create repos where the .git directory is NOT | |
575 | # inside the one of the working directory. That is, where .git is a file | |
576 | # that points to a directory elsewhere. This happens for submodules and | |
577 | # non-primary worktrees. | |
578 | ||
579 | test_expect_success 'setup worktree base' ' | |
580 | git init wt-base && | |
581 | echo 1 >wt-base/file1 && | |
582 | git -C wt-base add file1 && | |
583 | git -C wt-base commit -m "c1" | |
584 | ' | |
585 | ||
586 | test_expect_success 'worktree with .git file' ' | |
587 | git -C wt-base worktree add ../wt-secondary && | |
588 | ||
589 | start_daemon -C wt-secondary \ | |
590 | --tf "$PWD/trace_wt_secondary" \ | |
591 | --t2 "$PWD/trace2_wt_secondary" && | |
592 | ||
593 | git -C wt-secondary fsmonitor--daemon stop && | |
594 | test_must_fail git -C wt-secondary fsmonitor--daemon status | |
595 | ' | |
596 | ||
597 | # NEEDSWORK: Repeat one of the "edit" tests on wt-secondary and | |
598 | # confirm that we get the same events and behavior -- that is, that | |
599 | # fsmonitor--daemon correctly watches BOTH the working directory and | |
600 | # the external GITDIR directory and behaves the same as when ".git" | |
601 | # is a directory inside the working directory. | |
602 | ||
603 | test_expect_success 'cleanup worktrees' ' | |
604 | stop_daemon_delete_repo wt-secondary && | |
605 | stop_daemon_delete_repo wt-base | |
606 | ' | |
607 | ||
a3dfe97f JH |
608 | # The next few tests perform arbitrary/contrived file operations and |
609 | # confirm that status is correct. That is, that the data (or lack of | |
610 | # data) from fsmonitor doesn't cause incorrect results. And doesn't | |
611 | # cause incorrect results when the untracked-cache is enabled. | |
612 | ||
613 | test_lazy_prereq UNTRACKED_CACHE ' | |
614 | git update-index --test-untracked-cache | |
615 | ' | |
616 | ||
617 | test_expect_success 'Matrix: setup for untracked-cache,fsmonitor matrix' ' | |
618 | test_unconfig core.fsmonitor && | |
619 | git update-index --no-fsmonitor && | |
620 | test_might_fail git fsmonitor--daemon stop | |
621 | ' | |
622 | ||
623 | matrix_clean_up_repo () { | |
624 | git reset --hard HEAD && | |
625 | git clean -fd | |
626 | } | |
627 | ||
628 | matrix_try () { | |
629 | uc=$1 && | |
630 | fsm=$2 && | |
631 | fn=$3 && | |
632 | ||
633 | if test $uc = true && test $fsm = false | |
634 | then | |
635 | # The untracked-cache is buggy when FSMonitor is | |
636 | # DISABLED, so skip the tests for this matrix | |
637 | # combination. | |
638 | # | |
639 | # We've observed random, occasional test failures on | |
640 | # Windows and MacOS when the UC is turned on and FSM | |
641 | # is turned off. These are rare, but they do happen | |
642 | # indicating that it is probably a race condition within | |
643 | # the untracked cache itself. | |
644 | # | |
645 | # It usually happens when a test does F/D trickery and | |
646 | # then the NEXT test fails because of extra status | |
647 | # output from stale UC data from the previous test. | |
648 | # | |
649 | # Since FSMonitor is not involved in the error, skip | |
650 | # the tests for this matrix combination. | |
651 | # | |
652 | return 0 | |
653 | fi && | |
654 | ||
655 | test_expect_success "Matrix[uc:$uc][fsm:$fsm] $fn" ' | |
656 | matrix_clean_up_repo && | |
657 | $fn && | |
658 | if test $uc = false && test $fsm = false | |
659 | then | |
660 | git status --porcelain=v1 >.git/expect.$fn | |
661 | else | |
662 | git status --porcelain=v1 >.git/actual.$fn && | |
663 | test_cmp .git/expect.$fn .git/actual.$fn | |
664 | fi | |
665 | ' | |
666 | } | |
667 | ||
668 | uc_values="false" | |
669 | test_have_prereq UNTRACKED_CACHE && uc_values="false true" | |
670 | for uc_val in $uc_values | |
671 | do | |
672 | if test $uc_val = false | |
673 | then | |
674 | test_expect_success "Matrix[uc:$uc_val] disable untracked cache" ' | |
675 | git config core.untrackedcache false && | |
676 | git update-index --no-untracked-cache | |
677 | ' | |
678 | else | |
679 | test_expect_success "Matrix[uc:$uc_val] enable untracked cache" ' | |
680 | git config core.untrackedcache true && | |
681 | git update-index --untracked-cache | |
682 | ' | |
683 | fi | |
684 | ||
685 | fsm_values="false true" | |
686 | for fsm_val in $fsm_values | |
687 | do | |
688 | if test $fsm_val = false | |
689 | then | |
690 | test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] disable fsmonitor" ' | |
691 | test_unconfig core.fsmonitor && | |
692 | git update-index --no-fsmonitor && | |
693 | test_might_fail git fsmonitor--daemon stop | |
694 | ' | |
695 | else | |
696 | test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] enable fsmonitor" ' | |
697 | git config core.fsmonitor true && | |
698 | git fsmonitor--daemon start && | |
699 | git update-index --fsmonitor | |
700 | ' | |
701 | fi | |
702 | ||
703 | matrix_try $uc_val $fsm_val edit_files | |
704 | matrix_try $uc_val $fsm_val delete_files | |
705 | matrix_try $uc_val $fsm_val create_files | |
706 | matrix_try $uc_val $fsm_val rename_files | |
707 | matrix_try $uc_val $fsm_val file_to_directory | |
708 | matrix_try $uc_val $fsm_val directory_to_file | |
709 | ||
b5337082 JH |
710 | matrix_try $uc_val $fsm_val move_directory_contents_deeper |
711 | matrix_try $uc_val $fsm_val move_directory_up | |
712 | matrix_try $uc_val $fsm_val move_directory | |
713 | ||
a3dfe97f JH |
714 | if test $fsm_val = true |
715 | then | |
716 | test_expect_success "Matrix[uc:$uc_val][fsm:$fsm_val] disable fsmonitor at end" ' | |
717 | test_unconfig core.fsmonitor && | |
718 | git update-index --no-fsmonitor && | |
719 | test_might_fail git fsmonitor--daemon stop | |
720 | ' | |
721 | fi | |
722 | done | |
723 | done | |
724 | ||
27b5d417 JH |
725 | # Test Unicode UTF-8 characters in the pathname of the working |
726 | # directory root. Use of "*A()" routines rather than "*W()" routines | |
727 | # on Windows can sometimes lead to odd failures. | |
728 | # | |
729 | u1=$(printf "u_c3_a6__\xC3\xA6") | |
730 | u2=$(printf "u_e2_99_ab__\xE2\x99\xAB") | |
731 | u_values="$u1 $u2" | |
732 | for u in $u_values | |
733 | do | |
734 | test_expect_success "unicode in repo root path: $u" ' | |
735 | test_when_finished "stop_daemon_delete_repo $u" && | |
736 | ||
737 | git init "$u" && | |
738 | echo 1 >"$u"/file1 && | |
739 | git -C "$u" add file1 && | |
740 | git -C "$u" config core.fsmonitor true && | |
741 | ||
742 | start_daemon -C "$u" && | |
743 | git -C "$u" status >actual && | |
744 | grep "new file: file1" actual | |
745 | ' | |
746 | done | |
747 | ||
f954c7b8 JH |
748 | # Test fsmonitor interaction with submodules. |
749 | # | |
750 | # If we start the daemon in the super, it will see FS events for | |
751 | # everything in the working directory cone and this includes any | |
752 | # files/directories contained *within* the submodules. | |
753 | # | |
754 | # A `git status` at top level will get events for items within the | |
755 | # submodule and ignore them, since they aren't named in the index | |
756 | # of the super repo. This makes the fsmonitor response a little | |
757 | # noisy, but it doesn't alter the correctness of the state of the | |
758 | # super-proper. | |
759 | # | |
760 | # When we have submodules, `git status` normally does a recursive | |
761 | # status on each of the submodules and adds a summary row for any | |
762 | # dirty submodules. (See the "S..." bits in porcelain V2 output.) | |
763 | # | |
764 | # It is therefore important that the top level status not be tricked | |
765 | # by the FSMonitor response to skip those recursive calls. That is, | |
766 | # even if FSMonitor says that the mtime of the submodule directory | |
767 | # hasn't changed and it could be implicitly marked valid, we must | |
768 | # not take that shortcut. We need to force the recusion into the | |
769 | # submodule so that we get a summary of the status *within* the | |
770 | # submodule. | |
771 | ||
772 | create_super () { | |
773 | super="$1" && | |
774 | ||
775 | git init "$super" && | |
776 | echo x >"$super/file_1" && | |
777 | echo y >"$super/file_2" && | |
778 | echo z >"$super/file_3" && | |
779 | mkdir "$super/dir_1" && | |
780 | echo a >"$super/dir_1/file_11" && | |
781 | echo b >"$super/dir_1/file_12" && | |
782 | mkdir "$super/dir_1/dir_2" && | |
783 | echo a >"$super/dir_1/dir_2/file_21" && | |
784 | echo b >"$super/dir_1/dir_2/file_22" && | |
785 | git -C "$super" add . && | |
786 | git -C "$super" commit -m "initial $super commit" | |
787 | } | |
788 | ||
789 | create_sub () { | |
790 | sub="$1" && | |
791 | ||
792 | git init "$sub" && | |
793 | echo x >"$sub/file_x" && | |
794 | echo y >"$sub/file_y" && | |
795 | echo z >"$sub/file_z" && | |
796 | mkdir "$sub/dir_x" && | |
797 | echo a >"$sub/dir_x/file_a" && | |
798 | echo b >"$sub/dir_x/file_b" && | |
799 | mkdir "$sub/dir_x/dir_y" && | |
800 | echo a >"$sub/dir_x/dir_y/file_a" && | |
801 | echo b >"$sub/dir_x/dir_y/file_b" && | |
802 | git -C "$sub" add . && | |
803 | git -C "$sub" commit -m "initial $sub commit" | |
804 | } | |
805 | ||
806 | my_match_and_clean () { | |
807 | git -C super --no-optional-locks status --porcelain=v2 >actual.with && | |
808 | git -C super --no-optional-locks -c core.fsmonitor=false \ | |
809 | status --porcelain=v2 >actual.without && | |
810 | test_cmp actual.with actual.without && | |
811 | ||
6a044a20 JS |
812 | git -C super --no-optional-locks diff-index --name-status HEAD >actual.with && |
813 | git -C super --no-optional-locks -c core.fsmonitor=false \ | |
814 | diff-index --name-status HEAD >actual.without && | |
815 | test_cmp actual.with actual.without && | |
816 | ||
f954c7b8 JH |
817 | git -C super/dir_1/dir_2/sub reset --hard && |
818 | git -C super/dir_1/dir_2/sub clean -d -f | |
819 | } | |
820 | ||
9a167cb7 TB |
821 | test_expect_success 'submodule setup' ' |
822 | git config --global protocol.file.allow always | |
823 | ' | |
824 | ||
f954c7b8 JH |
825 | test_expect_success 'submodule always visited' ' |
826 | test_when_finished "git -C super fsmonitor--daemon stop; \ | |
827 | rm -rf super; \ | |
828 | rm -rf sub" && | |
829 | ||
830 | create_super super && | |
831 | create_sub sub && | |
832 | ||
833 | git -C super submodule add ../sub ./dir_1/dir_2/sub && | |
834 | git -C super commit -m "add sub" && | |
835 | ||
836 | start_daemon -C super && | |
837 | git -C super config core.fsmonitor true && | |
838 | git -C super update-index --fsmonitor && | |
839 | git -C super status && | |
840 | ||
841 | # Now run pairs of commands w/ and w/o FSMonitor while we make | |
842 | # some dirt in the submodule and confirm matching output. | |
843 | ||
844 | # Completely clean status. | |
845 | my_match_and_clean && | |
846 | ||
847 | # .M S..U | |
848 | echo z >super/dir_1/dir_2/sub/dir_x/dir_y/foobar_u && | |
849 | my_match_and_clean && | |
850 | ||
851 | # .M S.M. | |
852 | echo z >super/dir_1/dir_2/sub/dir_x/dir_y/foobar_m && | |
853 | git -C super/dir_1/dir_2/sub add . && | |
854 | my_match_and_clean && | |
855 | ||
856 | # .M S.M. | |
857 | echo z >>super/dir_1/dir_2/sub/dir_x/dir_y/file_a && | |
858 | git -C super/dir_1/dir_2/sub add . && | |
859 | my_match_and_clean && | |
860 | ||
861 | # .M SC.. | |
862 | echo z >>super/dir_1/dir_2/sub/dir_x/dir_y/file_a && | |
863 | git -C super/dir_1/dir_2/sub add . && | |
864 | git -C super/dir_1/dir_2/sub commit -m "SC.." && | |
865 | my_match_and_clean | |
866 | ' | |
867 | ||
53fcfbc8 JH |
868 | # If a submodule has a `sub/.git/` directory (rather than a file |
869 | # pointing to the super's `.git/modules/sub`) and `core.fsmonitor` | |
870 | # turned on in the submodule and the daemon is not yet started in | |
871 | # the submodule, and someone does a `git submodule absorbgitdirs` | |
872 | # in the super, Git will recursively invoke `git submodule--helper` | |
873 | # to do the work and this may try to read the index. This will | |
bb61a962 | 874 | # try to start the daemon in the submodule. |
53fcfbc8 | 875 | |
bb61a962 | 876 | test_expect_success "submodule absorbgitdirs implicitly starts daemon" ' |
53fcfbc8 JH |
877 | test_when_finished "rm -rf super; \ |
878 | rm -rf sub; \ | |
879 | rm super-sub.trace" && | |
880 | ||
881 | create_super super && | |
882 | create_sub sub && | |
883 | ||
884 | # Copy rather than submodule add so that we get a .git dir. | |
885 | cp -R ./sub ./super/dir_1/dir_2/sub && | |
886 | ||
887 | git -C super/dir_1/dir_2/sub config core.fsmonitor true && | |
888 | ||
889 | git -C super submodule add ../sub ./dir_1/dir_2/sub && | |
890 | git -C super commit -m "add sub" && | |
891 | ||
892 | test_path_is_dir super/dir_1/dir_2/sub/.git && | |
893 | ||
bb61a962 ÆAB |
894 | cwd="$(cd super && pwd)" && |
895 | cat >expect <<-EOF && | |
896 | Migrating git directory of '\''dir_1/dir_2/sub'\'' from | |
897 | '\''$cwd/dir_1/dir_2/sub/.git'\'' to | |
898 | '\''$cwd/.git/modules/dir_1/dir_2/sub'\'' | |
899 | EOF | |
53fcfbc8 | 900 | GIT_TRACE2_EVENT="$PWD/super-sub.trace" \ |
bb61a962 ÆAB |
901 | git -C super submodule absorbgitdirs >out 2>actual && |
902 | test_cmp expect actual && | |
903 | test_must_be_empty out && | |
53fcfbc8 | 904 | |
bb61a962 ÆAB |
905 | # Confirm that the trace2 log contains a record of the |
906 | # daemon starting. | |
907 | test_subcommand git fsmonitor--daemon start <super-sub.trace | |
53fcfbc8 JH |
908 | ' |
909 | ||
caa9c37e JH |
910 | # On a case-insensitive file system, confirm that the daemon |
911 | # notices when the .git directory is moved/renamed/deleted | |
b39a8418 | 912 | # regardless of how it is spelled in the FS event. |
caa9c37e JH |
913 | # That is, does the FS event receive the spelling of the |
914 | # operation or does it receive the spelling preserved with | |
915 | # the file/directory. | |
916 | # | |
917 | test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' ' | |
a87a20cb | 918 | test_when_finished "stop_daemon_delete_repo test_insensitive" && |
caa9c37e JH |
919 | |
920 | git init test_insensitive && | |
921 | ||
922 | start_daemon -C test_insensitive --tf "$PWD/insensitive.trace" && | |
923 | ||
924 | mkdir -p test_insensitive/abc/def && | |
925 | echo xyz >test_insensitive/ABC/DEF/xyz && | |
926 | ||
927 | test_path_is_dir test_insensitive/.git && | |
928 | test_path_is_dir test_insensitive/.GIT && | |
929 | ||
b39a8418 AR |
930 | # Rename .git using an alternate spelling to verify that |
931 | # the daemon detects it and automatically shuts down. | |
caa9c37e | 932 | mv test_insensitive/.GIT test_insensitive/.FOO && |
3294ca61 JH |
933 | |
934 | # See [1] above. | |
caa9c37e | 935 | mv test_insensitive/.FOO test_insensitive/.git && |
3294ca61 JH |
936 | |
937 | verify_implicit_shutdown test_insensitive && | |
caa9c37e JH |
938 | |
939 | # Verify that events were reported using on-disk spellings of the | |
940 | # directories and files that we touched. We may or may not get a | |
941 | # trailing slash on modified directories. | |
942 | # | |
81580fa0 ĐTCD |
943 | grep -E "^event: abc/?$" ./insensitive.trace && |
944 | grep -E "^event: abc/def/?$" ./insensitive.trace && | |
945 | grep -E "^event: abc/def/xyz$" ./insensitive.trace | |
caa9c37e JH |
946 | ' |
947 | ||
eb299010 JH |
948 | # The variable "unicode_debug" is defined in the following library |
949 | # script to dump information about how the (OS, FS) handles Unicode | |
950 | # composition. Uncomment the following line if you want to enable it. | |
951 | # | |
952 | # unicode_debug=true | |
953 | ||
954 | . "$TEST_DIRECTORY/lib-unicode-nfc-nfd.sh" | |
955 | ||
956 | # See if the OS or filesystem does NFC/NFD aliasing/munging. | |
957 | # | |
958 | # The daemon should err on the side of caution and send BOTH the | |
959 | # NFC and NFD forms. It does not know the original spelling of | |
960 | # the pathname (how the user thinks it should be spelled), so | |
961 | # emit both and let the client decide (when necessary). This is | |
962 | # similar to "core.precomposeUnicode". | |
963 | # | |
964 | test_expect_success !UNICODE_COMPOSITION_SENSITIVE 'Unicode nfc/nfd' ' | |
965 | test_when_finished "stop_daemon_delete_repo test_unicode" && | |
966 | ||
967 | git init test_unicode && | |
968 | ||
969 | start_daemon -C test_unicode --tf "$PWD/unicode.trace" && | |
970 | ||
971 | # Create a directory using an NFC spelling. | |
972 | # | |
973 | mkdir test_unicode/nfc && | |
974 | mkdir test_unicode/nfc/c_${utf8_nfc} && | |
975 | ||
976 | # Create a directory using an NFD spelling. | |
977 | # | |
978 | mkdir test_unicode/nfd && | |
979 | mkdir test_unicode/nfd/d_${utf8_nfd} && | |
980 | ||
f591a9bf | 981 | test-tool -C test_unicode fsmonitor-client query --token 0 && |
eb299010 JH |
982 | |
983 | if test_have_prereq UNICODE_NFC_PRESERVED | |
984 | then | |
985 | # We should have seen NFC event from OS. | |
986 | # We should not have synthesized an NFD event. | |
81580fa0 ĐTCD |
987 | grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace && |
988 | grep -E -v "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace | |
eb299010 JH |
989 | else |
990 | # We should have seen NFD event from OS. | |
991 | # We should have synthesized an NFC event. | |
81580fa0 ĐTCD |
992 | grep -E "^event: nfc/c_${utf8_nfd}/?$" ./unicode.trace && |
993 | grep -E "^event: nfc/c_${utf8_nfc}/?$" ./unicode.trace | |
eb299010 JH |
994 | fi && |
995 | ||
996 | # We assume UNICODE_NFD_PRESERVED. | |
997 | # We should have seen explicit NFD from OS. | |
998 | # We should have synthesized an NFC event. | |
81580fa0 ĐTCD |
999 | grep -E "^event: nfd/d_${utf8_nfd}/?$" ./unicode.trace && |
1000 | grep -E "^event: nfd/d_${utf8_nfc}/?$" ./unicode.trace | |
eb299010 JH |
1001 | ' |
1002 | ||
3b7a4475 | 1003 | test_expect_success 'split-index and FSMonitor work well together' ' |
3704fed5 JS |
1004 | git init split-index && |
1005 | test_when_finished "git -C \"$PWD/split-index\" \ | |
1006 | fsmonitor--daemon stop" && | |
1007 | ( | |
1008 | cd split-index && | |
1009 | git config core.splitIndex true && | |
1010 | # force split-index in most cases | |
1011 | git config splitIndex.maxPercentChange 99 && | |
1012 | git config core.fsmonitor true && | |
1013 | ||
1014 | # Create the following commit topology: | |
1015 | # | |
1016 | # * merge three | |
1017 | # |\ | |
1018 | # | * three | |
1019 | # * | merge two | |
1020 | # |\| | |
1021 | # | * two | |
1022 | # * | one | |
1023 | # |/ | |
1024 | # * 5a5efd7 initial | |
1025 | ||
1026 | test_commit initial && | |
1027 | test_commit two && | |
1028 | test_commit three && | |
1029 | git reset --hard initial && | |
1030 | test_commit one && | |
1031 | test_tick && | |
1032 | git merge two && | |
1033 | test_tick && | |
1034 | git merge three && | |
1035 | ||
1036 | git rebase --force-rebase -r one | |
1037 | ) | |
1038 | ' | |
1039 | ||
32ca706f JH |
1040 | # The FSMonitor daemon reports the OBSERVED pathname of modified files |
1041 | # and thus contains the OBSERVED spelling on case-insensitive file | |
1042 | # systems. The daemon does not (and should not) load the .git/index | |
1043 | # file and therefore does not know the expected case-spelling. Since | |
1044 | # it is possible for the user to create files/subdirectories with the | |
1045 | # incorrect case, a modified file event for a tracked will not have | |
1046 | # the EXPECTED case. This can cause `index_name_pos()` to incorrectly | |
1047 | # report that the file is untracked. This causes the client to fail to | |
1048 | # mark the file as possibly dirty (keeping the CE_FSMONITOR_VALID bit | |
1049 | # set) so that `git status` will avoid inspecting it and thus not | |
1050 | # present in the status output. | |
1051 | # | |
1052 | # The setup is a little contrived. | |
1053 | # | |
29c139ce | 1054 | test_expect_success CASE_INSENSITIVE_FS 'fsmonitor subdir case wrong on disk' ' |
32ca706f JH |
1055 | test_when_finished "stop_daemon_delete_repo subdir_case_wrong" && |
1056 | ||
1057 | git init subdir_case_wrong && | |
1058 | ( | |
1059 | cd subdir_case_wrong && | |
1060 | echo x >AAA && | |
1061 | echo x >BBB && | |
1062 | ||
1063 | mkdir dir1 && | |
1064 | echo x >dir1/file1 && | |
1065 | mkdir dir1/dir2 && | |
1066 | echo x >dir1/dir2/file2 && | |
1067 | mkdir dir1/dir2/dir3 && | |
1068 | echo x >dir1/dir2/dir3/file3 && | |
1069 | ||
1070 | echo x >yyy && | |
1071 | echo x >zzz && | |
1072 | git add . && | |
1073 | git commit -m "data" && | |
1074 | ||
1075 | # This will cause "dir1/" and everything under it | |
1076 | # to be deleted. | |
1077 | git sparse-checkout set --cone --sparse-index && | |
1078 | ||
1079 | # Create dir2 with the wrong case and then let Git | |
1080 | # repopulate dir3 -- it will not correct the spelling | |
1081 | # of dir2. | |
1082 | mkdir dir1 && | |
1083 | mkdir dir1/DIR2 && | |
1084 | git sparse-checkout add dir1/dir2/dir3 | |
1085 | ) && | |
1086 | ||
1087 | start_daemon -C subdir_case_wrong --tf "$PWD/subdir_case_wrong.trace" && | |
1088 | ||
1089 | # Enable FSMonitor in the client. Run enough commands for | |
1090 | # the .git/index to sync up with the daemon with everything | |
1091 | # marked clean. | |
1092 | git -C subdir_case_wrong config core.fsmonitor true && | |
1093 | git -C subdir_case_wrong update-index --fsmonitor && | |
1094 | git -C subdir_case_wrong status && | |
1095 | ||
1096 | # Make some files dirty so that FSMonitor gets FSEvents for | |
1097 | # each of them. | |
1098 | echo xx >>subdir_case_wrong/AAA && | |
1099 | echo xx >>subdir_case_wrong/dir1/DIR2/dir3/file3 && | |
1100 | echo xx >>subdir_case_wrong/zzz && | |
1101 | ||
1102 | GIT_TRACE_FSMONITOR="$PWD/subdir_case_wrong.log" \ | |
1103 | git -C subdir_case_wrong --no-optional-locks status --short \ | |
1104 | >"$PWD/subdir_case_wrong.out" && | |
1105 | ||
1106 | # "git status" should have gotten file events for each of | |
1107 | # the 3 files. | |
1108 | # | |
1109 | # "dir2" should be in the observed case on disk. | |
1110 | grep "fsmonitor_refresh_callback" \ | |
1111 | <"$PWD/subdir_case_wrong.log" \ | |
1112 | >"$PWD/subdir_case_wrong.log1" && | |
1113 | ||
1114 | grep -q "AAA.*pos 0" "$PWD/subdir_case_wrong.log1" && | |
1115 | grep -q "zzz.*pos 6" "$PWD/subdir_case_wrong.log1" && | |
1116 | ||
1117 | grep -q "dir1/DIR2/dir3/file3.*pos -3" "$PWD/subdir_case_wrong.log1" && | |
1118 | ||
29c139ce JH |
1119 | # Verify that we get a mapping event to correct the case. |
1120 | grep -q "MAP:.*dir1/DIR2/dir3/file3.*dir1/dir2/dir3/file3" \ | |
1121 | "$PWD/subdir_case_wrong.log1" && | |
1122 | ||
32ca706f JH |
1123 | # The refresh-callbacks should have caused "git status" to clear |
1124 | # the CE_FSMONITOR_VALID bit on each of those files and caused | |
1125 | # the worktree scan to visit them and mark them as modified. | |
1126 | grep -q " M AAA" "$PWD/subdir_case_wrong.out" && | |
1127 | grep -q " M zzz" "$PWD/subdir_case_wrong.out" && | |
32ca706f JH |
1128 | grep -q " M dir1/dir2/dir3/file3" "$PWD/subdir_case_wrong.out" |
1129 | ' | |
1130 | ||
29c139ce | 1131 | test_expect_success CASE_INSENSITIVE_FS 'fsmonitor file case wrong on disk' ' |
32ca706f JH |
1132 | test_when_finished "stop_daemon_delete_repo file_case_wrong" && |
1133 | ||
1134 | git init file_case_wrong && | |
1135 | ( | |
1136 | cd file_case_wrong && | |
1137 | echo x >AAA && | |
1138 | echo x >BBB && | |
1139 | ||
1140 | mkdir dir1 && | |
1141 | mkdir dir1/dir2 && | |
1142 | mkdir dir1/dir2/dir3 && | |
1143 | echo x >dir1/dir2/dir3/FILE-3-B && | |
1144 | echo x >dir1/dir2/dir3/XXXX-3-X && | |
1145 | echo x >dir1/dir2/dir3/file-3-a && | |
1146 | echo x >dir1/dir2/dir3/yyyy-3-y && | |
1147 | mkdir dir1/dir2/dir4 && | |
1148 | echo x >dir1/dir2/dir4/FILE-4-A && | |
1149 | echo x >dir1/dir2/dir4/XXXX-4-X && | |
1150 | echo x >dir1/dir2/dir4/file-4-b && | |
1151 | echo x >dir1/dir2/dir4/yyyy-4-y && | |
1152 | ||
1153 | echo x >yyy && | |
1154 | echo x >zzz && | |
1155 | git add . && | |
1156 | git commit -m "data" | |
1157 | ) && | |
1158 | ||
1159 | start_daemon -C file_case_wrong --tf "$PWD/file_case_wrong.trace" && | |
1160 | ||
1161 | # Enable FSMonitor in the client. Run enough commands for | |
1162 | # the .git/index to sync up with the daemon with everything | |
1163 | # marked clean. | |
1164 | git -C file_case_wrong config core.fsmonitor true && | |
1165 | git -C file_case_wrong update-index --fsmonitor && | |
1166 | git -C file_case_wrong status && | |
1167 | ||
1168 | # Make some files dirty so that FSMonitor gets FSEvents for | |
1169 | # each of them. | |
1170 | echo xx >>file_case_wrong/AAA && | |
1171 | echo xx >>file_case_wrong/zzz && | |
1172 | ||
1173 | # Rename some files so that FSMonitor sees a create and delete | |
1174 | # FSEvent for each. (A simple "mv foo FOO" is not portable | |
1175 | # between macOS and Windows. It works on both platforms, but makes | |
1176 | # the test messy, since (1) one platform updates "ctime" on the | |
1177 | # moved file and one does not and (2) it causes a directory event | |
1178 | # on one platform and not on the other which causes additional | |
1179 | # scanning during "git status" which causes a "H" vs "h" discrepancy | |
1180 | # in "git ls-files -f".) So old-school it and move it out of the | |
1181 | # way and copy it to the case-incorrect name so that we get fresh | |
1182 | # "ctime" and "mtime" values. | |
1183 | ||
1184 | mv file_case_wrong/dir1/dir2/dir3/file-3-a file_case_wrong/dir1/dir2/dir3/ORIG && | |
1185 | cp file_case_wrong/dir1/dir2/dir3/ORIG file_case_wrong/dir1/dir2/dir3/FILE-3-A && | |
1186 | rm file_case_wrong/dir1/dir2/dir3/ORIG && | |
1187 | mv file_case_wrong/dir1/dir2/dir4/FILE-4-A file_case_wrong/dir1/dir2/dir4/ORIG && | |
1188 | cp file_case_wrong/dir1/dir2/dir4/ORIG file_case_wrong/dir1/dir2/dir4/file-4-a && | |
1189 | rm file_case_wrong/dir1/dir2/dir4/ORIG && | |
1190 | ||
1191 | # Run status enough times to fully sync. | |
1192 | # | |
1193 | # The first instance should get the create and delete FSEvents | |
1194 | # for each pair. Status should update the index with a new FSM | |
1195 | # token (so the next invocation will not see data for these | |
1196 | # events). | |
1197 | ||
1198 | GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try1.log" \ | |
1199 | git -C file_case_wrong status --short \ | |
1200 | >"$PWD/file_case_wrong-try1.out" && | |
1201 | grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try1.log" && | |
1202 | grep -q "fsmonitor_refresh_callback.*file-3-a.*pos 4" "$PWD/file_case_wrong-try1.log" && | |
1203 | grep -q "fsmonitor_refresh_callback.*FILE-4-A.*pos 6" "$PWD/file_case_wrong-try1.log" && | |
1204 | grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try1.log" && | |
1205 | ||
1206 | # FSM refresh will have invalidated the FSM bit and cause a regular | |
1207 | # (real) scan of these tracked files, so they should have "H" status. | |
1208 | # (We will not see a "h" status until the next refresh (on the next | |
1209 | # command).) | |
1210 | ||
1211 | git -C file_case_wrong ls-files -f >"$PWD/file_case_wrong-lsf1.out" && | |
1212 | grep -q "H dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-lsf1.out" && | |
1213 | grep -q "H dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-lsf1.out" && | |
1214 | ||
1215 | ||
1216 | # Try the status again. We assume that the above status command | |
1217 | # advanced the token so that the next one will not see those events. | |
1218 | ||
1219 | GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try2.log" \ | |
1220 | git -C file_case_wrong status --short \ | |
1221 | >"$PWD/file_case_wrong-try2.out" && | |
1222 | ! grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos" "$PWD/file_case_wrong-try2.log" && | |
1223 | ! grep -q "fsmonitor_refresh_callback.*file-3-a.*pos" "$PWD/file_case_wrong-try2.log" && | |
1224 | ! grep -q "fsmonitor_refresh_callback.*FILE-4-A.*pos" "$PWD/file_case_wrong-try2.log" && | |
1225 | ! grep -q "fsmonitor_refresh_callback.*file-4-a.*pos" "$PWD/file_case_wrong-try2.log" && | |
1226 | ||
1227 | # FSM refresh saw nothing, so it will mark all files as valid, | |
1228 | # so they should now have "h" status. | |
1229 | ||
1230 | git -C file_case_wrong ls-files -f >"$PWD/file_case_wrong-lsf2.out" && | |
1231 | grep -q "h dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-lsf2.out" && | |
1232 | grep -q "h dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-lsf2.out" && | |
1233 | ||
1234 | ||
1235 | # We now have files with clean content, but with case-incorrect | |
1236 | # file names. Modify them to see if status properly reports | |
1237 | # them. | |
1238 | ||
1239 | echo xx >>file_case_wrong/dir1/dir2/dir3/FILE-3-A && | |
1240 | echo xx >>file_case_wrong/dir1/dir2/dir4/file-4-a && | |
1241 | ||
1242 | GIT_TRACE_FSMONITOR="$PWD/file_case_wrong-try3.log" \ | |
1243 | git -C file_case_wrong --no-optional-locks status --short \ | |
1244 | >"$PWD/file_case_wrong-try3.out" && | |
29c139ce JH |
1245 | |
1246 | # Verify that we get a mapping event to correct the case. | |
1247 | grep -q "fsmonitor_refresh_callback MAP:.*dir1/dir2/dir3/FILE-3-A.*dir1/dir2/dir3/file-3-a" \ | |
1248 | "$PWD/file_case_wrong-try3.log" && | |
1249 | grep -q "fsmonitor_refresh_callback MAP:.*dir1/dir2/dir4/file-4-a.*dir1/dir2/dir4/FILE-4-A" \ | |
1250 | "$PWD/file_case_wrong-try3.log" && | |
1251 | ||
32ca706f JH |
1252 | # FSEvents are in observed case. |
1253 | grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try3.log" && | |
1254 | grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try3.log" && | |
1255 | ||
29c139ce JH |
1256 | # The refresh-callbacks should have caused "git status" to clear |
1257 | # the CE_FSMONITOR_VALID bit on each of those files and caused | |
1258 | # the worktree scan to visit them and mark them as modified. | |
32ca706f JH |
1259 | grep -q " M dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-try3.out" && |
1260 | grep -q " M dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-try3.out" | |
1261 | ' | |
1262 | ||
a00cdff8 | 1263 | test_done |