"""Tests for the product_additional_upc dual-write mirror helpers.""" from datetime import datetime from product_digital.connectors import mysql from product_digital.models import product_additional_upc from product_digital.models.product_additional_upc import ProductAdditionalUpc from product_digital.models.product_additional_upc import ProductAdditionalUpcType from tests.testutils import db def _rows_for(product_id): """Plain-dict snapshot of every product_additional_upc row for a product.""" with mysql.db_session() as session: return [ {'upc': row.upc, 'type': row.type, 'deleted_at': row.deleted_at} for row in session.query(ProductAdditionalUpc).filter( ProductAdditionalUpc.product_id == product_id).all() ] @db.test_schema def test_mirror_create_inserts_active_atmos_row(): """A first mirror write inserts one active atmos row carrying the type.""" with mysql.db_session() as session: product_additional_upc.mirror_create_or_restore(100, 9876543210123, session) rows = _rows_for(100) assert len(rows) == 1 assert rows[0]['type'] == 'atmos' assert rows[0]['upc'] == 9876543210123 assert rows[0]['deleted_at'] is None @db.test_schema def test_mirror_create_restores_and_updates_soft_deleted_row(): """A re-create restores the soft-deleted row in place, matching the new UPC.""" db.seed_models(ProductAdditionalUpc( product_id=100, type=ProductAdditionalUpcType.ATMOS, upc=9876543210123, deleted_at=datetime(2026, 1, 1))) with mysql.db_session() as session: product_additional_upc.mirror_create_or_restore(100, 1112223334445, session) rows = _rows_for(100) assert len(rows) == 1 assert rows[0]['deleted_at'] is None assert rows[0]['upc'] == 1112223334445 @db.test_schema def test_mirror_soft_delete_sets_deleted_at_keeping_row(): """Mirroring a delete sets deleted_at without removing the row.""" with mysql.db_session() as session: product_additional_upc.mirror_create_or_restore(100, 9876543210123, session) with mysql.db_session() as session: product_additional_upc.mirror_soft_delete(100, session) rows = _rows_for(100) assert len(rows) == 1 assert rows[0]['deleted_at'] is not None @db.test_schema def test_mirror_soft_delete_no_active_row_is_noop(): """Mirroring a delete for a product with no active atmos row does nothing.""" with mysql.db_session() as session: product_additional_upc.mirror_soft_delete(999, session) assert _rows_for(999) == [] @db.test_schema def test_mirror_soft_delete_leaves_already_soft_deleted_row_untouched(): """An already-soft-deleted row is excluded, so its deleted_at is not re-stamped.""" already_deleted_at = datetime(2026, 1, 1) db.seed_models(ProductAdditionalUpc( product_id=100, type=ProductAdditionalUpcType.ATMOS, upc=9876543210123, deleted_at=already_deleted_at)) with mysql.db_session() as session: product_additional_upc.mirror_soft_delete(100, session) rows = _rows_for(100) assert len(rows) == 1 assert rows[0]['deleted_at'] == already_deleted_at @db.test_schema def test_mirror_create_or_restore_scopes_restore_to_its_own_product(): """A create for one product inserts its own row, never restoring another's.""" db.seed_models(ProductAdditionalUpc( product_id=100, type=ProductAdditionalUpcType.ATMOS, upc=9876543210123, deleted_at=datetime(2026, 1, 1))) with mysql.db_session() as session: product_additional_upc.mirror_create_or_restore(200, 1112223334445, session) assert _rows_for(100)[0]['deleted_at'] is not None product_200_rows = _rows_for(200) assert len(product_200_rows) == 1 assert product_200_rows[0]['deleted_at'] is None assert product_200_rows[0]['upc'] == 1112223334445 @db.test_schema def test_get_atmos_upc_returns_upc_when_present(): """get_atmos_upc returns the product's atmos UPC.""" db.seed_models(ProductAdditionalUpc( product_id=100, type=ProductAdditionalUpcType.ATMOS, upc=9876543210123)) result = product_additional_upc.get_atmos_upc(100) assert result.message == 9876543210123 @db.test_schema def test_get_atmos_upc_reuses_soft_deleted_upc(): """get_atmos_upc returns the UPC even when the row is soft-deleted (permanent).""" db.seed_models(ProductAdditionalUpc( product_id=100, type=ProductAdditionalUpcType.ATMOS, upc=9876543210123, deleted_at=datetime(2026, 1, 1))) result = product_additional_upc.get_atmos_upc(100) assert result.message == 9876543210123 @db.test_schema def test_get_atmos_upc_returns_none_when_absent(): """get_atmos_upc returns a None message when the product has no atmos UPC.""" result = product_additional_upc.get_atmos_upc(999) assert result.message is None