Skip to content

Commit 08939a8

Browse files
committed
✨ [Backend] Add async function for paginated listing of service summaries and refactor mock setup in tests
1 parent f726f76 commit 08939a8

File tree

3 files changed

+121
-34
lines changed

3 files changed

+121
-34
lines changed

packages/models-library/src/models_library/api_schemas_catalog/services.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,41 @@ class ServiceSummary(CatalogOutputSchema):
182182

183183
contact: LowerCaseEmailStr | None
184184

185+
service_type: Annotated[ServiceType, Field(alias="type")]
186+
187+
@staticmethod
188+
def _update_json_schema_extra(schema: JsonDict) -> None:
189+
schema.update(
190+
{
191+
"examples": [
192+
{
193+
"key": _EXAMPLE_SLEEPER["key"],
194+
"version": _EXAMPLE_SLEEPER["version"],
195+
"name": _EXAMPLE_SLEEPER["name"],
196+
"description": _EXAMPLE_SLEEPER["description"],
197+
"version_display": _EXAMPLE_SLEEPER["version_display"],
198+
"contact": _EXAMPLE_SLEEPER["contact"],
199+
"type": _EXAMPLE_SLEEPER["type"],
200+
},
201+
{
202+
"key": _EXAMPLE_FILEPICKER["key"],
203+
"version": _EXAMPLE_FILEPICKER["version"],
204+
"name": _EXAMPLE_FILEPICKER["name"],
205+
"description": _EXAMPLE_FILEPICKER["description"],
206+
"version_display": None,
207+
"contact": _EXAMPLE_FILEPICKER["contact"],
208+
"type": _EXAMPLE_FILEPICKER["type"],
209+
},
210+
]
211+
}
212+
)
213+
214+
model_config = ConfigDict(
215+
extra="ignore",
216+
populate_by_name=True,
217+
json_schema_extra=_update_json_schema_extra,
218+
)
219+
185220

186221
class _BaseServiceGetV2(ServiceSummary):
187222
# Model used in catalog's rpc and rest interfaces
@@ -190,8 +225,6 @@ class _BaseServiceGetV2(ServiceSummary):
190225

191226
description_ui: bool = False
192227

193-
service_type: Annotated[ServiceType, Field(alias="type")]
194-
195228
authors: Annotated[list[Author], Field(min_length=1)]
196229
owner: Annotated[
197230
LowerCaseEmailStr | None,

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
LatestServiceGet,
1414
ServiceGetV2,
1515
ServiceListFilters,
16+
ServiceSummary,
1617
ServiceUpdateV2,
1718
)
1819
from models_library.api_schemas_catalog.services_ports import ServicePortGet
@@ -200,6 +201,62 @@ async def get_service_ports(
200201
ServicePortGet.model_json_schema()["examples"],
201202
)
202203

204+
@validate_call(config={"arbitrary_types_allowed": True})
205+
async def list_all_services_summaries_paginated(
206+
self,
207+
rpc_client: RabbitMQRPCClient | MockType,
208+
*,
209+
product_name: ProductName,
210+
user_id: UserID,
211+
limit: PageLimitInt,
212+
offset: NonNegativeInt,
213+
filters: ServiceListFilters | None = None,
214+
):
215+
assert rpc_client
216+
assert product_name
217+
assert user_id
218+
219+
service_summaries = TypeAdapter(list[ServiceSummary]).validate_python(
220+
ServiceSummary.model_json_schema()["examples"],
221+
)
222+
if filters:
223+
filtered_summaries = []
224+
for summary in service_summaries:
225+
# Match service type if specified
226+
if (
227+
filters.service_type
228+
and summary.service_type != filters.service_type
229+
):
230+
continue
231+
232+
# Match service key pattern if specified
233+
if filters.service_key_pattern and not fnmatch.fnmatch(
234+
summary.key, filters.service_key_pattern
235+
):
236+
continue
237+
238+
# Match version display pattern if specified
239+
if filters.version_display_pattern and (
240+
summary.version_display is None
241+
or not fnmatch.fnmatch(
242+
summary.version_display, filters.version_display_pattern
243+
)
244+
):
245+
continue
246+
247+
filtered_summaries.append(summary)
248+
249+
service_summaries = filtered_summaries
250+
251+
total_count = len(service_summaries)
252+
253+
return PageRpc[ServiceSummary].create(
254+
service_summaries[offset : offset + limit],
255+
total=total_count,
256+
limit=limit,
257+
offset=offset,
258+
)
259+
203260

204261
@dataclass
205262
class ZeroListingCatalogRpcSideEffects:
@@ -216,3 +273,11 @@ async def list_my_service_history_latest_first(self, *args, **kwargs):
216273
limit=10,
217274
offset=0,
218275
)
276+
277+
async def list_all_services_summaries_paginated(self, *args, **kwargs):
278+
return PageRpc[ServiceSummary].create(
279+
[],
280+
total=0,
281+
limit=10,
282+
offset=0,
283+
)

services/api-server/tests/unit/conftest.py

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -509,38 +509,27 @@ def mocked_catalog_rpc_api(
509509
services as catalog_rpc, # keep import here
510510
)
511511

512-
return {
513-
"list_services_paginated": mocker.patch.object(
514-
catalog_rpc,
515-
"list_services_paginated",
516-
autospec=True,
517-
side_effect=catalog_rpc_side_effects.list_services_paginated,
518-
),
519-
"get_service": mocker.patch.object(
520-
catalog_rpc,
521-
"get_service",
522-
autospec=True,
523-
side_effect=catalog_rpc_side_effects.get_service,
524-
),
525-
"update_service": mocker.patch.object(
526-
catalog_rpc,
527-
"update_service",
528-
autospec=True,
529-
side_effect=catalog_rpc_side_effects.update_service,
530-
),
531-
"list_my_service_history_latest_first": mocker.patch.object(
532-
catalog_rpc,
533-
"list_my_service_history_latest_first",
534-
autospec=True,
535-
side_effect=catalog_rpc_side_effects.list_my_service_history_latest_first,
536-
),
537-
"get_service_ports": mocker.patch.object(
538-
catalog_rpc,
539-
"get_service_ports",
540-
autospec=True,
541-
side_effect=catalog_rpc_side_effects.get_service_ports,
542-
),
543-
}
512+
mocks = {}
513+
514+
# Get all callable methods from the side effects class that are not built-ins
515+
side_effect_methods = [
516+
method_name
517+
for method_name in dir(catalog_rpc_side_effects)
518+
if not method_name.startswith("_")
519+
and callable(getattr(catalog_rpc_side_effects, method_name))
520+
]
521+
522+
# Create mocks for each method in catalog_rpc that has a corresponding side effect
523+
for method_name in side_effect_methods:
524+
if hasattr(catalog_rpc, method_name):
525+
mocks[method_name] = mocker.patch.object(
526+
catalog_rpc,
527+
method_name,
528+
autospec=True,
529+
side_effect=getattr(catalog_rpc_side_effects, method_name),
530+
)
531+
532+
return mocks
544533

545534

546535
#

0 commit comments

Comments
 (0)