Files
ModelForge-Public/backend/tests/test_selected_replacement.py
T

146 lines
6.6 KiB
Python

from uuid import uuid4
import pytest
from sqlalchemy import event, select
from modelforge_api.persistence.models import (
CapabilityContract,
ProductionExecutionApproval,
Project,
ProjectBinding,
SelectedModelComparison,
)
from modelforge_api.services.lifecycle import LifecycleError
from modelforge_api.services.selected_replacement import SelectedReplacementService
from tests.test_lifecycle_serving import serving_pair
__all__ = ["serving_pair"]
def _preview(pair):
return SelectedReplacementService(pair[0]).preview(next(iter(pair[4].comparison_ids.values())))
def test_preview_derives_exact_selection_without_writes_or_satisfied_claim(serving_pair):
session, _, current, candidate, selection, _ = serving_pair
statements = []
def observe(_conn, _cursor, statement, _parameters, _context, _many):
statements.append(statement.lstrip().split(None, 1)[0].upper())
event.listen(session.get_bind(), "before_cursor_execute", observe)
try:
result = _preview(serving_pair)
finally:
event.remove(session.get_bind(), "before_cursor_execute", observe)
assert result.selection == selection
assert result.route_generation == session.get(CapabilityContract, current.capability_contract_id).serving_generation
assert result.same_embedding_space and result.affected_bindings[0].eligible
assert result.production_approvals[0].id == selection.production_approval_id
assert [item.code for item in result.blockers] == ["PRODUCTION_VALIDATION_REVIEW_REQUIRED"]
assert result.production_promotion_performed is False
assert result.model_dump().get("production_validation") is None
assert not set(statements) & {"INSERT", "UPDATE", "DELETE", "TRUNCATE"}
assert current.status == "stable" and candidate.production is False
assert not session.new and not session.dirty and not session.deleted
def test_preview_lists_other_affected_project_as_blocker(serving_pair):
session, _, current, _, _, _ = serving_pair
project = Project(key="unreviewed", name="Unreviewed", description="test")
session.add(project)
session.flush()
binding = ProjectBinding(project_id=project.id, capability_contract_id=current.capability_contract_id,
channel="stable", priority="production")
session.add(binding)
session.commit()
result = _preview(serving_pair)
assert len(result.affected_bindings) == 2
assert result.selection is None
assert any(item.code == "BINDING_COMPARISON_REQUIRED" and item.project_binding_id == binding.id for item in result.blockers)
@pytest.mark.parametrize("mutation,expected", [
("incomplete", "COMPARISON_NOT_COMPLETED"),
("different-space", "SERVING_REINDEX_REQUIRED"),
("revoked", "PRODUCTION_APPROVAL_REQUIRED"),
("changed-route", "SERVING_SELECTION_INVALID"),
])
def test_preview_blocks_missing_execution_identity_or_authority(serving_pair, mutation, expected):
session, serving, current, candidate, selection, _ = serving_pair
if mutation == "incomplete":
session.get(SelectedModelComparison, next(iter(selection.comparison_ids.values()))).status = "interrupted"
elif mutation == "different-space":
candidate.embedding_space_id = None
elif mutation == "revoked":
serving.repo.approval(selection.production_approval_id).status = "revoked"
else:
current.status = "draining"
session.commit()
result = _preview(serving_pair)
assert result.selection is None
assert expected in {item.code for item in result.blockers}
def test_missing_comparison_is_not_found(serving_pair):
with pytest.raises(LifecycleError) as error:
SelectedReplacementService(serving_pair[0]).preview(uuid4())
assert error.value.status_code == 404
def test_latest_negative_project_fit_remains_visible_blocker(serving_pair):
from tests.test_lifecycle_serving import _fit
_fit(serving_pair, recommendation="KEEP_LAB", production_validation="DEFERRED_EXTERNAL_VALIDATION")
result = _preview(serving_pair)
assert result.selection is None
assert any(item.code == "SERVING_PROJECT_FIT_BLOCKED" for item in result.blockers)
assert serving_pair[0].scalar(select(CapabilityContract.serving_generation)) == result.route_generation
def test_stale_historical_approval_does_not_hide_valid_choice(serving_pair):
session, _, _, _, selection, _ = serving_pair
valid = session.get(ProductionExecutionApproval, selection.production_approval_id)
stale = ProductionExecutionApproval(**{
column.name: getattr(valid, column.name)
for column in ProductionExecutionApproval.__table__.columns
if column.name not in {"id", "evidence_fingerprint"}
}, evidence_fingerprint="f" * 64)
session.add(stale)
session.commit()
result = _preview(serving_pair)
assert result.selection == selection
assert [item.id for item in result.production_approvals] == [valid.id]
assert [item.code for item in result.blockers] == ["PRODUCTION_VALIDATION_REVIEW_REQUIRED"]
def test_actual_app_preview_requires_operator_auth_and_disables_cache(serving_pair, monkeypatch):
from fastapi.testclient import TestClient
from pydantic import SecretStr
from modelforge_api.db import get_session
from modelforge_api.main import app
from modelforge_api.settings import Settings, get_settings
token = "preview-offline-operator-test" # noqa: S105 - isolated test credential
configured = Settings(_env_file=None, operator_api_key=SecretStr(token))
previous = dict(app.dependency_overrides)
# SQLite fixture connections are thread-bound; qualify the real service above,
# then exercise middleware, dependencies and response serialization in TestClient.
result = _preview(serving_pair)
monkeypatch.setattr(SelectedReplacementService, "preview", lambda self, comparison_id: result)
app.dependency_overrides[get_session] = lambda: serving_pair[0]
app.dependency_overrides[get_settings] = lambda: configured
path = f"/api/v1/selected-model-comparisons/{next(iter(serving_pair[4].comparison_ids.values()))}/replacement-preview"
try:
client = TestClient(app)
assert client.get(path).status_code == 401
response = client.get(path, headers={"X-ModelForge-Admin-Token": token})
assert response.status_code == 200, response.text
assert response.headers["Cache-Control"] == "no-store"
assert response.json()["selection"]["candidate_deployment_id"] == str(serving_pair[3].id)
assert response.json()["production_promotion_performed"] is False
finally:
app.dependency_overrides.clear()
app.dependency_overrides.update(previous)