c85c0068a2
- Replace all datetime.utcnow() with datetime.now(tz=timezone.utc) across 8 files - Fix 12 failing tests to match current implementation behavior - Fix pytest_plugins in non-top-level conftest (moved to root conftest.py) - Auto-fix 189 lint issues (import sorting, unused imports) - Add CI/CD pipeline infrastructure (ARC, ArgoCD, Kargo manifests) - Add values-beta.yaml and values-paper.yaml for staged deployments - Update GitHub Actions workflow to use self-hosted-gremlin runners - Add integration-test job to CI pipeline Result: 1596 passed, 0 failed, 0 warnings
161 lines
5.6 KiB
Python
161 lines
5.6 KiB
Python
"""Tests for the execution audit trail module.
|
|
|
|
Validates audit event construction, event type constants, and the
|
|
convenience helpers that record each stage of the execution pipeline.
|
|
"""
|
|
from services.shared.audit import (
|
|
AUDIT_ORDER_CANCELLED,
|
|
AUDIT_ORDER_DUPLICATE,
|
|
AUDIT_ORDER_FILLED,
|
|
AUDIT_ORDER_REJECTED,
|
|
AUDIT_ORDER_SUBMITTED,
|
|
AUDIT_POSITION_CLOSED,
|
|
AUDIT_POSITION_OPENED,
|
|
AUDIT_POSITION_UPDATED,
|
|
AUDIT_RECOMMENDATION_GENERATED,
|
|
AUDIT_RECOMMENDATION_SUPPRESSED,
|
|
AUDIT_RISK_EVALUATED,
|
|
AUDIT_RISK_REJECTED,
|
|
AUDIT_TRADING_MODE_CHANGED,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Event type constants
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestAuditEventTypes:
|
|
"""Verify event type constants are well-formed and distinct."""
|
|
|
|
def test_recommendation_events(self):
|
|
assert AUDIT_RECOMMENDATION_GENERATED == "recommendation.generated"
|
|
assert AUDIT_RECOMMENDATION_SUPPRESSED == "recommendation.suppressed"
|
|
|
|
def test_risk_events(self):
|
|
assert AUDIT_RISK_EVALUATED == "risk.evaluated"
|
|
assert AUDIT_RISK_REJECTED == "risk.rejected"
|
|
|
|
def test_order_events(self):
|
|
assert AUDIT_ORDER_SUBMITTED == "order.submitted"
|
|
assert AUDIT_ORDER_FILLED == "order.filled"
|
|
assert AUDIT_ORDER_REJECTED == "order.rejected"
|
|
assert AUDIT_ORDER_CANCELLED == "order.cancelled"
|
|
assert AUDIT_ORDER_DUPLICATE == "order.duplicate_prevented"
|
|
|
|
def test_position_events(self):
|
|
assert AUDIT_POSITION_OPENED == "position.opened"
|
|
assert AUDIT_POSITION_CLOSED == "position.closed"
|
|
assert AUDIT_POSITION_UPDATED == "position.updated"
|
|
|
|
def test_trading_mode_event(self):
|
|
assert AUDIT_TRADING_MODE_CHANGED == "trading.mode_changed"
|
|
|
|
def test_all_event_types_unique(self):
|
|
all_types = [
|
|
AUDIT_RECOMMENDATION_GENERATED,
|
|
AUDIT_RECOMMENDATION_SUPPRESSED,
|
|
AUDIT_RISK_EVALUATED,
|
|
AUDIT_RISK_REJECTED,
|
|
AUDIT_ORDER_SUBMITTED,
|
|
AUDIT_ORDER_FILLED,
|
|
AUDIT_ORDER_REJECTED,
|
|
AUDIT_ORDER_CANCELLED,
|
|
AUDIT_ORDER_DUPLICATE,
|
|
AUDIT_POSITION_OPENED,
|
|
AUDIT_POSITION_CLOSED,
|
|
AUDIT_POSITION_UPDATED,
|
|
AUDIT_TRADING_MODE_CHANGED,
|
|
]
|
|
assert len(all_types) == len(set(all_types))
|
|
|
|
def test_event_types_follow_dot_notation(self):
|
|
"""All event types should follow entity.action pattern."""
|
|
all_types = [
|
|
AUDIT_RECOMMENDATION_GENERATED,
|
|
AUDIT_RECOMMENDATION_SUPPRESSED,
|
|
AUDIT_RISK_EVALUATED,
|
|
AUDIT_RISK_REJECTED,
|
|
AUDIT_ORDER_SUBMITTED,
|
|
AUDIT_ORDER_FILLED,
|
|
AUDIT_ORDER_REJECTED,
|
|
AUDIT_ORDER_CANCELLED,
|
|
AUDIT_ORDER_DUPLICATE,
|
|
AUDIT_POSITION_OPENED,
|
|
AUDIT_POSITION_CLOSED,
|
|
AUDIT_POSITION_UPDATED,
|
|
AUDIT_TRADING_MODE_CHANGED,
|
|
]
|
|
for t in all_types:
|
|
assert "." in t, f"Event type {t} should use dot notation"
|
|
parts = t.split(".")
|
|
assert len(parts) == 2, f"Event type {t} should have exactly one dot"
|
|
assert all(p for p in parts), f"Event type {t} has empty parts"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Module imports and structure
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestAuditModuleStructure:
|
|
"""Verify the audit module exports the expected functions."""
|
|
|
|
def test_record_audit_event_exists(self):
|
|
from services.shared.audit import record_audit_event
|
|
assert callable(record_audit_event)
|
|
|
|
def test_convenience_helpers_exist(self):
|
|
from services.shared.audit import (
|
|
audit_duplicate_prevented,
|
|
audit_order_cancelled,
|
|
audit_order_filled,
|
|
audit_order_rejected,
|
|
audit_order_submitted,
|
|
audit_position_change,
|
|
audit_recommendation_generated,
|
|
audit_risk_evaluated,
|
|
audit_trading_mode_changed,
|
|
)
|
|
for fn in [
|
|
audit_recommendation_generated,
|
|
audit_risk_evaluated,
|
|
audit_order_submitted,
|
|
audit_order_filled,
|
|
audit_order_rejected,
|
|
audit_order_cancelled,
|
|
audit_duplicate_prevented,
|
|
audit_position_change,
|
|
audit_trading_mode_changed,
|
|
]:
|
|
assert callable(fn)
|
|
|
|
def test_query_helpers_exist(self):
|
|
from services.shared.audit import (
|
|
get_entity_audit_trail,
|
|
get_order_audit_trail,
|
|
)
|
|
assert callable(get_order_audit_trail)
|
|
assert callable(get_entity_audit_trail)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Broker service audit integration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestBrokerServiceAuditImports:
|
|
"""Verify the broker service uses audit functions from the audit module."""
|
|
|
|
def test_broker_service_has_audit_calls(self):
|
|
"""The broker service module should reference audit functions."""
|
|
import inspect
|
|
|
|
import services.adapters.broker_service as bs
|
|
|
|
source = inspect.getsource(bs)
|
|
assert "audit_order_submitted" in source
|
|
assert "audit_order_filled" in source
|
|
assert "audit_order_rejected" in source
|
|
assert "audit_risk_evaluated" in source
|
|
assert "audit_duplicate_prevented" in source
|