4e94780470
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.
171 lines
5.1 KiB
Python
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")
|