elytra_client/tests/test_client.py
claudi aa7db1a3ab Add mixins for various Lobster REST API client functionalities
- Implement JobsMixin for job-related operations including job overview, execution, and control.
- Implement MediaMixin for media management, including creation, updating, and file uploads.
- Implement ProductGroupsMixin for handling product groups, including bulk operations and hierarchy retrieval.
- Implement ProductsMixin for product management, including bulk creation and updates.
- Implement ProtocolsMixin for protocol-related operations, including retrieval by job ID and category.
- Implement TextMixin for managing text entries, including bulk operations.
- Implement TreeGroupsMixin for tree group management, including bulk operations and hierarchy retrieval.
2026-03-24 16:12:58 +01:00

175 lines
5.4 KiB
Python

"""Tests for the Elytra PIM Client with Pydantic validation"""
from unittest.mock import Mock, patch
import pytest
from pydantic import ValidationError
from elytra_client import ElytraClient, SingleNewProductRequestBody, SingleProductResponse
from elytra_client.exceptions import ElytraAuthenticationError, ElytraNotFoundError
@pytest.fixture
def client():
"""Create a test client"""
return ElytraClient(
base_url="https://test.example.com/api/v1",
api_key="test-api-key",
)
def test_client_initialization(client):
"""Test client initialization"""
assert client.base_url == "https://test.example.com/api/v1"
assert client.api_key == "test-api-key"
assert client.timeout == 30
def test_client_context_manager():
"""Test client context manager"""
with ElytraClient(
base_url="https://test.example.com/api/v1",
api_key="test-api-key",
) as client:
assert client is not None
@patch("elytra_client.client.requests.Session.request")
def test_get_products_with_pydantic_validation(mock_request, client):
"""Test get_products with Pydantic validation"""
mock_response = Mock()
mock_response.json.return_value = {
"items": [
{
"id": 1,
"clientId": 231,
"productName": "Product 1",
"treeId": 0,
"created": "2025-04-08T12:00:00Z",
"modified": "2025-04-08T12:00:00Z",
"creatorUserId": 235,
"modifierUserId": 235,
"objectStatus": "original",
"originalId": 0,
"attributes": [],
}
],
"total": 1,
"page": 1,
}
mock_request.return_value = mock_response
result = client.get_products(lang="en", page=1, limit=10)
assert result["total"] == 1
assert len(result["items"]) == 1
# Items should be Pydantic models
assert isinstance(result["items"][0], SingleProductResponse)
assert result["items"][0].productName == "Product 1"
mock_request.assert_called_once()
@patch("elytra_client.client.requests.Session.request")
def test_get_product_returns_pydantic_model(mock_request, client):
"""Test get_product returns Pydantic model"""
mock_response = Mock()
mock_response.json.return_value = {
"id": 123,
"clientId": 231,
"productName": "Test Product",
"treeId": 0,
"created": "2025-04-08T12:00:00Z",
"modified": "2025-04-08T12:00:00Z",
"creatorUserId": 235,
"modifierUserId": 235,
"objectStatus": "original",
"originalId": 0,
"attributes": [],
}
mock_request.return_value = mock_response
result = client.get_product(product_id=123, lang="en")
assert isinstance(result, SingleProductResponse)
assert result.id == 123
assert result.productName == "Test Product"
@patch("elytra_client.client.requests.Session.request")
def test_create_product_with_pydantic(mock_request, client):
"""Test product creation with Pydantic validation"""
mock_response = Mock()
mock_response.json.return_value = {
"id": 999,
"clientId": 231,
"productName": "NEW-PRODUCT-001",
"treeId": 0,
"created": "2025-04-08T12:00:00Z",
"modified": "2025-04-08T12:00:00Z",
"creatorUserId": 235,
"modifierUserId": 235,
"objectStatus": "original",
"originalId": 0,
"attributes": [],
}
mock_request.return_value = mock_response
# Create with Pydantic model
new_product = SingleNewProductRequestBody( # type: ignore[arg-type]
productName="NEW-PRODUCT-001",
parentId=1,
attributeGroupId=10,
)
result = client.create_product(new_product)
assert isinstance(result, SingleProductResponse)
assert result.id == 999
assert result.productName == "NEW-PRODUCT-001"
def test_pydantic_validation_on_creation():
"""Test Pydantic validation on model creation"""
# Valid model
valid_product = SingleNewProductRequestBody( # type: ignore[arg-type]
productName="VALID-PRODUCT",
parentId=1,
attributeGroupId=10,
)
assert valid_product.productName == "VALID-PRODUCT"
# Invalid model - missing required field
with pytest.raises(ValidationError):
SingleNewProductRequestBody( # type: ignore[arg-type]
productName="INVALID-PRODUCT",
# Missing parentId - required
attributeGroupId=10,
)
@patch("elytra_client.client.requests.Session.request")
def test_authentication_error(mock_request, client):
"""Test authentication error handling"""
mock_response = Mock()
mock_response.status_code = 401
mock_response.text = "Unauthorized"
mock_request.return_value.raise_for_status.side_effect = __import__(
"requests"
).exceptions.HTTPError(response=mock_response)
with pytest.raises(ElytraAuthenticationError):
client.get_products()
@patch("elytra_client.client.requests.Session.request")
def test_not_found_error(mock_request, client):
"""Test not found error handling"""
mock_response = Mock()
mock_response.status_code = 404
mock_response.text = "Not Found"
mock_request.return_value.raise_for_status.side_effect = __import__(
"requests"
).exceptions.HTTPError(response=mock_response)
with pytest.raises(ElytraNotFoundError):
client.get_product(product_id=999)