Skip to content

Commit 0a8eb2e

Browse files
committed
MPT-14934 E2E for notifications/batches
1 parent 690b127 commit 0a8eb2e

File tree

8 files changed

+108
-164
lines changed

8 files changed

+108
-164
lines changed

e2e_config.test.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"commerce.subscription.agreement.id": "AGR-2473-3299-1721",
4747
"commerce.subscription.id": "SUB-3678-1831-2188",
4848
"commerce.subscription.product.item.id": "ITM-1767-7355-0001",
49+
"notifications.batch.id": "MST-3638-2460-4825",
4950
"notifications.category.id": "NTC-6157-0397",
5051
"notifications.subscriber.id": "NTS-0829-7123-7123",
5152
"notifications.message.id": "MSG-0000-6215-1019-0139"

mpt_api_client/resources/notifications/batches.py

Lines changed: 7 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
from httpx._types import FileTypes
2-
31
from mpt_api_client.http import AsyncService, Service
4-
from mpt_api_client.http.client import json_to_file_payload
52
from mpt_api_client.http.mixins import (
63
AsyncCollectionMixin,
4+
AsyncCreateFileMixin,
75
AsyncGetMixin,
86
CollectionMixin,
7+
CreateFileMixin,
98
GetMixin,
109
)
11-
from mpt_api_client.models import FileModel, Model, ResourceData
10+
from mpt_api_client.models import FileModel, Model
1211

1312

1413
class Batch(Model):
@@ -21,44 +20,19 @@ class BatchesServiceConfig:
2120
_endpoint = "/public/v1/notifications/batches"
2221
_model_class = Batch
2322
_collection_key = "data"
23+
_upload_file_key = "attachment"
24+
_upload_data_key = "batch"
2425

2526

2627
class BatchesService(
28+
CreateFileMixin[Batch],
2729
GetMixin[Batch],
2830
CollectionMixin[Batch],
2931
Service[Batch],
3032
BatchesServiceConfig,
3133
):
3234
"""Notifications Batches service."""
3335

34-
def create(
35-
self,
36-
resource_data: ResourceData | None = None,
37-
files: dict[str, FileTypes] | None = None, # noqa: WPS221
38-
data_key: str = "_attachment_data",
39-
) -> Model:
40-
"""Create batch with attachments.
41-
42-
Args:
43-
resource_data: batch data.
44-
files: Files data.
45-
data_key: Key to use for the JSON data in the multipart form.
46-
47-
Returns:
48-
Created resource.
49-
"""
50-
files = files or {}
51-
52-
if resource_data:
53-
files[data_key] = (
54-
None,
55-
json_to_file_payload(resource_data),
56-
"application/json",
57-
)
58-
59-
response = self.http_client.request("post", self.path, files=files)
60-
return self._model_class.from_response(response)
61-
6236
def get_batch_attachment(self, batch_id: str, attachment_id: str) -> FileModel:
6337
"""Get batch attachment.
6438
@@ -77,41 +51,14 @@ def get_batch_attachment(self, batch_id: str, attachment_id: str) -> FileModel:
7751

7852

7953
class AsyncBatchesService(
54+
AsyncCreateFileMixin[Batch],
8055
AsyncGetMixin[Batch],
8156
AsyncCollectionMixin[Batch],
8257
AsyncService[Batch],
8358
BatchesServiceConfig,
8459
):
8560
"""Async Notifications Batches service."""
8661

87-
async def create(
88-
self,
89-
resource_data: ResourceData | None = None,
90-
files: dict[str, FileTypes] | None = None, # noqa: WPS221
91-
data_key: str = "_attachment_data",
92-
) -> Model:
93-
"""Create batch with attachments.
94-
95-
Args:
96-
resource_data: batch data.
97-
files: Files data.
98-
data_key: Key to use for the JSON data in the multipart form.
99-
100-
Returns:
101-
Created resource.
102-
"""
103-
files = files or {}
104-
105-
if resource_data:
106-
files[data_key] = (
107-
None,
108-
json_to_file_payload(resource_data),
109-
"application/json",
110-
)
111-
112-
response = await self.http_client.request("post", self.path, files=files)
113-
return self._model_class.from_response(response)
114-
11562
async def get_batch_attachment(self, batch_id: str, attachment_id: str) -> FileModel:
11663
"""Get batch attachment.
11764
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pytest
2+
3+
4+
@pytest.fixture
5+
def batch_service(mpt_ops):
6+
return mpt_ops.notifications.batches
7+
8+
9+
@pytest.fixture
10+
def async_batch_service(async_mpt_ops):
11+
return async_mpt_ops.notifications.batches
12+
13+
14+
@pytest.fixture
15+
def batch_id(e2e_config):
16+
return e2e_config["notifications.batch.id"]
17+
18+
19+
@pytest.fixture
20+
def batch_data(category_id, short_uuid):
21+
return {
22+
"category": {"id": category_id},
23+
"subject": f"E2E - please delete - {short_uuid}",
24+
"body": "Hello world",
25+
"contacts": [{"email": f"{short_uuid}@example.com"}],
26+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import pytest
2+
3+
from mpt_api_client.rql.query_builder import RQLQuery
4+
5+
6+
@pytest.mark.skip(reason="Batches can not be deleted")
7+
async def test_create_batch(async_batch_service, batch_data):
8+
result = await async_batch_service.create(batch_data)
9+
10+
assert result is not None
11+
12+
13+
async def test_get_batch(async_batch_service, batch_id):
14+
result = await async_batch_service.get(batch_id)
15+
16+
assert result.id == batch_id
17+
18+
19+
async def test_iterate_and_filter(async_batch_service, batch_id):
20+
batches = [batch async for batch in async_batch_service.filter(RQLQuery(id=batch_id)).iterate()]
21+
22+
assert len(batches) == 1
23+
assert batches[0].id == batch_id
24+
25+
26+
@pytest.mark.skip(reason="Batches can not be deleted")
27+
async def test_create_batch_with_file(async_batch_service, batch_data, logo_fd):
28+
result = await async_batch_service.create(batch_data, file=logo_fd)
29+
30+
assert result is not None
31+
32+
33+
@pytest.mark.skip(reason="Batches attachments not implemented")
34+
async def test_download_attachment():
35+
# TODO - Implement get and download E2E tests for attachments
36+
raise NotImplementedError
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import pytest
2+
3+
from mpt_api_client import RQLQuery
4+
5+
6+
@pytest.mark.skip(reason="Batches can not be deleted")
7+
def test_create_batch(batch_service, batch_data):
8+
result = batch_service.create(batch_data)
9+
10+
assert result is not None
11+
12+
13+
def test_get_batch(batch_service, batch_id):
14+
result = batch_service.get(batch_id)
15+
16+
assert result.id == batch_id
17+
18+
19+
def test_iterate_and_filter(batch_service, batch_id):
20+
result = list(batch_service.filter(RQLQuery(id=batch_id)).iterate())
21+
22+
assert len(result) == 1
23+
assert result[0].id == batch_id
24+
25+
26+
@pytest.mark.skip(reason="Batches can not be deleted")
27+
def test_create_batch_with_file(batch_service, batch_data, logo_fd):
28+
result = batch_service.create(batch_data, file=logo_fd)
29+
30+
assert result is not None
31+
32+
33+
@pytest.mark.skip(reason="Batches attachments not implemented") # noqa: AAA01
34+
def test_download_attachment():
35+
# TODO - Implement get and download E2E tests for attachment
36+
raise NotImplementedError

tests/e2e/notifications/categories/test_async_categories.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ async def async_created_category(async_mpt_ops, category_data):
1717
print(f"TEARDOWN - Unable to delete category {category.id}: {error.title}") # noqa: WPS421
1818

1919

20-
def test_create_category(async_created_category, category_data):
20+
def test_create_category(async_created_category, category_data): # noqa: AAA01
2121
assert async_created_category.name == category_data["name"]
2222
assert async_created_category.description == category_data["description"]
2323

@@ -46,10 +46,7 @@ async def test_update_category(async_mpt_ops, async_created_category):
4646
async def test_filter_categories(async_mpt_vendor, category_id):
4747
service = async_mpt_vendor.notifications.categories
4848

49-
result = [
50-
category
51-
async for category in service.filter(RQLQuery(id=category_id)).iterate()
52-
]
49+
result = [category async for category in service.filter(RQLQuery(id=category_id)).iterate()]
5350

5451
assert len(result) == 1
5552
assert result[0].id == category_id

tests/e2e/notifications/categories/test_sync_categories.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ def test_update_category(mpt_ops, created_category):
4545
assert result.description == "Updated description"
4646

4747

48-
4948
def test_filter_categories(mpt_client, category_id):
5049
service = mpt_client.notifications.categories
5150

Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import io
2-
3-
import httpx
41
import pytest
5-
import respx
62

73
from mpt_api_client.resources.notifications.batches import (
84
AsyncBatchesService,
@@ -32,97 +28,3 @@ def test_async_batches_service_methods(async_batches_service, method):
3228
result = hasattr(async_batches_service, method)
3329

3430
assert result is True
35-
36-
37-
def test_sync_get_batch_attachment(batches_service):
38-
attachment_content = b"Attachment file content or binary data"
39-
with respx.mock:
40-
mock_route = respx.get(
41-
"https://api.example.com/public/v1/notifications/batches/BAT-123/attachments/ATT-456"
42-
).mock(
43-
return_value=httpx.Response(
44-
status_code=httpx.codes.OK,
45-
headers={
46-
"content-type": "application/octet-stream",
47-
"content-disposition": (
48-
'form-data; name="file"; filename="batch_attachment.pdf"'
49-
),
50-
},
51-
content=attachment_content,
52-
)
53-
)
54-
55-
result = batches_service.get_batch_attachment("BAT-123", "ATT-456")
56-
57-
assert mock_route.call_count == 1
58-
assert result.file_contents == attachment_content
59-
assert result.content_type == "application/octet-stream"
60-
assert result.filename == "batch_attachment.pdf"
61-
62-
63-
@pytest.mark.asyncio
64-
async def test_async_get_batch_attachment(async_batches_service):
65-
attachment_content = b"Attachment file content or binary data"
66-
with respx.mock:
67-
mock_route = respx.get(
68-
"https://api.example.com/public/v1/notifications/batches/BAT-123/attachments/ATT-456"
69-
).mock(
70-
return_value=httpx.Response(
71-
status_code=httpx.codes.OK,
72-
headers={
73-
"content-type": "application/octet-stream",
74-
"content-disposition": (
75-
'form-data; name="file"; filename="batch_attachment.pdf"'
76-
),
77-
},
78-
content=attachment_content,
79-
)
80-
)
81-
82-
result = await async_batches_service.get_batch_attachment("BAT-123", "ATT-456")
83-
84-
assert mock_route.call_count == 1
85-
assert result.file_contents == attachment_content
86-
assert result.content_type == "application/octet-stream"
87-
assert result.filename == "batch_attachment.pdf"
88-
89-
90-
def test_sync_batches_create_with_data(batches_service):
91-
batch_data = {"name": "Test Batch"}
92-
with respx.mock:
93-
mock_route = respx.post("https://api.example.com/public/v1/notifications/batches").mock(
94-
return_value=httpx.Response(
95-
status_code=httpx.codes.OK,
96-
json={"id": "BAT-133", "name": "Test Batch"},
97-
)
98-
)
99-
files = {"attachment": ("test.pdf", io.BytesIO(b"PDF content"), "application/pdf")}
100-
101-
result = batches_service.create(batch_data, files=files)
102-
103-
request = mock_route.calls[0].request
104-
assert b'Content-Disposition: form-data; name="_attachment_data"' in request.content
105-
assert mock_route.call_count == 1
106-
assert result.id == "BAT-133"
107-
assert result.name == "Test Batch"
108-
109-
110-
@pytest.mark.asyncio
111-
async def test_async_batches_create_with_data(async_batches_service):
112-
batch_data = {"name": "Test Batch"}
113-
with respx.mock:
114-
mock_route = respx.post("https://api.example.com/public/v1/notifications/batches").mock(
115-
return_value=httpx.Response(
116-
status_code=httpx.codes.OK,
117-
json={"id": "BAT-133", "name": "Test Batch"},
118-
)
119-
)
120-
files = {"attachment": ("test.pdf", io.BytesIO(b"PDF content"), "application/pdf")}
121-
122-
result = await async_batches_service.create(batch_data, files=files)
123-
124-
request = mock_route.calls[0].request
125-
assert b'Content-Disposition: form-data; name="_attachment_data"' in request.content
126-
assert mock_route.call_count == 1
127-
assert result.id == "BAT-133"
128-
assert result.name == "Test Batch"

0 commit comments

Comments
 (0)