- Создан новый класс SystemCustomerProtectionTestCase с 5 критичными тестами - Тест создания системного клиента с правильными атрибутами - Тест защиты от удаления системного клиента (ValidationError) - Тест защиты email системного клиента от изменения - Тест защиты флага is_system_customer от изменения - Тест что обычные клиенты не затронуты защитой - Исправлена логика в Customer.save(): проверка теперь использует original.is_system_customer - Добавлен импорт ValidationError из django.core.exceptions - Рефакторинг структуры тестов customers: - Разделены тесты по отдельным модулям в папке customers/tests/ - test_search_strategies.py - тесты стратегий поиска - test_system_customer.py - тесты защиты системного клиента - test_wallet_balance.py - тесты баланса кошелька - test_wallet_service.py - тесты WalletService - test_wallet_model.py - тесты модели WalletTransaction - Обновлён анализ тестов: 50 тестов (было 45), все проходят успешно - Критичная функциональность POS системы теперь покрыта тестами - Учтена tenant-система (используется TenantTestCase)
136 lines
6.7 KiB
Python
136 lines
6.7 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
Тесты защиты системного клиента от изменений и удаления.
|
||
|
||
Системный клиент используется для анонимных продаж в POS системе
|
||
и должен быть защищён от случайного изменения или удаления.
|
||
|
||
Используем TenantTestCase для корректной работы с tenant-системой.
|
||
"""
|
||
from django.core.exceptions import ValidationError
|
||
from django_tenants.test.cases import TenantTestCase
|
||
|
||
from customers.models import Customer
|
||
|
||
|
||
class SystemCustomerProtectionTestCase(TenantTestCase):
|
||
"""
|
||
Тесты защиты системного клиента от изменений и удаления.
|
||
|
||
Системный клиент используется для анонимных продаж в POS системе
|
||
и должен быть защищён от случайного изменения или удаления.
|
||
"""
|
||
|
||
def setUp(self):
|
||
"""Создаём системного клиента для тестов."""
|
||
self.system_customer, created = Customer.get_or_create_system_customer()
|
||
self.regular_customer = Customer.objects.create(
|
||
name="Обычный клиент",
|
||
email="regular@test.com"
|
||
)
|
||
|
||
def test_get_or_create_system_customer_creates_with_correct_attributes(self):
|
||
"""
|
||
Метод get_or_create_system_customer() создаёт клиента с правильными атрибутами.
|
||
|
||
Проверяем:
|
||
- Фиксированный email: system@pos.customer
|
||
- Флаг is_system_customer = True
|
||
- Правильное имя и заметки
|
||
"""
|
||
# Удаляем существующего системного клиента для чистоты теста
|
||
Customer.objects.filter(is_system_customer=True).delete()
|
||
|
||
# Создаём через метод класса
|
||
customer, created = Customer.get_or_create_system_customer()
|
||
|
||
# Проверяем, что клиент действительно создан
|
||
self.assertTrue(created, "Системный клиент должен быть создан")
|
||
|
||
# Проверяем атрибуты
|
||
self.assertEqual(customer.email, "system@pos.customer")
|
||
self.assertTrue(customer.is_system_customer)
|
||
self.assertEqual(customer.name, "АНОНИМНЫЙ ПОКУПАТЕЛЬ (POS)")
|
||
self.assertIn("SYSTEM_CUSTOMER", customer.notes)
|
||
|
||
# Проверяем идемпотентность - повторный вызов возвращает того же клиента
|
||
customer2, created2 = Customer.get_or_create_system_customer()
|
||
self.assertFalse(created2, "Системный клиент не должен создаваться повторно")
|
||
self.assertEqual(customer.pk, customer2.pk, "Должен вернуться тот же клиент")
|
||
|
||
def test_system_customer_cannot_be_deleted(self):
|
||
"""
|
||
Системный клиент защищён от удаления через метод delete().
|
||
|
||
При попытке удаления должен подниматься ValidationError.
|
||
Это критично для работы POS системы.
|
||
"""
|
||
with self.assertRaises(ValidationError) as context:
|
||
self.system_customer.delete()
|
||
|
||
self.assertIn("Нельзя удалить системного клиента", str(context.exception))
|
||
|
||
# Проверяем, что клиент действительно не удалён
|
||
self.assertTrue(
|
||
Customer.objects.filter(pk=self.system_customer.pk).exists(),
|
||
"Системный клиент не должен быть удалён"
|
||
)
|
||
|
||
def test_system_customer_email_cannot_be_changed(self):
|
||
"""
|
||
Email системного клиента защищён от изменения.
|
||
|
||
Фиксированный email "system@pos.customer" используется для поиска
|
||
системного клиента в POS системе. Изменение приведёт к сбоям.
|
||
"""
|
||
original_email = self.system_customer.email
|
||
|
||
# Пытаемся изменить email
|
||
self.system_customer.email = "hacker@evil.com"
|
||
|
||
with self.assertRaises(ValidationError) as context:
|
||
self.system_customer.save()
|
||
|
||
self.assertIn("Нельзя изменить email системного клиента", str(context.exception))
|
||
|
||
# Проверяем, что email остался прежним в БД
|
||
self.system_customer.refresh_from_db()
|
||
self.assertEqual(self.system_customer.email, original_email)
|
||
|
||
def test_system_customer_flag_cannot_be_removed(self):
|
||
"""
|
||
Флаг is_system_customer защищён от изменения.
|
||
|
||
Нельзя "превратить" системного клиента в обычного,
|
||
это нарушит логику POS системы.
|
||
"""
|
||
# Пытаемся снять флаг системного клиента
|
||
self.system_customer.is_system_customer = False
|
||
|
||
with self.assertRaises(ValidationError) as context:
|
||
self.system_customer.save()
|
||
|
||
self.assertIn("Нельзя изменить флаг системного клиента", str(context.exception))
|
||
|
||
# Проверяем, что флаг остался True в БД
|
||
self.system_customer.refresh_from_db()
|
||
self.assertTrue(self.system_customer.is_system_customer)
|
||
|
||
def test_regular_customer_can_be_deleted_normally(self):
|
||
"""
|
||
Обычный клиент (не системный) может быть удалён без ограничений.
|
||
|
||
Защита применяется ТОЛЬКО к системному клиенту.
|
||
Это гарантирует, что мы не сломали обычный функционал удаления.
|
||
"""
|
||
customer_pk = self.regular_customer.pk
|
||
|
||
# Удаление должно пройти успешно
|
||
self.regular_customer.delete()
|
||
|
||
# Проверяем, что клиент действительно удалён
|
||
self.assertFalse(
|
||
Customer.objects.filter(pk=customer_pk).exists(),
|
||
"Обычный клиент должен быть удалён"
|
||
)
|