Files
Priceflow/verify_fix_item_service.py
T

165 lines
5.4 KiB
Python

import os
import glob
import sys
from unittest.mock import MagicMock
# --- MOCKS SETUP ---
# We need to mock these BEFORE importing app.services.item_service
# to avoid ImportErrors due to missing dependencies in the test env.
# 1. Mock External Libs
sys.modules["fastapi"] = MagicMock()
sys.modules["sqlalchemy"] = MagicMock()
sys.modules["sqlalchemy.orm"] = MagicMock()
# 2. Mock Internal App Modules that have heavy dependencies
# Mock app.database
mock_database = MagicMock()
sys.modules["app.database"] = mock_database
# Mock app.models
# We need models.Item and models.PriceHistory to be accessible attributes
mock_models = MagicMock()
sys.modules["app.models"] = mock_models
# Mock app.schemas
sys.modules["app.schemas"] = MagicMock()
# Mock app.services.settings_service
sys.modules["app.services.settings_service"] = MagicMock()
# Mock app.url_validation
sys.modules["app.url_validation"] = MagicMock()
# --- IMPORT TARGET ---
from app.services.item_service import ItemService
def verify_item_service_fix():
print("Starting verification of ItemService fix...")
# 1. Setup Mock DB and Item
# We must ensure that when ItemService does `item.id`, it works.
mock_db = MagicMock()
# Create a simple class to act as the Item model instance
class MockItem:
def __init__(self, id, name):
self.id = id
self.name = name
self.url = "http://test.com"
self.current_price = 10.0
self.in_stock = True
self.screenshot_url = None # This will be set by the service
# Attributes accessed by the service
self.notification_channel = None
self.target_price = None
self.current_price_confidence = 1.0
self.in_stock_confidence = 1.0
self.is_active = True
self.last_checked = None
self.is_refreshing = False
self.last_error = None
self.category = None
self.tags = None
self.description = None
# __dict__ is used by the service to create the result
self.dict_storage = {k:v for k,v in self.__dict__.items()}
@property
def __dict__(self):
# Update dict storage with current attributes
return {
"id": self.id,
"name": self.name,
"url": self.url
}
item_888 = MockItem(888, "Test Item")
# ItemService.get_items calls db.query(models.Item).all()
# We need to make sure models.Item is used in the query.
# The service does: items = db.query(models.Item).all()
mock_db.query.return_value.all.return_value = [item_888]
# It also queries PriceHistory
# db.query(models.PriceHistory).filter(...).first()
# Let's mock that to return None to force filesytem check (or check logic priority)
mock_db.query.return_value.filter.return_value.filter.return_value.order_by.return_value.first.return_value = None
# 2. Create Dummy Screenshot Files
os.makedirs("screenshots", exist_ok=True)
# Clean up
for f in glob.glob("screenshots/item_888_*.png"):
os.remove(f)
if os.path.exists("screenshots/item_888.png"):
os.remove("screenshots/item_888.png")
# Scenario:
# 1. item_888.png exists (legacy)
# 2. item_888_1000.png exists (old timestamp)
# 3. item_888_2000.png exists (new timestamp)
# Expected: get_items should pick item_888_2000.png
file_legacy = "screenshots/item_888.png"
file_old = "screenshots/item_888_1000.png"
file_new = "screenshots/item_888_2000.png"
with open(file_legacy, "w") as f: f.write(".")
with open(file_old, "w") as f: f.write(".")
with open(file_new, "w") as f: f.write(".")
print(f"Created files: {file_legacy}, {file_old}, {file_new}")
try:
# 3. Test get_items
print("Testing get_items()...")
items = ItemService.get_items(mock_db)
if not items:
print("FAILURE: No items returned")
exit(1)
result = items[0]
screenshot_url = result.get("screenshot_url")
print(f"Returned screenshot_url: {screenshot_url}")
expected_url = f"/screenshots/{os.path.basename(file_new)}"
if screenshot_url == expected_url:
print("SUCCESS: Correctly identified the latest screenshot!")
else:
print(f"FAILURE: Expected {expected_url}, got {screenshot_url}")
# If it failed, maybe it picked legacy?
if screenshot_url == f"/screenshots/{os.path.basename(file_legacy)}":
print("Picked legacy file instead of timestamped one.")
exit(1)
# 4. Test delete_item
print("Testing delete_item()...")
# Ensure the query returns our item
mock_db.query.return_value.filter.return_value.first.return_value = item_888
ItemService.delete_item(mock_db, 888)
# Check files
remaining = glob.glob("screenshots/item_888*.png")
if not remaining:
print("SUCCESS: All screenshots deleted.")
else:
print(f"FAILURE: Files remaining: {remaining}")
exit(1)
finally:
# Cleanup
for f in [file_legacy, file_old, file_new]:
if os.path.exists(f):
os.remove(f)
if __name__ == "__main__":
verify_item_service_fix()