Files
mostovik-backend/tests/apps/core/test_bulk_operations.py
Aleksandr Meshchriakov ee95628a0a
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
feat: обновления парсеров, тестов и миграций
- Обновлены клиенты парсеров (checko, fns, minpromtorg, proverki, zakupki)
- Добавлены новые миграции для моделей
- Расширено покрытие тестами
- Обновлены конфигурации и настройки проекта
- Добавлены утилиты для тестирования

Co-Authored-By: Warp <agent@warp.dev>
2026-02-10 10:17:47 +01:00

233 lines
8.1 KiB
Python
Raw 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.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)