Files
mostovik-backend/tests/apps/core/test_bulk_operations.py
Aleksandr Meshchriakov f121445313 feat(core): add core module with mixins, services, and background jobs
- Add Model Mixins: TimestampMixin, SoftDeleteMixin, AuditMixin, etc.
- Add Base Services: BaseService, BulkOperationsMixin, QueryOptimizerMixin
- Add Base ViewSets with bulk operations
- Add BackgroundJob model for Celery task tracking
- Add BaseAppCommand for management commands
- Add permissions, pagination, filters, cache, logging
- Migrate tests to factory_boy + faker
- Add CHANGELOG.md
- 297 tests passing
2026-01-21 11:47:26 +01:00

187 lines
6.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Тесты для BulkOperationsMixin и QueryOptimizerMixin."""
from apps.core.models import BackgroundJob
from apps.core.services import (
BulkOperationsMixin,
QueryOptimizerMixin,
)
from django.test import TestCase
from faker import Faker
fake = Faker()
class BulkOperationsMixinTest(TestCase):
"""Тесты для BulkOperationsMixin."""
def test_mixin_has_bulk_create_chunked(self):
"""Проверка наличия метода bulk_create_chunked."""
self.assertTrue(hasattr(BulkOperationsMixin, "bulk_create_chunked"))
def test_mixin_has_bulk_update_or_create(self):
"""Проверка наличия метода bulk_update_or_create."""
self.assertTrue(hasattr(BulkOperationsMixin, "bulk_update_or_create"))
def test_mixin_has_bulk_delete(self):
"""Проверка наличия метода bulk_delete."""
self.assertTrue(hasattr(BulkOperationsMixin, "bulk_delete"))
def test_mixin_has_bulk_update_fields(self):
"""Проверка наличия метода bulk_update_fields."""
self.assertTrue(hasattr(BulkOperationsMixin, "bulk_update_fields"))
class QueryOptimizerMixinTest(TestCase):
"""Тесты для QueryOptimizerMixin."""
def test_mixin_has_get_optimized_queryset(self):
"""Проверка наличия метода get_optimized_queryset."""
self.assertTrue(hasattr(QueryOptimizerMixin, "get_optimized_queryset"))
def test_mixin_has_apply_optimizations(self):
"""Проверка наличия метода apply_optimizations."""
self.assertTrue(hasattr(QueryOptimizerMixin, "apply_optimizations"))
def test_mixin_has_get_list_queryset(self):
"""Проверка наличия метода get_list_queryset."""
self.assertTrue(hasattr(QueryOptimizerMixin, "get_list_queryset"))
def test_mixin_has_get_detail_queryset(self):
"""Проверка наличия метода get_detail_queryset."""
self.assertTrue(hasattr(QueryOptimizerMixin, "get_detail_queryset"))
def test_mixin_has_with_counts(self):
"""Проверка наличия метода with_counts."""
self.assertTrue(hasattr(QueryOptimizerMixin, "with_counts"))
def test_mixin_has_with_exists(self):
"""Проверка наличия метода with_exists."""
self.assertTrue(hasattr(QueryOptimizerMixin, "with_exists"))
def test_mixin_default_attributes(self):
"""Проверка атрибутов по умолчанию."""
self.assertEqual(QueryOptimizerMixin.select_related, [])
self.assertEqual(QueryOptimizerMixin.prefetch_related, [])
self.assertEqual(QueryOptimizerMixin.default_only, [])
self.assertEqual(QueryOptimizerMixin.default_defer, [])
class BulkOperationsIntegrationTest(TestCase):
"""Интеграционные тесты для bulk операций с BackgroundJob."""
def test_bulk_create_chunked(self):
"""Тест массового создания чанками."""
# Создаём тестовый сервис с BulkOperationsMixin
class TestService(BulkOperationsMixin):
model = BackgroundJob
# Создаём 10 объектов чанками по 3
jobs = [
BackgroundJob(
task_id=f"bulk-chunk-{i}",
task_name="test.bulk.task",
)
for i in range(10)
]
count = TestService.bulk_create_chunked(jobs, chunk_size=3)
self.assertEqual(count, 10)
# Проверяем что все созданы
self.assertEqual(BackgroundJob.objects.filter(task_name="test.bulk.task").count(), 10)
def test_bulk_delete(self):
"""Тест массового удаления."""
class TestService(BulkOperationsMixin):
model = BackgroundJob
# Создаём несколько задач
jobs = []
for i in range(5):
job = BackgroundJob.objects.create(
task_id=f"bulk-delete-{i}",
task_name="test.delete.task",
)
jobs.append(job)
# Удаляем первые 3
ids_to_delete = [j.pk for j in jobs[:3]]
deleted = TestService.bulk_delete(ids_to_delete)
self.assertEqual(deleted, 3)
self.assertEqual(BackgroundJob.objects.filter(task_name="test.delete.task").count(), 2)
def test_bulk_update_fields(self):
"""Тест массового обновления полей."""
class TestService(BulkOperationsMixin):
model = BackgroundJob
# Создаём задачи
for i in range(5):
BackgroundJob.objects.create(
task_id=f"bulk-update-{i}",
task_name="test.update.task",
progress=0,
)
# Обновляем все задачи этого типа
updated = TestService.bulk_update_fields(
filters={"task_name": "test.update.task"},
updates={"progress": 50},
)
self.assertEqual(updated, 5)
# Проверяем что обновились
for job in BackgroundJob.objects.filter(task_name="test.update.task"):
self.assertEqual(job.progress, 50)
def test_bulk_update_or_create_creates(self):
"""Тест upsert - создание новых."""
class TestService(BulkOperationsMixin):
model = BackgroundJob
items = [
{"task_id": "upsert-new-1", "task_name": "upsert.task", "progress": 10},
{"task_id": "upsert-new-2", "task_name": "upsert.task", "progress": 20},
]
created, updated = TestService.bulk_update_or_create(
items=items,
unique_fields=["task_id"],
update_fields=["task_name", "progress"],
)
self.assertEqual(created, 2)
self.assertEqual(updated, 0)
def test_bulk_update_or_create_updates(self):
"""Тест upsert - обновление существующих."""
class TestService(BulkOperationsMixin):
model = BackgroundJob
# Создаём существующую запись
BackgroundJob.objects.create(
task_id="upsert-existing",
task_name="old.task",
progress=0,
)
items = [
{"task_id": "upsert-existing", "task_name": "new.task", "progress": 100},
]
created, updated = TestService.bulk_update_or_create(
items=items,
unique_fields=["task_id"],
update_fields=["task_name", "progress"],
)
self.assertEqual(created, 0)
self.assertEqual(updated, 1)
# Проверяем обновление
job = BackgroundJob.objects.get(task_id="upsert-existing")
self.assertEqual(job.task_name, "new.task")
self.assertEqual(job.progress, 100)