Fix test suite: pad expectations, container pytest config, asyncio markers
Three unrelated failures from `make test` on the node:
test_metadata_watcher: two tests asserted the old zero-pad tgid_change
contract. Both were off by exactly call_tail_pad_seconds, i.e. the code
was doing what f1de157 intended and the tests encoded the behaviour we
deliberately changed. Updated to expect the pad.
test_pulse: four async tests errored with "async def functions are not
natively supported". Root cause is not the tests - pytest.ini sets
asyncio_mode = auto but the Dockerfile only copies app/ and tests/, so
the container had no pytest config at all and fell back to strict mode.
That is also why these passed in a local venv and failed on the node.
Copy pytest.ini into the image, and add explicit @pytest.mark.asyncio so
the tests hold up regardless of how pytest is configured.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,5 +15,8 @@ RUN pip install uv && uv pip install --system --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY app/ ./app/
|
||||
COPY tests/ ./tests/
|
||||
# Without this the container runs pytest with asyncio_mode defaulting to strict,
|
||||
# so unmarked async tests error out even though they pass locally.
|
||||
COPY pytest.ini .
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--reload"]
|
||||
|
||||
@@ -452,9 +452,11 @@ async def test_different_tgid_grant_splits_recording(watcher, clock):
|
||||
assert ended["call_id"] == first_id
|
||||
assert ended["tgid"] == 1111
|
||||
assert ended["end_reason"] == "tgid_change"
|
||||
# The outgoing segment ends exactly where the new one begins — no tail pad,
|
||||
# or it would swallow the first moments of the new talkgroup.
|
||||
assert ended["ended_at_epoch"] == split_time
|
||||
# The outgoing segment is padded PAST where the new one begins. The buffered
|
||||
# audio lags control-channel timestamps by ~1.5s, so ending exactly at the
|
||||
# split cut the outgoing call's last words. The overlap is correct — the
|
||||
# audio stream really does hold one call's tail then the next call's start.
|
||||
assert ended["ended_at_epoch"] == split_time + settings.call_tail_pad_seconds
|
||||
assert watcher.on_call_start.call_args[0][0]["started_at_epoch"] == split_time
|
||||
|
||||
|
||||
@@ -482,7 +484,8 @@ async def test_multiple_call_log_entries_in_one_poll(watcher, clock):
|
||||
assert ended["tgid"] == 1111
|
||||
assert ended["transmissions"] == 2
|
||||
assert ended["started_at_epoch"] == t0
|
||||
assert ended["ended_at_epoch"] == t0 + 0.9
|
||||
# Split close is padded past the new grant — see the tgid_change test above.
|
||||
assert ended["ended_at_epoch"] == t0 + 0.9 + settings.call_tail_pad_seconds
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -17,6 +17,8 @@ is proven at the layer that matters.
|
||||
import subprocess
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from app.internal import pulse
|
||||
|
||||
|
||||
@@ -53,6 +55,7 @@ def test_is_ready_false_when_daemon_does_not_respond(monkeypatch):
|
||||
assert pulse.is_ready() is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wait_until_ready_short_circuits_when_already_live(monkeypatch):
|
||||
calls = Mock(return_value=True)
|
||||
monkeypatch.setattr(pulse, "_daemon_responds", calls)
|
||||
@@ -60,6 +63,7 @@ async def test_wait_until_ready_short_circuits_when_already_live(monkeypatch):
|
||||
assert calls.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wait_until_ready_polls_until_daemon_comes_up(monkeypatch):
|
||||
monkeypatch.setattr(pulse, "POLL_INTERVAL", 0.01)
|
||||
responses = iter([False, False, True])
|
||||
@@ -67,12 +71,14 @@ async def test_wait_until_ready_polls_until_daemon_comes_up(monkeypatch):
|
||||
assert await pulse.wait_until_ready(timeout=5) is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wait_until_ready_times_out_when_daemon_never_responds(monkeypatch):
|
||||
monkeypatch.setattr(pulse, "POLL_INTERVAL", 0.01)
|
||||
monkeypatch.setattr(pulse, "_daemon_responds", lambda: False)
|
||||
assert await pulse.wait_until_ready(timeout=0.05) is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wait_until_ready_uses_settings_default_when_timeout_omitted(monkeypatch):
|
||||
monkeypatch.setattr(pulse.settings, "pulse_wait_timeout", 0.05)
|
||||
monkeypatch.setattr(pulse, "POLL_INTERVAL", 0.01)
|
||||
|
||||
Reference in New Issue
Block a user