Skip to content

Commit 21028aa

Browse files
authored
Merge pull request #7 from hexfrost/beta-0.1.6
Beta 0.1.6
2 parents 0e68eb3 + d245423 commit 21028aa

File tree

12 files changed

+388
-63
lines changed

12 files changed

+388
-63
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ dependencies = [
2222
"sqlalchemy-utils>=0.41.2",
2323
]
2424
name = "hexfrost-toolbox"
25-
version = "0.1.6"
25+
version = "0.1.6b"
2626
description = "Open source library with useful utils for fast development"
2727
readme = "README.md"
2828

tests/fixtures/database.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,22 @@
33
from toolbox.sqlalchemy.connection import DatabaseConnectionSettings
44

55

6-
@pytest.fixture(autouse=True)
6+
@pytest.fixture(autouse=True, scope="session")
77
def db_settings():
8-
from pydantic import BaseModel
9-
data = dict(
8+
data = DatabaseConnectionSettings(
109
POSTGRES_USER="postgres",
1110
POSTGRES_PASSWORD = "postgres",
1211
POSTGRES_HOST = "0.0.0.0",
1312
POSTGRES_PORT = "5432",
1413
POSTGRES_DB = "postgres"
1514
)
16-
class TestSettings(BaseModel, DatabaseConnectionSettings):
17-
pass
18-
19-
return TestSettings(**data)
15+
return data
2016

2117

22-
@pytest.fixture(autouse=True)
18+
@pytest.fixture(autouse=True, scope="session")
2319
async def temp_db(db_settings):
2420
from toolbox.testing import temporary_database
25-
from toolbox.sqlalchemy.models import BaseModel
26-
async with temporary_database(settings=db_settings, base_model=BaseModel):
21+
from toolbox.sqlalchemy.models import BaseDatabaseModel
22+
async with temporary_database(settings=db_settings, base_model=BaseDatabaseModel):
2723
yield
2824
pass
29-
30-
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import pytest
2+
from sqlalchemy import Column, Integer, String, orm, LargeBinary
3+
4+
from toolbox.schemes import SensitiveDataScheme, SensitiveFieldData
5+
from toolbox.sqlalchemy.connection import DatabaseConnectionManager, DatabaseConnectionSettings
6+
from toolbox.sqlalchemy.repositories import AbstractDatabaseCrudManager
7+
8+
9+
class BaseDatabaseModel(orm.DeclarativeBase):
10+
pass
11+
12+
13+
class TestSQLAlchemyModel(BaseDatabaseModel):
14+
__tablename__ = "test_items"
15+
id = Column(Integer, primary_key=True, index=True)
16+
name = Column(String, index=True)
17+
sensitive_field = Column(LargeBinary)
18+
19+
20+
class TestPydanticModel(SensitiveDataScheme):
21+
_sensitive_attributes = ["sensitive_field"]
22+
23+
name: str
24+
sensitive_field: SensitiveFieldData
25+
26+
27+
class TestItemRepository(AbstractDatabaseCrudManager):
28+
_alchemy_model = TestSQLAlchemyModel
29+
_pydantic_model = TestPydanticModel
30+
31+
32+
@pytest.fixture(autouse=True, scope="session")
33+
def db_settings():
34+
data = DatabaseConnectionSettings(
35+
POSTGRES_USER="postgres",
36+
POSTGRES_PASSWORD="postgres",
37+
POSTGRES_HOST="0.0.0.0",
38+
POSTGRES_PORT="5432",
39+
POSTGRES_DB="postgres"
40+
)
41+
return data
42+
43+
44+
@pytest.fixture(autouse=True, scope="session")
45+
async def temp_db(db_settings):
46+
from toolbox.testing import temporary_database
47+
from toolbox.sqlalchemy.models import BaseDatabaseModel
48+
async with temporary_database(settings=db_settings, base_model=BaseDatabaseModel) as db_connection:
49+
yield db_connection
50+
pass
51+
52+
53+
@pytest.fixture(autouse=True, scope="session")
54+
def database_connection(db_settings):
55+
dc = DatabaseConnectionManager(settings=db_settings)
56+
return dc
57+
58+
class MockCipherManager:
59+
def encrypt(self, value):
60+
return f"{value}_secret".encode()
61+
62+
def decrypt(self, value):
63+
return value.decode()[:-7]
64+
65+
66+
async def test_add_one_sensitive_field(temp_db, database_connection):
67+
new_obj = TestPydanticModel(
68+
name="test_item",
69+
sensitive_field="test_sensitive_field"
70+
)
71+
72+
TestPydanticModel.set_cipher_suite_manager(MockCipherManager())
73+
async with database_connection.get_db_session() as conn:
74+
from sqlalchemy.schema import CreateTable
75+
try:
76+
await conn.execute(CreateTable(TestSQLAlchemyModel.__table__))
77+
except:
78+
pass
79+
80+
all_ = await TestItemRepository.get_all(conn)
81+
assert len(all_) == 0
82+
83+
await TestItemRepository.add_one(conn, new_obj)
84+
85+
import asyncpg
86+
another_conn = await asyncpg.connect(dsn=database_connection._get_settings().get_dsn())
87+
raw_results = await another_conn.fetch(f"SELECT * FROM {TestSQLAlchemyModel.__table__}")
88+
await another_conn.close()
89+
90+
assert len(raw_results) == 1
91+
result = dict(zip(raw_results[0].keys(), raw_results[0].values()))
92+
93+
assert result["sensitive_field"] == "test_sensitive_field_secret".encode()
94+
95+
all_ = await TestItemRepository.get_all(conn)
96+
assert len(all_) == 1
97+
obj = all_[0]
98+
assert obj.sensitive_field == "test_sensitive_field"

tests/test_alchemy.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
1-
import pytest
21
from unittest.mock import MagicMock, AsyncMock, patch
3-
from sqlalchemy import select, String
2+
3+
import pytest
44
from sqlalchemy.orm import mapped_column, Mapped
55
from sqlalchemy.sql.selectable import Select
66

7+
from sqlalchemy import select, String
8+
from toolbox.schemes import SensitiveDataScheme
9+
from toolbox.sqlalchemy.models import BaseDatabaseModel
710
from toolbox.sqlalchemy.repositories import AbstractDatabaseCrudManager
8-
from toolbox.sqlalchemy.models import BaseModel
9-
from toolbox.schemes import BaseScheme, SensitiveDataScheme
1011

1112

12-
class TestPydanticModel(BaseScheme):
13+
class TestPydanticModel(SensitiveDataScheme):
1314
name: str
1415
value: str
1516

1617
def encrypt_fields(self):
1718
return self
1819

1920

20-
class TestSQLAlchemyModel(BaseModel):
21+
class TestSQLAlchemyDatabaseModel(BaseDatabaseModel):
2122
__tablename__ = "test_table"
2223
name: Mapped[str] = mapped_column(String, primary_key=True)
2324
value: Mapped[str] = mapped_column(String)
2425

2526

2627
class TestCrudManager(AbstractDatabaseCrudManager):
27-
_alchemy_model = TestSQLAlchemyModel
28+
_alchemy_model = TestSQLAlchemyDatabaseModel
2829
_pydantic_model = TestPydanticModel
2930

3031

@@ -57,7 +58,7 @@ async def test_add_one(mock_db_manager, mock_session, test_data):
5758

5859
session.add.assert_called_once()
5960
added_model = session.add.call_args[0][0]
60-
assert isinstance(added_model, TestSQLAlchemyModel)
61+
assert isinstance(added_model, TestSQLAlchemyDatabaseModel)
6162
assert added_model.name == test_data.name
6263
assert added_model.value == test_data.value
6364

@@ -71,8 +72,8 @@ async def test_get_all(mock_db_manager, mock_session):
7172
session_maker, session = mock_session
7273

7374
test_models = [
74-
TestSQLAlchemyModel(name="test1", value="value1"),
75-
TestSQLAlchemyModel(name="test2", value="value2")
75+
TestSQLAlchemyDatabaseModel(name="test1", value="value1"),
76+
TestSQLAlchemyDatabaseModel(name="test2", value="value2")
7677
]
7778

7879
db_operation_result_mock = MagicMock()
@@ -87,8 +88,7 @@ async def test_get_all(mock_db_manager, mock_session):
8788
assert isinstance(query, Select)
8889

8990
assert len(result) == 2
90-
assert all(isinstance(item, TestSQLAlchemyModel) for item in result)
91-
assert result == test_models
91+
assert all(isinstance(item, TestPydanticModel) for item in result)
9292

9393

9494
@pytest.mark.asyncio

tests/test_database.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
from unittest.mock import MagicMock, patch
22

33
import pytest
4-
from sqlalchemy import select
5-
from sqlalchemy.ext.asyncio import AsyncSession
64

5+
from sqlalchemy import select
76
from tests.fixtures.database import db_settings, temp_db
87
from tests.fixtures.db_connect import database_connector
98

0 commit comments

Comments
 (0)