Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions services/api-server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 5 additions & 5 deletions services/api-server/tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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 = {}
Expand Down
23 changes: 18 additions & 5 deletions services/api-server/tests/unit/pact_broker/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
# Contract testing (PACT)

Maintainer @matusdrobuliak66
- Maintainer @matusdrobuliak66

## How to run this test as a provider?

```bash
PACT_BROKER_URL=<fill-broker-url> PACT_BROKER_USERNAME=<fill-username> PACT_BROKER_PASSWORD=<fill-secret> make test-pacts
PACT_BROKER_URL=<fill-broker-url> PACT_BROKER_USERNAME=<fill-username> PACT_BROKER_PASSWORD=<fill-secret>

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=<fill-broker-url> --broker-username=<fill-username> --broker-password=<fill-secret>
```
27 changes: 17 additions & 10 deletions services/api-server/tests/unit/pact_broker/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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="[email protected]")
return broker_url, broker_username, broker_password


@pytest.fixture()
@pytest.fixture
def running_test_server_url(
app: FastAPI,
):
Expand All @@ -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="[email protected]")

app.dependency_overrides[get_current_identity] = _mock_get_current_identity

port = unused_port()
base_url = f"http://localhost:{port}"
Expand All @@ -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()
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# pylint: disable=too-many-arguments


import os
from collections.abc import Iterable

import pytest
from fastapi import FastAPI
Expand All @@ -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(
Expand Down Expand Up @@ -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
Expand All @@ -83,26 +74,28 @@ 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(
_client=mocker.MagicMock(spec=RabbitMQRPCClient)
)
)

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,
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
# pylint: disable=unused-variable
# pylint: disable=too-many-arguments

import os

import pytest
from fastapi import FastAPI
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
Loading