import pytest from database.init_db import _ensure_bind_session_card_columns, _ensure_cards_allow_multiple_per_device class FakeScalarResult: def __init__(self, value): self.value = value def scalar(self): return self.value class FakeConnection: def __init__(self): self.stat_counts = { "idx_device_bind_sessions_card_uuid": 0, "idx_cards_device_id": 0, "uq_cards_device_id": 1, } self.column_counts = { "bind_mode": 0, "card_uuid": 0, } self.sql = [] async def execute(self, statement, params=None): sql = str(statement) self.sql.append(sql) if "INFORMATION_SCHEMA.COLUMNS" in sql: return FakeScalarResult(self.column_counts.get(params["column_name"], 0)) if "INFORMATION_SCHEMA.STATISTICS" in sql: for index_name, count in self.stat_counts.items(): if f"INDEX_NAME = '{index_name}'" in sql: return FakeScalarResult(count) return FakeScalarResult(0) return FakeScalarResult(0) @pytest.mark.asyncio async def test_ensure_bind_session_card_columns_adds_missing_columns_and_index(): conn = FakeConnection() await _ensure_bind_session_card_columns(conn) executed = "\n".join(conn.sql) assert "ALTER TABLE device_bind_sessions ADD COLUMN bind_mode TINYINT NOT NULL DEFAULT 1 AFTER status" in executed assert "ALTER TABLE device_bind_sessions ADD COLUMN card_uuid VARCHAR(64) NULL AFTER bind_mode" in executed assert "ALTER TABLE device_bind_sessions ADD INDEX idx_device_bind_sessions_card_uuid (card_uuid)" in executed @pytest.mark.asyncio async def test_ensure_cards_allow_multiple_per_device_replaces_unique_device_index(): conn = FakeConnection() await _ensure_cards_allow_multiple_per_device(conn) executed = "\n".join(conn.sql) assert "ALTER TABLE cards ADD INDEX idx_cards_device_id (device_id)" in executed assert "ALTER TABLE cards DROP INDEX uq_cards_device_id" in executed assert executed.index("ALTER TABLE cards ADD INDEX idx_cards_device_id") < executed.index( "ALTER TABLE cards DROP INDEX uq_cards_device_id" )