Skip to content

Commit df7c8de

Browse files
jentykalbertsola
authored andcommitted
E2E Notification subscriber
- Add enable/disable actions for notifications subscriber - Add e2e test suite for notification subscribers
1 parent a6a3cff commit df7c8de

File tree

9 files changed

+351
-1
lines changed

9 files changed

+351
-1
lines changed

e2e_config.test.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@
4242
"commerce.subscription.agreement.id": "AGR-2473-3299-1721",
4343
"commerce.subscription.id": "SUB-3678-1831-2188",
4444
"commerce.subscription.product.item.id": "ITM-1767-7355-0001",
45+
"notifications.subscriber.id": "NTS-0829-7123-7123",
4546
"notifications.message.id": "MSG-0000-6215-1019-0139"
4647
}

mpt_api_client/http/mixins.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,46 @@ async def get(self, resource_id: str, select: list[str] | str | None = None) ->
395395
return await self._resource_action(resource_id=resource_id, query_params={"select": select}) # type: ignore[attr-defined, no-any-return]
396396

397397

398+
class AsyncEnableMixin[Model: BaseModel]:
399+
"""Enable resource mixin."""
400+
401+
async def enable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
402+
"""Disable a specific resource using."""
403+
return await self._resource_action( # type: ignore[attr-defined, no-any-return]
404+
resource_id=resource_id, method="POST", action="enable", json=resource_data
405+
)
406+
407+
408+
class EnableMixin[Model: BaseModel]:
409+
"""Disable resource mixin."""
410+
411+
def enable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
412+
"""Disable a specific resource using."""
413+
return self._resource_action( # type: ignore[attr-defined, no-any-return]
414+
resource_id=resource_id, method="POST", action="enable", json=resource_data
415+
)
416+
417+
418+
class AsyncDisableMixin[Model: BaseModel]:
419+
"""Disable resource mixin."""
420+
421+
async def disable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
422+
"""Disable a specific resource using."""
423+
return await self._resource_action( # type: ignore[attr-defined, no-any-return]
424+
resource_id=resource_id, method="POST", action="disable", json=resource_data
425+
)
426+
427+
428+
class DisableMixin[Model: BaseModel]:
429+
"""Disable resource mixin."""
430+
431+
def disable(self, resource_id: str, resource_data: ResourceData | None = None) -> Model:
432+
"""Disable a specific resource using."""
433+
return self._resource_action( # type: ignore[attr-defined, no-any-return]
434+
resource_id=resource_id, method="POST", action="disable", json=resource_data
435+
)
436+
437+
398438
class QueryableMixin:
399439
"""Mixin providing query functionality for filtering, ordering, and selecting fields."""
400440

mpt_api_client/resources/notifications/subscribers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4+
AsyncDisableMixin,
5+
AsyncEnableMixin,
46
AsyncManagedResourceMixin,
57
CollectionMixin,
8+
DisableMixin,
9+
EnableMixin,
610
ManagedResourceMixin,
711
)
812
from mpt_api_client.models import Model
@@ -21,6 +25,8 @@ class SubscribersServiceConfig:
2125

2226

2327
class SubscribersService(
28+
EnableMixin[Subscriber],
29+
DisableMixin[Subscriber],
2430
ManagedResourceMixin[Subscriber],
2531
CollectionMixin[Subscriber],
2632
Service[Subscriber],
@@ -30,6 +36,8 @@ class SubscribersService(
3036

3137

3238
class AsyncSubscribersService(
39+
AsyncEnableMixin[Subscriber],
40+
AsyncDisableMixin[Subscriber],
3341
AsyncManagedResourceMixin[Subscriber],
3442
AsyncCollectionMixin[Subscriber],
3543
AsyncService[Subscriber],

tests/e2e/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,8 @@ def authorization_id(e2e_config):
151151
@pytest.fixture
152152
def price_list_id(e2e_config):
153153
return e2e_config["catalog.price_list.id"]
154+
155+
156+
@pytest.fixture
157+
def user_group_id(e2e_config):
158+
return e2e_config["accounts.user_group.id"]

tests/e2e/notifications/subscribers/__init__.py

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import pytest
2+
3+
from mpt_api_client.exceptions import MPTAPIError
4+
5+
6+
@pytest.fixture
7+
def subscriber_id(e2e_config):
8+
return e2e_config.get("notifications.subscriber.id")
9+
10+
11+
@pytest.fixture
12+
def invalid_subscriber_id():
13+
return "NTS-0000-0000-0000"
14+
15+
16+
@pytest.fixture
17+
def recipients_factory(user_id, user_group_id):
18+
def _recipients( # noqa: WPS430
19+
users: list | None = None,
20+
user_groups: list | None = None,
21+
) -> dict:
22+
return {
23+
"users": users or [{"id": user_id}],
24+
"userGroups": user_groups or [{"id": user_group_id}],
25+
}
26+
27+
return _recipients
28+
29+
30+
@pytest.fixture
31+
def subscriber_factory(recipients_factory):
32+
def _subscriber( # noqa: WPS430
33+
recipients: dict | None = None,
34+
note: str = "Test note",
35+
) -> dict:
36+
return {
37+
"recipients": recipients or recipients_factory(),
38+
"note": note,
39+
}
40+
41+
return _subscriber
42+
43+
44+
@pytest.fixture
45+
def disabled_subscriber_id(mpt_client, subscriber_id):
46+
subscriber = mpt_client.notifications.subscribers.get(subscriber_id)
47+
if subscriber.status != "Disabled":
48+
subscriber = mpt_client.notifications.subscribers.disable(subscriber_id)
49+
50+
yield subscriber.id
51+
52+
try:
53+
mpt_client.notifications.subscribers.enable(subscriber_id)
54+
except MPTAPIError:
55+
print(f"TEARDOWN - Unable to re-enable subscriber {subscriber_id=}") # noqa: WPS421
56+
57+
58+
@pytest.fixture
59+
def active_subscriber_id(mpt_client, subscriber_id):
60+
subscriber = mpt_client.notifications.subscribers.get(subscriber_id)
61+
if subscriber.status != "Active":
62+
subscriber = mpt_client.notifications.subscribers.enable(subscriber_id)
63+
64+
return subscriber.id
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
async def test_get_subscriber_by_id(async_mpt_client, subscriber_id):
10+
result = await async_mpt_client.notifications.subscribers.get(subscriber_id)
11+
12+
assert result is not None
13+
14+
15+
async def test_list_subscribers(async_mpt_client):
16+
limit = 10
17+
18+
result = await async_mpt_client.notifications.subscribers.fetch_page(limit=limit)
19+
20+
assert len(result) > 0
21+
22+
23+
async def test_get_subscriber_by_id_not_found(async_mpt_client, invalid_subscriber_id):
24+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
25+
await async_mpt_client.notifications.subscribers.get(invalid_subscriber_id)
26+
27+
28+
async def test_filter_subscribers(async_mpt_client, subscriber_id):
29+
select_fields = ["-config"]
30+
async_filtered_subscribers = async_mpt_client.notifications.subscribers.filter(
31+
RQLQuery(id=subscriber_id)
32+
).select(*select_fields)
33+
34+
result = [
35+
filtered_subscriber async for filtered_subscriber in async_filtered_subscribers.iterate()
36+
]
37+
38+
assert len(result) > 0
39+
40+
41+
async def test_update_subscriber_not_found(
42+
async_mpt_client, subscriber_factory, invalid_subscriber_id, recipients_factory
43+
):
44+
updated_subscriber_data = subscriber_factory(recipients=recipients_factory())
45+
46+
with pytest.raises(MPTAPIError):
47+
await async_mpt_client.notifications.subscribers.update(
48+
invalid_subscriber_id, updated_subscriber_data
49+
)
50+
51+
52+
async def test_disable_subscriber(async_mpt_client, active_subscriber_id):
53+
result = await async_mpt_client.notifications.subscribers.disable(active_subscriber_id)
54+
55+
assert result is not None
56+
assert result.status == "Disabled"
57+
58+
59+
async def test_disable_subscriber_not_found(async_mpt_client, invalid_subscriber_id):
60+
with pytest.raises(
61+
MPTAPIError, match=r"400 Bad Request - Subscriber with id 'NTS-0000-0000-0000' not found"
62+
):
63+
await async_mpt_client.notifications.subscribers.disable(invalid_subscriber_id)
64+
65+
66+
async def test_enable_subscriber(async_mpt_client, disabled_subscriber_id):
67+
result = await async_mpt_client.notifications.subscribers.enable(disabled_subscriber_id)
68+
69+
assert result is not None
70+
assert result.status == "Active"
71+
72+
73+
async def test_enable_subscriber_not_found(async_mpt_client, invalid_subscriber_id):
74+
with pytest.raises(
75+
MPTAPIError, match=r"400 Bad Request - Subscriber with id 'NTS-0000-0000-0000' not found"
76+
):
77+
await async_mpt_client.notifications.subscribers.enable(invalid_subscriber_id)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
def test_get_subscriber_by_id(mpt_client, subscriber_id):
10+
result = mpt_client.notifications.subscribers.get(subscriber_id)
11+
12+
assert result is not None
13+
14+
15+
def test_list_subscribers(mpt_client):
16+
limit = 10
17+
18+
result = mpt_client.notifications.subscribers.fetch_page(limit=limit)
19+
20+
assert len(result) > 0
21+
22+
23+
def test_get_subscriber_by_id_not_found(mpt_client, invalid_subscriber_id):
24+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
25+
mpt_client.notifications.subscribers.get(invalid_subscriber_id)
26+
27+
28+
def test_filter_subscribers(mpt_ops, subscriber_id):
29+
select_fields = ["-config"]
30+
filtered_subscribers = mpt_ops.notifications.subscribers.filter(
31+
RQLQuery(id=subscriber_id)
32+
).select(*select_fields)
33+
34+
result = list(filtered_subscribers.iterate())
35+
36+
assert len(result) > 0
37+
38+
39+
def test_update_subscriber_not_found(
40+
mpt_ops, subscriber_factory, invalid_subscriber_id, recipients_factory
41+
):
42+
updated_subscriber_data = subscriber_factory(recipients=recipients_factory())
43+
44+
with pytest.raises(MPTAPIError):
45+
mpt_ops.notifications.subscribers.update(invalid_subscriber_id, updated_subscriber_data)
46+
47+
48+
def test_disable_subscriber(mpt_client, active_subscriber_id):
49+
result = mpt_client.notifications.subscribers.disable(active_subscriber_id)
50+
51+
assert result is not None
52+
assert result.status == "Disabled"
53+
54+
55+
def test_disable_subscriber_not_found(mpt_client, invalid_subscriber_id):
56+
with pytest.raises(
57+
MPTAPIError, match=r"400 Bad Request - Subscriber with id 'NTS-0000-0000-0000' not found"
58+
):
59+
mpt_client.notifications.subscribers.disable(invalid_subscriber_id)
60+
61+
62+
def test_enable_subscriber(mpt_client, disabled_subscriber_id):
63+
result = mpt_client.notifications.subscribers.enable(disabled_subscriber_id)
64+
65+
assert result is not None
66+
assert result.status == "Active"
67+
68+
69+
def test_enable_subscriber_not_found(mpt_client, invalid_subscriber_id):
70+
with pytest.raises(
71+
MPTAPIError, match=r"400 Bad Request - Subscriber with id 'NTS-0000-0000-0000' not found"
72+
):
73+
mpt_client.notifications.subscribers.enable(invalid_subscriber_id)

0 commit comments

Comments
 (0)