Skip to content

Commit 20cef27

Browse files
fix: remove workbench references from catalog
1 parent f6ae1d7 commit 20cef27

File tree

3 files changed

+148
-53
lines changed

3 files changed

+148
-53
lines changed

packages/pytest-simcore/src/pytest_simcore/helpers/faker_factories.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
DEFAULT_FAKER: Final = Faker()
2626

2727

28+
def random_service_key(fake: Faker = DEFAULT_FAKER, *, name: str | None = None) -> str:
29+
"""Generates a random service key"""
30+
return f"simcore/services/{fake.random_element(['dynamic', 'computational'])}/{name or fake.name()}"
31+
32+
33+
def random_service_version(fake: Faker = DEFAULT_FAKER) -> str:
34+
return ".".join([str(fake.pyint()) for _ in range(3)])
35+
36+
2837
def random_icon_url(fake: Faker):
2938
return fake.image_url(width=16, height=16)
3039

@@ -186,6 +195,26 @@ def random_project(fake: Faker = DEFAULT_FAKER, **overrides) -> dict[str, Any]:
186195
return data
187196

188197

198+
def random_project_node(fake: Faker = DEFAULT_FAKER, **overrides) -> dict[str, Any]:
199+
"""Generates random fake data project nodes DATABASE table"""
200+
from simcore_postgres_database.models.projects_nodes import projects_nodes
201+
202+
_name = fake.name()
203+
204+
data = {
205+
"node_id": fake.uuid4(),
206+
"project_uuid": fake.uuid4(),
207+
"key": random_service_key(fake, name=_name),
208+
"version": random_service_version(fake),
209+
"label": _name,
210+
}
211+
212+
assert set(data.keys()).issubset({c.name for c in projects_nodes.columns})
213+
214+
data.update(overrides)
215+
return data
216+
217+
189218
def random_group(fake: Faker = DEFAULT_FAKER, **overrides) -> dict[str, Any]:
190219
from simcore_postgres_database.models.groups import groups
191220
from simcore_postgres_database.webserver_models import GroupType
@@ -481,7 +510,7 @@ def random_service_meta_data(
481510
) -> dict[str, Any]:
482511
from simcore_postgres_database.models.services import services_meta_data
483512

484-
_version = ".".join([str(fake.pyint()) for _ in range(3)])
513+
_version = random_service_version(fake)
485514
_name = fake.name()
486515

487516
data: dict[str, Any] = {

services/catalog/src/simcore_service_catalog/repository/projects.py

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,53 @@
44
from models_library.services import ServiceKeyVersion
55
from pydantic import ValidationError
66
from simcore_postgres_database.models.projects import ProjectType, projects
7+
from simcore_postgres_database.models.projects_nodes import projects_nodes
78

89
from ._base import BaseRepository
910

1011
_logger = logging.getLogger(__name__)
1112

1213

14+
_IGNORED_SERVICE_KEYS: set[str] = {
15+
# NOTE: frontend only nodes
16+
"simcore/services/frontend/file-picker",
17+
"simcore/services/frontend/nodes-group",
18+
}
19+
20+
1321
class ProjectsRepository(BaseRepository):
1422
async def list_services_from_published_templates(self) -> list[ServiceKeyVersion]:
15-
list_of_published_services: list[ServiceKeyVersion] = []
1623
async with self.db_engine.connect() as conn:
17-
async for row in await conn.stream(
18-
sa.select(projects).where(
19-
(projects.c.type == ProjectType.TEMPLATE)
20-
& (projects.c.published.is_(True))
24+
query = (
25+
sa.select(projects_nodes.c.key, projects_nodes.c.version)
26+
.distinct()
27+
.select_from(
28+
projects_nodes.join(
29+
projects, projects_nodes.c.project_uuid == projects.c.uuid
30+
)
31+
)
32+
.where(
33+
sa.and_(
34+
projects.c.type == ProjectType.TEMPLATE,
35+
projects.c.published.is_(True),
36+
projects_nodes.c.key.notin_(_IGNORED_SERVICE_KEYS),
37+
)
2138
)
22-
):
23-
project_workbench = row.workbench
24-
for node in project_workbench:
25-
service = project_workbench[node]
26-
try:
27-
if (
28-
"file-picker" in service["key"]
29-
or "nodes-group" in service["key"]
30-
):
31-
# these 2 are not going to pass the validation tests, they are frontend only nodes.
32-
continue
33-
list_of_published_services.append(ServiceKeyVersion(**service))
34-
except ValidationError:
35-
_logger.warning(
36-
"service %s could not be validated", service, exc_info=True
37-
)
38-
continue
39-
40-
return list_of_published_services
39+
)
40+
41+
services = []
42+
async for row in await conn.stream(query):
43+
try:
44+
service = ServiceKeyVersion.model_validate(
45+
row, from_attributes=True
46+
)
47+
services.append(service)
48+
except ValidationError:
49+
_logger.warning(
50+
"service with key=%s and version=%s could not be validated",
51+
row.key,
52+
row.version,
53+
exc_info=True,
54+
)
55+
56+
return services

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

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
from packaging import version
2424
from pydantic import EmailStr, HttpUrl, TypeAdapter
2525
from pytest_simcore.helpers.catalog_services import CreateFakeServiceDataCallable
26-
from pytest_simcore.helpers.faker_factories import random_project
26+
from pytest_simcore.helpers.faker_factories import random_project, random_project_node
2727
from pytest_simcore.helpers.postgres_tools import insert_and_get_row_lifespan
2828
from simcore_postgres_database.models.projects import ProjectType, projects
29+
from simcore_postgres_database.models.projects_nodes import projects_nodes
2930
from simcore_service_catalog.models.services_db import (
3031
ServiceAccessRightsDB,
3132
ServiceDBFilters,
@@ -812,21 +813,41 @@ async def test_list_services_from_published_templates(
812813
type=ProjectType.TEMPLATE,
813814
published=True,
814815
prj_owner=user["id"],
815-
workbench={
816-
"node-1": {
817-
"key": "simcore/services/dynamic/jupyterlab",
818-
"version": "1.0.0",
819-
},
820-
"node-2": {
821-
"key": "simcore/services/frontend/file-picker",
822-
"version": "1.0.0",
823-
},
824-
},
825816
),
826817
pk_col=projects.c.uuid,
827818
pk_value="template-1",
828819
)
829820
)
821+
await stack.enter_async_context(
822+
insert_and_get_row_lifespan(
823+
sqlalchemy_async_engine,
824+
table=projects_nodes,
825+
values=random_project_node(
826+
node_id="node-1.1",
827+
project_uuid="template-1",
828+
key="simcore/services/dynamic/jupyterlab",
829+
version="1.0.0",
830+
label="jupyterlab",
831+
),
832+
pk_col=projects_nodes.c.node_id,
833+
pk_value="node-1.1",
834+
)
835+
)
836+
await stack.enter_async_context(
837+
insert_and_get_row_lifespan(
838+
sqlalchemy_async_engine,
839+
table=projects_nodes,
840+
values=random_project_node(
841+
node_id="node-1.2",
842+
project_uuid="template-1",
843+
key="simcore/services/frontend/file-picker",
844+
version="1.0.0",
845+
label="file-picker",
846+
),
847+
pk_col=projects_nodes.c.node_id,
848+
pk_value="node-1.2",
849+
)
850+
)
830851
await stack.enter_async_context(
831852
insert_and_get_row_lifespan(
832853
sqlalchemy_async_engine,
@@ -836,17 +857,26 @@ async def test_list_services_from_published_templates(
836857
type=ProjectType.TEMPLATE,
837858
published=False,
838859
prj_owner=user["id"],
839-
workbench={
840-
"node-1": {
841-
"key": "simcore/services/dynamic/some-service",
842-
"version": "2.0.0",
843-
},
844-
},
845860
),
846861
pk_col=projects.c.uuid,
847862
pk_value="template-2",
848863
)
849864
)
865+
await stack.enter_async_context(
866+
insert_and_get_row_lifespan(
867+
sqlalchemy_async_engine,
868+
table=projects_nodes,
869+
values=random_project_node(
870+
node_id="node-2.1",
871+
project_uuid="template-2",
872+
key="simcore/services/dynamic/some-service",
873+
version="2.0.0",
874+
label="some-service",
875+
),
876+
pk_col=projects_nodes.c.node_id,
877+
pk_value="node-2.1",
878+
)
879+
)
850880

851881
# Act: Call the method
852882
services = await projects_repo.list_services_from_published_templates()
@@ -874,21 +904,41 @@ async def test_list_services_from_published_templates_with_invalid_service(
874904
type=ProjectType.TEMPLATE,
875905
published=True,
876906
prj_owner=user["id"],
877-
workbench={
878-
"node-1": {
879-
"key": "simcore/services/frontend/file-picker",
880-
"version": "1.0.0",
881-
},
882-
"node-2": {
883-
"key": "simcore/services/dynamic/invalid-service",
884-
"version": "invalid",
885-
},
886-
},
887907
),
888908
pk_col=projects.c.uuid,
889909
pk_value="template-1",
890910
)
891911
)
912+
await stack.enter_async_context(
913+
insert_and_get_row_lifespan(
914+
sqlalchemy_async_engine,
915+
table=projects_nodes,
916+
values=random_project_node(
917+
node_id="node-1.1",
918+
project_uuid="template-1",
919+
key="simcore/services/frontend/file-picker",
920+
version="1.0.0",
921+
label="file-picker",
922+
),
923+
pk_col=projects_nodes.c.node_id,
924+
pk_value="node-1.1",
925+
)
926+
)
927+
await stack.enter_async_context(
928+
insert_and_get_row_lifespan(
929+
sqlalchemy_async_engine,
930+
table=projects_nodes,
931+
values=random_project_node(
932+
node_id="node-1.2",
933+
project_uuid="template-1",
934+
key="simcore/services/dynamic/invalid-service",
935+
version="invalid", # NOTE: invalid version
936+
label="invalid-service",
937+
),
938+
pk_col=projects_nodes.c.node_id,
939+
pk_value="node-1.2",
940+
)
941+
)
892942

893943
# Act: Call the method and capture logs
894944
with caplog.at_level(logging.WARNING):
@@ -897,7 +947,7 @@ async def test_list_services_from_published_templates_with_invalid_service(
897947
# Assert: Validate the results
898948
assert len(services) == 0 # No valid services should be returned
899949
assert (
900-
"service {'key': 'simcore/services/dynamic/invalid-service', 'version': 'invalid'} could not be validated"
950+
"service with key=simcore/services/dynamic/invalid-service and version=invalid could not be validated"
901951
in caplog.text
902952
)
903953

0 commit comments

Comments
 (0)