Files
orion/tests/integration/api/v1/test_pagination.py
Samir Boulahtit 238c1ec9b8 refactor: modernize code quality tooling with Ruff
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter)
- Add comprehensive pyproject.toml configuration
- Simplify Makefile code quality targets
- Configure exclusions for venv/.venv in pyproject.toml
- Auto-fix 1,359 linting issues across codebase

Benefits:
- Much faster builds (Ruff is written in Rust)
- Single tool replaces multiple tools
- More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q)
- All configuration centralized in pyproject.toml
- Better import sorting and formatting consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 19:37:38 +01:00

363 lines
13 KiB
Python

# tests/integration/api/v1/test_pagination.py
import pytest
from models.database.marketplace_product import MarketplaceProduct
from models.database.vendor import Vendor
@pytest.mark.integration
@pytest.mark.api
@pytest.mark.database
@pytest.mark.products
class TestPagination:
def test_product_pagination_success(self, client, auth_headers, db):
"""Test pagination for product listing successfully"""
import uuid
unique_suffix = str(uuid.uuid4())[:8]
# Create multiple products
products = []
for i in range(25):
product = MarketplaceProduct(
marketplace_product_id=f"PAGE{i:03d}_{unique_suffix}",
title=f"Pagination Test MarketplaceProduct {i}",
marketplace="PaginationTest",
)
products.append(product)
db.add_all(products)
db.commit()
# Test first page
response = client.get(
"/api/v1/marketplace/product?limit=10&skip=0", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert len(data["products"]) == 10
assert data["total"] >= 25 # At least our test products
assert data["skip"] == 0
assert data["limit"] == 10
# Test second page
response = client.get(
"/api/v1/marketplace/product?limit=10&skip=10", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert len(data["products"]) == 10
assert data["skip"] == 10
# Test last page (should have remaining products)
response = client.get(
"/api/v1/marketplace/product?limit=10&skip=20", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert len(data["products"]) >= 5 # At least 5 remaining from our test set
def test_pagination_boundary_negative_skip_validation_error(
self, client, auth_headers
):
"""Test negative skip parameter returns ValidationException"""
response = client.get(
"/api/v1/marketplace/product?skip=-1", headers=auth_headers
)
assert response.status_code == 422
data = response.json()
assert data["error_code"] == "VALIDATION_ERROR"
assert data["status_code"] == 422
assert "Request validation failed" in data["message"]
assert "validation_errors" in data["details"]
def test_pagination_boundary_zero_limit_validation_error(
self, client, auth_headers
):
"""Test zero limit parameter returns ValidationException"""
response = client.get(
"/api/v1/marketplace/product?limit=0", headers=auth_headers
)
assert response.status_code == 422
data = response.json()
assert data["error_code"] == "VALIDATION_ERROR"
assert data["status_code"] == 422
assert "Request validation failed" in data["message"]
def test_pagination_boundary_excessive_limit_validation_error(
self, client, auth_headers
):
"""Test excessive limit parameter returns ValidationException"""
response = client.get(
"/api/v1/marketplace/product?limit=10000", headers=auth_headers
)
assert response.status_code == 422
data = response.json()
assert data["error_code"] == "VALIDATION_ERROR"
assert data["status_code"] == 422
assert "Request validation failed" in data["message"]
def test_pagination_beyond_available_records(self, client, auth_headers, db):
"""Test pagination beyond available records returns empty results"""
# Test skip beyond available records
response = client.get(
"/api/v1/marketplace/product?skip=10000&limit=10", headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert data["products"] == []
assert data["skip"] == 10000
assert data["limit"] == 10
# total should still reflect actual count
def test_pagination_with_filters(self, client, auth_headers, db):
"""Test pagination combined with filtering"""
import uuid
unique_suffix = str(uuid.uuid4())[:8]
# Create products with same brand for filtering
products = []
for i in range(15):
product = MarketplaceProduct(
marketplace_product_id=f"FILTPAGE{i:03d}_{unique_suffix}",
title=f"Filter Page MarketplaceProduct {i}",
brand="FilterBrand",
marketplace="FilterMarket",
)
products.append(product)
db.add_all(products)
db.commit()
# Test first page with filter
response = client.get(
"/api/v1/marketplace/product?brand=FilterBrand&limit=5&skip=0",
headers=auth_headers,
)
assert response.status_code == 200
data = response.json()
assert len(data["products"]) == 5
assert data["total"] >= 15 # At least our test products
# Verify all products have the filtered brand
test_products = [
p
for p in data["products"]
if p["marketplace_product_id"].endswith(unique_suffix)
]
for product in test_products:
assert product["brand"] == "FilterBrand"
# Test second page with same filter
response = client.get(
"/api/v1/marketplace/product?brand=FilterBrand&limit=5&skip=5",
headers=auth_headers,
)
assert response.status_code == 200
data = response.json()
assert len(data["products"]) == 5
assert data["skip"] == 5
def test_pagination_default_values(self, client, auth_headers):
"""Test pagination with default values"""
response = client.get("/api/v1/marketplace/product", headers=auth_headers)
assert response.status_code == 200
data = response.json()
assert data["skip"] == 0 # Default skip
assert data["limit"] == 100 # Default limit
assert len(data["products"]) <= 100 # Should not exceed limit
def test_pagination_consistency(self, client, auth_headers, db):
"""Test pagination consistency across multiple requests"""
import uuid
unique_suffix = str(uuid.uuid4())[:8]
# Create products with predictable ordering
products = []
for i in range(10):
product = MarketplaceProduct(
marketplace_product_id=f"CONSIST{i:03d}_{unique_suffix}",
title=f"Consistent MarketplaceProduct {i:03d}",
marketplace="ConsistentMarket",
)
products.append(product)
db.add_all(products)
db.commit()
# Get first page
response1 = client.get(
"/api/v1/marketplace/product?limit=5&skip=0", headers=auth_headers
)
assert response1.status_code == 200
first_page_ids = [
p["marketplace_product_id"] for p in response1.json()["products"]
]
# Get second page
response2 = client.get(
"/api/v1/marketplace/product?limit=5&skip=5", headers=auth_headers
)
assert response2.status_code == 200
second_page_ids = [
p["marketplace_product_id"] for p in response2.json()["products"]
]
# Verify no overlap between pages
overlap = set(first_page_ids) & set(second_page_ids)
assert len(overlap) == 0, "Pages should not have overlapping products"
def test_vendor_pagination_success(self, client, admin_headers, db, test_user):
"""Test pagination for vendor listing successfully"""
import uuid
unique_suffix = str(uuid.uuid4())[:8]
# Create multiple vendors for pagination testing
vendors = []
for i in range(15):
vendor = Vendor(
vendor_code=f"PAGEVENDOR{i:03d}_{unique_suffix}",
vendor_name=f"Pagination Vendor {i}",
owner_user_id=test_user.id,
is_active=True,
)
vendors.append(vendor)
db.add_all(vendors)
db.commit()
# Test first page (assuming admin endpoint exists)
response = client.get("/api/v1/vendor?limit=5&skip=0", headers=admin_headers)
assert response.status_code == 200
data = response.json()
assert len(data["vendors"]) == 5
assert data["total"] >= 15 # At least our test vendors
assert data["skip"] == 0
assert data["limit"] == 5
def test_inventory_pagination_success(self, client, auth_headers, db):
"""Test pagination for inventory listing successfully"""
import uuid
unique_suffix = str(uuid.uuid4())[:8]
# Create multiple inventory entries
from models.database.inventory import Inventory
inventory_entries = []
for i in range(20):
inventory = Inventory(
gtin=f"123456789{i:04d}",
location=f"LOC_{unique_suffix}_{i}",
quantity=10 + i,
)
inventory_entries.append(inventory)
db.add_all(inventory_entries)
db.commit()
# Test first page
response = client.get("/api/v1/inventory?limit=8&skip=0", headers=auth_headers)
assert response.status_code == 200
data = response.json()
assert len(data) == 8
# Test second page
response = client.get("/api/v1/inventory?limit=8&skip=8", headers=auth_headers)
assert response.status_code == 200
data = response.json()
assert len(data) == 8
def test_pagination_performance_large_offset(self, client, auth_headers, db):
"""Test pagination performance with large offset values"""
# Test with large skip value (should still be reasonable performance)
import time
start_time = time.time()
response = client.get(
"/api/v1/marketplace/product?skip=1000&limit=10", headers=auth_headers
)
end_time = time.time()
assert response.status_code == 200
assert end_time - start_time < 5.0 # Should complete within 5 seconds
data = response.json()
assert data["skip"] == 1000
assert data["limit"] == 10
def test_pagination_with_invalid_parameters_types(self, client, auth_headers):
"""Test pagination with invalid parameter types returns ValidationException"""
# Test non-numeric skip
response = client.get(
"/api/v1/marketplace/product?skip=invalid", headers=auth_headers
)
assert response.status_code == 422
data = response.json()
assert data["error_code"] == "VALIDATION_ERROR"
# Test non-numeric limit
response = client.get(
"/api/v1/marketplace/product?limit=invalid", headers=auth_headers
)
assert response.status_code == 422
data = response.json()
assert data["error_code"] == "VALIDATION_ERROR"
# Test float values (should be converted or rejected)
response = client.get(
"/api/v1/marketplace/product?skip=10.5&limit=5.5", headers=auth_headers
)
assert response.status_code in [200, 422] # Depends on implementation
def test_empty_dataset_pagination(self, client, auth_headers):
"""Test pagination behavior with empty dataset"""
# Use a filter that should return no results
response = client.get(
"/api/v1/marketplace/product?brand=NonexistentBrand999&limit=10&skip=0",
headers=auth_headers,
)
assert response.status_code == 200
data = response.json()
assert data["products"] == []
assert data["total"] == 0
assert data["skip"] == 0
assert data["limit"] == 10
def test_exception_structure_in_pagination_errors(self, client, auth_headers):
"""Test that pagination validation errors follow consistent exception structure"""
response = client.get(
"/api/v1/marketplace/product?skip=-1", headers=auth_headers
)
assert response.status_code == 422
data = response.json()
# Verify exception structure matches WizamartException.to_dict()
required_fields = ["error_code", "message", "status_code"]
for field in required_fields:
assert field in data, f"Missing required field: {field}"
assert isinstance(data["error_code"], str)
assert isinstance(data["message"], str)
assert isinstance(data["status_code"], int)
assert data["error_code"] == "VALIDATION_ERROR"
assert data["status_code"] == 422
# Details should contain validation errors
if "details" in data:
assert isinstance(data["details"], dict)
assert "validation_errors" in data["details"]