Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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 AsyncIterable

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,30 @@ 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
) -> 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 +122,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