Files
ss-tools/backend/tests/api/test_dashboard_testing_verification_api.py
busya a32ca0631b feat(037): capture, verification lifecycle, inheritance + close 036 stabilization
- Authoritative candidate capture with server-issued artifacts and raw-byte
  immutability hashing (source_response_hash server-owned)
- Closed-period lifecycle: request-hash bound approvals, persisted closure
  immutability violations, byte-for-byte catalog stability on reclosure
- Verification runs: persisted VerificationRun model + FK migration,
  publish gate (block_publish), scheduled observability runs (02:00 UTC)
- FR-013 baseline inheritance: prior_release_id migration, plan_inheritance/
  execute_inheritance classification and re-extraction, API endpoints
- Visual executor bound to release-deployment environment; caller mismatch
  rejected; visual SSIM/reconciliation modules
- Query execution decomposed: envelope/model/executor split, no direct SQL
- AgentRun approvals extracted to submodule; evidence adapter; _utils
- Dashboard testing service decomposed into 30+ modules (all <400 LOC)
- Five Feature-037 agent tools with permission guards (tools_037.py)
- API readiness endpoint; Alembic env/migrations; test fixture repos
- Specs 036/037 contracts, openapi.yaml, schema.json, tasks/traceability
  updated; semantic index rebuilt with 0 parse warnings
- Fix ADR-0003 parser ambiguity: remove [DEF🆔ADR] prose example
- Add axiom-mcp-agent-feedback.md: agent findings for MCP rework plan
- Tests: 298 service + 1464 API + 45 agent passing; ruff clean
2026-07-31 11:28:50 +03:00

172 lines
8.0 KiB
Python

# #region Test.Api.DashboardTesting.VerificationApi [C:3] [TYPE Module] [SEMANTICS test,api,dashboard-testing,verification-runs,http,persistence]
# @defgroup Verification-run HTTP tests with real repository fixtures.
# @LAYER Test
# @RELATION BINDS_TO -> [Api.DashboardTesting.CreateVerificationRun]
# @TEST_FIXTURE: verification_repository -> INLINE_JSON
# @TEST_EDGE: valid_repository -> API persists a run only for an existing repository.
# @TEST_EDGE: invalid_repository -> API returns 422 without weakening production validation.
from __future__ import annotations
from src.models.agent_run import AgentRun
# #region Test.Api.DashboardTesting.VerificationApi.Create [C:3] [TYPE Class] [SEMANTICS test,api,verification-runs,http,persistence]
# @BRIEF HTTP-level verification-run creation exercises the API database fixture.
# @RELATION VERIFIES -> [Api.DashboardTesting.CreateVerificationRun]
class TestVerificationRunApi:
# #region Test.Api.DashboardTesting.VerificationApi.Test201Persistence [C:2] [TYPE Function]
# @BRIEF POST with real repository and agent-run foreign keys persists a verification record.
def test_create_verification_run_201_and_persistence(
self,
dashboard_testing_client,
dashboard_testing_verification_repository_id: str,
):
from src.core.database import SessionLocal
from src.models.verification_run import VerificationRunRecord
setup_session = SessionLocal()
try:
run = AgentRun(
user_id="test-user",
intent="dashboard_scenario_build",
trigger="manual",
dashboard_id="42",
environment_id="dev",
context_snapshot={"test": True},
)
setup_session.add(run)
setup_session.commit()
run_id = run.id
finally:
setup_session.close()
response = dashboard_testing_client.post(
"/api/dashboard-testing/verification-runs",
json={
"repository_id": dashboard_testing_verification_repository_id,
"trigger": "manual",
"environment_id": "dev",
"categories": ["structure"],
"evidence_refs": {"structure": ["ev://s/diff-abc"]},
"agent_run_id": run_id,
},
)
assert response.status_code == 201, response.text
data = response.json()
assert data["overall_status"] == "inconclusive"
outcome = data["category_outcomes"][0]
assert outcome["category"] == "structure"
assert outcome["status"] == "inconclusive"
assert outcome["evidence_refs"] == ["ev://s/diff-abc"]
verify_session = SessionLocal()
try:
record = verify_session.get(VerificationRunRecord, data["id"])
assert record is not None
assert record.repository_id == dashboard_testing_verification_repository_id
assert record.agent_run_id == run_id
finally:
verify_session.close()
# #endregion Test.Api.DashboardTesting.VerificationApi.Test201Persistence
# #region Test.Api.DashboardTesting.VerificationApi.Test422BadTrigger [C:2] [TYPE Function]
# @BRIEF Invalid request literals are rejected by request validation before persistence.
def test_create_verification_run_422_bad_trigger(
self, dashboard_testing_client, dashboard_testing_verification_repository_id: str
):
response = dashboard_testing_client.post(
"/api/dashboard-testing/verification-runs",
json={
"repository_id": dashboard_testing_verification_repository_id,
"trigger": "not_a_valid_trigger",
"environment_id": "dev",
"categories": ["metric"],
},
)
assert response.status_code == 422
# #endregion Test.Api.DashboardTesting.VerificationApi.Test422BadTrigger
# #region Test.Api.DashboardTesting.VerificationApi.Test422MissingAgentRun [C:2] [TYPE Function]
# @BRIEF Nonexistent agent-run references return the production validation error.
def test_create_verification_run_422_invalid_agent_run(
self, dashboard_testing_client, dashboard_testing_verification_repository_id: str
):
response = dashboard_testing_client.post(
"/api/dashboard-testing/verification-runs",
json={
"repository_id": dashboard_testing_verification_repository_id,
"trigger": "manual",
"environment_id": "dev",
"categories": ["metric"],
"evidence_refs": {"metric": ["ev://m/1"]},
"agent_run_id": "00000000-0000-0000-0000-000000000000",
},
)
assert response.status_code == 422
assert "agent_run_id" in response.json()["detail"]
# #endregion Test.Api.DashboardTesting.VerificationApi.Test422MissingAgentRun
# #region Test.Api.DashboardTesting.VerificationApi.TestBlockedUnsupported [C:2] [TYPE Function]
# @BRIEF Unsupported categories remain blocked after repository validation succeeds.
def test_blocked_unsupported_category_via_api(
self, dashboard_testing_client, dashboard_testing_verification_repository_id: str
):
response = dashboard_testing_client.post(
"/api/dashboard-testing/verification-runs",
json={
"repository_id": dashboard_testing_verification_repository_id,
"trigger": "scheduled",
"environment_id": "prod",
"categories": ["content_integrity"],
},
)
assert response.status_code == 201, response.text
outcome = response.json()["category_outcomes"][0]
assert outcome["status"] == "blocked"
assert "no executor" in outcome["summary"].lower()
# #endregion Test.Api.DashboardTesting.VerificationApi.TestBlockedUnsupported
# #region Test.Api.DashboardTesting.VerificationApi.TestEvidenceOnly [C:2] [TYPE Function]
# @BRIEF Evidence-only categories are inconclusive rather than fabricated passes.
def test_evidence_only_inconclusive_via_api(
self, dashboard_testing_client, dashboard_testing_verification_repository_id: str
):
response = dashboard_testing_client.post(
"/api/dashboard-testing/verification-runs",
json={
"repository_id": dashboard_testing_verification_repository_id,
"trigger": "release_publish",
"environment_id": "staging",
"categories": ["xlsx"],
"evidence_refs": {"xlsx": ["s3://bucket/report.xlsx"]},
},
)
assert response.status_code == 201, response.text
outcome = response.json()["category_outcomes"][0]
assert outcome["status"] == "inconclusive"
assert outcome["evidence_refs"] == ["s3://bucket/report.xlsx"]
# #endregion Test.Api.DashboardTesting.VerificationApi.TestEvidenceOnly
# #region Test.Api.DashboardTesting.VerificationApi.TestStructureBlocked [C:2] [TYPE Function]
# @BRIEF Structure execution without evidence or parameters remains blocked.
def test_structure_blocked_without_evidence_via_api(
self, dashboard_testing_client, dashboard_testing_verification_repository_id: str
):
response = dashboard_testing_client.post(
"/api/dashboard-testing/verification-runs",
json={
"repository_id": dashboard_testing_verification_repository_id,
"trigger": "deploy_to_preprod",
"environment_id": "dev",
"categories": ["structure"],
},
)
assert response.status_code == 201, response.text
outcome = response.json()["category_outcomes"][0]
assert outcome["status"] == "blocked"
assert "evidence_refs" in outcome["summary"]
# #endregion Test.Api.DashboardTesting.VerificationApi.TestStructureBlocked
# #endregion Test.Api.DashboardTesting.VerificationApi.Create
# #endregion Test.Api.DashboardTesting.VerificationApi