mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
test: coverage campaign and mutation testing across five packages (#628)
Coverage 83.6 to 87.36% lines, 81.63 to 84.14% branches. Mutation testing across five packages: image-engine 85, media-engine 92, doc-engine 87, shared+enterprise 86, apps/api security and jobs slice. Runs all five lanes weekly. Fixes the silently-broken mutation CI (babel pin), a redact-pdf envelope-shape test bug, an untested enterprise license valid-signature path, and an audit test that only exercised a hand-copied reproduction. Test and config only, no product code changes beyond the babel pin and one test-only oidc export. Full suite: 16,712 pass, 0 fail.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"""Contract tests for progress_heartbeat.run_with_heartbeat: it advances a
|
||||
rising progress bar from a background thread while an opaque model call runs,
|
||||
caps below ``end``, returns the call's value, and propagates its exception.
|
||||
Pure (threading), deterministic via events rather than sleep races."""
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
import progress_heartbeat # noqa: E402
|
||||
|
||||
|
||||
def test_returns_fn_value_without_beats_when_interval_long():
|
||||
emitted = []
|
||||
result = progress_heartbeat.run_with_heartbeat(
|
||||
lambda: 42,
|
||||
lambda pct, stage: emitted.append((pct, stage)),
|
||||
start=0,
|
||||
end=100,
|
||||
stage="work",
|
||||
interval=100,
|
||||
)
|
||||
assert result == 42
|
||||
assert emitted == [] # fn returned long before the first (100s) beat
|
||||
|
||||
|
||||
def test_propagates_fn_exception():
|
||||
emitted = []
|
||||
|
||||
def boom():
|
||||
raise ValueError("nope")
|
||||
|
||||
with pytest.raises(ValueError, match="nope"):
|
||||
progress_heartbeat.run_with_heartbeat(
|
||||
boom,
|
||||
lambda pct, stage: emitted.append((pct, stage)),
|
||||
start=0,
|
||||
end=100,
|
||||
stage="work",
|
||||
interval=100,
|
||||
)
|
||||
assert emitted == []
|
||||
|
||||
|
||||
def test_emits_rising_progress_capped_below_end():
|
||||
emitted = []
|
||||
reached_two = threading.Event()
|
||||
|
||||
def emit(pct, stage):
|
||||
emitted.append((pct, stage))
|
||||
if len(emitted) >= 2:
|
||||
reached_two.set()
|
||||
|
||||
def fn():
|
||||
reached_two.wait(timeout=2.0) # block until two heartbeats fire
|
||||
return "done"
|
||||
|
||||
result = progress_heartbeat.run_with_heartbeat(
|
||||
fn, emit, start=10, end=13, stage="infer", interval=0.01
|
||||
)
|
||||
assert result == "done"
|
||||
pcts = [p for p, _ in emitted]
|
||||
# start+1 .. end-1, monotonically rising, never reaching end.
|
||||
assert pcts == [11, 12]
|
||||
assert all(stage == "infer" for _, stage in emitted)
|
||||
assert max(pcts) <= 13 - 1
|
||||
|
||||
|
||||
def test_no_emit_when_start_at_cap():
|
||||
emitted = []
|
||||
|
||||
def fn():
|
||||
time.sleep(0.05) # give the beat thread room to attempt an emit
|
||||
return "x"
|
||||
|
||||
result = progress_heartbeat.run_with_heartbeat(
|
||||
fn, lambda pct, stage: emitted.append(pct), start=12, end=13, stage="s", interval=0.01
|
||||
)
|
||||
assert result == "x"
|
||||
assert emitted == [] # pct=12 is not < end-1=12, so nothing is emitted
|
||||
|
||||
|
||||
def test_stops_emitting_after_fn_returns():
|
||||
emitted = []
|
||||
reached_one = threading.Event()
|
||||
|
||||
def emit(pct, stage):
|
||||
emitted.append(pct)
|
||||
reached_one.set()
|
||||
|
||||
def fn():
|
||||
reached_one.wait(timeout=2.0)
|
||||
return None
|
||||
|
||||
progress_heartbeat.run_with_heartbeat(
|
||||
fn, emit, start=0, end=100, stage="s", interval=0.01
|
||||
)
|
||||
count = len(emitted)
|
||||
time.sleep(0.05) # a still-alive beat thread would push more emits here
|
||||
assert len(emitted) == count # the heartbeat stopped on return
|
||||
Reference in New Issue
Block a user