import json import pytest from services.storage.database_storage import ( AccountModel, AuthKeyModel, DatabaseStorageBackend, ) def _account_rows(backend: DatabaseStorageBackend) -> dict[str, AccountModel]: session = backend.Session() try: return { row.access_token: row for row in session.query(AccountModel).order_by(AccountModel.id).all() } finally: session.close() def test_save_accounts_preserves_existing_rows_and_updates_only_changed_data(tmp_path): backend = DatabaseStorageBackend(f"sqlite:///{tmp_path / 'accounts.db'}") backend.save_accounts( [ {"access_token": "token-a", "name": "A"}, {"access_token": "token-b", "name": "B"}, ] ) before = _account_rows(backend) before_ids = {token: row.id for token, row in before.items()} before_b_data = before["token-b"].data backend.save_accounts( [ {"access_token": "token-b", "name": "B"}, {"access_token": "token-a", "name": "A updated"}, {"access_token": "token-c", "name": "C"}, ] ) after = _account_rows(backend) assert set(after) == {"token-a", "token-b", "token-c"} assert after["token-a"].id == before_ids["token-a"] assert after["token-b"].id == before_ids["token-b"] assert after["token-b"].data == before_b_data assert json.loads(after["token-a"].data)["name"] == "A updated" def test_save_accounts_deletes_only_rows_missing_from_new_snapshot(tmp_path): backend = DatabaseStorageBackend(f"sqlite:///{tmp_path / 'accounts.db'}") backend.save_accounts( [ {"access_token": "token-a", "name": "A"}, {"access_token": "token-b", "name": "B"}, ] ) before = _account_rows(backend) token_b_id = before["token-b"].id backend.save_accounts([{"access_token": "token-b", "name": "B"}]) after = _account_rows(backend) assert set(after) == {"token-b"} assert after["token-b"].id == token_b_id def test_save_accounts_rejects_duplicate_tokens_and_rolls_back(tmp_path): backend = DatabaseStorageBackend(f"sqlite:///{tmp_path / 'accounts.db'}") original = {"access_token": "token-a", "name": "A"} backend.save_accounts([original]) with pytest.raises(ValueError, match="Duplicate access_token") as exc_info: backend.save_accounts( [ {"access_token": "token-a", "name": "first update"}, {"access_token": "token-a", "name": "second update"}, ] ) assert "token-a" not in str(exc_info.value) assert backend.load_accounts() == [original] def test_save_accounts_rejects_duplicate_new_tokens_and_rolls_back(tmp_path): backend = DatabaseStorageBackend(f"sqlite:///{tmp_path / 'accounts.db'}") original = {"access_token": "token-a", "name": "A"} backend.save_accounts([original]) with pytest.raises(ValueError, match="Duplicate access_token") as exc_info: backend.save_accounts( [ original, {"access_token": "token-b", "name": "first new"}, {"access_token": "token-b", "name": "second new"}, ] ) assert "token-b" not in str(exc_info.value) assert backend.load_accounts() == [original] def test_save_auth_keys_preserves_ids_with_target_key_mapping(tmp_path): backend = DatabaseStorageBackend(f"sqlite:///{tmp_path / 'auth-keys.db'}") backend.save_auth_keys( [ {"id": "key-a", "name": "A"}, {"id": "key-b", "name": "B"}, ] ) session = backend.Session() try: before_ids = { row.key_id: row.id for row in session.query(AuthKeyModel).order_by(AuthKeyModel.id).all() } finally: session.close() backend.save_auth_keys( [ {"id": "key-b", "name": "B"}, {"id": "key-a", "name": "A updated"}, {"id": "key-c", "name": "C"}, ] ) session = backend.Session() try: after = { row.key_id: row for row in session.query(AuthKeyModel).order_by(AuthKeyModel.id).all() } assert set(after) == {"key-a", "key-b", "key-c"} assert after["key-a"].id == before_ids["key-a"] assert after["key-b"].id == before_ids["key-b"] assert json.loads(after["key-a"].data)["name"] == "A updated" finally: session.close() def test_save_auth_keys_rejects_duplicate_ids_and_rolls_back(tmp_path): backend = DatabaseStorageBackend(f"sqlite:///{tmp_path / 'auth-keys.db'}") original = {"id": "key-a", "name": "A"} backend.save_auth_keys([original]) with pytest.raises(ValueError, match="Duplicate id") as exc_info: backend.save_auth_keys( [ {"id": "key-a", "name": "first update"}, {"id": "key-a", "name": "second update"}, ] ) assert "key-a" not in str(exc_info.value) assert backend.load_auth_keys() == [original]