添加数据库加密处理的单元测试
This commit is contained in:
119
tests/unit/test_metadata_repository_dsn_decrypt.py
Normal file
119
tests/unit/test_metadata_repository_dsn_decrypt.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import asyncio
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from cryptography.fernet import InvalidToken
|
||||
|
||||
from app.infra.repositories.metadata_repository import MetadataRepository
|
||||
|
||||
|
||||
class _DummyResult:
|
||||
def __init__(self, record):
|
||||
self._record = record
|
||||
|
||||
def scalar_one_or_none(self):
|
||||
return self._record
|
||||
|
||||
|
||||
class _DummyEncryptor:
|
||||
def __init__(self, decrypted=None, raise_invalid_token=False):
|
||||
self._decrypted = decrypted
|
||||
self._raise_invalid_token = raise_invalid_token
|
||||
self.encrypted_values = []
|
||||
|
||||
def decrypt(self, _value):
|
||||
if self._raise_invalid_token:
|
||||
raise InvalidToken()
|
||||
return self._decrypted
|
||||
|
||||
def _build_record(dsn_encrypted: str):
|
||||
return SimpleNamespace(
|
||||
project_id=uuid4(),
|
||||
db_role="biz_data",
|
||||
db_type="postgresql",
|
||||
dsn_encrypted=dsn_encrypted,
|
||||
pool_min_size=1,
|
||||
pool_max_size=5,
|
||||
)
|
||||
|
||||
|
||||
def test_invalid_token_with_plaintext_dsn_value_raises_clear_error(monkeypatch):
|
||||
record = _build_record("postgresql://user:p@ss@localhost:5432/db")
|
||||
session = SimpleNamespace(
|
||||
execute=None,
|
||||
commit=None,
|
||||
)
|
||||
session.execute = AsyncMock(return_value=_DummyResult(record))
|
||||
session.commit = AsyncMock()
|
||||
encryptor = _DummyEncryptor(raise_invalid_token=True)
|
||||
repo = MetadataRepository(session)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"app.infra.repositories.metadata_repository.is_database_encryption_configured",
|
||||
lambda: True,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.infra.repositories.metadata_repository.get_database_encryptor",
|
||||
lambda: encryptor,
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="DATABASE_ENCRYPTION_KEY mismatch or invalid dsn_encrypted value",
|
||||
):
|
||||
asyncio.run(repo.get_project_db_routing(record.project_id, "biz_data"))
|
||||
session.commit.assert_not_awaited()
|
||||
|
||||
|
||||
def test_invalid_token_with_non_dsn_value_raises_clear_error(monkeypatch):
|
||||
record = _build_record("gAAAAABinvalidciphertext")
|
||||
session = SimpleNamespace(
|
||||
execute=None,
|
||||
commit=None,
|
||||
)
|
||||
session.execute = AsyncMock(return_value=_DummyResult(record))
|
||||
session.commit = AsyncMock()
|
||||
repo = MetadataRepository(session)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"app.infra.repositories.metadata_repository.is_database_encryption_configured",
|
||||
lambda: True,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.infra.repositories.metadata_repository.get_database_encryptor",
|
||||
lambda: _DummyEncryptor(raise_invalid_token=True),
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="DATABASE_ENCRYPTION_KEY mismatch or invalid dsn_encrypted value",
|
||||
):
|
||||
asyncio.run(repo.get_project_db_routing(record.project_id, "biz_data"))
|
||||
session.commit.assert_not_awaited()
|
||||
|
||||
|
||||
def test_encrypted_dsn_decrypts_without_migration(monkeypatch):
|
||||
record = _build_record("encrypted-value")
|
||||
session = SimpleNamespace(
|
||||
execute=None,
|
||||
commit=None,
|
||||
)
|
||||
session.execute = AsyncMock(return_value=_DummyResult(record))
|
||||
session.commit = AsyncMock()
|
||||
repo = MetadataRepository(session)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"app.infra.repositories.metadata_repository.is_database_encryption_configured",
|
||||
lambda: True,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.infra.repositories.metadata_repository.get_database_encryptor",
|
||||
lambda: _DummyEncryptor(decrypted="postgresql://u:p@ss@host/db"),
|
||||
)
|
||||
|
||||
routing = asyncio.run(repo.get_project_db_routing(record.project_id, "biz_data"))
|
||||
|
||||
assert routing.dsn == "postgresql://u:p%40ss@host/db"
|
||||
session.commit.assert_not_awaited()
|
||||
Reference in New Issue
Block a user