Skip to content

Commit c4bd271

Browse files
committed
MPT-14767 E2E seeding proof of concept
- Added seeding proof of concept - Fix create product request
1 parent 419d0d5 commit c4bd271

13 files changed

Lines changed: 196 additions & 10 deletions

File tree

mpt_api_client/http/client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ def __init__(
4949
base_headers = {
5050
"User-Agent": "swo-marketplace-client/1.0",
5151
"Authorization": f"Bearer {api_token}",
52-
"content-type": "application/json",
5352
}
5453
self.httpx_client = Client(
5554
base_url=base_url,

mpt_api_client/http/mixins.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ def create(
8686
_json_to_file_payload(resource_data),
8787
"application/json",
8888
)
89-
9089
response = self.http_client.request("post", self.path, files=files) # type: ignore[attr-defined]
9190

9291
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]

mpt_api_client/resources/catalog/products.py

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import json
2+
13
from mpt_api_client.http import AsyncService, Service
24
from mpt_api_client.http.mixins import (
35
AsyncCollectionMixin,
4-
AsyncManagedResourceMixin,
6+
AsyncModifiableResourceMixin,
57
CollectionMixin,
6-
ManagedResourceMixin,
8+
ModifiableResourceMixin,
79
)
10+
from mpt_api_client.http.types import FileTypes
811
from mpt_api_client.models import Model, ResourceData
912
from mpt_api_client.resources.catalog.mixins import (
1013
AsyncPublishableMixin,
@@ -54,13 +57,38 @@ class ProductsServiceConfig:
5457

5558
class ProductsService(
5659
PublishableMixin[Product],
57-
ManagedResourceMixin[Product],
60+
ModifiableResourceMixin[Product],
5861
CollectionMixin[Product],
5962
Service[Product],
6063
ProductsServiceConfig,
6164
):
6265
"""Products service."""
6366

67+
def create(
68+
self,
69+
resource_data: ResourceData,
70+
icon: FileTypes,
71+
) -> Model:
72+
"""Create product with icon.
73+
74+
Args:
75+
resource_data: Product data.
76+
icon: Icon image in jpg, png, GIF, etc.
77+
78+
Returns:
79+
Created resource.
80+
"""
81+
files: dict[str, FileTypes] = {}
82+
files["product"] = (
83+
None,
84+
json.dumps(resource_data),
85+
"application/json",
86+
)
87+
files["icon"] = icon
88+
response = self.http_client.request("post", self.path, files=files)
89+
90+
return self._model_class.from_response(response)
91+
6492
def item_groups(self, product_id: str) -> ItemGroupsService:
6593
"""Return item_groups service."""
6694
return ItemGroupsService(
@@ -108,13 +136,37 @@ def update_settings(self, product_id: str, settings: ResourceData) -> Product:
108136

109137
class AsyncProductsService(
110138
AsyncPublishableMixin[Product],
111-
AsyncManagedResourceMixin[Product],
139+
AsyncModifiableResourceMixin[Product],
112140
AsyncCollectionMixin[Product],
113141
AsyncService[Product],
114142
ProductsServiceConfig,
115143
):
116144
"""Products service."""
117145

146+
async def create(
147+
self,
148+
resource_data: ResourceData,
149+
icon: FileTypes,
150+
) -> Model:
151+
"""Create product with icon.
152+
153+
Args:
154+
resource_data: Product data.
155+
icon: Icon image in jpg, png, GIF, etc.
156+
157+
Returns:
158+
Created resource.
159+
"""
160+
files: dict[str, FileTypes] = {}
161+
files["product"] = (
162+
None,
163+
json.dumps(resource_data),
164+
"application/json",
165+
)
166+
files["icon"] = icon
167+
response = await self.http_client.request("post", self.path, files=files)
168+
return self._model_class.from_response(response)
169+
118170
def item_groups(self, product_id: str) -> AsyncItemGroupsService:
119171
"""Return item_groups service."""
120172
return AsyncItemGroupsService(

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ build-backend = "hatchling.build"
6060
[tool.pytest.ini_options]
6161
testpaths = "tests"
6262
pythonpath = "."
63-
addopts = "--cov=mpt_api_client --cov-report=term-missing --cov-report=html --cov-report=xml --import-mode=importlib"
63+
addopts = "--cov=mpt_api_client --cov-report=term-missing --cov-report=html --cov-report=xml --import-mode=importlib -m 'not dataseed'"
6464
log_cli = false
6565
asyncio_mode = "auto"
6666
asyncio_default_fixture_loop_scope = "function"
@@ -69,6 +69,9 @@ filterwarnings = [
6969
"ignore:pkg_resources is deprecated as an API:DeprecationWarning",
7070
]
7171
rp_project = "mpt-api-python-client"
72+
markers = [
73+
"dataseed: Creates the required data in the API for E2E tests",
74+
]
7275

7376
[tool.coverage.run]
7477
branch = true

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ per-file-ignores =
4848
tests/unit/resources/accounts/test_users.py: WPS204 WPS202 WPS210
4949
tests/unit/test_mpt_client.py: WPS235
5050

51-
tests/unit/*:
51+
tests/*:
5252
# Allow magic strings.
5353
WPS432
5454
# Found too many modules members.

tests/seed/__init__.py

Whitespace-only changes.
84 KB
Loading

tests/seed/catalog/__init__.py

Whitespace-only changes.

tests/seed/catalog/test_product.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import datetime as dt
2+
import json
3+
import pathlib
4+
import uuid
5+
6+
import httpx
7+
import pytest
8+
9+
pytestmark = pytest.mark.dataseed
10+
11+
12+
@pytest.fixture
13+
def icon_path():
14+
return pathlib.Path(__file__).parent / "FIL-9920-4780-9379.png"
15+
16+
17+
@pytest.fixture
18+
def product_id(mpt_vendor, mpt_operations, icon_path):
19+
product_data = {
20+
"name": "Microsoft 365 online services for commercial",
21+
"shortDescription": "Microsoft 365 and Office 365 [...]",
22+
"longDescription": "Microsoft 365 and Office 365 [...long]",
23+
"website": "https://www.microsoft.com",
24+
}
25+
26+
with pathlib.Path.open(icon_path, "rb") as icon_file:
27+
new_product = mpt_vendor.catalog.products.create(
28+
product_data,
29+
icon=icon_file,
30+
)
31+
assert new_product.meta.response.status_code == httpx.Response.raise_for_status()
32+
33+
return new_product.id
34+
35+
36+
@pytest.fixture
37+
def product_data(product_id):
38+
return {
39+
"product_id": product_id,
40+
}
41+
42+
43+
@pytest.fixture
44+
def product_json_path():
45+
date = dt.datetime.now(tz=dt.UTC).strftime("%Y-%m-%d")
46+
test_run_id = str(uuid.uuid4())[:8]
47+
return pathlib.Path(__file__).parent / f"../../../test-data-{date}-{test_run_id}.json"
48+
49+
50+
def test_dataseed_marker(request):
51+
marker = request.node.get_closest_marker("dataseed")
52+
assert marker is not None
53+
54+
55+
def test_save(product_json_path, product_data, logger):
56+
catalog_data_json = json.dumps(product_data, indent=2)
57+
pathlib.Path(product_json_path).write_text(catalog_data_json, encoding="utf-8")
58+
logger.info("Saved commerce data to `%s`", product_json_path)
59+
logger.debug(catalog_data_json)

tests/seed/conftest.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
3+
import pytest
4+
5+
from mpt_api_client import MPTClient
6+
7+
8+
@pytest.fixture
9+
def operations_token():
10+
return os.getenv("MPT_API_TOKEN_OPERATIONS")
11+
12+
13+
@pytest.fixture
14+
def base_url():
15+
return os.getenv("MPT_API_BASE_URL")
16+
17+
18+
@pytest.fixture
19+
def vendor_token():
20+
return os.getenv("MPT_API_TOKEN_VENDOR")
21+
22+
23+
@pytest.fixture
24+
def mpt_vendor(vendor_token, base_url):
25+
return MPTClient.from_config(api_token=vendor_token, base_url=base_url)
26+
27+
28+
@pytest.fixture
29+
def mpt_operations(operations_token, base_url):
30+
return MPTClient.from_config(api_token=operations_token, base_url=base_url)

0 commit comments

Comments
 (0)