Skip to content

Commit 650a448

Browse files
author
Robert Segal
committed
Added Accounts account by id users endpoints e2e tests
1 parent 8994da6 commit 650a448

File tree

9 files changed

+615
-5
lines changed

9 files changed

+615
-5
lines changed

e2e_config.test.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"accounts.module.id": "MOD-1756",
1010
"accounts.module.name": "Access Management",
1111
"accounts.seller.id": "SEL-7310-3075",
12+
"accounts.user.id": "USR-9673-3314",
1213
"accounts.user_group.id": "UGR-6822-0561",
1314
"catalog.product.item.id": "ITM-7255-3950-0751",
1415
"catalog.product.document.id": "PDC-7255-3950-0001",

mpt_api_client/http/mixins.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,24 @@ def update(self, resource_id: str, resource_data: ResourceData) -> Model:
5656
return self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
5757

5858

59+
class UpdateWithNoUpdateIdMixin[Model]:
60+
"""Update resource mixin without resource ID."""
61+
62+
def update(self, resource_data: ResourceData) -> Model:
63+
"""Update a resource using `PUT /endpoint`.
64+
65+
Args:
66+
resource_data: Resource data.
67+
68+
Returns:
69+
Resource object.
70+
71+
"""
72+
response = self.http_client.request("put", self.path, json=resource_data) # type: ignore[attr-defined]
73+
74+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
75+
76+
5977
class DownloadFileMixin[Model]:
6078
"""Download file mixin."""
6179

@@ -228,6 +246,24 @@ async def update(self, resource_id: str, resource_data: ResourceData) -> Model:
228246
return await self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
229247

230248

249+
class AsyncUpdateWithNoUpdateIdMixin[Model]:
250+
"""Update resource mixin without resource ID."""
251+
252+
async def update(self, resource_data: ResourceData) -> Model:
253+
"""Update a resource using `PUT /endpoint`.
254+
255+
Args:
256+
resource_data: Resource data.
257+
258+
Returns:
259+
Resource object.
260+
261+
"""
262+
response = await self.http_client.request("put", self.path, json=resource_data) # type: ignore[attr-defined]
263+
264+
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
265+
266+
231267
class AsyncDownloadFileMixin[Model]:
232268
"""Download file mixin."""
233269

@@ -614,6 +650,18 @@ class AsyncModifiableResourceMixin[Model](
614650
"""Editable resource mixin allows to read and update a resource resources."""
615651

616652

653+
class ModifiableResourceWithNoUpdateIdMixin[Model](
654+
GetMixin[Model], UpdateWithNoUpdateIdMixin[Model], DeleteMixin
655+
):
656+
"""Editable resource mixin without resource ID to read and update a resource resources."""
657+
658+
659+
class AsyncModifiableResourceWithNoUpdateIdMixin[Model](
660+
AsyncGetMixin[Model], AsyncUpdateWithNoUpdateIdMixin[Model], AsyncDeleteMixin
661+
):
662+
"""Editable resource mixin without resource ID to read and update a resource resources."""
663+
664+
617665
class ManagedResourceMixin[Model](CreateMixin[Model], ModifiableResourceMixin[Model]):
618666
"""Managed resource mixin allows to read, create, update and delete a resource resources."""
619667

@@ -622,3 +670,15 @@ class AsyncManagedResourceMixin[Model](
622670
AsyncCreateMixin[Model], AsyncModifiableResourceMixin[Model]
623671
):
624672
"""Managed resource mixin allows to read, create, update and delete a resource resources."""
673+
674+
675+
class ManagedResourceWithNoUpdateIdMixin[Model](
676+
CreateMixin[Model], ModifiableResourceWithNoUpdateIdMixin[Model]
677+
):
678+
"""Managed resource mixin to read, create, update with no id and delete a resource resources."""
679+
680+
681+
class AsyncManagedResourceWithNoUpdateIdMixin[Model](
682+
AsyncCreateMixin[Model], AsyncModifiableResourceWithNoUpdateIdMixin[Model]
683+
):
684+
"""Managed resource mixin to read, create, update with no id and delete a resource resources."""

mpt_api_client/resources/accounts/accounts_user_groups.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncManagedResourceMixin,
4+
AsyncManagedResourceWithNoUpdateIdMixin,
55
CollectionMixin,
6-
ManagedResourceMixin,
6+
ManagedResourceWithNoUpdateIdMixin,
77
)
88
from mpt_api_client.models import Model
99

@@ -21,7 +21,7 @@ class AccountsUserGroupsServiceConfig:
2121

2222

2323
class AccountsUserGroupsService(
24-
ManagedResourceMixin[AccountsUserGroup],
24+
ManagedResourceWithNoUpdateIdMixin[AccountsUserGroup],
2525
CollectionMixin[AccountsUserGroup],
2626
Service[AccountsUserGroup],
2727
AccountsUserGroupsServiceConfig,
@@ -30,7 +30,7 @@ class AccountsUserGroupsService(
3030

3131

3232
class AsyncAccountsUserGroupsService(
33-
AsyncManagedResourceMixin[AccountsUserGroup],
33+
AsyncManagedResourceWithNoUpdateIdMixin[AccountsUserGroup],
3434
AsyncCollectionMixin[AccountsUserGroup],
3535
AsyncService[AccountsUserGroup],
3636
AccountsUserGroupsServiceConfig,

setup.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ per-file-ignores =
4444
mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214
4545
tests/unit/http/test_async_service.py: WPS204 WPS202
4646
tests/unit/http/test_service.py: WPS204 WPS202
47-
tests/unit/http/test_mixins.py: WPS204 WPS202 WPS210
47+
tests/unit/http/test_mixins.py: WPS204 WPS202 WPS210 WPS235 WPS402
4848
tests/unit/resources/catalog/test_products.py: WPS202 WPS210
4949
tests/unit/resources/accounts/*.py: WPS204 WPS202 WPS210
5050
tests/unit/resources/*/test_mixins.py: WPS118 WPS202 WPS204 WPS235
5151
tests/unit/test_mpt_client.py: WPS235
5252
tests/e2e/accounts/*.py: WPS430 WPS202
53+
tests/e2e/accounts/accounts_users/*.py: WPS204 WPS202
5354
tests/e2e/catalog/*.py: WPS202 WPS421
5455
tests/e2e/catalog/items/*.py: WPS110 WPS202
5556

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import uuid
2+
3+
import pytest
4+
5+
6+
@pytest.fixture
7+
def invalid_user_id():
8+
return "USR-0000-0000"
9+
10+
11+
@pytest.fixture
12+
def account_user_factory(account_id, user_group_id):
13+
def _account_user( # noqa: WPS430
14+
email: str = "e2e_created@dummy.com", # Must be unique in Marketplace
15+
first_name: str = "E2E Created",
16+
last_name: str = "Account User",
17+
):
18+
if not email:
19+
email = f"e2e_{uuid.uuid4()!s}@dummy.com"
20+
21+
return {
22+
"user": {
23+
"firstName": first_name,
24+
"lastName": last_name,
25+
"email": email,
26+
},
27+
"account": {
28+
"id": account_id,
29+
},
30+
"groups": [
31+
{"id": user_group_id},
32+
],
33+
"invitation": {
34+
"status": "Invited",
35+
},
36+
}
37+
38+
return _account_user
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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+
@pytest.fixture
10+
async def created_account_user(async_mpt_vendor, account_user_factory, account_id):
11+
ret_account_user = None
12+
13+
async def _created_account_user( # noqa: WPS430
14+
first_name: str = "E2E Created",
15+
last_name: str = "Account User",
16+
):
17+
nonlocal ret_account_user # noqa: WPS420
18+
account_user_data = account_user_factory(
19+
first_name=first_name,
20+
last_name=last_name,
21+
)
22+
ret_account_user = await async_mpt_vendor.accounts.accounts.users(
23+
account_id=account_id
24+
).create(account_user_data)
25+
return ret_account_user
26+
27+
yield _created_account_user
28+
29+
if ret_account_user:
30+
try:
31+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id).delete(
32+
ret_account_user.id
33+
)
34+
except MPTAPIError:
35+
print( # noqa: WPS421
36+
f"TEARDOWN - Unable to delete account user {ret_account_user.id}",
37+
)
38+
39+
40+
@pytest.fixture
41+
async def created_user_group(async_mpt_ops, user_group_factory):
42+
new_user_group_request_data = user_group_factory()
43+
created_user_group = await async_mpt_ops.accounts.user_groups.create(
44+
new_user_group_request_data
45+
)
46+
47+
yield created_user_group
48+
49+
try:
50+
await async_mpt_ops.accounts.user_groups.delete(created_user_group.id)
51+
except MPTAPIError as error:
52+
print(f"TEARDOWN - Unable to delete user group: {error.title}") # noqa: WPS421
53+
54+
55+
@pytest.fixture
56+
async def created_account_user_group(
57+
async_mpt_vendor, created_account_user, created_user_group, account_id
58+
):
59+
created_account_user_data = await created_account_user()
60+
user_group_data = created_user_group
61+
create_user_group_data = {"id": user_group_data.id}
62+
created_account_user_group = (
63+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id)
64+
.groups(user_id=created_account_user_data.id)
65+
.create(create_user_group_data)
66+
)
67+
yield created_account_user_group
68+
69+
try:
70+
await (
71+
async_mpt_vendor.accounts.accounts.users(account_id=account_id)
72+
.groups(user_id=created_account_user_data.id)
73+
.delete(user_group_data.id)
74+
)
75+
except MPTAPIError as error:
76+
print(f"TEARDOWN - Unable to delete account user group: {error.title}") # noqa: WPS421
77+
78+
79+
async def test_get_account_user_by_id(async_mpt_vendor, user_id, account_id):
80+
account_user = await async_mpt_vendor.accounts.accounts.users(account_id=account_id).get(
81+
user_id
82+
)
83+
assert account_user is not None
84+
85+
86+
async def test_list_account_users(async_mpt_vendor, account_id):
87+
limit = 10
88+
89+
account_users = await async_mpt_vendor.accounts.accounts.users(
90+
account_id=account_id
91+
).fetch_page(limit=limit)
92+
93+
assert len(account_users) > 0
94+
95+
96+
async def test_get_account_user_by_id_not_found(async_mpt_vendor, invalid_user_id, account_id):
97+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
98+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id).get(invalid_user_id)
99+
100+
101+
async def test_filter_account_users(async_mpt_vendor, user_id, account_id):
102+
select_fields = ["-name"]
103+
104+
filtered_account_users = (
105+
async_mpt_vendor.accounts.accounts.users(account_id=account_id)
106+
.filter(RQLQuery(id=user_id))
107+
.select(*select_fields)
108+
)
109+
110+
account_users = [user async for user in filtered_account_users.iterate()]
111+
112+
assert len(account_users) == 1
113+
114+
115+
async def test_create_account_user(created_account_user):
116+
account_user_data = await created_account_user()
117+
assert account_user_data is not None
118+
119+
120+
async def test_delete_account_user(async_mpt_vendor, created_account_user, account_id):
121+
account_user_data = await created_account_user()
122+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id).delete(
123+
account_user_data.id
124+
)
125+
126+
127+
async def test_update_account_user(
128+
async_mpt_vendor,
129+
account_user_factory,
130+
created_account_user,
131+
account_id,
132+
):
133+
account_user_data = await created_account_user()
134+
updated_account_user_data = account_user_factory(
135+
first_name="E2E Updated",
136+
last_name="Account User",
137+
)
138+
updated_account_user = await async_mpt_vendor.accounts.accounts.users(
139+
account_id=account_id
140+
).update(
141+
account_user_data.id,
142+
updated_account_user_data,
143+
)
144+
assert updated_account_user is not None
145+
146+
147+
async def test_account_user_resend_invite(
148+
async_mpt_vendor,
149+
created_account_user,
150+
account_id,
151+
):
152+
account_user_data = await created_account_user()
153+
resend_invite = await async_mpt_vendor.accounts.accounts.users(
154+
account_id=account_id
155+
).resend_invite(account_user_data.id)
156+
assert resend_invite is not None
157+
158+
159+
def test_account_user_group_post(created_account_user_group):
160+
created_account_user_group_data = created_account_user_group
161+
assert created_account_user_group_data is not None
162+
163+
164+
async def test_account_user_group_update(
165+
async_mpt_vendor,
166+
created_account_user,
167+
created_user_group,
168+
account_id,
169+
):
170+
created_account_user_data = await created_account_user()
171+
update_user_group_data = [{"id": created_user_group.id}]
172+
updated_account_user_group = (
173+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id)
174+
.groups(user_id=created_account_user_data.id)
175+
.update(update_user_group_data)
176+
)
177+
assert updated_account_user_group is not None
178+
179+
180+
async def test_account_user_group_delete(
181+
async_mpt_vendor,
182+
created_account_user,
183+
created_user_group,
184+
account_id,
185+
):
186+
created_account_user_data = await created_account_user()
187+
create_user_group_data = {"id": created_user_group.id}
188+
(
189+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id)
190+
.groups(user_id=created_account_user_data.id)
191+
.create(create_user_group_data)
192+
)
193+
(
194+
await async_mpt_vendor.accounts.accounts.users(account_id=account_id)
195+
.groups(user_id=created_account_user_data.id)
196+
.delete(created_user_group.id)
197+
)

0 commit comments

Comments
 (0)