Skip to content

Commit 9976f92

Browse files
authored
[MPT-14865] Added Accounts account by id users endpoints e2e tests (#131)
Added Accounts account by id users endpoints e2e tests https://softwareone.atlassian.net/browse/MPT-14865 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added update capability for account user groups. * **Tests** * Expanded end-to-end async and sync test coverage for account users and groups (create, retrieve, list, filter, update, delete, resend invite, and group associations). * Added unit tests verifying account-user-group update flows. * New test fixtures for UUIDs, user IDs, and account-user creation helpers. * **Chores** * Test configuration updated with a test user identifier. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents 9619a7a + 92ce69a commit 9976f92

File tree

8 files changed

+549
-7
lines changed

8 files changed

+549
-7
lines changed

.github/workflows/pr-build-merge.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
run: docker compose run --service-ports app_test
4242

4343
- name: "Run E2E test"
44-
run: docker compose run --service-ports e2e bash -c "pytest -v -p no:randomly --no-cov --reportportal --rp-launch=$RP_LAUNCH --rp-api-key=$RP_API_KEY --rp-endpoint=$RP_ENDPOINT --junitxml=e2e-report.xml tests/e2e"
44+
run: docker compose run --service-ports e2e bash -c "pytest -v -p no:randomly --no-cov --junitxml=e2e-report.xml tests/e2e"
4545
env:
4646
RP_LAUNCH: github-e2e-test
4747
RP_ENDPOINT: ${{ secrets.RP_ENDPOINT }}

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/resources/accounts/accounts_user_groups.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncManagedResourceMixin,
4+
AsyncCreateMixin,
5+
AsyncDeleteMixin,
6+
AsyncGetMixin,
57
CollectionMixin,
6-
ManagedResourceMixin,
8+
CreateMixin,
9+
DeleteMixin,
10+
GetMixin,
711
)
812
from mpt_api_client.models import Model
13+
from mpt_api_client.models.model import ResourceData
914

1015

1116
class AccountsUserGroup(Model):
@@ -21,18 +26,48 @@ class AccountsUserGroupsServiceConfig:
2126

2227

2328
class AccountsUserGroupsService(
24-
ManagedResourceMixin[AccountsUserGroup],
29+
GetMixin[AccountsUserGroup],
30+
CreateMixin[AccountsUserGroup],
31+
DeleteMixin,
2532
CollectionMixin[AccountsUserGroup],
2633
Service[AccountsUserGroup],
2734
AccountsUserGroupsServiceConfig,
2835
):
2936
"""Account User Groups Service."""
3037

38+
def update(self, resource_data: ResourceData) -> AccountsUserGroup:
39+
"""Update Account User Group.
40+
41+
Args:
42+
resource_data (ResourceData): Resource data to update.
43+
44+
Returns:
45+
AccountsUserGroup: Updated Account User Group.
46+
"""
47+
response = self.http_client.request("put", self.path, json=resource_data)
48+
49+
return self._model_class.from_response(response)
50+
3151

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

0 commit comments

Comments
 (0)