Skip to content

Commit 32ca706

Browse files
jeffhostetlergitster
authored andcommitted
t7527: add case-insensitve test for FSMonitor
The FSMonitor client code trusts the spelling of the pathnames in the FSEvents received from the FSMonitor daemon. On case-insensitive file systems, these OBSERVED pathnames may be spelled differently than the EXPECTED pathnames listed in the .git/index. This causes a miss when using `index_name_pos()` which expects the given case to be correct. When this happens, the FSMonitor client code does not update the state of the CE_FSMONITOR_VALID bit when refreshing the index (and before starting to scan the worktree). This results in modified files NOT being reported by `git status` when there is a discrepancy in the case-spelling of a tracked file's pathname. This commit contains a (rather contrived) test case to demonstrate this. A later commit in this series will update the FSMonitor client code to recognize these discrepancies and update the CE_ bit accordingly. Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b316552 commit 32ca706

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

t/t7527-builtin-fsmonitor.sh

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,4 +1037,221 @@ test_expect_success 'split-index and FSMonitor work well together' '
10371037
)
10381038
'
10391039

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+
#
1054+
test_expect_failure CASE_INSENSITIVE_FS 'fsmonitor subdir case wrong on disk' '
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+
1119+
# The refresh-callbacks should have caused "git status" to clear
1120+
# the CE_FSMONITOR_VALID bit on each of those files and caused
1121+
# the worktree scan to visit them and mark them as modified.
1122+
grep -q " M AAA" "$PWD/subdir_case_wrong.out" &&
1123+
grep -q " M zzz" "$PWD/subdir_case_wrong.out" &&
1124+
1125+
# Expect Breakage: with the case confusion, the "(pos -3)" causes
1126+
# the client to not clear the CE_FSMONITOR_VALID bit and therefore
1127+
# status will not rescan the file and therefore not report it as dirty.
1128+
grep -q " M dir1/dir2/dir3/file3" "$PWD/subdir_case_wrong.out"
1129+
'
1130+
1131+
test_expect_failure CASE_INSENSITIVE_FS 'fsmonitor file case wrong on disk' '
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" &&
1245+
# FSEvents are in observed case.
1246+
grep -q "fsmonitor_refresh_callback.*FILE-3-A.*pos -3" "$PWD/file_case_wrong-try3.log" &&
1247+
grep -q "fsmonitor_refresh_callback.*file-4-a.*pos -9" "$PWD/file_case_wrong-try3.log" &&
1248+
1249+
# Expect Breakage: with the case confusion, the "(pos-3)" and
1250+
# "(pos -9)" causes the client to not clear the CE_FSMONITOR_VALID
1251+
# bit and therefore status will not rescan the files and therefore
1252+
# not report them as dirty.
1253+
grep -q " M dir1/dir2/dir3/file-3-a" "$PWD/file_case_wrong-try3.out" &&
1254+
grep -q " M dir1/dir2/dir4/FILE-4-A" "$PWD/file_case_wrong-try3.out"
1255+
'
1256+
10401257
test_done

0 commit comments

Comments
 (0)