Skip to content

Commit 4db7dbc

Browse files
committed
MPT-14884 Catalog product e2e
1 parent 50d5138 commit 4db7dbc

File tree

12 files changed

+227
-45
lines changed

12 files changed

+227
-45
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,19 @@ jobs:
3333
RP_API_KEY: ${{ secrets.RP_API_KEY }}
3434
MPT_API_BASE_URL: ${{ secrets.MPT_API_BASE_URL }}
3535
MPT_API_TOKEN: ${{ secrets.MPT_API_TOKEN }}
36+
MPT_API_TOKEN_CLIENT: ${{ secrets.MPT_API_TOKEN_CLIENT }}
37+
MPT_API_TOKEN_OPERATIONS: ${{ secrets.MPT_API_TOKEN_OPERATIONS }}
38+
MPT_API_TOKEN_VENDOR: ${{ secrets.MPT_API_TOKEN_VENDOR }}
3639

3740
- name: "Run validation & test"
3841
run: docker compose run --service-ports app_test
3942

4043
- name: "Run E2E test"
41-
run: docker compose run --service-ports app_test bash -c "pytest -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 app_test 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"
4245
env:
4346
RP_LAUNCH: github-e2e-test
4447
RP_ENDPOINT: ${{ secrets.RP_ENDPOINT }}
4548
RP_API_KEY: ${{ secrets.RP_API_KEY }}
46-
MPT_API_BASE_URL: ${{ secrets.MPT_API_BASE_URL }}
47-
MPT_API_TOKEN: ${{ secrets.MPT_API_TOKEN }}
4849

4950

5051
- name: "Run SonarCloud Scan"

e2e_config.test.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"catalog.product.id": "PRD-7255-3950"
3+
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ dev = [
3333
"mypy==1.15.*",
3434
"pre-commit==4.2.*",
3535
"pytest==8.3.*",
36-
"pytest-asyncio==1.1.*",
36+
"pytest-asyncio==1.2.*",
3737
"pytest-cov==6.1.*",
3838
"pytest-deadfixtures==2.2.*",
3939
"pytest-mock==3.14.*",

seed/catalog/product.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async def init_product(
4848
logger.debug("Creating product ...")
4949
with pathlib.Path.open(icon, "rb") as icon_file:
5050
product = await mpt_vendor.catalog.products.create(
51-
{"name": "Test Product", "website": "https://www.example.com"}, icon=icon_file
51+
{"name": "E2E Seeded", "website": "https://www.example.com"}, icon=icon_file
5252
)
5353
context.set_resource(namespace, product)
5454
context[f"{namespace}.id"] = product.id
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pathlib
2+
3+
import pytest
4+
5+
6+
@pytest.fixture
7+
def product_icon():
8+
return pathlib.Path.open(pathlib.Path(__file__).parent / "logo.png", "rb")
9+
10+
11+
@pytest.fixture
12+
def product_data():
13+
return {"name": "Test Product", "website": "https://www.example.com"}

tests/e2e/catalog/product/logo.png

929 KB
Loading
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import pytest
2+
3+
from mpt_api_client import RQLQuery
4+
from mpt_api_client.exceptions import MPTAPIError
5+
6+
7+
@pytest.fixture
8+
async def async_created_product(logger, async_mpt_vendor, product_data, product_icon):
9+
product = await async_mpt_vendor.catalog.products.create(product_data, icon=product_icon)
10+
11+
yield product
12+
13+
try:
14+
await async_mpt_vendor.catalog.products.delete(product.id)
15+
except MPTAPIError as error:
16+
logger.exception("TEARDOWN - Unable to delete product %s: %s", product.id, error.title)
17+
18+
19+
@pytest.mark.flaky
20+
def test_create_product(async_created_product, product_data):
21+
assert async_created_product.name == product_data["name"]
22+
23+
24+
@pytest.mark.flaky
25+
async def test_update_product(async_mpt_vendor, async_created_product):
26+
update_data = {"name": "Updated Product"}
27+
28+
product = await async_mpt_vendor.catalog.products.update(async_created_product.id, update_data)
29+
30+
assert product.name == update_data["name"]
31+
32+
33+
@pytest.mark.skip(reason="Leaves test products in the catalog")
34+
@pytest.mark.flaky
35+
async def test_product_review_and_publish(async_mpt_vendor, async_mpt_ops, async_created_product):
36+
await async_mpt_vendor.catalog.products.review(async_created_product.id)
37+
await async_mpt_ops.catalog.products.publish(async_created_product.id)
38+
39+
40+
@pytest.mark.flaky
41+
async def test_get_product(async_mpt_vendor, product_id, logger):
42+
await async_mpt_vendor.catalog.products.get(product_id)
43+
44+
45+
@pytest.mark.flaky
46+
async def test_product_save_settings(async_mpt_vendor, async_created_product):
47+
await async_mpt_vendor.catalog.products.update_settings(
48+
async_created_product.id, {"itemSelection": True}
49+
)
50+
51+
52+
@pytest.mark.flaky
53+
async def test_filter_and_select_products(async_mpt_vendor, product_id):
54+
select_fields = ["-icon", "-revision", "-settings", "-vendor", "-statistics", "-website"]
55+
56+
filtered_products = (
57+
async_mpt_vendor.catalog.products.filter(RQLQuery(id=product_id))
58+
.filter(RQLQuery(name="E2E Seeded"))
59+
.select(*select_fields)
60+
)
61+
62+
products = [product async for product in filtered_products.iterate()]
63+
assert len(products) == 1
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import pytest
2+
3+
from mpt_api_client import RQLQuery
4+
from mpt_api_client.exceptions import MPTAPIError
5+
6+
7+
@pytest.fixture
8+
def created_product(logger, mpt_vendor, product_data, product_icon):
9+
product = mpt_vendor.catalog.products.create(product_data, icon=product_icon)
10+
11+
yield product
12+
13+
try:
14+
mpt_vendor.catalog.products.delete(product.id)
15+
except MPTAPIError as error:
16+
logger.exception("TEARDOWN - Unable to delete product %s: %s", product.id, error.title)
17+
18+
19+
@pytest.mark.flaky
20+
def test_create_product(created_product, product_data):
21+
assert created_product.name == product_data["name"]
22+
23+
24+
@pytest.mark.flaky
25+
def test_update_product(mpt_vendor, created_product):
26+
update_data = {"name": "Updated Product"}
27+
28+
product = mpt_vendor.catalog.products.update(created_product.id, update_data)
29+
30+
assert product.name == update_data["name"]
31+
32+
33+
@pytest.mark.skip(reason="Leaves test products in the catalog")
34+
@pytest.mark.flaky
35+
def test_product_review_and_publish(mpt_vendor, mpt_ops, created_product):
36+
mpt_vendor.catalog.products.review(created_product.id)
37+
mpt_ops.catalog.products.publish(created_product.id)
38+
39+
40+
@pytest.mark.flaky
41+
def test_get_product(mpt_vendor, product_id):
42+
mpt_vendor.catalog.products.get(product_id)
43+
44+
45+
@pytest.mark.flaky
46+
def test_product_save_settings(mpt_vendor, created_product):
47+
mpt_vendor.catalog.products.update_settings(created_product.id, {"itemSelection": True})
48+
49+
50+
@pytest.mark.flaky
51+
def test_filter_and_select_products(mpt_vendor, product_id):
52+
select_fields = ["-icon", "-revision", "-settings", "-vendor", "-statistics", "-website"]
53+
54+
filtered_products = (
55+
mpt_vendor.catalog.products.filter(RQLQuery(id=product_id))
56+
.filter(RQLQuery(name="E2E Seeded"))
57+
.select(*select_fields)
58+
)
59+
60+
products = list(filtered_products.iterate())
61+
assert len(products) == 1

tests/e2e/conftest.py

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,80 @@
1+
import json
12
import logging
23
import os
4+
import pathlib
35

46
import pytest
57
from reportportal_client import RPLogger
68

7-
from mpt_api_client import MPTClient
9+
from mpt_api_client import AsyncMPTClient, MPTClient
810

911

1012
@pytest.fixture
11-
def api_token():
12-
return os.getenv("MPT_API_TOKEN")
13+
def base_url():
14+
return os.getenv("MPT_API_BASE_URL")
1315

1416

1517
@pytest.fixture
16-
def base_url():
17-
return os.getenv("MPT_API_BASE_URL")
18+
def mpt_vendor(base_url):
19+
return MPTClient.from_config(api_token=os.getenv("MPT_API_TOKEN_VENDOR"), base_url=base_url) # type: ignore
1820

1921

2022
@pytest.fixture
21-
def mpt_client(api_token, base_url):
22-
return MPTClient.from_config(api_token=api_token, base_url=base_url)
23+
def async_mpt_vendor(base_url):
24+
return AsyncMPTClient.from_config(
25+
api_token=os.getenv("MPT_API_TOKEN_VENDOR"), base_url=base_url
26+
) # type: ignore
27+
28+
29+
@pytest.fixture
30+
def mpt_ops(base_url):
31+
return MPTClient.from_config(api_token=os.getenv("MPT_API_TOKEN_OPERATIONS"), base_url=base_url) # type: ignore
32+
2333

34+
@pytest.fixture
35+
def async_mpt_ops(base_url):
36+
return AsyncMPTClient.from_config(
37+
api_token=os.getenv("MPT_API_TOKEN_OPERATIONS"), base_url=base_url
38+
) # type: ignore
39+
40+
41+
@pytest.fixture
42+
def mpt_client(base_url):
43+
return MPTClient.from_config(api_token=os.getenv("MPT_API_TOKEN_CLIENT"), base_url=base_url) # type: ignore
44+
45+
46+
@pytest.fixture
47+
def async_mpt_client(base_url):
48+
return AsyncMPTClient.from_config(
49+
api_token=os.getenv("MPT_API_TOKEN_CLIENT"), base_url=base_url
50+
) # type: ignore
2451

25-
@pytest.fixture(scope="session")
52+
53+
@pytest.fixture
2654
def rp_logger():
2755
logger = logging.getLogger(__name__)
2856
logger.setLevel(logging.DEBUG)
2957
logging.setLoggerClass(RPLogger)
3058
return logger
59+
60+
61+
@pytest.fixture
62+
def logger():
63+
return logging.getLogger("E2E")
64+
65+
66+
@pytest.fixture
67+
def project_root_path():
68+
return pathlib.Path(__file__).parent.parent.parent
69+
70+
71+
@pytest.fixture
72+
def e2e_config(project_root_path):
73+
filename = os.getenv("TEST_CONFIG_FILE", "e2e_config.test.json")
74+
file_path = project_root_path.joinpath(filename)
75+
return json.loads(file_path.read_text())
76+
77+
78+
@pytest.fixture
79+
def product_id(e2e_config):
80+
return e2e_config["catalog.product.id"]

tests/e2e/test_access.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import pytest
2+
3+
from mpt_api_client import MPTClient
4+
from mpt_api_client.exceptions import MPTAPIError
5+
6+
7+
@pytest.mark.flaky
8+
def test_unauthorised(base_url):
9+
client = MPTClient.from_config(api_token="TKN-invalid", base_url=base_url) # noqa: S106
10+
11+
with pytest.raises(MPTAPIError, match=r"401 Unauthorized"):
12+
client.catalog.products.fetch_page()
13+
14+
15+
@pytest.mark.flaky
16+
def test_access(mpt_vendor, product_id):
17+
product = mpt_vendor.catalog.products.get(product_id)
18+
assert product.id == product_id

0 commit comments

Comments
 (0)