Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/pr-build-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@ jobs:
RP_API_KEY: ${{ secrets.RP_API_KEY }}
MPT_API_BASE_URL: ${{ secrets.MPT_API_BASE_URL }}
MPT_API_TOKEN: ${{ secrets.MPT_API_TOKEN }}
MPT_API_TOKEN_CLIENT: ${{ secrets.MPT_API_TOKEN_CLIENT }}
MPT_API_TOKEN_OPERATIONS: ${{ secrets.MPT_API_TOKEN_OPERATIONS }}
MPT_API_TOKEN_VENDOR: ${{ secrets.MPT_API_TOKEN_VENDOR }}

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

- name: "Run E2E test"
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"
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"
env:
RP_LAUNCH: github-e2e-test
RP_ENDPOINT: ${{ secrets.RP_ENDPOINT }}
RP_API_KEY: ${{ secrets.RP_API_KEY }}
MPT_API_BASE_URL: ${{ secrets.MPT_API_BASE_URL }}
MPT_API_TOKEN: ${{ secrets.MPT_API_TOKEN }}


- name: "Run SonarCloud Scan"
Expand Down
3 changes: 3 additions & 0 deletions e2e_config.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"catalog.product.id": "PRD-7255-3950"
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dev = [
"mypy==1.15.*",
"pre-commit==4.2.*",
"pytest==8.3.*",
"pytest-asyncio==1.1.*",
"pytest-asyncio==1.2.*",
"pytest-cov==6.1.*",
"pytest-deadfixtures==2.2.*",
"pytest-mock==3.14.*",
Expand Down
2 changes: 1 addition & 1 deletion seed/catalog/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ async def init_product(
logger.debug("Creating product ...")
with pathlib.Path.open(icon, "rb") as icon_file:
product = await mpt_vendor.catalog.products.create(
{"name": "Test Product", "website": "https://www.example.com"}, icon=icon_file
{"name": "E2E Seeded", "website": "https://www.example.com"}, icon=icon_file
)
context.set_resource(namespace, product)
context[f"{namespace}.id"] = product.id
Expand Down
13 changes: 13 additions & 0 deletions tests/e2e/catalog/product/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import pathlib

import pytest


@pytest.fixture
def product_icon():
return pathlib.Path.open(pathlib.Path(__file__).parent / "logo.png", "rb")


@pytest.fixture
def product_data():
return {"name": "Test Product", "website": "https://www.example.com"}
Binary file added tests/e2e/catalog/product/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions tests/e2e/catalog/product/test_async_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import pytest

from mpt_api_client import RQLQuery
from mpt_api_client.exceptions import MPTAPIError


@pytest.fixture
async def async_created_product(logger, async_mpt_vendor, product_data, product_icon):
product = await async_mpt_vendor.catalog.products.create(product_data, icon=product_icon)

yield product

try:
await async_mpt_vendor.catalog.products.delete(product.id)
except MPTAPIError as error:
logger.exception("TEARDOWN - Unable to delete product %s: %s", product.id, error.title)


@pytest.mark.flaky
def test_create_product(async_created_product, product_data):
assert async_created_product.name == product_data["name"]


@pytest.mark.flaky
async def test_update_product(async_mpt_vendor, async_created_product):
update_data = {"name": "Updated Product"}

product = await async_mpt_vendor.catalog.products.update(async_created_product.id, update_data)

assert product.name == update_data["name"]


@pytest.mark.skip(reason="Leaves test products in the catalog")
@pytest.mark.flaky
async def test_product_review_and_publish(async_mpt_vendor, async_mpt_ops, async_created_product):
await async_mpt_vendor.catalog.products.review(async_created_product.id)
await async_mpt_ops.catalog.products.publish(async_created_product.id)


@pytest.mark.flaky
async def test_get_product(async_mpt_vendor, product_id, logger):
await async_mpt_vendor.catalog.products.get(product_id)


@pytest.mark.flaky
async def test_product_save_settings(async_mpt_vendor, async_created_product):
await async_mpt_vendor.catalog.products.update_settings(
async_created_product.id, {"itemSelection": True}
)


@pytest.mark.flaky
async def test_filter_and_select_products(async_mpt_vendor, product_id):
select_fields = ["-icon", "-revision", "-settings", "-vendor", "-statistics", "-website"]

filtered_products = (
async_mpt_vendor.catalog.products.filter(RQLQuery(id=product_id))
.filter(RQLQuery(name="E2E Seeded"))
.select(*select_fields)
)

products = [product async for product in filtered_products.iterate()]
assert len(products) == 1
61 changes: 61 additions & 0 deletions tests/e2e/catalog/product/test_sync_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import pytest

from mpt_api_client import RQLQuery
from mpt_api_client.exceptions import MPTAPIError


@pytest.fixture
def created_product(logger, mpt_vendor, product_data, product_icon):
product = mpt_vendor.catalog.products.create(product_data, icon=product_icon)

yield product

try:
mpt_vendor.catalog.products.delete(product.id)
except MPTAPIError as error:
logger.exception("TEARDOWN - Unable to delete product %s: %s", product.id, error.title)


@pytest.mark.flaky
def test_create_product(created_product, product_data):
assert created_product.name == product_data["name"]


@pytest.mark.flaky
def test_update_product(mpt_vendor, created_product):
update_data = {"name": "Updated Product"}

product = mpt_vendor.catalog.products.update(created_product.id, update_data)

assert product.name == update_data["name"]


@pytest.mark.skip(reason="Leaves test products in the catalog")
@pytest.mark.flaky
def test_product_review_and_publish(mpt_vendor, mpt_ops, created_product):
mpt_vendor.catalog.products.review(created_product.id)
mpt_ops.catalog.products.publish(created_product.id)


@pytest.mark.flaky
def test_get_product(mpt_vendor, product_id):
mpt_vendor.catalog.products.get(product_id)


@pytest.mark.flaky
def test_product_save_settings(mpt_vendor, created_product):
mpt_vendor.catalog.products.update_settings(created_product.id, {"itemSelection": True})


@pytest.mark.flaky
def test_filter_and_select_products(mpt_vendor, product_id):
select_fields = ["-icon", "-revision", "-settings", "-vendor", "-statistics", "-website"]

filtered_products = (
mpt_vendor.catalog.products.filter(RQLQuery(id=product_id))
.filter(RQLQuery(name="E2E Seeded"))
.select(*select_fields)
)

products = list(filtered_products.iterate())
assert len(products) == 1
66 changes: 58 additions & 8 deletions tests/e2e/conftest.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,80 @@
import json
import logging
import os
import pathlib

import pytest
from reportportal_client import RPLogger

from mpt_api_client import MPTClient
from mpt_api_client import AsyncMPTClient, MPTClient


@pytest.fixture
def api_token():
return os.getenv("MPT_API_TOKEN")
def base_url():
return os.getenv("MPT_API_BASE_URL")


@pytest.fixture
def base_url():
return os.getenv("MPT_API_BASE_URL")
def mpt_vendor(base_url):
return MPTClient.from_config(api_token=os.getenv("MPT_API_TOKEN_VENDOR"), base_url=base_url) # type: ignore


@pytest.fixture
def mpt_client(api_token, base_url):
return MPTClient.from_config(api_token=api_token, base_url=base_url)
def async_mpt_vendor(base_url):
return AsyncMPTClient.from_config(
api_token=os.getenv("MPT_API_TOKEN_VENDOR"), base_url=base_url
) # type: ignore


@pytest.fixture
def mpt_ops(base_url):
return MPTClient.from_config(api_token=os.getenv("MPT_API_TOKEN_OPERATIONS"), base_url=base_url) # type: ignore


@pytest.fixture
def async_mpt_ops(base_url):
return AsyncMPTClient.from_config(
api_token=os.getenv("MPT_API_TOKEN_OPERATIONS"), base_url=base_url
) # type: ignore


@pytest.fixture
def mpt_client(base_url):
return MPTClient.from_config(api_token=os.getenv("MPT_API_TOKEN_CLIENT"), base_url=base_url) # type: ignore


@pytest.fixture
def async_mpt_client(base_url):
return AsyncMPTClient.from_config(
api_token=os.getenv("MPT_API_TOKEN_CLIENT"), base_url=base_url
) # type: ignore

@pytest.fixture(scope="session")

@pytest.fixture
def rp_logger():
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.setLoggerClass(RPLogger)
return logger


@pytest.fixture
def logger():
return logging.getLogger("E2E")


@pytest.fixture
def project_root_path():
return pathlib.Path(__file__).parent.parent.parent


@pytest.fixture
def e2e_config(project_root_path):
filename = os.getenv("TEST_CONFIG_FILE", "e2e_config.test.json")
file_path = project_root_path.joinpath(filename)
return json.loads(file_path.read_text())


@pytest.fixture
def product_id(e2e_config):
return e2e_config["catalog.product.id"]
18 changes: 18 additions & 0 deletions tests/e2e/test_access.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest

from mpt_api_client import MPTClient
from mpt_api_client.exceptions import MPTAPIError


@pytest.mark.flaky
def test_unauthorised(base_url):
client = MPTClient.from_config(api_token="TKN-invalid", base_url=base_url) # noqa: S106

with pytest.raises(MPTAPIError, match=r"401 Unauthorized"):
client.catalog.products.fetch_page()


@pytest.mark.flaky
def test_access(mpt_vendor, product_id):
product = mpt_vendor.catalog.products.get(product_id)
assert product.id == product_id
28 changes: 0 additions & 28 deletions tests/e2e/test_e2e.py

This file was deleted.

9 changes: 5 additions & 4 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.