Files
cozystack/hack/select-e2e_test.bats
IvanHunters e0597e3d99 fix(platform): make *-rd sources depend on cozystack-engine (#3041)
## Problem

On an unlucky Flux reconcile order, a `*-application` PackageSource that
ships a `system/*-rd` component can install before the
`applicationdefinitions.cozystack.io` CRD exists. Every `*-rd` chart
renders an `ApplicationDefinition` (`cozystack.io/v1alpha1`); that CRD
is installed by the `application-definition-crd` component of
`cozystack.cozystack-engine`. When an `*-rd` HelmRelease renders first,
it hard-fails with `no matches for kind "ApplicationDefinition" in
version "cozystack.io/v1alpha1"`, and that cascades into a broad install
timeout — surfacing even on changes that have nothing to do with
ordering, because it is a latent race.

## Fix

Add `- cozystack.cozystack-engine` to the `dependsOn` of every
`*-application` source that ships a `system/*-rd` component (29
sources). `gateway-application` already carried this edge — it was added
earlier for the TenantGateway CRD, the same bug class, but only for that
one source. A new invariant test fails if any source with a
`system/*-rd` component is missing the edge.

## Why

The ordering was previously implicit, relying on Flux happening to
reconcile `cozystack-engine` before the `*-application` sources. Making
the edge explicit removes the race deterministically. No dependency
cycle is introduced: `cozystack-engine` depends only on `networking` and
`cert-manager` (plus keycloak in its oidc variant), none of which reach
back to any `*-application`.

## Test

- New generic guard `hack/check-applicationdefinition-crd-ordering.bats`
(auto-discovered by `make bats-unit-tests`, runs in CI via `make
unit-tests`): parses every source and fails if any PackageSource variant
with a `system/*-rd` component lacks the `cozystack.cozystack-engine`
edge — so future sources are covered, not just today's set.
- `helm unittest packages/core/platform`: 13 suites / 66 tests pass; the
source edits do not disturb existing assertions.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved dependency ordering across several platform packages to
ensure related components install in the correct sequence.
* Prevented end-to-end test selection from being overly broad when only
ordering-related dependencies change.

* **Tests**
* Added checks to catch missing dependency requirements and to verify
test selection behavior stays accurate.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 19:21:50 +03:00

142 lines
5.5 KiB
Bash

#!/usr/bin/env bats
# -----------------------------------------------------------------------------
# Unit tests for hack/select-e2e.sh
#
# cozytest.sh's awk parser recognizes only @test blocks and a bare `}` on its
# own line; there is no bats `run` or `$status`. Each test runs as a shell
# function under `set -eu -x`, so assertions are direct shell tests that exit
# non-zero on failure. setup()/teardown() are not honored — each test creates
# and cleans its own scratch dir.
#
# Run with: hack/cozytest.sh hack/select-e2e_test.bats
# -----------------------------------------------------------------------------
@test "single app diff selects only that bats" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "packages/apps/postgres/values.yaml" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ "$output" = "postgres" ]
}
@test "operator diff selects all dependent app bats" {
# postgres-operator is depended on by postgres-application, harbor-application
# (Harbor uses postgres as its backing DB), and monitoring-application (Grafana
# DB). monitoring isn't in hack/e2e-apps/ so it's filtered out by the selector.
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "packages/system/postgres-operator/values.yaml" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
echo "$output" | grep -wq postgres
echo "$output" | grep -wq harbor
if echo "$output" | grep -wq kafka; then
echo "operator diff must not trigger full suite; got: $output" >&2
exit 1
fi
}
@test "engine-dependency change does not fan out via the ordering edge" {
# cert-manager is a dependency of cozystack-engine, and every app declares
# dependsOn cozystack-engine purely as an INSTALL-ORDERING edge (the app's
# *-rd HelmRelease waits for the ApplicationDefinition CRD). That edge must
# not propagate test selection: a cert-manager change selects only its
# genuine direct dependents (postgres, harbor, ...), never unrelated apps
# like kafka that reach cert-manager solely through the engine.
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "packages/system/cert-manager/values.yaml" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
echo "$output" | grep -wq postgres
echo "$output" | grep -wq harbor
if echo "$output" | grep -wq kafka; then
echo "cert-manager change must not fan out via engine; got: $output" >&2
exit 1
fi
}
@test "networking change triggers full suite" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "packages/system/cilium/values.yaml" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
# Full suite means more than 5 bats files
[ "$(echo "$output" | wc -w)" -gt 5 ]
}
@test "library change triggers full suite" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "packages/library/cozy-lib/templates/_helpers.tpl" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ "$(echo "$output" | wc -w)" -gt 5 ]
}
@test "docs-only diff selects nothing" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "docs/README.md" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ -z "$output" ]
}
@test "kubernetes-application maps to two bats files" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "packages/apps/kubernetes/values.yaml" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
echo "$output" | grep -q "kubernetes-latest"
echo "$output" | grep -q "kubernetes-previous"
}
@test "dashboards-only diff selects nothing (path is plural)" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "dashboards/gpu/gpu-fleet.json" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ -z "$output" ]
}
@test "shared E2E helper script triggers full suite" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "hack/e2e-apps/run-kubernetes.sh" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ "$(echo "$output" | wc -w)" -gt 5 ]
}
@test "install bats triggers full suite" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "hack/e2e-install-cozystack.bats" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ "$(echo "$output" | wc -w)" -gt 5 ]
}
@test "per-app bats edit selects only that app, never escalates" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo "hack/e2e-apps/redis.bats" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ "$output" = "redis" ]
}
@test "pull-requests workflow change triggers full suite" {
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
cp -r packages/core/platform/sources "$tmp/sources"
echo ".github/workflows/pull-requests.yaml" > "$tmp/diff"
output=$(hack/select-e2e.sh "$tmp/diff" "$tmp/sources")
[ "$(echo "$output" | wc -w)" -gt 5 ]
}