Files
ACORE/apps/it_manager/tests.py
T
lokses 4b61e78c16 Обновить тесты it_manager под каталог моделей оборудования
Тесты создавали Equipment со старыми полями type/model и били по
удалённому /equipment/create/. Переведены на EquipmentModel + массовый
ввод/выдачу (bulk-create/bulk-assign), добавлен тест массовой выдачи.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 20:55:51 +03:00

224 lines
8.8 KiB
Python

"""Тести IT-порталу: доступ через групу IT, інвентаризація обладнання
(зі списанням історії видачі), черга заявок, журнал робіт."""
from datetime import date
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.test import Client, TestCase
from apps.it_manager.models import (
Equipment, EquipmentAssignment, EquipmentModel, Ticket, WorkLog,
)
from core.models.directories import Directory
Employee = get_user_model()
_employee_seq = 0
def _dir_id(type_code, code):
"""Знаходить Directory.pk за (тип, код) — довідники засіяні data-міграціями конверсії choices."""
return Directory.objects.get(directory_type__code=type_code, code=code).id
def make_employee(**overrides):
global _employee_seq
_employee_seq += 1
defaults = {
'username': f'itman.user{_employee_seq}',
'email': f'itman.user{_employee_seq}@company.local',
'first_name': 'Тест',
'last_name': 'Співробітник',
'hire_date': date(2026, 1, 1),
'user_location_type': 'office',
'mattermost_sync_enabled': False,
'ad_sync_enabled': False,
}
defaults.update(overrides)
return Employee.objects.create(**defaults)
def make_equipment_model(**overrides):
defaults = {
'equipment_type_id': _dir_id('equipment_type', 'laptop'),
'name': 'ThinkPad T14',
}
defaults.update(overrides)
obj, _ = EquipmentModel.objects.get_or_create(**defaults)
return obj
def make_equipment(**overrides):
defaults = {
'equipment_model': make_equipment_model(),
'serial_number': f'SN-{Equipment.objects.count() + 1}',
}
defaults.update(overrides)
return Equipment.objects.create(**defaults)
class ItManagerAccessTests(TestCase):
"""Сторінка й усі мутації доступні лише групі IT (або суперюзеру)."""
def setUp(self):
self.outsider = make_employee()
self.client = Client()
self.client.force_login(self.outsider)
def test_page_forbidden_for_non_it(self):
r = self.client.get('/it-manager/')
self.assertEqual(r.status_code, 403)
def test_equipment_create_forbidden_for_non_it(self):
r = self.client.post('/it-manager/equipment/bulk-create/', {
'equipment_model_id': '1', 'serial_numbers': 'X1',
})
self.assertEqual(r.status_code, 403)
def test_worklog_create_forbidden_for_non_it(self):
r = self.client.post('/it-manager/worklog/create/', {
'work_type': 'repair', 'description': 'test',
})
self.assertEqual(r.status_code, 403)
class ItManagerEquipmentTests(TestCase):
def setUp(self):
self.it_user = make_employee(is_staff=False)
self.it_user.groups.add(Group.objects.get(name='IT'))
self.client = Client()
self.client.force_login(self.it_user)
def test_page_accessible_for_it_group(self):
r = self.client.get('/it-manager/')
self.assertEqual(r.status_code, 200)
def test_bulk_create_equipment(self):
model = make_equipment_model()
# масовий ввід: одна модель + список серійників (з дублем)
r = self.client.post('/it-manager/equipment/bulk-create/', {
'equipment_model_id': str(model.pk),
'serial_numbers': 'SN-100\nSN-101\nSN-101\nSN-102',
}, HTTP_HX_REQUEST='true')
self.assertEqual(r.status_code, 200)
units = Equipment.objects.filter(equipment_model=model)
self.assertEqual(units.count(), 3) # дубль SN-101 пропущено
self.assertEqual(
sorted(units.values_list('serial_number', flat=True)),
['SN-100', 'SN-101', 'SN-102'],
)
self.assertTrue(all(u.status.code == 'stock' for u in units))
def test_bulk_assign_equipment(self):
model = make_equipment_model()
units = [
Equipment.objects.create(equipment_model=model, serial_number=f'BA-{i}')
for i in range(3)
]
emp = make_employee()
r = self.client.post('/it-manager/equipment/bulk-assign/', {
'equipment_ids': [str(units[0].pk), str(units[1].pk)],
'assigned_to_id': str(emp.id),
}, HTTP_HX_REQUEST='true')
self.assertEqual(r.status_code, 200)
units[0].refresh_from_db(); units[1].refresh_from_db(); units[2].refresh_from_db()
self.assertEqual(units[0].assigned_to_id, emp.id)
self.assertEqual(units[0].status.code, 'assigned')
self.assertIsNone(units[2].assigned_to_id) # не відмічений — не чіпаємо
self.assertEqual(EquipmentAssignment.objects.filter(equipment__in=units[:2]).count(), 2)
def test_assign_equipment_creates_and_closes_history(self):
equipment = make_equipment()
emp1 = make_employee()
emp2 = make_employee()
self.client.post(f'/it-manager/equipment/{equipment.id}/update/', {
'status': 'assigned', 'assigned_to_id': emp1.id,
})
equipment.refresh_from_db()
self.assertEqual(equipment.assigned_to_id, emp1.id)
self.assertEqual(equipment.status.code, 'assigned')
self.assertEqual(EquipmentAssignment.objects.filter(equipment=equipment, returned_at__isnull=True).count(), 1)
self.client.post(f'/it-manager/equipment/{equipment.id}/update/', {
'status': 'assigned', 'assigned_to_id': emp2.id,
})
equipment.refresh_from_db()
self.assertEqual(equipment.assigned_to_id, emp2.id)
first_assignment = EquipmentAssignment.objects.get(equipment=equipment, assigned_to=emp1)
self.assertIsNotNone(first_assignment.returned_at)
self.assertEqual(
EquipmentAssignment.objects.filter(equipment=equipment, assigned_to=emp2, returned_at__isnull=True).count(), 1,
)
def test_unassign_equipment_closes_history_without_new_entry(self):
equipment = make_equipment()
emp1 = make_employee()
self.client.post(f'/it-manager/equipment/{equipment.id}/update/', {
'status': 'assigned', 'assigned_to_id': emp1.id,
})
self.client.post(f'/it-manager/equipment/{equipment.id}/update/', {
'status': 'stock', 'assigned_to_id': '',
})
equipment.refresh_from_db()
self.assertIsNone(equipment.assigned_to_id)
self.assertEqual(equipment.status.code, 'stock')
self.assertEqual(EquipmentAssignment.objects.filter(equipment=equipment, returned_at__isnull=True).count(), 0)
class ItManagerTicketTests(TestCase):
def setUp(self):
self.it_user = make_employee(is_staff=False)
self.it_user.groups.add(Group.objects.get(name='IT'))
self.requester = make_employee()
self.client = Client()
self.client.force_login(self.it_user)
def test_resolve_ticket_stamps_resolved_at(self):
ticket = Ticket.objects.create(
title='Не працює принтер', description='...',
ticket_type_id=_dir_id('ticket_type', 'repair'),
requester=self.requester,
)
self.client.post(f'/it-manager/tickets/{ticket.id}/update/', {
'status': 'resolved', 'assignee_id': self.it_user.id,
})
ticket.refresh_from_db()
self.assertEqual(ticket.status.code, 'resolved')
self.assertEqual(ticket.assignee_id, self.it_user.id)
self.assertIsNotNone(ticket.resolved_at)
def test_add_comment(self):
ticket = Ticket.objects.create(
title='Питання', description='...',
ticket_type_id=_dir_id('ticket_type', 'consultation'),
requester=self.requester,
)
r = self.client.post(f'/it-manager/tickets/{ticket.id}/comment/', {
'text': 'Дивимось', 'is_internal': 'on',
})
self.assertEqual(r.status_code, 200)
self.assertEqual(ticket.comments.count(), 1)
self.assertTrue(ticket.comments.first().is_internal)
class ItManagerWorkLogTests(TestCase):
def setUp(self):
self.it_user = make_employee(is_staff=False)
self.it_user.groups.add(Group.objects.get(name='IT'))
self.client = Client()
self.client.force_login(self.it_user)
def test_create_worklog(self):
r = self.client.post('/it-manager/worklog/create/', {
'work_type': 'maintenance', 'description': 'Профілактика серверної',
'hours_spent': '2.5',
})
self.assertEqual(r.status_code, 200)
log = WorkLog.objects.get(description='Профілактика серверної')
self.assertEqual(log.technician_id, self.it_user.id)
self.assertEqual(float(log.hours_spent), 2.5)