Skip to content

Commit 625e380

Browse files
matheustavaresgitster
authored andcommitted
parallel-checkout: add tests related to clone collisions
Add tests to confirm that path collisions are properly reported during a clone operation using parallel-checkout. Original-patch-by: Jeff Hostetler <[email protected]> Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Matheus Tavares <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 682569c commit 625e380

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/bin/sh
2+
3+
test_description='parallel-checkout collisions'
4+
5+
. ./test-lib.sh
6+
7+
# When there are pathname collisions during a clone, Git should report a warning
8+
# listing all of the colliding entries. The sequential code detects a collision
9+
# by calling lstat() before trying to open(O_CREAT) the file. Then, to find the
10+
# colliding pair of an item k, it searches cache_entry[0, k-1].
11+
#
12+
# This is not sufficient in parallel-checkout mode since colliding files may be
13+
# created in a racy order. The tests in this file make sure the collision
14+
# detection code is extended for parallel-checkout. This is done in two parts:
15+
#
16+
# - First, two parallel workers create four colliding files racily.
17+
# - Then this exercise is repeated but forcing the colliding pair to appear in
18+
# the second half of the cache_entry's array.
19+
#
20+
# The second item uses the fact that files with clean/smudge filters are not
21+
# parallel-eligible; and that they are processed sequentially *before* any
22+
# worker is spawned. We set a filter attribute to the last entry in the
23+
# cache_entry[] array, making it non-eligible, so that it is populated first.
24+
# This way, we can test if the collision detection code is correctly looking
25+
# for collision pairs in the second half of the array.
26+
27+
test_expect_success CASE_INSENSITIVE_FS 'setup' '
28+
file_hex=$(git hash-object -w --stdin </dev/null) &&
29+
file_oct=$(echo $file_hex | hex2oct) &&
30+
31+
attr_hex=$(echo "file_x filter=logger" | git hash-object -w --stdin) &&
32+
attr_oct=$(echo $attr_hex | hex2oct) &&
33+
34+
printf "100644 FILE_X\0${file_oct}" >tree &&
35+
printf "100644 FILE_x\0${file_oct}" >>tree &&
36+
printf "100644 file_X\0${file_oct}" >>tree &&
37+
printf "100644 file_x\0${file_oct}" >>tree &&
38+
printf "100644 .gitattributes\0${attr_oct}" >>tree &&
39+
40+
tree_hex=$(git hash-object -w -t tree --stdin <tree) &&
41+
commit_hex=$(git commit-tree -m collisions $tree_hex) &&
42+
git update-ref refs/heads/collisions $commit_hex &&
43+
44+
write_script logger_script <<-\EOF
45+
echo "$@" >>filter.log
46+
EOF
47+
'
48+
49+
clone_and_check_collision()
50+
{
51+
id=$1 workers=$2 threshold=$3 expected_workers=$4 filter=$5 &&
52+
53+
filter_opts=
54+
if test "$filter" -eq "use_filter"
55+
then
56+
# We use `core.ignoreCase=0` so that only `file_x`
57+
# matches the pattern in .gitattributes.
58+
#
59+
filter_opts='-c filter.logger.smudge="../logger_script %f" -c core.ignoreCase=0'
60+
fi &&
61+
62+
test_path_is_missing $id.trace &&
63+
GIT_TRACE2="$(pwd)/$id.trace" git \
64+
-c checkout.workers=$workers \
65+
-c checkout.thresholdForParallelism=$threshold \
66+
$filter_opts clone --branch=collisions -- . r_$id 2>$id.warning &&
67+
68+
# Check that checkout spawned the right number of workers
69+
workers_in_trace=$(grep "child_start\[.\] git checkout--helper" $id.trace | wc -l) &&
70+
test $workers_in_trace -eq $expected_workers &&
71+
72+
if test $filter -eq "use_filter"
73+
then
74+
# Make sure only 'file_x' was filtered
75+
test_path_is_file r_$id/filter.log &&
76+
echo file_x >expected.filter.log &&
77+
test_cmp r_$id/filter.log expected.filter.log
78+
else
79+
test_path_is_missing r_$id/filter.log
80+
fi &&
81+
82+
grep FILE_X $id.warning &&
83+
grep FILE_x $id.warning &&
84+
grep file_X $id.warning &&
85+
grep file_x $id.warning &&
86+
test_i18ngrep "the following paths have collided" $id.warning
87+
}
88+
89+
test_expect_success CASE_INSENSITIVE_FS 'collision detection on parallel clone' '
90+
clone_and_check_collision parallel 2 0 2
91+
'
92+
93+
test_expect_success CASE_INSENSITIVE_FS 'collision detection on fallback to sequential clone' '
94+
git ls-tree --name-only -r collisions >files &&
95+
nr_files=$(wc -l <files) &&
96+
threshold=$(($nr_files + 1)) &&
97+
clone_and_check_collision sequential 2 $threshold 0
98+
'
99+
100+
# The next two tests don't work on Windows because, on this system, collision
101+
# detection uses strcmp() (when core.ignoreCase=0) to find the colliding pair.
102+
# But they work on OSX, where collision detection uses inode.
103+
104+
test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN 'collision detection on parallel clone w/ filter' '
105+
clone_and_check_collision parallel-with-filter 2 0 2 use_filter
106+
'
107+
108+
test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN 'collision detection on fallback to sequential clone w/ filter' '
109+
git ls-tree --name-only -r collisions >files &&
110+
nr_files=$(wc -l <files) &&
111+
threshold=$(($nr_files + 1)) &&
112+
clone_and_check_collision sequential-with-filter 2 $threshold 0 use_filter
113+
'
114+
115+
test_done

0 commit comments

Comments
 (0)