This commit is contained in:
valenti
2026-09-08 07:21:34 -04:00
commit a4b224da8e
169 changed files with 27483 additions and 0 deletions
View File
@@ -0,0 +1,130 @@
"""asf-ai tests — MockProvider + AIGateway routing, no network calls."""
from __future__ import annotations
import sys
from pathlib import Path
from uuid import UUID
import pytest
AI_ROOT = Path(__file__).resolve().parents[1]
if str(AI_ROOT) not in sys.path:
sys.path.insert(0, str(AI_ROOT))
TENANT_ID = UUID("99999999-0000-0000-0000-000000000001")
PROJECT_ID = UUID("88888888-0000-0000-0000-000000000002")
JOB_ID = UUID("77777777-0000-0000-0000-000000000003")
@pytest.fixture
def trace_ctx():
from app.capabilities import TraceContext
return TraceContext(
tenant_id=TENANT_ID, project_id=PROJECT_ID, job_id=JOB_ID, correlation_id="ai-trace"
)
@pytest.fixture
def mock_provider():
from app.providers import MockProvider
return MockProvider(response_latency_ms=0)
class TestMockProviderChat:
@pytest.mark.asyncio
async def test_chat_mirrors_last_user_in_reply(self, mock_provider, trace_ctx):
from app.capabilities import ChatRequest, ChatMessage
req = ChatRequest(
trace=trace_ctx,
messages=[
ChatMessage(role="system", content="You are helpful."),
ChatMessage(role="user", content="what is REQ-103?"),
],
)
resp = await mock_provider.chat(req)
assert resp.provider == "mock"
assert resp.model_used == "asf-mock-v1"
assert resp.estimated_cost == 0.0
assert "what is REQ-103?" in resp.reply
assert resp.input_tokens >= 0 and resp.output_tokens > 0
assert resp.references == ["mock://no-real-data"]
class TestMockProviderCodeAnalysis:
@pytest.mark.asyncio
async def test_analyze_code_detects_todo_and_broad_except(self, mock_provider, trace_ctx):
from app.capabilities import CodeAnalysisRequest
code = (
"def foo():\n"
" # TODO: refactor this later\n"
" try:\n"
" risky_call()\n"
" except Exception:\n"
" pass\n"
)
req = CodeAnalysisRequest(trace=trace_ctx, code_snippet=code, language="python")
resp = await mock_provider.analyze_code(req)
kinds = {f.kind for f in resp.findings}
assert "todo" in kinds
assert "broad_exception" in kinds
sevs = {f.severity for f in resp.findings}
assert "medium" in sevs # broad_exception is medium
assert resp.summary.startswith("Mock: analyzed ")
assert resp.input_tokens > 0
@pytest.mark.asyncio
async def test_analyze_code_clean_snippet_zero_findings(self, mock_provider, trace_ctx):
from app.capabilities import CodeAnalysisRequest
req = CodeAnalysisRequest(trace=trace_ctx, code_snippet="x = 1\ny = 2\n", language="python")
resp = await mock_provider.analyze_code(req)
assert resp.findings == []
assert "0 informational finding" in resp.summary
class TestMockProviderTestGeneration:
@pytest.mark.asyncio
async def test_generate_tests_returns_placeholders(self, mock_provider, trace_ctx):
from app.capabilities import TestGenerationRequest
req = TestGenerationRequest(
trace=trace_ctx,
code_snippet="def add(a, b): return a+b\n",
language="python",
test_framework="pytest",
)
resp = await mock_provider.generate_tests(req)
assert len(resp.test_cases) >= 2
assert any("test_mock_happy_path" in t for t in resp.test_cases)
assert resp.fixtures_needed
assert resp.coverage_notes.startswith("Mock response.")
assert resp.output_tokens > 0
class TestMockProviderDecomposeRequirement:
@pytest.mark.asyncio
async def test_decompose_respects_max_subtasks_cap(self, mock_provider, trace_ctx):
from app.capabilities import RequirementDecomposeRequest
req = RequirementDecomposeRequest(
trace=trace_ctx, requirement_text="Build a billing page.", max_subtasks=3
)
resp = await mock_provider.decompose_requirement(req)
assert len(resp.subtasks) == 3
# graph edges sanity: second subtask depends on first
assert 0 in (resp.subtasks[1].depends_on or [])
assert resp.open_questions
assert resp.architecture_notes
class TestProviderRegistry:
def test_registry_register_and_get(self):
from app.providers import ProviderRegistry, MockProvider
reg = ProviderRegistry()
reg.register("m", MockProvider(response_latency_ms=0))
assert reg.names() == ["m"]
assert reg.get("m").name == "mock"
def test_registry_get_missing_raises_keyerror(self):
from app.providers import ProviderRegistry
reg = ProviderRegistry()
with pytest.raises(KeyError, match="Unknown AI provider"):
reg.get("nope")