old_console/users/tests.py
2024-11-02 14:12:45 +03:00

621 lines
26 KiB
Python

import datetime
import json
import logging
from datetime import date, timedelta
from enum import Enum
import pytest
from django.contrib.auth.models import User
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ValidationError
from django.urls import reverse
from rest_framework import status
from console.tasks import expire_users
from core.utils import dtnow
from perms.models import Perm
from users.models import UserInfo
from users.services.userinfo import UserStatusService, InUserInfoStrategy
_log = logging.getLogger(__name__)
class MethodEnum(Enum):
GET = 0
HEAD = 1
POST = 3
PUT = 4
DELETE = 5
OPTIONS = 6
TRACE = 7
PATCH = 8
@pytest.fixture
def receive_url(client):
def _get(url, method=MethodEnum.GET, **kwargs):
if method == MethodEnum.GET:
return client.get(url, **kwargs)
elif method == MethodEnum.HEAD:
return client.head(url, **kwargs)
elif method == MethodEnum.POST:
return client.post(url, **kwargs, content_type="application/json")
elif method == MethodEnum.PUT:
return client.put(url, **kwargs, content_type="application/json")
elif method == MethodEnum.DELETE:
return client.delete(url, **kwargs)
elif method == MethodEnum.OPTIONS:
return client.options(url, **kwargs)
elif method == MethodEnum.TRACE:
return client.trace(url, **kwargs)
elif method == MethodEnum.PATCH:
return client.patch(url, **kwargs, content_type="application/json")
raise NotImplemented(f'Method {method} not implemented')
return _get
@pytest.fixture()
def create_user_info():
"""Return new user with userinfo"""
user = User.objects.create(username="Max", first_name="Pane", is_active=True)
UserInfo.objects.create(user=user, comment="New user Max Pane")
@pytest.fixture()
def create_users():
users_list = []
for item in range(5):
if item % 2 == 0:
username = f'deleted_{item}'
user = User.objects.create_user(username=username, is_active=False)
else:
username = f'user_{item}'
user = User.objects.create_user(username=username, is_active=False)
users_list.append(user)
for user in users_list:
UserInfo.objects.create(user=user, comment=f'{user.username}')
@pytest.mark.django_db
@pytest.fixture
def can_open_url(client, receive_url, add_user_with_permissions):
def _open(url: str, permissions: list, method=MethodEnum.GET, **kwargs):
username = 'user'
password = 'test'
user = add_user_with_permissions(username=username, password=password)
client.force_login(user)
if permissions:
response = receive_url(url=url, method=method, **kwargs)
assert response.status_code == status.HTTP_403_FORBIDDEN
user_1 = add_user_with_permissions(username=username + '1', password=password, permissions=permissions)
client.force_login(user_1)
response = receive_url(url=url, method=method, **kwargs)
assert response.status_code != status.HTTP_403_FORBIDDEN
return _open
test_args = [
('active-users-list', [MethodEnum.GET], [Perm.can_view_user_list]),
('active-users-list', [MethodEnum.POST], [Perm.can_add_user]),
('active-users-detail', [MethodEnum.GET], [Perm.can_view_user]),
('active-users-detail', [MethodEnum.PUT], [Perm.can_edit_user]),
('active-users-detail', [MethodEnum.PATCH], [Perm.can_edit_user]),
]
@pytest.mark.django_db
class TestUsers:
url_name_and_url_kwargs_map = {}
url_data_map = {} # data for POST, PATCH, PUT
@pytest.fixture(autouse=True)
def setup_test(self, add_user_with_permissions):
self.user = add_user_with_permissions(username='test_username1', password='testpwd', is_superuser=True)
self.url_name_and_url_kwargs_map['active-users-detail'] = {'pk': 1}
@pytest.mark.unit
def test_api_list(self, client, add_user_with_permissions, create_users):
user_count = User.objects.count()
user = add_user_with_permissions(username='user0', password='passwd12', is_superuser=True)
url = reverse('active-users-list')
client.force_login(user)
response = client.get(url)
data_json = response.json()
assert response.status_code == 200
assert len(data_json) == 4
assert len(data_json) != user_count
# Test skipped, because we have no permissions
@pytest.mark.skip
@pytest.mark.unit
@pytest.mark.parametrize("url, methods, permissions", test_args)
def test_permissions(self, url: str, methods: list, permissions: list, client, receive_url, get_url,
add_user_with_permissions, can_open_url):
url_kwargs = self.url_name_and_url_kwargs_map.get(url)
if url_kwargs:
_url = get_url(url, kwargs=url_kwargs)
else:
_url = get_url(url)
data = self.url_data_map.get(url, {})
for method in methods:
can_open_url(url=_url, method=method, permissions=permissions, **data)
@pytest.mark.unit
def test_user_details(self, client, add_user_with_permissions, create_user_info):
user = add_user_with_permissions(username='user0', password='passwd12', is_superuser=True)
url = reverse('active-users-detail', kwargs={"pk": User.objects.get(username='Max').pk})
client.force_login(user)
response = client.get(url)
data_json = response.json()
assert response.status_code == 200
assert data_json["user"]["username"] == "Max"
assert data_json["user"]["is_active"] == True
assert data_json["user"]["first_name"] == "Pane"
@pytest.mark.unit
def test_add_user(self, client, add_user_with_permissions, create_user_info):
url = reverse('active-users-list')
client.force_login(self.user)
users_before = User.objects.count()
data = {
"user": {
"username": "swaggeruserYYYYMMDD",
"first_name": "swagger_name",
"is_active": True,
"email": "swagger@mail.ru",
"password": "IamTheKingOfTheWorld1"
},
"comment": "asdasd",
"timezone": "Europe/Moscow",
"expire_date": "2030-10-10"
}
response = client.post(url, data=json.dumps(data), content_type="application/json")
assert response.status_code == 201
users_after = User.objects.count()
assert users_before != users_after
new_user = User.objects.get(username="swaggeruserYYYYMMDD")
info = UserInfo.objects.get(user=new_user)
assert new_user.first_name == 'swagger_name'
assert new_user.email == "swagger@mail.ru"
assert info.comment == "asdasd"
assert info.timezone == "Europe/Moscow"
assert new_user.is_superuser
assert new_user.is_staff
assert info.expire_date == datetime.date(2030, 10, 10)
client.logout()
response_ = client.post(reverse('api_login'), {"username": "swaggeruserYYYYMMDD",
"password": "IamTheKingOfTheWorld1"})
assert response_.wsgi_request.user.is_authenticated
url = reverse('active-users-detail', kwargs={"pk": User.objects.get(username='Max').pk})
response = client.get(url)
assert response.status_code == 200
@pytest.mark.unit
def test_add_user_bad_password(self, client, add_user_with_permissions, create_user_info):
url = reverse('active-users-list')
client.force_login(self.user)
users_before = User.objects.count()
data = {
"user": {
"username": "swagger_user_YYYY-MM-DD",
"first_name": "swagger_name",
"is_active": True,
"email": "swagger@mail.ru",
"password": "password"
},
"comment": "asdasd",
"timezone": "Europe/Moscow",
"expire_date": "2030-10-10"
}
response = client.post(url, data=json.dumps(data), content_type="application/json")
assert response.status_code == 400
assert users_before == User.objects.count()
@pytest.mark.unit
def test_add_user_bad_expire_date(self, client, add_user_with_permissions, create_user_info):
url = reverse('active-users-list')
client.force_login(self.user)
data = {
"user": {
"username": "userBadExpDate",
"first_name": "swagger_name",
"is_active": True,
"email": "swagger@mail.ru",
"password": "IamTheKingOfTheWorld1"
},
"comment": "asdasd",
"timezone": "Europe/Moscow",
"expire_date": "2000-10-10"
}
before = User.objects.count()
response = client.post(url, data=json.dumps(data), content_type="application/json")
assert response.status_code == 400
assert before == User.objects.count()
@pytest.mark.unit
def test_add_user_empty_first_name(self, api_client):
url = reverse('active-users-list')
api_client.force_authenticate(self.user)
data = {
"user": {
"username": "userBadExpDate",
"first_name": "",
"is_active": True,
"email": "swagger@mail.ru",
"password": "IamTheKingOfTheWorld1"
},
"comment": "asdasd",
"timezone": "Europe/Moscow",
"expire_date": "2000-10-10"
}
before = User.objects.count()
response = api_client.post(url, data=data, format='json')
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert 'first_name' in response.json()['user']
assert response.json()['user']['first_name'] == ['This field may not be blank.']
assert before == User.objects.count()
@pytest.mark.unit
def test_add_user_with_too_long_username(self, api_client, add_user_with_permissions):
url = reverse('active-users-list')
api_client.force_authenticate(self.user)
long_username = 'a' * 150
data = {
"user": {
"username": long_username,
"first_name": "swagger_name",
"is_active": True,
"email": "swagger@mail.ru",
"password": "IamTheKingOfTheWorld1"
},
"comment": "asdasd",
"timezone": "Europe/Moscow",
}
response = api_client.post(url, data=data, format="json")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()['user']['username'] == ["Ensure this field has no more than 131 characters."]
normal_username = 'a' * 131
data['user']['username'] = normal_username
response = api_client.post(url, data=data, format="json")
print(response.json())
assert response.status_code == status.HTTP_201_CREATED
@pytest.mark.unit
def test_edit_user_patch(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {"user": {"first_name": "user"}, "timezone": "Europe/Moscow"}
response = client.patch(url, data=data,
content_type="application/json", format="json")
edited_customer = User.objects.get(pk=customer.pk)
info = UserInfo.objects.get(user=edited_customer)
assert response.status_code == 200
assert edited_customer.username == 'Max'
assert edited_customer.first_name == "user"
assert edited_customer.is_active
@pytest.mark.unit
def test_edit_user_patch_good_expire_date(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {"user": {"first_name": "user"}, "expire_date": date.today() + timedelta(days=1),
"timezone": "Europe/Moscow"}
response = client.patch(url, data=data,
content_type="application/json", format="json")
edited_customer = User.objects.get(pk=customer.pk)
info = UserInfo.objects.get(user=edited_customer)
assert response.status_code == 200
assert edited_customer.username == 'Max'
assert edited_customer.first_name == "user"
assert edited_customer.is_active
@pytest.mark.unit
def test_edit_user_patch_bad_expire_date(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {"user": {"first_name": "user"}, "expire_date": date.today() - timedelta(days=1)}
response = client.patch(url, data=data,
content_type="application/json", format="json")
assert response.status_code == 400
@pytest.mark.unit
def test_edit_user_patch_today_expire_date(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {"user": {"first_name": "user"}, "expire_date": date.today()}
response = client.patch(url, data=data,
content_type="application/json", format="json")
assert response.status_code == 400
@pytest.mark.unit
def test_edit_user_without_user(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {"comment": "asdasdasd"}
response = client.patch(url, data=data,
content_type="application/json", format="json")
edited_customer = User.objects.get(pk=customer.pk)
info = UserInfo.objects.get(user=edited_customer)
assert response.status_code == 400
@pytest.mark.unit
def test_edit_user_patch_with_password(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {
"user": {"username": "Max", "first_name": "Ivan", "is_active": False, "password": "IamAlien2"},
"comment": "comment for new user", "timezone": "Europe/Moscow"}
response = client.patch(url, data=data,
content_type="application/json")
edited_customer = User.objects.get(pk=customer.pk)
response_ = client.post(reverse('api_login'), {"username": "Max", "password": "IamAlien2"})
assert response_.wsgi_request.user.is_authenticated == True
assert edited_customer.username == 'Max'
assert response.status_code == 200
assert edited_customer.first_name == "Ivan"
assert not edited_customer.is_active
client.logout()
@pytest.mark.unit
def test_edit_user_patch_with_bad_password(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {
"user": {"username": "Max", "first_name": "Ivan", "is_active": False, "password": "12345675"},
"comment": "comment for new user", "timezone": "Europe/Moscow"}
response = client.patch(url, data=data,
content_type="application/json", format="json")
assert response.status_code == 400
@pytest.mark.unit
def test_edit_user_patch_with_short_password(self, client, add_user_with_permissions, create_user_info):
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
client.force_login(self.user)
data = {
"user": {"username": "Max", "first_name": "Ivan", "is_active": False, "password": "Thepss1"},
"comment": "comment for new user", "timezone": "Europe/Moscow"}
response = client.patch(url, data=data,
content_type="application/json", format="json")
assert response.status_code == 400
@pytest.mark.unit
def test_edit_user_patch_with_previous_password(self, client, add_user_with_permissions):
user = add_user_with_permissions(username='user0', password='User1user!')
url = reverse('active-users-detail', kwargs={"pk": user.pk})
client.force_login(self.user)
data = {"user": {"password": "User1user!"}}
response = client.patch(url, data=data,
content_type="application/json", format="json")
assert response.status_code == 400
@pytest.mark.unit
def test_edit_user_with_too_long_username(self, api_client, add_user_with_permissions):
user = add_user_with_permissions(username='user0', password='User1user!')
url = reverse('active-users-detail', kwargs={"pk": user.pk})
api_client.force_authenticate(self.user)
long_username = 'a' * 150
data = {"user": {"username": long_username}}
response = api_client.patch(url, data=data, format="json")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()['user']['username'] == ["Ensure this field has no more than 131 characters."]
normal_username = 'a' * 131
data = {"user": {"username": normal_username}, 'timezone': 'Africa/Bangui'}
response = api_client.patch(url, data=data, format="json")
print(response.json())
assert response.status_code == status.HTTP_200_OK
@pytest.mark.unit
def test_delete_user(self, client, add_user_with_permissions, create_user_info):
operator = User.objects.get(username="Max")
client.force_login(self.user)
url = reverse('active-users-detail', kwargs={"pk": operator.pk})
response = client.delete(url)
assert response.status_code == 204
with pytest.raises(ObjectDoesNotExist):
User.objects.get(username="Max")
assert False
@pytest.mark.unit
def test_user_cannot_delete_himself(self, api_client):
api_client.force_authenticate(self.user)
url = reverse('active-users-detail', kwargs={"pk": self.user.pk})
response = api_client.delete(url)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json() == {'details': 'You cannot delete your account'}
@pytest.mark.unit
def test_admin_disable_himself(self, client, add_user_with_permissions, create_user_info):
admin = add_user_with_permissions(username='user007', password='passwd12', is_superuser=True)
url = reverse('active-users-detail', kwargs={"pk": admin.userinfo.pk})
client.force_login(admin)
data = {"user": {"is_active": False}}
response = client.patch(url, data=data,
content_type="application/json", format="json")
edited_admin = User.objects.get(pk=admin.pk)
assert response.status_code == 400
assert edited_admin.is_active
@pytest.mark.unit
def test_admin_disable_other(self, client, add_user_with_permissions, create_user_info):
admin = add_user_with_permissions(username='user007', password='passwd12', is_superuser=True)
url = reverse('active-users-detail', kwargs={"pk": admin.userinfo.pk})
client.force_login(self.user)
data = {"user": {"is_active": False}, "timezone": "Europe/Moscow"}
response = client.patch(url, data=data,
content_type="application/json", format="json")
edited_admin = User.objects.get(pk=admin.pk)
assert response.status_code == 200
assert not edited_admin.is_active
@pytest.mark.unit
def test_user_whoami(self, client, add_user_with_permissions, create_user_info):
url = reverse('active-users-whoami')
client.force_login(self.user)
response = client.get(url)
data_json = response.json()
assert response.status_code == 200
assert data_json["username"] == "test_username1"
def test_validate_username_create_user(self, client):
"""Test create user with bad username(with space and special symbol)."""
url = reverse('active-users-list')
client.force_login(self.user)
users_before = User.objects.count()
data = {
"user": {
"username": "username with space and +-#",
"first_name": "swagger_name",
"is_active": True,
"email": "swagger@mail.ru",
"password": "Pas123wordZ"
},
"comment": "asdasd",
"timezone": "Europe/Moscow",
"expire_date": "2030-10-10"
}
response = client.post(url, data=json.dumps(data), content_type="application/json")
assert response.status_code == 400
assert response.json() == {'user': ['The username must be contain only latin alphabet and digit, 0-9']}
@pytest.mark.unit
def test_edit_user_password(self, api_client, add_user_with_permissions, create_user_info):
api_client.force_authenticate(self.user)
customer = User.objects.get(username='Max')
url = reverse('active-users-detail', kwargs={"pk": customer.pk})
data = {
"user": {"username": "Max", "first_name": "Ivan", "is_active": False, "password": "IamAlien2"},
"comment": "comment for new user", "timezone": "Europe/Moscow"}
response = api_client.patch(url, data=data, format='json')
assert response.status_code == status.HTTP_200_OK
@pytest.mark.unit
def test_change_password_for_myself(self, api_client, add_user_with_permissions, create_user_info):
api_client.force_authenticate(self.user)
url = reverse('active-users-detail', kwargs={"pk": self.user.pk})
data = {
"user": {"username": "TESTTEST", "first_name": "Ivan", "password": "IamAlien2"},
"comment": "comment for new user", "timezone": "Europe/Moscow"}
response = api_client.patch(url, data=data, format='json')
assert response.status_code == status.HTTP_400_BAD_REQUEST # because old_password is required
data['user']['old_password'] = 'testpwd'
response = api_client.patch(url, data=data, format='json')
assert response.status_code == status.HTTP_200_OK
@pytest.mark.django_db
class TestUserExpire(object):
@pytest.mark.unit
def test_expiry(self):
""" Tests that user becomes disabled if their expire date has happened """
user_before_count = User.objects.filter(is_active=True).count()
user = User.objects.create_user(username='expired_active', is_active=True)
UserInfo(user=user, expire_date=dtnow(days=-3).date()).save()
user = User.objects.create_user(username='expired_not_active', is_active=False)
UserInfo(user=user, expire_date=dtnow(days=-1).date()).save()
user = User.objects.create_user(username='not_expired_active', is_active=True)
UserInfo(user=user, expire_date=dtnow(days=1).date()).save()
user = User.objects.create_user(username='not_expired_not_active', is_active=False)
UserInfo(user=user, expire_date=dtnow(days=3).date()).save()
user = User.objects.create_user(username='no_expire_active', is_active=True)
UserInfo(user=user).save()
user = User.objects.create_user(username='no_expire_not_active', is_active=False)
UserInfo(user=user).save()
assert User.objects.filter(is_active=True).count() == 3 + user_before_count
expire_users()
assert User.objects.filter(is_active=True).count() == 2 + user_before_count
@pytest.mark.django_db
class TestPasswordValidator:
@pytest.mark.uint
def test_password_validator(self):
passwords = [{'name': 'Short password', 'value': 'asdW567', 'expect': 'error', 'result': 'Not test'},
{'name': 'Only digit', 'value': '12345678', 'expect': 'error', 'result': 'Not test'},
{'name': 'No upper-case letter', 'value': '123qwert', 'expect': 'error', 'result': 'Not test'},
{'name': 'No lower-case letter', 'value': '123QWERT', 'expect': 'error', 'result': 'Not test'},
{'name': 'Good password', 'value': '123qweWW', 'expect': 'success', 'result': 'Not test'}]
test_result = True
for p in passwords:
try:
validate_password(p['value'], user=None)
if p['expect'] == 'error':
test_result = False
p['result'] = 'Bad'
else:
p['result'] = 'Ok'
except ValidationError:
if p['expect'] == 'success':
test_result = False
p['result'] = 'Bad'
else:
p['result'] = 'Ok'
_log.info(f"Test {p['name']}, expect {p['expect']}, result - {p['result']}")
assert test_result == True
def get_params(step):
params = (
(dtnow() - datetime.timedelta(minutes=2), 'offline'),
(dtnow(), 'online'),
(None, 'offline'),
)
return params[step]
@pytest.mark.django_db
@pytest.mark.unit
class TestUserStatusService:
@pytest.mark.parametrize('step', range(3))
def test_user_get_status_online_offline(self, step, add_user_with_permissions):
user = add_user_with_permissions(username='test_username_status', password='Testpwd!123*', is_superuser=True)
user.userinfo.last_seen = get_params(step)[0]
user.userinfo.save()
service = UserStatusService(user, strategy=InUserInfoStrategy)
assert service.get_status() == get_params(step)[1]