Skip to content

Commit 4e72013

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

7 files changed

Lines changed: 199 additions & 29 deletions

File tree

mpt_api_client/resources/catalog/mixins.py

Lines changed: 11 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,13 @@ 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+
class AsyncMediaMixin[Model](
232+
AsyncCreateFileMixin[Model],
233+
AsyncDownloadFileMixin[Model],
234+
AsyncPublishableMixin[Model],
235+
):
236+
"""Media mixin."""
237+
238+
_upload_file_key = "file"
239+
_upload_data_key = "media"

mpt_api_client/resources/catalog/products_media.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
)
1313
from mpt_api_client.models import Model, ResourceData
1414
from mpt_api_client.resources.catalog.mixins import (
15+
AsyncMediaMixin,
1516
AsyncPublishableMixin,
1617
MediaMixin,
1718
)
@@ -40,30 +41,10 @@ class MediaService(
4041

4142

4243
class AsyncMediaService(
43-
AsyncFilesOperationsMixin[Media],
44-
AsyncPublishableMixin[Media],
44+
AsyncMediaMixin[Media],
4545
AsyncModifiableResourceMixin[Media],
4646
AsyncCollectionMixin[Media],
4747
AsyncService[Media],
4848
MediaServiceConfig,
4949
):
5050
"""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: 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+
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(async_mpt_vendor, async_mpt_ops, created_media_from_file_async):
56+
await async_mpt_vendor.catalog.products.media(created_media_from_file_async.product.id).review(created_media_from_file_async.id)
57+
await async_mpt_ops.catalog.products.media(created_media_from_file_async.product.id).publish(created_media_from_file_async.id)
58+
await async_mpt_vendor.catalog.products.media(created_media_from_file_async.product.id).unpublish(
59+
created_media_from_file_async.id
60+
)
61+
62+
async def test_delete_media_async(async_vendor_media_service, created_media_from_file_async):
63+
await async_vendor_media_service.delete(created_media_from_file_async.id)
64+
with pytest.raises(MPTAPIError):
65+
await async_vendor_media_service.get(created_media_from_file_async.id)
66+
67+
68+
async def test_get_media_async(async_vendor_media_service, created_media_from_file_async):
69+
media = await async_vendor_media_service.get(created_media_from_file_async.id)
70+
assert media.id == created_media_from_file_async.id
71+
72+
73+
async def test_download_media_async(async_vendor_media_service, created_media_from_file_async):
74+
file_response = await async_vendor_media_service.download(created_media_from_file_async.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_async(async_vendor_media_service):
80+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
81+
await async_vendor_media_service.get("INVALID-ID")
82+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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+
@pytest.fixture
23+
def created_media_from_url(logger, vendor_media_service, media_data, jpg_url):
24+
media_data["url"] = jpg_url
25+
media = vendor_media_service.create(media_data)
26+
yield media
27+
try:
28+
vendor_media_service.delete(media.id)
29+
except MPTAPIError as error:
30+
print(f"TEARDOWN - Unable to delete media {media.id}: {error.title}")
31+
32+
33+
def test_create_media(created_media_from_file, media_data):
34+
assert created_media_from_file.name == media_data["name"]
35+
assert created_media_from_file.description == media_data["description"]
36+
37+
38+
def test_create_media_from_url(created_media_from_file, media_data):
39+
assert created_media_from_file.name == media_data["name"]
40+
assert created_media_from_file.description == media_data["description"]
41+
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(created_media_from_file.id)
52+
mpt_ops.catalog.products.media(created_media_from_file.product.id).publish(created_media_from_file.id)
53+
mpt_vendor.catalog.products.media(created_media_from_file.product.id).unpublish(
54+
created_media_from_file.id
55+
)
56+
57+
def test_delete_media(vendor_media_service, created_media_from_file):
58+
vendor_media_service.delete(created_media_from_file.id)
59+
with pytest.raises(MPTAPIError):
60+
vendor_media_service.get(created_media_from_file.id)
61+
62+
63+
def test_get_media(vendor_media_service, created_media_from_file):
64+
media = vendor_media_service.get(created_media_from_file.id)
65+
assert media.id == created_media_from_file.id
66+
67+
68+
def test_download_media(vendor_media_service, created_media_from_file):
69+
file_response = vendor_media_service.download(created_media_from_file.id)
70+
assert file_response.file_contents is not None
71+
assert file_response.filename == "logo.png"
72+
73+
74+
async def test_get_not_found_media(vendor_media_service):
75+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
76+
await vendor_media_service.get("INVALID-ID")

tests/e2e/conftest.py

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

82+
@pytest.fixture
83+
def jpg_url():
84+
return "https://sample-files.com/downloads/images/jpg/color_test_800x600_118kb.jpg"
8285

8386
@pytest.fixture
8487
def e2e_config(project_root_path):

tests/unit/http/test_mixins.py

Lines changed: 6 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+
file = ("test.jpg", io.BytesIO(b"Image content"), "image/jpeg")
239+
new_media = await async_media_service.create({"name": "Product image"}, file=file)
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,12 @@ 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({}, file=("test.jpg", io.BytesIO(b"Image content"), "image/jpeg"))
270269

271270
request: httpx.Request = mock_route.calls[0].request
272271

273272
assert (
274-
b'Content-Disposition: form-data; name="media"; filename="test.jpg"\r\n'
273+
b'Content-Disposition: form-data; name="file"; filename="test.jpg"\r\n'
275274
b"Content-Type: image/jpeg\r\n\r\n"
276275
b"Image content\r\n" in request.content
277276
)

0 commit comments

Comments
 (0)