I decided to take a stab at a full review of the test coverage report in
order to try and understand all of the uncovered code. The snippets I
highlight below include uncovered code that is not immediately obvious as
an acceptable block to leave uncovered. (Some snippets required looking
around at the context to know that is the case.)
In at least one case, I found a block that is actually covered in my
local testing, so something is wrong with the build environment I use
to generate this report. I'm currently investigating.
On 5/30/2019 8:52 AM, Derrick Stolee wrote:
This section appears in the following block:
/* More invalidating of results that may be affected by the choice of
* most certain line.
* Discard the matches for lines in B that are currently matched with a
* line in A such that their ordering contradicts the ordering imposed
* by the choice of most certain line.
*/
for (i = most_certain_local_line_b - 1; i >= invalidate_min; --i) {
/* In this loop we discard results for lines in B that are
* before most-certain-line-B but are matched with a line in A
* that is after most-certain-line-A.
*/
if (certainties[i] >= 0 &&
(result[i] >= most_certain_line_a ||
second_best_result[i] >= most_certain_line_a)) {
certainties[i] = CERTAINTY_NOT_CALCULATED;
}
}
for (i = most_certain_local_line_b + 1; i < invalidate_max; ++i) {
/* In this loop we discard results for lines in B that are
* after most-certain-line-B but are matched with a line in A
* that is before most-certain-line-A.
*/
if (certainties[i] >= 0 &&
(result[i] <= most_certain_line_a ||
second_best_result[i] <= most_certain_line_a)) {
certainties[i] = CERTAINTY_NOT_CALCULATED;
}
}
Note that the first for loop includes the uncovered lines. The logical operands
are backwards of the conditions in the second for loop, which are covered. This
seems non-trivial enough to merit a test.
The fact that they are uncovered means that the && chain is short-circuited at
"ent->s_lno + ent->num_lines == next->s_lno" before the new conditions can be
checked. So, the block inside is never covered. It includes a call to
blame_origin_decref() and free(), so it would be good to try and exercise this region.
This line being uncovered means that 'target' is never NULL. In the code above,
base_url is used in all cases so this is safe enough.
promisor-remote.c
7bdf0926 93) previous->next = r->next;
This isn't being hit because "previous" is always NULL in the call to
promisor_remote_move_to_tail(), which is filled by a call to
promisor_remote_lookup(). All of this code is rather difficult to read
(double pointers, for loops with two iterator variables) so it is hard
to do the mental math and guarantee that it is working.
I tried playing around with adding more promisor remotes to t0410-partial-clone.sh,
but could not get this line to hit.
dcc8b4e9 202) static int remove_fetched_oids(struct object_id **oids, int oid_nr, int to_free)
This method isn't covered at all, so I responded directly to the patch thread.
This string_list_clear() is preceded by
if (data->uri_protocols.nr && !data->writer.use_sideband)
but earlier is populated by
if (skip_prefix(arg, "packfile-uris ", &p)) {
string_list_split(&data->uri_protocols, p, ',', -1);
continue;
}
Why don't we simply not use string_list_split() if !data->writer.use_sideband?
I would apply this diff to avoid calling string_list_split at all:
This line seemed suspicious, but is preceded by
if (ctx->progress_done < ctx->approx_nr_objects)
so is pretty harmless to leave uncovered.
builtin/fast-export.c
e80001f8 81) static int parse_opt_reencode_mode(const struct option *opt,
I'm always suspicious of a method that is never called by the test suite.
The only caller is given by this portion of the patch:
+ OPT_CALLBACK(0, "reencode", &reencode_mode, N_("mode"),
+ N_("select handling of commit messages in an alternate encoding"),
+ parse_opt_reencode_mode),
But we DO have tests that cover this flag, and inserting a die() in the
method triggers it on t9350-fast-export.sh. I'll investigate what went wrong
on the build [1] to cause this. I see a lot of these in the logs:
sh: echo: I/O error
So maybe some tests did not actually run. Further, these tests failed:
t3400-rebase.sh (Wstat: 256 Tests: 28 Failed: 2)
Failed tests: 20, 28
Non-zero exit status: 1
t3420-rebase-autostash.sh (Wstat: 256 Tests: 38 Failed: 6)
Failed tests: 6, 13, 16, 23, 26, 33
Non-zero exit status: 1
t3404-rebase-interactive.sh (Wstat: 256 Tests: 110 Failed: 5)
Failed tests: 3, 9-10, 100-101
Non-zero exit status: 1
t5521-pull-options.sh (Wstat: 256 Tests: 19 Failed: 1)
Failed test: 3
Non-zero exit status: 1
t5551-http-fetch-smart.sh (Wstat: 256 Tests: 37 Failed: 1)
Failed test: 26
Non-zero exit status: 1
They don't fail locally, so perhaps we shouldn't blindly trust the coverage data
until I work out why these errors occurred. (Many of the cases I called out
above I couldn't hit locally with a die() statement.)
[1] https://dev.azure.com/git/git/_build/results?buildId=606
Further, these tests failed
t3400-rebase.sh (Wstat: 256 Tests: 28 Failed: 2)
Failed tests: 20, 28
Non-zero exit status: 1
t3420-rebase-autostash.sh (Wstat: 256 Tests: 38 Failed: 6)
Failed tests: 6, 13, 16, 23, 26, 33
Non-zero exit status: 1
t3404-rebase-interactive.sh (Wstat: 256 Tests: 110 Failed: 5)
Failed tests: 3, 9-10, 100-101
Non-zero exit status: 1
t5521-pull-options.sh (Wstat: 256 Tests: 19 Failed: 1)
Failed test: 3
Non-zero exit status: 1
t5551-http-fetch-smart.sh (Wstat: 256 Tests: 37 Failed: 1)
Failed test: 26
Non-zero exit status: 1
They don't fail locally, so perhaps we shouldn't blindly trust the coverage data
until I work out why these errors occurred. (Many of the cases I called out
above I couldn't hit locally with a die() statement.)
These tests all failed during the second run that set optional GIT_TEST
environment variables. Specifically, GIT_TEST_REBASE_USE_BUILTIN=false
caused these tests to break. We now output this message:
warning: the rebase.useBuiltin support has been removed!
See its entry in 'git help config' for details.
I'm removing that variable from the build definition.
Thanks,
-Stolee
From: Johannes Schindelin <hidden> Date: 2019-05-31 18:59:23
Hi Stolee,
On Fri, 31 May 2019, Derrick Stolee wrote:
On 5/30/2019 2:24 PM, Derrick Stolee wrote:
quoted
Further, these tests failed
t3400-rebase.sh (Wstat: 256 Tests: 28 Failed: 2)
Failed tests: 20, 28
Non-zero exit status: 1
t3420-rebase-autostash.sh (Wstat: 256 Tests: 38 Failed: 6)
Failed tests: 6, 13, 16, 23, 26, 33
Non-zero exit status: 1
t3404-rebase-interactive.sh (Wstat: 256 Tests: 110 Failed: 5)
Failed tests: 3, 9-10, 100-101
Non-zero exit status: 1
t5521-pull-options.sh (Wstat: 256 Tests: 19 Failed: 1)
Failed test: 3
Non-zero exit status: 1
t5551-http-fetch-smart.sh (Wstat: 256 Tests: 37 Failed: 1)
Failed test: 26
Non-zero exit status: 1
They don't fail locally, so perhaps we shouldn't blindly trust the coverage data
until I work out why these errors occurred. (Many of the cases I called out
above I couldn't hit locally with a die() statement.)
These tests all failed during the second run that set optional GIT_TEST
environment variables. Specifically, GIT_TEST_REBASE_USE_BUILTIN=false
caused these tests to break. We now output this message:
warning: the rebase.useBuiltin support has been removed!
See its entry in 'git help config' for details.
I'm removing that variable from the build definition.
Would it make sense to have a file in t/ (or a script-let in ci/)
specifying all of the `GIT_TEST_*` variables that are currently supported
(and that actually make sense to be set)?
I saw a similar issue recently in a now-defunct Azure Pipeline that also
tried to replicate what half of the `linux-gcc` job [*1*] does: to run the
test suite with those variables overriding the defaults. That Pipeline
broke for the exact same reason you mentioned: we now handle
`GIT_TEST_REBASE_USE_BUILTIN` by showing that warning.
And issues like this could easily be avoided if we had, say,
`ci/non-standard-settings.sh` that simply set all those `GIT_TEST_*`
variables in the way that the `linux-gcc` job does (and of course, this
job should then source that file instead of duplicating those
assignments).
What do you think?
Dscho
Footnote *1*: It is a thorn in my side ever since I started work on our
Azure Pipeline support that the `linux-gcc` job actually runs *two* jobs:
it runs the vanilla test suite, and then it runs it again after setting
all supported `GIT_TEST_*` variables to the non-default settings. This
almost doubles the running time of that job, often making it the very last
job to finish, and it also makes it unclear whether a test failure stems
from said `GIT_TEST_*` settings or not.
I got so annoyed by this, in fact, that I finally broke down and opened
https://github.com/gitgitgadget/git/issues/242.
From: Michael Platings <hidden> Date: 2019-06-01 21:22:22
Thanks very much for this Derrick. I looked into it and it turns out
that the missing coverage in blame.c for "certainties[i] =
CERTAINTY_NOT_CALCULATED" was due to earlier code overwriting the same
value in most cases, thereby defeating an optimization. I've deleted
that earlier code and now coverage is as expected. I posted the patch
here: https://public-inbox.org/git/20190601210925.15339-1-michael@platin.gs/T/#u
I also deleted the other uncovered code that appeared in the same
patch as it was unreachable.
This section appears in the following block:
/* More invalidating of results that may be affected by the choice of
* most certain line.
* Discard the matches for lines in B that are currently matched with a
* line in A such that their ordering contradicts the ordering imposed
* by the choice of most certain line.
*/
for (i = most_certain_local_line_b - 1; i >= invalidate_min; --i) {
/* In this loop we discard results for lines in B that are
* before most-certain-line-B but are matched with a line in A
* that is after most-certain-line-A.
*/
if (certainties[i] >= 0 &&
(result[i] >= most_certain_line_a ||
second_best_result[i] >= most_certain_line_a)) {
certainties[i] = CERTAINTY_NOT_CALCULATED;
}
}
for (i = most_certain_local_line_b + 1; i < invalidate_max; ++i) {
/* In this loop we discard results for lines in B that are
* after most-certain-line-B but are matched with a line in A
* that is before most-certain-line-A.
*/
if (certainties[i] >= 0 &&
(result[i] <= most_certain_line_a ||
second_best_result[i] <= most_certain_line_a)) {
certainties[i] = CERTAINTY_NOT_CALCULATED;
}
}
Note that the first for loop includes the uncovered lines. The logical operands
are backwards of the conditions in the second for loop, which are covered. This
seems non-trivial enough to merit a test.
The fact that they are uncovered means that the && chain is short-circuited at
"ent->s_lno + ent->num_lines == next->s_lno" before the new conditions can be
checked. So, the block inside is never covered. It includes a call to
blame_origin_decref() and free(), so it would be good to try and exercise this region.
What is your setup for determining if a line is uncovered? Are you
running something like gcov for all of the tests in t/?
I removed this change, and none of the other blame tests appeared to
trigger this code block either, independently of this change. (I put an
assert(0) inside the block).
However, two of our blame-ignore tests do get past the first two checks
in the if clause, (the suspects are equal and the s_lno chunks are
adjacent) and we do check the ignored/unblamable conditions.
Specifically, if I undo this change and put an assert(0) in that block,
two of our tests hit that code, and one of our tests fails if I don't do
the check for ignored/unblamable.
Thanks,
Barret
for (ent = sb->ent; ent && (next = ent->next); ent = next) {
if (ent->suspect == next->suspect &&
- ent->s_lno + ent->num_lines == next->s_lno) {
+ ent->s_lno + ent->num_lines == next->s_lno &&
+ ent->ignored == next->ignored &&
+ ent->unblamable == next->unblamable) {
ent->num_lines += next->num_lines;
ent->next = next->next;
blame_origin_decref(next->suspect);
The fact that they are uncovered means that the && chain is short-circuited at
"ent->s_lno + ent->num_lines == next->s_lno" before the new conditions can be
checked. So, the block inside is never covered. It includes a call to
blame_origin_decref() and free(), so it would be good to try and exercise this region.
What is your setup for determining if a line is uncovered? Are you running something like gcov for all of the tests in t/?
I removed this change, and none of the other blame tests appeared to trigger this code block either, independently of this change. (I put an assert(0) inside the block).
However, two of our blame-ignore tests do get past the first two checks in the if clause, (the suspects are equal and the s_lno chunks are adjacent) and we do check the ignored/unblamable conditions.
Specifically, if I undo this change and put an assert(0) in that block, two of our tests hit that code, and one of our tests fails if I don't do the check for ignored/unblamable.
The tests use gcov while running the tests in t/. Here is the build [1].
There are some i/o errors happening in the build, which I have not
full diagnosed. It is entirely possible that you actually are covered,
but there was an error collecting the coverage statistics. The simplest
thing to do is to insert a die() statement and re-run the tests.
Thanks,
-Stolee
[1] https://dev.azure.com/git/git/_build/results?buildId=615
The fact that they are uncovered means that the && chain is short-circuited at
"ent->s_lno + ent->num_lines == next->s_lno" before the new conditions can be
checked. So, the block inside is never covered. It includes a call to
blame_origin_decref() and free(), so it would be good to try and exercise this region.
What is your setup for determining if a line is uncovered? Are you running something like gcov for all of the tests in t/?
I removed this change, and none of the other blame tests appeared to trigger this code block either, independently of this change. (I put an assert(0) inside the block).
However, two of our blame-ignore tests do get past the first two checks in the if clause, (the suspects are equal and the s_lno chunks are adjacent) and we do check the ignored/unblamable conditions.
Specifically, if I undo this change and put an assert(0) in that block, two of our tests hit that code, and one of our tests fails if I don't do the check for ignored/unblamable.
The tests use gcov while running the tests in t/. Here is the build [1].
There are some i/o errors happening in the build, which I have not
full diagnosed. It is entirely possible that you actually are covered,
but there was an error collecting the coverage statistics. The simplest
thing to do is to insert a die() statement and re-run the tests.
It looks like no existing tests cover that block in blame_coalesce(),
regardless of my commit. That's based on putting die() in there and
running make in t/. So at the worst, my patch isn't decreasing
coverage. That's a pretty low bar. =)
I'll try to come up with a test, independent of my blame-ignore work,
that can get in that block.
Thanks,
Barret
I'll try to come up with a test, independent of my blame-ignore work,
that can get in that block.
I have a test that covers blame_coalesce(), which works both with and
without my blame-ignore commit that started this thread.
However, the only thing we are really testing is that git blame didn't
crash. There is no detectable change to the output. AFAIK,
blame_coalesce() is a performance enhancement.
If you all are interested in that sort of test, I can put it in a patch.
Right now, I have this (below).
Thanks,
Barret
Hi -
On 6/4/19 12:38 PM, Barret Rhoden wrote:
However, the only thing we are really testing is that git blame didn't crash.
This would not be enough.
There is no detectable change to the output. AFAIK, blame_coalesce() is a performance enhancement.
Thank you for stating that the output didn't change. I
tested this locally, and did see that the behavior was
identical.
I think you should just make the test be complete by
checking a post-condition. Please see the inserted lines
below (which _should_ work, I haven't actually ran this
in the test suite).
I think you should just make the test be complete by
checking a post-condition. Please see the inserted lines
below (which _should_ work, I haven't actually ran this
in the test suite).
With a little massaging, this did the trick. I'll roll the patch into
my blame-ignore series, to keep things simple.
Thanks,
Barret