mesh/merge-gate out of date: judged against trunk 91763dd70ee4, the trunk is now 2db8ef5079f5; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk 91763dd70ee4, the trunk is now 2db8ef5079f5; judged again on a recheck or when it is merged
mesh/delivery delivered
132 lines
6.2 KiB
Bash
132 lines
6.2 KiB
Bash
#!/bin/sh
|
|
# mesh-check-toolchain: go
|
|
#
|
|
# The Go part of the SDK's own check (novox/hq ADR 0237 as amended, ADR 0272): the Go binding, run by the build
|
|
# seat in the mesh's Go toolchain, its own container, because the SDK's merge-check.sh declares it
|
|
# (`# mesh-check-also: go go/merge-check.sh`) — and by hand, from anywhere: `sh go/merge-check.sh`.
|
|
#
|
|
# Formatted, vetted (with and without the build tag `integration`), and run at two levels (novox/hq ADR 0391):
|
|
#
|
|
# 1. the unit level: `go test ./...` untagged, no bus or other process, timed and held to a bound
|
|
# (unit_bound below); over it the check fails and names the slowest tests (issue 895);
|
|
# 2. the integration level: the whole suite with `-tags integration`, each test against a bus of its
|
|
# own (internal/testbus, which issue 1171 brings with the first test that needs a bus) so nothing is
|
|
# serialised. With no tagged test yet, the level runs the unit tests again and says their count.
|
|
#
|
|
# **A test that starts a bus or another process carries `//go:build integration`** as the first line of
|
|
# its file; a file that held both kinds is two files (`<name>_integration_test.go` beside `<name>_test.go`).
|
|
# Each level says its test count and its time.
|
|
#
|
|
# No dependency is committed (no vendor directory: .gitignore; the operator, 2026-10-19; issue 1304). Every dependency
|
|
# is resolved by the version and checksum go.sum names (novox/hq ADR 0405 §5), from its public source: this binding
|
|
# requires nothing of the mesh's own forge. `go mod verify` fails by module name when a downloaded dependency does not
|
|
# match go.sum, and -mod=readonly fails a build whose go.sum lacks an entry instead of writing it. gofmt reads only
|
|
# the binding's own files.
|
|
#
|
|
# Exit 0 is a pass; anything else fails `mesh/repo-check` with the last line printed.
|
|
set -eu
|
|
cd "$(dirname "$0")"
|
|
# The toolchain the check runs in sets -mod=vendor; there is no vendor directory, so it is replaced.
|
|
GOFLAGS="$(printf '%s' "${GOFLAGS:-}" | sed 's/-mod=[a-z]*//g') -mod=readonly"
|
|
export GOFLAGS
|
|
export GOPRIVATE=git.novox.be
|
|
|
|
# **The unit level's bound, in seconds** (issue 895): the slowest package's own test time of the untagged run,
|
|
# the compile not counted. A run over it fails the check and names the slowest tests. The SDK's unit suite is
|
|
# small (its slowest package measured well under a second on a quiet machine), so 2 s leaves room for a busier
|
|
# build node without hiding a test that should carry `integration` instead.
|
|
unit_bound=2
|
|
|
|
# judge_unit_run says the unit level as `go test -v` reported it and fails when it was over the bound: $1 the
|
|
# file holding the output of the untagged `go test -v` of every package (packages one after another, each
|
|
# ending in its `ok <package> <time>` line), $2 the bound in seconds. Packages run side by side, so the
|
|
# level's time is that of its slowest package; the five slowest tests of the run are named when it is over,
|
|
# so that the bound is kept by making them cheap or by tagging them `integration`, and never by raising it
|
|
# (issue 895).
|
|
judge_unit_run() {
|
|
out=$1 bound=$2
|
|
awk '
|
|
/^--- (PASS|FAIL|SKIP): / {
|
|
name = $3; took = $4; gsub(/[()s]/, "", took)
|
|
pending[++n] = took "\t" name
|
|
if ($2 == "SKIP:") skipped++
|
|
next
|
|
}
|
|
/^(ok|FAIL)[ \t]/ && NF >= 3 && $3 ~ /^[0-9.]+s$/ {
|
|
t = $3; sub(/s$/, "", t)
|
|
for (i = 1; i <= n; i++) print "T\t" pending[i] "\t" $2
|
|
n = 0
|
|
print "P\t" t "\t" $2
|
|
}
|
|
END { print "S\t" skipped + 0 }
|
|
' "$out" >"$out.judged"
|
|
tests=$(grep -c '^T' "$out.judged" || true)
|
|
skipped=$(awk -F'\t' '$1 == "S" {print $2}' "$out.judged")
|
|
level=$(awk -F'\t' '$1 == "P" && $2 + 0 > m {m = $2 + 0} END {printf "%.2f", m}' "$out.judged")
|
|
echo "unit level: $tests tests ($skipped skipped), $level s (bound $bound s)"
|
|
if awk -v t="$level" -v b="$bound" 'BEGIN {exit !(t + 0 > b + 0)}'; then
|
|
echo "the unit level took $level s, over its bound of $bound s; the slowest tests:"
|
|
awk -F'\t' '$1 == "T" {print $2 "\t" $4 "\t" $3}' "$out.judged" | sort -t"$(printf '\t')" -k1,1 -nr | head -n 5 |
|
|
awk -F'\t' '{printf " %s s %s %s\n", $1, $3, $2}'
|
|
echo "make them cheap (no wait, no process), or give their files //go:build integration if they start a bus or another process"
|
|
return 1
|
|
fi
|
|
}
|
|
# `sh go/merge-check.sh judge-unit-run <output> <bound>` runs only the judging of the unit level, on a
|
|
# recorded output.
|
|
if [ "${1:-}" = judge-unit-run ]; then
|
|
shift
|
|
judge_unit_run "$@"
|
|
exit
|
|
fi
|
|
|
|
if ! fetched=$(go mod download 2>&1); then
|
|
echo "FAILED: the dependencies cannot be fetched: $(printf '%s\n' "$fetched" | tail -n 1)"
|
|
exit 1
|
|
fi
|
|
if ! verified=$(go mod verify 2>&1); then
|
|
echo "FAILED: a dependency does not match go.sum: $verified"
|
|
exit 1
|
|
fi
|
|
|
|
unformatted=$(find . -name '*.go' -not -path './vendor/*' | xargs gofmt -l)
|
|
if [ -n "$unformatted" ]; then
|
|
echo "not gofmt'd:"
|
|
echo "$unformatted"
|
|
exit 1
|
|
fi
|
|
go vet ./...
|
|
# The files tagged `integration` are vetted too, or nothing would read them.
|
|
go vet -tags integration ./...
|
|
|
|
# NOT RACE-CHECKED here: the SDK's suite is small and carries no store or other shared state between
|
|
# packages, so the race detector is not required of this check (novox/hq issue 1175); a module that needs
|
|
# it asks for it in its own merge-check.sh.
|
|
echo "NOT RACE-CHECKED: the Go binding's check runs without the race detector"
|
|
|
|
work=$(mktemp -d)
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
# The unit level first and alone: every package untagged, no bus or other process (judged above).
|
|
status=0
|
|
go test -count=1 -v ./... >"$work/unit.out" 2>&1 || status=$?
|
|
if [ "$status" -ne 0 ]; then
|
|
grep -vE '^(=== |[[:space:]]*--- PASS)' "$work/unit.out"
|
|
echo "the unit level failed (go test exited $status)"
|
|
exit 1
|
|
fi
|
|
judge_unit_run "$work/unit.out" "$unit_bound"
|
|
|
|
# The integration level: the whole suite with the tag, each test against its own bus (internal/testbus).
|
|
integration_start=$(date +%s)
|
|
status=0
|
|
go test -tags integration -count=1 -v ./... >"$work/integration.out" 2>&1 || status=$?
|
|
grep -vE '^(=== |[[:space:]]*--- PASS)' "$work/integration.out" || true
|
|
tests=$(grep -cE '^--- (PASS|FAIL|SKIP): ' "$work/integration.out" || true)
|
|
skipped=$(grep -cE '^--- SKIP: ' "$work/integration.out" || true)
|
|
echo "integration level: $tests tests ($skipped skipped), $(($(date +%s) - integration_start)) s"
|
|
if [ "$status" -ne 0 ]; then
|
|
echo "the integration level failed (go test exited $status)"
|
|
exit 1
|
|
fi
|