219 lines
7.6 KiB
Python
219 lines
7.6 KiB
Python
# #region Test.SessionEventLogger [C:2] [TYPE Module] [SEMANTICS test,dataset,event,logger,session,audit]
|
|
# @BRIEF Tests for event_logger.py — session event logging and persistence.
|
|
# @RELATION BINDS_TO -> [SessionEventLoggerModule]
|
|
# @TEST_EDGE: log_event -> Persists event payload correctly
|
|
# @TEST_EDGE: log_event_validation -> Empty fields raise ValueError
|
|
# @TEST_EDGE: log_event_with_details -> Event details stored
|
|
# @TEST_EDGE: log_for_session -> Convenience wrapper from session object
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
import pytest
|
|
|
|
|
|
class TestSessionEventPayload:
|
|
"""SessionEventPayload — dataclass contract."""
|
|
|
|
def test_payload_creation(self):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="user-1",
|
|
event_type="session_started",
|
|
event_summary="Session created",
|
|
current_phase="RECOVERY",
|
|
readiness_state="IMPORTING",
|
|
event_details={"key": "val"},
|
|
)
|
|
assert payload.session_id == "sess-1"
|
|
assert payload.event_type == "session_started"
|
|
assert payload.event_details == {"key": "val"}
|
|
|
|
|
|
class TestSessionEventLoggerLogEvent:
|
|
"""SessionEventLogger.log_event — persist event."""
|
|
|
|
@pytest.fixture
|
|
def db(self):
|
|
return MagicMock()
|
|
|
|
@pytest.fixture
|
|
def logger(self, db):
|
|
from src.services.dataset_review.event_logger import SessionEventLogger
|
|
return SessionEventLogger(db)
|
|
|
|
def test_log_event_success(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
# Mock SessionEvent
|
|
mock_event = MagicMock()
|
|
mock_event.session_event_id = "evt-1"
|
|
mock_event.event_type = "session_started"
|
|
db.add.return_value = None
|
|
db.refresh.return_value = None
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="user-1",
|
|
event_type="session_started",
|
|
event_summary="Session created",
|
|
current_phase="RECOVERY",
|
|
readiness_state="IMPORTING",
|
|
event_details={"source": "superset"},
|
|
)
|
|
|
|
result = logger.log_event(payload)
|
|
db.add.assert_called_once()
|
|
db.commit.assert_called_once()
|
|
db.refresh.assert_called_once()
|
|
|
|
def test_log_event_minimal(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="user-1",
|
|
event_type="update",
|
|
event_summary="Updated",
|
|
)
|
|
result = logger.log_event(payload)
|
|
db.add.assert_called_once()
|
|
db.commit.assert_called_once()
|
|
|
|
def test_empty_session_id_raises(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="",
|
|
actor_user_id="user-1",
|
|
event_type="test",
|
|
event_summary="test",
|
|
)
|
|
with pytest.raises(ValueError, match="session_id"):
|
|
logger.log_event(payload)
|
|
db.add.assert_not_called()
|
|
|
|
def test_empty_actor_user_id_raises(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="",
|
|
event_type="test",
|
|
event_summary="test",
|
|
)
|
|
with pytest.raises(ValueError, match="actor_user_id"):
|
|
logger.log_event(payload)
|
|
db.add.assert_not_called()
|
|
|
|
def test_empty_event_type_raises(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="user-1",
|
|
event_type="",
|
|
event_summary="test",
|
|
)
|
|
with pytest.raises(ValueError, match="event_type"):
|
|
logger.log_event(payload)
|
|
db.add.assert_not_called()
|
|
|
|
def test_empty_event_summary_raises(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="user-1",
|
|
event_type="test",
|
|
event_summary="",
|
|
)
|
|
with pytest.raises(ValueError, match="event_summary"):
|
|
logger.log_event(payload)
|
|
db.add.assert_not_called()
|
|
|
|
def test_event_with_complex_details(self, logger, db):
|
|
from src.services.dataset_review.event_logger import SessionEventPayload
|
|
|
|
payload = SessionEventPayload(
|
|
session_id="sess-1",
|
|
actor_user_id="user-1",
|
|
event_type="mapping_approved",
|
|
event_summary="Mappings approved by assistant",
|
|
event_details={
|
|
"mapping_ids": ["m-1", "m-2"],
|
|
"count": 2,
|
|
"nested": {"key": "value"},
|
|
},
|
|
)
|
|
result = logger.log_event(payload)
|
|
db.add.assert_called_once()
|
|
# Verify the event_details dict
|
|
added = db.add.call_args[0][0]
|
|
assert added.event_details["mapping_ids"] == ["m-1", "m-2"]
|
|
|
|
|
|
class TestSessionEventLoggerLogForSession:
|
|
"""SessionEventLogger.log_for_session — convenience wrapper."""
|
|
|
|
def test_log_for_session(self):
|
|
from src.services.dataset_review.event_logger import SessionEventLogger, SessionEventPayload
|
|
from src.models.dataset_review import DatasetReviewSession, SessionPhase, ReadinessState
|
|
|
|
db = MagicMock()
|
|
|
|
session = MagicMock(spec=DatasetReviewSession)
|
|
session.session_id = "sess-1"
|
|
session.current_phase = MagicMock(value="review")
|
|
session.readiness_state = MagicMock(value="review_ready")
|
|
|
|
logger = SessionEventLogger(db)
|
|
|
|
with patch.object(logger, "log_event") as mock_log:
|
|
mock_log.return_value = MagicMock(session_event_id="evt-1")
|
|
|
|
result = logger.log_for_session(
|
|
session,
|
|
actor_user_id="user-1",
|
|
event_type="preview_generated",
|
|
event_summary="Preview ready",
|
|
event_details={"preview_id": "pv-1"},
|
|
)
|
|
mock_log.assert_called_once()
|
|
payload = mock_log.call_args[0][0]
|
|
assert payload.session_id == "sess-1"
|
|
assert payload.event_type == "preview_generated"
|
|
assert payload.current_phase == "review"
|
|
assert payload.readiness_state == "review_ready"
|
|
|
|
def test_log_for_session_no_details(self):
|
|
from src.services.dataset_review.event_logger import SessionEventLogger
|
|
from src.models.dataset_review import DatasetReviewSession
|
|
|
|
db = MagicMock()
|
|
session = MagicMock(spec=DatasetReviewSession)
|
|
session.session_id = "sess-1"
|
|
session.current_phase = None
|
|
session.readiness_state = None
|
|
|
|
logger = SessionEventLogger(db)
|
|
|
|
with patch.object(logger, "log_event") as mock_log:
|
|
mock_log.return_value = MagicMock(session_event_id="evt-1")
|
|
|
|
logger.log_for_session(
|
|
session,
|
|
actor_user_id="user-1",
|
|
event_type="test",
|
|
event_summary="test",
|
|
)
|
|
payload = mock_log.call_args[0][0]
|
|
assert payload.current_phase is None
|
|
assert payload.readiness_state is None
|
|
# #endregion Test.SessionEventLogger
|