Skip to content

Commit 3ff886a

Browse files
committed
finish implementing test
1 parent 63d64c9 commit 3ff886a

File tree

6 files changed

+123
-4
lines changed

6 files changed

+123
-4
lines changed

packages/models-library/src/models_library/api_schemas_rpc_async_jobs/async_jobs.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ class AsyncJobResult(BaseModel):
3030

3131

3232
class AsyncJobGet(BaseModel):
33+
model_config = ConfigDict(
34+
json_schema_extra={
35+
"examples": [
36+
{
37+
"job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
38+
"job_name": "export_data_task",
39+
}
40+
]
41+
}
42+
)
43+
3344
job_id: AsyncJobId
3445
job_name: AsyncJobName
3546

@@ -42,6 +53,18 @@ class AsyncJobAbort(BaseModel):
4253
class AsyncJobFilter(AsyncJobFilterBase):
4354
"""Data for controlling access to an async job"""
4455

56+
model_config = ConfigDict(
57+
json_schema_extra={
58+
"examples": [
59+
{
60+
"product_name": "osparc",
61+
"user_id": 123,
62+
"client_name": "web_client",
63+
}
64+
]
65+
},
66+
)
67+
4568
product_name: ProductName
4669
user_id: UserID
4770
client_name: Annotated[
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# pylint: disable=no-self-use
2+
# pylint: disable=not-context-manager
3+
# pylint: disable=protected-access
4+
# pylint: disable=redefined-outer-name
5+
# pylint: disable=unused-argument
6+
# pylint: disable=unused-variable
7+
8+
9+
from typing import Literal
10+
11+
from models_library.api_schemas_rpc_async_jobs.async_jobs import (
12+
AsyncJobFilter,
13+
AsyncJobGet,
14+
)
15+
from models_library.api_schemas_webserver.storage import PathToExport
16+
from models_library.products import ProductName
17+
from models_library.users import UserID
18+
from pydantic import TypeAdapter, validate_call
19+
from pytest_mock import MockType
20+
from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient
21+
22+
23+
class StorageSideEffects:
24+
# pylint: disable=no-self-use
25+
@validate_call(config={"arbitrary_types_allowed": True})
26+
async def start_export_data(
27+
self,
28+
rabbitmq_rpc_client: RabbitMQRPCClient | MockType,
29+
*,
30+
user_id: UserID,
31+
product_name: ProductName,
32+
paths_to_export: list[PathToExport],
33+
export_as: Literal["path", "download_link"],
34+
) -> tuple[AsyncJobGet, AsyncJobFilter]:
35+
assert rabbitmq_rpc_client
36+
assert user_id
37+
assert product_name
38+
assert paths_to_export
39+
assert export_as
40+
41+
async_job_get = TypeAdapter(AsyncJobGet).validate_python(
42+
AsyncJobGet.model_json_schema()["examples"][0],
43+
)
44+
async_job_filter = TypeAdapter(AsyncJobFilter).validate_python(
45+
AsyncJobFilter.model_json_schema()["examples"][0],
46+
)
47+
48+
return async_job_get, async_job_filter

services/api-server/src/simcore_service_api_server/api/routes/function_jobs_routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ async def function_job_outputs(
303303

304304

305305
@function_job_router.post(
306-
"/{function_job_id:uuid}/logs",
306+
"/{function_job_id:uuid}/log",
307307
response_model=TaskGet,
308308
responses={**_COMMON_FUNCTION_JOB_ERROR_RESPONSES},
309309
)

services/api-server/src/simcore_service_api_server/services_rpc/storage.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from models_library.products import ProductName
77
from models_library.users import UserID
88
from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient
9-
from servicelib.rabbitmq.rpc_interfaces.storage.simcore_s3 import start_export_data
9+
from servicelib.rabbitmq.rpc_interfaces.storage import simcore_s3 as storage_rpc
1010

1111
from ..exceptions.service_errors_utils import service_exception_mapper
1212

@@ -24,7 +24,7 @@ async def start_data_export(
2424
self,
2525
paths_to_export: list[PathToExport],
2626
) -> AsyncJobGet:
27-
async_job_get, _ = await start_export_data(
27+
async_job_get, _ = await storage_rpc.start_export_data(
2828
self._rpc_client,
2929
user_id=self._user_id,
3030
product_name=self._product_name,

services/api-server/tests/unit/api_functions/test_api_routers_functions.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,8 @@ async def test_export_logs(
886886
mock_handler_in_functions_rpc_interface: Callable[[str, Any], None],
887887
mock_registered_project_function: RegisteredProjectFunction,
888888
mock_registered_function_job: RegisteredFunctionJob,
889+
mocked_directorv2_rpc_api: dict[str, MockType],
890+
mocked_storage_rpc_api: dict[str, MockType],
889891
auth: httpx.BasicAuth,
890892
user_id: UserID,
891893
):
@@ -897,6 +899,8 @@ async def test_export_logs(
897899
)
898900

899901
response = await client.post(
900-
f"{API_VTAG}/functions/{mock_registered_project_function.uid}/logs",
902+
f"{API_VTAG}/function_jobs/{mock_registered_function_job.uid}/log",
901903
auth=auth,
902904
)
905+
906+
assert response.status_code == status.HTTP_200_OK

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
from pytest_simcore.helpers.director_v2_rpc_server import DirectorV2SideEffects
5252
from pytest_simcore.helpers.host import get_localhost_ip
5353
from pytest_simcore.helpers.monkeypatch_envs import EnvVarsDict, setenvs_from_dict
54+
from pytest_simcore.helpers.storage_rpc_server import StorageSideEffects
5455
from pytest_simcore.helpers.webserver_rpc_server import WebserverRpcSideEffects
5556
from pytest_simcore.simcore_webserver_projects_rest_api import GET_PROJECT
5657
from requests.auth import HTTPBasicAuth
@@ -655,6 +656,49 @@ def mocked_directorv2_rpc_api(
655656
return mocks
656657

657658

659+
@pytest.fixture
660+
def storage_rpc_side_effects(request) -> Any:
661+
if "param" in dir(request) and request.param is not None:
662+
return request.param
663+
return StorageSideEffects()
664+
665+
666+
@pytest.fixture
667+
def mocked_storage_rpc_api(
668+
mocked_app_dependencies: None,
669+
mocker: MockerFixture,
670+
storage_rpc_side_effects: Any,
671+
) -> dict[str, MockType]:
672+
"""
673+
Mocks the storage's simcore service RPC API for testing purposes.
674+
"""
675+
from servicelib.rabbitmq.rpc_interfaces.storage import (
676+
simcore_s3 as storage_rpc, # keep import here
677+
)
678+
679+
mocks = {}
680+
681+
# Get all callable methods from the side effects class that are not built-ins
682+
side_effect_methods = [
683+
method_name
684+
for method_name in dir(storage_rpc_side_effects)
685+
if not method_name.startswith("_")
686+
and callable(getattr(storage_rpc_side_effects, method_name))
687+
]
688+
689+
# Create mocks for each method in storage_rpc that has a corresponding side effect
690+
for method_name in side_effect_methods:
691+
if hasattr(storage_rpc, method_name):
692+
mocks[method_name] = mocker.patch.object(
693+
storage_rpc,
694+
method_name,
695+
autospec=True,
696+
side_effect=getattr(storage_rpc_side_effects, method_name),
697+
)
698+
699+
return mocks
700+
701+
658702
#
659703
# Other Mocks
660704
#

0 commit comments

Comments
 (0)