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
1 change: 1 addition & 0 deletions mpt_api_client/resources/catalog/mixins.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from mpt_api_client.models import ResourceData


# TODO: Consider moving publishable and activatable mixins to http/mixins
class PublishableMixin[Model]:
"""Publishable mixin adds the ability to review, publish and unpublish."""

Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ per-file-ignores =
tests/http/test_service.py: WPS204 WPS202
tests/http/test_mixins.py: WPS204 WPS202
tests/resources/catalog/test_products.py: WPS202 WPS210
tests/resources/catalog/test_mixins.py: WPS118 WPS202 WPS204

tests/*:
# Allow magic strings.
Expand Down
230 changes: 205 additions & 25 deletions tests/resources/catalog/test_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,71 @@
import pytest
import respx

from mpt_api_client.resources.catalog.products import AsyncProductsService, Product, ProductsService
from mpt_api_client.http.async_service import AsyncService
from mpt_api_client.http.service import Service
from mpt_api_client.resources.catalog.mixins import (
ActivatableMixin,
AsyncActivatableMixin,
AsyncPublishableMixin,
PublishableMixin,
)
from tests.conftest import DummyModel


class DummyPublishableService( # noqa: WPS215
PublishableMixin[DummyModel],
Service[DummyModel],
):
_endpoint = "/public/v1/dummy/publishable/"
_model_class = DummyModel
_collection_key = "data"


class DummyAsyncPublishableService( # noqa: WPS215
AsyncPublishableMixin[DummyModel],
AsyncService[DummyModel],
):
_endpoint = "/public/v1/dummy/publishable/"
_model_class = DummyModel
_collection_key = "data"


class DummyActivatableService( # noqa: WPS215
ActivatableMixin[DummyModel],
Service[DummyModel],
):
_endpoint = "/public/v1/dummy/activatable/"
_model_class = DummyModel
_collection_key = "data"


class DummyAsyncActivatableService( # noqa: WPS215
AsyncActivatableMixin[DummyModel],
AsyncService[DummyModel],
):
_endpoint = "/public/v1/dummy/activatable/"
_model_class = DummyModel
_collection_key = "data"


@pytest.fixture
def publishable_service(http_client):
return DummyPublishableService(http_client=http_client)


@pytest.fixture
def product_service(http_client):
return ProductsService(http_client=http_client)
def async_publishable_service(async_http_client):
return DummyAsyncPublishableService(http_client=async_http_client)


@pytest.fixture
def async_product_service(async_http_client):
return AsyncProductsService(http_client=async_http_client)
def activatable_service(http_client):
return DummyActivatableService(http_client=http_client)


@pytest.fixture
def async_activatable_service(async_http_client):
return DummyAsyncActivatableService(http_client=async_http_client)


@pytest.mark.parametrize(
Expand All @@ -23,27 +77,27 @@ def async_product_service(async_http_client):
("unpublish", {"id": "PRD-123", "status": "update"}),
],
)
def test_custom_resource_actions(product_service, action, input_status):
def test_custom_resource_actions(publishable_service, action, input_status):
request_expected_content = b'{"id":"PRD-123","status":"update"}'
response_expected_data = {"id": "PRD-123", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/catalog/products/PRD-123/{action}"
f"https://api.example.com/public/v1/dummy/publishable/PRD-123/{action}"
).mock(
return_value=httpx.Response(
status_code=200,
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)
order = getattr(product_service, action)("PRD-123", input_status)
order = getattr(publishable_service, action)("PRD-123", input_status)

assert mock_route.call_count == 1
request = mock_route.calls[0].request

assert request.content == request_expected_content
assert order.to_dict() == response_expected_data
assert isinstance(order, Product)
assert isinstance(order, DummyModel)


@pytest.mark.parametrize(
Expand All @@ -54,27 +108,27 @@ def test_custom_resource_actions(product_service, action, input_status):
("unpublish", None),
],
)
def test_custom_resource_actions_no_data(product_service, action, input_status):
def test_custom_resource_actions_no_data(publishable_service, action, input_status):
request_expected_content = b""
response_expected_data = {"id": "PRD-123", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/catalog/products/PRD-123/{action}"
f"https://api.example.com/public/v1/dummy/publishable/PRD-123/{action}"
).mock(
return_value=httpx.Response(
status_code=200,
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)

order = getattr(product_service, action)("PRD-123")
order = getattr(publishable_service, action)("PRD-123")

assert mock_route.call_count == 1
request = mock_route.calls[0].request
assert request.content == request_expected_content
assert order.to_dict() == response_expected_data
assert isinstance(order, Product)
assert isinstance(order, DummyModel)


@pytest.mark.parametrize(
Expand All @@ -85,27 +139,27 @@ def test_custom_resource_actions_no_data(product_service, action, input_status):
("unpublish", {"id": "PRD-123", "status": "update"}),
],
)
async def test_async_custom_resource_actions(async_product_service, action, input_status):
async def test_async_custom_resource_actions(async_publishable_service, action, input_status):
request_expected_content = b'{"id":"PRD-123","status":"update"}'
response_expected_data = {"id": "PRD-123", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/catalog/products/PRD-123/{action}"
f"https://api.example.com/public/v1/dummy/publishable/PRD-123/{action}"
).mock(
return_value=httpx.Response(
status_code=200,
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)
order = await getattr(async_product_service, action)("PRD-123", input_status)
order = await getattr(async_publishable_service, action)("PRD-123", input_status)

assert mock_route.call_count == 1
request = mock_route.calls[0].request

assert request.content == request_expected_content
assert order.to_dict() == response_expected_data
assert isinstance(order, Product)
assert isinstance(order, DummyModel)


@pytest.mark.parametrize(
Expand All @@ -116,24 +170,150 @@ async def test_async_custom_resource_actions(async_product_service, action, inpu
("unpublish", None),
],
)
async def test_async_custom_resource_actions_no_data(async_product_service, action, input_status):
async def test_async_custom_resource_actions_no_data(
async_publishable_service, action, input_status
):
request_expected_content = b""
response_expected_data = {"id": "PRD-123", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/catalog/products/PRD-123/{action}"
f"https://api.example.com/public/v1/dummy/publishable/PRD-123/{action}"
).mock(
return_value=httpx.Response(
status_code=200,
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)

order = await getattr(async_product_service, action)("PRD-123")
order = await getattr(async_publishable_service, action)("PRD-123")

assert mock_route.call_count == 1
request = mock_route.calls[0].request
assert request.content == request_expected_content
assert order.to_dict() == response_expected_data
assert isinstance(order, Product)
assert isinstance(order, DummyModel)


@pytest.mark.parametrize(
("action", "input_status"),
[
("activate", {"id": "OBJ-0000-0001", "status": "update"}),
("deactivate", {"id": "OBJ-0000-0001", "status": "update"}),
],
)
def test_custom_resource_activatable_actions(activatable_service, action, input_status):
request_expected_content = b'{"id":"OBJ-0000-0001","status":"update"}'
response_expected_data = {"id": "OBJ-0000-0001", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/dummy/activatable/OBJ-0000-0001/{action}"
).mock(
return_value=httpx.Response(
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)
attachment = getattr(activatable_service, action)("OBJ-0000-0001", input_status)

assert mock_route.call_count == 1
request = mock_route.calls[0].request

assert request.content == request_expected_content
assert attachment.to_dict() == response_expected_data
assert isinstance(attachment, DummyModel)


@pytest.mark.parametrize(
("action", "input_status"),
[
("activate", None),
("deactivate", None),
],
)
def test_custom_resource_activatable_actions_no_data(activatable_service, action, input_status):
request_expected_content = b""
response_expected_data = {"id": "OBJ-0000-0001", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/dummy/activatable/OBJ-0000-0001/{action}"
).mock(
return_value=httpx.Response(
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)
attachment = getattr(activatable_service, action)("OBJ-0000-0001", input_status)

assert mock_route.call_count == 1
request = mock_route.calls[0].request

assert request.content == request_expected_content
assert attachment.to_dict() == response_expected_data
assert isinstance(attachment, DummyModel)


@pytest.mark.parametrize(
("action", "input_status"),
[
("activate", {"id": "OBJ-0000-0001", "status": "update"}),
("deactivate", {"id": "OBJ-0000-0001", "status": "update"}),
],
)
async def test_async_custom_resource_activatable_actions(
async_activatable_service, action, input_status
):
request_expected_content = b'{"id":"OBJ-0000-0001","status":"update"}'
response_expected_data = {"id": "OBJ-0000-0001", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/dummy/activatable/OBJ-0000-0001/{action}"
).mock(
return_value=httpx.Response(
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)
attachment = await getattr(async_activatable_service, action)("OBJ-0000-0001", input_status)

assert mock_route.call_count == 1
request = mock_route.calls[0].request

assert request.content == request_expected_content
assert attachment.to_dict() == response_expected_data
assert isinstance(attachment, DummyModel)


@pytest.mark.parametrize(
("action", "input_status"),
[
("activate", None),
("deactivate", None),
],
)
async def test_async_custom_resource_activatable_actions_no_data(
async_activatable_service, action, input_status
):
request_expected_content = b""
response_expected_data = {"id": "OBJ-0000-0001", "status": "new_status"}
with respx.mock:
mock_route = respx.post(
f"https://api.example.com/public/v1/dummy/activatable/OBJ-0000-0001/{action}"
).mock(
return_value=httpx.Response(
status_code=httpx.codes.OK,
headers={"content-type": "application/json"},
json=response_expected_data,
)
)
attachment = await getattr(async_activatable_service, action)("OBJ-0000-0001", input_status)

assert mock_route.call_count == 1
request = mock_route.calls[0].request

assert request.content == request_expected_content
assert attachment.to_dict() == response_expected_data
assert isinstance(attachment, DummyModel)