Cover the camera path in the edge e2e test

The camera work had unit tests on both ends and nothing exercising it
against a real printer. This adds that, and it immediately earned its
keep: it is the only test that covers `stream_base_url` surviving the
hello, living on an in-memory connection, and coming back out of
`GET /printers/:id/stream` - a path with no unit test behind it, because
the connection map is not reachable without a socket.

Verified against a live H2C: it reports a camera stream named after its
own gateway id, and the endpoint answers
`{"streamUrl":"http://e2e-gateway.invalid:1984","cameraId":"h2c"}`.

Both halves are asserted, because "some printers have a stream and most
do not" is the expected state rather than a defect. Only the X1/H2 class
publishes an `rtsp_url` - confirmed at the network layer, where the H2C
accepts TCP on 322 and a P1P refuses it and listens on 6000 - so the
test also asserts that a printer without one is refused with a 404 that
blames the printer's camera and not the gateway. A run where no printer
has a camera still passes, but says so rather than claiming the path
works.

`CONTINUUM_STREAM_BASE_URL` is set to an unreachable name on purpose:
nothing here plays video, and it only has to prove the value made the
round trip. The gateway's go2rtc config is also pointed into the
scratch directory now, so a run no longer writes `go2rtc.yaml` into the
proxy checkout.
This commit is contained in:
2026-10-18 13:35:10 +00:00
parent 57af710b1a
commit e9083cc9e3
+64 -1
View File
@@ -186,13 +186,19 @@ echo "==> starting the real continuum-proxy against it"
# or cleanup kills only the wrapper and leaves an orphan reconnecting with a
# stale token. An earlier version did exactly that, and the orphan then
# reported a deleted farm's printers into the next run.
# STREAM_BASE_URL is deliberately set: it is what the gateway advertises in
# its hello and the only way GET /printers/:id/stream can answer 200, so
# leaving it unset would make the camera assertions below untestable rather
# than passing. It does not have to be reachable - nothing here plays video.
STREAM_BASE_URL="http://e2e-gateway.invalid:1984"
env -C "$PROXY_DIR" \
CONTINUUM_GATEWAY_ID=e2e-gw \
CONTINUUM_FARM_ID="$FARM_ID" \
CONTINUUM_GATEWAY_TOKEN="$TOKEN" \
CONTINUUM_UPLINK_URL="ws://localhost:$PORT/ws/edge/v1" \
CONTINUUM_GO2RTC_BIN=/nonexistent-go2rtc \
CONTINUUM_GO2RTC_CONFIG=./go2rtc.yaml \
CONTINUUM_GO2RTC_CONFIG="$WORK/go2rtc.yaml" \
CONTINUUM_STREAM_BASE_URL="$STREAM_BASE_URL" \
CONTINUUM_PRINTERS_PATH=printers.toml \
RUST_LOG=info \
"$PROXY_DIR/target/debug/continuum-proxy" > "$WORK/proxy.log" 2>&1 &
@@ -277,6 +283,58 @@ else
COMMAND_TESTED=yes
fi
# --- 5b. the camera path ---------------------------------------------------
# Only the X1/H2 class publishes an rtsp_url - confirmed at the network layer:
# the H2C accepts TCP on 322, a P1P refuses it and listens on 6000 instead. So
# "some printers have a stream and most do not" is the expected state, and both
# halves are asserted. A run where no printer has a camera still passes, but
# says so rather than claiming the path works.
echo "==> the camera path: what the gateway reported, and what the API answers"
WITH_CAMERA="$(psql_q "SELECT gateway_printer_id FROM printers
WHERE farm_id='$FARM_ID' AND camera_stream IS NOT NULL
ORDER BY gateway_printer_id LIMIT 1")"
if [ -z "$WITH_CAMERA" ]; then
echo " SKIPPED: no printer reported a camera stream."
echo " Expected if only P1/A1-class printers are on: they publish no rtsp_url."
else
# The gateway sets camera_stream to its own printer id, so this also checks
# the two ends agree about the name a stream is served under.
STREAM_NAME="$(psql_q "SELECT camera_stream FROM printers
WHERE farm_id='$FARM_ID' AND gateway_printer_id='$WITH_CAMERA'")"
[ "$STREAM_NAME" = "$WITH_CAMERA" ] \
|| fail "camera_stream for '$WITH_CAMERA' is '$STREAM_NAME', expected its own gateway id"
ok "'$WITH_CAMERA' reported camera stream '$STREAM_NAME'"
CAM_UUID="$(psql_q "SELECT id FROM printers
WHERE farm_id='$FARM_ID' AND gateway_printer_id='$WITH_CAMERA'")"
STREAM="$(curl -sf -H "$AUTH_HEADER" "$BASE/printers/$CAM_UUID/stream")" \
|| fail "GET /printers/$CAM_UUID/stream failed for a printer that has a camera"
echo "$STREAM" | grep -q "\"cameraId\":\"$WITH_CAMERA\"" \
|| fail "wrong cameraId: $STREAM"
# The farm's stream base URL has to survive the hello and come back out of
# an in-memory connection, which is the part with no unit test behind it.
echo "$STREAM" | grep -q "\"streamUrl\":\"$STREAM_BASE_URL\"" \
|| fail "streamUrl did not come back from the gateway's hello: $STREAM"
ok "GET .../stream: $STREAM"
fi
# A printer with no camera must 404, and say which half is missing. This is
# the case a frontend hits for most of a mixed fleet, so it matters that it is
# a clean refusal rather than a 200 carrying nulls.
NO_CAMERA="$(psql_q "SELECT id FROM printers
WHERE farm_id='$FARM_ID' AND camera_stream IS NULL
AND gateway_printer_id IS NOT NULL LIMIT 1")"
if [ -n "$NO_CAMERA" ]; then
CODE="$(curl -s -o "$WORK/nocam.json" -w '%{http_code}' -H "$AUTH_HEADER" \
"$BASE/printers/$NO_CAMERA/stream")"
[ "$CODE" = "404" ] || fail "expected 404 for a printer with no camera, got $CODE"
grep -q 'no camera' "$WORK/nocam.json" \
|| fail "the 404 should blame the printer's camera, not the gateway: $(cat "$WORK/nocam.json")"
ok "a printer with no camera is refused with 404, blaming the right half"
fi
# --- 6. the negative case --------------------------------------------------
echo "==> an unclaimed printer must be refused, not guessed at"
@@ -292,6 +350,11 @@ ok "unclaimed printer refused with 409 PRINTER_UNREACHABLE"
echo
# Say what was actually exercised. Claiming commands work when the command test
# was skipped is worse than not running it.
if [ -n "${WITH_CAMERA:-}" ]; then
echo " Camera path verified: '$WITH_CAMERA' reported a stream and the API served it."
else
echo " Camera path NOT verified: no printer on this LAN publishes an rtsp_url."
fi
if [ "$COMMAND_TESTED" = yes ]; then
echo "PASS - telemetry and commands both verified against a real database and real printers."
else