Private
Public Access
0
0
Files
manual_slop/tests/test_provider_state_migration.py
T
ed 4e94780470 test(provider_state): add migration regression-guard suite
TIER-2 READ AGENTS.md conductor/workflow.md conductor/edit_workflow.md conductor/tier2/githooks/forbidden-files.txt conductor/tracks/tier2_leak_prevention_20260620/spec.md conductor/code_styleguides/data_oriented_design.md conductor/code_styleguides/error_handling.md conductor/code_styleguides/type_aliases.md before Phase 0 Task 0.3.

Phase 0 of code_path_audit_phase_3_provider_state_20260624. 14 regression-guard tests covering ProviderHistory API:
- 6 providers reachable as singletons
- append/get_all/clear/replace_all ordering preserved
- RLock re-entrancy in with-block (nested function call)
- concurrent append thread-safety (2 threads x 100 msgs = 200 unique)
- defensive copy semantics of get_all()
- __bool__/__len__/__iter__/__getitem__ dunders per provider
- clear_all() resets all 6 providers
- KeyError on unknown provider

All 14 tests PASS on current state (aliases still present; ProviderHistory API reachable).

Conventions: 1-space indentation, CRLF, no comments, from __future__ import annotations.
2026-06-25 12:03:02 -04:00

171 lines
5.1 KiB
Python

"""Regression-guard tests for src/provider_state.py
Phase 3 of any_type_componentization_20260621. Verifies the 4-method
ProviderHistory API is reachable and behaves correctly for all 6
providers (anthropic/deepseek/minimax/qwen/grok/llama) following the
migration of _X_history aliases in src/ai_client.py.
CONVENTION: 1-space indentation. NO COMMENTS.
"""
from __future__ import annotations
import threading
import pytest
from src import provider_state
EXPECTED_PROVIDERS: tuple[str, ...] = ("anthropic", "deepseek", "minimax", "qwen", "grok", "llama")
def _clear_all() -> None:
provider_state.clear_all()
def test_each_provider_reachable() -> None:
histories = [provider_state.get_history(p) for p in EXPECTED_PROVIDERS]
assert all(isinstance(h, provider_state.ProviderHistory) for h in histories)
assert len({id(h) for h in histories}) == 6
for p in EXPECTED_PROVIDERS:
assert provider_state.get_history(p) is provider_state.get_history(p)
def test_append_preserves_ordering() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.append({"role": "user", "content": f"{p}-1"})
h.append({"role": "assistant", "content": f"{p}-2"})
h.append({"role": "user", "content": f"{p}-3"})
assert h.get_all() == [
{"role": "user", "content": f"{p}-1"},
{"role": "assistant", "content": f"{p}-2"},
{"role": "user", "content": f"{p}-3"},
]
def test_lock_acquisition_no_deadlock() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
def inner() -> None:
with h.lock:
h.append({"role": "user", "content": f"{p}-inner"})
with h.lock:
assert len(h) == 0
inner()
assert len(h) == 1
assert h.get_all() == [{"role": "user", "content": f"{p}-inner"}]
def test_concurrent_append_thread_safety() -> None:
h = provider_state.get_history("anthropic")
h.clear()
def worker(start: int) -> None:
for i in range(100):
role = "user" if (i % 2 == 0) else "assistant"
h.append({"role": role, "content": f"t{start}-{i}"})
threads = [threading.Thread(target=worker, args=(t,)) for t in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
all_msgs = h.get_all()
assert len(all_msgs) == 200
contents = {m["content"] for m in all_msgs}
assert len(contents) == 200
def test_get_all_returns_copy() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.append({"role": "user", "content": f"{p}-original"})
snapshot = h.get_all()
snapshot.append({"role": "user", "content": f"{p}-leaked"})
assert h.get_all() == [{"role": "user", "content": f"{p}-original"}]
def test_replace_all_replaces_state() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.append({"role": "user", "content": f"{p}-a"})
h.append({"role": "assistant", "content": f"{p}-b"})
h.append({"role": "user", "content": f"{p}-c"})
h.replace_all([{"role": "user", "content": "fresh"}])
assert len(h.get_all()) == 1
assert h.get_all() == [{"role": "user", "content": "fresh"}]
def test_clear_resets_history() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.append({"role": "user", "content": "x"})
h.append({"role": "assistant", "content": "y"})
h.clear()
assert len(h.get_all()) == 0
assert bool(h) is False
def test_getitem_returns_specific_message() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.append({"role": "user", "content": f"{p}-first"})
h.append({"role": "assistant", "content": f"{p}-mid"})
h.append({"role": "user", "content": f"{p}-last"})
assert h[0] == {"role": "user", "content": f"{p}-first"}
assert h[1] == {"role": "assistant", "content": f"{p}-mid"}
assert h[-1] == {"role": "user", "content": f"{p}-last"}
def test_iter_returns_messages() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.append({"role": "user", "content": f"{p}-1"})
h.append({"role": "assistant", "content": f"{p}-2"})
h.append({"role": "user", "content": f"{p}-3"})
collected = [m for m in h]
assert collected == h.get_all()
def test_len_returns_count() -> None:
_clear_all()
for n in (0, 1, 5, 10):
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
h.clear()
for i in range(n):
h.append({"role": "user", "content": f"{p}-{i}"})
assert len(h) == n
def test_bool_empty_vs_populated() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
h = provider_state.get_history(p)
assert bool(h) is False
h.append({"role": "user", "content": "x"})
assert bool(h) is True
h.clear()
assert bool(h) is False
def test_clear_all_resets_all_6() -> None:
_clear_all()
for p in EXPECTED_PROVIDERS:
provider_state.get_history(p).append({"role": "user", "content": f"{p}-msg"})
provider_state.clear_all()
for p in EXPECTED_PROVIDERS:
assert len(provider_state.get_history(p).get_all()) == 0
def test_providers_returns_6_tuple() -> None:
assert provider_state.providers() == EXPECTED_PROVIDERS
def test_unknown_provider_raises() -> None:
with pytest.raises(KeyError):
provider_state.get_history("nonexistent")