Skip to content

Commit 452320f

Browse files
peffgitster
authored andcommitted
test-lib: add --verbose-log option
The "--verbose" option redirects output from arbitrary test commands to stdout. This is useful for examining the output manually, like: ./t5547-push-quarantine.sh -v | less But it also means that the output is intermingled with the TAP directives, which can confuse a TAP parser like "prove". This has always been a potential problem, but became an issue recently when one test happened to output the word "ok" on a line by itself, which prove interprets as a test success: $ prove t5547-push-quarantine.sh :: -v t5547-push-quarantine.sh .. 1/? To dest.git * [new branch] HEAD -> master To dest.git ! [remote rejected] reject -> reject (pre-receive hook declined) error: failed to push some refs to 'dest.git' fatal: git cat-file d08c8eba97f4e683ece08654c7c8d2ba0c03b129: bad file t5547-push-quarantine.sh .. Failed -1/4 subtests Test Summary Report ------------------- t5547-push-quarantine.sh (Wstat: 0 Tests: 5 Failed: 0) Parse errors: Tests out of sequence. Found (2) but expected (3) Tests out of sequence. Found (3) but expected (4) Tests out of sequence. Found (4) but expected (5) Bad plan. You planned 4 tests but ran 5. Files=1, Tests=5, 0 wallclock secs ( 0.01 usr + 0.01 sys = 0.02 CPU) Result: FAIL One answer is "if it hurts, don't do it", but that's not quite the whole story. The Travis tests use "--verbose --tee" so that they can get the benefit of prove's parallel options, along with a verbose log in case there is a failure. We just need the verbose output to go to the log, but keep stdout clean. Getting this right turns out to be surprisingly difficult. Here's the progression of alternatives I considered: 1. Add an option to write verbose output to stderr. This is hard to capture, though, because we want each test to have its own log (because they're all run in parallel and the jumbled output would be useless). 2. Add an option to write verbose output to a file in test-results. This works, but the log is missing all of the non-verbose output, which gives context. 3. Like (2), but teach say_color() to additionally output to the log. This mostly works, but misses any output that happens outside of the say() functions (which isn't a lot, but is a potential maintenance headache). 4. Like (2), but make the log file the same as the "--tee" file. That almost works, but now we have two processes opening the same file. That gives us two separate descriptors, each with their own idea of the current position. They'll each start writing at offset 0, and overwrite each other's data. 5. Like (4), but in each case open the file for appending. That atomically positions each write at the end of the file. It's possible we may still get sheared writes between the two processes, but this is already the case when writing to stdout. It's not a problem in practice because the test harness generally waits for snippets to finish before writing the TAP output. We can ignore buffering issues with tee, because POSIX mandates that it does not buffer. Likewise, POSIX specifies "tee -a", so it should be available everywhere. This patch implements option (5), which seems to work well in practice. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 925bdc9 commit 452320f

File tree

2 files changed

+25
-3
lines changed

2 files changed

+25
-3
lines changed

t/README

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ appropriately before running "make".
153153
As the names depend on the tests' file names, it is safe to
154154
run the tests with this option in parallel.
155155

156+
--verbose-log::
157+
Write verbose output to the same logfile as `--tee`, but do
158+
_not_ write it to stdout. Unlike `--tee --verbose`, this option
159+
is safe to use when stdout is being consumed by a TAP parser
160+
like `prove`. Implies `--tee` and `--verbose`.
161+
156162
--with-dashes::
157163
By default tests are run without dashed forms of
158164
commands (like git-commit) in the PATH (it only uses

t/test-lib.sh

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,21 @@ case "$GIT_TEST_TEE_STARTED, $* " in
5454
done,*)
5555
# do not redirect again
5656
;;
57-
*' --tee '*|*' --va'*)
57+
*' --tee '*|*' --va'*|*' --verbose-log '*)
5858
mkdir -p "$TEST_OUTPUT_DIRECTORY/test-results"
5959
BASE="$TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" .sh)"
60+
61+
# Make this filename available to the sub-process in case it is using
62+
# --verbose-log.
63+
GIT_TEST_TEE_OUTPUT_FILE=$BASE.out
64+
export GIT_TEST_TEE_OUTPUT_FILE
65+
66+
# Truncate before calling "tee -a" to get rid of the results
67+
# from any previous runs.
68+
>"$GIT_TEST_TEE_OUTPUT_FILE"
69+
6070
(GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1;
61-
echo $? >"$BASE.exit") | tee "$BASE.out"
71+
echo $? >"$BASE.exit") | tee -a "$GIT_TEST_TEE_OUTPUT_FILE"
6272
test "$(cat "$BASE.exit")" = 0
6373
exit
6474
;;
@@ -242,6 +252,9 @@ do
242252
trace=t
243253
verbose=t
244254
shift ;;
255+
--verbose-log)
256+
verbose_log=t
257+
shift ;;
245258
*)
246259
echo "error: unknown test option '$1'" >&2; exit 1 ;;
247260
esac
@@ -315,7 +328,10 @@ fi
315328

316329
exec 5>&1
317330
exec 6<&0
318-
if test "$verbose" = "t"
331+
if test "$verbose_log" = "t"
332+
then
333+
exec 3>>"$GIT_TEST_TEE_OUTPUT_FILE" 4>&3
334+
elif test "$verbose" = "t"
319335
then
320336
exec 4>&2 3>&1
321337
else

0 commit comments

Comments
 (0)