Skip to content

Commit b1f36d0

Browse files
author
Robert Segal
committed
Added seeding and e2e tests for commerce subscriptions
1 parent d4ca602 commit b1f36d0

File tree

8 files changed

+234
-4
lines changed

8 files changed

+234
-4
lines changed

e2e_config.test.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,8 @@
3333
"commerce.product.item.id": "ITM-1767-7355-0001",
3434
"commerce.product.listing.id": "LST-5489-0806",
3535
"commerce.product.template.id": "TPL-1767-7355-0003",
36+
"commerce.subscription.agreement.id": "AGR-2473-3299-1721",
37+
"commerce.subscription.id": "SUB-3678-1831-2188",
38+
"commerce.subscription.product.item.id": "ITM-1767-7355-0001",
3639
"notifications.message.id": "MSG-0000-6215-1019-0139"
3740
}

mpt_api_client/resources/commerce/subscriptions.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
AsyncCreateMixin,
88
AsyncDeleteMixin,
99
AsyncGetMixin,
10+
AsyncUpdateMixin,
1011
CollectionMixin,
1112
CreateMixin,
1213
DeleteMixin,
1314
GetMixin,
15+
UpdateMixin,
1416
)
1517
from mpt_api_client.models import Model, ResourceData
1618

@@ -29,6 +31,7 @@ class SubscriptionsServiceConfig:
2931

3032
class SubscriptionsService( # noqa: WPS215
3133
CreateMixin[Subscription],
34+
UpdateMixin[Subscription],
3235
DeleteMixin,
3336
GetMixin[Subscription],
3437
CollectionMixin[Subscription],
@@ -49,7 +52,9 @@ def render(self, resource_id: str) -> str:
4952
response = self._resource_do_request(resource_id, "GET", "render")
5053
return response.text
5154

52-
def terminate(self, resource_id: str, resource_data: ResourceData) -> Subscription:
55+
def terminate(
56+
self, resource_id: str, resource_data: ResourceData | None = None
57+
) -> Subscription:
5358
"""Terminate subscription.
5459
5560
Args:
@@ -64,6 +69,7 @@ def terminate(self, resource_id: str, resource_data: ResourceData) -> Subscripti
6469

6570
class AsyncSubscriptionsService( # noqa: WPS215
6671
AsyncCreateMixin[Subscription],
72+
AsyncUpdateMixin[Subscription],
6773
AsyncDeleteMixin,
6874
AsyncGetMixin[Subscription],
6975
AsyncCollectionMixin[Subscription],
@@ -84,7 +90,9 @@ async def render(self, resource_id: str) -> str:
8490
response = await self._resource_do_request(resource_id, "GET", "render")
8591
return response.text
8692

87-
async def terminate(self, resource_id: str, resource_data: ResourceData) -> Subscription:
93+
async def terminate(
94+
self, resource_id: str, resource_data: ResourceData | None = None
95+
) -> Subscription:
8896
"""Terminate subscription.
8997
9098
Args:

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ filterwarnings = [
7474
"ignore:pkg_resources is deprecated as an API:DeprecationWarning",
7575
]
7676
rp_project = "mpt-api-python-client"
77+
markers = [
78+
"flaky: mark test as flaky (may fail intermittently)",
79+
]
7780

7881
[tool.coverage.run]
7982
branch = true
@@ -120,6 +123,7 @@ per-file-ignores = [
120123
"mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215 WPS235",
121124
"mpt_api_client/resources/catalog/mixins.py: WPS110 WPS202 WPS214 WPS215 WPS235",
122125
"mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 WPS235",
126+
"mpt_api_client/resources/commerce/*.py: WPS235 WPS215",
123127
"mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214",
124128
"tests/unit/http/test_async_service.py: WPS204 WPS202",
125129
"tests/unit/http/test_service.py: WPS204 WPS202",

tests/e2e/commerce/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,13 @@ def agreement_id(e2e_config):
99
@pytest.fixture
1010
def commerce_product_id(e2e_config):
1111
return e2e_config["commerce.product.id"]
12+
13+
14+
@pytest.fixture
15+
def subscription_item_id(e2e_config):
16+
return e2e_config["commerce.subscription.product.item.id"]
17+
18+
19+
@pytest.fixture
20+
def subscription_agreement_id(e2e_config):
21+
return e2e_config["commerce.subscription.agreement.id"]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import pytest
2+
from freezegun import freeze_time
3+
4+
5+
@pytest.fixture
6+
def subscription_id(e2e_config):
7+
return e2e_config["commerce.subscription.id"]
8+
9+
10+
@pytest.fixture
11+
def invalid_subscription_id():
12+
return "SUB-0000-0000-0000"
13+
14+
15+
@pytest.fixture
16+
def subscription_factory(subscription_agreement_id, subscription_item_id):
17+
@freeze_time("2025-11-14T09:00:00.000Z")
18+
def factory(
19+
name: str = "E2E Created Subscription",
20+
external_vendor_id: str = "ext-vendor-id",
21+
quantity: int = 1,
22+
):
23+
return {
24+
"name": name,
25+
"startDate": "2025-11-03T09:00:00.000Z",
26+
"commitmentDate": "2026-11-02T09:00:00.000Z",
27+
"autoRenew": True,
28+
"agreement": {"id": subscription_agreement_id},
29+
"externalIds": {"vendor": external_vendor_id},
30+
"template": None,
31+
"lines": [
32+
{
33+
"item": {"id": subscription_item_id},
34+
"quantity": quantity,
35+
"price": {"unitPP": 10},
36+
}
37+
],
38+
"parameters": {"fulfillment": []},
39+
}
40+
41+
return factory
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
3+
from mpt_api_client.exceptions import MPTAPIError
4+
from mpt_api_client.rql.query_builder import RQLQuery
5+
6+
pytestmark = [pytest.mark.flaky]
7+
8+
9+
@pytest.fixture
10+
async def created_subscription(async_mpt_vendor, subscription_factory):
11+
subscription_data = subscription_factory()
12+
13+
subscription = await async_mpt_vendor.commerce.subscriptions.create(subscription_data)
14+
15+
yield subscription
16+
17+
try:
18+
await async_mpt_vendor.commerce.subscriptions.terminate(subscription.id)
19+
except MPTAPIError as error:
20+
print(f"TEARDOWN - Unable to terminate subscription: {getattr(error, 'title', str(error))}") # noqa: WPS421
21+
22+
23+
async def test_get_subscription_by_id(async_mpt_vendor, subscription_id):
24+
result = await async_mpt_vendor.commerce.subscriptions.get(subscription_id)
25+
26+
assert result is not None
27+
28+
29+
async def test_list_subscriptions(async_mpt_vendor):
30+
limit = 10
31+
32+
result = await async_mpt_vendor.commerce.subscriptions.fetch_page(limit=limit)
33+
34+
assert result is not None
35+
36+
37+
async def test_get_subscription_by_id_not_found(async_mpt_vendor, invalid_subscription_id):
38+
with pytest.raises(MPTAPIError, match="404 Not Found"):
39+
await async_mpt_vendor.commerce.subscriptions.get(invalid_subscription_id)
40+
41+
42+
async def test_filter_subscriptions(async_mpt_vendor, subscription_id):
43+
select_fields = ["-externalIds"]
44+
filtered_subscriptions = (
45+
async_mpt_vendor.commerce.subscriptions.filter(RQLQuery(id=subscription_id))
46+
.filter(RQLQuery(name="E2E Seeded Subscription"))
47+
.select(*select_fields)
48+
)
49+
50+
result = [subscription async for subscription in filtered_subscriptions.iterate()]
51+
52+
assert len(result) == 1
53+
54+
55+
def test_create_subscription(created_subscription):
56+
result = created_subscription
57+
58+
assert result is not None
59+
60+
61+
async def test_update_subscription(async_mpt_vendor, created_subscription):
62+
updated_subscription_data = {
63+
"name": "E2E Updated Subscription",
64+
}
65+
66+
result = await async_mpt_vendor.commerce.subscriptions.update(
67+
created_subscription.id, updated_subscription_data
68+
)
69+
70+
assert result is not None
71+
72+
73+
async def test_terminate_subscription(async_mpt_vendor, created_subscription):
74+
result = await async_mpt_vendor.commerce.subscriptions.terminate(created_subscription.id)
75+
76+
assert result is not None
77+
78+
79+
async def test_render_subscription(async_mpt_vendor, created_subscription):
80+
result = await async_mpt_vendor.commerce.subscriptions.render(created_subscription.id)
81+
82+
assert result is not None
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
3+
from mpt_api_client.exceptions import MPTAPIError
4+
from mpt_api_client.rql.query_builder import RQLQuery
5+
6+
pytestmark = [pytest.mark.flaky]
7+
8+
9+
@pytest.fixture
10+
def created_subscription(mpt_vendor, subscription_factory):
11+
subscription_data = subscription_factory()
12+
13+
subscription = mpt_vendor.commerce.subscriptions.create(subscription_data)
14+
15+
yield subscription
16+
17+
try:
18+
mpt_vendor.commerce.subscriptions.terminate(subscription.id)
19+
except MPTAPIError as error:
20+
print(f"TEARDOWN - Unable to terminate subscription: {getattr(error, 'title', str(error))}") # noqa: WPS421
21+
22+
23+
def test_get_subscription_by_id(mpt_vendor, subscription_id):
24+
result = mpt_vendor.commerce.subscriptions.get(subscription_id)
25+
26+
assert result is not None
27+
28+
29+
def test_list_subscriptions(mpt_vendor):
30+
limit = 10
31+
32+
result = mpt_vendor.commerce.subscriptions.fetch_page(limit=limit)
33+
34+
assert result is not None
35+
36+
37+
def test_get_subscription_by_id_not_found(mpt_vendor, invalid_subscription_id):
38+
with pytest.raises(MPTAPIError, match="404 Not Found"):
39+
mpt_vendor.commerce.subscriptions.get(invalid_subscription_id)
40+
41+
42+
def test_filter_subscriptions(mpt_vendor, subscription_id):
43+
select_fields = ["-externalIds"]
44+
filtered_subscriptions = (
45+
mpt_vendor.commerce.subscriptions.filter(RQLQuery(id=subscription_id))
46+
.filter(RQLQuery(name="E2E Seeded Subscription"))
47+
.select(*select_fields)
48+
)
49+
50+
result = list(filtered_subscriptions.iterate())
51+
52+
assert len(result) == 1
53+
54+
55+
def test_create_subscription(created_subscription):
56+
result = created_subscription
57+
58+
assert result is not None
59+
60+
61+
def test_update_subscription(mpt_vendor, created_subscription):
62+
updated_subscription_data = {
63+
"name": "E2E Updated Subscription",
64+
}
65+
66+
result = mpt_vendor.commerce.subscriptions.update(
67+
created_subscription.id, updated_subscription_data
68+
)
69+
70+
assert result is not None
71+
72+
73+
def test_terminate_subscription(mpt_vendor, created_subscription):
74+
result = mpt_vendor.commerce.subscriptions.terminate(created_subscription.id)
75+
76+
assert result is not None
77+
78+
79+
def test_render_subscription(mpt_vendor, created_subscription):
80+
result = mpt_vendor.commerce.subscriptions.render(created_subscription.id)
81+
82+
assert result is not None

tests/unit/resources/commerce/test_subscriptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ def async_subscriptions_service(async_http_client):
1818
return AsyncSubscriptionsService(http_client=async_http_client)
1919

2020

21-
@pytest.mark.parametrize("method", ["get", "create", "delete"])
21+
@pytest.mark.parametrize("method", ["get", "create", "update", "delete", "iterate"])
2222
def test_methods_present(subscriptions_service, method):
2323
result = hasattr(subscriptions_service, method)
2424

2525
assert result is True
2626

2727

28-
@pytest.mark.parametrize("method", ["get", "create", "delete"])
28+
@pytest.mark.parametrize("method", ["get", "create", "update", "delete", "iterate"])
2929
def test_async_methods_present(async_subscriptions_service, method):
3030
result = hasattr(async_subscriptions_service, method)
3131

0 commit comments

Comments
 (0)