Files
tfm_ainventory/backend/tests/test_schema.py
Daniel Bedeleanu ea49cd6e4a feat(phase1): add image storage utilities
- Create backend/services/image_storage.py with 4 core functions:
  - sanitize_filename(): remove unsafe chars, limit to 255 chars, convert to lowercase
  - get_unique_filename(): handle collisions with UUID suffix (format: {name}_{uuid8}_{variant}.jpg)
  - ensure_image_directories(): create /images/ root and category subdirs on startup
  - save_image(): save bytes to /images/{category}/{filename}, returns relative path
- Create comprehensive test suite (22 tests) covering all functionality
- Integrate ensure_image_directories() into FastAPI startup event
- Directory structure: /images/{category}/{filename}
- Collision handling: auto-suffix with UUID if filename exists
- All tests passing, pathlib.Path for safe operations
2026-04-20 21:57:26 +03:00

182 lines
6.4 KiB
Python

import pytest
from datetime import datetime
from sqlalchemy.orm import Session
from backend.models import Item, AuditLog, User
class TestItemPhotoFields:
"""Tests for Item model photo fields."""
def test_item_has_photo_path_field(self, test_db: Session):
"""Verify Item model has photo_path field."""
# Verify the field exists as an attribute
assert hasattr(Item, "photo_path"), "Item model must have photo_path field"
def test_item_has_photo_thumbnail_path_field(self, test_db: Session):
"""Verify Item model has photo_thumbnail_path field."""
assert hasattr(Item, "photo_thumbnail_path"), "Item model must have photo_thumbnail_path field"
def test_item_has_photo_upload_date_field(self, test_db: Session):
"""Verify Item model has photo_upload_date field."""
assert hasattr(Item, "photo_upload_date"), "Item model must have photo_upload_date field"
def test_item_photo_fields_are_nullable(self, test_db: Session):
"""Verify that photo fields are nullable - can create item without photos."""
# Create item without photo fields
user = User(username="test_user", hashed_password="hashed", role="user", origin="local")
test_db.add(user)
test_db.commit()
item = Item(
barcode="TEST-001",
name="Test Item",
category="Electronics",
quantity=5.0
)
test_db.add(item)
test_db.commit()
test_db.refresh(item)
# Verify item was created and photo fields are None
assert item.id is not None
assert item.photo_path is None
assert item.photo_thumbnail_path is None
assert item.photo_upload_date is None
def test_item_photo_fields_can_be_set(self, test_db: Session):
"""Verify that photo fields can be set with values."""
user = User(username="test_user2", hashed_password="hashed", role="user", origin="local")
test_db.add(user)
test_db.commit()
upload_date = datetime.now()
item = Item(
barcode="TEST-002",
name="Test Item with Photo",
category="Electronics",
quantity=3.0,
photo_path="networking/SFP-LR_original.jpg",
photo_thumbnail_path="networking/SFP-LR_thumb.jpg",
photo_upload_date=upload_date
)
test_db.add(item)
test_db.commit()
test_db.refresh(item)
# Verify fields were set correctly
assert item.photo_path == "networking/SFP-LR_original.jpg"
assert item.photo_thumbnail_path == "networking/SFP-LR_thumb.jpg"
assert item.photo_upload_date == upload_date
def test_item_photo_path_is_string_type(self, test_db: Session):
"""Verify photo_path field accepts string values."""
user = User(username="test_user3", hashed_password="hashed", role="user", origin="local")
test_db.add(user)
test_db.commit()
path = "path/to/image.jpg"
item = Item(
barcode="TEST-003",
name="Item",
category="Electronics",
photo_path=path
)
test_db.add(item)
test_db.commit()
test_db.refresh(item)
assert isinstance(item.photo_path, str)
assert item.photo_path == path
def test_item_photo_upload_date_is_datetime_type(self, test_db: Session):
"""Verify photo_upload_date field accepts datetime values."""
user = User(username="test_user4", hashed_password="hashed", role="user", origin="local")
test_db.add(user)
test_db.commit()
now = datetime.now()
item = Item(
barcode="TEST-004",
name="Item",
category="Electronics",
photo_upload_date=now
)
test_db.add(item)
test_db.commit()
test_db.refresh(item)
assert isinstance(item.photo_upload_date, datetime)
assert item.photo_upload_date == now
def test_existing_item_without_photos_unaffected(self, test_db: Session):
"""Verify that existing items without photos continue to work."""
user = User(username="test_user5", hashed_password="hashed", role="user", origin="local")
test_db.add(user)
test_db.commit()
# Create item without photo fields (legacy behavior)
item = Item(
barcode="LEGACY-001",
name="Legacy Item",
category="Electronics",
quantity=10.0,
part_number="PN-999",
description="A legacy item"
)
test_db.add(item)
test_db.commit()
test_db.refresh(item)
# Verify all existing fields still work
assert item.barcode == "LEGACY-001"
assert item.name == "Legacy Item"
assert item.category == "Electronics"
assert item.quantity == 10.0
assert item.part_number == "PN-999"
assert item.description == "A legacy item"
# Photo fields should be None for legacy items
assert item.photo_path is None
assert item.photo_thumbnail_path is None
assert item.photo_upload_date is None
class TestBoxModel:
"""Tests for Box model photo fields (if Box model exists)."""
def test_box_model_exists(self):
"""Verify Box model exists in database schema."""
# Import Box model if it exists
try:
from backend.models import Box
assert Box is not None
except ImportError:
pytest.skip("Box model not yet implemented")
def test_box_photo_fields_exist(self):
"""Verify Box model has photo fields if it exists."""
try:
from backend.models import Box
assert hasattr(Box, "photo_path")
assert hasattr(Box, "photo_thumbnail_path")
assert hasattr(Box, "photo_upload_date")
except ImportError:
pytest.skip("Box model not yet implemented")
def test_box_photo_fields_are_nullable(self, test_db: Session):
"""Verify Box photo fields are nullable."""
try:
from backend.models import Box
box = Box(name="Test Box")
test_db.add(box)
test_db.commit()
test_db.refresh(box)
assert box.id is not None
assert box.photo_path is None
assert box.photo_thumbnail_path is None
assert box.photo_upload_date is None
except ImportError:
pytest.skip("Box model not yet implemented")