Files
substrate/hack/run-root-tests.sh
Steven Shriver 7c0c70c7a2 CI: create JUnit artifacts and gate on all tests passing (#1873)
This change wires the `gotestsum` seam into the actual CI and ensures
that all tests _run_ and _pass_ using a new "gate" that verifies the
JUnit artifacts they produce. Specifically, the new gate works as
follows:

1. _registers_ that a test _should_ run and produce an artifact
2. _verifies_ that the artifact was produced and _all_ tests passed
(none were skipped).

The registration phase happens when a test is run in CI and requires
that the test be provided a `E2E_JUNIT_FILE` env variable.

Partial work for #1871

- [x] Tests pass
   ```
  Run make build-junittool
  make build-junittool
  bin/junittool verify -manifest "${ARTIFACTS}/expected-junit.txt"
  shell: /usr/bin/bash -e {0}
  env:
    E2E_ATENET_DATAPLANE: agentgateway
    ARTIFACTS: /home/runner/work/substrate/substrate/_artifacts
go -C tools/junittool build -o
/home/runner/work/substrate/substrate/bin//junittool .
FILE TESTS FAILURES ERRORS SKIPPED
/home/runner/work/substrate/substrate/_artifacts/e2e-gvisor.xml 84 0 0 4
/home/runner/work/substrate/substrate/_artifacts/e2e-microvm.xml 84 0 0
5
/home/runner/work/substrate/substrate/_artifacts/e2e-mitm.xml 1 0 0 0
/home/runner/work/substrate/substrate/_artifacts/e2e-mitm-microvm.xml 1
0 0 0

/home/runner/work/substrate/substrate/_artifacts/e2e-networking-mitm.xml
11 0 0 1

/home/runner/work/substrate/substrate/_artifacts/e2e-networking-mitm-microvm.xml
11 0 0 1
  TOTAL   
  ```
- [x] Appropriate changes to documentation are included in the PR
2026-09-28 22:01:26 +00:00

85 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Runs every root-gated test package under sudo. A package is root-gated when
# its tests import internal/roottest (the tests self-skip unless run as root),
# so adding privileged tests anywhere picks them up here with no CI change.
# Extra arguments are passed through to `go test` (e.g. -v, -run).
set -o errexit -o nounset -o pipefail
ROOT="$(git rev-parse --show-toplevel)"
cd "${ROOT}"
MARKER="github.com/agent-substrate/substrate/internal/roottest"
# Look for the marker in both in-package (TestImports) and external _test
# package (XTestImports) test files.
PKGS="$(go list \
-f '{{range .TestImports}}{{if eq . "'"${MARKER}"'"}}{{println $.ImportPath}}{{end}}{{end}}{{range .XTestImports}}{{if eq . "'"${MARKER}"'"}}{{println $.ImportPath}}{{end}}{{end}}' \
./... | sort -u)"
if [[ -z "${PKGS}" ]]; then
echo "No root-gated test packages found (nothing imports ${MARKER})."
exit 0
fi
echo "Root-gated test packages:"
echo "${PKGS}"
# -count=1: the Go test cache does not key on euid, so without it a rerun as
# root replays the unprivileged run's cached skips.
# -timeout: declared here rather than inherited from go's 10m default, and
# overridable for a slow machine.
test_args=(-count=1 -timeout "${ROOT_TEST_TIMEOUT:-10m}" "$@")
# ROOT_JUNIT_FILE opts into a machine-readable record of the run. Resolve the
# binary as the invoking user: hack/run-tool.sh compiles on demand, and doing
# that under sudo would leave root-owned entries in the user's build cache.
# The runner is only ever a prefix — the privilege dispatch below is unchanged,
# because a root-gated package run without root self-skips and reports success.
# CI requires a JUnit file; see hack/run-e2e.sh for the same precondition.
if [[ -z "${ROOT_JUNIT_FILE:-}" && "${CI:-}" == "true" ]]; then
echo "run-root-tests.sh: ROOT_JUNIT_FILE must be set when CI=true." >&2
echo " Set it to a path unique to this run, e.g." >&2
echo " ROOT_JUNIT_FILE=\"\${ARTIFACTS}/root.xml\"" >&2
echo " CI verifies each run reported at least one test; a run that writes" >&2
echo " no JUnit file cannot be verified." >&2
exit 1
fi
if [[ -n "${ROOT_JUNIT_FILE:-}" ]]; then
mkdir -p "$(dirname "${ROOT_JUNIT_FILE}")"
# Claim the path before running. Runs as the invoking user, before the sudo
# dispatch below, so the manifest is not left root-owned.
go -C "${ROOT}/tools/junittool" run . register "${ROOT_JUNIT_FILE}"
runner=("$("${ROOT}/hack/run-tool.sh" --print-bin-path gotestsum)"
--junitfile "${ROOT_JUNIT_FILE}"
--jsonfile "${ROOT_JUNIT_FILE%.xml}.json"
--format standard-verbose
--)
else
runner=(go test)
fi
# shellcheck disable=SC2086 # intentional word splitting of the package list
if [[ "$(id -u)" -eq 0 ]]; then
exec "${runner[@]}" "${test_args[@]}" ${PKGS}
fi
# -E / env PATH: keep the invoking user's Go toolchain and module caches.
# shellcheck disable=SC2086
exec sudo -E env "PATH=${PATH}" "${runner[@]}" "${test_args[@]}" ${PKGS}