Files
004.erp.generic/backend/modules/fleet/tests/test_photo_services.py
mariomitte 5d39e048ba
Some checks failed
ERP CI Pipeline / test (push) Has been cancelled
prvi kod za live uporabu
2026-07-09 21:21:17 +02:00

362 lines
12 KiB
Python

import uuid
from io import BytesIO
from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile
from django.contrib.auth import get_user_model
from rest_framework.exceptions import ValidationError as DRFValidationError
from PIL import Image
from modules.fleet.models import Vehicle, VehicleServiceRecord, VehicleServicePhoto
from modules.fleet.services import VehicleServicePhotoService
User = get_user_model()
def create_test_image(filename="test.jpg", size=(100, 100), color='red'):
"""
Stvori test sliku u memoriji koristeći Pillow.
Vraća SimpleUploadedFile spreman za upload.
"""
file = BytesIO()
image = Image.new('RGB', size=size, color=color)
image.save(file, 'JPEG')
file.seek(0)
return SimpleUploadedFile(
name=filename,
content=file.getvalue(),
content_type='image/jpeg'
)
class VehicleServicePhotoServiceTests(TestCase):
def setUp(self):
# Create users
self.uploader = User.objects.create_user(
username=f"uploader_{uuid.uuid4().hex[:6]}",
email=f"uploader+{uuid.uuid4()}@example.test",
password="pass"
)
self.other_user = User.objects.create_user(
username=f"other_{uuid.uuid4().hex[:6]}",
email=f"other+{uuid.uuid4()}@example.test",
password="pass"
)
self.staff_user = User.objects.create_user(
username=f"admin_{uuid.uuid4().hex[:6]}",
email=f"admin+{uuid.uuid4()}@example.test",
password="pass",
is_staff=True
)
# Create vehicle and service record
self.vehicle = Vehicle.objects.create(
registration_number=f"SRVPHOTO-{uuid.uuid4().hex[:6].upper()}",
make="TestMake",
model="TestModel",
current_mileage=5000,
service_interval_km=10000
)
self.service_record = VehicleServiceRecord.objects.create(
vehicle=self.vehicle,
performed_by=self.uploader,
description="Test service",
mileage=5000,
parts="part1;part2"
)
def test_upload_photo_success(self):
"""
Test uspješnog uploada fotografije s valjanim podacima.
"""
image = create_test_image(filename="success.jpg")
data = {
'service_record': self.service_record,
'image': image,
'description': 'Test brake replacement'
}
photo = VehicleServicePhotoService.upload_photo(data=data, uploaded_by=self.uploader)
self.assertIsNotNone(photo.pk)
self.assertEqual(photo.uploaded_by, self.uploader)
self.assertEqual(photo.service_record, self.service_record)
self.assertEqual(photo.description, 'Test brake replacement')
self.assertTrue(photo.image)
def test_upload_photo_with_service_record_id(self):
"""
Test uploada koristeći service_record ID umjesto instancije.
"""
image = create_test_image(filename="by_id.jpg")
data = {
'service_record': self.service_record.id, # ID, ne instanca
'image': image,
'description': 'Upload by ID'
}
photo = VehicleServicePhotoService.upload_photo(data=data, uploaded_by=self.uploader)
self.assertIsNotNone(photo.pk)
self.assertEqual(photo.service_record, self.service_record)
def test_upload_photo_without_user_raises(self):
"""
Test — upload bez korisnika (uploaded_by) baca ValidationError.
"""
image = create_test_image(filename="no_user.jpg")
data = {
'service_record': self.service_record,
'image': image,
'description': 'No user'
}
with self.assertRaises(DRFValidationError):
VehicleServicePhotoService.upload_photo(data=data, uploaded_by=None)
def test_upload_photo_invalid_service_record_raises(self):
"""
Test — upload s nepostojeću service_record ID baca ValidationError.
"""
image = create_test_image(filename="invalid_sr.jpg")
data = {
'service_record': 99999, # ne postoji
'image': image,
'description': 'Invalid SR'
}
with self.assertRaises(DRFValidationError):
VehicleServicePhotoService.upload_photo(data=data, uploaded_by=self.uploader)
def test_update_photo_by_uploader_success(self):
"""
Test ažuriranja fotografije od strane korisnika koji ju je uploadao.
"""
image = create_test_image(filename="original.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="Original description",
uploaded_by=self.uploader
)
update_data = {'description': 'Updated description'}
updated_photo = VehicleServicePhotoService.update_photo(
instance=photo,
data=update_data,
user=self.uploader
)
self.assertEqual(updated_photo.description, 'Updated description')
photo.refresh_from_db()
self.assertEqual(photo.description, 'Updated description')
def test_update_photo_by_staff_success(self):
"""
Test ažuriranja fotografije od strane staff korisnika (može ažurirati bilo koju).
"""
image = create_test_image(filename="staff_update.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="Original",
uploaded_by=self.uploader
)
update_data = {'description': 'Staff updated'}
updated_photo = VehicleServicePhotoService.update_photo(
instance=photo,
data=update_data,
user=self.staff_user
)
self.assertEqual(updated_photo.description, 'Staff updated')
def test_update_photo_by_non_uploader_denied(self):
"""
Test — korisnik koji nije uploader niti staff ne može ažurirati.
"""
image = create_test_image(filename="denied_update.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="Original",
uploaded_by=self.uploader
)
update_data = {'description': 'Hacker attempt'}
with self.assertRaises(DRFValidationError):
VehicleServicePhotoService.update_photo(
instance=photo,
data=update_data,
user=self.other_user
)
def test_update_photo_without_user_denied(self):
"""
Test — ažuriranje bez korisnika (user=None) baca ValidationError.
"""
image = create_test_image(filename="no_user_update.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="Original",
uploaded_by=self.uploader
)
update_data = {'description': 'No auth'}
with self.assertRaises(DRFValidationError):
VehicleServicePhotoService.update_photo(
instance=photo,
data=update_data,
user=None
)
def test_delete_photo_by_uploader_success(self):
"""
Test soft-delete fotografije od strane korisnika koji ju je uploadao.
"""
image = create_test_image(filename="delete.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="To delete",
uploaded_by=self.uploader
)
self.assertTrue(photo.is_active)
deleted_photo = VehicleServicePhotoService.delete_photo(
instance=photo,
user=self.uploader
)
self.assertFalse(deleted_photo.is_active)
photo.refresh_from_db()
self.assertFalse(photo.is_active)
def test_delete_photo_by_staff_success(self):
"""
Test soft-delete od strane staff korisnika.
"""
image = create_test_image(filename="staff_delete.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="To delete",
uploaded_by=self.uploader
)
VehicleServicePhotoService.delete_photo(
instance=photo,
user=self.staff_user
)
photo.refresh_from_db()
self.assertFalse(photo.is_active)
def test_delete_photo_by_non_uploader_denied(self):
"""
Test — korisnik koji nije uploader niti staff ne može obrisati.
"""
image = create_test_image(filename="denied_delete.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="Original",
uploaded_by=self.uploader
)
with self.assertRaises(DRFValidationError):
VehicleServicePhotoService.delete_photo(
instance=photo,
user=self.other_user
)
# Fotografija je i dalje aktivna
photo.refresh_from_db()
self.assertTrue(photo.is_active)
def test_delete_photo_without_user_denied(self):
"""
Test — brisanje bez korisnika (user=None) baca ValidationError.
"""
image = create_test_image(filename="no_user_delete.jpg")
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image,
description="Original",
uploaded_by=self.uploader
)
with self.assertRaises(DRFValidationError):
VehicleServicePhotoService.delete_photo(
instance=photo,
user=None
)
photo.refresh_from_db()
self.assertTrue(photo.is_active)
def test_update_photo_does_not_allow_image_field_update(self):
"""
Test — update ne dozvoljava ponovno upload slike (ili je ignorirano).
Sadržaj image polja se ne mijenja ako je proslijeđen u update_data.
"""
image1 = create_test_image(filename="original.jpg", color='red')
photo = VehicleServicePhoto.objects.create(
service_record=self.service_record,
image=image1,
description="Original",
uploaded_by=self.uploader
)
original_image_name = photo.image.name
# Pokušaj update s novom slikom
image2 = create_test_image(filename="new.jpg", color='blue')
update_data = {
'description': 'Updated',
'image': image2
}
VehicleServicePhotoService.update_photo(
instance=photo,
data=update_data,
user=self.uploader
)
photo.refresh_from_db()
# image bi trebao biti preskočen (ne ažurira se)
self.assertEqual(photo.image.name, original_image_name)
self.assertEqual(photo.description, 'Updated')
def test_multiple_photos_for_same_service_record(self):
"""
Test — isti servisni zapis može imati više fotografija.
"""
image1 = create_test_image(filename="photo1.jpg", color='red')
image2 = create_test_image(filename="photo2.jpg", color='blue')
image3 = create_test_image(filename="photo3.jpg", color='green')
data1 = {'service_record': self.service_record, 'image': image1, 'description': 'Photo 1'}
data2 = {'service_record': self.service_record, 'image': image2, 'description': 'Photo 2'}
data3 = {'service_record': self.service_record, 'image': image3, 'description': 'Photo 3'}
photo1 = VehicleServicePhotoService.upload_photo(data=data1, uploaded_by=self.uploader)
photo2 = VehicleServicePhotoService.upload_photo(data=data2, uploaded_by=self.uploader)
photo3 = VehicleServicePhotoService.upload_photo(data=data3, uploaded_by=self.other_user)
photos = VehicleServicePhoto.objects.filter(service_record=self.service_record, is_active=True)
self.assertEqual(photos.count(), 3)
# Provjeri da su sve aktivne
for photo in [photo1, photo2, photo3]:
self.assertTrue(photo.is_active)