Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,12 @@ jobs:
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y bats jq

- name: Install gomplate
run: |
sudo curl -fsSL -o /usr/local/bin/gomplate \
https://github.com/hairyhenderson/gomplate/releases/download/v4.3.3/gomplate_linux-amd64
sudo chmod +x /usr/local/bin/gomplate
gomplate --version

- name: Run unit tests
run: make test-unit
2 changes: 2 additions & 0 deletions k8s/deployment/tests/build_deployment.bats
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ _render_context() {
"capabilities": {
"cpu_millicores": 100,
"ram_memory": 128,
"cpu_millicores_limit": 200,
"ram_memory_limit": 256,
"additional_ports": [],
"scaling_type": "fixed",
"autoscaling": {
Expand Down
10 changes: 8 additions & 2 deletions k8s/diagnose/tests/scope/health_probe_endpoints.bats
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ EOF
stripped=$(strip_ansi "$output")
assert_contains "$stripped" "Readiness Probe on HTTP://8080/health:"
assert_contains "$stripped" "HTTP 404 - Health check endpoint not found"
assert_contains "$stripped" "Update probe path or implement the endpoint in application"
# Remediation guidance lives in the structured evidence (suggested_actions),
# not in stdout - the check publishes it for the AI summarizer, not operators.
actions=$(jq -r '.evidence.suggested_actions[]' "$SCRIPT_OUTPUT_FILE")
assert_contains "$actions" "Update probe path or implement health endpoint in application"
}

@test "scope/health_probe_endpoints: updates status to failed on 404" {
Expand Down Expand Up @@ -261,7 +264,10 @@ EOF
stripped=$(strip_ansi "$output")
assert_contains "$stripped" "Readiness Probe on HTTP://8080/health:"
assert_contains "$stripped" "HTTP 500 - Application error"
assert_contains "$stripped" "Check application logs and fix internal errors or dependencies"
# Remediation guidance lives in the structured evidence (suggested_actions),
# not in stdout - the check publishes it for the AI summarizer, not operators.
actions=$(jq -r '.evidence.suggested_actions[]' "$SCRIPT_OUTPUT_FILE")
assert_contains "$actions" "Check application logs for internal errors"
}

@test "scope/health_probe_endpoints: updates status to warning on 500" {
Expand Down
2 changes: 2 additions & 0 deletions k8s/scope/tests/build_context.bats
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ teardown() {
"gateway_name": "co-gateway-public",
"alb_name": "co-balancer-public",
"component": "test-namespace-test-app",
"base_domain": "cloud-domain.io",
"k8s_modifiers": {}
}'

Expand Down Expand Up @@ -213,6 +214,7 @@ teardown() {
"gateway_name": "co-gateway-private",
"alb_name": "co-balancer-private",
"component": "test-namespace-test-app",
"base_domain": "cloud-domain.io",
"k8s_modifiers": {}
}'

Expand Down
10 changes: 8 additions & 2 deletions k8s/scope/tests/wait_on_balancer.bats
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,15 @@ teardown() {
# external_dns: Success after retries
# =============================================================================
@test "wait_on_balancer: external_dns success after retries" {
local call_count=0
# The script reads kubectl output via command substitution ($(kubectl ...)),
# which runs the mock in a subshell — an in-memory counter would reset every
# call. Persist the attempt count in a file so it survives across subshells.
export CALL_COUNT_FILE="$BATS_TEST_TMPDIR/dnsendpoint_calls"
echo 0 > "$CALL_COUNT_FILE"
kubectl() {
call_count=$((call_count + 1))
local call_count
call_count=$(($(cat "$CALL_COUNT_FILE") + 1))
echo "$call_count" > "$CALL_COUNT_FILE"
case "$*" in
"get dnsendpoint k8s-my-app-my-scope-scope-123-dns -n default-namespace -o jsonpath={.status.observedGeneration}")
if [ "$call_count" -ge 2 ]; then
Expand Down
5 changes: 4 additions & 1 deletion k8s/utils/assume_role_lib
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ arn_for_selector() {
local json="$1" selector="$2"
[ -n "$json" ] || return 0
[ -n "$selector" ] || return 0
# jq exits non-zero (status 5) on malformed JSON; swallow it so the helper
# honors its "never crashes, returns empty" contract instead of propagating
# jq's failure as the function's return code.
printf '%s' "$json" | jq -r --arg sel "$selector" '
[ .iam_role_arns.arns[]?
| select(.selector == $sel)
| .arn ]
| first // ""' 2>/dev/null
| first // ""' 2>/dev/null || true
}

# resolve_assume_role_arn <iam_provider_json> <selector>
Expand Down
31 changes: 26 additions & 5 deletions testing/run_bats_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,24 @@ run_tests_in_dir() {
local exit_code=0
(
cd "$test_dir"
# Use script to force TTY for colored output
# Exclude integration directory - those tests are run by run_integration_tests.sh
# --print-output-on-failure: only show test output when a test fails
script -q /dev/null bats --formatter pretty --print-output-on-failure $(find . -name "*.bats" -not -path "*/integration/*" | sort)
) 2>&1 | tee "$temp_output" || exit_code=$?
# Force a TTY so the bats "pretty" formatter renders; --print-output-on-failure
# only dumps test output when a test fails. Exclude integration tests (run
# separately). `script`'s command syntax differs by platform: BSD/macOS takes a
# positional command (script <file> <cmd...>), while util-linux (Linux CI) needs
# -c "<cmd>" <file>. Using the wrong one silently runs zero tests.
local test_files
test_files=$(find . -name "*.bats" -not -path "*/integration/*" | sort | tr '\n' ' ')
local bats_cmd="bats --formatter pretty --print-output-on-failure $test_files"
# The pretty formatter shells out to `tput`, which needs $TERM. CI runners and
# containers often leave it unset - default it so tput can find a terminfo entry.
export TERM="${TERM:-xterm}"
if [ "$(uname)" = "Darwin" ]; then
script -q /dev/null $bats_cmd
else
script -qec "$bats_cmd" /dev/null
fi
) 2>&1 | tee "$temp_output"
exit_code=${PIPESTATUS[0]}

# Extract failed tests from output
# Strip all ANSI escape codes (colors, cursor movements, etc.)
Expand Down Expand Up @@ -191,4 +204,12 @@ if [ ${#FAILED_TESTS[@]} -gt 0 ]; then
exit 1
fi

# A non-zero runner exit with no parsed "✗" lines means bats itself failed to run
# (e.g. a malformed .bats file or a broken `script` invocation) - never report success.
if [ "$HAS_FAILURES" -ne 0 ]; then
echo -e "${RED}BATS runner exited with errors but no individual test failures were parsed.${NC}"
echo -e "${RED}This usually means the test harness failed to execute - check the output above.${NC}"
exit 1
fi

echo -e "${GREEN}All BATS tests passed!${NC}"
Loading