Files
cozystack/hack/build-matrix_test.bats
Aleksei Sviridkin cd448fdc04 test(bats): widen the comments describing the errexit exemption
Six suites explain why they avoid `! cmd` by saying errexit is
suppressed for a "negated pipeline". The exemption is not about
pipelines: a bare `! true`, a negated `[ ... ]`, one inside a `for`
body or a brace group, one in a case branch, and one following `;`,
`&`, `&&` or `||` are all exempt too. Anyone reading the narrower
wording could conclude the other shapes are safe.

One of the six carries the sentence twice, and the second copy is
split across two physical lines -- `` `!` `` ending one and
`pipeline)` opening the next -- so a line-oriented search for the
phrase does not see it. Prose wraps; a grep for it has to fold the
lines first.

Comment text only; every one of these files already uses the working
form the comment recommends.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-10-02 15:09:20 +03:00

212 lines
7.5 KiB
Bash

#!/usr/bin/env bats
# Unit tests for hack/build-matrix.sh — the CI build-matrix selector.
#
# Run via hack/cozytest.sh from the repo root (make bats-unit-tests); the
# relative `hack/build-matrix.sh` calls below resolve against that cwd. A bats
# setup() hook would be dead here — cozytest never invokes it — so the
# repo-root cwd is supplied by the runner rather than a setup() cd.
#
# Test-level EXIT traps replace Bats' own handler and hide failing TAP results.
# Cleanup follows aborting assertions; see docs/agents/e2e-testing.md.
@test "no argument emits the full matrix" {
out=$(hack/build-matrix.sh)
# The parallel units; assert known members are present.
echo "$out" | grep -q '"packages/core/platform"'
echo "$out" | grep -q '"packages/apps/mariadb"'
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
}
@test "talos and installer are excluded from the parallel matrix" {
out=$(hack/build-matrix.sh)
# `! cmd` would be vacuous: cozytest.sh runs each @test under `set -e`,
# which is suppressed for any command whose status is inverted with `!`, so
# a regression that wrongly included these paths would not fail the test.
# Assert via `if cmd; then ...`.
if echo "$out" | grep -q '"packages/core/talos"'; then echo "FAIL: packages/core/talos must be excluded from the parallel matrix"; false; fi
if echo "$out" | grep -q '"packages/core/installer"'; then echo "FAIL: packages/core/installer must be excluded from the parallel matrix"; false; fi
}
@test "the arm64 matrix drops the amd64-only e2e sandbox and nothing else" {
full=$(hack/build-matrix.sh)
arm=$(MATRIX_ARCH=arm64 hack/build-matrix.sh)
echo "$full" | grep -q '"packages/core/testing"'
if echo "$arm" | grep -q '"packages/core/testing"'; then echo "FAIL: the arm64 matrix builds the amd64-only sandbox"; false; fi
[ "$(echo "$full" | sed 's/,*"packages\/core\/testing"//')" = "$arm" ]
# A diff that touches only the sandbox gives the arm64 leg nothing to build.
tmp=$(mktemp)
echo "packages/core/testing/Makefile" > "$tmp"
[ "$(MATRIX_ARCH=arm64 hack/build-matrix.sh "$tmp")" = "[]" ]
rm -f "$tmp"
}
@test "talos-only diff selects nothing (handled by the dedicated leg)" {
tmp=$(mktemp)
echo "packages/core/talos/images/matchbox/Dockerfile" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '[]' ]
rm -f "$tmp"
}
@test "installer-only diff selects nothing (handled by finalize)" {
tmp=$(mktemp)
echo "packages/core/installer/images/cozystack-operator/Dockerfile" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '[]' ]
rm -f "$tmp"
}
@test "FULL sentinel emits the full matrix" {
out=$(hack/build-matrix.sh FULL)
echo "$out" | grep -q '"packages/system/dashboard"'
}
@test "single-package diff selects only that unit" {
tmp=$(mktemp)
echo "packages/apps/mariadb/values.yaml" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '["packages/apps/mariadb"]' ]
rm -f "$tmp"
}
@test "kubeovn source patch selects the kubeovn image build" {
tmp=$(mktemp)
echo "packages/system/kubeovn/images/kubeovn/patches/fix-vmim-scheduling-retry.diff" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '["packages/system/kubeovn"]' ]
rm -f "$tmp"
}
@test "two-package diff selects both units" {
tmp=$(mktemp)
printf 'packages/apps/mariadb/values.yaml\npackages/system/dashboard/values.yaml\n' > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
echo "$out" | grep -q '"packages/apps/mariadb"'
echo "$out" | grep -q '"packages/system/dashboard"'
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -eq 2 ]
rm -f "$tmp"
}
@test "docs-only diff selects nothing" {
tmp=$(mktemp)
echo "docs/agents/overview.md" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '[]' ]
rm -f "$tmp"
}
@test "a package with no image target selects nothing" {
tmp=$(mktemp)
# postgres ships no in-repo image build, so it is not a build unit.
echo "packages/apps/postgres/values.yaml" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '[]' ]
rm -f "$tmp"
}
@test "seaweedfs change fans out to objectstorage-controller" {
tmp=$(mktemp)
echo "packages/system/seaweedfs/values.yaml" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '["packages/system/objectstorage-controller"]' ]
rm -f "$tmp"
}
@test "seaweedfs change does not duplicate an already-selected objectstorage-controller" {
tmp=$(mktemp)
printf 'packages/system/seaweedfs/values.yaml\npackages/system/objectstorage-controller/values.yaml\n' > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$out" = '["packages/system/objectstorage-controller"]' ]
rm -f "$tmp"
}
@test "cozy-lib change forces the full matrix" {
tmp=$(mktemp)
echo "packages/library/cozy-lib/templates/_helpers.tpl" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
echo "$out" | grep -q '"packages/core/platform"'
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
rm -f "$tmp"
}
@test "common-envs.mk change forces the full matrix" {
tmp=$(mktemp)
echo "hack/common-envs.mk" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
rm -f "$tmp"
}
@test "go.mod change forces the full matrix" {
tmp=$(mktemp)
echo "go.mod" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
rm -f "$tmp"
}
@test "build workflow change forces the full matrix" {
tmp=$(mktemp)
echo ".github/workflows/pull-requests.yaml" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
rm -f "$tmp"
}
@test "root Go source change (api/) forces the full matrix" {
tmp=$(mktemp)
echo "api/apps/v1alpha1/kubernetes/types.go" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
rm -f "$tmp"
}
@test "root Go source change (pkg/) forces the full matrix" {
tmp=$(mktemp)
echo "pkg/cluster/reconciler.go" > "$tmp"
out=$(hack/build-matrix.sh "$tmp")
[ "$(echo "$out" | tr ',' '\n' | wc -l)" -gt 20 ]
rm -f "$tmp"
}
@test "emitted JSON is parseable and matches make build's unit list" {
out=$(hack/build-matrix.sh)
# Valid JSON array.
echo "$out" | jq -e 'type == "array"' >/dev/null
# Every emitted dir exists and has a Makefile.
for d in $(echo "$out" | jq -r '.[]'); do
[ -f "$d/Makefile" ]
done
# Count matches the `make -C packages/... image` lines in Makefile, minus the
# two units handled outside the parallel matrix (talos, installer).
expected=$(sed -n '/^build:/,/^[^[:space:]]/p' Makefile \
| grep -oE 'make -C packages/[A-Za-z0-9._/-]+ image' \
| sed -E 's/^make -C (packages[^ ]+) image$/\1/' \
| grep -vxcE 'packages/core/(talos|installer)')
actual=$(echo "$out" | jq 'length')
[ "$expected" -eq "$actual" ]
}
@test "every package that builds an image is in the build list" {
# The build list is maintained by hand, and a package missing from it is
# rebuilt by no CI path: its Dockerfile and patches keep changing while the
# pinned image stays whatever was last pushed by hand. Derive the set from
# the package Makefiles so a new image target cannot be forgotten.
listed=$(sed -n '/^build:/,/^[^[:space:]]/p' Makefile \
| grep -oE 'make -C packages/[A-Za-z0-9._/-]+ image' \
| sed -E 's/^make -C (packages[^ ]+) image$/\1/')
missing=""
checked=0
for m in packages/*/*/Makefile; do
grep -q 'docker buildx build' "$m" || continue
checked=$((checked + 1))
d=${m%/Makefile}
printf '%s\n' "$listed" | grep -qx "$d" || missing="$missing $d"
done
[ "$checked" -gt 0 ]
if [ -n "$missing" ]; then
echo "image-building packages missing from the root Makefile build: list:$missing" >&2
false
fi
}