LibreChat/helm/librechat/tests/configmap_render_test.sh

131 lines
4.5 KiB
Bash
Executable file

#!/usr/bin/env bash
# Regression test for the librechat ConfigMap template.
#
# Background: at one point templates/configmap.yaml ran
# `.Values.librechat.configYamlContent | toYaml | indent 4`. Because the
# value is already a YAML literal string, toYaml re-wrapped it in another `|`
# block scalar, producing a mounted /app/librechat.yaml whose first line was
# a bare `|`. js-yaml "recovered" by returning the body as a string, so
# LibreChat silently fell back to internal defaults for every config block
# (endpoints, interface, modelSpecs, ...).
#
# This test renders the ConfigMap with a sample configYamlContent and asserts
# that the rendered librechat.yaml is a proper YAML object preserving nested
# keys.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CHART_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
VALUES_FILE="$(mktemp -t librechat-configmap-values.XXXXXX)"
RENDERED_FILE="$(mktemp -t librechat-configmap-render.XXXXXX)"
trap 'rm -f "${VALUES_FILE}" "${RENDERED_FILE}"' EXIT
cat > "${VALUES_FILE}" <<'YAML'
librechat:
configYamlContent: |
version: 1.3.11
endpoints:
agents:
disableBuilder: false
YAML
if ! command -v helm >/dev/null 2>&1; then
echo "FAIL: helm not on PATH" >&2
exit 1
fi
# Render only the chart's templates so dependent sub-charts don't need network access.
helm template librechat "${CHART_DIR}" \
--show-only templates/configmap.yaml \
-f "${VALUES_FILE}" > "${RENDERED_FILE}"
# Pull the block scalar body that lives under `librechat.yaml: |`.
# awk: enter the block on the header line, then emit subsequent lines while
# they are indented (the body) and stop at the next unindented line.
BODY="$(awk '
/^ librechat\.yaml: \|/ { in_block = 1; next }
in_block {
if ($0 ~ /^ /) { sub(/^ /, ""); print; next }
if ($0 ~ /^$/) { print; next }
exit
}
' "${RENDERED_FILE}")"
if [[ -z "${BODY}" ]]; then
echo "FAIL: could not extract librechat.yaml body from rendered ConfigMap" >&2
cat "${RENDERED_FILE}" >&2
exit 1
fi
FIRST_LINE="$(printf '%s\n' "${BODY}" | awk 'NF { print; exit }')"
if [[ "${FIRST_LINE}" == "|" ]]; then
echo "FAIL: rendered librechat.yaml starts with a bare '|' — configYamlContent is double-wrapped" >&2
echo "----- rendered body -----" >&2
printf '%s\n' "${BODY}" >&2
exit 1
fi
if ! printf '%s\n' "${BODY}" | grep -qE '^version: 1\.3\.11$'; then
echo "FAIL: expected top-level 'version: 1.3.11' in rendered librechat.yaml" >&2
printf '%s\n' "${BODY}" >&2
exit 1
fi
if ! printf '%s\n' "${BODY}" | grep -qE '^endpoints:$'; then
echo "FAIL: expected top-level 'endpoints:' key in rendered librechat.yaml" >&2
printf '%s\n' "${BODY}" >&2
exit 1
fi
if ! printf '%s\n' "${BODY}" | grep -qE '^ agents:$'; then
echo "FAIL: expected nested 'endpoints.agents' key in rendered librechat.yaml" >&2
printf '%s\n' "${BODY}" >&2
exit 1
fi
# If a YAML parser is available, do a real parse to confirm the body loads as
# an object (not a string) and that endpoints.agents survives the round trip.
PARSER=""
if command -v python3 >/dev/null 2>&1 && python3 -c 'import yaml' >/dev/null 2>&1; then
PARSER="python3"
elif command -v node >/dev/null 2>&1 && node -e 'require("js-yaml")' >/dev/null 2>&1; then
PARSER="node"
fi
case "${PARSER}" in
python3)
BODY="${BODY}" python3 - <<'PY'
import os, sys, yaml
body = os.environ["BODY"]
doc = yaml.safe_load(body)
if not isinstance(doc, dict):
sys.stderr.write(f"FAIL: parsed librechat.yaml is {type(doc).__name__}, expected dict\n")
sys.exit(1)
agents = (doc.get("endpoints") or {}).get("agents")
if not isinstance(agents, dict) or "disableBuilder" not in agents:
sys.stderr.write(f"FAIL: endpoints.agents missing or malformed after parse: {agents!r}\n")
sys.exit(1)
PY
;;
node)
BODY="${BODY}" node -e '
const yaml = require("js-yaml");
const doc = yaml.load(process.env.BODY);
if (doc === null || typeof doc !== "object" || Array.isArray(doc)) {
console.error("FAIL: parsed librechat.yaml is " + typeof doc + ", expected object");
process.exit(1);
}
const agents = doc.endpoints && doc.endpoints.agents;
if (!agents || typeof agents.disableBuilder === "undefined") {
console.error("FAIL: endpoints.agents missing after parse: " + JSON.stringify(agents));
process.exit(1);
}
'
;;
*)
echo "NOTE: skipping YAML-parser assertion (install python3+pyyaml or node+js-yaml to enable)"
;;
esac
echo "PASS: rendered librechat.yaml is a proper YAML document with nested keys preserved"