GoWelcome/tests/test_web.py

73 lines
1.9 KiB
Python

"""Tests for the optional MJPEG web viewer (stdlib only -- no cv2 / hardware).
Binds an ephemeral localhost port, hits each route, and checks the framing.
"""
from __future__ import annotations
import time
import urllib.request
import pytest
from gowelcome.web import MjpegServer
# A minimal valid JPEG (SOI ... EOI) used as the stub frame.
_FAKE_JPEG = bytes.fromhex("ffd8ffe000104a46494600010100000100010000ffd9")
@pytest.fixture()
def server():
srv = MjpegServer(lambda: _FAKE_JPEG, host="127.0.0.1", port=0, fps=30)
srv.start()
time.sleep(0.2)
try:
yield srv
finally:
srv.stop()
def _get(port: int, path: str, n: int | None = None):
resp = urllib.request.urlopen(f"http://127.0.0.1:{port}{path}", timeout=3)
return resp.status, resp.headers.get("Content-Type"), (resp.read(n) if n else resp.read())
def test_healthz(server):
status, ctype, body = _get(server.port, "/healthz")
assert status == 200
assert body == b"ok"
def test_index_embeds_stream(server):
status, ctype, body = _get(server.port, "/")
assert status == 200
assert "text/html" in ctype
assert b"/stream.mjpg" in body
def test_snapshot_returns_jpeg(server):
status, ctype, body = _get(server.port, "/snapshot.jpg")
assert status == 200
assert ctype == "image/jpeg"
assert body[:2] == b"\xff\xd8" # JPEG SOI
def test_stream_is_multipart_mjpeg(server):
resp = urllib.request.urlopen(f"http://127.0.0.1:{server.port}/stream.mjpg", timeout=3)
assert "multipart/x-mixed-replace" in resp.headers.get("Content-Type", "")
chunk = resp.read(400)
resp.close()
assert b"--gowelcomeframe" in chunk
assert b"image/jpeg" in chunk
def test_unknown_path_404(server):
with pytest.raises(urllib.error.HTTPError) as exc:
_get(server.port, "/nope")
assert exc.value.code == 404
def test_stop_is_idempotent(server):
server.stop()
server.stop() # must not raise