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
This commit is contained in:
2026-01-21 11:47:26 +01:00
parent 06b30fca02
commit f121445313
72 changed files with 9258 additions and 594 deletions

View File

@@ -0,0 +1,92 @@
"""Тесты для базового класса management commands."""
from io import StringIO
from apps.core.management.commands.base import BaseAppCommand
from django.core.management.base import CommandError
from django.test import TestCase
class TestCommand(BaseAppCommand):
"""Тестовая команда для проверки BaseAppCommand."""
help = "Test command"
def execute_command(self, *args, **options):
if options.get("fail"):
raise ValueError("Test error")
return "Success"
class BaseAppCommandTest(TestCase):
"""Тесты для BaseAppCommand."""
def test_base_command_has_dry_run_argument(self):
"""Проверка наличия аргумента --dry-run."""
cmd = BaseAppCommand()
parser = cmd.create_parser("manage.py", "test")
# Парсер должен принимать --dry-run
args = parser.parse_args(["--dry-run"])
self.assertTrue(args.dry_run)
def test_base_command_has_silent_argument(self):
"""Проверка наличия аргумента --silent."""
cmd = BaseAppCommand()
parser = cmd.create_parser("manage.py", "test")
args = parser.parse_args(["--silent"])
self.assertTrue(args.silent)
def test_log_methods_exist(self):
"""Проверка наличия методов логирования."""
cmd = BaseAppCommand()
cmd.stdout = StringIO()
cmd.stderr = StringIO()
cmd.silent = False
cmd.verbosity = 2
# Методы должны существовать и не падать
cmd.log_info("Test info")
cmd.log_success("Test success")
cmd.log_warning("Test warning")
cmd.log_error("Test error")
cmd.log_debug("Test debug")
def test_progress_iter(self):
"""Тест итератора с прогрессом."""
cmd = BaseAppCommand()
cmd.stdout = StringIO()
cmd.silent = True # Без вывода
items = list(range(10))
result = list(cmd.progress_iter(items, "Processing"))
self.assertEqual(result, items)
def test_confirm_in_dry_run(self):
"""Тест подтверждения в dry-run режиме."""
cmd = BaseAppCommand()
cmd.stdout = StringIO()
cmd.dry_run = True
cmd.silent = False
# В dry-run confirm всегда возвращает True
result = cmd.confirm("Continue?")
self.assertTrue(result)
def test_abort_raises_command_error(self):
"""Тест прерывания команды."""
cmd = BaseAppCommand()
with self.assertRaises(CommandError):
cmd.abort("Test abort")
def test_timed_operation(self):
"""Тест контекстного менеджера для измерения времени."""
cmd = BaseAppCommand()
cmd.stdout = StringIO()
cmd.verbosity = 2
with cmd.timed_operation("Test operation"):
pass # Операция
# Не должно падать