Skip to content

Commit 1c317ac

Browse files
committed
✨ Refactor test fixtures for improved clarity and consistency in mocking APIs
1 parent 1b46209 commit 1c317ac

File tree

3 files changed

+46
-50
lines changed

3 files changed

+46
-50
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ async def create_fake_api_keys(
272272
create_user_ids: Callable[[PositiveInt], AsyncGenerator[PositiveInt, None]],
273273
create_product_names: Callable[[PositiveInt], AsyncGenerator[str, None]],
274274
) -> AsyncGenerator[Callable[[PositiveInt], AsyncGenerator[ApiKeyInDB, None]], None]:
275+
275276
async def _generate_fake_api_key(n: PositiveInt):
276277
users, products = create_user_ids(n), create_product_names(n)
277278
excluded_column = "api_secret"

services/api-server/tests/unit/_with_db/test_product.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,22 @@ async def test_product_webserver(
2929
mocked_webserver_rest_api_base: respx.MockRouter,
3030
create_fake_api_keys: Callable[[PositiveInt], AsyncGenerator[ApiKeyInDB, None]],
3131
faker: Faker,
32-
) -> None:
32+
):
3333
assert client
3434

35-
keys: dict[int, ApiKeyInDB] = {}
35+
wallet_to_api_keys_map: dict[int, ApiKeyInDB] = {}
3636
wallet_id: int = faker.pyint(min_value=1)
37-
async for key in create_fake_api_keys(2):
37+
async for api_key in create_fake_api_keys(2):
3838
wallet_id += faker.pyint(min_value=1)
39-
keys[wallet_id] = key
39+
wallet_to_api_keys_map[wallet_id] = api_key
4040

4141
def _check_key_product_compatibility(request: httpx.Request, **kwargs):
4242
assert (
4343
received_product_name := request.headers.get("x-simcore-products-name")
4444
) is not None
4545
assert (wallet_id := kwargs.get("wallet_id")) is not None
46-
assert (key := keys[int(wallet_id)]) is not None
47-
assert key.product_name == received_product_name
46+
assert (api_key := wallet_to_api_keys_map[int(wallet_id)]) is not None
47+
assert api_key.product_name == received_product_name
4848
return httpx.Response(
4949
status.HTTP_200_OK,
5050
json=jsonable_encoder(
@@ -53,7 +53,7 @@ def _check_key_product_compatibility(request: httpx.Request, **kwargs):
5353
wallet_id=wallet_id,
5454
name="my_wallet",
5555
description="this is my wallet",
56-
owner=key.id_,
56+
owner=api_key.id_,
5757
thumbnail="something",
5858
status=WalletStatus.ACTIVE,
5959
created=datetime.datetime.now(),
@@ -68,30 +68,29 @@ def _check_key_product_compatibility(request: httpx.Request, **kwargs):
6868
path__regex=r"/wallets/(?P<wallet_id>[-+]?\d+)"
6969
).mock(side_effect=_check_key_product_compatibility)
7070

71-
for wallet_id in keys:
72-
key = keys[wallet_id]
71+
for wallet_id, api_key in wallet_to_api_keys_map.items():
7372
response = await client.get(
7473
f"{API_VTAG}/wallets/{wallet_id}",
75-
auth=httpx.BasicAuth(key.api_key, key.api_secret),
74+
auth=httpx.BasicAuth(api_key.api_key, api_key.api_secret),
7675
)
7776
assert response.status_code == status.HTTP_200_OK
78-
assert wallet_get_mock.call_count == len(keys)
77+
assert wallet_get_mock.call_count == len(wallet_to_api_keys_map)
7978

8079

8180
async def test_product_catalog(
8281
client: httpx.AsyncClient,
8382
mocked_catalog_rpc_api: dict[str, MockType],
8483
create_fake_api_keys: Callable[[PositiveInt], AsyncGenerator[ApiKeyInDB, None]],
85-
) -> None:
84+
):
8685
assert client
8786

88-
keys: list[ApiKeyInDB] = [key async for key in create_fake_api_keys(2)]
89-
assert len({key.product_name for key in keys}) == 2
87+
valid_api_auths: list[ApiKeyInDB] = [key async for key in create_fake_api_keys(2)]
88+
assert len({key.product_name for key in valid_api_auths}) == 2
9089

91-
for key in keys:
90+
for api_auth in valid_api_auths:
9291
await client.get(
9392
f"{API_VTAG}/solvers/simcore/services/comp/isolve/releases/2.0.24",
94-
auth=httpx.BasicAuth(key.api_key, key.api_secret),
93+
auth=httpx.BasicAuth(api_auth.api_key, api_auth.api_secret),
9594
)
9695

9796
assert mocked_catalog_rpc_api["get_service"].called

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

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# pylint: disable=redefined-outer-name
33
# pylint: disable=unused-argument
44
# pylint: disable=unused-variable
5+
# pylint: disable=broad-exception-caught
56

67
import json
78
import subprocess
8-
from collections.abc import AsyncIterator, Callable, Iterable, Iterator
9+
from collections.abc import AsyncIterator, Callable, Iterator
910
from copy import deepcopy
1011
from pathlib import Path
1112
from typing import Any
@@ -45,9 +46,6 @@
4546
from pytest_simcore.simcore_webserver_projects_rest_api import GET_PROJECT
4647
from requests.auth import HTTPBasicAuth
4748
from respx import MockRouter
48-
from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient
49-
from servicelib.rabbitmq.rpc_interfaces.catalog import services as catalog_rpc
50-
from simcore_service_api_server.api.dependencies.rabbitmq import get_rabbitmq_rpc_client
5149
from simcore_service_api_server.core.application import init_app
5250
from simcore_service_api_server.core.settings import ApplicationSettings
5351
from simcore_service_api_server.repository.api_keys import UserAndProductTuple
@@ -92,10 +90,19 @@ def app_environment(
9290
def mock_missing_plugins(app_environment: EnvVarsDict, mocker: MockerFixture):
9391
settings = ApplicationSettings.create_from_envs()
9492
if settings.API_SERVER_RABBITMQ is None:
95-
mocker.patch("simcore_service_api_server.core.application.setup_rabbitmq")
96-
mocker.patch(
97-
"simcore_service_api_server.core._prometheus_instrumentation.setup_prometheus_instrumentation"
93+
import simcore_service_api_server.core.application
94+
95+
mocker.patch.object(
96+
simcore_service_api_server.core.application,
97+
"setup_rabbitmq",
98+
autospec=True,
9899
)
100+
mocker.patch.object(
101+
simcore_service_api_server.core.application,
102+
"setup_prometheus_instrumentation",
103+
autospec=True,
104+
)
105+
99106
return app_environment
100107

101108

@@ -331,34 +338,27 @@ def mocked_webserver_rest_api_base(
331338

332339

333340
@pytest.fixture
334-
def mocked_webserver_rpc_api(
335-
app: FastAPI, mocker: MockerFixture
336-
) -> dict[str, MockType]:
337-
from servicelib.rabbitmq.rpc_interfaces.webserver import projects as projects_rpc
338-
from simcore_service_api_server.services_rpc import wb_api_server
339-
340-
# NOTE: mock_missing_plugins patches `setup_rabbitmq`
341-
try:
342-
wb_api_server.WbApiRpcClient.get_from_app_state(app)
343-
except AttributeError:
344-
wb_api_server.setup(
345-
app, RabbitMQRPCClient("fake_rpc_client", settings=mocker.MagicMock())
346-
)
347-
348-
settings: ApplicationSettings = app.state.settings
349-
assert settings.API_SERVER_WEBSERVER
341+
def mocked_webserver_rpc_api(mocker: MockerFixture) -> dict[str, MockType]:
342+
"""
343+
Mocks the webserver's simcore service RPC API for testing purposes.
344+
"""
345+
from servicelib.rabbitmq.rpc_interfaces.webserver import (
346+
projects as projects_rpc, # keep import here
347+
)
350348

351349
side_effects = WebserverRpcSideEffects()
352350

353351
return {
354352
"mark_project_as_job": mocker.patch.object(
355353
projects_rpc,
356354
"mark_project_as_job",
355+
autospec=True,
357356
side_effect=side_effects.mark_project_as_job,
358357
),
359358
"list_projects_marked_as_jobs": mocker.patch.object(
360359
projects_rpc,
361360
"list_projects_marked_as_jobs",
361+
autospec=True,
362362
side_effect=side_effects.list_projects_marked_as_jobs,
363363
),
364364
}
@@ -458,20 +458,16 @@ def mocked_catalog_rest_api_base(
458458

459459

460460
@pytest.fixture
461-
def mocked_catalog_rpc_api(
462-
app: FastAPI, mocker: MockerFixture
463-
) -> Iterable[dict[str, MockType]]:
461+
def mocked_catalog_rpc_api(mocker: MockerFixture) -> dict[str, MockType]:
464462
"""
465-
Mocks the RPC catalog service API for testing purposes.
463+
Mocks the catalog's simcore service RPC API for testing purposes.
466464
"""
465+
from servicelib.rabbitmq.rpc_interfaces.catalog import (
466+
services as catalog_rpc, # keep import here
467+
)
467468

468-
def get_mock_rabbitmq_rpc_client():
469-
return MagicMock()
470-
471-
app.dependency_overrides[get_rabbitmq_rpc_client] = get_mock_rabbitmq_rpc_client
472469
side_effects = CatalogRpcSideEffects()
473-
474-
yield {
470+
return {
475471
"list_services_paginated": mocker.patch.object(
476472
catalog_rpc,
477473
"list_services_paginated",
@@ -503,7 +499,6 @@ def get_mock_rabbitmq_rpc_client():
503499
side_effect=side_effects.get_service_ports,
504500
),
505501
}
506-
app.dependency_overrides.pop(get_rabbitmq_rpc_client)
507502

508503

509504
#
@@ -633,6 +628,7 @@ def clone_project_task(self, request: httpx.Request, *, project_id: str):
633628
return self._set_result_and_get_reponse(project_get)
634629

635630
def get_result(self, request: httpx.Request, *, task_id: str):
631+
assert request
636632
return httpx.Response(
637633
status.HTTP_200_OK, json={"data": self._results[task_id]}
638634
)

0 commit comments

Comments
 (0)