Files
haproxy/deploy/test/integration-test.sh
Scaffolder ea619ba456
All checks were successful
Build and Publish TechDocs (Helm Chart Resource) / build-and-publish-helm-chart (push) Successful in 1m12s
initial commit
Change-Id: If67c32e979b6d03a135072c836ca54ee01c99e66
2026-04-15 16:23:13 +00:00

785 lines
25 KiB
Bash
Executable File

#!/bin/bash
#
# Integration test: deploy Helm chart(s) to a real Kubernetes cluster.
#
# By default, creates a Kind cluster named "dev-helm-charts", runs the tests,
# and deletes the cluster when done. Set KIND_KEEP_CLUSTER=1 to keep it.
#
# Prerequisites:
# - kind (https://kind.sigs.k8s.io/)
# - kubectl
# - Helm v3.x
#
# Usage:
# ./test/integration-test.sh # test all charts
# ./test/integration-test.sh haproxy-unified-gateway # test only HUG
# ./test/integration-test.sh kubernetes-ingress # test only ingress
#
# Options (env vars):
# TIMEOUT=120 Max seconds to wait for pods (default: 120)
# KEEP_NS=1 Don't delete test namespaces on success (for debugging)
# CI_FILTER=<glob> Only test ci/ files matching pattern (e.g. "deployment-*")
# TEST_FILTER=<name> Run only a specific test (defaults, daemonset, hpa, pdb, monitoring, ci)
# KIND_KEEP_CLUSTER=1 Don't delete the Kind cluster after tests
# KIND_CLUSTER_NAME=name Custom cluster name (default: dev-helm-charts)
# SKIP_KIND=1 Skip Kind cluster creation (use existing kubeconfig)
#
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
TIMEOUT="${TIMEOUT:-120}"
KEEP_NS="${KEEP_NS:-0}"
CI_FILTER="${CI_FILTER:-}"
KIND_KEEP_CLUSTER="${KIND_KEEP_CLUSTER:-0}"
KIND_CLUSTER_NAME="${KIND_CLUSTER_NAME:-dev-helm-charts}"
SKIP_KIND="${SKIP_KIND:-0}"
TEST_FILTER="${TEST_FILTER:-}"
PASSED=0
FAILED=0
SKIPPED=0
FAILURES=()
NAMESPACES=()
KIND_CREATED=false
KEDA_CRDS_INSTALLED=false
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BOLD='\033[1m'
NC='\033[0m'
log_pass() { echo -e " ${GREEN}PASS${NC} $1"; PASSED=$((PASSED + 1)); }
log_fail() { echo -e " ${RED}FAIL${NC} $1"; FAILED=$((FAILED + 1)); FAILURES+=("$1"); }
log_skip() { echo -e " ${YELLOW}SKIP${NC} $1"; SKIPPED=$((SKIPPED + 1)); }
log_section() { echo -e "\n${BOLD}=== $1 ===${NC}"; }
log_info() { echo -e " ${YELLOW}INFO${NC} $1"; }
# --- Kind cluster management ---
create_kind_cluster() {
if [ "$SKIP_KIND" = "1" ]; then
echo -e "${YELLOW}SKIP_KIND=1, using existing kubeconfig${NC}"
return
fi
if ! command -v kind &>/dev/null; then
echo -e "${RED}ERROR:${NC} 'kind' not found in PATH" >&2
echo "Install it: https://kind.sigs.k8s.io/docs/user/quick-start/#installation" >&2
exit 1
fi
# Check if cluster already exists
if kind get clusters 2>/dev/null | grep -q "^${KIND_CLUSTER_NAME}$"; then
echo -e "Kind cluster ${BOLD}${KIND_CLUSTER_NAME}${NC} already exists, reusing it"
kubectl cluster-info --context "kind-${KIND_CLUSTER_NAME}" &>/dev/null || {
echo -e "${RED}ERROR:${NC} cluster exists but is not reachable" >&2
exit 1
}
export KUBECONFIG
KUBECONFIG=$(kind get kubeconfig-path --name="${KIND_CLUSTER_NAME}" 2>/dev/null || echo "")
kubectl config use-context "kind-${KIND_CLUSTER_NAME}" &>/dev/null || true
return
fi
echo -e "Creating Kind cluster ${BOLD}${KIND_CLUSTER_NAME}${NC}..."
kind create cluster \
--name "${KIND_CLUSTER_NAME}" \
--wait 120s
KIND_CREATED=true
echo -e "${GREEN}Kind cluster created${NC}"
}
delete_kind_cluster() {
if [ "$SKIP_KIND" = "1" ]; then
return
fi
if [ "$KIND_KEEP_CLUSTER" = "1" ]; then
echo -e "\n${YELLOW}KIND_KEEP_CLUSTER=1, keeping cluster '${KIND_CLUSTER_NAME}'${NC}"
echo -e " To use: kubectl --context kind-${KIND_CLUSTER_NAME} ..."
echo -e " Delete: kind delete cluster --name ${KIND_CLUSTER_NAME}"
return
fi
if $KIND_CREATED || kind get clusters 2>/dev/null | grep -q "^${KIND_CLUSTER_NAME}$"; then
echo -e "\nDeleting Kind cluster ${BOLD}${KIND_CLUSTER_NAME}${NC}..."
kind delete cluster --name "${KIND_CLUSTER_NAME}"
echo -e "${GREEN}Kind cluster deleted${NC}"
fi
}
# --- helpers ---
check_prerequisites() {
local ok=true
for cmd in kubectl helm; do
if ! command -v "$cmd" &>/dev/null; then
echo -e "${RED}ERROR:${NC} '$cmd' not found in PATH" >&2
ok=false
fi
done
if ! kubectl cluster-info &>/dev/null; then
echo -e "${RED}ERROR:${NC} cannot connect to Kubernetes cluster" >&2
ok=false
fi
if ! $ok; then
exit 1
fi
}
find_charts() {
local filter="${1:-}"
local charts=()
for dir in "$REPO_ROOT"/*/; do
[ -f "$dir/Chart.yaml" ] || continue
local name
name="$(basename "$dir")"
if [ -n "$filter" ] && [ "$name" != "$filter" ]; then
continue
fi
charts+=("$name")
done
if [ ${#charts[@]} -eq 0 ]; then
echo "No charts found${filter:+ matching '$filter'}." >&2
exit 1
fi
echo "${charts[@]}"
}
# Generate a unique namespace for a test run
make_ns() {
local chart="$1"
local suffix="$2"
# namespace max 63 chars; keep it short
local ns="it-${chart}-${suffix}-$(date +%s)"
ns="${ns:0:63}"
echo "$ns"
}
create_ns() {
local ns="$1"
kubectl create namespace "$ns" --dry-run=client -o yaml | kubectl apply -f - >/dev/null
NAMESPACES+=("$ns")
}
delete_ns() {
local ns="$1"
if [ "$KEEP_NS" = "1" ]; then
log_info "KEEP_NS=1, not deleting namespace $ns"
return
fi
kubectl delete namespace "$ns" --wait=false --ignore-not-found >/dev/null 2>&1 || true
}
# Wait for all pods in a namespace to be Ready (or Completed for Jobs)
wait_for_pods() {
local ns="$1"
local deadline=$((SECONDS + TIMEOUT))
while [ $SECONDS -lt $deadline ]; do
local not_ready=0
local pod_lines
pod_lines=$(kubectl get pods -n "$ns" --no-headers 2>/dev/null || true)
if [ -z "$pod_lines" ]; then
# No pods yet, keep waiting
sleep 2
continue
fi
while IFS= read -r line; do
local status
status=$(echo "$line" | awk '{print $3}')
case "$status" in
Running|Completed|Succeeded)
# Check if Running pods have all containers ready
if [ "$status" = "Running" ]; then
local ready_col
ready_col=$(echo "$line" | awk '{print $2}')
local ready_count="${ready_col%/*}"
local total_count="${ready_col#*/}"
if [ "$ready_count" != "$total_count" ]; then
not_ready=$((not_ready + 1))
fi
fi
;;
Error|CrashLoopBackOff|ImagePullBackOff|ErrImagePull|CreateContainerConfigError|InvalidImageName)
# Terminal failure
return 1
;;
*)
not_ready=$((not_ready + 1))
;;
esac
done <<< "$pod_lines"
if [ "$not_ready" -eq 0 ]; then
return 0
fi
sleep 3
done
return 1 # timeout
}
# Collect debug info on failure
dump_debug() {
local ns="$1"
echo -e " ${YELLOW}--- debug info (ns: $ns) ---${NC}"
echo " Pods:"
kubectl get pods -n "$ns" -o wide 2>/dev/null | sed 's/^/ /'
echo " Events (last 10):"
kubectl get events -n "$ns" --sort-by='.lastTimestamp' 2>/dev/null | tail -10 | sed 's/^/ /'
# Show logs from non-ready pods
local pods
pods=$(kubectl get pods -n "$ns" --no-headers 2>/dev/null | awk '$3 !~ /Running|Completed|Succeeded/ {print $1}')
if [ -z "$pods" ]; then
# Also grab CrashLoopBackOff pods that show as "Running"
pods=$(kubectl get pods -n "$ns" --no-headers 2>/dev/null | awk '{split($2,a,"/"); if (a[1]!=a[2]) print $1}')
fi
for pod in $pods; do
echo " Logs ($pod):"
kubectl logs -n "$ns" "$pod" --all-containers --tail=20 2>/dev/null | sed 's/^/ /' || true
done
echo -e " ${YELLOW}--- end debug ---${NC}"
}
# --- test functions ---
# Return chart-specific helm args needed for test installs.
# Some charts need overrides to install cleanly on a fresh cluster.
chart_test_args() {
local chart="$1"
case "$chart" in
haproxy-unified-gateway)
# No special overrides needed: the HugConf CR is a post-install hook
# (weight 5) that runs after the CRD job (weight 0), avoiding the
# chicken-and-egg validation problem.
;;
esac
}
# Install chart with given values, wait for pods, verify resources, then clean up.
install_and_verify() {
local chart="$1"
local label="$2"
local ns="$3"
shift 3
# Remaining args are passed to helm install
local helm_args=("$@")
# Add chart-specific test overrides
local extra_args
extra_args=$(chart_test_args "$chart")
if [ -n "$extra_args" ]; then
# shellcheck disable=SC2206
helm_args+=($extra_args)
fi
create_ns "$ns"
# Install
if ! helm install "test-${chart}" "$REPO_ROOT/$chart" \
--namespace "$ns" \
--wait --timeout "${TIMEOUT}s" \
"${helm_args[@]}" 2>&1 | sed 's/^/ /'; then
log_fail "$label (helm install failed)"
dump_debug "$ns"
delete_ns "$ns"
return
fi
# Wait for pods to be ready (belt-and-suspenders on top of --wait)
if ! wait_for_pods "$ns"; then
log_fail "$label (pods not ready within ${TIMEOUT}s)"
dump_debug "$ns"
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
return
fi
# Basic resource verification
local ok=true
# Check that we have at least one Running or Completed pod
local running
running=$(kubectl get pods -n "$ns" --no-headers 2>/dev/null | grep -cE 'Running|Completed|Succeeded' || true)
if [ "$running" -eq 0 ]; then
echo -e " ${RED}No running pods found${NC}"
ok=false
fi
# Verify ServiceAccount exists
if kubectl get serviceaccount -n "$ns" -l "app.kubernetes.io/instance=test-${chart}" --no-headers 2>/dev/null | grep -q .; then
: # ok
else
# Some charts may not label SA; check by name
if ! kubectl get serviceaccount -n "$ns" 2>/dev/null | grep -q "test-${chart}\|${chart}"; then
echo -e " ${YELLOW}ServiceAccount not found (may be expected)${NC}"
fi
fi
# Verify Service exists (if applicable)
local svc_count
svc_count=$(kubectl get svc -n "$ns" --no-headers 2>/dev/null | wc -l)
if [ "$svc_count" -gt 0 ]; then
: # ok
fi
if $ok; then
log_pass "$label"
else
log_fail "$label"
dump_debug "$ns"
fi
# Cleanup
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
}
# Test: default values install
test_install_defaults() {
local chart="$1"
local label="$chart: install (defaults)"
local ns
ns=$(make_ns "$chart" "defaults")
install_and_verify "$chart" "$label" "$ns"
}
# Install KEDA CRDs if not already installed.
# Required for ci/ values files that enable KEDA ScaledObject.
ensure_keda_crds() {
if $KEDA_CRDS_INSTALLED; then
return 0
fi
local keda_crd_url="https://github.com/kedacore/keda/releases/download/v2.16.1/keda-2.16.1-crds.yaml"
if kubectl apply --server-side -f "$keda_crd_url" >/dev/null 2>&1; then
KEDA_CRDS_INSTALLED=true
log_info "Installed KEDA CRDs (ScaledObject, ScaledJob, TriggerAuthentication)"
return 0
else
return 1
fi
}
# Test: install with each ci/ values file
test_install_ci_values() {
local chart="$1"
local ci_dir="$REPO_ROOT/$chart/ci"
if [ ! -d "$ci_dir" ]; then
log_skip "$chart: no ci/ directory"
return
fi
local count=0
for values_file in "$ci_dir"/*.yaml "$ci_dir"/*.yml; do
[ -f "$values_file" ] || continue
local fname
fname="$(basename "$values_file")"
# Apply CI_FILTER if set
if [ -n "$CI_FILTER" ]; then
# shellcheck disable=SC2254
case "$fname" in
$CI_FILTER) ;;
*) continue ;;
esac
fi
count=$((count + 1))
# Install KEDA CRDs if this values file enables KEDA
if [[ "$fname" == *keda* ]]; then
if ! ensure_keda_crds; then
log_skip "$chart: install ci/$fname - could not install KEDA CRDs"
continue
fi
fi
local label="$chart: install ci/$fname"
local suffix="${fname%.yaml}"
suffix="${suffix%.yml}"
suffix="${suffix%-values}"
local ns
ns=$(make_ns "$chart" "$suffix")
install_and_verify "$chart" "$label" "$ns" -f "$values_file"
done
if [ "$count" -eq 0 ]; then
log_skip "$chart: ci/ directory is empty${CI_FILTER:+ (or no match for '$CI_FILTER')}"
fi
}
# Test: Deployment vs DaemonSet mode (if chart supports it)
test_install_daemonset() {
local chart="$1"
local values_yaml="$REPO_ROOT/$chart/values.yaml"
if ! grep -q 'kind: Deployment' "$values_yaml" 2>/dev/null; then
return
fi
if [ ! -f "$REPO_ROOT/$chart/templates/controller-daemonset.yaml" ]; then
return
fi
local label="$chart: install (DaemonSet mode)"
local ns
ns=$(make_ns "$chart" "daemonset")
install_and_verify "$chart" "$label" "$ns" --set controller.kind=DaemonSet
}
# Test: verify HPA creates when enabled (if chart supports it)
test_install_hpa() {
local chart="$1"
local values_yaml="$REPO_ROOT/$chart/values.yaml"
if ! grep -q 'autoscaling:' "$values_yaml" 2>/dev/null; then
return
fi
local label="$chart: install (HPA enabled)"
local ns
ns=$(make_ns "$chart" "hpa")
install_and_verify "$chart" "$label" "$ns" \
--set controller.autoscaling.enabled=true \
--set controller.autoscaling.minReplicas=1 \
--set controller.autoscaling.maxReplicas=3 \
--set controller.autoscaling.targetCPUUtilizationPercentage=80
}
# Test: verify PDB creates when enabled (if chart supports it)
test_install_pdb() {
local chart="$1"
local values_yaml="$REPO_ROOT/$chart/values.yaml"
if ! grep -q 'podDisruptionBudget:' "$values_yaml" 2>/dev/null; then
return
fi
local label="$chart: install (PDB enabled)"
local ns
ns=$(make_ns "$chart" "pdb")
install_and_verify "$chart" "$label" "$ns" \
--set controller.replicaCount=2 \
--set controller.podDisruptionBudget.enabled=true \
--set controller.podDisruptionBudget.minAvailable=1
}
# Test: verify metrics port is exposed and metricsAuth flag is passed
test_install_metrics_port() {
local chart="$1"
local values_yaml="$REPO_ROOT/$chart/values.yaml"
if ! grep -q 'metricsAuth:' "$values_yaml" 2>/dev/null; then
return
fi
local label="$chart: install (metrics port exposed)"
local ns
ns=$(make_ns "$chart" "metrics")
create_ns "$ns"
local extra_args
extra_args=$(chart_test_args "$chart")
# shellcheck disable=SC2086
if ! helm install "test-${chart}" "$REPO_ROOT/$chart" \
--namespace "$ns" \
--wait --timeout "${TIMEOUT}s" \
$extra_args 2>&1 | sed 's/^/ /'; then
log_fail "$label (helm install failed)"
dump_debug "$ns"
delete_ns "$ns"
return
fi
if ! wait_for_pods "$ns"; then
log_fail "$label (pods not ready within ${TIMEOUT}s)"
dump_debug "$ns"
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
return
fi
# Verify the controller pod has the metrics container port (31060)
local ports_label="$chart: controller pod has metrics port 31060"
if kubectl get pods -n "$ns" -o jsonpath='{.items[*].spec.containers[*].ports[*].containerPort}' 2>/dev/null | tr ' ' '\n' | grep -q '31060'; then
log_pass "$ports_label"
else
log_fail "$ports_label"
fi
# Verify --metrics-auth=kube-rbac is in the container args
local args_label="$chart: controller pod has --metrics-auth=kube-rbac arg"
if kubectl get pods -n "$ns" -o jsonpath='{.items[*].spec.containers[*].args[*]}' 2>/dev/null | grep -q 'metrics-auth=kube-rbac'; then
log_pass "$args_label"
else
log_fail "$args_label"
fi
# Verify the main Service has the stat port (it should NOT have metrics — that's only on the metrics Service)
local svc_label="$chart: main Service has stat port"
if kubectl get svc -n "$ns" "test-${chart}" -o jsonpath='{.spec.ports[*].name}' 2>/dev/null | grep -q 'stat'; then
log_pass "$svc_label"
else
log_fail "$svc_label"
fi
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
}
# Test: verify ServiceMonitor/PodMonitor install (if chart supports it)
# Installs Prometheus Operator CRDs so the monitoring.coreos.com/v1 API is available,
# then verifies the resources are created.
test_install_monitoring() {
local chart="$1"
local values_yaml="$REPO_ROOT/$chart/values.yaml"
if ! grep -q 'serviceMonitor:' "$values_yaml" 2>/dev/null; then
return
fi
# Install Prometheus Operator CRDs so the API is available
local prom_crds_installed=false
local prom_crd_url="https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/main/jsonnet/prometheus-operator/podmonitors-crd.json"
local sm_crd_url="https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/main/jsonnet/prometheus-operator/servicemonitors-crd.json"
# Try to apply the CRDs; if curl/URLs fail, skip
if kubectl apply -f "$sm_crd_url" >/dev/null 2>&1 && \
kubectl apply -f "$prom_crd_url" >/dev/null 2>&1; then
prom_crds_installed=true
log_info "Installed Prometheus Operator CRDs (ServiceMonitor, PodMonitor)"
else
log_skip "$chart: install (ServiceMonitor) - could not install Prometheus Operator CRDs"
log_skip "$chart: install (PodMonitor) - could not install Prometheus Operator CRDs"
return
fi
# ServiceMonitor test
local label="$chart: install (ServiceMonitor enabled)"
local ns
ns=$(make_ns "$chart" "svcmon")
create_ns "$ns"
local extra_args
extra_args=$(chart_test_args "$chart")
# shellcheck disable=SC2086
if helm install "test-${chart}" "$REPO_ROOT/$chart" \
--namespace "$ns" \
--wait --timeout "${TIMEOUT}s" \
--set controller.serviceMonitor.enabled=true \
$extra_args 2>&1 | sed 's/^/ /'; then
# Verify ServiceMonitor exists
if kubectl get servicemonitor -n "$ns" --no-headers 2>/dev/null | grep -q .; then
log_pass "$label"
else
log_fail "$label (ServiceMonitor resource not found)"
fi
# Verify metrics Service exists
local metrics_label="$chart: install (metrics Service created)"
if kubectl get svc -n "$ns" --no-headers 2>/dev/null | grep -q metrics; then
log_pass "$metrics_label"
else
log_fail "$metrics_label"
fi
# Verify metrics Service exposes both stat and metrics ports
local ports_label="$chart: install (metrics Service has stat + metrics ports)"
local svc_ports
svc_ports=$(kubectl get svc -n "$ns" -l "app.kubernetes.io/instance=test-${chart}" -o jsonpath='{.items[*].spec.ports[*].name}' 2>/dev/null || true)
if echo "$svc_ports" | grep -q 'stat' && echo "$svc_ports" | grep -q 'metrics'; then
log_pass "$ports_label"
else
log_fail "$ports_label"
fi
else
log_fail "$label (helm install failed)"
dump_debug "$ns"
fi
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
# PodMonitor test
label="$chart: install (PodMonitor enabled)"
ns=$(make_ns "$chart" "podmon")
create_ns "$ns"
# shellcheck disable=SC2086
if helm install "test-${chart}" "$REPO_ROOT/$chart" \
--namespace "$ns" \
--wait --timeout "${TIMEOUT}s" \
--set controller.podMonitor.enabled=true \
$extra_args 2>&1 | sed 's/^/ /'; then
# Verify PodMonitor exists
if kubectl get podmonitor -n "$ns" --no-headers 2>/dev/null | grep -q .; then
log_pass "$label"
else
log_fail "$label (PodMonitor resource not found)"
fi
# Verify no metrics Service (PodMonitor shouldn't create one)
local no_metrics_label="$chart: install (no metrics Service with PodMonitor)"
if kubectl get svc -n "$ns" --no-headers 2>/dev/null | grep -q metrics; then
log_fail "$no_metrics_label"
else
log_pass "$no_metrics_label"
fi
else
log_fail "$label (helm install failed)"
dump_debug "$ns"
fi
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
}
# Test: verify HugConf is deleted after helm uninstall
test_hugconf_cleanup() {
local chart="$1"
local values_yaml="$REPO_ROOT/$chart/values.yaml"
if ! grep -q 'hugconf:' "$values_yaml" 2>/dev/null; then
return
fi
local label="$chart: HugConf deleted on uninstall"
local ns
ns=$(make_ns "$chart" "hugconf-cleanup")
create_ns "$ns"
local extra_args
extra_args=$(chart_test_args "$chart")
# shellcheck disable=SC2086
if ! helm install "test-${chart}" "$REPO_ROOT/$chart" \
--namespace "$ns" \
--wait --timeout "${TIMEOUT}s" \
$extra_args 2>&1 | sed 's/^/ /'; then
log_fail "$label (helm install failed)"
dump_debug "$ns"
delete_ns "$ns"
return
fi
if ! wait_for_pods "$ns"; then
log_fail "$label (pods not ready within ${TIMEOUT}s)"
dump_debug "$ns"
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
return
fi
# Verify HugConf exists before uninstall
if ! kubectl get hugconfs.gate.v3.haproxy.org -n "$ns" --no-headers 2>/dev/null | grep -q .; then
log_fail "$label (HugConf not found after install)"
helm uninstall "test-${chart}" -n "$ns" --wait 2>/dev/null || true
delete_ns "$ns"
return
fi
# Uninstall and verify HugConf is cleaned up
if ! helm uninstall "test-${chart}" -n "$ns" --wait --timeout "${TIMEOUT}s" 2>&1 | sed 's/^/ /'; then
log_fail "$label (helm uninstall failed)"
delete_ns "$ns"
return
fi
# Check that HugConf is gone
if kubectl get hugconfs.gate.v3.haproxy.org -n "$ns" --no-headers 2>/dev/null | grep -q .; then
log_fail "$label (HugConf still exists after uninstall)"
else
log_pass "$label"
fi
delete_ns "$ns"
}
# --- cleanup trap ---
cleanup() {
if [ "$KEEP_NS" = "1" ]; then
if [ ${#NAMESPACES[@]} -gt 0 ]; then
echo -e "\n${YELLOW}KEEP_NS=1, these namespaces were left:${NC}"
printf ' %s\n' "${NAMESPACES[@]}"
fi
else
# In case of early exit, clean up any remaining namespaces
for ns in "${NAMESPACES[@]}"; do
kubectl delete namespace "$ns" --wait=false --ignore-not-found >/dev/null 2>&1 || true
done
fi
delete_kind_cluster
}
trap cleanup EXIT
# --- main ---
main() {
local filter="${1:-}"
echo -e "${BOLD}Helm Chart Integration Test${NC}"
echo "Repo: $REPO_ROOT"
echo "Helm: $(helm version --short 2>/dev/null)"
echo "Timeout: ${TIMEOUT}s per install"
[ -n "$CI_FILTER" ] && echo "CI filter: $CI_FILTER"
[ -n "$TEST_FILTER" ] && echo "Test: $TEST_FILTER"
# Create or reuse Kind cluster
create_kind_cluster
check_prerequisites
echo "Cluster: $(kubectl config current-context 2>/dev/null || echo 'unknown')"
echo "K8s server: $(kubectl version 2>/dev/null | grep 'Server Version' | head -1 || true)"
local charts
read -ra charts <<< "$(find_charts "$filter")"
echo "Charts: ${charts[*]}"
for chart in "${charts[@]}"; do
log_section "$chart"
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "defaults" ]; then test_install_defaults "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "daemonset" ]; then test_install_daemonset "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "hpa" ]; then test_install_hpa "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "pdb" ]; then test_install_pdb "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "metrics-port" ]; then test_install_metrics_port "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "monitoring" ]; then test_install_monitoring "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "hugconf-cleanup" ]; then test_hugconf_cleanup "$chart"; fi
if [ -z "$TEST_FILTER" ] || [ "$TEST_FILTER" = "ci" ]; then test_install_ci_values "$chart"; fi
done
# Summary
log_section "Summary"
echo -e " ${GREEN}Passed:${NC} $PASSED"
echo -e " ${RED}Failed:${NC} $FAILED"
echo -e " ${YELLOW}Skipped:${NC} $SKIPPED"
if [ ${#FAILURES[@]} -gt 0 ]; then
echo -e "\n${RED}Failures:${NC}"
for f in "${FAILURES[@]}"; do
echo " - $f"
done
exit 1
fi
echo -e "\n${GREEN}All integration tests passed.${NC}"
}
main "$@"