Add tests to confirm that path collisions are properly reported during a clone operation using parallel-checkout. Original-patch-by: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> Signed-off-by: Jeff Hostetler <jeffhost@xxxxxxxxxxxxx> Signed-off-by: Matheus Tavares <matheus.bernardino@xxxxxx> --- t/lib-parallel-checkout.sh | 4 +- t/t2081-parallel-checkout-collisions.sh | 98 +++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100755 t/t2081-parallel-checkout-collisions.sh diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh index 4dad9043fb..e62a433eb1 100644 --- a/t/lib-parallel-checkout.sh +++ b/t/lib-parallel-checkout.sh @@ -18,7 +18,7 @@ git_pc() -c checkout.workers=$workers \ -c checkout.thresholdForParallelism=$threshold \ -c advice.detachedHead=0 \ - "$@" && + "$@" 2>&8 && # Check that the expected number of workers has been used. Note that it # can be different from the requested number in two cases: when the @@ -28,7 +28,7 @@ git_pc() local workers_in_trace=$(grep "child_start\[..*\] git checkout--helper" trace | wc -l) && test $workers_in_trace -eq $expected_workers && rm -f trace -} +} 8>&2 2>&4 # Verify that both the working tree and the index were created correctly verify_checkout() diff --git a/t/t2081-parallel-checkout-collisions.sh b/t/t2081-parallel-checkout-collisions.sh new file mode 100755 index 0000000000..5cab2dcd2c --- /dev/null +++ b/t/t2081-parallel-checkout-collisions.sh @@ -0,0 +1,98 @@ +#!/bin/sh + +test_description='parallel-checkout collisions + +When there are path collisions during a clone, Git should report a warning +listing all of the colliding entries. The sequential code detects a collision +by calling lstat() before trying to open(O_CREAT) the file. Then, to find the +colliding pair of an item k, it searches cache_entry[0, k-1]. + +This is not sufficient in parallel checkout since: + +- A colliding file may be created between the lstat() and open() calls; +- A colliding entry might appear in the second half of the cache_entry array. + +The tests in this file make sure that the collision detection code is extended +for parallel checkout. +' + +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-parallel-checkout.sh" + +TEST_ROOT="$PWD" + +test_expect_success CASE_INSENSITIVE_FS 'setup' ' + file_x_hex=$(git hash-object -w --stdin </dev/null) && + file_x_oct=$(echo $file_x_hex | hex2oct) && + + attr_hex=$(echo "file_x filter=logger" | git hash-object -w --stdin) && + attr_oct=$(echo $attr_hex | hex2oct) && + + printf "100644 FILE_X\0${file_x_oct}" >tree && + printf "100644 FILE_x\0${file_x_oct}" >>tree && + printf "100644 file_X\0${file_x_oct}" >>tree && + printf "100644 file_x\0${file_x_oct}" >>tree && + printf "100644 .gitattributes\0${attr_oct}" >>tree && + + tree_hex=$(git hash-object -w -t tree --stdin <tree) && + commit_hex=$(git commit-tree -m collisions $tree_hex) && + git update-ref refs/heads/collisions $commit_hex && + + write_script "$TEST_ROOT"/logger_script <<-\EOF + echo "$@" >>filter.log + EOF +' + +for mode in parallel sequential-fallback +do + + case $mode in + parallel) workers=2 threshold=0 expected_workers=2 ;; + sequential-fallback) workers=2 threshold=100 expected_workers=0 ;; + esac + + test_expect_success CASE_INSENSITIVE_FS "collision detection on $mode clone" ' + git_pc $workers $threshold $expected_workers \ + clone --branch=collisions . $mode 2>$mode.stderr && + + grep FILE_X $mode.stderr && + grep FILE_x $mode.stderr && + grep file_X $mode.stderr && + grep file_x $mode.stderr && + test_i18ngrep "the following paths have collided" $mode.stderr + ' + + # The following test ensures that the collision detection code is + # correctly looking for colliding peers in the second half of the + # cache_entry array. This is done by defining a smudge command for the + # *last* array entry, which makes it non-eligible for parallel-checkout. + # The last entry is then checked out *before* any worker is spawned, + # making it succeed and the workers' entries collide. + # + # Note: this test don't work on Windows because, on this system, + # collision detection uses strcmp() when core.ignoreCase=false. And we + # have to set core.ignoreCase=false so that only 'file_x' matches the + # pattern of the filter attribute. But it works on OSX, where collision + # detection uses inode. + # + test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN "collision detection on $mode clone w/ filter" ' + git_pc $workers $threshold $expected_workers \ + -c core.ignoreCase=false \ + -c filter.logger.smudge="\"$TEST_ROOT/logger_script\" %f" \ + clone --branch=collisions . ${mode}_with_filter \ + 2>${mode}_with_filter.stderr && + + grep FILE_X ${mode}_with_filter.stderr && + grep FILE_x ${mode}_with_filter.stderr && + grep file_X ${mode}_with_filter.stderr && + grep file_x ${mode}_with_filter.stderr && + test_i18ngrep "the following paths have collided" ${mode}_with_filter.stderr && + + # Make sure only "file_x" was filtered + test_path_is_file ${mode}_with_filter/filter.log && + echo file_x >expected.filter.log && + test_cmp ${mode}_with_filter/filter.log expected.filter.log + ' +done + +test_done -- 2.28.0