chore: remainder — backend test infra, agent config, docker, i18n, frontend ui
- Backend: alembic env, config manager/models, dependencies, translate plugin - Backend tests: async_sync_regression, integration tests, git services, test_agent - Docker: docker-compose.yml updates - Agent: qa-tester.md update, semantics-testing SKILL.md update - Frontend: TopNavbar, sidebarNavigation, FeaturesSettings, FeatureGate - i18n: assistant.json en/ru locale updates - New: frontend/src/lib/components/agent/ directory
This commit is contained in:
130
backend/tests/test_agent/test_model_fixtures.py
Normal file
130
backend/tests/test_agent/test_model_fixtures.py
Normal file
@@ -0,0 +1,130 @@
|
||||
# #region TestAgentChat.ModelFixtures [C:2] [TYPE Module] [SEMANTICS test,agent,fixtures,model]
|
||||
# @BRIEF Materialize model fixtures from JSON — verify fixture structure matches expected.
|
||||
# @RELATION BINDS_TO -> [AgentChat.Model]
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
FIXTURES_DIR = Path(__file__).resolve().parent.parent.parent.parent / "specs" / "033-gradio-agent-chat" / "fixtures" / "model"
|
||||
|
||||
|
||||
# #region TestAgentChat.ModelFixtures.SendMessageValid [C:2] [TYPE Function] [SEMANTICS test,fixture,send]
|
||||
# @BRIEF FX_AgentChat.Model.SendMessage.Valid — verify fixture structure.
|
||||
def test_fixture_send_message_valid():
|
||||
"""Load send_message_valid fixture and verify structural integrity."""
|
||||
fixture_path = FIXTURES_DIR / "send_message_valid.json"
|
||||
assert fixture_path.exists(), f"Fixture not found: {fixture_path}"
|
||||
|
||||
with open(fixture_path) as f:
|
||||
fixture = json.load(f)
|
||||
|
||||
assert fixture["fixture_id"] == "FX_AgentChat.Model.SendMessage.Valid"
|
||||
assert fixture["verifies"] == "AgentChat.Model"
|
||||
assert fixture["invariant"] == "StreamingStateGatesInput"
|
||||
assert fixture["input"]["action"] == "sendMessage"
|
||||
assert fixture["input"]["state_before"]["streamingState"] == "idle"
|
||||
assert fixture["expected"]["state_after"]["streamingState"] == "streaming"
|
||||
assert fixture["expected"]["state_after"]["isInputLocked"] is True
|
||||
assert fixture["expected"]["state_after"]["error"] is None
|
||||
# #endregion TestAgentChat.ModelFixtures.SendMessageValid
|
||||
|
||||
|
||||
# #region TestAgentChat.ModelFixtures.CancelGeneration [C:2] [TYPE Function] [SEMANTICS test,fixture,cancel]
|
||||
# @BRIEF FX_AgentChat.Model.CancelGeneration — verify cancel fixture structure.
|
||||
def test_fixture_cancel_generation():
|
||||
"""Load cancel_generation fixture and verify structural integrity."""
|
||||
fixture_path = FIXTURES_DIR / "cancel_generation.json"
|
||||
assert fixture_path.exists(), f"Fixture not found: {fixture_path}"
|
||||
|
||||
with open(fixture_path) as f:
|
||||
fixture = json.load(f)
|
||||
|
||||
assert fixture["fixture_id"] == "FX_AgentChat.Model.CancelGeneration"
|
||||
assert fixture["edge"] == "cancel_during_streaming"
|
||||
assert fixture["input"]["action"] == "cancelGeneration"
|
||||
expected = fixture["expected"]["state_after"]
|
||||
assert expected["streamingState"] == "idle"
|
||||
assert expected["isInputLocked"] is False
|
||||
assert "partialText" in expected
|
||||
# #endregion TestAgentChat.ModelFixtures.CancelGeneration
|
||||
|
||||
|
||||
# #region TestAgentChat.ModelFixtures.ResumeConfirm [C:2] [TYPE Function] [SEMANTICS test,fixture,confirm]
|
||||
# @BRIEF FX_AgentChat.Model.ResumeConfirm — verify resume confirm fixture.
|
||||
def test_fixture_resume_confirm():
|
||||
"""Load resume_confirm fixture and verify structural integrity."""
|
||||
fixture_path = FIXTURES_DIR / "resume_confirm.json"
|
||||
assert fixture_path.exists(), f"Fixture not found: {fixture_path}"
|
||||
|
||||
with open(fixture_path) as f:
|
||||
fixture = json.load(f)
|
||||
|
||||
assert fixture["fixture_id"] == "FX_AgentChat.Model.ResumeConfirm"
|
||||
assert fixture["edge"] == "confirm_from_awaiting"
|
||||
assert fixture["input"]["action"] == "resumeConfirm"
|
||||
assert fixture["input"]["args"] == ["confirm"]
|
||||
expected = fixture["expected"]["state_after"]
|
||||
assert expected["streamingState"] == "streaming"
|
||||
assert expected["pendingThreadId"] is None
|
||||
# #endregion TestAgentChat.ModelFixtures.ResumeConfirm
|
||||
|
||||
|
||||
# #region TestAgentChat.ModelFixtures.ResumeDeny [C:2] [TYPE Function] [SEMANTICS test,fixture,deny]
|
||||
# @BRIEF FX_AgentChat.Model.ResumeDeny — verify resume deny fixture.
|
||||
def test_fixture_resume_deny():
|
||||
"""Load resume_deny fixture and verify structural integrity."""
|
||||
fixture_path = FIXTURES_DIR / "resume_deny.json"
|
||||
assert fixture_path.exists(), f"Fixture not found: {fixture_path}"
|
||||
|
||||
with open(fixture_path) as f:
|
||||
fixture = json.load(f)
|
||||
|
||||
assert fixture["fixture_id"] == "FX_AgentChat.Model.ResumeDeny"
|
||||
assert fixture["edge"] == "deny_from_awaiting"
|
||||
assert fixture["input"]["action"] == "resumeConfirm"
|
||||
assert fixture["input"]["args"] == ["deny"]
|
||||
expected = fixture["expected"]["state_after"]
|
||||
assert expected["streamingState"] == "idle"
|
||||
assert expected["pendingThreadId"] is None
|
||||
# #endregion TestAgentChat.ModelFixtures.ResumeDeny
|
||||
|
||||
|
||||
# #region TestAgentChat.ModelFixtures.RejectedWebSocket [C:2] [TYPE Function] [SEMANTICS test,fixture,rejected]
|
||||
# @BRIEF FX_AgentChat.Model.RejectedPath — verify no WebSocket resurrection.
|
||||
def test_fixture_rejected_websocket():
|
||||
"""Verify no WebSocket resurrection in AgentChatModel."""
|
||||
fixture_path = FIXTURES_DIR / "rejected_websocket.json"
|
||||
assert fixture_path.exists(), f"Fixture not found: {fixture_path}"
|
||||
|
||||
with open(fixture_path) as f:
|
||||
fixture = json.load(f)
|
||||
|
||||
assert fixture["fixture_id"] == "FX_AgentChat.Model.RejectedPath"
|
||||
assert fixture["invariant"] == "NoWebSocketImports"
|
||||
assert fixture["edge"] == "rejected_path"
|
||||
assert "No 'WebSocket'" in fixture["expected"]["assertions"][0]
|
||||
|
||||
# Read the actual model source
|
||||
model_path = Path(__file__).resolve().parent.parent.parent.parent / "frontend" / "src" / "lib" / "models" / "AgentChatModel.svelte.ts"
|
||||
source = model_path.read_text()
|
||||
|
||||
# Verify no WebSocket imports (not just the word — it's in comments as @REJECTED)
|
||||
assertions = fixture["expected"]["assertions"]
|
||||
for assertion in assertions:
|
||||
if "WebSocket" in assertion:
|
||||
# Check for actual WebSocket import (import WebSocket, from ... import ... WebSocket)
|
||||
for line in source.split("\n"):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("import") and "WebSocket" in stripped:
|
||||
pytest.fail(f"FAIL: {assertion} — found WebSocket import: {stripped}")
|
||||
if stripped.startswith("from") and "WebSocket" in stripped:
|
||||
pytest.fail(f"FAIL: {assertion} — found WebSocket import: {stripped}")
|
||||
if "tabRole" in assertion:
|
||||
assert "tabRole" not in source, f"FAIL: {assertion}"
|
||||
if "follower_notify" in assertion:
|
||||
assert "follower_notify" not in source, f"FAIL: {assertion}"
|
||||
if "takeoverSession" in assertion:
|
||||
assert "takeoverSession" not in source, f"FAIL: {assertion}"
|
||||
# #endregion TestAgentChat.ModelFixtures.RejectedWebSocket
|
||||
# #endregion TestAgentChat.ModelFixtures
|
||||
Reference in New Issue
Block a user