Files
voculinux/tests/test_perf_baseline_protocol.py
T
soubarnak ea7be5f111 feat(identity): rename user-visible identity to voculinux with one-time legacy import
The fork takes its own name everywhere a user can see it: binaries
(voculinux, voculinux-gui), desktop entry, autostart, tray, D-Bus
namespace (com.voculinux.Voculinux, no alias for the old name),
config/data/cache dirs, single-instance lock, IBus engine identity,
tray icons, resource prefixes, VOCULINUX_* environment names, and the
update-checker user agent. The internal Python module stays vocalinux
and the distribution metadata keeps the upstream URLs as provenance.

On first run a previous Vocalinux install's config.json, custom
dictionary, and portal restore token are copied once into the new
locations (new config always wins, no merge, no write-back); models
re-resolve through the pinned-checksum download path. An offline
naming-sweep test proves no old-name strings remain on user-visible
surfaces outside the allowlist.

Refs #18
2026-11-06 01:29:39 +05:30

137 lines
5.7 KiB
Python

"""Behaviour tests for the ticket-19 performance-baseline protocol script.
The script (scripts/measure_perf_baseline.py) is the locked measurement
protocol for the installed-build baseline: every number it reports comes
from an observed run on the target machine class, parsed by the pure
helpers tested here. Tests run offline with fixture text only and never
touch audio hardware, the GPU, or the network.
"""
import importlib.util
from pathlib import Path
import pytest
SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "measure_perf_baseline.py"
SPEC = importlib.util.spec_from_file_location("measure_perf_baseline", SCRIPT)
assert SPEC is not None and SPEC.loader is not None
PROTOCOL = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(PROTOCOL)
def test_parse_vmrss_kb_reads_kilobytes() -> None:
"""VmRSS lines parse to kilobytes; anything else yields None."""
status = "Name:\tvoculinux\nVmRSS:\t 412336 kB\nVmSwap:\t0 kB\n"
assert PROTOCOL.parse_vmrss_kb(status) == 412336
assert PROTOCOL.parse_vmrss_kb("Name:\tvoculinux\n") is None
def test_describe_reports_count_mean_min_max() -> None:
"""Spread statistics come from the samples, never fabricated."""
stats = PROTOCOL.describe([1.0, 2.0, 3.0])
assert stats["n"] == 3
assert stats["mean"] == pytest.approx(2.0)
assert stats["min"] == pytest.approx(1.0)
assert stats["max"] == pytest.approx(3.0)
def test_describe_empty_is_explicit() -> None:
"""No samples means n == 0, never a zero mean pretending to be data."""
stats = PROTOCOL.describe([])
assert stats["n"] == 0
assert stats["mean"] is None
WAKE_LOG = """\
2026-11-05 22:44:01,100 - vocalinux.ui.action_handler - DEBUG - Handling action: toggle
2026-11-05 22:44:01,350 - vocalinux.audio.capture - DEBUG - Opened capture stream: 1 channel(s) at 16000Hz
2026-11-05 22:44:05,100 - vocalinux.ui.action_handler - DEBUG - Handling action: toggle
2026-11-05 22:44:05,500 - vocalinux.audio.capture - DEBUG - Opened capture stream: 1 channel(s) at 16000Hz
"""
def test_parse_wake_latencies_pairs_toggle_to_capture() -> None:
"""Each toggle pairs with the next capture-stream line, in seconds."""
assert PROTOCOL.parse_wake_latencies(WAKE_LOG) == pytest.approx([0.25, 0.4])
def test_parse_wake_latencies_ignores_unpaired_toggle() -> None:
"""A toggle with no later capture start is dropped, not zero-filled."""
log = (
WAKE_LOG
+ "2026-11-05 22:44:09,100 - vocalinux.ui.action_handler - DEBUG - Handling action: start\n"
)
assert PROTOCOL.parse_wake_latencies(log) == pytest.approx([0.25, 0.4])
def test_realtime_factor_is_audio_over_wall() -> None:
"""RTF below one means faster than real time; zero audio is refused."""
assert PROTOCOL.realtime_factor(30.0, 15.0) == pytest.approx(0.5)
with pytest.raises(ValueError):
PROTOCOL.realtime_factor(0.0, 1.0)
def test_parse_nvidia_smi_csv_reads_first_gpu() -> None:
"""The locked nvidia-smi query shape parses to total/free MiB."""
out = (
"name, driver_version, memory.total [MiB], memory.free [MiB]\n"
"NVIDIA GeForce RTX 2050, 595.112.07, 4096 MiB, 3711 MiB\n"
)
assert PROTOCOL.parse_nvidia_smi_memory(out) == (4096, 3711)
assert PROTOCOL.parse_nvidia_smi_memory("no gpu here\n") is None
def test_recommend_thresholds_come_from_footprints() -> None:
"""Ladder thresholds derive from measured footprints plus headroom."""
footprints = {"q8_0": 1000.0, "q5_0": 700.0, "small": 500.0}
advice = PROTOCOL.recommend_thresholds(footprints, headroom_mib=512.0)
assert advice["prefer_q8_0_above_mib"] == pytest.approx(1512.0)
assert advice["prefer_q5_0_above_mib"] == pytest.approx(1212.0)
assert advice["floor_small_below_mib"] == pytest.approx(1212.0)
def test_render_report_names_protocol_and_host() -> None:
"""The evidence report carries protocol version and host facts."""
report = PROTOCOL.render_markdown_report(
{"os": "Void", "gpu": "NVIDIA GeForce RTX 2050"}, {"idle": {}}
)
assert PROTOCOL.PROTOCOL_VERSION in report
assert "Void" in report
assert "NVIDIA GeForce RTX 2050" in report
def test_sample_generator_is_deterministic(tmp_path) -> None:
"""The fixed sample regenerates byte-identical from its seed."""
first = tmp_path / "a.wav"
second = tmp_path / "b.wav"
PROTOCOL.make_sample_wav(first, seed=19)
PROTOCOL.make_sample_wav(second, seed=19)
assert first.read_bytes() == second.read_bytes()
def test_sample_shape_is_thirty_seconds_mono_16k(tmp_path) -> None:
"""The sample is 30 s, mono, 16 kHz, 16-bit for whisper.cpp."""
import wave
target = tmp_path / "sample.wav"
PROTOCOL.make_sample_wav(target, seed=19)
with wave.open(str(target), "rb") as handle:
assert handle.getnchannels() == 1
assert handle.getsampwidth() == 2
assert handle.getframerate() == 16000
assert handle.getnframes() / 16000 == pytest.approx(30.0)
DBUS_TOGGLE_LOG = """\
2026-11-05 23:01:11,400 - vocalinux.ui.tray_indicator - DEBUG - Toggle requested in state IDLE
2026-11-05 23:01:11,546 - vocalinux.audio.capture - DEBUG - Opened capture stream: 2 channel(s) at 44100Hz
2026-11-05 23:01:16,400 - vocalinux.ui.tray_indicator - DEBUG - Toggle requested in state LISTENING
2026-11-05 23:01:22,100 - vocalinux.ui.tray_indicator - DEBUG - Toggle requested in state IDLE
2026-11-05 23:01:22,749 - vocalinux.audio.capture - DEBUG - Opened capture stream: 2 channel(s) at 44100Hz
"""
def test_parse_wake_latencies_pairs_dbus_toggle_starts_only() -> None:
"""Only IDLE toggles open capture; a stop toggle never borrows the next run."""
assert PROTOCOL.parse_wake_latencies(DBUS_TOGGLE_LOG) == pytest.approx([0.146, 0.649])