Yuriy Kulakov 0a85ddacd2 Merge branch 'develop' into feature/react_test
# Conflicts:
#	access_controller/settings.py
#	main/templates/pages/adm_ruleset.html
#	static/main/js/control.js
2021-05-27 19:35:59 +03:00

921 lines
50 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.

"""
Тестирование работы программы.
"""
import random
from unittest.mock import patch, Mock
from django.contrib.auth import get_user_model
from django.core import mail
from django.http import HttpResponseRedirect
from django.template.loader import render_to_string
from django.test import TestCase, Client
from django.urls import reverse, reverse_lazy
from django.utils import translation, timezone
import access_controller.settings as sets
from main.zendesk_admin import zenpy
from main.extra_func import log
class UsersBaseTestCase(TestCase):
"""
Базовый класс загрузки данных для тестов с пользователями.
Для тестов используются фикстуры тестовых пользователей (test_users.json).
"""
fixtures = ['fixtures/test_users.json']
def setUp(self) -> None:
"""
Функция предустановки значений переменных.
Добавляем email тестовых пользователей и создаем клиентов для тестов.
:param light_agent: email тестового пользователя с правами light_agent
:type light_agent: :class:`str`
:param engineer: email тестового пользователя с правами engineer
:type engineer: :class:`str`
:param admin: email тестового пользователя с правами admin
:type admin: :class:`str`
:param agent_client: клиент, залогиненный как пользователь с email light_agent
:type agent_client: :class:`django.test.client.Client`
:param engineer_client: клиент, залогиненный как пользователь с email engineer
:type engineer_client: :class:`django.test.client.Client`
:param admin_client: клиент, залогиненный как пользователь с email admin
:type admin_client: :class:`django.test.client.Client`
"""
self.light_agent = '123@test.ru'
self.admin = 'admin@gmail.com'
self.engineer = 'customer@example.com'
self.agent_client = Client()
self.agent_client.force_login(get_user_model().objects.get(email=self.light_agent))
self.admin_client = Client()
self.admin_client.force_login(get_user_model().objects.get(email=self.admin))
self.engineer_client = Client()
self.engineer_client.force_login(get_user_model().objects.get(email=self.engineer))
class RegistrationTestCase(TestCase):
"""
Класс тестирования регистрации.
Для тестов используются фикстуры с данными пользователей engineer и light_agent (data.json).
"""
fixtures = ['fixtures/data.json']
def setUp(self) -> None:
"""
Функция предустановки значений переменных.
Добавляем email тестовых пользователей и создаем клиентов для тестов.
:param email_backend: locmem бэкенд со списком отправленных писем
:type email_backend: :class:`str`
:param any_zendesk_user_email: email пользователя, зарегистрированного на Zendesk
:type any_zendesk_user_email: :class:`str`
:param zendesk_admin_email: email администратора
:type zendesk_admin_email: :class:`str`
:param client: новый клиент
:type client: :class:`django.test.client.Client`
"""
self.email_backend = 'django.core.mail.backends.locmem.EmailBackend'
self.any_zendesk_user_email = 'idar.sokurov.05@mail.ru'
self.zendesk_admin_email = 'idar.sokurov.05@mail.ru'
self.client = Client()
def test_registration_complete_redirect(self) -> None:
"""
Функция тестирования успешной регистрации пользователя.
Проверяет, что в случае если email пользователя зарегистрирован на Zendesk, была заполнена форма регистрации
и направлено письмо со ссылкой для завершения регистрации, происходит редирект на страницу завершения
регистрации.
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
resp = self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email})
self.assertRedirects(resp, reverse('password_reset_done'))
def test_registration_fail_redirect(self) -> None:
"""
Функция тестирования не успешной регистрации пользователя (введен email, не зарегистрированный на Zendesk).
Проверяет, что происходит редирект на страницу "registration disallowed"
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
resp = self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email + 'asd'})
self.assertRedirects(resp, reverse('django_registration_disallowed'))
def test_registration_user_already_exist(self) -> None:
"""
Функция тестирования попытки зарегистрироваться, используя email уже зарегистрированного в приложении
пользователя ("123@test.ru").
Проверяет, что пользователь получает сообщение "Этот адрес электронной почты уже используется"
"""
with self.settings(EMAIL_BACKEND=self.email_backend) and translation.override('ru'):
resp = self.client.post(reverse('registration'), data={'email': '123@test.ru'})
self.assertContains(resp, 'Этот адрес электронной почты уже используется', count=1, status_code=200)
def test_registration_send_email(self) -> None:
"""
Функция тестирования отправки email пользователю при регистрации.
Проверяет отправку уведомления на указанный пользователем адрес, а также содержание письма (заголовка и тела)
через email locmem backend.
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
response: HttpResponseRedirect = \
self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email})
self.assertEqual(response.status_code, 302)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.any_zendesk_user_email])
# context that the email template was rendered with
email_context = response.context[0].dicts[1]
correct_subject = render_to_string('registration/password_reset_subject.txt', email_context, response.request)
self.assertEqual(mail.outbox[0].subject, correct_subject.strip())
correct_body = render_to_string('registration/password_reset_email.html', email_context, response.request)
self.assertEqual(mail.outbox[0].body, correct_body)
def test_registration_user_creating(self) -> None:
"""
Функция тестирования создания пользователя приложения при регистрации.
Проверяет соответствие имени созданного пользователя с именем пользователя в Zendesk
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
self.client.post(reverse('registration'), data={'email': self.any_zendesk_user_email})
user = get_user_model().objects.get(email=self.any_zendesk_user_email)
zendesk_user = zenpy.get_user(self.any_zendesk_user_email)
self.assertEqual(user.userprofile.name, zendesk_user.name)
def test_permissions_applying(self) -> None:
"""
Функция тестирования создания администратора и присвоения ему соответствующих прав.
Проверяет, что у созданного пользователя роль "admin" и права "has_control_access".
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
self.client.post(reverse('registration'), data={'email': self.zendesk_admin_email})
user = get_user_model().objects.get(email=self.zendesk_admin_email)
self.assertEqual(user.userprofile.role, 'admin')
self.assertTrue(user.has_perm('main.has_control_access'))
class MakeEngineerTestCase(UsersBaseTestCase):
"""
Класс тестирования присвоения пользователю роли engineer.
В тестах используется @patch('main.extra_func.zenpy') Mock для работы с API Zendesk.
"""
@patch('main.extra_func.zenpy')
def test_become_engineer_redirect(self, _zenpy_mock: Mock) -> None:
"""
Функция тестирования редиректа на рабочую страницу тестового пользователя при назначении его инженером.
:param _zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
"""
user = get_user_model().objects.get(email=self.light_agent)
resp = self.agent_client.post(reverse_lazy('work_become_engineer'))
self.assertRedirects(resp, reverse('work', args=[user.id]))
self.assertEqual(resp.status_code, 302)
@patch('main.extra_func.zenpy')
def test_light_agent_make_engineer(self, zenpy_mock: Mock) -> None:
"""
Функция тестирования назначения легкого агента на роль инженера.
Проверяет установку роли "engineer" в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
"""
self.agent_client.post(reverse_lazy('work_become_engineer'))
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
@patch('main.extra_func.zenpy')
def test_admin_make_engineer(self, zenpy_mock: Mock) -> None:
"""
Функция тестирования назначения администратора на роль инженера.
Проверяет установку роли "engineer" в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
"""
self.admin_client.post(reverse_lazy('work_become_engineer'))
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
@patch('main.extra_func.zenpy')
def test_engineer_make_engineer(self, zenpy_mock: Mock) -> None:
"""
Функция тестирования назначения инженера на роль инженера.
Проверяет установку роли "engineer" в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
"""
self.engineer_client.post(reverse_lazy('work_become_engineer'))
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
@patch('main.extra_func.zenpy')
def test_control_page_make_engineer_one(self, zenpy_mock: Mock) -> None:
"""
Функция тестирования назначения администратором одного инженера на странице "Управление".
Проверяет обновление администратором роли пользователя с light_agent на engineer.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
"""
self.admin_client.post(
reverse_lazy('control'),
data={'users': [get_user_model().objects.get(email=self.light_agent).userprofile.id],
'engineer': 'engineer'}
)
call_list = zenpy_mock.update_user.call_args_list
mock_object = call_list[0][0][0]
self.assertEqual(len(call_list), 1)
self.assertEqual(mock_object.custom_role_id, sets.ZENDESK_ROLES['engineer'])
@patch('main.extra_func.zenpy')
def test_control_page_make_engineer_many(self, zenpy_mock: Mock) -> None:
"""
Функция тестирования назначения администратором нескольких инженеров на странице "Управление".
Проверяет обновление администратором ролей двух пользователей с light_agent на engineer.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
"""
self.admin_client.post(
reverse_lazy('control'),
data={
'users': [
get_user_model().objects.get(email=self.light_agent).userprofile.id,
get_user_model().objects.get(email=self.engineer).userprofile.id,
],
'engineer': 'engineer'
}
)
call_list = zenpy_mock.update_user.call_args_list
mock_objects = list(call_list)
self.assertEqual(len(call_list), 2)
for obj in mock_objects:
self.assertEqual(obj[0][0].custom_role_id, sets.ZENDESK_ROLES['engineer'])
class MakeLightAgentTestCase(UsersBaseTestCase):
"""
Класс тестирования присвоения пользователю роли light_agent.
В тестах используется @patch('main.extra_func.zenpy') Mock для работы API Zendesk, а также
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]]), предоставляющий пустой
список в качестве списка тикетов пользователя.
"""
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
@patch('main.extra_func.zenpy')
def test_hand_over_redirect(self, _zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования переадресации инженера на рабочую страницу, после сдачи прав.
:param _zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
user = get_user_model().objects.get(email=self.engineer)
resp = self.engineer_client.post(reverse_lazy('work_hand_over'))
self.assertRedirects(resp, reverse('work', args=[user.id]))
self.assertEqual(resp.status_code, 302)
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
@patch('main.extra_func.zenpy')
def test_engineer_make_light_agent_no_tickets(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования назначения инженера легким агентом, в случае, когда у него в работе нет тикетов.
Проверяет назначение роли light_agent в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
self.engineer_client.post(reverse_lazy('work_hand_over'))
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[
[Mock(id=1, status='solved'), Mock(id=2, status='open'), Mock(id=3, status='open')]
])
@patch('main.extra_func.zenpy')
def test_engineer_make_light_agent_with_tickets(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования назначения инженера легким агентом, в случае, когда у него в работе есть тикеты.
Для тестирования принимается, что в работе у инженера находится 3 тикета, один в состоянии: решен,
два в состоянии: открыт.
Проверяет распределение тикетов (поместить в решенные или назначить нового ответственного),
а также назначение роли light_agent в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
zenpy_mock.solved_tickets_user_id = Mock()
self.engineer_client.post(reverse_lazy('work_hand_over'))
tickets_update = zenpy_mock.admin.tickets.update.call_args[0][0]
self.assertEqual(tickets_update[0].assignee_id, zenpy_mock.solved_tickets_user_id)
self.assertIsNone(tickets_update[1].assignee)
self.assertIsNone(tickets_update[2].assignee)
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
@patch('main.extra_func.zenpy')
def test_admin_make_light_agent_no_tickets(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования назначения администратора на роль легкого агента.
Проверяет назначение роли light_agent в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
self.admin_client.post(reverse_lazy('work_hand_over'))
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[
[Mock(id=1, status='solved'), Mock(id=2, status='open'), Mock(id=3, status='open')]
])
@patch('main.extra_func.zenpy')
def test_admin_make_light_agent_with_tickets(self, zenpy_mock: zenpy, _user_tickets_mock: list) -> None:
"""
Функция тестирования назначения администратора легким агентом, в случае, когда у него в работе есть тикеты.
Для тестирования принимается, что в работе находится 3 тикета, один в состоянии: решен,
два в состоянии: открыт.
Проверяет распределение тикетов (поместить в решенные или назначить нового ответственного),
а также назначение роли light_agent в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
zenpy_mock.solved_tickets_user_id = Mock()
self.admin_client.post(reverse_lazy('work_hand_over'))
tickets_update = zenpy_mock.admin.tickets.update.call_args[0][0]
self.assertEqual(tickets_update[0].assignee_id, zenpy_mock.solved_tickets_user_id)
self.assertIsNone(tickets_update[1].assignee)
self.assertIsNone(tickets_update[2].assignee)
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
@patch('main.extra_func.zenpy')
def test_light_agent_make_light_agent(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования назначения легкого агента на роль легкого агента.
Проверяет назначение роли light_agent в Zendesk.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
self.agent_client.post(reverse_lazy('work_hand_over'))
self.assertEqual(zenpy_mock.update_user.call_args[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[]])
@patch('main.extra_func.zenpy')
def test_control_page_make_light_agent_one(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования назначения администратором одного легкого агента на странице "Управление".
Проверяет обновление администратором роли пользователя с engineer на light_agent.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
self.admin_client.post(
reverse_lazy('control'),
data={'users': [get_user_model().objects.get(email=self.engineer).userprofile.id],
'light_agent': 'light_agent'}
)
call_list = zenpy_mock.update_user.call_args_list
mock_object = call_list[0][0][0]
self.assertEqual(len(call_list), 1)
self.assertEqual(mock_object.custom_role_id, sets.ZENDESK_ROLES['light_agent'])
@patch('main.requester.TicketListRequester.get_tickets_list_for_user', side_effect=[[], []])
@patch('main.extra_func.zenpy')
def test_control_page_make_light_agent_many(self, zenpy_mock: Mock, _user_tickets_mock: Mock) -> None:
"""
Функция тестирования назначения администратором нескольких легких агентов на странице "Управление".
Проверяет обновление администратором ролей двух пользователей с engineer на light_agent.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param _user_tickets_mock: Mock, заменяющий список тикетов пользователя на пустой список.
"""
self.admin_client.post(
reverse_lazy('control'),
data={
'users': [
get_user_model().objects.get(email=self.light_agent).userprofile.id,
get_user_model().objects.get(email=self.engineer).userprofile.id,
],
'light_agent': 'light_agent'
}
)
call_list = zenpy_mock.update_user.call_args_list
mock_objects = list(call_list)
self.assertEqual(len(call_list), 2)
for obj in mock_objects:
self.assertEqual(obj[0][0].custom_role_id, sets.ZENDESK_ROLES['light_agent'])
class PasswordResetTestCase(UsersBaseTestCase):
"""
Класс тестирования сброса пароля.
"""
def setUp(self):
super().setUp()
self.email_backend = 'django.core.mail.backends.locmem.EmailBackend'
def test_redirect(self) -> None:
"""
Функция тестирования успешной смены пароля.
Проверяется переадресация на страницу завершения смены пароля, в случае, когда пользователь существует и на его
email было направлено письмо для сброса пароля.
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
resp = self.agent_client.post(reverse_lazy('password_reset'), data={'email': self.light_agent})
self.assertRedirects(resp, reverse('password_reset_done'))
self.assertEqual(resp.status_code, 302)
def test_send_email(self) -> None:
"""
Функция тестирования отправки email для сброса пароля.
Проверяет наличие отправленного письма, и его содержание, сверяет email адресата с email пользователя.
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
response: HttpResponseRedirect = \
self.agent_client.post(reverse_lazy('password_reset'), data={'email': self.light_agent})
self.assertEqual(response.status_code, 302)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.light_agent])
# context that the email template was rendered with
email_context = response.context[0].dicts[1]
correct_subject = render_to_string('registration/password_reset_subject.txt', email_context, response.request)
self.assertEqual(mail.outbox[0].subject, correct_subject.strip())
correct_body = render_to_string('registration/password_reset_email.html', email_context, response.request)
self.assertEqual(mail.outbox[0].body, correct_body)
def test_email_invalid(self) -> None:
"""
Функция тестирования попытки смены пароля с некорректным email.
Проверяет уведомление пользователя о неверном адресе электронной почты.
"""
with self.settings(EMAIL_BACKEND=self.email_backend) and translation.override('ru'):
resp = self.agent_client.post(reverse_lazy('password_reset'), data={'email': 1})
self.assertContains(resp, 'Введите правильный адрес электронной почты.', count=1, status_code=200)
def test_user_does_not_exist(self) -> None:
"""
Функция тестирования попытки смены пароля с email, который не зарегистрирован.
Проверяет отсутствие отправки письма о смене пароля.
"""
with self.settings(EMAIL_BACKEND=self.email_backend):
resp = self.agent_client.post(reverse_lazy('password_reset'),
data={'email': self.light_agent + str(random.random())})
self.assertRedirects(resp, reverse('password_reset_done'))
self.assertEqual(resp.status_code, 302)
self.assertEqual(len(mail.outbox), 0)
class PasswordChangeTestCase(UsersBaseTestCase):
"""
Класс тестирования смены пароля.
"""
def setUp(self) -> None:
super().setUp()
self.set_password()
def set_password(self) -> None:
"""
Функция предустанавливает тестовому пользователю с ролью light_agent пароль 'ImpossiblyHardPassword' и создает
клиента с соответствующими данным для тестирования.
"""
user = get_user_model().objects.get(email=self.light_agent)
user.set_password('ImpossiblyHardPassword')
user.save()
self.agent_client.force_login(get_user_model().objects.get(email=self.light_agent))
def test_change_successful(self) -> None:
"""
Функция тестирования успешной смены пароля.
Проверяет установку нового пароля пользователю при вводе корректных данных: старый пароль, новый пароль
(2 раза).
"""
self.agent_client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': 'EasyPassword',
'new_password2': 'EasyPassword',
}
)
user = get_user_model().objects.get(email=self.light_agent)
self.assertTrue(user.check_password('EasyPassword'))
def test_invalid_old_password(self) -> None:
"""
Функция тестирования смены пароля, при неверном вводе старого пароля.
Проверяет текст уведомления пользователя 'Ваш старый пароль введен неправильно'.
"""
with translation.override('ru'):
resp = self.agent_client.post(
reverse_lazy('password_change'),
data={
'old_password': 'EasyPassword',
'new_password1': 'EasyPassword',
'new_password2': 'EasyPassword',
}
)
self.assertContains(resp, 'Ваш старый пароль введен неправильно', count=1, status_code=200)
def test_different_new_passwords(self) -> None:
"""
Функция тестирования смены пароля, при вводе не совпадающих новых паролей.
Проверяет текст уведомления пользователя 'Введенные пароли не совпадают'.
"""
with translation.override('ru'):
resp = self.agent_client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': 'EasyPassword',
'new_password2': 'EasyPassword1',
}
)
self.assertContains(resp, 'Введенные пароли не совпадают', count=1, status_code=200)
def test_invalid_new_password1(self):
"""
Функция тестирования попытки смены пароля, когда новый пароль не соответствует требованиям: слишком короткий.
Проверяет текст уведомления пользователя 'Введённый пароль слишком короткий'.
"""
with translation.override('ru'):
resp = self.agent_client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': 'short',
'new_password2': 'short',
}
)
self.assertContains(resp, 'Введённый пароль слишком короткий', count=1, status_code=200)
def test_invalid_new_password2(self) -> None:
"""
Функция тестирования попытки смены пароля, когда новый пароль не соответствует требованиям: состоит
только из цифр.
Проверяет текст уведомления пользователя 'Введённый пароль состоит только из цифр'.
"""
with translation.override('ru'):
resp = self.agent_client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': '123123123123123123132123123',
'new_password2': '123123123123123123132123123',
}
)
self.assertContains(resp, 'Введённый пароль состоит только из цифр', count=1, status_code=200)
def test_invalid_new_password3(self):
"""
Функция тестирования попытки смены пароля, когда новый пароль не соответствует требованиям: аналогичен имени
пользователя.
Проверяет текст уведомления пользователя 'Введённый пароль слишком похож на имя пользователя'.
"""
with translation.override('ru'):
resp = self.agent_client.post(
reverse_lazy('password_change'),
data={
'old_password': 'ImpossiblyHardPassword',
'new_password1': self.light_agent,
'new_password2': self.light_agent,
}
)
self.assertContains(resp, 'Введённый пароль слишком похож на имя пользователя', count=1, status_code=200)
class GetTicketsTestCase(UsersBaseTestCase):
"""
Класс тестов для проверки функции получения тикетов.
В тестах используются @patch('main.views.zenpy.get_user') и @patch('main.views.zenpy.get_user')
для работы с API Zendesk.
"""
@patch('main.views.zenpy.get_user')
@patch('main.extra_func.zenpy')
def test_redirect(self, _zenpy_mock: Mock, get_user_mock: Mock) -> None:
"""
Функция проверки переадресации пользователя на рабочую страницу.
Проверяет редирект на рабочую страницу, в случае, когда пользователь с правами инженера заполняет форму
принятия тикетов в работу.
:param _zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param get_user_mock: Mock объекта zenpy_user.
"""
get_user_mock.return_value = Mock()
user = get_user_model().objects.get(email=self.engineer)
resp = self.engineer_client.post(reverse('work_get_tickets'))
self.assertRedirects(resp, reverse('work', args=[user.id]))
self.assertEqual(resp.status_code, 302)
@patch('main.views.zenpy')
@patch('main.views.get_tickets_list_for_group')
def test_take_one_ticket(self, group_tickets_mock: Mock, zenpy_mock: Mock) -> None:
"""
Функция проверки назначения одного тикета на engineer.
Проверяет соответствие ответственного за тикет объекта tickets и тестового клиента правами инженера,
направившего запрос на назначение одного тикета.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param group_tickets_mock: Mock списка не назначенных и нерешенных тикетов группы.
"""
group_tickets_mock.return_value = [Mock()]
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.engineer_client.post(reverse('work_get_tickets'), data={'count_tickets': 1})
tickets = zenpy_mock.update_tickets.call_args
self.assertEqual(tickets[0][0][0].assignee, zenpy_mock.get_user.return_value)
@patch('main.views.get_tickets_list_for_group')
@patch('main.views.zenpy')
def test_take_many_tickets(self, zenpy_mock: Mock, group_tickets_mock: Mock) -> None:
"""
Функция проверки назначения нескольких тикетов на engineer.
Проверяет соответствие ответственного за тикеты объекта tickets и тестового клиента правами инженера,
направившего запрос на назначение трех тикетов.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param group_tickets_mock: Mock списка не назначенных и нерешенных тикетов группы.
"""
group_tickets_mock.return_value = [Mock()] * 3
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.engineer_client.post(reverse('work_get_tickets'), data={'count_tickets': 3})
tickets = zenpy_mock.update_tickets.call_args
for ticket in tickets[0][0]:
self.assertEqual(ticket.assignee, zenpy_mock.get_user.return_value)
@patch('main.views.zenpy.get_user')
@patch('main.views.zenpy')
def test_light_agent_take_ticket(self, zenpy_mock: Mock, get_user_mock: Mock) -> None:
"""
Функция проверки попытки назначения тикета на light_agent.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param get_user_mock: Mock объекта zenpy_user.
"""
get_user_mock.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['light_agent'])
self.agent_client.post(reverse('work_get_tickets'), data={'count_tickets': 3})
tickets = zenpy_mock.update_tickets.call_args
self.assertIsNone(tickets)
@patch('main.views.zenpy')
@patch('main.views.get_tickets_list_for_group')
def test_take_zero_tickets(self, tickets_mock: Mock, zenpy_mock: Mock) -> None:
"""
Функция проверки попытки назначения нулевого количества тикетов.
Проверяет, что список тикетов остался пустым.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param tickets_mock: Mock списка тикетов - возвращает пустой список.
"""
tickets_mock.return_value = [Mock()] * 3
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.engineer_client.post(reverse('work_get_tickets'), data={'count_tickets': 0})
tickets = zenpy_mock.update_tickets.call_args[0][0]
self.assertListEqual(tickets, [])
@patch('main.views.get_tickets_list_for_group')
@patch('main.views.zenpy')
def test_take_invalid_count_tickets(self, zenpy_mock: Mock, group_tickets_mock: Mock) -> None:
"""
Функция проверки попытки назначения некорректного количества тикетов (введении в форму назначения тикетов
не числового значения, а строки).
Проверяет, отсутствие списка тикетов.
:param zenpy_mock: Mock объекта zenpy для функций, работающих с API Zendesk.
:param group_tickets_mock: Mock списка не назначенных и нерешенных тикетов группы.
"""
group_tickets_mock.return_value = [Mock()] * 3
zenpy_mock.get_user.return_value = Mock(role='agent', custom_role_id=sets.ZENDESK_ROLES['engineer'])
self.engineer_client.post(reverse('work_get_tickets'), data={'count_tickets': 'asd'})
tickets = zenpy_mock.update_tickets.call_args
self.assertIsNone(tickets)
class ProfileTestCase(TestCase):
"""
Класс тестов для проверки синхронизации профиля пользователя.
Для тестов используются фикстуры тестовых пользователей (profile.json).
"""
fixtures = ['fixtures/profile.json']
def setUp(self) -> None:
"""
Функция предустановки значений переменных.
Добавляем email тестовых пользователей Zendesk и создаем клиентов для тестов.
:param zendesk_agent_email: email тестового пользователя с правами light_agent
:type zendesk_agent_email: :class:`str`
:param zendesk_admin_email: email тестового пользователя с правами admin
:type zendesk_admin_email: :class:`str`
:param client: клиент, залогиненный как пользователь с email zendesk_agent_email
:type client: :class:`django.test.client.Client`
:param admin_client: клиент, залогиненный как пользователь с zendesk_admin_email
:type admin_client: :class:`django.test.client.Client`
"""
self.zendesk_agent_email = 'krav-88@mail.ru'
self.zendesk_admin_email = 'idar.sokurov.05@mail.ru'
self.client = Client()
self.client.force_login(get_user_model().objects.get(email=self.zendesk_agent_email))
self.admin_client = Client()
self.admin_client.force_login(get_user_model().objects.get(email=self.zendesk_admin_email))
def test_correct_username(self) -> None:
"""
Функция проверки синхронизации имени пользователя.
Проверяет соответствие имени пользователя из контекста страницы профиля имени пользователя в Zendesk.
"""
resp = self.client.get(reverse('profile'))
self.assertEqual(resp.context['profile'].name, zenpy.get_user(self.zendesk_agent_email).name)
def test_correct_email(self) -> None:
"""
Функция проверки синхронизации почты пользователя.
Проверяет соответствие email пользователя из контекста страницы профиля email пользователя в Zendesk.
"""
resp = self.client.get(reverse('profile'))
self.assertEqual(resp.context['profile'].user.email, zenpy.get_user(self.zendesk_agent_email).email)
def test_correct_role(self) -> None:
"""
Функция проверки синхронизации роли пользователя.
Проверяет соответствие роли пользователя из контекста страницы профиля роли пользователя в Zendesk. Проверка
осуществляется на примере администратора и агента.
"""
resp = self.client.get(reverse('profile'))
self.assertEqual(resp.context['profile'].role, zenpy.get_user(self.zendesk_agent_email).role)
resp = self.admin_client.get(reverse('profile'))
self.assertEqual(resp.context['profile'].role, zenpy.get_user(self.zendesk_admin_email).role)
def test_correct_custom_role_id(self) -> None:
"""
Функция проверки синхронизации рабочей роли пользователя.
Проверяет соответствие id рабочей роли пользователя из контекста страницы профиля id
роли пользователя в Zendesk. Проверка осуществляется на примере администратора и агента.
"""
resp = self.client.get(reverse('profile'))
user = zenpy.get_user(self.zendesk_agent_email)
self.assertEqual(resp.context['profile'].custom_role_id, user.custom_role_id if user.custom_role_id else 0)
resp = self.admin_client.get(reverse('profile'))
user = zenpy.get_user(self.zendesk_admin_email)
self.assertEqual(resp.context['profile'].custom_role_id, user.custom_role_id if user.custom_role_id else 0)
def test_correct_image(self) -> None:
"""
Функция проверки синхронизации изображения пользователя.
Проверяет соответствие аватарки пользователя из контекста страницы профиля аватарке пользователя в Zendesk.
"""
resp = self.client.get(reverse('profile'))
user = zenpy.get_user(self.zendesk_agent_email)
self.assertEqual(resp.context['profile'].image, user.photo['content_url'] if user.photo else None)
class LoggingTestCase(UsersBaseTestCase):
"""
Класс тестирования процесса логгирования.
"""
def setUp(self) -> None:
"""
Функция предустановки значений переменных.
Определяем профили пользователей с разными ролями.
:param admin_profile: профиль тестового пользователя с правами admin
:type admin_profile: :class:`Userprofile`
:param agent_profile: профиль тестового пользователя с правами light_agent
:type agent_profile: :class:`Userprofile`
:param engineer_profile: профиль тестового пользователя с правами engineer
:type engineer_profile: :class:`Userprofile`
"""
super().setUp()
self.admin_profile = get_user_model().objects.get(email=self.admin).userprofile
self.agent_profile = get_user_model().objects.get(email=self.light_agent).userprofile
self.engineer_profile = get_user_model().objects.get(email=self.engineer).userprofile
@staticmethod
def get_file_output() -> str:
"""
Получение данных из файла логов.
"""
with open('logs/logs.csv', 'r') as file:
file_output = file.readlines()[-1]
return file_output
def test_engineer_with_admin(self) -> None:
"""
Функция проверки корректной записи лога по смене роли инженера в файл.
Сравнивает запись в файле и созданный лог с переданными значениями профилей инженера и администратора
для смены прав.
"""
log(self.engineer_profile, self.admin_profile)
file_output = self.get_file_output()
self.assertEqual(file_output, f'UserForAccessTest,engineer,'
f'{str(timezone.now().today())[:16]},ZendeskAdmin\n')
def test_engineer_without_admin(self) -> None:
"""
Функция проверки корректной записи лога по смене роли инженера в файл без указания администратора.
Сравнивает запись в файле и созданный лог с переданным значением профиля инженера для смены прав.
"""
log(self.engineer_profile)
file_output = self.get_file_output()
self.assertEqual(file_output, f'UserForAccessTest,engineer,'
f'{str(timezone.now().today())[:16]},UserForAccessTest\n')
def test_light_agent_with_admin(self) -> None:
"""
Функция проверки корректной записи лога по смене роли агента в файл.
Сравнивает запись в файле и созданный лог с переданными значениями профилей агента и администратора
для смены прав.
"""
log(self.agent_profile, self.admin_profile)
file_output = self.get_file_output()
self.assertEqual(file_output, f'UserForAccessTest,light_agent,'
f'{str(timezone.now().today())[:16]},ZendeskAdmin\n')
def test_light_agent_without_admin(self) -> None:
"""
Функция проверки корректной записи лога по смене роли агента в файл без указания администратора.
Сравнивает запись в файле и созданный лог с переданным значением профиля агента для смены прав.
"""
log(self.agent_profile)
file_output = self.get_file_output()
self.assertEqual(file_output, f'UserForAccessTest,light_agent,'
f'{str(timezone.now().today())[:16]},UserForAccessTest\n')
class ControlAccessTests(TestCase):
"""
Класс тестов для проверки доступа к странице управления
"""
fixtures = ['fixtures/data.json']
def setUp(self) -> None:
self.User = get_user_model()
self.client = Client()
def test_admin_has_perm(self):
self.client.force_login(self.User.objects.get(email='admin@gmail.com'))
self.response = self.client.get(reverse('control'))
self.assertEqual(self.response.status_code, 200)
def test_engineer_doesnt_have_perm(self):
self.client.force_login(self.User.objects.get(email='123@test.ru'))
self.response = self.client.get(reverse('control'))
self.assertEqual(self.response.status_code, 403)