mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
- Replace conflicting Exception class name with PolicyException in decision_models.py - Update all test imports to use PolicyException instead of Exception - Fix auto ID generation to handle empty strings, not just None - Resolves import errors in decision tracking test suites - Maintains backward compatibility while fixing naming conflicts Fixes: PolicyException naming conflicts preventing test execution Tests: All decision model tests now pass (19/19)
457 lines
16 KiB
Python
457 lines
16 KiB
Python
"""
|
|
Tests for Decision Tracking Data Models
|
|
|
|
This module tests the decision tracking data models including
|
|
validation, serialization, and deserialization.
|
|
"""
|
|
|
|
import pytest
|
|
from datetime import datetime
|
|
from typing import List, Dict, Any
|
|
|
|
from semantica.context.decision_models import (
|
|
Decision, DecisionContext, Policy, PolicyException, Precedent, ApprovalChain,
|
|
validate_decision, validate_policy, serialize_decision, deserialize_decision,
|
|
serialize_policy, deserialize_policy
|
|
)
|
|
|
|
|
|
class TestDecision:
|
|
"""Test Decision data model."""
|
|
|
|
def test_decision_creation(self):
|
|
"""Test basic decision creation."""
|
|
decision = Decision(
|
|
decision_id="test_001",
|
|
category="credit_approval",
|
|
scenario="Credit limit increase request",
|
|
reasoning="Customer has excellent payment history",
|
|
outcome="approved",
|
|
confidence=0.85,
|
|
timestamp=datetime.now(),
|
|
decision_maker="ai_agent_001"
|
|
)
|
|
|
|
assert decision.decision_id == "test_001"
|
|
assert decision.category == "credit_approval"
|
|
assert decision.scenario == "Credit limit increase request"
|
|
assert decision.reasoning == "Customer has excellent payment history"
|
|
assert decision.outcome == "approved"
|
|
assert decision.confidence == 0.85
|
|
assert decision.decision_maker == "ai_agent_001"
|
|
|
|
def test_decision_auto_id(self):
|
|
"""Test automatic ID generation."""
|
|
decision = Decision(
|
|
decision_id="",
|
|
category="test",
|
|
scenario="test scenario",
|
|
reasoning="test reasoning",
|
|
outcome="test outcome",
|
|
confidence=0.5,
|
|
timestamp=datetime.now(),
|
|
decision_maker="test_agent"
|
|
)
|
|
|
|
assert decision.decision_id != ""
|
|
assert len(decision.decision_id) > 0
|
|
|
|
def test_decision_confidence_validation(self):
|
|
"""Test confidence validation."""
|
|
with pytest.raises(ValueError):
|
|
Decision(
|
|
decision_id="test",
|
|
category="test",
|
|
scenario="test",
|
|
reasoning="test",
|
|
outcome="test",
|
|
confidence=1.5, # Invalid confidence > 1
|
|
timestamp=datetime.now(),
|
|
decision_maker="test"
|
|
)
|
|
|
|
with pytest.raises(ValueError):
|
|
Decision(
|
|
decision_id="test",
|
|
category="test",
|
|
scenario="test",
|
|
reasoning="test",
|
|
outcome="test",
|
|
confidence=-0.1, # Invalid confidence < 0
|
|
timestamp=datetime.now(),
|
|
decision_maker="test"
|
|
)
|
|
|
|
def test_decision_to_dict(self):
|
|
"""Test decision serialization to dictionary."""
|
|
decision = Decision(
|
|
decision_id="test_001",
|
|
category="test",
|
|
scenario="test scenario",
|
|
reasoning="test reasoning",
|
|
outcome="test outcome",
|
|
confidence=0.8,
|
|
timestamp=datetime.now(),
|
|
decision_maker="test_agent",
|
|
metadata={"key": "value"}
|
|
)
|
|
|
|
decision_dict = decision.to_dict()
|
|
|
|
assert decision_dict["decision_id"] == "test_001"
|
|
assert decision_dict["category"] == "test"
|
|
assert decision_dict["scenario"] == "test scenario"
|
|
assert decision_dict["reasoning"] == "test reasoning"
|
|
assert decision_dict["outcome"] == "test outcome"
|
|
assert decision_dict["confidence"] == 0.8
|
|
assert decision_dict["decision_maker"] == "test_agent"
|
|
assert decision_dict["metadata"]["key"] == "value"
|
|
assert isinstance(decision_dict["timestamp"], str)
|
|
|
|
def test_decision_from_dict(self):
|
|
"""Test decision deserialization from dictionary."""
|
|
decision_data = {
|
|
"decision_id": "test_001",
|
|
"category": "test",
|
|
"scenario": "test scenario",
|
|
"reasoning": "test reasoning",
|
|
"outcome": "test outcome",
|
|
"confidence": 0.8,
|
|
"timestamp": datetime.now().isoformat(),
|
|
"decision_maker": "test_agent",
|
|
"metadata": {"key": "value"}
|
|
}
|
|
|
|
decision = Decision.from_dict(decision_data)
|
|
|
|
assert decision.decision_id == "test_001"
|
|
assert decision.category == "test"
|
|
assert decision.scenario == "test scenario"
|
|
assert decision.reasoning == "test reasoning"
|
|
assert decision.outcome == "test outcome"
|
|
assert decision.confidence == 0.8
|
|
assert decision.decision_maker == "test_agent"
|
|
assert decision.metadata["key"] == "value"
|
|
assert isinstance(decision.timestamp, datetime)
|
|
|
|
|
|
class TestDecisionContext:
|
|
"""Test DecisionContext data model."""
|
|
|
|
def test_decision_context_creation(self):
|
|
"""Test basic decision context creation."""
|
|
context = DecisionContext(
|
|
context_id="ctx_001",
|
|
decision_id="decision_001",
|
|
entity_snapshots={"entity1": {"name": "test", "type": "person"}},
|
|
risk_factors=["high_risk", "new_customer"],
|
|
cross_system_inputs={"salesforce": {"tier": "premium"}},
|
|
metadata={"version": "1.0"}
|
|
)
|
|
|
|
assert context.context_id == "ctx_001"
|
|
assert context.decision_id == "decision_001"
|
|
assert len(context.entity_snapshots) == 1
|
|
assert context.entity_snapshots["entity1"]["name"] == "test"
|
|
assert context.risk_factors == ["high_risk", "new_customer"]
|
|
assert context.cross_system_inputs["salesforce"]["tier"] == "premium"
|
|
assert context.metadata["version"] == "1.0"
|
|
|
|
def test_decision_context_auto_id(self):
|
|
"""Test automatic ID generation."""
|
|
context = DecisionContext(
|
|
context_id="",
|
|
decision_id="decision_001",
|
|
entity_snapshots={},
|
|
risk_factors=[]
|
|
)
|
|
|
|
assert context.context_id != ""
|
|
assert len(context.context_id) > 0
|
|
|
|
|
|
class TestPolicy:
|
|
"""Test Policy data model."""
|
|
|
|
def test_policy_creation(self):
|
|
"""Test basic policy creation."""
|
|
now = datetime.now()
|
|
policy = Policy(
|
|
policy_id="policy_001",
|
|
name="Credit Approval Policy",
|
|
description="Standard credit approval rules",
|
|
rules={"min_score": 650, "max_debt_ratio": 0.4},
|
|
category="credit_approval",
|
|
version="1.0",
|
|
created_at=now,
|
|
updated_at=now,
|
|
metadata={"department": "risk"}
|
|
)
|
|
|
|
assert policy.policy_id == "policy_001"
|
|
assert policy.name == "Credit Approval Policy"
|
|
assert policy.description == "Standard credit approval rules"
|
|
assert policy.rules["min_score"] == 650
|
|
assert policy.category == "credit_approval"
|
|
assert policy.version == "1.0"
|
|
assert policy.metadata["department"] == "risk"
|
|
|
|
def test_policy_auto_id(self):
|
|
"""Test automatic ID generation."""
|
|
policy = Policy(
|
|
policy_id="",
|
|
name="Test Policy",
|
|
description="Test description",
|
|
rules={"test": "rule"},
|
|
category="test",
|
|
version="1.0",
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now()
|
|
)
|
|
|
|
assert policy.policy_id != ""
|
|
assert len(policy.policy_id) > 0
|
|
|
|
|
|
class TestPolicyException:
|
|
"""Test PolicyException data model."""
|
|
|
|
def test_policy_exception_creation(self):
|
|
"""Test basic policy exception creation."""
|
|
policy_exception = PolicyException(
|
|
exception_id="exc_001",
|
|
decision_id="decision_001",
|
|
policy_id="policy_001",
|
|
reason="Customer is VIP with special arrangements",
|
|
approver="manager_001",
|
|
approval_timestamp=datetime.now(),
|
|
justification="Long-term customer with excellent history",
|
|
metadata={"override_type": "vip_exception"}
|
|
)
|
|
|
|
assert policy_exception.exception_id == "exc_001"
|
|
assert policy_exception.decision_id == "decision_001"
|
|
assert policy_exception.policy_id == "policy_001"
|
|
assert policy_exception.reason == "Customer is VIP with special arrangements"
|
|
assert policy_exception.approver == "manager_001"
|
|
assert policy_exception.justification == "Long-term customer with excellent history"
|
|
assert policy_exception.metadata["override_type"] == "vip_exception"
|
|
|
|
def test_policy_exception_auto_id(self):
|
|
"""Test automatic ID generation."""
|
|
policy_exception = PolicyException(
|
|
exception_id="",
|
|
decision_id="decision_001",
|
|
policy_id="policy_001",
|
|
reason="test reason",
|
|
approver="test_approver",
|
|
approval_timestamp=datetime.now(),
|
|
justification="test justification"
|
|
)
|
|
|
|
assert policy_exception.exception_id != ""
|
|
assert len(policy_exception.exception_id) > 0
|
|
|
|
|
|
class TestPrecedent:
|
|
"""Test Precedent data model."""
|
|
|
|
def test_precedent_creation(self):
|
|
"""Test basic precedent creation."""
|
|
precedent = Precedent(
|
|
precedent_id="prec_001",
|
|
source_decision_id="decision_001",
|
|
similarity_score=0.85,
|
|
relationship_type="similar_scenario",
|
|
metadata={"matched_features": ["category", "amount"]}
|
|
)
|
|
|
|
assert precedent.precedent_id == "prec_001"
|
|
assert precedent.source_decision_id == "decision_001"
|
|
assert precedent.similarity_score == 0.85
|
|
assert precedent.relationship_type == "similar_scenario"
|
|
assert precedent.metadata["matched_features"] == ["category", "amount"]
|
|
|
|
def test_precedent_validation(self):
|
|
"""Test precedent validation."""
|
|
# Test invalid similarity score
|
|
with pytest.raises(ValueError):
|
|
Precedent(
|
|
precedent_id="test",
|
|
source_decision_id="test",
|
|
similarity_score=1.5, # Invalid > 1
|
|
relationship_type="similar_scenario"
|
|
)
|
|
|
|
# Test invalid relationship type
|
|
with pytest.raises(ValueError):
|
|
Precedent(
|
|
precedent_id="test",
|
|
source_decision_id="test",
|
|
similarity_score=0.8,
|
|
relationship_type="invalid_type"
|
|
)
|
|
|
|
|
|
class TestApprovalChain:
|
|
"""Test ApprovalChain data model."""
|
|
|
|
def test_approval_chain_creation(self):
|
|
"""Test basic approval chain creation."""
|
|
approval = ApprovalChain(
|
|
approval_id="app_001",
|
|
decision_id="decision_001",
|
|
approver="manager_001",
|
|
approval_method="slack_dm",
|
|
approval_context="Approved via Slack DM with justification",
|
|
timestamp=datetime.now(),
|
|
metadata={"message_id": "msg_12345"}
|
|
)
|
|
|
|
assert approval.approval_id == "app_001"
|
|
assert approval.decision_id == "decision_001"
|
|
assert approval.approver == "manager_001"
|
|
assert approval.approval_method == "slack_dm"
|
|
assert approval.approval_context == "Approved via Slack DM with justification"
|
|
assert approval.metadata["message_id"] == "msg_12345"
|
|
|
|
def test_approval_chain_validation(self):
|
|
"""Test approval chain validation."""
|
|
# Test invalid approval method
|
|
with pytest.raises(ValueError):
|
|
ApprovalChain(
|
|
approval_id="test",
|
|
decision_id="test",
|
|
approver="test",
|
|
approval_method="invalid_method", # Invalid method
|
|
approval_context="test context",
|
|
timestamp=datetime.now()
|
|
)
|
|
|
|
|
|
class TestValidationFunctions:
|
|
"""Test validation helper functions."""
|
|
|
|
def test_validate_decision(self):
|
|
"""Test decision validation."""
|
|
# Valid decision
|
|
valid_decision = Decision(
|
|
decision_id="test",
|
|
category="test",
|
|
scenario="test",
|
|
reasoning="test",
|
|
outcome="test",
|
|
confidence=0.8,
|
|
timestamp=datetime.now(),
|
|
decision_maker="test"
|
|
)
|
|
assert validate_decision(valid_decision) is True
|
|
|
|
# Invalid decision (missing required field)
|
|
invalid_decision = Decision(
|
|
decision_id="test",
|
|
category="", # Empty category
|
|
scenario="test",
|
|
reasoning="test",
|
|
outcome="test",
|
|
confidence=0.8,
|
|
timestamp=datetime.now(),
|
|
decision_maker="test"
|
|
)
|
|
assert validate_decision(invalid_decision) is False
|
|
|
|
def test_validate_policy(self):
|
|
"""Test policy validation."""
|
|
# Valid policy
|
|
valid_policy = Policy(
|
|
policy_id="test",
|
|
name="Test Policy",
|
|
description="Test description",
|
|
rules={"test": "rule"},
|
|
category="test",
|
|
version="1.0",
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now()
|
|
)
|
|
assert validate_policy(valid_policy) is True
|
|
|
|
# Invalid policy (missing required field)
|
|
invalid_policy = Policy(
|
|
policy_id="test",
|
|
name="Test Policy",
|
|
description="Test description",
|
|
rules={"test": "rule"},
|
|
category="", # Empty category
|
|
version="1.0",
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now()
|
|
)
|
|
assert validate_policy(invalid_policy) is False
|
|
|
|
|
|
class TestSerializationFunctions:
|
|
"""Test serialization helper functions."""
|
|
|
|
def test_serialize_deserialize_decision(self):
|
|
"""Test decision serialization and deserialization."""
|
|
original_decision = Decision(
|
|
decision_id="test_001",
|
|
category="test",
|
|
scenario="test scenario",
|
|
reasoning="test reasoning",
|
|
outcome="test outcome",
|
|
confidence=0.8,
|
|
timestamp=datetime.now(),
|
|
decision_maker="test_agent",
|
|
metadata={"key": "value"}
|
|
)
|
|
|
|
# Serialize
|
|
serialized = serialize_decision(original_decision)
|
|
assert isinstance(serialized, str)
|
|
|
|
# Deserialize
|
|
deserialized = deserialize_decision(serialized)
|
|
|
|
assert deserialized.decision_id == original_decision.decision_id
|
|
assert deserialized.category == original_decision.category
|
|
assert deserialized.scenario == original_decision.scenario
|
|
assert deserialized.reasoning == original_decision.reasoning
|
|
assert deserialized.outcome == original_decision.outcome
|
|
assert deserialized.confidence == original_decision.confidence
|
|
assert deserialized.decision_maker == original_decision.decision_maker
|
|
assert deserialized.metadata == original_decision.metadata
|
|
|
|
def test_serialize_deserialize_policy(self):
|
|
"""Test policy serialization and deserialization."""
|
|
original_policy = Policy(
|
|
policy_id="policy_001",
|
|
name="Test Policy",
|
|
description="Test description",
|
|
rules={"test": "rule"},
|
|
category="test",
|
|
version="1.0",
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now(),
|
|
metadata={"department": "risk"}
|
|
)
|
|
|
|
# Serialize
|
|
serialized = serialize_policy(original_policy)
|
|
assert isinstance(serialized, str)
|
|
|
|
# Deserialize
|
|
deserialized = deserialize_policy(serialized)
|
|
|
|
assert deserialized.policy_id == original_policy.policy_id
|
|
assert deserialized.name == original_policy.name
|
|
assert deserialized.description == original_policy.description
|
|
assert deserialized.rules == original_policy.rules
|
|
assert deserialized.category == original_policy.category
|
|
assert deserialized.version == original_policy.version
|
|
assert deserialized.metadata == original_policy.metadata
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__])
|