Skip to content

Commit

Permalink
t1404: add a bunch of tests of D/F conflicts
Browse files Browse the repository at this point in the history
It is currently not allowed, in a single transaction, to add one
reference and delete another reference if the two reference names D/F
conflict with each other (e.g., like `refs/foo/bar` and `refs/foo`).
The reason is that the code would need to take locks

    $GIT_DIR/refs/foo.lock
    $GIT_DIR/refs/foo/bar.lock

But the latter lock couldn't coexist with the loose reference file

    $GIT_DIR/refs/foo

, because `$GIT_DIR/refs/foo` cannot be both a directory and a file at
the same time (hence the name "D/F conflict).

Add a bunch of tests that we cleanly reject such transactions.

In fact, many of the new tests currently fail. They will be fixed in
the next commit along with an explanation.

Reported-by: Jeff King <peff@peff.net>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
mhagger authored and gitster committed Oct 25, 2017
1 parent 5e00a6c commit 2e9de01
Showing 1 changed file with 141 additions and 0 deletions.
141 changes: 141 additions & 0 deletions t/t1404-update-ref-errors.sh
Expand Up @@ -34,6 +34,81 @@ test_update_rejected () {

Q="'"

# Test adding and deleting D/F-conflicting references in a single
# transaction.
df_test() {
prefix="$1"
pack=: symadd=false symdel=false add_del=false addref= delref=
shift
while test $# -gt 0
do
case "$1" in
--pack)
pack="git pack-refs --all"
shift
;;
--sym-add)
# Perform the add via a symbolic reference
symadd=true
shift
;;
--sym-del)
# Perform the del via a symbolic reference
symdel=true
shift
;;
--del-add)
# Delete first reference then add second
add_del=false
delref="$prefix/r/$2"
addref="$prefix/r/$3"
shift 3
;;
--add-del)
# Add first reference then delete second
add_del=true
addref="$prefix/r/$2"
delref="$prefix/r/$3"
shift 3
;;
*)
echo 1>&2 "Extra args to df_test: $*"
return 1
;;
esac
done
git update-ref "$delref" $C &&
if $symadd
then
addname="$prefix/s/symadd" &&
git symbolic-ref "$addname" "$addref"
else
addname="$addref"
fi &&
if $symdel
then
delname="$prefix/s/symdel" &&
git symbolic-ref "$delname" "$delref"
else
delname="$delref"
fi &&
cat >expected-err <<-EOF &&
fatal: cannot lock ref $Q$addname$Q: $Q$delref$Q exists; cannot create $Q$addref$Q
EOF
$pack &&
if $add_del
then
printf "%s\n" "create $addname $D" "delete $delname"
else
printf "%s\n" "delete $delname" "create $addname $D"
fi >commands &&
test_must_fail git update-ref --stdin <commands 2>output.err &&
test_cmp expected-err output.err &&
printf "%s\n" "$C $delref" >expected-refs &&
git for-each-ref --format="%(objectname) %(refname)" $prefix/r >actual-refs &&
test_cmp expected-refs actual-refs
}

test_expect_success 'setup' '
git commit --allow-empty -m Initial &&
Expand Down Expand Up @@ -188,6 +263,72 @@ test_expect_success 'empty directory should not fool 1-arg delete' '
git update-ref --stdin
'

test_expect_success 'D/F conflict prevents add long + delete short' '
df_test refs/df-al-ds --add-del foo/bar foo
'

test_expect_success 'D/F conflict prevents add short + delete long' '
df_test refs/df-as-dl --add-del foo foo/bar
'

test_expect_failure 'D/F conflict prevents delete long + add short' '
df_test refs/df-dl-as --del-add foo/bar foo
'

test_expect_failure 'D/F conflict prevents delete short + add long' '
df_test refs/df-ds-al --del-add foo foo/bar
'

test_expect_success 'D/F conflict prevents add long + delete short packed' '
df_test refs/df-al-dsp --pack --add-del foo/bar foo
'

test_expect_success 'D/F conflict prevents add short + delete long packed' '
df_test refs/df-as-dlp --pack --add-del foo foo/bar
'

test_expect_failure 'D/F conflict prevents delete long packed + add short' '
df_test refs/df-dlp-as --pack --del-add foo/bar foo
'

test_expect_failure 'D/F conflict prevents delete short packed + add long' '
df_test refs/df-dsp-al --pack --del-add foo foo/bar
'

# Try some combinations involving symbolic refs...

test_expect_failure 'D/F conflict prevents indirect add long + delete short' '
df_test refs/df-ial-ds --sym-add --add-del foo/bar foo
'

test_expect_success 'D/F conflict prevents indirect add long + indirect delete short' '
df_test refs/df-ial-ids --sym-add --sym-del --add-del foo/bar foo
'

test_expect_success 'D/F conflict prevents indirect add short + indirect delete long' '
df_test refs/df-ias-idl --sym-add --sym-del --add-del foo foo/bar
'

test_expect_failure 'D/F conflict prevents indirect delete long + indirect add short' '
df_test refs/df-idl-ias --sym-add --sym-del --del-add foo/bar foo
'

test_expect_failure 'D/F conflict prevents indirect add long + delete short packed' '
df_test refs/df-ial-dsp --sym-add --pack --add-del foo/bar foo
'

test_expect_success 'D/F conflict prevents indirect add long + indirect delete short packed' '
df_test refs/df-ial-idsp --sym-add --sym-del --pack --add-del foo/bar foo
'

test_expect_success 'D/F conflict prevents add long + indirect delete short packed' '
df_test refs/df-al-idsp --sym-del --pack --add-del foo/bar foo
'

test_expect_failure 'D/F conflict prevents indirect delete long packed + indirect add short' '
df_test refs/df-idlp-ias --sym-add --sym-del --pack --del-add foo/bar foo
'

# Test various errors when reading the old values of references...

test_expect_success 'missing old value blocks update' '
Expand Down

0 comments on commit 2e9de01

Please sign in to comment.