|
11 | 11 | from copy import deepcopy |
12 | 12 | from itertools import combinations |
13 | 13 | from random import randint |
14 | | -from typing import Any, Dict, List, Optional, Tuple |
| 14 | +from secrets import choice |
| 15 | +from typing import Any, AsyncIterator, Dict, Iterator, List, Optional, Set, Tuple |
15 | 16 | from uuid import UUID, uuid5 |
16 | 17 |
|
17 | 18 | import pytest |
18 | 19 | import sqlalchemy as sa |
19 | 20 | from aiohttp.test_utils import TestClient |
| 21 | +from models_library.projects import ProjectID |
| 22 | +from models_library.projects_nodes_io import NodeID |
20 | 23 | from psycopg2.errors import UniqueViolation |
21 | 24 | from simcore_postgres_database.models.groups import GroupType |
22 | 25 | from simcore_service_webserver.db_models import UserRole |
|
32 | 35 | _convert_to_schema_names, |
33 | 36 | _create_project_access_rights, |
34 | 37 | _find_changed_dict_keys, |
35 | | - setup_projects_db, |
36 | 38 | ) |
37 | 39 | from simcore_service_webserver.users_exceptions import UserNotFoundError |
38 | 40 | from simcore_service_webserver.utils import to_datetime |
@@ -233,26 +235,20 @@ def _project_access_rights_from_permissions( |
233 | 235 | _check_project_permissions(project, user_id, user_groups, wanted_permissions) |
234 | 236 |
|
235 | 237 |
|
236 | | -def _create_project_db(client: TestClient) -> ProjectDBAPI: |
237 | | - setup_projects_db(client.app) |
238 | | - |
239 | | - assert APP_PROJECT_DBAPI in client.app |
| 238 | +async def test_setup_projects_db(client: TestClient): |
| 239 | + assert client.app |
240 | 240 | db_api = client.app[APP_PROJECT_DBAPI] |
241 | 241 | assert db_api |
242 | 242 | assert isinstance(db_api, ProjectDBAPI) |
243 | 243 |
|
244 | 244 | assert db_api._app == client.app |
245 | | - assert db_api._engine |
246 | | - return db_api |
247 | | - |
248 | | - |
249 | | -async def test_setup_projects_db(client: TestClient): |
250 | | - _create_project_db(client) |
| 245 | + assert db_api.engine |
251 | 246 |
|
252 | 247 |
|
253 | 248 | @pytest.fixture() |
254 | | -def db_api(client: TestClient, postgres_db: sa.engine.Engine) -> ProjectDBAPI: |
255 | | - db_api = _create_project_db(client) |
| 249 | +def db_api(client: TestClient, postgres_db: sa.engine.Engine) -> Iterator[ProjectDBAPI]: |
| 250 | + assert client.app |
| 251 | + db_api = client.app[APP_PROJECT_DBAPI] |
256 | 252 |
|
257 | 253 | yield db_api |
258 | 254 |
|
@@ -670,3 +666,86 @@ async def test_patch_user_project_workbench_concurrently( |
670 | 666 | creation_date=to_datetime(new_project["creationDate"]), |
671 | 667 | last_change_date=latest_change_date, |
672 | 668 | ) |
| 669 | + |
| 670 | + |
| 671 | +@pytest.fixture() |
| 672 | +async def lots_of_projects_and_nodes( |
| 673 | + logged_user: Dict[str, Any], |
| 674 | + fake_project: Dict[str, Any], |
| 675 | + db_api: ProjectDBAPI, |
| 676 | +) -> AsyncIterator[Dict[ProjectID, List[NodeID]]]: |
| 677 | + """Will create >1000 projects with each between 200-1434 nodes""" |
| 678 | + NUMBER_OF_PROJECTS = 1245 |
| 679 | + |
| 680 | + BASE_UUID = UUID("ccc0839f-93b8-4387-ab16-197281060927") |
| 681 | + all_created_projects = {} |
| 682 | + project_creation_tasks = [] |
| 683 | + for p in range(NUMBER_OF_PROJECTS): |
| 684 | + project_uuid = uuid5(BASE_UUID, f"project_{p}") |
| 685 | + all_created_projects[project_uuid] = [] |
| 686 | + workbench = {} |
| 687 | + for n in range(randint(200, 1434)): |
| 688 | + node_uuid = uuid5(project_uuid, f"node_{n}") |
| 689 | + all_created_projects[project_uuid].append(node_uuid) |
| 690 | + workbench[f"{node_uuid}"] = { |
| 691 | + "key": "simcore/services/comp/sleepers", |
| 692 | + "version": "1.43.5", |
| 693 | + "label": f"I am node {n}", |
| 694 | + } |
| 695 | + new_project = deepcopy(fake_project) |
| 696 | + new_project.update(uuid=project_uuid, name=f"project {p}", workbench=workbench) |
| 697 | + # add the project |
| 698 | + project_creation_tasks.append( |
| 699 | + db_api.add_project(prj=new_project, user_id=logged_user["id"]) |
| 700 | + ) |
| 701 | + await asyncio.gather(*project_creation_tasks) |
| 702 | + print(f"---> created {len(all_created_projects)} projects in the database") |
| 703 | + yield all_created_projects |
| 704 | + print(f"<--- removed {len(all_created_projects)} projects in the database") |
| 705 | + |
| 706 | + # cleanup |
| 707 | + await asyncio.gather( |
| 708 | + *[ |
| 709 | + db_api.delete_user_project(logged_user["id"], f"{p_uuid}") |
| 710 | + for p_uuid in all_created_projects |
| 711 | + ] |
| 712 | + ) |
| 713 | + |
| 714 | + |
| 715 | +@pytest.mark.parametrize( |
| 716 | + "user_role", |
| 717 | + [UserRole.USER], |
| 718 | +) |
| 719 | +async def test_node_id_exists( |
| 720 | + db_api: ProjectDBAPI, lots_of_projects_and_nodes: Dict[ProjectID, List[NodeID]] |
| 721 | +): |
| 722 | + |
| 723 | + # create a node uuid that does not exist from an existing project |
| 724 | + existing_project_id = choice(list(lots_of_projects_and_nodes.keys())) |
| 725 | + not_existing_node_id_in_existing_project = uuid5( |
| 726 | + existing_project_id, "node_invalid_node" |
| 727 | + ) |
| 728 | + |
| 729 | + node_id_exists = await db_api.node_id_exists( |
| 730 | + f"{not_existing_node_id_in_existing_project}" |
| 731 | + ) |
| 732 | + assert node_id_exists == False |
| 733 | + existing_node_id = choice(lots_of_projects_and_nodes[existing_project_id]) |
| 734 | + node_id_exists = await db_api.node_id_exists(f"{existing_node_id}") |
| 735 | + assert node_id_exists == True |
| 736 | + |
| 737 | + |
| 738 | +@pytest.mark.parametrize( |
| 739 | + "user_role", |
| 740 | + [UserRole.USER], |
| 741 | +) |
| 742 | +async def test_get_node_ids_from_project( |
| 743 | + db_api: ProjectDBAPI, lots_of_projects_and_nodes: Dict[ProjectID, List[NodeID]] |
| 744 | +): |
| 745 | + for project_id in lots_of_projects_and_nodes: |
| 746 | + node_ids_inside_project: Set[str] = await db_api.get_node_ids_from_project( |
| 747 | + f"{project_id}" |
| 748 | + ) |
| 749 | + assert node_ids_inside_project == { |
| 750 | + f"{n}" for n in lots_of_projects_and_nodes[project_id] |
| 751 | + } |
0 commit comments