-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathconftest.py
More file actions
117 lines (87 loc) · 3.77 KB
/
conftest.py
File metadata and controls
117 lines (87 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
from collections.abc import Awaitable, Callable
from typing import Optional
from unittest.mock import AsyncMock, create_autospec
import pytest
import sqlalchemy as sa
from aiohttp import web
from aiohttp.test_utils import TestClient
from pytest_aiohttp import AiohttpClient
from sqlalchemy.ext.asyncio import (AsyncEngine, AsyncSession,
async_sessionmaker, create_async_engine)
from sqlalchemy.orm import DeclarativeBaseNoMeta, Mapped, mapped_column, relationship
import aiohttp_admin
from _auth import check_credentials
from aiohttp_admin.backends.sqlalchemy import SAResource
IdentityCallback = Callable[[Optional[str]], Awaitable[aiohttp_admin.UserDetails]]
_Client = TestClient[web.Request, web.Application]
class Base(DeclarativeBaseNoMeta):
"""Base model."""
class DummyModel(Base):
__tablename__ = "dummy"
id: Mapped[int] = mapped_column(primary_key=True)
foreigns: Mapped[list["ForeignModel"]] = relationship()
class Dummy2Model(Base):
__tablename__ = "dummy2"
id: Mapped[int] = mapped_column(primary_key=True)
msg: Mapped[Optional[str]]
class ForeignModel(Base):
__tablename__ = "foreign"
id: Mapped[int] = mapped_column(primary_key=True)
dummy: Mapped[int] = mapped_column(sa.ForeignKey(DummyModel.id))
model = web.AppKey[type[DummyModel]]("model")
model2 = web.AppKey[type[Dummy2Model]]("model2")
db = web.AppKey("db", async_sessionmaker[AsyncSession])
admin = web.AppKey("admin", web.Application)
@pytest.fixture
def mock_engine() -> AsyncMock:
return create_autospec(AsyncEngine, instance=True, spec_set=True) # type: ignore[no-any-return] # noqa: B950
@pytest.fixture
def create_admin_client(
aiohttp_client: AiohttpClient
) -> Callable[[Optional[IdentityCallback]], Awaitable[_Client]]:
async def admin_client(identity_callback: Optional[IdentityCallback] = None) -> _Client:
app = web.Application()
app[model] = DummyModel
app[model2] = Dummy2Model
engine = create_async_engine("sqlite+aiosqlite:///:memory:")
app[db] = async_sessionmaker(engine, expire_on_commit=False)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async with app[db].begin() as sess:
dummy = DummyModel()
sess.add(dummy)
sess.add(Dummy2Model(msg="Test"))
sess.add(Dummy2Model(msg="Test"))
sess.add(Dummy2Model(msg="Other"))
async with app[db].begin() as sess:
sess.add(ForeignModel(dummy=dummy.id))
schema: aiohttp_admin.Schema = {
"security": {
"check_credentials": check_credentials,
"secure": False
},
"resources": (
{"model": SAResource(engine, DummyModel)},
{"model": SAResource(engine, Dummy2Model)},
{"model": SAResource(engine, ForeignModel)}
)
}
if identity_callback:
schema["security"]["identity_callback"] = identity_callback
app[admin] = aiohttp_admin.setup(app, schema)
return await aiohttp_client(app)
return admin_client
@pytest.fixture
async def admin_client(create_admin_client: Callable[[], Awaitable[_Client]]) -> _Client:
return await create_admin_client()
@pytest.fixture
def login() -> Callable[[_Client], Awaitable[dict[str, str]]]:
async def do_login(admin_client: _Client) -> dict[str, str]:
assert admin_client.app
url = admin_client.app[admin].router["token"].url_for()
login = {"username": "admin", "password": "admin123"}
async with admin_client.post(url, json=login) as resp:
assert resp.status == 200
token = resp.headers["X-Token"]
return {"Authorization": token}
return do_login