Skip to content

Commit d89dc9a

Browse files
committed
MPT-14890 Tests for catalog/product/media
- Add E2E tests - Fix async service for catalog/product/media
1 parent 72dac51 commit d89dc9a

File tree

7 files changed

+216
-36
lines changed

7 files changed

+216
-36
lines changed

mpt_api_client/resources/catalog/mixins.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class MediaMixin[Model](
169169
DownloadFileMixin[Model],
170170
PublishableMixin[Model],
171171
):
172-
"""Document mixin."""
172+
"""Media mixin."""
173173

174174
_upload_file_key = "file"
175175
_upload_data_key = "media"
@@ -227,3 +227,14 @@ async def deactivate(
227227
return await self._resource_action( # type: ignore[attr-defined, no-any-return]
228228
resource_id, "POST", "deactivate", json=resource_data
229229
)
230+
231+
232+
class AsyncMediaMixin[Model](
233+
AsyncCreateFileMixin[Model],
234+
AsyncDownloadFileMixin[Model],
235+
AsyncPublishableMixin[Model],
236+
):
237+
"""Media mixin."""
238+
239+
_upload_file_key = "file"
240+
_upload_data_key = "media"
Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
1-
from typing import override
2-
3-
from httpx._types import FileTypes
4-
51
from mpt_api_client.http import AsyncService, Service
62
from mpt_api_client.http.mixins import (
73
AsyncCollectionMixin,
8-
AsyncFilesOperationsMixin,
94
AsyncModifiableResourceMixin,
105
CollectionMixin,
116
ModifiableResourceMixin,
127
)
13-
from mpt_api_client.models import Model, ResourceData
8+
from mpt_api_client.models import Model
149
from mpt_api_client.resources.catalog.mixins import (
15-
AsyncPublishableMixin,
10+
AsyncMediaMixin,
1611
MediaMixin,
1712
)
1813

@@ -40,30 +35,10 @@ class MediaService(
4035

4136

4237
class AsyncMediaService(
43-
AsyncFilesOperationsMixin[Media],
44-
AsyncPublishableMixin[Media],
38+
AsyncMediaMixin[Media],
4539
AsyncModifiableResourceMixin[Media],
4640
AsyncCollectionMixin[Media],
4741
AsyncService[Media],
4842
MediaServiceConfig,
4943
):
5044
"""Media service."""
51-
52-
@override
53-
async def create(
54-
self,
55-
resource_data: ResourceData | None = None,
56-
files: dict[str, FileTypes] | None = None,
57-
data_key: str = "_media_data",
58-
) -> Media:
59-
"""Create Media resource.
60-
61-
Args:
62-
resource_data: Resource data.
63-
files: Files data.
64-
data_key: Key to use for the JSON data in the multipart form.
65-
66-
Returns:
67-
Media resource.
68-
"""
69-
return await super().create(resource_data=resource_data, files=files, data_key=data_key)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import pytest
2+
3+
4+
@pytest.fixture
5+
def media_data():
6+
return {
7+
"name": "e2e test media - please delete",
8+
"description": "E2E test media for automated testing",
9+
"displayOrder": 1,
10+
"type": "Image",
11+
"mediatype": "Image",
12+
"url": "",
13+
"language": "en-gb",
14+
}
15+
16+
17+
@pytest.fixture
18+
def test_media_file(logo_fd):
19+
return logo_fd
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import pytest
2+
3+
from mpt_api_client.exceptions import MPTAPIError
4+
5+
pytestmark = [pytest.mark.flaky, pytest.mark.asyncio]
6+
7+
8+
@pytest.fixture
9+
def async_media_service(async_mpt_vendor, product_id):
10+
return async_mpt_vendor.catalog.products.media(product_id)
11+
12+
13+
@pytest.fixture
14+
def async_vendor_media_service(async_mpt_vendor, product_id):
15+
return async_mpt_vendor.catalog.products.media(product_id)
16+
17+
18+
@pytest.fixture
19+
async def created_media_from_file_async(logger, async_media_service, media_data, test_media_file):
20+
media = await async_media_service.create(media_data, test_media_file)
21+
yield media
22+
try:
23+
await async_media_service.delete(media.id)
24+
except MPTAPIError as error:
25+
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}")
26+
27+
28+
@pytest.fixture
29+
async def created_media_from_url_async(logger, async_media_service, media_data, jpg_url):
30+
media_data["url"] = jpg_url
31+
media = await async_media_service.create(media_data)
32+
yield media
33+
try:
34+
await async_media_service.delete(media.id)
35+
except MPTAPIError as error:
36+
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}")
37+
38+
39+
def test_create_media_async(created_media_from_file_async, media_data):
40+
assert created_media_from_file_async.name == media_data["name"]
41+
assert created_media_from_file_async.description == media_data["description"]
42+
43+
44+
def test_create_media_async_from_url(created_media_from_file_async, media_data):
45+
assert created_media_from_file_async.name == media_data["name"]
46+
assert created_media_from_file_async.description == media_data["description"]
47+
48+
49+
async def test_update_media_async(async_media_service, created_media_from_file_async):
50+
update_data = {"name": "Updated e2e test media - please delete"}
51+
media = await async_media_service.update(created_media_from_file_async.id, update_data)
52+
assert media.name == update_data["name"]
53+
54+
55+
async def test_media_lifecycle_async(
56+
async_mpt_vendor, async_mpt_ops, created_media_from_file_async
57+
):
58+
await async_mpt_vendor.catalog.products.media(created_media_from_file_async.product.id).review(
59+
created_media_from_file_async.id
60+
)
61+
await async_mpt_ops.catalog.products.media(created_media_from_file_async.product.id).publish(
62+
created_media_from_file_async.id
63+
)
64+
await async_mpt_vendor.catalog.products.media(
65+
created_media_from_file_async.product.id
66+
).unpublish(created_media_from_file_async.id)
67+
68+
69+
async def test_delete_media_async(async_vendor_media_service, created_media_from_file_async):
70+
await async_vendor_media_service.delete(created_media_from_file_async.id)
71+
with pytest.raises(MPTAPIError):
72+
await async_vendor_media_service.get(created_media_from_file_async.id)
73+
74+
75+
async def test_get_media_async(async_vendor_media_service, created_media_from_file_async):
76+
media = await async_vendor_media_service.get(created_media_from_file_async.id)
77+
assert media.id == created_media_from_file_async.id
78+
79+
80+
async def test_download_media_async(async_vendor_media_service, created_media_from_file_async):
81+
file_response = await async_vendor_media_service.download(created_media_from_file_async.id)
82+
assert file_response.file_contents is not None
83+
assert file_response.filename == "logo.png"
84+
85+
86+
async def test_get_not_found_media_async(async_vendor_media_service):
87+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
88+
await async_vendor_media_service.get("INVALID-ID")
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import pytest
2+
3+
from mpt_api_client.exceptions import MPTAPIError
4+
5+
pytestmark = [pytest.mark.flaky]
6+
7+
8+
@pytest.fixture
9+
def vendor_media_service(mpt_vendor, product_id):
10+
return mpt_vendor.catalog.products.media(product_id)
11+
12+
13+
@pytest.fixture
14+
def created_media_from_file(logger, vendor_media_service, media_data, test_media_file):
15+
media = vendor_media_service.create(media_data, test_media_file)
16+
yield media
17+
try:
18+
vendor_media_service.delete(media.id)
19+
except MPTAPIError as error:
20+
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}")
21+
22+
23+
@pytest.fixture
24+
def created_media_from_url(logger, vendor_media_service, media_data, jpg_url):
25+
media_data["url"] = jpg_url
26+
media = vendor_media_service.create(media_data)
27+
yield media
28+
try:
29+
vendor_media_service.delete(media.id)
30+
except MPTAPIError as error:
31+
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}")
32+
33+
34+
def test_create_media(created_media_from_file, media_data):
35+
assert created_media_from_file.name == media_data["name"]
36+
assert created_media_from_file.description == media_data["description"]
37+
38+
39+
def test_create_media_from_url(created_media_from_file, media_data):
40+
assert created_media_from_file.name == media_data["name"]
41+
assert created_media_from_file.description == media_data["description"]
42+
43+
44+
def test_update_media(vendor_media_service, created_media_from_file):
45+
update_data = {"name": "Updated e2e test media - please delete"}
46+
media = vendor_media_service.update(created_media_from_file.id, update_data)
47+
assert media.name == update_data["name"]
48+
49+
50+
def test_media_lifecycle(mpt_vendor, mpt_ops, created_media_from_file):
51+
mpt_vendor.catalog.products.media(created_media_from_file.product.id).review(
52+
created_media_from_file.id
53+
)
54+
mpt_ops.catalog.products.media(created_media_from_file.product.id).publish(
55+
created_media_from_file.id
56+
)
57+
mpt_vendor.catalog.products.media(created_media_from_file.product.id).unpublish(
58+
created_media_from_file.id
59+
)
60+
61+
62+
def test_delete_media(vendor_media_service, created_media_from_file):
63+
vendor_media_service.delete(created_media_from_file.id)
64+
with pytest.raises(MPTAPIError):
65+
vendor_media_service.get(created_media_from_file.id)
66+
67+
68+
def test_get_media(vendor_media_service, created_media_from_file):
69+
media = vendor_media_service.get(created_media_from_file.id)
70+
assert media.id == created_media_from_file.id
71+
72+
73+
def test_download_media(vendor_media_service, created_media_from_file):
74+
file_response = vendor_media_service.download(created_media_from_file.id)
75+
assert file_response.file_contents is not None
76+
assert file_response.filename == "logo.png"
77+
78+
79+
async def test_get_not_found_media(vendor_media_service):
80+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
81+
await vendor_media_service.get("INVALID-ID")

tests/e2e/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ def pdf_url():
8080
return "https://sample-files.com/downloads/documents/pdf/basic-text.pdf"
8181

8282

83+
@pytest.fixture
84+
def jpg_url():
85+
return "https://sample-files.com/downloads/images/jpg/color_test_800x600_118kb.jpg"
86+
87+
8388
@pytest.fixture
8489
def e2e_config(project_root_path):
8590
filename = os.getenv("TEST_CONFIG_FILE", "e2e_config.test.json")

tests/unit/http/test_mixins.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,18 +235,18 @@ async def test_async_file_create_with_data(async_media_service):
235235
json=media_data,
236236
)
237237
)
238-
files = {"media": ("test.jpg", io.BytesIO(b"Image content"), "image/jpeg")}
239-
new_media = await async_media_service.create({"name": "Product image"}, files=files)
238+
media_image = ("test.jpg", io.BytesIO(b"Image content"), "image/jpeg")
239+
new_media = await async_media_service.create({"name": "Product image"}, file=media_image)
240240

241241
request: httpx.Request = mock_route.calls[0].request
242242

243243
assert (
244-
b'Content-Disposition: form-data; name="_media_data"\r\n'
244+
b'Content-Disposition: form-data; name="media"\r\n'
245245
b"Content-Type: application/json\r\n\r\n"
246246
b'{"name":"Product image"}\r\n' in request.content
247247
)
248248
assert (
249-
b'Content-Disposition: form-data; name="media"; filename="test.jpg"\r\n'
249+
b'Content-Disposition: form-data; name="file"; filename="test.jpg"\r\n'
250250
b"Content-Type: image/jpeg\r\n\r\n"
251251
b"Image content\r\n" in request.content
252252
)
@@ -265,13 +265,14 @@ async def test_async_file_create_no_data(async_media_service):
265265
json=media_data,
266266
)
267267
)
268-
files = {"media": ("test.jpg", io.BytesIO(b"Image content"), "image/jpeg")}
269-
new_media = await async_media_service.create(files=files)
268+
new_media = await async_media_service.create(
269+
{}, file=("test.jpg", io.BytesIO(b"Image content"), "image/jpeg")
270+
)
270271

271272
request: httpx.Request = mock_route.calls[0].request
272273

273274
assert (
274-
b'Content-Disposition: form-data; name="media"; filename="test.jpg"\r\n'
275+
b'Content-Disposition: form-data; name="file"; filename="test.jpg"\r\n'
275276
b"Content-Type: image/jpeg\r\n\r\n"
276277
b"Image content\r\n" in request.content
277278
)

0 commit comments

Comments
 (0)