tigrbl-tests 0.3.2__py3-none-any.whl → 0.3.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. tests/i9n/test_tigrbl_api_app_usage_uvicorn.py +98 -0
  2. tests/i9n/test_tigrbl_api_usage_uvicorn.py +105 -0
  3. tests/i9n/test_tigrbl_api_uvicorn.py +67 -0
  4. tests/i9n/test_tigrbl_app_include_api_uvicorn.py +149 -0
  5. tests/i9n/test_tigrbl_app_multi_api_uvicorn.py +80 -0
  6. tests/i9n/test_tigrbl_app_usage_uvicorn.py +103 -0
  7. tests/i9n/test_tigrbl_app_uvicorn.py +58 -0
  8. tests/unit/test_initialize_async_task.py +27 -0
  9. tests/unit/test_initialize_mixed_engines.py +41 -0
  10. tests/unit/test_initialize_task_schedule.py +27 -0
  11. tests/unit/test_spec_app.py +1 -1
  12. tests/unit/test_table_collect_spec.py +1 -1
  13. tests/unit/test_table_namespace_init.py +27 -0
  14. tests/unit/test_table_namespace_isolation.py +43 -0
  15. tests/unit/test_tigrbl_api_app_configuration.py +83 -0
  16. tests/unit/test_tigrbl_api_app_instantiation.py +42 -0
  17. tests/unit/test_tigrbl_api_app_subclass_definition.py +38 -0
  18. tests/unit/test_tigrbl_api_configuration.py +47 -0
  19. tests/unit/test_tigrbl_api_instantiation.py +37 -0
  20. tests/unit/test_tigrbl_api_subclass_definition.py +37 -0
  21. tests/unit/test_tigrbl_app_configuration.py +47 -0
  22. tests/unit/test_tigrbl_app_instantiation.py +37 -0
  23. tests/unit/test_tigrbl_app_subclass_definition.py +37 -0
  24. {tigrbl_tests-0.3.2.dist-info → tigrbl_tests-0.3.3.dist-info}/METADATA +16 -1
  25. {tigrbl_tests-0.3.2.dist-info → tigrbl_tests-0.3.3.dist-info}/RECORD +27 -6
  26. {tigrbl_tests-0.3.2.dist-info → tigrbl_tests-0.3.3.dist-info}/WHEEL +0 -0
  27. {tigrbl_tests-0.3.2.dist-info → tigrbl_tests-0.3.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,98 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+ from fastapi import Security
5
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
6
+
7
+ from tigrbl import Base, TigrblApi, TigrblApp
8
+ from tigrbl.engine.shortcuts import mem
9
+ from tigrbl.orm.mixins import GUIDPk
10
+ from tigrbl.specs import F, IO, S, acol
11
+ from tigrbl.types import Mapped, String
12
+
13
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
14
+
15
+
16
+ bearer = HTTPBearer()
17
+
18
+
19
+ def auth_dependency(
20
+ credentials: HTTPAuthorizationCredentials = Security(bearer),
21
+ ) -> HTTPAuthorizationCredentials:
22
+ return credentials
23
+
24
+
25
+ class Kappa(Base, GUIDPk):
26
+ __tablename__ = "kappa_api_app_usage"
27
+ __allow_unmapped__ = True
28
+
29
+ name: Mapped[str] = acol(
30
+ storage=S(type_=String, nullable=False),
31
+ field=F(py_type=str),
32
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
33
+ )
34
+
35
+ __tigrbl_cols__ = {"id": GUIDPk.id, "name": name}
36
+
37
+
38
+ class KappaApi(TigrblApi):
39
+ MODELS = (Kappa,)
40
+
41
+
42
+ @pytest_asyncio.fixture()
43
+ async def running_api_app():
44
+ api = KappaApi(engine=mem(async_=False))
45
+ api.set_auth(authn=auth_dependency, allow_anon=False)
46
+ api.include_models([Kappa])
47
+ api.initialize()
48
+
49
+ class KappaApp(TigrblApp):
50
+ APIS = (api,)
51
+
52
+ app = KappaApp(engine=mem(async_=False))
53
+ app.include_router(api)
54
+
55
+ base_url, server, task = await run_uvicorn_in_task(app)
56
+ try:
57
+ yield base_url
58
+ finally:
59
+ await stop_uvicorn_server(server, task)
60
+
61
+
62
+ @pytest.mark.i9n
63
+ @pytest.mark.asyncio
64
+ async def test_tigrbl_api_app_deploys_and_serves_openapi(running_api_app) -> None:
65
+ base_url = running_api_app
66
+
67
+ async with httpx.AsyncClient() as client:
68
+ openapi_resp = await client.get(f"{base_url}/openapi.json")
69
+
70
+ assert openapi_resp.status_code == 200
71
+ openapi = openapi_resp.json()
72
+ paths = openapi["paths"]
73
+
74
+ assert "/kappa" in paths
75
+ assert "/kappa/{item_id}" in paths
76
+ assert {"get", "post", "delete"}.issubset(paths["/kappa"])
77
+ assert {"get", "patch", "put", "delete"}.issubset(paths["/kappa/{item_id}"])
78
+
79
+ security_schemes = openapi.get("components", {}).get("securitySchemes", {})
80
+ assert "HTTPBearer" in security_schemes
81
+
82
+
83
+ @pytest.mark.i9n
84
+ @pytest.mark.asyncio
85
+ async def test_tigrbl_api_app_handles_authenticated_request(running_api_app) -> None:
86
+ base_url = running_api_app
87
+ headers = {"Authorization": "Bearer demo"}
88
+
89
+ async with httpx.AsyncClient() as client:
90
+ resp = await client.post(
91
+ f"{base_url}/kappa",
92
+ json={"name": "Kappa"},
93
+ headers=headers,
94
+ )
95
+
96
+ assert resp.status_code == 201
97
+ payload = resp.json()
98
+ assert payload["name"] == "Kappa"
@@ -0,0 +1,105 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+ from fastapi import Security
5
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
6
+
7
+ from tigrbl import Base, TigrblApi
8
+ from tigrbl.engine.shortcuts import mem
9
+ from tigrbl.orm.mixins import GUIDPk
10
+ from tigrbl.specs import F, IO, S, acol
11
+ from tigrbl.types import App, Mapped, String
12
+
13
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
14
+
15
+
16
+ bearer = HTTPBearer()
17
+
18
+
19
+ def auth_dependency(
20
+ credentials: HTTPAuthorizationCredentials = Security(bearer),
21
+ ) -> HTTPAuthorizationCredentials:
22
+ return credentials
23
+
24
+
25
+ class Alpha(Base, GUIDPk):
26
+ __tablename__ = "alpha_api_usage"
27
+ __allow_unmapped__ = True
28
+
29
+ name: Mapped[str] = acol(
30
+ storage=S(type_=String, nullable=False),
31
+ field=F(py_type=str),
32
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
33
+ )
34
+
35
+ __tigrbl_cols__ = {"id": GUIDPk.id, "name": name}
36
+
37
+
38
+ class Beta(Base, GUIDPk):
39
+ __tablename__ = "beta_api_usage"
40
+ __allow_unmapped__ = True
41
+
42
+ name: Mapped[str] = acol(
43
+ storage=S(type_=String, nullable=False),
44
+ field=F(py_type=str),
45
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
46
+ )
47
+
48
+ __tigrbl_cols__ = {"id": GUIDPk.id, "name": name}
49
+
50
+
51
+ @pytest_asyncio.fixture()
52
+ async def running_api():
53
+ app = App()
54
+ api = TigrblApi(engine=mem(async_=False))
55
+ api.set_auth(authn=auth_dependency, allow_anon=False)
56
+ api.include_models([Alpha, Beta])
57
+ api.initialize()
58
+ app.include_router(api)
59
+
60
+ base_url, server, task = await run_uvicorn_in_task(app)
61
+ try:
62
+ yield base_url
63
+ finally:
64
+ await stop_uvicorn_server(server, task)
65
+
66
+
67
+ @pytest.mark.i9n
68
+ @pytest.mark.asyncio
69
+ async def test_tigrbl_api_deploys_and_serves_openapi(running_api) -> None:
70
+ base_url = running_api
71
+
72
+ async with httpx.AsyncClient() as client:
73
+ openapi_resp = await client.get(f"{base_url}/openapi.json")
74
+
75
+ assert openapi_resp.status_code == 200
76
+ openapi = openapi_resp.json()
77
+ paths = openapi["paths"]
78
+
79
+ assert "/alpha" in paths
80
+ assert "/alpha/{item_id}" in paths
81
+ assert "/beta" in paths
82
+ assert "/beta/{item_id}" in paths
83
+ assert {"get", "post", "delete"}.issubset(paths["/alpha"])
84
+ assert {"get", "patch", "put", "delete"}.issubset(paths["/alpha/{item_id}"])
85
+
86
+ security_schemes = openapi.get("components", {}).get("securitySchemes", {})
87
+ assert "HTTPBearer" in security_schemes
88
+
89
+
90
+ @pytest.mark.i9n
91
+ @pytest.mark.asyncio
92
+ async def test_tigrbl_api_handles_authenticated_request(running_api) -> None:
93
+ base_url = running_api
94
+ headers = {"Authorization": "Bearer demo"}
95
+
96
+ async with httpx.AsyncClient() as client:
97
+ resp = await client.post(
98
+ f"{base_url}/alpha",
99
+ json={"name": "Alpha"},
100
+ headers=headers,
101
+ )
102
+
103
+ assert resp.status_code == 201
104
+ payload = resp.json()
105
+ assert payload["name"] == "Alpha"
@@ -0,0 +1,67 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+
5
+ from tigrbl import Base, TigrblApi
6
+ from tigrbl.engine.shortcuts import mem
7
+ from tigrbl.orm.mixins import GUIDPk
8
+ from tigrbl.specs import F, IO, S, acol
9
+ from tigrbl.types import App, Mapped, String
10
+
11
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
12
+
13
+
14
+ class Gadget(Base, GUIDPk):
15
+ __tablename__ = "gadgets_api"
16
+ __resource__ = "gadget"
17
+
18
+ name: Mapped[str] = acol(
19
+ storage=S(String, nullable=False),
20
+ field=F(py_type=str),
21
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
22
+ )
23
+
24
+
25
+ @pytest_asyncio.fixture()
26
+ async def running_api_app():
27
+ api = TigrblApi(
28
+ engine=mem(async_=False),
29
+ models=[Gadget],
30
+ prefix="/gadgets",
31
+ system_prefix="/diagnostics",
32
+ )
33
+ await api.initialize()
34
+
35
+ app = App()
36
+ app.include_router(api.router)
37
+ api.attach_diagnostics(app=app)
38
+
39
+ base_url, server, task = await run_uvicorn_in_task(app)
40
+ try:
41
+ yield base_url
42
+ finally:
43
+ await stop_uvicorn_server(server, task)
44
+
45
+
46
+ @pytest.mark.i9n
47
+ @pytest.mark.asyncio
48
+ async def test_tigrbl_api_create_gadget(running_api_app):
49
+ async with httpx.AsyncClient() as client:
50
+ response = await client.post(
51
+ f"{running_api_app}/gadgets/gadget", json={"name": "gyro"}
52
+ )
53
+
54
+ assert response.status_code == 201
55
+ payload = response.json()
56
+ assert payload["name"] == "gyro"
57
+ assert "id" in payload
58
+
59
+
60
+ @pytest.mark.i9n
61
+ @pytest.mark.asyncio
62
+ async def test_tigrbl_api_healthz(running_api_app):
63
+ async with httpx.AsyncClient() as client:
64
+ response = await client.get(f"{running_api_app}/diagnostics/healthz")
65
+
66
+ assert response.status_code == 200
67
+ assert response.json()["ok"] is True
@@ -0,0 +1,149 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+
5
+ from tigrbl import Base, TigrblApi, TigrblApp
6
+ from tigrbl.engine.shortcuts import mem
7
+ from tigrbl.orm.mixins import GUIDPk
8
+ from tigrbl.specs import F, IO, S, acol
9
+ from tigrbl.types import Mapped, String
10
+
11
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
12
+
13
+
14
+ class AlphaWidget(Base, GUIDPk):
15
+ __tablename__ = "alpha_widgets_alt"
16
+ __resource__ = "alpha-widget"
17
+
18
+ name: Mapped[str] = acol(
19
+ storage=S(String, nullable=False),
20
+ field=F(py_type=str),
21
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
22
+ )
23
+
24
+
25
+ class BetaWidget(Base, GUIDPk):
26
+ __tablename__ = "beta_widgets_alt"
27
+ __resource__ = "beta-widget"
28
+
29
+ name: Mapped[str] = acol(
30
+ storage=S(String, nullable=False),
31
+ field=F(py_type=str),
32
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
33
+ )
34
+
35
+
36
+ class ZetaWidget(Base, GUIDPk):
37
+ __tablename__ = "zeta_widgets_alt"
38
+ __resource__ = "zeta-widget"
39
+
40
+ name: Mapped[str] = acol(
41
+ storage=S(String, nullable=False),
42
+ field=F(py_type=str),
43
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
44
+ )
45
+
46
+
47
+ @pytest_asyncio.fixture()
48
+ async def running_app_with_apis():
49
+ engine = mem(async_=False)
50
+ alpha_api = TigrblApi(engine=engine, models=[AlphaWidget], prefix="/alpha")
51
+ beta_api = TigrblApi(engine=engine)
52
+ beta_api.include_model(BetaWidget)
53
+ zeta_api = TigrblApi(engine=engine)
54
+ zeta_api.include_model(ZetaWidget)
55
+
56
+ app = TigrblApp(engine=engine, apis=[alpha_api, (zeta_api, "/zeta")])
57
+ app.include_api(beta_api, prefix="/beta")
58
+ await app.initialize()
59
+
60
+ base_url, server, task = await run_uvicorn_in_task(app)
61
+ try:
62
+ yield base_url
63
+ finally:
64
+ await stop_uvicorn_server(server, task)
65
+
66
+
67
+ @pytest_asyncio.fixture()
68
+ async def running_app_with_api_router():
69
+ engine = mem(async_=False)
70
+ alpha_api = TigrblApi(engine=engine)
71
+ alpha_api.include_model(AlphaWidget)
72
+ beta_api = TigrblApi(engine=engine)
73
+ beta_api.include_model(BetaWidget)
74
+
75
+ app = TigrblApp(engine=engine, apis=[alpha_api])
76
+ app.include_api(beta_api, prefix="/beta")
77
+ app.include_api(alpha_api.router, prefix="/alpha")
78
+ await app.initialize()
79
+
80
+ base_url, server, task = await run_uvicorn_in_task(app)
81
+ try:
82
+ yield base_url
83
+ finally:
84
+ await stop_uvicorn_server(server, task)
85
+
86
+
87
+ @pytest.mark.i9n
88
+ @pytest.mark.asyncio
89
+ async def test_tigrbl_app_api_list_alpha(running_app_with_apis):
90
+ async with httpx.AsyncClient() as client:
91
+ response = await client.post(
92
+ f"{running_app_with_apis}/alpha/alpha-widget", json={"name": "ace"}
93
+ )
94
+
95
+ assert response.status_code == 201
96
+ payload = response.json()
97
+ assert payload["name"] == "ace"
98
+
99
+
100
+ @pytest.mark.i9n
101
+ @pytest.mark.asyncio
102
+ async def test_tigrbl_app_include_api_beta(running_app_with_apis):
103
+ async with httpx.AsyncClient() as client:
104
+ response = await client.post(
105
+ f"{running_app_with_apis}/beta/beta-widget", json={"name": "bolt"}
106
+ )
107
+
108
+ assert response.status_code == 201
109
+ payload = response.json()
110
+ assert payload["name"] == "bolt"
111
+
112
+
113
+ @pytest.mark.i9n
114
+ @pytest.mark.asyncio
115
+ async def test_tigrbl_app_api_list_zeta(running_app_with_apis):
116
+ async with httpx.AsyncClient() as client:
117
+ response = await client.post(
118
+ f"{running_app_with_apis}/zeta/zeta-widget", json={"name": "zen"}
119
+ )
120
+
121
+ assert response.status_code == 201
122
+ payload = response.json()
123
+ assert payload["name"] == "zen"
124
+
125
+
126
+ @pytest.mark.i9n
127
+ @pytest.mark.asyncio
128
+ async def test_tigrbl_app_include_api_router_alpha(running_app_with_api_router):
129
+ async with httpx.AsyncClient() as client:
130
+ response = await client.post(
131
+ f"{running_app_with_api_router}/alpha/alpha-widget", json={"name": "ace"}
132
+ )
133
+
134
+ assert response.status_code == 201
135
+ payload = response.json()
136
+ assert payload["name"] == "ace"
137
+
138
+
139
+ @pytest.mark.i9n
140
+ @pytest.mark.asyncio
141
+ async def test_tigrbl_app_include_api_router_beta(running_app_with_api_router):
142
+ async with httpx.AsyncClient() as client:
143
+ response = await client.post(
144
+ f"{running_app_with_api_router}/beta/beta-widget", json={"name": "bolt"}
145
+ )
146
+
147
+ assert response.status_code == 201
148
+ payload = response.json()
149
+ assert payload["name"] == "bolt"
@@ -0,0 +1,80 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+
5
+ from tigrbl import Base, TigrblApi, TigrblApp
6
+ from tigrbl.engine.shortcuts import mem
7
+ from tigrbl.orm.mixins import GUIDPk
8
+ from tigrbl.specs import F, IO, S, acol
9
+ from tigrbl.types import Mapped, String
10
+
11
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
12
+
13
+
14
+ class AlphaWidget(Base, GUIDPk):
15
+ __tablename__ = "alpha_widgets"
16
+ __resource__ = "alpha-widget"
17
+
18
+ name: Mapped[str] = acol(
19
+ storage=S(String, nullable=False),
20
+ field=F(py_type=str),
21
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
22
+ )
23
+
24
+
25
+ class BetaWidget(Base, GUIDPk):
26
+ __tablename__ = "beta_widgets"
27
+ __resource__ = "beta-widget"
28
+
29
+ name: Mapped[str] = acol(
30
+ storage=S(String, nullable=False),
31
+ field=F(py_type=str),
32
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
33
+ )
34
+
35
+
36
+ @pytest_asyncio.fixture()
37
+ async def running_multi_api_app():
38
+ engine = mem(async_=False)
39
+ alpha_api = TigrblApi(engine=engine)
40
+ alpha_api.include_model(AlphaWidget)
41
+
42
+ beta_api = TigrblApi(engine=engine)
43
+ beta_api.include_model(BetaWidget)
44
+
45
+ app = TigrblApp(engine=engine, apis=[alpha_api])
46
+ app.include_router(beta_api, prefix="/beta")
47
+ app.include_router(alpha_api.router, prefix="/alpha")
48
+ await app.initialize()
49
+
50
+ base_url, server, task = await run_uvicorn_in_task(app)
51
+ try:
52
+ yield base_url
53
+ finally:
54
+ await stop_uvicorn_server(server, task)
55
+
56
+
57
+ @pytest.mark.i9n
58
+ @pytest.mark.asyncio
59
+ async def test_tigrbl_app_routes_alpha_api(running_multi_api_app):
60
+ async with httpx.AsyncClient() as client:
61
+ response = await client.post(
62
+ f"{running_multi_api_app}/alpha/alpha-widget", json={"name": "ace"}
63
+ )
64
+
65
+ assert response.status_code == 201
66
+ payload = response.json()
67
+ assert payload["name"] == "ace"
68
+
69
+
70
+ @pytest.mark.i9n
71
+ @pytest.mark.asyncio
72
+ async def test_tigrbl_app_routes_beta_api(running_multi_api_app):
73
+ async with httpx.AsyncClient() as client:
74
+ response = await client.post(
75
+ f"{running_multi_api_app}/beta/beta-widget", json={"name": "bolt"}
76
+ )
77
+
78
+ assert response.status_code == 201
79
+ payload = response.json()
80
+ assert payload["name"] == "bolt"
@@ -0,0 +1,103 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+ from fastapi import Security
5
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
6
+
7
+ from tigrbl import Base, TigrblApp
8
+ from tigrbl.engine.shortcuts import mem
9
+ from tigrbl.orm.mixins import GUIDPk
10
+ from tigrbl.specs import F, IO, S, acol
11
+ from tigrbl.types import Mapped, String
12
+
13
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
14
+
15
+
16
+ bearer = HTTPBearer()
17
+
18
+
19
+ def auth_dependency(
20
+ credentials: HTTPAuthorizationCredentials = Security(bearer),
21
+ ) -> HTTPAuthorizationCredentials:
22
+ return credentials
23
+
24
+
25
+ class Gamma(Base, GUIDPk):
26
+ __tablename__ = "gamma_app_usage"
27
+ __allow_unmapped__ = True
28
+
29
+ name: Mapped[str] = acol(
30
+ storage=S(type_=String, nullable=False),
31
+ field=F(py_type=str),
32
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
33
+ )
34
+
35
+ __tigrbl_cols__ = {"id": GUIDPk.id, "name": name}
36
+
37
+
38
+ class Delta(Base, GUIDPk):
39
+ __tablename__ = "delta_app_usage"
40
+ __allow_unmapped__ = True
41
+
42
+ name: Mapped[str] = acol(
43
+ storage=S(type_=String, nullable=False),
44
+ field=F(py_type=str),
45
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
46
+ )
47
+
48
+ __tigrbl_cols__ = {"id": GUIDPk.id, "name": name}
49
+
50
+
51
+ @pytest_asyncio.fixture()
52
+ async def running_app():
53
+ app = TigrblApp(engine=mem(async_=False))
54
+ app.set_auth(authn=auth_dependency, allow_anon=False)
55
+ app.include_models([Gamma, Delta])
56
+ app.initialize()
57
+
58
+ base_url, server, task = await run_uvicorn_in_task(app)
59
+ try:
60
+ yield base_url
61
+ finally:
62
+ await stop_uvicorn_server(server, task)
63
+
64
+
65
+ @pytest.mark.i9n
66
+ @pytest.mark.asyncio
67
+ async def test_tigrbl_app_deploys_and_serves_openapi(running_app) -> None:
68
+ base_url = running_app
69
+
70
+ async with httpx.AsyncClient() as client:
71
+ openapi_resp = await client.get(f"{base_url}/openapi.json")
72
+
73
+ assert openapi_resp.status_code == 200
74
+ openapi = openapi_resp.json()
75
+ paths = openapi["paths"]
76
+
77
+ assert "/gamma" in paths
78
+ assert "/gamma/{item_id}" in paths
79
+ assert "/delta" in paths
80
+ assert "/delta/{item_id}" in paths
81
+ assert {"get", "post", "delete"}.issubset(paths["/gamma"])
82
+ assert {"get", "patch", "put", "delete"}.issubset(paths["/gamma/{item_id}"])
83
+
84
+ security_schemes = openapi.get("components", {}).get("securitySchemes", {})
85
+ assert "HTTPBearer" in security_schemes
86
+
87
+
88
+ @pytest.mark.i9n
89
+ @pytest.mark.asyncio
90
+ async def test_tigrbl_app_handles_authenticated_request(running_app) -> None:
91
+ base_url = running_app
92
+ headers = {"Authorization": "Bearer demo"}
93
+
94
+ async with httpx.AsyncClient() as client:
95
+ resp = await client.post(
96
+ f"{base_url}/gamma",
97
+ json={"name": "Gamma"},
98
+ headers=headers,
99
+ )
100
+
101
+ assert resp.status_code == 201
102
+ payload = resp.json()
103
+ assert payload["name"] == "Gamma"
@@ -0,0 +1,58 @@
1
+ import httpx
2
+ import pytest
3
+ import pytest_asyncio
4
+
5
+ from tigrbl import Base, TigrblApp
6
+ from tigrbl.engine.shortcuts import mem
7
+ from tigrbl.orm.mixins import GUIDPk
8
+ from tigrbl.specs import F, IO, S, acol
9
+ from tigrbl.types import Mapped, String
10
+
11
+ from .uvicorn_utils import run_uvicorn_in_task, stop_uvicorn_server
12
+
13
+
14
+ class Widget(Base, GUIDPk):
15
+ __tablename__ = "widgets_app"
16
+ __resource__ = "widget"
17
+
18
+ name: Mapped[str] = acol(
19
+ storage=S(String, nullable=False),
20
+ field=F(py_type=str),
21
+ io=IO(in_verbs=("create",), out_verbs=("create", "read", "list")),
22
+ )
23
+
24
+
25
+ @pytest_asyncio.fixture()
26
+ async def running_app():
27
+ app = TigrblApp(engine=mem(async_=False))
28
+ app.include_model(Widget)
29
+ app.attach_diagnostics()
30
+ await app.initialize()
31
+
32
+ base_url, server, task = await run_uvicorn_in_task(app)
33
+ try:
34
+ yield base_url
35
+ finally:
36
+ await stop_uvicorn_server(server, task)
37
+
38
+
39
+ @pytest.mark.i9n
40
+ @pytest.mark.asyncio
41
+ async def test_tigrbl_app_create_widget(running_app):
42
+ async with httpx.AsyncClient() as client:
43
+ response = await client.post(f"{running_app}/widget", json={"name": "alpha"})
44
+
45
+ assert response.status_code == 201
46
+ payload = response.json()
47
+ assert payload["name"] == "alpha"
48
+ assert "id" in payload
49
+
50
+
51
+ @pytest.mark.i9n
52
+ @pytest.mark.asyncio
53
+ async def test_tigrbl_app_healthz(running_app):
54
+ async with httpx.AsyncClient() as client:
55
+ response = await client.get(f"{running_app}/system/healthz")
56
+
57
+ assert response.status_code == 200
58
+ assert response.json()["ok"] is True
@@ -0,0 +1,27 @@
1
+ import asyncio
2
+
3
+ import pytest
4
+ from sqlalchemy import Column, Integer
5
+
6
+ from tigrbl import Base, TigrblApp
7
+ from tigrbl.engine.shortcuts import mem
8
+
9
+
10
+ class Widget(Base):
11
+ __tablename__ = "widgets_async_task"
12
+
13
+ id = Column(Integer, primary_key=True)
14
+
15
+
16
+ @pytest.mark.asyncio
17
+ async def test_initialize_returns_task_for_async_engine():
18
+ app = TigrblApp(engine=mem())
19
+ app.include_model(Widget, prefix="")
20
+
21
+ result = app.initialize()
22
+
23
+ assert isinstance(result, asyncio.Task)
24
+
25
+ await result
26
+
27
+ assert getattr(app, "_ddl_executed", False) is True