Some checks failed
CI/CD Pipeline / Run Tests (push) Failing after 37s
CI/CD Pipeline / Code Quality Checks (push) Failing after 43s
CI/CD Pipeline / Build & Push Images (push) Has been skipped
CI/CD Pipeline / Deploy (dev) (push) Has been skipped
CI/CD Pipeline / Deploy (prod) (push) Has been skipped
CI/CD Pipeline / Code Quality Checks (pull_request) Failing after 0s
CI/CD Pipeline / Run Tests (pull_request) Failing after 0s
CI/CD Pipeline / Build & Push Images (pull_request) Has been skipped
CI/CD Pipeline / Deploy (dev) (pull_request) Has been skipped
CI/CD Pipeline / Deploy (prod) (pull_request) Has been skipped
- Обновлены клиенты парсеров (checko, fns, minpromtorg, proverki, zakupki) - Добавлены новые миграции для моделей - Расширено покрытие тестами - Обновлены конфигурации и настройки проекта - Добавлены утилиты для тестирования Co-Authored-By: Warp <agent@warp.dev>
233 lines
8.1 KiB
Python
233 lines
8.1 KiB
Python
"""Тесты для BulkOperationsMixin и QueryOptimizerMixin."""
|
||
|
||
from apps.core.models import BackgroundJob
|
||
from apps.core.services import (
|
||
BulkOperationsMixin,
|
||
QueryOptimizerMixin,
|
||
)
|
||
from django.contrib.auth import get_user_model
|
||
from django.db.models import OuterRef
|
||
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, [])
|
||
|
||
def test_optimizer_methods_execute(self):
|
||
User = get_user_model()
|
||
|
||
class UserService(QueryOptimizerMixin):
|
||
model = User
|
||
prefetch_related = ["groups"]
|
||
default_only = ["id", "email"]
|
||
default_defer = ["password"]
|
||
|
||
qs = UserService.get_optimized_queryset()
|
||
self.assertIsNotNone(qs)
|
||
|
||
qs_no_opts = UserService.apply_optimizations(
|
||
User.objects.all(),
|
||
include_select=False,
|
||
include_prefetch=False,
|
||
include_only=False,
|
||
include_defer=False,
|
||
)
|
||
self.assertIsNotNone(qs_no_opts)
|
||
|
||
qs_list = UserService.get_list_queryset()
|
||
qs_detail = UserService.get_detail_queryset()
|
||
self.assertIsNotNone(qs_list)
|
||
self.assertIsNotNone(qs_detail)
|
||
|
||
qs_counts = UserService.with_counts(User.objects.all(), "groups")
|
||
self.assertIsNotNone(qs_counts)
|
||
|
||
qs_exists = UserService.with_exists(
|
||
User.objects.all(),
|
||
has_self=User.objects.filter(pk=OuterRef("pk")),
|
||
)
|
||
self.assertIsNotNone(qs_exists)
|
||
|
||
|
||
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)
|