507 lines
19 KiB
Python
507 lines
19 KiB
Python
# tests/test_stats_service.py
|
|
import pytest
|
|
|
|
from app.services.stats_service import StatsService
|
|
from models.database.marketplace_product import MarketplaceProduct
|
|
from models.database.stock import Stock
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.stats
|
|
class TestStatsService:
|
|
"""Test suite for StatsService following the application's testing patterns"""
|
|
|
|
def setup_method(self):
|
|
"""Setup method following the same pattern as other service tests"""
|
|
self.service = StatsService()
|
|
|
|
def test_get_comprehensive_stats_basic(self, db, test_marketplace_product, test_stock):
|
|
"""Test getting comprehensive stats with basic data"""
|
|
stats = self.service.get_comprehensive_stats(db)
|
|
|
|
assert "total_products" in stats
|
|
assert "unique_brands" in stats
|
|
assert "unique_categories" in stats
|
|
assert "unique_marketplaces" in stats
|
|
assert "unique_vendors" in stats
|
|
assert "total_stock_entries" in stats
|
|
assert "total_inventory_quantity" in stats
|
|
|
|
assert stats["total_products"] >= 1
|
|
assert stats["total_stock_entries"] >= 1
|
|
assert stats["total_inventory_quantity"] >= 10 # test_stock has quantity 10
|
|
|
|
def test_get_comprehensive_stats_multiple_products(self, db, test_marketplace_product):
|
|
"""Test comprehensive stats with multiple products across different dimensions"""
|
|
# Create products with different brands, categories, marketplaces
|
|
additional_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="PROD002",
|
|
title="MarketplaceProduct 2",
|
|
brand="DifferentBrand",
|
|
google_product_category="Different Category",
|
|
marketplace="Amazon",
|
|
vendor_name="AmazonShop",
|
|
price="15.99",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="PROD003",
|
|
title="MarketplaceProduct 3",
|
|
brand="ThirdBrand",
|
|
google_product_category="Third Category",
|
|
marketplace="eBay",
|
|
vendor_name="eBayShop",
|
|
price="25.99",
|
|
currency="USD",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="PROD004",
|
|
title="MarketplaceProduct 4",
|
|
brand="TestBrand", # Same as test_marketplace_product
|
|
google_product_category="Different Category",
|
|
marketplace="Letzshop", # Same as test_marketplace_product
|
|
vendor_name="DifferentShop",
|
|
price="35.99",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(additional_products)
|
|
db.commit()
|
|
|
|
stats = self.service.get_comprehensive_stats(db)
|
|
|
|
assert stats["total_products"] >= 4 # test_marketplace_product + 3 additional
|
|
assert stats["unique_brands"] >= 3 # TestBrand, DifferentBrand, ThirdBrand
|
|
assert stats["unique_categories"] >= 2 # At least 2 different categories
|
|
assert stats["unique_marketplaces"] >= 3 # Letzshop, Amazon, eBay
|
|
assert stats["unique_vendors"] >= 3 # At least 3 different vendors
|
|
|
|
def test_get_comprehensive_stats_handles_nulls(self, db):
|
|
"""Test comprehensive stats handles null/empty values correctly"""
|
|
# Create products with null/empty values
|
|
products_with_nulls = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="NULL001",
|
|
title="MarketplaceProduct with Nulls",
|
|
brand=None, # Null brand
|
|
google_product_category=None, # Null category
|
|
marketplace=None, # Null marketplace
|
|
vendor_name=None, # Null vendor
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="EMPTY001",
|
|
title="MarketplaceProduct with Empty Values",
|
|
brand="", # Empty brand
|
|
google_product_category="", # Empty category
|
|
marketplace="", # Empty marketplace
|
|
vendor_name="", # Empty vendor
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(products_with_nulls)
|
|
db.commit()
|
|
|
|
stats = self.service.get_comprehensive_stats(db)
|
|
|
|
# These products shouldn't contribute to unique counts due to null/empty values
|
|
assert stats["total_products"] >= 2
|
|
# Brands, categories, marketplaces, vendors should not count null/empty values
|
|
assert isinstance(stats["unique_brands"], int)
|
|
assert isinstance(stats["unique_categories"], int)
|
|
assert isinstance(stats["unique_marketplaces"], int)
|
|
assert isinstance(stats["unique_vendors"], int)
|
|
|
|
def test_get_marketplace_breakdown_stats_basic(self, db, test_marketplace_product):
|
|
"""Test getting marketplace breakdown stats with basic data"""
|
|
stats = self.service.get_marketplace_breakdown_stats(db)
|
|
|
|
assert isinstance(stats, list)
|
|
assert len(stats) >= 1
|
|
|
|
# Find our test marketplace in the results
|
|
test_marketplace_stat = next(
|
|
(stat for stat in stats if stat["marketplace"] == test_marketplace_product.marketplace),
|
|
None,
|
|
)
|
|
assert test_marketplace_stat is not None
|
|
assert test_marketplace_stat["total_products"] >= 1
|
|
assert test_marketplace_stat["unique_vendors"] >= 1
|
|
assert test_marketplace_stat["unique_brands"] >= 1
|
|
|
|
def test_get_marketplace_breakdown_stats_multiple_marketplaces(
|
|
self, db, test_marketplace_product
|
|
):
|
|
"""Test marketplace breakdown with multiple marketplaces"""
|
|
# Create products for different marketplaces
|
|
marketplace_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="AMAZON001",
|
|
title="Amazon MarketplaceProduct 1",
|
|
brand="AmazonBrand1",
|
|
marketplace="Amazon",
|
|
vendor_name="AmazonShop1",
|
|
price="20.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="AMAZON002",
|
|
title="Amazon MarketplaceProduct 2",
|
|
brand="AmazonBrand2",
|
|
marketplace="Amazon",
|
|
vendor_name="AmazonShop2",
|
|
price="25.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="EBAY001",
|
|
title="eBay MarketplaceProduct",
|
|
brand="eBayBrand",
|
|
marketplace="eBay",
|
|
vendor_name="eBayShop",
|
|
price="30.00",
|
|
currency="USD",
|
|
),
|
|
]
|
|
db.add_all(marketplace_products)
|
|
db.commit()
|
|
|
|
stats = self.service.get_marketplace_breakdown_stats(db)
|
|
|
|
# Should have at least 3 marketplaces: test_marketplace_product.marketplace, Amazon, eBay
|
|
marketplace_names = [stat["marketplace"] for stat in stats]
|
|
assert "Amazon" in marketplace_names
|
|
assert "eBay" in marketplace_names
|
|
assert test_marketplace_product.marketplace in marketplace_names
|
|
|
|
# Check Amazon stats specifically
|
|
amazon_stat = next(stat for stat in stats if stat["marketplace"] == "Amazon")
|
|
assert amazon_stat["total_products"] == 2
|
|
assert amazon_stat["unique_vendors"] == 2
|
|
assert amazon_stat["unique_brands"] == 2
|
|
|
|
# Check eBay stats specifically
|
|
ebay_stat = next(stat for stat in stats if stat["marketplace"] == "eBay")
|
|
assert ebay_stat["total_products"] == 1
|
|
assert ebay_stat["unique_vendors"] == 1
|
|
assert ebay_stat["unique_brands"] == 1
|
|
|
|
def test_get_marketplace_breakdown_stats_excludes_nulls(self, db):
|
|
"""Test marketplace breakdown excludes products with null marketplaces"""
|
|
# Create product with null marketplace
|
|
null_marketplace_product = MarketplaceProduct(
|
|
marketplace_product_id="NULLMARKET001",
|
|
title="MarketplaceProduct without marketplace",
|
|
marketplace=None,
|
|
vendor_name="SomeShop",
|
|
brand="SomeBrand",
|
|
price="10.00",
|
|
currency="EUR",
|
|
)
|
|
db.add(null_marketplace_product)
|
|
db.commit()
|
|
|
|
stats = self.service.get_marketplace_breakdown_stats(db)
|
|
|
|
# Should not include any stats for null marketplace
|
|
marketplace_names = [
|
|
stat["marketplace"] for stat in stats if stat["marketplace"] is not None
|
|
]
|
|
assert None not in marketplace_names
|
|
|
|
def test_get_product_count(self, db, test_marketplace_product):
|
|
"""Test getting total product count"""
|
|
count = self.service._get_product_count(db)
|
|
|
|
assert count >= 1
|
|
assert isinstance(count, int)
|
|
|
|
def test_get_unique_brands_count(self, db, test_marketplace_product):
|
|
"""Test getting unique brands count"""
|
|
# Add products with different brands
|
|
brand_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="BRAND001",
|
|
title="Brand MarketplaceProduct 1",
|
|
brand="BrandA",
|
|
marketplace="Test",
|
|
vendor_name="TestVendor",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="BRAND002",
|
|
title="Brand MarketplaceProduct 2",
|
|
brand="BrandB",
|
|
marketplace="Test",
|
|
vendor_name="TestVendor",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(brand_products)
|
|
db.commit()
|
|
|
|
count = self.service._get_unique_brands_count(db)
|
|
|
|
assert (
|
|
count >= 2
|
|
) # At least BrandA and BrandB, plus possibly test_marketplace_product brand
|
|
assert isinstance(count, int)
|
|
|
|
def test_get_unique_categories_count(self, db, test_marketplace_product):
|
|
"""Test getting unique categories count"""
|
|
# Add products with different categories
|
|
category_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="CAT001",
|
|
title="Category MarketplaceProduct 1",
|
|
google_product_category="Electronics",
|
|
marketplace="Test",
|
|
vendor_name="TestVendor",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="CAT002",
|
|
title="Category MarketplaceProduct 2",
|
|
google_product_category="Books",
|
|
marketplace="Test",
|
|
vendor_name="TestVendor",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(category_products)
|
|
db.commit()
|
|
|
|
count = self.service._get_unique_categories_count(db)
|
|
|
|
assert count >= 2 # At least Electronics and Books
|
|
assert isinstance(count, int)
|
|
|
|
def test_get_unique_marketplaces_count(self, db, test_marketplace_product):
|
|
"""Test getting unique marketplaces count"""
|
|
# Add products with different marketplaces
|
|
marketplace_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="MARKET001",
|
|
title="Marketplace MarketplaceProduct 1",
|
|
marketplace="Amazon",
|
|
vendor_name="AmazonShop",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="MARKET002",
|
|
title="Marketplace MarketplaceProduct 2",
|
|
marketplace="eBay",
|
|
vendor_name="eBayShop",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(marketplace_products)
|
|
db.commit()
|
|
|
|
count = self.service._get_unique_marketplaces_count(db)
|
|
|
|
assert count >= 2 # At least Amazon and eBay, plus test_marketplace_product marketplace
|
|
assert isinstance(count, int)
|
|
|
|
def test_get_unique_vendors_count(self, db, test_marketplace_product):
|
|
"""Test getting unique vendors count"""
|
|
# Add products with different vendor names
|
|
products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="SHOP001",
|
|
title="Vendor MarketplaceProduct 1",
|
|
marketplace="Test",
|
|
vendor_name="ShopA",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="SHOP002",
|
|
title="Vendor MarketplaceProduct 2",
|
|
marketplace="Test",
|
|
vendor_name="ShopB",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(products)
|
|
db.commit()
|
|
|
|
count = self.service._get_unique_vendors_count(db)
|
|
|
|
assert count >= 2 # At least ShopA and ShopB, plus test_marketplace_product vendor
|
|
assert isinstance(count, int)
|
|
|
|
def test_get_stock_statistics(self, db, test_stock):
|
|
"""Test getting stock statistics"""
|
|
# Add additional stock entries
|
|
additional_stocks = [
|
|
Stock(
|
|
gtin="1234567890124",
|
|
location="LOCATION2",
|
|
quantity=25,
|
|
reserved_quantity=5,
|
|
vendor_id=test_stock.vendor_id,
|
|
),
|
|
Stock(
|
|
gtin="1234567890125",
|
|
location="LOCATION3",
|
|
quantity=0, # Out of stock
|
|
reserved_quantity=0,
|
|
vendor_id=test_stock.vendor_id,
|
|
),
|
|
]
|
|
db.add_all(additional_stocks)
|
|
db.commit()
|
|
|
|
stats = self.service.get_stock_statistics(db)
|
|
|
|
assert "total_stock_entries" in stats
|
|
assert "total_inventory_quantity" in stats
|
|
assert stats["total_stock_entries"] >= 3 # test_stock + 2 additional
|
|
assert stats["total_inventory_quantity"] >= 35 # 10 + 25 + 0 = 35
|
|
|
|
def test_get_brands_by_marketplace(self, db):
|
|
"""Test getting brands for a specific marketplace"""
|
|
# Create products for specific marketplace
|
|
marketplace_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="SPECIFIC001",
|
|
title="Specific MarketplaceProduct 1",
|
|
brand="SpecificBrand1",
|
|
marketplace="SpecificMarket",
|
|
vendor_name="SpecificShop1",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="SPECIFIC002",
|
|
title="Specific MarketplaceProduct 2",
|
|
brand="SpecificBrand2",
|
|
marketplace="SpecificMarket",
|
|
vendor_name="SpecificShop2",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="OTHER001",
|
|
title="Other MarketplaceProduct",
|
|
brand="OtherBrand",
|
|
marketplace="OtherMarket",
|
|
vendor_name="OtherShop",
|
|
price="20.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(marketplace_products)
|
|
db.commit()
|
|
|
|
brands = self.service._get_brands_by_marketplace(db, "SpecificMarket")
|
|
|
|
assert len(brands) == 2
|
|
assert "SpecificBrand1" in brands
|
|
assert "SpecificBrand2" in brands
|
|
assert "OtherBrand" not in brands
|
|
|
|
def test_get_vendors_by_marketplace(self, db):
|
|
"""Test getting vendors for a specific marketplace"""
|
|
# Create products for specific marketplace
|
|
marketplace_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="SHOPTEST001",
|
|
title="Vendor Test MarketplaceProduct 1",
|
|
brand="TestBrand",
|
|
marketplace="TestMarketplace",
|
|
vendor_name="TestVendor1",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="SHOPTEST002",
|
|
title="Vendor Test MarketplaceProduct 2",
|
|
brand="TestBrand",
|
|
marketplace="TestMarketplace",
|
|
vendor_name="TestVendor2",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(marketplace_products)
|
|
db.commit()
|
|
|
|
vendors =self.service._get_vendors_by_marketplace(db, "TestMarketplace")
|
|
|
|
assert len(vendors) == 2
|
|
assert "TestVendor1" in vendors
|
|
assert "TestVendor2" in vendors
|
|
|
|
def test_get_products_by_marketplace(self, db):
|
|
"""Test getting product count for a specific marketplace"""
|
|
# Create products for specific marketplace
|
|
marketplace_products = [
|
|
MarketplaceProduct(
|
|
marketplace_product_id="COUNT001",
|
|
title="Count MarketplaceProduct 1",
|
|
marketplace="CountMarketplace",
|
|
vendor_name="CountShop",
|
|
price="10.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="COUNT002",
|
|
title="Count MarketplaceProduct 2",
|
|
marketplace="CountMarketplace",
|
|
vendor_name="CountShop",
|
|
price="15.00",
|
|
currency="EUR",
|
|
),
|
|
MarketplaceProduct(
|
|
marketplace_product_id="COUNT003",
|
|
title="Count MarketplaceProduct 3",
|
|
marketplace="CountMarketplace",
|
|
vendor_name="CountShop",
|
|
price="20.00",
|
|
currency="EUR",
|
|
),
|
|
]
|
|
db.add_all(marketplace_products)
|
|
db.commit()
|
|
|
|
count = self.service._get_products_by_marketplace_count(db, "CountMarketplace")
|
|
|
|
assert count == 3
|
|
|
|
def test_get_products_by_marketplace_not_found(self, db):
|
|
"""Test getting product count for non-existent marketplace"""
|
|
count = self.service._get_products_by_marketplace_count(db, "NonExistentMarketplace")
|
|
|
|
assert count == 0
|
|
|
|
def test_empty_database_stats(self, db):
|
|
"""Test stats with empty database"""
|
|
stats = self.service.get_comprehensive_stats(db)
|
|
|
|
assert stats["total_products"] == 0
|
|
assert stats["unique_brands"] == 0
|
|
assert stats["unique_categories"] == 0
|
|
assert stats["unique_marketplaces"] == 0
|
|
assert stats["unique_vendors"] == 0
|
|
assert stats["total_stock_entries"] == 0
|
|
assert stats["total_inventory_quantity"] == 0
|
|
|
|
def test_marketplace_breakdown_empty_database(self, db):
|
|
"""Test marketplace breakdown with empty database"""
|
|
stats = self.service.get_marketplace_breakdown_stats(db)
|
|
|
|
assert isinstance(stats, list)
|
|
assert len(stats) == 0
|