git » chasquid » commit 3c3c32e

test: Don't run "go build" each time a helper is invoked

author Alberto Bertogli
2024-03-09 13:03:24 UTC
committer Alberto Bertogli
2024-03-12 20:43:21 UTC
parent 76a72367aefa08d80ae107f34167ed03d749a5f8

test: Don't run "go build" each time a helper is invoked

Our tests invoke a variety of helpers, some of them are written in Go.
Today, we call "go build" (directly or indirectly via "go run"), which is
a bit wasteful and slows down the tests.

This patch makes the tests only build our Go helpers once every 10s at
most.

The solution is a bit hacky but in the context of these tests, it's
practical.

test/cover.sh +6 -2
test/t-04-aliases/chasquid-util.sh +1 -1
test/t-04-aliases/run.sh +2 -0
test/util/lib.sh +37 -13

diff --git a/test/cover.sh b/test/cover.sh
index 891ff15..f552b85 100755
--- a/test/cover.sh
+++ b/test/cover.sh
@@ -44,8 +44,12 @@ GOCOVERDIR="${COVER_DIR}/sh" setsid -w ./cmd/chasquid-util/test.sh
 go tool covdata merge -i "${COVER_DIR}/go,${COVER_DIR}/sh" -o "${COVER_DIR}/all"
 go tool covdata textfmt -i "${COVER_DIR}/all" -o "${COVER_DIR}/merged.out"
 
-# Ignore protocol buffer-generated files, as they are not relevant.
-grep -v ".pb.go:" < "${COVER_DIR}/merged.out" > "${COVER_DIR}/final.out"
+# Ignore protocol buffer-generated files and test utilities, as they are not
+# relevant.
+cat "${COVER_DIR}/merged.out" \
+	| grep -v ".pb.go:" \
+	| grep -v "blitiri.com.ar/go/chasquid/test/util/" \
+	> "${COVER_DIR}/final.out"
 
 # Generate reports based on the merged output.
 go tool cover -func="$COVER_DIR/final.out" | sort -k 3 -n > "$COVER_DIR/func.txt"
diff --git a/test/t-04-aliases/chasquid-util.sh b/test/t-04-aliases/chasquid-util.sh
index 5d3360e..c5e5c01 100755
--- a/test/t-04-aliases/chasquid-util.sh
+++ b/test/t-04-aliases/chasquid-util.sh
@@ -3,4 +3,4 @@
 
 # Run from the config directory because data_dir is relative.
 cd config || exit 1
-go run ../../../cmd/chasquid-util/ -C=. "$@"
+../../../cmd/chasquid-util/chasquid-util -C=. "$@"
diff --git a/test/t-04-aliases/run.sh b/test/t-04-aliases/run.sh
index 1244e15..100fed9 100755
--- a/test/t-04-aliases/run.sh
+++ b/test/t-04-aliases/run.sh
@@ -74,6 +74,8 @@ fi
 
 # Test chasquid-util's ability to do alias resolution talking to chasquid.
 # We use chamuyero for convenience, so we can match the output exactly.
+# We run it once to ensure it gets built.
+chasquid-util --help > /dev/null
 for i in *.cmy; do
 	if ! chamuyero "$i" > "$i.log" 2>&1 ; then
 		echo "$i failed, log follows"
diff --git a/test/util/lib.sh b/test/util/lib.sh
index 8762f52..3cdba0a 100644
--- a/test/util/lib.sh
+++ b/test/util/lib.sh
@@ -15,6 +15,9 @@ function init() {
 	if [ "${RACE}" == "1" ]; then
 		GOFLAGS="$GOFLAGS -race"
 	fi
+	if [ "${GOCOVERDIR}" != "" ]; then
+		GOFLAGS="$GOFLAGS -cover -covermode=count"
+	fi
 
 	# Remove the directory where test-mda will deliver mail, so previous
 	# runs don't interfere with this one.
@@ -27,12 +30,7 @@ function init() {
 }
 
 function chasquid() {
-	if [ "${GOCOVERDIR}" != "" ]; then
-		GOFLAGS="-cover -covermode=count -o chasquid $GOFLAGS"
-	fi
-
-	# shellcheck disable=SC2086
-	( cd "${TBASE}/../../" || exit 1; go build $GOFLAGS -tags="$GOTAGS" . )
+	go-build-cached "${TBASE}/../../"
 
 	# HOSTALIASES: so we "fake" hostnames.
 	# PATH: so chasquid can call test-mda without path issues.
@@ -43,12 +41,37 @@ function chasquid() {
 		"${TBASE}/../../chasquid" "$@"
 }
 
+function go-build-cached() { (
+	# This runs "go build" on the given directory, but only once every
+	# 10s, or if the build flags/tags change.
+	# Because in tests we run some of the Go programs often, this speeds
+	# up the tests.
+	cd "$1" || exit 1
+	touch -d "10 seconds ago" .reference
+	echo "-tags=$GOTAGS : $GOFLAGS" > .flags-new
+	if
+		! cmp -s .flags-new .flags >/dev/null 2>&1 ||
+		[ "$(basename "$PWD")" -ot ".reference" ] ;
+	then
+		# shellcheck disable=SC2086
+		go build -tags="$GOTAGS" $GOFLAGS
+
+		# Write to .flags instead of renaming, to prevent races where
+		# was .flags-new is already renamed by the time we get here.
+		# Do this _after_ the build so worst case we build twice,
+		# instead of having the chance to run an old binary.
+		echo "-tags=$GOTAGS : $GOFLAGS" > .flags
+	fi
+) }
+
+
 function chasquid-util() {
 	# Run chasquid-util from inside the config dir, since in our tests
 	# data_dir is relative to the config.
+	go-build-cached "${TBASE}/../../cmd/chasquid-util/"
 	CONFDIR="${CONFDIR:-config}"
 	( cd "$CONFDIR" && \
-	  go run "${TBASE}/../../cmd/chasquid-util/" \
+	  "${TBASE}/../../cmd/chasquid-util/chasquid-util" \
 		-C=. \
 		"$@" \
 	)
@@ -80,7 +103,8 @@ function add_user() {
 }
 
 function dovecot-auth-cli() {
-	go run "${TBASE}/../../cmd/dovecot-auth-cli/dovecot-auth-cli.go" "$@"
+	go-build-cached "${TBASE}/../../cmd/dovecot-auth-cli/"
+	"${TBASE}/../../cmd/dovecot-auth-cli/dovecot-auth-cli" "$@"
 }
 
 function run_msmtp() {
@@ -109,28 +133,28 @@ function chamuyero() {
 }
 
 function generate_cert() {
-	( cd "${UTILDIR}/generate_cert/" || exit 1; go build )
+	go-build-cached "${UTILDIR}/generate_cert/"
 	"${UTILDIR}/generate_cert/generate_cert" "$@"
 }
 
 function loadgen() {
-	( cd "${UTILDIR}/loadgen/" || exit 1; go build )
+	go-build-cached "${UTILDIR}/loadgen/"
 	"${UTILDIR}/loadgen/loadgen" "$@"
 }
 
 function conngen() {
-	( cd "${UTILDIR}/conngen/" || exit 1; go build )
+	go-build-cached "${UTILDIR}/conngen/"
 	"${UTILDIR}/conngen/conngen" "$@"
 }
 
 function minidns_bg() {
-	( cd "${UTILDIR}/minidns" || exit 1; go build )
+	go-build-cached "${UTILDIR}/minidns/"
 	"${UTILDIR}/minidns/minidns" "$@" &
 	export MINIDNS=$!
 }
 
 function fexp() {
-	( cd "${UTILDIR}/fexp/" || exit 1; go build )
+	go-build-cached "${UTILDIR}/fexp/"
 	"${UTILDIR}/fexp/fexp" "$@"
 }