1616# tests are run might not match exactly that used when the upstream tests are
1717# run through the autotools.
1818
19+ # Exit codes: 0 if all tests passed, 1 if at least one test failed, and 2 if
20+ # the test suite could not be run at all (e.g. the upstream repository couldn't
21+ # be fetched). Callers must treat 2 as an infrastructure error: no meaningful
22+ # result was produced.
23+
1924# By default it expects a release build of the diffutils binary, but a
2025# different build profile can be specified as an argument
2126# (e.g. 'dev' or 'test').
2631scriptpath=$( dirname " $( readlink -f " $0 " ) " )
2732rev=$( git rev-parse HEAD)
2833
34+ # Report an infrastructure error: the test suite could not be run at all
35+ die () {
36+ echo " ERROR: $* " >&2
37+ exit 2
38+ }
39+
2940# Allow passing a specific profile as parameter (default to "release")
3041profile=" release"
3142[[ -n $1 ]] && profile=" $1 "
@@ -34,35 +45,47 @@ profile="release"
3445binary=" $scriptpath /../target/$profile /diffutils"
3546if [[ ! -x " $binary " ]]
3647then
37- echo " Missing build for profile $profile "
38- exit 1
48+ die " Missing build for profile $profile "
3949fi
4050
4151# Work in a temporary directory
4252tempdir=$( mktemp -d)
43- cd " $tempdir "
53+ trap ' rm -rf "$tempdir"' EXIT
54+ cd " $tempdir " || die " Cannot enter temporary directory $tempdir "
4455
45- # Check out the upstream test suite
56+ # Check out the upstream test suite. git.savannah.gnu.org is regularly
57+ # unavailable or slow, so retry a few times before giving up.
4658gitserver=" https://git.savannah.gnu.org"
4759testsuite=" $gitserver /git/diffutils.git"
48- echo " Fetching upstream test suite from $testsuite "
49- git clone -n --depth=1 --filter=tree:0 " $testsuite " & > /dev/null
50- cd diffutils
51- git sparse-checkout set --no-cone tests & > /dev/null
52- git checkout & > /dev/null
60+ attempts=3
61+ for (( attempt = 1 ; attempt <= attempts; attempt++ ))
62+ do
63+ echo " Fetching upstream test suite from $testsuite (attempt $attempt /$attempts )"
64+ rm -rf diffutils
65+ git clone -n --depth=1 --filter=tree:0 " $testsuite " && break
66+ (( attempt < attempts )) && sleep $(( attempt * 10 ))
67+ done
68+ [[ -d diffutils ]] || die " Failed to fetch the upstream test suite from $testsuite "
69+ cd diffutils || die " Failed to fetch the upstream test suite from $testsuite "
70+ git sparse-checkout set --no-cone tests & > /dev/null || die " Cannot sparse-checkout the upstream tests"
71+ git checkout & > /dev/null || die " Cannot check out the upstream tests"
5372upstreamrev=$( git rev-parse HEAD)
73+ [[ -d tests ]] || die " The upstream checkout contains no tests directory"
5474
5575# Ensure that calling `diff` invokes the built `diffutils` binary instead of
5676# the upstream `diff` binary that is most likely installed on the system
5777mkdir src
58- cd src
78+ cd src || die " Cannot create the directory holding the diff and cmp symlinks "
5979ln -s " $binary " diff
6080ln -s " $binary " cmp
61- cd ../tests
81+ cd ../tests || die " Cannot enter the upstream tests directory "
6282
6383# Fetch tests/init.sh from the gnulib repository (needed since
6484# https://git.savannah.gnu.org/cgit/diffutils.git/commit/tests?id=1d2456f539)
65- curl -sL " $gitserver /gitweb/?p=gnulib.git;a=blob_plain;f=tests/init.sh;hb=HEAD" -o init.sh
85+ curl -sL --fail --retry 3 --retry-delay 5 --retry-all-errors \
86+ " $gitserver /gitweb/?p=gnulib.git;a=blob_plain;f=tests/init.sh;hb=HEAD" -o init.sh \
87+ || die " Failed to fetch tests/init.sh from the gnulib repository"
88+ [[ -s init.sh ]] || die " Fetched an empty tests/init.sh from the gnulib repository"
6689
6790if [[ -n " $TESTS " ]]
6891then
7396 tests=$( make -f Makefile.am printtests)
7497fi
7598total=$( echo " $tests " | wc -w)
99+ (( total > 0 )) || die " No test to run: the upstream test list is empty"
76100echo " Running $total tests"
77101export LC_ALL=C
78102export KEEP=yes
105129 # but there isn't much value added in doing so
106130 for file in *
107131 do
108- [[ -f " $file " ]] && json+=" \" $file \" :\" $( base64 -w0 < " $file " ) \" ,"
132+ # Encode the name with jq: some tests create files whose name contains
133+ # quotes or control characters, which would produce invalid JSON
134+ [[ -f " $file " ]] && json+=" $( jq -Rn --arg name " $file " ' $name' ) :\" $( base64 -w0 < " $file " ) \" ,"
109135 done
110136 json=" ${json% ,} }},"
111137 cd - > /dev/null
@@ -144,10 +170,16 @@ json="{$metadata $json}"
144170
145171# Clean up
146172cd " $scriptpath "
147- rm -rf " $tempdir "
148173
174+ # Write the results out only once they are known to be valid JSON, so that a
175+ # malformed (or truncated) file is never left behind for the caller to consume
149176resultsfile=" test-results.json"
150- echo " $json " | jq > " $resultsfile "
177+ if ! echo " $json " | jq > " $resultsfile .tmp"
178+ then
179+ rm -f " $resultsfile .tmp"
180+ die " Generated invalid JSON results"
181+ fi
182+ mv " $resultsfile .tmp" " $resultsfile "
151183echo " Results written to $scriptpath /$resultsfile "
152184
153185(( failed > 0 )) && exit 1
0 commit comments