Spaces:
Build error
Build error
| import pytest | |
| import datetime | |
| from unittest.mock import MagicMock | |
| from sqlalchemy import create_engine | |
| from sqlalchemy.orm import sessionmaker | |
| from app.database.base import Base | |
| from app.database.models_intents import IntentDB | |
| from app.services.outcome_service import record_outcome, OutcomeConflictError | |
| from agentic_reliability_framework.core.governance.intents import ( | |
| ProvisionResourceIntent, | |
| ResourceType, | |
| ) | |
| def db_session(): | |
| engine = create_engine("sqlite:///:memory:", future=True) | |
| TestingSessionLocal = sessionmaker(bind=engine, future=True) | |
| Base.metadata.create_all(bind=engine) | |
| sess = TestingSessionLocal() | |
| yield sess | |
| sess.close() | |
| def mock_risk_engine(): | |
| engine = MagicMock() | |
| engine.update_outcome = MagicMock() | |
| return engine | |
| def test_record_outcome_creates_row_and_updates_engine( | |
| db_session, mock_risk_engine): | |
| oss_intent = ProvisionResourceIntent( | |
| resource_type=ResourceType.VM, | |
| region="eastus", | |
| size="Standard", | |
| environment="dev", | |
| requester="test_user" | |
| ) | |
| oss_payload = oss_intent.model_dump(mode='json') | |
| intent = IntentDB( | |
| deterministic_id="intent_abc", | |
| intent_type="ProvisionResourceIntent", | |
| payload={}, | |
| oss_payload=oss_payload, | |
| created_at=datetime.datetime.utcnow() | |
| ) | |
| db_session.add(intent) | |
| db_session.commit() | |
| db_session.refresh(intent) | |
| outcome = record_outcome( | |
| db=db_session, | |
| deterministic_id="intent_abc", | |
| success=True, | |
| recorded_by="tester", | |
| notes="works", | |
| risk_engine=mock_risk_engine, | |
| idempotency_key="key123" | |
| ) | |
| assert outcome.success is True | |
| assert outcome.recorded_by == "tester" | |
| assert outcome.idempotency_key == "key123" | |
| mock_risk_engine.update_outcome.assert_called_once() | |
| # Idempotent call with same key should return existing outcome and not | |
| # call engine again | |
| outcome2 = record_outcome( | |
| db=db_session, | |
| deterministic_id="intent_abc", | |
| success=True, | |
| recorded_by="tester", | |
| notes="again", | |
| risk_engine=mock_risk_engine, | |
| idempotency_key="key123" | |
| ) | |
| assert outcome2.id == outcome.id | |
| mock_risk_engine.update_outcome.assert_called_once() # still once | |
| def test_conflict_different_result(db_session, mock_risk_engine): | |
| intent = IntentDB( | |
| deterministic_id="intent_def", | |
| intent_type="ProvisionResourceIntent", | |
| payload={}, | |
| created_at=datetime.datetime.utcnow() | |
| ) | |
| db_session.add(intent) | |
| db_session.commit() | |
| record_outcome( | |
| db_session, | |
| "intent_def", | |
| True, | |
| None, | |
| None, | |
| mock_risk_engine) | |
| with pytest.raises(OutcomeConflictError): | |
| record_outcome( | |
| db_session, | |
| "intent_def", | |
| False, | |
| None, | |
| None, | |
| mock_risk_engine) | |
| def test_nonexistent_intent(db_session, mock_risk_engine): | |
| with pytest.raises(ValueError): | |
| record_outcome( | |
| db_session, | |
| "missing", | |
| True, | |
| None, | |
| None, | |
| mock_risk_engine) | |
| def test_record_outcome_reconstruction_failure_does_not_update_engine( | |
| db_session, mock_risk_engine): | |
| # Create an intent with invalid oss_payload (missing required fields) | |
| intent = IntentDB( | |
| deterministic_id="intent_bad", | |
| intent_type="ProvisionResourceIntent", | |
| payload={}, | |
| oss_payload={"intent_type": "provision_resource"}, # missing fields | |
| created_at=datetime.datetime.utcnow() | |
| ) | |
| db_session.add(intent) | |
| db_session.commit() | |
| # This should NOT call risk_engine.update_outcome (no dummy fallback) | |
| outcome = record_outcome( | |
| db=db_session, | |
| deterministic_id="intent_bad", | |
| success=True, | |
| recorded_by="tester", | |
| notes="fallback test", | |
| risk_engine=mock_risk_engine | |
| ) | |
| assert outcome.success is True | |
| # The engine should NOT be updated because reconstruction failed | |
| mock_risk_engine.update_outcome.assert_not_called() | |