Skip to content

Commit 47eb205

Browse files
committed
✨ [Tests] Enhance test fixtures with AsyncExitStack for better resource management
1 parent 6cd2a96 commit 47eb205

File tree

11 files changed

+84
-42
lines changed

11 files changed

+84
-42
lines changed

services/web/server/tests/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# pylint: disable=unused-variable
55

66
import asyncio
7+
import contextlib
78
import json
89
import logging
910
import random
@@ -88,6 +89,13 @@
8889
]
8990

9091

92+
@pytest.fixture
93+
async def exit_stack() -> AsyncIterator[contextlib.AsyncExitStack]:
94+
"""Provides an AsyncExitStack that gets cleaned up after each test"""
95+
async with contextlib.AsyncExitStack() as stack:
96+
yield stack
97+
98+
9199
@pytest.fixture(scope="session")
92100
def package_dir() -> Path:
93101
"""osparc-simcore installed directory"""

services/web/server/tests/integration/01/test_garbage_collection.py

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# pylint: disable=unused-variable
44

55
import asyncio
6+
import contextlib
67
import logging
78
import re
89
from collections.abc import AsyncIterable, Awaitable, Callable
@@ -203,14 +204,20 @@ async def _fake_background_task(app: web.Application):
203204
)
204205

205206

206-
async def login_user(client: TestClient):
207+
async def login_user(client: TestClient, *, exit_stack: contextlib.AsyncExitStack):
207208
"""returns a logged in regular user"""
208-
return await log_client_in(client=client, user_data={"role": UserRole.USER.name})
209+
return await log_client_in(
210+
client=client, user_data={"role": UserRole.USER.name}, exit_stack=exit_stack
211+
)
209212

210213

211-
async def login_guest_user(client: TestClient):
214+
async def login_guest_user(
215+
client: TestClient, *, exit_stack: contextlib.AsyncExitStack
216+
):
212217
"""returns a logged in Guest user"""
213-
return await log_client_in(client=client, user_data={"role": UserRole.GUEST.name})
218+
return await log_client_in(
219+
client=client, user_data={"role": UserRole.GUEST.name}, exit_stack=exit_stack
220+
)
214221

215222

216223
async def new_project(
@@ -482,10 +489,11 @@ async def test_t1_while_guest_is_connected_no_resources_are_removed(
482489
aiopg_engine: aiopg.sa.engine.Engine,
483490
tests_data_dir: Path,
484491
osparc_product_name: str,
492+
exit_stack: contextlib.AsyncExitStack,
485493
):
486494
"""while a GUEST user is connected GC will not remove none of its projects nor the user itself"""
487495
assert client.app
488-
logged_guest_user = await login_guest_user(client)
496+
logged_guest_user = await login_guest_user(client, exit_stack=exit_stack)
489497
empty_guest_user_project = await new_project(
490498
client, logged_guest_user, osparc_product_name, tests_data_dir
491499
)
@@ -508,10 +516,11 @@ async def test_t2_cleanup_resources_after_browser_is_closed(
508516
aiopg_engine: aiopg.sa.engine.Engine,
509517
tests_data_dir: Path,
510518
osparc_product_name: str,
519+
exit_stack: contextlib.AsyncExitStack,
511520
):
512521
"""After a GUEST users with one opened project closes browser tab regularly (GC cleans everything)"""
513522
assert client.app
514-
logged_guest_user = await login_guest_user(client)
523+
logged_guest_user = await login_guest_user(client, exit_stack=exit_stack)
515524
empty_guest_user_project = await new_project(
516525
client, logged_guest_user, osparc_product_name, tests_data_dir
517526
)
@@ -557,11 +566,12 @@ async def test_t3_gc_will_not_intervene_for_regular_users_and_their_resources(
557566
fake_project: dict,
558567
tests_data_dir: Path,
559568
osparc_product_name: str,
569+
exit_stack: contextlib.AsyncExitStack,
560570
):
561571
"""after a USER disconnects the GC will remove none of its projects or templates nor the user itself"""
562572
number_of_projects = 5
563573
number_of_templates = 5
564-
logged_user = await login_user(client)
574+
logged_user = await login_user(client, exit_stack=exit_stack)
565575
user_projects = [
566576
await new_project(client, logged_user, osparc_product_name, tests_data_dir)
567577
for _ in range(number_of_projects)
@@ -604,16 +614,17 @@ async def test_t4_project_shared_with_group_transferred_to_user_in_group_on_owne
604614
aiopg_engine: aiopg.sa.engine.Engine,
605615
tests_data_dir: Path,
606616
osparc_product_name: str,
617+
exit_stack: contextlib.AsyncExitStack,
607618
):
608619
"""
609620
USER "u1" creates a GROUP "g1" and invites USERS "u2" and "u3";
610621
USER "u1" creates a project and shares it with "g1";
611622
USER "u1" is manually marked as "GUEST";
612623
EXPECTED: one of the users in the "g1" will become the new owner of the project and "u1" will be deleted
613624
"""
614-
u1 = await login_user(client)
615-
u2 = await login_user(client)
616-
u3 = await login_user(client)
625+
u1 = await login_user(client, exit_stack=exit_stack)
626+
u2 = await login_user(client, exit_stack=exit_stack)
627+
u3 = await login_user(client, exit_stack=exit_stack)
617628

618629
# creating g1 and inviting u2 and u3
619630
g1 = await get_group(client, u1)
@@ -648,15 +659,16 @@ async def test_t5_project_shared_with_other_users_transferred_to_one_of_them(
648659
aiopg_engine: aiopg.sa.engine.Engine,
649660
tests_data_dir: Path,
650661
osparc_product_name: str,
662+
exit_stack: contextlib.AsyncExitStack,
651663
):
652664
"""
653665
USER "u1" creates a project and shares it with "u2" and "u3";
654666
USER "u1" is manually marked as "GUEST";
655667
EXPECTED: one of "u2" or "u3" will become the new owner of the project and "u1" will be deleted
656668
"""
657-
u1 = await login_user(client)
658-
u2 = await login_user(client)
659-
u3 = await login_user(client)
669+
u1 = await login_user(client, exit_stack=exit_stack)
670+
u2 = await login_user(client, exit_stack=exit_stack)
671+
u3 = await login_user(client, exit_stack=exit_stack)
660672

661673
q_u2 = await fetch_user_from_db(aiopg_engine, u2)
662674
assert q_u2
@@ -694,6 +706,7 @@ async def test_t6_project_shared_with_group_transferred_to_last_user_in_group_on
694706
aiopg_engine: aiopg.sa.engine.Engine,
695707
tests_data_dir: Path,
696708
osparc_product_name: str,
709+
exit_stack: contextlib.AsyncExitStack,
697710
):
698711
"""
699712
USER "u1" creates a GROUP "g1" and invites USERS "u2" and "u3";
@@ -703,9 +716,9 @@ async def test_t6_project_shared_with_group_transferred_to_last_user_in_group_on
703716
the new owner either "u2" or "u3" will be manually marked as "GUEST";
704717
EXPECTED: the GUEST user will be deleted and the project will pass to the last member of "g1"
705718
"""
706-
u1 = await login_user(client)
707-
u2 = await login_user(client)
708-
u3 = await login_user(client)
719+
u1 = await login_user(client, exit_stack=exit_stack)
720+
u2 = await login_user(client, exit_stack=exit_stack)
721+
u3 = await login_user(client, exit_stack=exit_stack)
709722

710723
# creating g1 and inviting u2 and u3
711724
g1 = await get_group(client, u1)
@@ -765,6 +778,7 @@ async def test_t7_project_shared_with_group_transferred_from_one_member_to_the_l
765778
aiopg_engine: aiopg.sa.engine.Engine,
766779
tests_data_dir: Path,
767780
osparc_product_name: str,
781+
exit_stack: contextlib.AsyncExitStack,
768782
):
769783
"""
770784
USER "u1" creates a GROUP "g1" and invites USERS "u2" and "u3";
@@ -777,9 +791,9 @@ async def test_t7_project_shared_with_group_transferred_from_one_member_to_the_l
777791
EXPECTED: the last user will be removed and the project will be removed
778792
"""
779793
assert client.app
780-
u1 = await login_user(client)
781-
u2 = await login_user(client)
782-
u3 = await login_user(client)
794+
u1 = await login_user(client, exit_stack=exit_stack)
795+
u2 = await login_user(client, exit_stack=exit_stack)
796+
u3 = await login_user(client, exit_stack=exit_stack)
783797

784798
# creating g1 and inviting u2 and u3
785799
g1 = await get_group(client, u1)
@@ -853,6 +867,7 @@ async def test_t8_project_shared_with_other_users_transferred_to_one_of_them_unt
853867
aiopg_engine: aiopg.sa.engine.Engine,
854868
tests_data_dir: Path,
855869
osparc_product_name: str,
870+
exit_stack: contextlib.AsyncExitStack,
856871
):
857872
"""
858873
USER "u1" creates a project and shares it with "u2" and "u3";
@@ -861,9 +876,9 @@ async def test_t8_project_shared_with_other_users_transferred_to_one_of_them_unt
861876
same as T5 => afterwards afterwards the new owner either "u2" or "u3" will be manually marked as "GUEST";
862877
EXPECTED: the GUEST user will be deleted and the project will pass to the last member of "g1"
863878
"""
864-
u1 = await login_user(client)
865-
u2 = await login_user(client)
866-
u3 = await login_user(client)
879+
u1 = await login_user(client, exit_stack=exit_stack)
880+
u2 = await login_user(client, exit_stack=exit_stack)
881+
u3 = await login_user(client, exit_stack=exit_stack)
867882

868883
q_u2 = await fetch_user_from_db(aiopg_engine, u2)
869884
assert q_u2
@@ -927,6 +942,7 @@ async def test_t9_project_shared_with_other_users_transferred_between_them_and_t
927942
aiopg_engine: aiopg.sa.engine.Engine,
928943
tests_data_dir: Path,
929944
osparc_product_name: str,
945+
exit_stack: contextlib.AsyncExitStack,
930946
):
931947
"""
932948
USER "u1" creates a project and shares it with "u2" and "u3";
@@ -937,9 +953,9 @@ async def test_t9_project_shared_with_other_users_transferred_between_them_and_t
937953
same as T8 => afterwards the last user will be marked as "GUEST";
938954
EXPECTED: the last user will be removed and the project will be removed
939955
"""
940-
u1 = await login_user(client)
941-
u2 = await login_user(client)
942-
u3 = await login_user(client)
956+
u1 = await login_user(client, exit_stack=exit_stack)
957+
u2 = await login_user(client, exit_stack=exit_stack)
958+
u3 = await login_user(client, exit_stack=exit_stack)
943959

944960
q_u2 = await fetch_user_from_db(aiopg_engine, u2)
945961
assert q_u2
@@ -1014,6 +1030,7 @@ async def test_t10_owner_and_all_shared_users_marked_as_guests(
10141030
aiopg_engine: aiopg.sa.engine.Engine,
10151031
tests_data_dir: Path,
10161032
osparc_product_name: str,
1033+
exit_stack: contextlib.AsyncExitStack,
10171034
):
10181035
"""
10191036
USER "u1" creates a project and shares it with "u2" and "u3";
@@ -1026,9 +1043,9 @@ async def test_t10_owner_and_all_shared_users_marked_as_guests(
10261043
)
10271044
assert not gc_task.done()
10281045

1029-
u1 = await login_user(client)
1030-
u2 = await login_user(client)
1031-
u3 = await login_user(client)
1046+
u1 = await login_user(client, exit_stack=exit_stack)
1047+
u2 = await login_user(client, exit_stack=exit_stack)
1048+
u3 = await login_user(client, exit_stack=exit_stack)
10321049

10331050
q_u2 = await fetch_user_from_db(aiopg_engine, u2)
10341051
q_u3 = await fetch_user_from_db(aiopg_engine, u3)
@@ -1067,16 +1084,17 @@ async def test_t11_owner_and_all_users_in_group_marked_as_guests(
10671084
aiopg_engine: aiopg.sa.engine.Engine,
10681085
tests_data_dir: Path,
10691086
osparc_product_name: str,
1087+
exit_stack: contextlib.AsyncExitStack,
10701088
):
10711089
"""
10721090
USER "u1" creates a group and invites "u2" and "u3";
10731091
USER "u1" creates a project and shares it with the group
10741092
USER "u1", "u2" and "u3" are manually marked as "GUEST"
10751093
EXPECTED: the project and all the users are removed
10761094
"""
1077-
u1 = await login_user(client)
1078-
u2 = await login_user(client)
1079-
u3 = await login_user(client)
1095+
u1 = await login_user(client, exit_stack=exit_stack)
1096+
u2 = await login_user(client, exit_stack=exit_stack)
1097+
u3 = await login_user(client, exit_stack=exit_stack)
10801098

10811099
# creating g1 and inviting u2 and u3
10821100
g1 = await get_group(client, u1)

services/web/server/tests/unit/with_dbs/01/groups/test_groups_handlers_crud.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async def test_list_user_groups_and_try_modify_organizations(
5959
):
6060
assert client.app
6161
assert logged_user["id"] != standard_groups_owner["id"]
62-
assert logged_user["role"] == user_role.value
62+
assert logged_user["role"] == user_role
6363

6464
# List all groups (organizations, primary, everyone and products) I belong to
6565
url = client.app.router["list_groups"].url_for()
@@ -130,7 +130,7 @@ async def test_group_creation_workflow(
130130
):
131131
assert client.app
132132
assert logged_user["id"] != 0
133-
assert logged_user["role"] == user_role.value
133+
assert logged_user["role"] == user_role
134134

135135
url = client.app.router["create_group"].url_for()
136136
new_group_data = {

services/web/server/tests/unit/with_dbs/01/groups/test_groups_handlers_users.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ async def test_create_organization_and_add_users(
552552
):
553553
assert client.app
554554
assert logged_user["id"] != 0
555-
assert logged_user["role"] == user_role.value
555+
assert logged_user["role"] == user_role
556556

557557
# CREATE GROUP
558558
url = client.app.router["create_group"].url_for()

services/web/server/tests/unit/with_dbs/02/test_projects_groups_handlers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ async def test_share_project_with_roles(
311311
):
312312
assert client.app
313313

314-
assert logged_user["role"] == user_role.value
314+
assert logged_user["role"] == user_role
315315

316316
# Attempt to share the project
317317
url = client.app.router["share_project"].url_for(

services/web/server/tests/unit/with_dbs/02/test_projects_states_handlers.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# pylint: disable=unused-variable
77

88
import asyncio
9+
import contextlib
910
import time
1011
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator
1112
from copy import deepcopy
@@ -280,6 +281,7 @@ async def test_share_project(
280281
share_rights: dict,
281282
project_db_cleaner,
282283
request_create_project: Callable[..., Awaitable[ProjectDict]],
284+
exit_stack: contextlib.AsyncExitStack,
283285
):
284286
# Use-case: the user shares some projects with a group
285287

@@ -303,7 +305,10 @@ async def test_share_project(
303305

304306
# get another user logged in now
305307
await log_client_in(
306-
client, {"role": user_role.name}, enable_check=user_role != UserRole.ANONYMOUS
308+
client,
309+
{"role": user_role.name},
310+
enable_check=user_role != UserRole.ANONYMOUS,
311+
exit_stack=exit_stack,
307312
)
308313
if new_project:
309314
# user 2 can get the project if user 2 has read access
@@ -1272,6 +1277,7 @@ async def test_open_shared_project_2_users_locked(
12721277
clean_redis_table: None,
12731278
mock_dynamic_scheduler_rabbitmq: None,
12741279
mocked_notifications_plugin: dict[str, mock.Mock],
1280+
exit_stack: contextlib.AsyncExitStack,
12751281
):
12761282
# Use-case: user 1 opens a shared project, user 2 tries to open it as well
12771283
mock_project_state_updated_handler = mocker.Mock()
@@ -1332,7 +1338,10 @@ async def test_open_shared_project_2_users_locked(
13321338

13331339
# 2. create a separate client now and log in user2, try to open the same shared project
13341340
user_2 = await log_client_in(
1335-
client_2, {"role": user_role.name}, enable_check=user_role != UserRole.ANONYMOUS
1341+
client_2,
1342+
{"role": user_role.name},
1343+
enable_check=user_role != UserRole.ANONYMOUS,
1344+
exit_stack=exit_stack,
13361345
)
13371346
await _connect_websocket(
13381347
socketio_client_factory,
@@ -1454,6 +1463,7 @@ async def test_open_shared_project_at_same_time(
14541463
clean_redis_table,
14551464
mock_dynamic_scheduler_rabbitmq: None,
14561465
mocked_notifications_plugin: dict[str, mock.Mock],
1466+
exit_stack: contextlib.AsyncExitStack,
14571467
):
14581468
NUMBER_OF_ADDITIONAL_CLIENTS = 10
14591469
# log client 1
@@ -1475,6 +1485,7 @@ async def test_open_shared_project_at_same_time(
14751485
new_client,
14761486
{"role": user_role.name},
14771487
enable_check=user_role != UserRole.ANONYMOUS,
1488+
exit_stack=exit_stack,
14781489
)
14791490
client_id = client_session_id_factory()
14801491
sio = await _connect_websocket(

services/web/server/tests/unit/with_dbs/03/test_email.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
import pytest
1616
from aiohttp import web
1717
from aiohttp.test_utils import TestClient, make_mocked_request
18+
from common_library.users_enums import UserRole
1819
from faker import Faker
1920
from pydantic import ValidationError
2021
from pytest_mock import MockerFixture
2122
from pytest_simcore.helpers.assert_checks import assert_status
2223
from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict
2324
from pytest_simcore.helpers.typing_env import EnvVarsDict
24-
from pytest_simcore.helpers.webserver_login import UserInfoDict, UserRole
25+
from pytest_simcore.helpers.webserver_users import UserInfoDict
2526
from servicelib.aiohttp import status
2627
from settings_library.email import EmailProtocol, SMTPSettings
2728
from simcore_service_webserver._meta import API_VTAG

0 commit comments

Comments
 (0)