diff mbox series

[2/3] checkout: show bug about failed entries being included in final report

Message ID 8da18a0a8c34a1c10d55bcdda725817db586f763.1657685948.git.matheus.bernardino@usp.br (mailing list archive)
State Superseded
Headers show
Series checkout: fix two bugs on count of updated entries | expand

Commit Message

Matheus Tavares July 13, 2022, 4:19 a.m. UTC
After checkout, git usually reports how many entries were updated at
that operation. However, because we count the entries too soon during
the checkout process, we may actually include entries that do not get
properly checked out in the end. This can lead to an inaccurate final
report if the user expects it to show only the *successful* updates.
This will be fixed in the next commit, but for now let's document it
with a test that cover all checkout modes.

Note that `test_checkout_workers` have to be slightly adjusted in order
to use the construct `test_checkout_workers ...  test_must_fail git
checkout`. The function runs the command given to it with an assignment
prefix to set the GIT_TRACE2 variable. However, this this assignment has
an undefined behavior when the command is a shell function (like
`test_must_fail`). As POSIX specifies:

  If the command name is a function that is not a standard utility
  implemented as a function, variable assignments shall affect the
  current execution environment during the execution of the function. It
  is unspecified:

    - Whether or not the variable assignments persist after the
      completion of the function

    - Whether or not the variables gain the export attribute during the
      execution of the function

Thus, in order to make sure the GIT_TRACE2 value gets visible to the git
command executed by `test_must_fail`, export the variable and run git in
a subshell.

[1]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
     (Section 2.9.1: Simple Commands)

Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
---
 t/lib-parallel-checkout.sh          |  6 +++-
 t/t2080-parallel-checkout-basics.sh | 50 +++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

Comments

Ævar Arnfjörð Bjarmason July 13, 2022, 11:14 a.m. UTC | #1
On Wed, Jul 13 2022, Matheus Tavares wrote:

> After checkout, git usually reports how many entries were updated at
> that operation. However, because we count the entries too soon during
> the checkout process, we may actually include entries that do not get
> properly checked out in the end. This can lead to an inaccurate final
> report if the user expects it to show only the *successful* updates.
> This will be fixed in the next commit, but for now let's document it
> with a test that cover all checkout modes.
>
> Note that `test_checkout_workers` have to be slightly adjusted in order
> to use the construct `test_checkout_workers ...  test_must_fail git
> checkout`. The function runs the command given to it with an assignment
> prefix to set the GIT_TRACE2 variable. However, this this assignment has
> an undefined behavior when the command is a shell function (like
> `test_must_fail`). As POSIX specifies:
>
>   If the command name is a function that is not a standard utility
>   implemented as a function, variable assignments shall affect the
>   current execution environment during the execution of the function. It
>   is unspecified:
>
>     - Whether or not the variable assignments persist after the
>       completion of the function
>
>     - Whether or not the variables gain the export attribute during the
>       execution of the function
>
> Thus, in order to make sure the GIT_TRACE2 value gets visible to the git
> command executed by `test_must_fail`, export the variable and run git in
> a subshell.
>
> [1]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
>      (Section 2.9.1: Simple Commands)
>
> Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
> ---
>  t/lib-parallel-checkout.sh          |  6 +++-
>  t/t2080-parallel-checkout-basics.sh | 50 +++++++++++++++++++++++++++++
>  2 files changed, 55 insertions(+), 1 deletion(-)
>
> diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh
> index 83b279a846..acaee9cbb6 100644
> --- a/t/lib-parallel-checkout.sh
> +++ b/t/lib-parallel-checkout.sh
> @@ -25,7 +25,11 @@ test_checkout_workers () {
>  
>  	local trace_file=trace-test-checkout-workers &&
>  	rm -f "$trace_file" &&
> -	GIT_TRACE2="$(pwd)/$trace_file" "$@" 2>&8 &&
> +	(
> +		GIT_TRACE2="$(pwd)/$trace_file" &&
> +		export GIT_TRACE2 &&
> +		"$@" 2>&8
> +	) &&
>  
>  	local workers="$(grep "child_start\[..*\] git checkout--worker" "$trace_file" | wc -l)" &&
>  	test $workers -eq $expected_workers &&
> diff --git a/t/t2080-parallel-checkout-basics.sh b/t/t2080-parallel-checkout-basics.sh
> index 3e0f8c675f..6fd7e4c4b2 100755
> --- a/t/t2080-parallel-checkout-basics.sh
> +++ b/t/t2080-parallel-checkout-basics.sh
> @@ -226,4 +226,54 @@ test_expect_success SYMLINKS 'parallel checkout checks for symlinks in leading d
>  	)
>  '
>  
> +# This test is here (and not in e.g. t2022-checkout-paths.sh), because we
> +# check the final report including sequential, parallel, and delayed entries
> +# all at the same time. So we must have finer control of the parallel checkout
> +# variables.
> +test_expect_failure PERL '"git checkout ." report should not include failed entries' '
> +	write_script rot13-filter.pl "$PERL_PATH" \
> +		<"$TEST_DIRECTORY"/t0021/rot13-filter.pl &&
> +
> +	test_config_global filter.delay.process \
> +		"\"$(pwd)/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
> +	test_config_global filter.delay.required true &&
> +	test_config_global filter.cat.clean cat  &&
> +	test_config_global filter.cat.smudge cat  &&
> +	test_config_global filter.cat.required true  &&
> +
> +	set_checkout_config 2 0 &&
> +	git init failed_entries &&
> +	(
> +		cd failed_entries &&
> +		cat >.gitattributes <<-EOF &&
> +		*delay*              filter=delay
> +		parallel-ineligible* filter=cat
> +		EOF
> +		echo a >missing-delay.a &&
> +		echo a >parallel-ineligible.a &&
> +		echo a >parallel-eligible.a &&
> +		echo b >success-delay.b &&
> +		echo b >parallel-ineligible.b &&
> +		echo b >parallel-eligible.b &&
> +		git add -A &&
> +		git commit -m files &&
> +
> +		a_blob="$(git rev-parse :parallel-ineligible.a)" &&
> +		dir="$(echo "$a_blob" | cut -c 1-2)" &&
> +		file="$(echo "$a_blob" | cut -c 3-)" &&

Can't this use test_oid_to_path?
> +		rm ".git/objects/$dir/$file" &&
> +		rm *.a *.b &&
> +
> +		test_checkout_workers 2 test_must_fail git checkout . 2>err &&
> +
> +		# All *.b entries should succeed and all *.a entries should fail:
> +		#  - missing-delay.a: the delay filter will drop this path
> +		#  - parallel-*.a: the blob will be missing
> +		#
> +		grep "Updated 3 paths from the index" err &&
> +		test "$(ls *.b | wc -l)" -eq 3 &&
> +		test "$(ls *.a | wc -l)" -eq 0

And this test_stdout_line_count?
Matheus Tavares July 13, 2022, 1 p.m. UTC | #2
On Wed, Jul 13, 2022 at 8:15 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> On Wed, Jul 13 2022, Matheus Tavares wrote:
> >
> > +             a_blob="$(git rev-parse :parallel-ineligible.a)" &&
> > +             dir="$(echo "$a_blob" | cut -c 1-2)" &&
> > +             file="$(echo "$a_blob" | cut -c 3-)" &&
>
> Can't this use test_oid_to_path?
[...]
> > +             test "$(ls *.b | wc -l)" -eq 3 &&
> > +             test "$(ls *.a | wc -l)" -eq 0
>
> And this test_stdout_line_count?

Sure! Thanks for pointing that out. Will change.
diff mbox series

Patch

diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh
index 83b279a846..acaee9cbb6 100644
--- a/t/lib-parallel-checkout.sh
+++ b/t/lib-parallel-checkout.sh
@@ -25,7 +25,11 @@  test_checkout_workers () {
 
 	local trace_file=trace-test-checkout-workers &&
 	rm -f "$trace_file" &&
-	GIT_TRACE2="$(pwd)/$trace_file" "$@" 2>&8 &&
+	(
+		GIT_TRACE2="$(pwd)/$trace_file" &&
+		export GIT_TRACE2 &&
+		"$@" 2>&8
+	) &&
 
 	local workers="$(grep "child_start\[..*\] git checkout--worker" "$trace_file" | wc -l)" &&
 	test $workers -eq $expected_workers &&
diff --git a/t/t2080-parallel-checkout-basics.sh b/t/t2080-parallel-checkout-basics.sh
index 3e0f8c675f..6fd7e4c4b2 100755
--- a/t/t2080-parallel-checkout-basics.sh
+++ b/t/t2080-parallel-checkout-basics.sh
@@ -226,4 +226,54 @@  test_expect_success SYMLINKS 'parallel checkout checks for symlinks in leading d
 	)
 '
 
+# This test is here (and not in e.g. t2022-checkout-paths.sh), because we
+# check the final report including sequential, parallel, and delayed entries
+# all at the same time. So we must have finer control of the parallel checkout
+# variables.
+test_expect_failure PERL '"git checkout ." report should not include failed entries' '
+	write_script rot13-filter.pl "$PERL_PATH" \
+		<"$TEST_DIRECTORY"/t0021/rot13-filter.pl &&
+
+	test_config_global filter.delay.process \
+		"\"$(pwd)/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
+	test_config_global filter.delay.required true &&
+	test_config_global filter.cat.clean cat  &&
+	test_config_global filter.cat.smudge cat  &&
+	test_config_global filter.cat.required true  &&
+
+	set_checkout_config 2 0 &&
+	git init failed_entries &&
+	(
+		cd failed_entries &&
+		cat >.gitattributes <<-EOF &&
+		*delay*              filter=delay
+		parallel-ineligible* filter=cat
+		EOF
+		echo a >missing-delay.a &&
+		echo a >parallel-ineligible.a &&
+		echo a >parallel-eligible.a &&
+		echo b >success-delay.b &&
+		echo b >parallel-ineligible.b &&
+		echo b >parallel-eligible.b &&
+		git add -A &&
+		git commit -m files &&
+
+		a_blob="$(git rev-parse :parallel-ineligible.a)" &&
+		dir="$(echo "$a_blob" | cut -c 1-2)" &&
+		file="$(echo "$a_blob" | cut -c 3-)" &&
+		rm ".git/objects/$dir/$file" &&
+		rm *.a *.b &&
+
+		test_checkout_workers 2 test_must_fail git checkout . 2>err &&
+
+		# All *.b entries should succeed and all *.a entries should fail:
+		#  - missing-delay.a: the delay filter will drop this path
+		#  - parallel-*.a: the blob will be missing
+		#
+		grep "Updated 3 paths from the index" err &&
+		test "$(ls *.b | wc -l)" -eq 3 &&
+		test "$(ls *.a | wc -l)" -eq 0
+	)
+'
+
 test_done