Skip to content

Commit 4fb627b

Browse files
author
Jeny Sadadia
committed
tests/e2e_tests: drop synchronous test client
Due to `fastapi` version change, the newer `TestClient` from `fastapi` is causing issues by creating its own different event loop (Reference: https://www.starlette.io/testclient/). That conflicts with the event loop of database client created in the app startup handler. Fix the below error by using async test client for all the tests: ``` @pytest.fixture(scope='session') def test_client(): """Fixture to get FastAPI Test client instance""" with TestClient(app=versioned_app, base_url=BASE_URL) as client: tests/e2e_tests/conftest.py:36: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ api/main.py:87: in initialize_beanie await db.initialize_beanie() api/db.py:51: in initialize_beanie await init_beanie( .local/lib/python3.11/site-packages/beanie/odm/utils/init.py:750: in init_beanie await Initializer( .local/lib/python3.11/site-packages/beanie/odm/utils/init.py:128: in __await__ yield from self.init_class(model).__await__() .local/lib/python3.11/site-packages/beanie/odm/utils/init.py:713: in init_class await self.init_document(cls) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <beanie.odm.utils.init.Initializer object at 0x7457d1843cd0> cls = <class 'api.models.User'> > build_info = await self.database.command({"buildInfo": 1}) E RuntimeError: Task <Task pending name='anyio.from_thread.BlockingPortal._call_func' coro=<BlockingPortal._call_func() running at /home/kernelci/.local/lib/python3.11/site-packages/anyio/from_thread.py:217> cb=[TaskGroup._spawn.<locals>.task_done() at /home/kernelci/.local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py:699]> got Future <Future pending cb=[_chain_future.<locals>._call_check_cancel() at /usr/local/lib/python3.11/asyncio/futures.py:387]> attached to a different loop .local/lib/python3.11/site-packages/beanie/odm/utils/init.py:545: RuntimeError ``` Signed-off-by: Jeny Sadadia <jeny.sadadia@collabora.com>
1 parent 1fce878 commit 4fb627b

6 files changed

+32
-28
lines changed

tests/e2e_tests/conftest.py

-8
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
from httpx import AsyncClient
1111
from motor.motor_asyncio import AsyncIOMotorClient
1212

13-
from fastapi.testclient import TestClient
14-
1513
from api.main import versioned_app
1614
from kernelci.api.models import Node, Regression
1715

@@ -30,12 +28,6 @@
3028
'offset',
3129
}
3230

33-
@pytest.fixture(scope='session')
34-
def test_client():
35-
"""Fixture to get FastAPI Test client instance"""
36-
with TestClient(app=versioned_app, base_url=BASE_URL) as client:
37-
yield client
38-
3931

4032
@pytest.fixture(scope='session')
4133
async def test_async_client():

tests/e2e_tests/test_count_handler.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,35 @@
1010
import pytest
1111

1212

13+
@pytest.mark.asyncio
1314
@pytest.mark.dependency(
1415
depends=[
1516
'tests/e2e_tests/test_pipeline.py::test_node_pipeline'],
1617
scope='session')
17-
def test_count_nodes(test_client):
18+
async def test_count_nodes(test_async_client):
1819
"""
1920
Test Case : Test KernelCI API GET /count endpoint
2021
Expected Result :
2122
HTTP Response Code 200 OK
2223
Total number of nodes available
2324
"""
24-
response = test_client.get("count")
25+
response = await test_async_client.get("count")
2526
assert response.status_code == 200
2627
assert response.json() >= 0
2728

2829

30+
@pytest.mark.asyncio
2931
@pytest.mark.dependency(
3032
depends=[
3133
'tests/e2e_tests/test_pipeline.py::test_node_pipeline'],
3234
scope='session')
33-
def test_count_nodes_matching_attributes(test_client):
35+
async def test_count_nodes_matching_attributes(test_async_client):
3436
"""
3537
Test Case : Test KernelCI API GET /count endpoint with attributes
3638
Expected Result :
3739
HTTP Response Code 200 OK
3840
Number of nodes matching attributes
3941
"""
40-
response = test_client.get("count?name=checkout")
42+
response = await test_async_client.get("count?name=checkout")
4143
assert response.status_code == 200
4244
assert response.json() >= 0

tests/e2e_tests/test_root_handler.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55

66
"""End-to-end test functions for KernelCI API root handler"""
77

8+
import pytest
89

9-
def test_root_endpoint(test_client):
10+
11+
@pytest.mark.asyncio
12+
async def test_root_endpoint(test_async_client):
1013
"""Test root handler"""
11-
response = test_client.get("/latest")
14+
response = await test_async_client.get("/")
1215
assert response.status_code == 200
1316
assert response.json() == {"message": "KernelCI API"}

tests/e2e_tests/test_subscribe_handler.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@
99
import pytest
1010

1111

12+
@pytest.mark.asyncio
1213
@pytest.mark.dependency(
1314
depends=['tests/e2e_tests/test_user_creation.py::test_create_regular_user'],
1415
scope='session')
1516
@pytest.mark.order(3)
16-
def test_subscribe_node_channel(test_client):
17+
async def test_subscribe_node_channel(test_async_client):
1718
"""
1819
Test Case : Test KernelCI API '/subscribe' endpoint with 'node' channel
1920
Expected Result :
2021
HTTP Response Code 200 OK
2122
JSON with subscription 'id' and 'channel' keys
2223
"""
23-
response = test_client.post(
24+
response = await test_async_client.post(
2425
"subscribe/node",
2526
headers={
2627
"Authorization": f"Bearer {pytest.BEARER_TOKEN}" # pylint: disable=no-member
@@ -32,18 +33,19 @@ def test_subscribe_node_channel(test_client):
3233
assert response.json().get('channel') == 'node'
3334

3435

36+
@pytest.mark.asyncio
3537
@pytest.mark.dependency(
3638
depends=['tests/e2e_tests/test_user_creation.py::test_create_regular_user'],
3739
scope='session')
3840
@pytest.mark.order(3)
39-
def test_subscribe_test_channel(test_client):
41+
async def test_subscribe_test_channel(test_async_client):
4042
"""
4143
Test Case : Test KernelCI API '/subscribe' endpoint with 'test_channel'
4244
Expected Result :
4345
HTTP Response Code 200 OK
4446
JSON with subscription 'id' and 'channel' keys
4547
"""
46-
response = test_client.post(
48+
response = await test_async_client.post(
4749
"subscribe/test_channel",
4850
headers={
4951
"Authorization": f"Bearer {pytest.BEARER_TOKEN}" # pylint: disable=no-member
@@ -55,19 +57,20 @@ def test_subscribe_test_channel(test_client):
5557
assert response.json().get('channel') == 'test_channel'
5658

5759

60+
@pytest.mark.asyncio
5861
@pytest.mark.dependency(
5962
depends=['tests/e2e_tests/test_user_creation.py::test_create_regular_user'],
6063
scope='session')
6164
@pytest.mark.order(3)
62-
def test_subscribe_user_group_channel(test_client):
65+
async def test_subscribe_user_group_channel(test_async_client):
6366
"""
6467
Test Case : Test KernelCI API '/subscribe' endpoint with 'user_group'
6568
channel
6669
Expected Result :
6770
HTTP Response Code 200 OK
6871
JSON with subscription 'id' and 'channel' keys
6972
"""
70-
response = test_client.post(
73+
response = await test_async_client.post(
7174
"subscribe/user_group",
7275
headers={
7376
"Authorization": f"Bearer {pytest.BEARER_TOKEN}" # pylint: disable=no-member

tests/e2e_tests/test_unsubscribe_handler.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@
99
import pytest
1010

1111

12+
@pytest.mark.asyncio
1213
@pytest.mark.dependency(
1314
depends=[
1415
'tests/e2e_tests/test_subscribe_handler.py::test_subscribe_node_channel'],
1516
scope='session')
1617
@pytest.mark.order("last")
17-
def test_unsubscribe_node_channel(test_client):
18+
async def test_unsubscribe_node_channel(test_async_client):
1819
"""
1920
Test Case : Test KernelCI API '/unsubscribe' endpoint with 'node' channel
2021
Expected Result :
2122
HTTP Response Code 200 OK
2223
"""
23-
response = test_client.post(
24+
response = await test_async_client.post(
2425
f"unsubscribe/{pytest.node_channel_subscription_id}", # pylint: disable=no-member
2526
headers={
2627
"Authorization": f"Bearer {pytest.BEARER_TOKEN}" # pylint: disable=no-member
@@ -29,18 +30,19 @@ def test_unsubscribe_node_channel(test_client):
2930
assert response.status_code == 200
3031

3132

33+
@pytest.mark.asyncio
3234
@pytest.mark.dependency(
3335
depends=[
3436
'tests/e2e_tests/test_subscribe_handler.py::test_subscribe_test_channel'],
3537
scope='session')
3638
@pytest.mark.order("last")
37-
def test_unsubscribe_test_channel(test_client):
39+
async def test_unsubscribe_test_channel(test_async_client):
3840
"""
3941
Test Case : Test KernelCI API '/unsubscribe' endpoint with 'test_channel'
4042
Expected Result :
4143
HTTP Response Code 200 OK
4244
"""
43-
response = test_client.post(
45+
response = await test_async_client.post(
4446
f"unsubscribe/{pytest.test_channel_subscription_id}", # pylint: disable=no-member
4547
headers={
4648
"Authorization": f"Bearer {pytest.BEARER_TOKEN}" # pylint: disable=no-member

tests/e2e_tests/test_user_creation.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,17 @@ async def test_create_regular_user(test_async_client):
118118
pytest.BEARER_TOKEN = response.json()['access_token']
119119

120120

121+
@pytest.mark.asyncio
121122
@pytest.mark.dependency(depends=["test_create_regular_user"])
122-
def test_whoami(test_client):
123+
async def test_whoami(test_async_client):
123124
"""
124125
Test Case : Test KernelCI API /whoami endpoint
125126
Expected Result :
126127
HTTP Response Code 200 OK
127128
JSON with 'id', 'email', username', 'groups', 'is_superuser'
128129
'is_verified' and 'is_active' keys
129130
"""
130-
response = test_client.get(
131+
response = await test_async_client.get(
131132
"whoami",
132133
headers={
133134
"Accept": "application/json",
@@ -140,16 +141,17 @@ def test_whoami(test_client):
140141
assert response.json()['username'] == 'test_user'
141142

142143

144+
@pytest.mark.asyncio
143145
@pytest.mark.dependency(depends=["test_create_regular_user"])
144-
def test_create_user_negative(test_client):
146+
async def test_create_user_negative(test_async_client):
145147
"""
146148
Test Case : Test KernelCI API /user/register endpoint when requested
147149
with regular user's bearer token.
148150
Expected Result :
149151
HTTP Response Code 403 Forbidden
150152
JSON with 'detail' key denoting 'Forbidden' error
151153
"""
152-
response = test_client.post(
154+
response = await test_async_client.post(
153155
"user/register",
154156
headers={
155157
"Accept": "application/json",

0 commit comments

Comments
 (0)