git-commit-vandalism/t/t5411/test-0033-report-with-options--porcelain.sh
Jiang Xin 8388a64cd1 t5411: use different out file to prevent overwriting
SZEDER reported that t5411 failed in Travis CI's s390x environment a
couple of times, and could be reproduced with '--stress' test on this
specific environment.  The test failure messages might look like this:

    + test_cmp expect actual
    --- expect      2021-01-17 21:55:23.430750004 +0000
    +++ actual      2021-01-17 21:55:23.430750004 +0000
    @@ -1 +1 @@
    -<COMMIT-A> refs/heads/main
    +<COMMIT-A> refs/heads/maifatal: the remote end hung up unexpectedly
    error: last command exited with $?=1
    not ok 86 - proc-receive: not support push options (builtin protocol)

The file 'actual' is filtered from the file 'out' which contains result
of 'git show-ref' command.  Due to the error messages from other process
is written into the file 'out' accidentally, t5411 failed.  SZEDER finds
the root cause of this issue:

 - 'git push' is executed with its standard output and error redirected
   to the file 'out'.

 - 'git push' executes 'git receive-pack' internally, which inherits
   the open file descriptors, so its output and error goes into that
   same 'out' file.

 - 'git push' ends without waiting for the close of 'git-receive-pack'
   for some cases, and the file 'out' is reused for test of
   'git show-ref' afterwards.

 - A mixture of the output of 'git show-ref' abd 'git receive-pack'
   leads to this issue.

The first intuitive reaction to resolve this issue is to remove the
file 'out' after use, so that the newly created file 'out' will have a
different file descriptor and will not be overwritten by the
'git receive-pack' process.  But Johannes pointed out that removing an
open file is not possible on Windows.  So we use different temporary
file names to store the output of 'git push' to solve this issue.

Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Helped-by: Johannes Sixt <j6t@kdbg.org>
Helped-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-22 13:09:04 -08:00

266 lines
9.8 KiB
Bash

test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "option refname refs/pull/123/head" \
-r "option old-oid $B"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report option without matching ok ($PROTOCOL/porcelain)" '
test_must_fail git -C workbench push --porcelain origin \
HEAD:refs/for/main/topic \
>out-$test_count 2>&1 &&
make_user_friendly_and_stable_output <out-$test_count >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> option refname refs/pull/123/head
remote: proc-receive> option old-oid <COMMIT-B>
remote: error: proc-receive reported "option" without a matching "ok/ng" directive
To <URL/of/upstream.git>
! HEAD:refs/for/main/topic [remote rejected] (proc-receive failed to report status)
Done
EOF
test_cmp expect actual
'
test_expect_success "setup proc-receive hook (option refname, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
-r "option refname refs/pull/123/head"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> ok refs/for/main/topic
remote: proc-receive> option refname refs/pull/123/head
remote: # post-receive hook
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
To <URL/of/upstream.git>
* HEAD:refs/pull/123/head [new reference]
Done
EOF
test_cmp expect actual
'
test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
-r "option refname refs/pull/123/head" \
-r "option forced-update"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> ok refs/for/main/topic
remote: proc-receive> option refname refs/pull/123/head
remote: proc-receive> option forced-update
remote: # post-receive hook
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
To <URL/of/upstream.git>
* HEAD:refs/pull/123/head [new reference]
Done
EOF
test_cmp expect actual
'
test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
-r "option refname refs/pull/123/head" \
-r "option old-oid $B"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> ok refs/for/main/topic
remote: proc-receive> option refname refs/pull/123/head
remote: proc-receive> option old-oid <COMMIT-B>
remote: # post-receive hook
remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/123/head
To <URL/of/upstream.git>
HEAD:refs/pull/123/head <OID-B>..<OID-A>
Done
EOF
test_cmp expect actual
'
test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
-r "option old-oid $B"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> ok refs/for/main/topic
remote: proc-receive> option old-oid <COMMIT-B>
remote: # post-receive hook
remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/main/topic
To <URL/of/upstream.git>
HEAD:refs/for/main/topic <OID-B>..<OID-A>
Done
EOF
test_cmp expect actual
'
test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/main/topic" \
-r "option old-oid $A" \
-r "option new-oid $B"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> ok refs/for/main/topic
remote: proc-receive> option old-oid <COMMIT-A>
remote: proc-receive> option new-oid <COMMIT-B>
remote: # post-receive hook
remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/main/topic
To <URL/of/upstream.git>
HEAD:refs/for/main/topic <OID-A>..<OID-B>
Done
EOF
test_cmp expect actual
'
test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL/porcelain)" '
write_script "$upstream/hooks/proc-receive" <<-EOF
printf >&2 "# proc-receive hook\n"
test-tool proc-receive -v \
-r "ok refs/for/a/b/c/topic" \
-r "ok refs/for/next/topic" \
-r "option refname refs/pull/123/head" \
-r "ok refs/for/main/topic" \
-r "option refname refs/pull/124/head" \
-r "option old-oid $B" \
-r "option forced-update" \
-r "option new-oid $A"
EOF
'
# Refs of upstream : main(A)
# Refs of workbench: main(A) tags/v123
# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/main/topic(A)
test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porcelain)" '
git -C workbench push --porcelain origin \
HEAD:refs/for/next/topic \
HEAD:refs/for/a/b/c/topic \
HEAD:refs/for/main/topic \
>out 2>&1 &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
remote: # pre-receive hook
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: # proc-receive hook
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/main/topic
remote: proc-receive> ok refs/for/a/b/c/topic
remote: proc-receive> ok refs/for/next/topic
remote: proc-receive> option refname refs/pull/123/head
remote: proc-receive> ok refs/for/main/topic
remote: proc-receive> option refname refs/pull/124/head
remote: proc-receive> option old-oid <COMMIT-B>
remote: proc-receive> option forced-update
remote: proc-receive> option new-oid <COMMIT-A>
remote: # post-receive hook
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/pull/123/head
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/a/b/c/topic
remote: post-receive< <COMMIT-B> <COMMIT-A> refs/pull/124/head
To <URL/of/upstream.git>
* HEAD:refs/pull/123/head [new reference]
* HEAD:refs/for/a/b/c/topic [new reference]
+ HEAD:refs/pull/124/head <OID-B>...<OID-A> (forced update)
Done
EOF
test_cmp expect actual &&
git -C "$upstream" show-ref >out &&
make_user_friendly_and_stable_output <out >actual &&
cat >expect <<-EOF &&
<COMMIT-A> refs/heads/main
EOF
test_cmp expect actual
'