|
1 | 1 | from unittest.mock import Mock
|
2 | 2 |
|
3 | 3 | import pytest
|
| 4 | +from django.utils.asyncio import async_unsafe |
4 | 5 |
|
5 | 6 | from ninja import NinjaAPI
|
6 | 7 | from ninja.errors import AuthorizationError, ConfigError
|
|
16 | 17 | )
|
17 | 18 | from ninja.security.base import AuthBase
|
18 | 19 | from ninja.testing import TestClient
|
| 20 | +from ninja.testing.client import TestAsyncClient |
19 | 21 |
|
20 | 22 |
|
21 | 23 | def callable_auth(request):
|
@@ -315,3 +317,46 @@ class MyAuth2(AuthBase):
|
315 | 317 |
|
316 | 318 | with pytest.raises(TypeError):
|
317 | 319 | HttpBasicAuth()(request)
|
| 320 | + |
| 321 | + |
| 322 | +@pytest.mark.asyncio |
| 323 | +async def test_async_auth(): |
| 324 | + _sync_auth_called = False |
| 325 | + _async_auth_called = False |
| 326 | + _async_unsafe_func_called = False |
| 327 | + |
| 328 | + # This is the same decorator Django uses to mark its ORM functions as async unsafe, |
| 329 | + # which in turns raises a `SynchronousOnlyOperation` error if called |
| 330 | + # without `sync_to_async`. |
| 331 | + @async_unsafe("called without sync_to_async") |
| 332 | + def async_unsafe_function(): |
| 333 | + nonlocal _async_unsafe_func_called |
| 334 | + _async_unsafe_func_called = True |
| 335 | + |
| 336 | + class AsyncAuth(APIKeyQuery): |
| 337 | + async def authenticate(self, request, key): |
| 338 | + nonlocal _async_auth_called |
| 339 | + _async_auth_called = True |
| 340 | + return False |
| 341 | + |
| 342 | + class SyncAuth(APIKeyQuery): |
| 343 | + def authenticate(self, request, key): |
| 344 | + async_unsafe_function() |
| 345 | + nonlocal _sync_auth_called |
| 346 | + _sync_auth_called = True |
| 347 | + return True |
| 348 | + |
| 349 | + async def handle_request(request): |
| 350 | + return {"ok": True} |
| 351 | + |
| 352 | + api = NinjaAPI(csrf=True) |
| 353 | + api.get("/foobar", auth=[AsyncAuth(), SyncAuth()])(handle_request) |
| 354 | + |
| 355 | + client = TestAsyncClient(api) |
| 356 | + response = await client.get("/foobar") |
| 357 | + assert response.status_code == 200 |
| 358 | + assert response.json() == {"ok": True} |
| 359 | + |
| 360 | + assert _sync_auth_called is True |
| 361 | + assert _async_auth_called is True |
| 362 | + assert _async_unsafe_func_called is True |
0 commit comments