Files
cozystack/hack/build-matrix_test.bats
T
Alexey Artamonov 1913104bd3 build(seaweedfs): build SeaweedFS in-tree with a bounded read-ahead
The S3 gateway is OOM-killed while serving a large object. SeaweedFS
starts read-ahead downloads after every read of a sequential stream and
counts only the downloads it newly starts toward its prefetch window,
so a GET reading 256 KiB at a time out of 4 MiB chunks pulls up to
about a gigabyte of the object into memory, past the 512Mi limit of
the S3 deployment. No SeaweedFS release carries a fix yet, so there is
no release to move to instead.

Build weed from the 4.45 sources with a patch that keeps the window at
the next prefetchCount chunks, and lay it over the upstream image of
the same tag so the rest of the image stays upstream's own. The image
build runs the tests of the packages the patch touches, including the
regression test the patch adds, because go build never compiles them.

Assisted-by: LLM
Signed-off-by: Alexey Artamonov <aleksei.artamonov@aenix.io>
2026-10-13 16:22:43 +03:00

214 lines
7.6 KiB
Bash

#!/usr/bin/env bats
# Unit tests for hack/build-matrix.sh — the CI build-matrix selector.
#
# Run from the repo root through `make bats-unit-tests`; the relative
# `hack/build-matrix.sh` calls below resolve against that cwd. The file also
# remains compatible with the legacy `hack/cozytest.sh` translator, which does
# not invoke setup(), so neither runner depends on 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.
load test_helper
@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/seaweedfs","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/seaweedfs","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
}