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