# #region Test.DatasetReviewMappingModels [C:3] [TYPE Module] [SEMANTICS test,sqlalchemy,dataset,review,mapping,execution,model] # @BRIEF Verify ExecutionMapping SQLAlchemy model — construction, defaults, JSON columns, approval gate, FK constraints. # @RELATION BINDS_TO -> [DatasetReviewMappingModels] # @TEST_EDGE: approval_gate -> requires_explicit_approval defaults False # @TEST_EDGE: approval_state_default -> Defaults to NOT_REQUIRED # @TEST_EDGE: effective_value_none -> effective_value can be None # @TEST_EDGE: warning_level_default -> warning_level can be None import uuid from datetime import UTC, datetime from sqlalchemy import create_engine, text from sqlalchemy.orm import Session as SASession import pytest from src.models.dataset_review_pkg._session_models import DatasetReviewSession from src.models.dataset_review_pkg._mapping_models import ( Base, ExecutionMapping, ) from src.models.dataset_review_pkg._enums import ( ApprovalState, MappingMethod, MappingWarningLevel, ) from src.models.mapping import Environment @pytest.fixture(scope="function") def db_session(): """Fresh in-memory SQLite with FK enforcement using single connection.""" engine = create_engine("sqlite:///:memory:", connect_args={"check_same_thread": False}) conn = engine.connect() conn.execute(text("PRAGMA foreign_keys=ON")) # Create the raw users table FIRST — multiple model tables FK-reference it conn.execute(text("CREATE TABLE IF NOT EXISTS users (id VARCHAR PRIMARY KEY)")) from src.models.mapping import Base as MappingBase MappingBase.metadata.create_all(conn) Base.metadata.create_all(conn) conn.commit() session = SASession(bind=conn) env = Environment(id="env-1", name="Test", url="https://example.com", credentials_id="cred-1") session.add(env) session.execute(text("INSERT OR IGNORE INTO users (id) VALUES ('user-1')")) session.commit() yield session session.close() conn.close() def _create_session(db_session) -> DatasetReviewSession: rev = DatasetReviewSession( user_id="user-1", environment_id="env-1", source_kind="superset", source_input="SELECT 1", dataset_ref="ds_1", ) db_session.add(rev) db_session.flush() return rev class TestExecutionMapping: """Verify ExecutionMapping model.""" def test_create_minimal(self, db_session): """Minimal required fields produce valid mapping with defaults.""" session = _create_session(db_session) mapping = ExecutionMapping( session_id=session.session_id, filter_id="filter-1", variable_id="var-1", mapping_method=MappingMethod.DIRECT_MATCH, raw_input_value={"values": ["active"]}, ) db_session.add(mapping) db_session.flush() assert mapping.mapping_id is not None assert isinstance(uuid.UUID(mapping.mapping_id), uuid.UUID) assert mapping.session_id == session.session_id assert mapping.filter_id == "filter-1" assert mapping.variable_id == "var-1" assert mapping.mapping_method == MappingMethod.DIRECT_MATCH assert mapping.raw_input_value == {"values": ["active"]} # Defaults assert mapping.effective_value is None assert mapping.transformation_note is None assert mapping.warning_level is None assert mapping.requires_explicit_approval is False assert mapping.approval_state == ApprovalState.NOT_REQUIRED assert mapping.approved_by_user_id is None assert mapping.approved_at is None assert mapping.created_at is not None assert mapping.updated_at is not None def test_all_fields(self, db_session): """All fields populated.""" session = _create_session(db_session) approved_at = datetime.now(UTC) mapping = ExecutionMapping( session_id=session.session_id, filter_id="f-1", variable_id="v-1", mapping_method=MappingMethod.HEURISTIC_MATCH, raw_input_value={"values": ["x", "y"]}, effective_value={"values": ["X", "Y"]}, transformation_note="Uppercased values", warning_level=MappingWarningLevel.LOW, requires_explicit_approval=True, approval_state=ApprovalState.PENDING, approved_by_user_id="user-2", approved_at=approved_at, ) db_session.add(mapping) db_session.flush() assert mapping.effective_value == {"values": ["X", "Y"]} assert mapping.transformation_note == "Uppercased values" assert mapping.warning_level == MappingWarningLevel.LOW assert mapping.requires_explicit_approval is True assert mapping.approval_state == ApprovalState.PENDING assert mapping.approved_by_user_id == "user-2" assert mapping.approved_at == approved_at def test_effective_value_as_list(self, db_session): """Effective value can be a JSON list.""" session = _create_session(db_session) mapping = ExecutionMapping( session_id=session.session_id, filter_id="f", variable_id="v", mapping_method=MappingMethod.SEMANTIC_MATCH, raw_input_value={}, effective_value=["a", "b", "c"], ) db_session.add(mapping) db_session.flush() loaded = db_session.query(ExecutionMapping).filter_by(mapping_id=mapping.mapping_id).first() assert loaded.effective_value == ["a", "b", "c"] def test_all_mapping_methods(self, db_session): """All MappingMethod values accepted.""" session = _create_session(db_session) for mm in MappingMethod: m = ExecutionMapping( session_id=session.session_id, filter_id=f"f_{mm.value}", variable_id="v", mapping_method=mm, raw_input_value={}, ) db_session.add(m) db_session.flush() assert db_session.query(ExecutionMapping).count() == len(MappingMethod) def test_all_approval_states(self, db_session): """All ApprovalState values accepted.""" session = _create_session(db_session) for as_ in ApprovalState: m = ExecutionMapping( session_id=session.session_id, filter_id="f", variable_id="v", mapping_method=MappingMethod.MANUAL_OVERRIDE, raw_input_value={}, approval_state=as_, requires_explicit_approval=True if as_ in (ApprovalState.PENDING, ApprovalState.APPROVED) else False, ) db_session.add(m) db_session.flush() assert db_session.query(ExecutionMapping).count() == len(ApprovalState) def test_cascade_delete(self, db_session): """Session delete cascades to execution mappings.""" session = _create_session(db_session) m = ExecutionMapping( session_id=session.session_id, filter_id="f", variable_id="v", mapping_method=MappingMethod.DIRECT_MATCH, raw_input_value={}, ) db_session.add(m) db_session.flush() db_session.delete(session) db_session.flush() assert db_session.query(ExecutionMapping).count() == 0 def test_relationship(self, db_session): """Navigate mapping -> session.""" session = _create_session(db_session) m = ExecutionMapping( session_id=session.session_id, filter_id="f", variable_id="v", mapping_method=MappingMethod.DIRECT_MATCH, raw_input_value={}, ) db_session.add(m) db_session.flush() assert m.session is session def test_transformation_none_and_empty(self, db_session): """transformation_note accepts None or string.""" session = _create_session(db_session) m1 = ExecutionMapping( session_id=session.session_id, filter_id="f1", variable_id="v1", mapping_method=MappingMethod.DIRECT_MATCH, raw_input_value={}, transformation_note="Note", ) m2 = ExecutionMapping( session_id=session.session_id, filter_id="f2", variable_id="v2", mapping_method=MappingMethod.DIRECT_MATCH, raw_input_value={}, transformation_note=None, ) db_session.add_all([m1, m2]) db_session.flush() assert m1.transformation_note == "Note" assert m2.transformation_note is None # #endregion Test.DatasetReviewMappingModels