129 lines
4.9 KiB
Bash
Executable File
129 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Job-level check that PRINTER_OPTIONS queue defaults reach the emitted job.
|
|
#
|
|
# The authority for this test is the PostScript that cupsd sends to the
|
|
# printer, not a settings file and NOT `lpoptions -p <queue> -l`: that command
|
|
# renders PPD Boolean options incorrectly (it shows `TonerSaveMode ... *False`
|
|
# even when the queue default is `True`), which is exactly the misreading this
|
|
# test guards against.
|
|
#
|
|
# Why `cupsfilter` and not "read cupsd's spool file after `lp`": with no
|
|
# reachable printer the job sticks at "The printer may not exist or is
|
|
# unavailable", the filters never run, and the spool file still holds the
|
|
# unfiltered input PDF. `cupsfilter -p /etc/cups/ppd/<queue>.ppd` produces the
|
|
# same `%%BeginFeature`/effect-line structure without needing a printer.
|
|
#
|
|
# Verified against cups-daemon 2.4.2-3+deb12u9 (Debian bookworm, the base of
|
|
# Containerfile).
|
|
set -euo pipefail
|
|
|
|
IMAGE="${IMAGE:-printserver:latest}"
|
|
QUEUE="${QUEUE:-HL4150CDN}"
|
|
CONTAINER="${CONTAINER:-printserver-queue-defaults-test}"
|
|
SAMPLE="${SAMPLE:-/usr/share/cups/data/default-testpage.pdf}"
|
|
PPD="/etc/cups/ppd/${QUEUE}.ppd"
|
|
|
|
# The documented PRINTER_OPTIONS example from the spec / README.
|
|
PRINTER_OPTIONS_VALUE="BRColorMode=Vivid TonerSaveMode=False"
|
|
|
|
pass=0
|
|
fail=0
|
|
|
|
cleanup() {
|
|
podman rm -f "${CONTAINER}" >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
check() {
|
|
# check <label> <postscript-file> <expected-line>
|
|
local label="$1" file="$2" expected="$3"
|
|
if podman exec "${CONTAINER}" grep -aqF -- "${expected}" "${file}"; then
|
|
echo "PASS: ${label}: found '${expected}'"
|
|
pass=$((pass + 1))
|
|
else
|
|
echo "FAIL: ${label}: expected '${expected}' in ${file}"
|
|
echo " actual option features:"
|
|
podman exec "${CONTAINER}" sh -c \
|
|
"grep -ao '%%BeginFeature: \\*[A-Za-z0-9]*' '${file}' | sort -u | sed 's/^/ /'" \
|
|
|| true
|
|
fail=$((fail + 1))
|
|
fi
|
|
}
|
|
|
|
echo "== building ${IMAGE} =="
|
|
podman build -t "${IMAGE}" .
|
|
|
|
echo "== starting container with PRINTER_OPTIONS=\"${PRINTER_OPTIONS_VALUE}\" =="
|
|
podman rm -f "${CONTAINER}" >/dev/null 2>&1 || true
|
|
podman run -d --name "${CONTAINER}" \
|
|
-e PRINTER_IP=192.0.2.1 \
|
|
-e "PRINTER_OPTIONS=${PRINTER_OPTIONS_VALUE}" \
|
|
"${IMAGE}" >/dev/null
|
|
|
|
ready=0
|
|
for _ in $(seq 1 90); do
|
|
if podman logs "${CONTAINER}" 2>&1 | grep -q 'ready: CUPS on 631/tcp'; then
|
|
ready=1
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
if [ "${ready}" -ne 1 ]; then
|
|
echo "FAIL: container did not reach 'ready: CUPS on 631/tcp'"
|
|
podman logs "${CONTAINER}" 2>&1 | tail -20
|
|
exit 1
|
|
fi
|
|
|
|
# `podman logs` can lag behind the container by a few seconds, and the ready
|
|
# line is printed after the option lines, so poll the log for each assignment
|
|
# instead of inspecting it once.
|
|
for opt in ${PRINTER_OPTIONS_VALUE}; do
|
|
applied=0
|
|
for _ in $(seq 1 30); do
|
|
if podman logs "${CONTAINER}" 2>&1 | grep -qF "queue default ${opt} applied"; then
|
|
applied=1
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
if [ "${applied}" -ne 1 ]; then
|
|
echo "FAIL: entrypoint did not report '${opt}' as applied"
|
|
podman logs "${CONTAINER}" 2>&1 | grep -i 'entrypoint\|warning' | tail -10
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "PASS: entrypoint applied every PRINTER_OPTIONS assignment"
|
|
|
|
echo "== queue state cross-check (config views, not the acceptance signal) =="
|
|
# TonerSaveMode is deliberately not asserted here: see the header comment.
|
|
podman exec "${CONTAINER}" lpoptions -p "${QUEUE}" -l | grep BRColorMode
|
|
podman exec "${CONTAINER}" grep -E '^\*Default(BRColorMode|TonerSaveMode)' "${PPD}"
|
|
|
|
echo "== filtering: queue defaults =="
|
|
podman exec "${CONTAINER}" sh -c \
|
|
"cupsfilter -p '${PPD}' -m application/vnd.cups-postscript '${SAMPLE}' > /tmp/qd.ps 2>/dev/null"
|
|
|
|
check "queue default BRColorMode=Vivid" /tmp/qd.ps "%%BeginFeature: *BRColorMode Vivid"
|
|
check "queue default BRColorMode=Vivid (effect)" /tmp/qd.ps "<</UseCIEColor true>>setpagedevice"
|
|
check "queue default TonerSaveMode=False" /tmp/qd.ps "%%BeginFeature: *TonerSaveMode False"
|
|
|
|
# A per-job option must win over the queue default: this is the regression guard
|
|
# that the options channel is live rather than pinned to a vendor value.
|
|
echo "== filtering: per-job override =="
|
|
podman exec "${CONTAINER}" sh -c \
|
|
"cupsfilter -p '${PPD}' -m application/vnd.cups-postscript -o BRColorMode=None '${SAMPLE}' > /tmp/override.ps 2>/dev/null"
|
|
|
|
check "per-job BRColorMode=None wins" /tmp/override.ps "%%BeginFeature: *BRColorMode None"
|
|
|
|
if podman exec "${CONTAINER}" grep -aqF -- "%%BeginFeature: *BRColorMode Vivid" /tmp/override.ps; then
|
|
echo "FAIL: per-job override: queue default Vivid leaked into the explicit None job"
|
|
fail=$((fail + 1))
|
|
else
|
|
echo "PASS: per-job override: queue default Vivid did not leak into the explicit None job"
|
|
pass=$((pass + 1))
|
|
fi
|
|
|
|
echo
|
|
echo "== result: ${pass} passed, ${fail} failed =="
|
|
[ "${fail}" -eq 0 ] || exit 1
|