diff --git a/services/api-server/Makefile b/services/api-server/Makefile index 555c88f6ec3..ee1d2af936f 100644 --- a/services/api-server/Makefile +++ b/services/api-server/Makefile @@ -95,11 +95,5 @@ test-api: ## Runs schemathesis against development server (NOTE: make up-devel f "$(APP_URL)/api/v0/openapi.json" -test-pacts: guard-PACT_BROKER_USERNAME guard-PACT_BROKER_PASSWORD guard-PACT_BROKER_URL _check_venv_active ## Test pacts +test-pacts: guard-PACT_BROKER_USERNAME guard-PACT_BROKER_PASSWORD guard-PACT_BROKER_URL _check_venv_active ## Test pacts. Usage: PACT_BROKER_USERNAME=your_username PACT_BROKER_PASSWORD=your_password PACT_BROKER_URL=your_broker_url make test-pacts pytest tests/unit/pact_broker/test* - -# Usage: -# PACT_BROKER_USERNAME=your_username \ -# PACT_BROKER_PASSWORD=your_password \ -# PACT_BROKER_URL=your_broker_url \ -# make test-pacts diff --git a/services/api-server/tests/unit/conftest.py b/services/api-server/tests/unit/conftest.py index aad4137c79d..2ddba69b585 100644 --- a/services/api-server/tests/unit/conftest.py +++ b/services/api-server/tests/unit/conftest.py @@ -683,11 +683,11 @@ def mocked_catalog_rpc_api( """ Mocks the catalog's simcore service RPC API for testing purposes. """ - from servicelib.rabbitmq.rpc_interfaces.catalog import ( - services as catalog_rpc, # keep import here + from servicelib.rabbitmq.rpc_interfaces.catalog import ( # noqa: PLC0415; keep import here + services as catalog_rpc, ) - mocks = {} + mocks: dict[str, MockType] = {} # Get all callable methods from the side effects class that are not built-ins side_effect_methods = [ @@ -726,8 +726,8 @@ def mocked_directorv2_rpc_api( """ Mocks the director-v2's simcore service RPC API for testing purposes. """ - from servicelib.rabbitmq.rpc_interfaces.director_v2 import ( - computations_tasks as directorv2_rpc, # keep import here + from servicelib.rabbitmq.rpc_interfaces.director_v2 import ( # noqa: PLC0415; keep import here + computations_tasks as directorv2_rpc, ) mocks = {} diff --git a/services/api-server/tests/unit/pact_broker/README.md b/services/api-server/tests/unit/pact_broker/README.md index 19620b24009..49f90bf8e6e 100644 --- a/services/api-server/tests/unit/pact_broker/README.md +++ b/services/api-server/tests/unit/pact_broker/README.md @@ -1,19 +1,32 @@ # Contract testing (PACT) -Maintainer @matusdrobuliak66 +- Maintainer @matusdrobuliak66 + +## How to run this test as a provider? ```bash -PACT_BROKER_URL= PACT_BROKER_USERNAME= PACT_BROKER_PASSWORD= make test-pacts +PACT_BROKER_URL= PACT_BROKER_USERNAME= PACT_BROKER_PASSWORD= + +make test-pacts ``` -## Install and Publish new contract to Broker +## How to run this test locally? + +- Still not implemented +- The idea would be use local copies of the pacts (see services/api-server/tests/unit/pact_broker/pacts/*.json) instead of reaching the pact server for them. + +## How to install and Publish new contract to Broker? + Contracts are generated by Consumer (ex. Sim4Life) -TODO: add reference to Sim4life repo where they can be generated -#### Install + +### Install + ```bash npm install @pact-foundation/pact-cli ``` + #### Publish + ```bash pact-broker publish ./pacts/05_licensed_items.json --tag licensed_items --consumer-app-version 8.2.1 --broker-base-url= --broker-username= --broker-password= ``` diff --git a/services/api-server/tests/unit/pact_broker/conftest.py b/services/api-server/tests/unit/pact_broker/conftest.py index e63b68a2012..750daeae7bc 100644 --- a/services/api-server/tests/unit/pact_broker/conftest.py +++ b/services/api-server/tests/unit/pact_broker/conftest.py @@ -37,10 +37,10 @@ def pytest_addoption(parser: pytest.Parser) -> None: ) -@pytest.fixture() +@pytest.fixture def pact_broker_credentials( request: pytest.FixtureRequest, -): +) -> tuple[str, str, str]: # Get credentials from either CLI arguments or environment variables broker_url = request.config.getoption("--broker-url", None) or os.getenv( "PACT_BROKER_URL" @@ -64,18 +64,20 @@ def pact_broker_credentials( ] if missing: - pytest.fail( - f"Missing Pact Broker credentials: {', '.join(missing)}. Set them as environment variables or pass them as CLI arguments." + pytest.skip( + reason="This test runs only if pact broker credentials are provided. " + f"Missing Pact Broker credentials: {', '.join(missing)}. " + "Set them as environment variables or pass them as CLI arguments. " ) - return broker_url, broker_username, broker_password - + assert broker_url + assert broker_username + assert broker_password -def mock_get_current_identity() -> Identity: - return Identity(user_id=1, product_name="osparc", email="test@itis.swiss") + return broker_url, broker_username, broker_password -@pytest.fixture() +@pytest.fixture def running_test_server_url( app: FastAPI, ): @@ -84,8 +86,12 @@ def running_test_server_url( The 'mocked_catalog_service' fixture ensures the function is already patched by the time we start the server. """ + # Override - app.dependency_overrides[get_current_identity] = mock_get_current_identity + def _mock_get_current_identity() -> Identity: + return Identity(user_id=1, product_name="osparc", email="test@itis.swiss") + + app.dependency_overrides[get_current_identity] = _mock_get_current_identity port = unused_port() base_url = f"http://localhost:{port}" @@ -106,5 +112,6 @@ def running_test_server_url( yield base_url # , before_server_start + app.dependency_overrides.pop(get_current_identity, None) server.should_exit = True thread.join() diff --git a/services/api-server/tests/unit/pact_broker/test_pact_checkout_release.py b/services/api-server/tests/unit/pact_broker/test_pact_checkout_release.py index 0dd6811910f..f1180953276 100644 --- a/services/api-server/tests/unit/pact_broker/test_pact_checkout_release.py +++ b/services/api-server/tests/unit/pact_broker/test_pact_checkout_release.py @@ -4,7 +4,7 @@ # pylint: disable=too-many-arguments -import os +from collections.abc import Iterable import pytest from fastapi import FastAPI @@ -18,13 +18,9 @@ from simcore_service_api_server.api.dependencies.resource_usage_tracker_rpc import ( get_resource_usage_tracker_client, ) -from simcore_service_api_server.api.dependencies.webserver_rpc import ( - get_wb_api_rpc_client, -) from simcore_service_api_server.services_rpc.resource_usage_tracker import ( ResourceUsageTrackerClient, ) -from simcore_service_api_server.services_rpc.wb_api_server import WbApiRpcClient # Fake response based on values from 01_checkout_release.json EXPECTED_CHECKOUT = LicensedItemCheckoutRpcGet.model_validate( @@ -64,14 +60,9 @@ @pytest.fixture async def mock_wb_api_server_rpc( app: FastAPI, - mocker: MockerFixture, + mocked_app_rpc_dependencies: None, mock_handler_in_licenses_rpc_interface: HandlerMockFactory, ) -> None: - from servicelib.rabbitmq.rpc_interfaces.webserver.v1 import WebServerRpcClient - - app.dependency_overrides[get_wb_api_rpc_client] = lambda: WbApiRpcClient( - _rpc_client=mocker.MagicMock(spec=WebServerRpcClient), - ) mock_handler_in_licenses_rpc_interface( "checkout_licensed_item_for_wallet", return_value=EXPECTED_CHECKOUT @@ -83,8 +74,9 @@ async def mock_wb_api_server_rpc( @pytest.fixture -async def mock_rut_server_rpc(app: FastAPI, mocker: MockerFixture) -> None: - from servicelib.rabbitmq import RabbitMQRPCClient +def mock_rut_server_rpc(app: FastAPI, mocker: MockerFixture) -> Iterable[None]: + import simcore_service_api_server.services_rpc.resource_usage_tracker # noqa: PLC0415 + from servicelib.rabbitmq import RabbitMQRPCClient # noqa: PLC0415 app.dependency_overrides[get_resource_usage_tracker_client] = ( lambda: ResourceUsageTrackerClient( @@ -92,17 +84,18 @@ async def mock_rut_server_rpc(app: FastAPI, mocker: MockerFixture) -> None: ) ) - mocker.patch( - "simcore_service_api_server.services_rpc.resource_usage_tracker._get_licensed_item_checkout", + mocker.patch.object( + simcore_service_api_server.services_rpc.resource_usage_tracker, + "_get_licensed_item_checkout", return_value=EXPECTED_CHECKOUT, ) + yield None -@pytest.mark.skipif( - not os.getenv("PACT_BROKER_URL"), - reason="This test runs only if PACT_BROKER_URL is provided", -) -def test_provider_against_pact( + app.dependency_overrides.pop(get_resource_usage_tracker_client, None) + + +def test_osparc_api_server_checkout_release_pact( pact_broker_credentials: tuple[str, str, str], mock_wb_api_server_rpc: None, mock_rut_server_rpc: None, @@ -127,7 +120,7 @@ def test_provider_against_pact( # NOTE: If you want to filter/test against specific contract use tags verifier = broker_builder.consumer_tags( - "checkout_release" # <-- Here you define which pact to verify + "checkout_release" # NOTE: Here you define which pact to verify ).build() # Set API version and run verification diff --git a/services/api-server/tests/unit/pact_broker/test_pact_licensed_items.py b/services/api-server/tests/unit/pact_broker/test_pact_licensed_items.py index 5ca14950b0a..31b1bf8c63a 100644 --- a/services/api-server/tests/unit/pact_broker/test_pact_licensed_items.py +++ b/services/api-server/tests/unit/pact_broker/test_pact_licensed_items.py @@ -3,7 +3,6 @@ # pylint: disable=unused-variable # pylint: disable=too-many-arguments -import os import pytest from fastapi import FastAPI @@ -146,11 +145,7 @@ async def mock_wb_api_server_rpc( ) -@pytest.mark.skipif( - not os.getenv("PACT_BROKER_URL"), - reason="This test runs only if PACT_BROKER_URL is provided", -) -def test_provider_against_pact( +def test_osparc_api_server_licensed_items_pact( pact_broker_credentials: tuple[str, str, str], mock_wb_api_server_rpc: None, running_test_server_url: str, @@ -174,7 +169,7 @@ def test_provider_against_pact( # NOTE: If you want to filter/test against specific contract use tags verifier = broker_builder.consumer_tags( - "licensed_items" # <-- Here you define which pact to verify + "licensed_items" # NOTE: Here you define which pact to verify ).build() # Set API version and run verification