Skip to content

Commit

Permalink
ci: Use gotestfmt to format go test output (#608)
Browse files Browse the repository at this point in the history
UDENG-4788
  • Loading branch information
adombeck authored Nov 13, 2024
2 parents d527cf1 + 3d62e18 commit 93d8d06
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 10 deletions.
50 changes: 40 additions & 10 deletions .github/workflows/qa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Install gotestfmt
run: go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest

- name: Install VHS and ttyd for integration tests
run: |
set -eu
Expand Down Expand Up @@ -198,10 +202,14 @@ jobs:
raw_cov_dir="${cov_dir}/raw"
mkdir -p "${raw_cov_dir}" "${cod_cov_dir}"
# Print executed commands to ease debugging
set -x
# Overriding the default coverage directory is not an exported flag of go test (yet), so
# we need to override it using the test.gocoverdir flag instead.
#TODO: Update when https://go-review.googlesource.com/c/go/+/456595 is merged.
go test -timeout ${GO_TESTS_TIMEOUT} -cover -covermode=set ./... -coverpkg=./... -shuffle=on -args -test.gocoverdir="${raw_cov_dir}"
go test -json -timeout ${GO_TESTS_TIMEOUT} -cover -covermode=set ./... -coverpkg=./... -shuffle=on -args -test.gocoverdir="${raw_cov_dir}" | \
./tools/gotestfmt --logfile "${AUTHD_TEST_ARTIFACTS_PATH}/gotestfmt.cover.log"
# Convert the raw coverage data into textfmt so we can merge the Rust one into it
go tool covdata textfmt -i="${raw_cov_dir}" -o="${cov_dir}/coverage.out"
Expand All @@ -220,7 +228,8 @@ jobs:
env:
GO_TESTS_TIMEOUT: 35m
run: |
go test -timeout ${GO_TESTS_TIMEOUT} -race ./...
go test -json -timeout ${GO_TESTS_TIMEOUT} -race ./... | \
./tools/gotestfmt --logfile "${AUTHD_TEST_ARTIFACTS_PATH}/gotestfmt.race.log"
- name: Run PAM tests (with Address Sanitizer)
if: matrix.test == 'asan'
Expand All @@ -233,23 +242,44 @@ jobs:
# Use these flags to give ASAN a better time to unwind the stack trace
GO_GC_FLAGS: -N -l
run: |
go test -C ./pam/internal -asan -gcflags=all="${GO_GC_FLAGS}" -timeout ${GO_TESTS_TIMEOUT} ./... || exit_code=$?
if [ "${exit_code}" -ne 0 ]; then
# Print executed commands to ease debugging
set -x
go test -C ./pam/internal -json -asan -gcflags=all="${GO_GC_FLAGS}" -timeout ${GO_TESTS_TIMEOUT} ./... | \
./tools/gotestfmt --logfile "${AUTHD_TEST_ARTIFACTS_PATH}/gotestfmt.pam-internal-asan.log" || exit_code=$?
if [ -n "${exit_code:-}" ]; then
cat "${AUTHD_TEST_ARTIFACTS_PATH}"/asan.log* || true
exit ${exit_code}
fi
echo "Running PAM integration tests"
pushd ./pam/integration-tests
go test -asan -gcflags=all="${GO_GC_FLAGS}" -c
# FIXME: Suppression may be removed with newer libpam, as the one we ship in ubuntu as some leaks
env LSAN_OPTIONS=suppressions=$(pwd)/lsan.supp \
./integration-tests.test \
-test.timeout ${GO_TESTS_TIMEOUT} \
|| exit_code=$?
LSAN_OPTIONS=suppressions=$(pwd)/lsan.supp \
go tool test2json -p pam/integrations-test ./integration-tests.test \
-test.v=test2json \
-test.timeout ${GO_TESTS_TIMEOUT} | \
../../tools/gotestfmt --logfile "${AUTHD_TEST_ARTIFACTS_PATH}/gotestfmt.pam-integration-tests-asan.log" || \
exit_code=$?
popd
# We don't need the xtrace output after this point
set +x
# We're logging to a file, and this is useful for having artifacts, but we still may want to see it in logs:
cat "${AUTHD_TEST_ARTIFACTS_PATH}"/asan.log* || true
for f in "${AUTHD_TEST_ARTIFACTS_PATH}"/asan.log*; do
if ! [ -e "${f}" ]; then
continue
fi
if [ -s "${f}" ]; then
echo "::group::${f} ($(wc -l < "${f}") lines)"
cat "${f}"
echo "::endgroup::"
else
echo "${f}: empty"
fi
done
exit ${exit_code}
Expand All @@ -260,7 +290,7 @@ jobs:
directory: ./coverage/codecov
token: ${{ secrets.CODECOV_TOKEN }}

- name: Upload test failures artifacts
- name: Upload test artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
Expand Down
63 changes: 63 additions & 0 deletions tools/gotestfmt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/bash

set -euo pipefail

# This script is a wrapper around gotestfmt. It expects the output of `go test -json`
# on stdin. The output of failed tests is written to stdout, while the full output
# (including successful tests) is written to a logfile.

usage(){
echo "Usage: $0 [--logfile <logfile>] [-h|--help]"
}

# Parse options
while [[ $# -gt 0 ]]; do
case "$1" in
--logfile)
LOGFILE="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done

LOGFILE="${LOGFILE:-$(mktemp -t gotestfmt.XXXXXX.log)}"
echo >&2 "Logging to $LOGFILE"
STDERR_FILE=${LOGFILE%.log}.stderr
STDOUT_FILE=${LOGFILE%.log}.stdout

strip_empty_coverage_lines() {
# This strips empty coverage lines from the output of `go test -cover -json`,
# which would otherwise be printed as error messages by gotestfmt.
jq -c 'select(.Output != null and (.Output | contains("coverage: 0.0%") | not))'
}

copy_to_logfile() {
# This copies the output of `go test -json` to the logfile. It also uses
# gotestfmt to format the output (but without GitHub Action workflow commands
# like `::group::` and `::endgroup::`) and removes ANSI color codes, to make
# the logfile more readable.
tee >(GITHUB_WORKFLOW='' gotestfmt -showteststatus | sed 's/\x1b\[[0-9;]*m//g' > "$LOGFILE")
}

copy_output() {
# Copy all output of `go test -json` unformatted to a file, for debugging purposes.
# This is useful if a jq format error occurs, to see the output that caused it.
tee "$STDOUT_FILE"
}

# Write stderr to a file which can be uploaded as an artifact
copy_output | strip_empty_coverage_lines | copy_to_logfile | gotestfmt --hide all <&0 2> "$STDERR_FILE" || exitcode=$?

# Print the stderr file to stderr
cat >&2 "$STDERR_FILE"

exit "${exitcode:-0}"

0 comments on commit 93d8d06

Please sign in to comment.