Skip to content

Commit 71052a2

Browse files
committed
✨ Add projects repository fixture and enhance service listing tests for published templates
1 parent 00a76d1 commit 71052a2

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

services/catalog/tests/unit/with_dbs/test_repositories.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,29 @@
33
# pylint: disable=unused-variable
44
# pylint: disable=too-many-arguments
55

6+
import logging
67
import random
78
from collections import Counter
89
from collections.abc import Callable
10+
from contextlib import AsyncExitStack
911
from dataclasses import dataclass, field
12+
from typing import Any
1013

1114
import pytest
1215
from models_library.products import ProductName
1316
from models_library.users import UserID
1417
from packaging import version
1518
from pydantic import EmailStr, HttpUrl, TypeAdapter
19+
from pytest_simcore.helpers.faker_factories import random_project
20+
from pytest_simcore.helpers.postgres_tools import insert_and_get_row_lifespan
21+
from simcore_postgres_database.models.projects import ProjectType, projects
1622
from simcore_service_catalog.models.services_db import (
1723
ServiceAccessRightsAtDB,
1824
ServiceMetaDataDBCreate,
1925
ServiceMetaDataDBGet,
2026
ServiceMetaDataDBPatch,
2127
)
28+
from simcore_service_catalog.repository.projects import ProjectsRepository
2229
from simcore_service_catalog.repository.services import ServicesRepository
2330
from simcore_service_catalog.utils.versioning import is_patch_release
2431
from sqlalchemy.ext.asyncio import AsyncEngine
@@ -36,6 +43,11 @@ def services_repo(sqlalchemy_async_engine: AsyncEngine) -> ServicesRepository:
3643
return ServicesRepository(sqlalchemy_async_engine)
3744

3845

46+
@pytest.fixture
47+
def projects_repo(sqlalchemy_async_engine: AsyncEngine) -> ProjectsRepository:
48+
return ProjectsRepository(sqlalchemy_async_engine)
49+
50+
3951
@dataclass
4052
class FakeCatalogInfo:
4153
jupyter_service_key: str = "simcore/services/dynamic/jupyterlab"
@@ -549,3 +561,109 @@ async def test_get_service_history_page(
549561

550562
# compare paginated results with the corresponding slice of the full history
551563
assert paginated_history == history[offset : offset + limit]
564+
565+
566+
async def test_list_services_from_published_templates(
567+
user: dict[str, Any],
568+
projects_repo: ProjectsRepository,
569+
sqlalchemy_async_engine: AsyncEngine,
570+
):
571+
# Setup: Use AsyncExitStack to manage multiple insert_and_get_row_lifespan
572+
async with AsyncExitStack() as stack:
573+
await stack.enter_async_context(
574+
insert_and_get_row_lifespan(
575+
sqlalchemy_async_engine,
576+
table=projects,
577+
values=random_project(
578+
uuid="template-1",
579+
type=ProjectType.TEMPLATE,
580+
published=True,
581+
prj_owner=user["id"],
582+
workbench={
583+
"node-1": {
584+
"key": "simcore/services/dynamic/jupyterlab",
585+
"version": "1.0.0",
586+
},
587+
"node-2": {
588+
"key": "simcore/services/frontend/file-picker",
589+
"version": "1.0.0",
590+
},
591+
},
592+
),
593+
pk_col=projects.c.uuid,
594+
pk_value="template-1",
595+
)
596+
)
597+
await stack.enter_async_context(
598+
insert_and_get_row_lifespan(
599+
sqlalchemy_async_engine,
600+
table=projects,
601+
values=random_project(
602+
uuid="template-2",
603+
type=ProjectType.TEMPLATE,
604+
published=False,
605+
prj_owner=user["id"],
606+
workbench={
607+
"node-1": {
608+
"key": "simcore/services/dynamic/some-service",
609+
"version": "2.0.0",
610+
},
611+
},
612+
),
613+
pk_col=projects.c.uuid,
614+
pk_value="template-2",
615+
)
616+
)
617+
618+
# Act: Call the method
619+
services = await projects_repo.list_services_from_published_templates()
620+
621+
# Assert: Validate the results
622+
assert len(services) == 1
623+
assert services[0].key == "simcore/services/dynamic/jupyterlab"
624+
assert services[0].version == "1.0.0"
625+
626+
627+
async def test_list_services_from_published_templates_with_invalid_service(
628+
user: dict[str, Any],
629+
projects_repo: ProjectsRepository,
630+
sqlalchemy_async_engine: AsyncEngine,
631+
caplog,
632+
):
633+
# Setup: Use AsyncExitStack to manage insert_and_get_row_lifespan
634+
async with AsyncExitStack() as stack:
635+
await stack.enter_async_context(
636+
insert_and_get_row_lifespan(
637+
sqlalchemy_async_engine,
638+
table=projects,
639+
values=random_project(
640+
uuid="template-1",
641+
type=ProjectType.TEMPLATE,
642+
published=True,
643+
prj_owner=user["id"],
644+
workbench={
645+
"node-1": {
646+
"key": "simcore/services/frontend/file-picker",
647+
"version": "1.0.0",
648+
},
649+
"node-2": {
650+
"key": "simcore/services/dynamic/invalid-service",
651+
"version": "invalid",
652+
},
653+
},
654+
),
655+
pk_col=projects.c.uuid,
656+
pk_value="template-1",
657+
)
658+
)
659+
660+
# Act: Call the method and capture logs
661+
with caplog.at_level(logging.WARNING):
662+
services = await projects_repo.list_services_from_published_templates()
663+
664+
# Assert: Validate the results
665+
assert len(services) == 0 # No valid services should be returned
666+
assert (
667+
"service {'key': 'simcore/services/dynamic/invalid-service', 'version': 'invalid'} could not be validated"
668+
in caplog.text
669+
)

0 commit comments

Comments
 (0)