From 96f77baacd333ce32995aa3e5fecd951634a75bc Mon Sep 17 00:00:00 2001 From: Pim van pelt Date: Wed, 22 Apr 2026 09:56:53 +0200 Subject: [PATCH] Make robot-test reuse artifacts and iterate quickly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pull the .deb + ASan-nginx rebuild out of `make robot-test` — a full dpkg-buildpackage + nginx recompile before every test run was turning a 15-second test loop into a multi-minute one, which hurts when iterating on a flaky suite. robot-test now fails fast with an actionable message if either artifact is missing: Bootstrap once: make pkg-deb build-asan Then iterate: make robot-test # reuses both install-deps grew to cover what a truly minimal Debian box needs — `build-essential`, `ca-certificates`, and an explicit check that `deb-src` is enabled (required by `apt source nginx`, which both fetch-nginx-src and build-asan rely on). `nginx-dev` transitively brings in the nginx build-deps (libpcre2-dev, libssl-dev, libxslt1-dev, libgeoip-dev, libperl-dev, libexpat-dev, libgd-dev, zlib1g-dev, debhelper-compat, po-debconf) so those stay off the explicit list. debian/rules' override_dh_clean now pre-clears build/nginx-asan/{fastcgi,proxy,scgi,uwsgi,client_body}_temp before running dh_clean. Those dirs get chowned to "nobody" when the 02-asan robot suite bind-mounts build/nginx-asan/ RW into its container and nginx master startup creates them — subsequent pkg-deb runs were dying with EACCES from dh_clean's find traversal. rm -rf only needs write access to the parent (which we have), so this is safe. Co-Authored-By: Claude Opus 4.7 (1M context) --- Makefile | 47 +++++++++++++++++++++++++++++++++++++++++++---- debian/rules | 23 +++++++++++++++++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 8848eb3..abffbac 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,12 @@ # # Targets: # build - build ngx_http_ipng_stats_module.so out-of-tree. +# build-asan - build an ASan/UBSan-instrumented full nginx + module. # pkg-deb - build a .deb via dpkg-buildpackage for the current release. -# robot-test - build .deb, then run Robot Framework end-to-end tests -# in containerlab (requires docker + containerlab). +# robot-test - run Robot Framework end-to-end tests in containerlab. +# Reuses build/ artifacts — run `make pkg-deb build-asan` +# once beforehand, then iterate on `make robot-test`. +# Requires docker + containerlab. # install-deps - install build and test dependencies via apt. # clean - remove build artifacts and the fetched nginx source tree. # help - print this help. @@ -39,6 +42,7 @@ help: @echo " into build/nginx-asan/ for local crash-hunting." @echo " make pkg-deb Build a Debian package via dpkg-buildpackage." @echo " make robot-test Run Robot Framework e2e tests (all suites)." + @echo " Reuses artifacts; bootstrap with 'make pkg-deb build-asan' first." @echo " make install-deps Install build and test dependencies (apt)." @echo " make clean Remove build artifacts." @echo "" @@ -224,19 +228,54 @@ tests/.venv: tests/requirements.txt python3 -m venv tests/.venv tests/.venv/bin/pip install -q -r tests/requirements.txt +# robot-test intentionally does NOT rebuild the .deb or the ASan +# nginx. A full rebuild every `make robot-test` makes the iterate- +# on-test loop painfully slow. Instead we fail fast with an +# actionable message if either artifact is missing. +# +# Bootstrap once: make pkg-deb build-asan +# Then iterate: make robot-test # reuses both artifacts robot-test: tests/.venv + @if ! ls $(BUILD_DIR)/libnginx-mod-http-ipng-stats_*.deb >/dev/null 2>&1; then \ + echo "error: no module .deb in $(BUILD_DIR)/ — run 'make pkg-deb' first" >&2; \ + exit 1; \ + fi + @if [ ! -x $(BUILD_DIR)/nginx-asan/sbin/nginx ]; then \ + echo "error: no ASan nginx in $(BUILD_DIR)/nginx-asan/ — run 'make build-asan' first" >&2; \ + exit 1; \ + fi tests/rf-run.sh docker $(TEST) # ---------------------------------------------------------------------- # install-deps: install build and test dependencies # ---------------------------------------------------------------------- +# install-deps covers everything needed for `make build`, `make build-asan`, +# `make pkg-deb`, and `make robot-test` (apart from docker + containerlab, +# which have their own installers). `nginx-dev` transitively pulls the +# nginx build-deps (libpcre2-dev, libssl-dev, libxslt1-dev, libgeoip-dev, +# libperl-dev, libexpat-dev, libgd-dev, zlib1g-dev, debhelper-compat, +# po-debconf) so we don't need to list them here — keep this list to the +# things nginx-dev does NOT already bring in. +# +# `apt source nginx` (used by fetch-nginx-src and build-asan) requires a +# deb-src line in /etc/apt/sources.list — verified separately below. install-deps: sudo apt-get update -qq sudo apt-get install -y \ - nginx-dev dpkg-dev debhelper \ + build-essential \ + nginx-dev \ + dpkg-dev debhelper \ python3 python3-venv \ - curl + curl ca-certificates + @echo "" + @echo "Checking that deb-src is enabled (needed by 'apt source nginx')..." + @if ! grep -qE '^[[:space:]]*deb-src' /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources 2>/dev/null; then \ + echo "warning: no 'deb-src' lines found in apt sources." >&2; \ + echo " Enable them (e.g. uncomment in /etc/apt/sources.list) and rerun:" >&2; \ + echo " sudo apt-get update" >&2; \ + exit 1; \ + fi @echo "" @echo "Build dependencies installed. For 'make robot-test' you also need:" @echo " - docker: https://docs.docker.com/engine/install/debian/" diff --git a/debian/rules b/debian/rules index 88f221e..5ce79bc 100755 --- a/debian/rules +++ b/debian/rules @@ -39,8 +39,23 @@ override_dh_auto_clean: override_dh_clean: # `dh_clean` recurses from the package root to remove junk files - # (editor backups, autom4te caches, etc.). `make build-asan` - # produces build/nginx-asan/{fastcgi,proxy,scgi,uwsgi}_temp owned - # by "nobody" with mode 0700, which the current user can't - # traverse — so we exclude anything under build/ from dh_clean. + # (editor backups, autom4te caches, etc.). Two obstacles under + # build/: + # 1. `make build-asan` produces build/nginx-asan/{fastcgi,proxy, + # scgi,uwsgi,client_body}_temp owned by "nobody" with mode + # 0700 after the ASan nginx has been run (the 02-asan robot + # suite bind-mounts build/nginx-asan/ RW into a container, + # and nginx chowns its temp dirs on master startup). The + # current user can't traverse them, which makes dh_clean's + # `find` abort with EACCES. + # 2. We don't want to delete anything under build/ anyway — it + # holds the ASan build artifacts from a prior `make build-asan`. + # Clear the unreadable temp dirs first (rm -rf only needs write + # access to the parent, which we have), then tell dh_clean to + # exclude build/ entirely. + rm -rf $(CURDIR)/build/nginx-asan/client_body_temp \ + $(CURDIR)/build/nginx-asan/fastcgi_temp \ + $(CURDIR)/build/nginx-asan/proxy_temp \ + $(CURDIR)/build/nginx-asan/scgi_temp \ + $(CURDIR)/build/nginx-asan/uwsgi_temp dh_clean -X build/