- 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
172 lines
7.8 KiB
Python
172 lines
7.8 KiB
Python
# #region Test.Api.DashboardTesting.Inheritance [C:4] [TYPE Module] [SEMANTICS testing,api,dashboard-testing,inheritance]
|
|
# @defgroup API contract tests for baseline inheritance endpoints — plan and execute.
|
|
# @LAYER Test
|
|
# @RELATION VERIFIES -> [Api.DashboardTesting.Inheritance]
|
|
# @TEST_INVARIANT POST /inheritance/plan returns plan with correct counts.
|
|
# @TEST_INVARIANT POST /inheritance/plan rejects same release IDs.
|
|
# @TEST_INVARIANT POST /inheritance/execute requires valid plan_id.
|
|
# @TEST_INVARIANT POST /inheritance/plan rejects missing releases.
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from unittest.mock import MagicMock, patch
|
|
from uuid import uuid4
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from src.app import app
|
|
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.Fixtures [C:1] [TYPE Class] [SEMANTICS testing,api,dashboard-testing,inheritance,fixtures]
|
|
@pytest.fixture
|
|
def inheritance_client() -> TestClient:
|
|
"""Provide TestClient without auth dependency overrides."""
|
|
from src.dependencies import get_current_user
|
|
from src.models.auth import Role, User
|
|
|
|
admin_role = Role(id="admin-role-test-001", name="Admin", is_admin=True)
|
|
user = User(id="test-user-inheritance", username="tester", email="tester@test.com")
|
|
user.roles = [admin_role]
|
|
app.dependency_overrides[get_current_user] = lambda: user
|
|
try:
|
|
yield TestClient(app)
|
|
finally:
|
|
app.dependency_overrides.pop(get_current_user, None)
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.Fixtures
|
|
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.RouterRegistration [C:2] [TYPE Function] [SEMANTICS testing,api,dashboard-testing,inheritance,registration]
|
|
# @BRIEF The inheritance router is registered and accessible.
|
|
def test_inheritance_routes_registered():
|
|
"""Inheritance plan and execute routes are registered in the router."""
|
|
from src.api.routes.dashboard_testing import router
|
|
|
|
paths = [
|
|
route.path for route in router.routes
|
|
if hasattr(route, "path") and "inheritance" in route.path
|
|
]
|
|
assert "/api/dashboard-testing/inheritance/plan" in paths
|
|
assert "/api/dashboard-testing/inheritance/execute" in paths
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.RouterRegistration
|
|
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.PlanEndpoint [C:3] [TYPE Class] [SEMANTICS testing,api,dashboard-testing,inheritance,plan]
|
|
class TestInheritancePlanEndpoint:
|
|
"""Tests for POST /api/dashboard-testing/inheritance/plan."""
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.PlanEndpoint.SameReleaseIds [C:2] [TYPE Function]
|
|
# @TEST_EDGE: Same prior and current release ID returns 422
|
|
def test_same_release_ids_rejected(self, inheritance_client: TestClient):
|
|
"""plan endpoint rejects request where prior_release_id == current_release_id."""
|
|
release_id = str(uuid4())
|
|
response = inheritance_client.post(
|
|
"/api/dashboard-testing/inheritance/plan",
|
|
json={
|
|
"prior_release_id": release_id,
|
|
"current_release_id": release_id,
|
|
},
|
|
)
|
|
assert response.status_code == 422, f"Expected 422, got {response.status_code}: {response.text}"
|
|
assert "must differ" in response.text
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.PlanEndpoint.SameReleaseIds
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.PlanEndpoint.MissingReleases [C:2] [TYPE Function]
|
|
# @TEST_EDGE: Missing releases return 404
|
|
def test_missing_prior_release_returns_404(self, inheritance_client: TestClient):
|
|
"""plan endpoint returns 404 when prior release does not exist."""
|
|
response = inheritance_client.post(
|
|
"/api/dashboard-testing/inheritance/plan",
|
|
json={
|
|
"prior_release_id": "nonexistent-prior",
|
|
"current_release_id": "nonexistent-current",
|
|
},
|
|
)
|
|
assert response.status_code == 404, f"Expected 404, got {response.status_code}: {response.text}"
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.PlanEndpoint.MissingReleases
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.PlanEndpoint.Success [C:2] [TYPE Function]
|
|
# @TEST_EDGE: Successful plan returns InheritancePlanResponse with counts
|
|
@patch("src.api.routes.dashboard_testing.inheritance.plan_inheritance")
|
|
@patch("src.api.routes.dashboard_testing.inheritance.build_plan_response")
|
|
def test_successful_plan(
|
|
self,
|
|
mock_build_response: MagicMock,
|
|
mock_plan: MagicMock,
|
|
inheritance_client: TestClient,
|
|
):
|
|
"""Successful plan endpoint returns InheritancePlanResponse."""
|
|
from src.schemas.dashboard_testing.inheritance import InheritancePlanResponse
|
|
|
|
mock_plan.return_value = MagicMock()
|
|
mock_build_response.return_value = InheritancePlanResponse(
|
|
plan_id="test-plan-1",
|
|
prior_release_id="prior-uuid",
|
|
current_release_id="current-uuid",
|
|
inherited_count=3,
|
|
changed_count=1,
|
|
new_count=0,
|
|
entries=[],
|
|
)
|
|
|
|
response = inheritance_client.post(
|
|
"/api/dashboard-testing/inheritance/plan",
|
|
json={
|
|
"prior_release_id": "prior-uuid",
|
|
"current_release_id": "current-uuid",
|
|
},
|
|
)
|
|
assert response.status_code == 200, f"Expected 200, got {response.status_code}: {response.text}"
|
|
data = response.json()
|
|
assert data["plan_id"] == "test-plan-1"
|
|
assert data["inherited_count"] == 3
|
|
assert data["changed_count"] == 1
|
|
assert data["new_count"] == 0
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.PlanEndpoint.Success
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.PlanEndpoint
|
|
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.ExecuteEndpoint [C:3] [TYPE Class] [SEMANTICS testing,api,dashboard-testing,inheritance,execute]
|
|
class TestInheritanceExecuteEndpoint:
|
|
"""Tests for POST /api/dashboard-testing/inheritance/execute."""
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.ExecuteEndpoint.InvalidPlanId [C:2] [TYPE Function]
|
|
# @TEST_EDGE: Invalid plan_id returns 400
|
|
def test_invalid_plan_id_returns_400(self, inheritance_client: TestClient):
|
|
"""execute endpoint returns 400 for invalid plan_id."""
|
|
response = inheritance_client.post(
|
|
"/api/dashboard-testing/inheritance/execute",
|
|
json={
|
|
"plan_id": "invalid-plan",
|
|
"target_environment_id": "ss-preprod",
|
|
},
|
|
)
|
|
assert response.status_code == 400, f"Expected 400, got {response.status_code}: {response.text}"
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.ExecuteEndpoint.InvalidPlanId
|
|
|
|
# #region Test.Api.DashboardTesting.Inheritance.ExecuteEndpoint.MissingTargetEnv [C:2] [TYPE Function]
|
|
# @TEST_EDGE: Missing target environment returns 404
|
|
@patch("src.api.routes.dashboard_testing.inheritance.get_config_manager")
|
|
def test_missing_target_env_returns_404(
|
|
self,
|
|
mock_config: MagicMock,
|
|
inheritance_client: TestClient,
|
|
):
|
|
"""execute endpoint returns 404 for unknown target environment."""
|
|
mock_mgr = MagicMock()
|
|
mock_mgr.get_environment.return_value = None
|
|
mock_config.return_value = mock_mgr
|
|
|
|
response = inheritance_client.post(
|
|
"/api/dashboard-testing/inheritance/execute",
|
|
json={
|
|
"plan_id": "prior-uuid:current-uuid",
|
|
"target_environment_id": "nonexistent-env",
|
|
},
|
|
)
|
|
assert response.status_code == 404, f"Expected 404, got {response.status_code}: {response.text}"
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.ExecuteEndpoint.MissingTargetEnv
|
|
# #endregion Test.Api.DashboardTesting.Inheritance.ExecuteEndpoint
|
|
|
|
# #endregion Test.Api.DashboardTesting.Inheritance
|