Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Failing after 1m42s
CI/CD Pipeline / Run Tests (push) Successful in 1m45s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped
CI/CD Pipeline / Deploy to Server (push) Has been skipped
395 lines
14 KiB
Python
395 lines
14 KiB
Python
"""Tests for user serializers"""
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
from apps.core.models import BackgroundJob, JobStatus
|
|
from apps.user.serializers import (
|
|
CurrentUserProfileSerializer,
|
|
CurrentUserSerializer,
|
|
LoginSerializer,
|
|
PasswordChangeSerializer,
|
|
ProfileUpdateSerializer,
|
|
TokenSerializer,
|
|
UserManagementSerializer,
|
|
UserRegistrationSerializer,
|
|
UserSerializer,
|
|
UserUpdateSerializer,
|
|
)
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase
|
|
from django.utils import timezone
|
|
from faker import Faker
|
|
|
|
from .factories import ProfileFactory, UserFactory
|
|
|
|
User = get_user_model()
|
|
fake = Faker("ru_RU")
|
|
|
|
|
|
class UserRegistrationSerializerTest(TestCase):
|
|
"""Tests for UserRegistrationSerializer"""
|
|
|
|
def setUp(self):
|
|
self.password = fake.password(length=12, special_chars=False)
|
|
self.user_data = {
|
|
"email": fake.unique.email(),
|
|
"username": fake.unique.user_name(),
|
|
"password": self.password,
|
|
"password_confirm": self.password,
|
|
"phone": f"+7{fake.numerify('##########')}",
|
|
}
|
|
|
|
def test_valid_registration_data(self):
|
|
"""Test valid registration data"""
|
|
serializer = UserRegistrationSerializer(data=self.user_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_passwords_do_not_match(self):
|
|
"""Test validation fails when passwords don't match"""
|
|
data = self.user_data.copy()
|
|
data["password_confirm"] = fake.password(length=12, special_chars=False)
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("non_field_errors", serializer.errors)
|
|
|
|
def test_short_password(self):
|
|
"""Test validation fails with short password"""
|
|
short_password = fake.pystr(min_chars=3, max_chars=5)
|
|
data = self.user_data.copy()
|
|
data["password"] = short_password
|
|
data["password_confirm"] = short_password
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("password", serializer.errors)
|
|
|
|
def test_duplicate_email(self):
|
|
"""Test validation fails with duplicate email"""
|
|
existing_user = UserFactory.create_user()
|
|
data = self.user_data.copy()
|
|
data["email"] = existing_user.email
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("email", serializer.errors)
|
|
|
|
def test_duplicate_username(self):
|
|
"""Test validation fails with duplicate username"""
|
|
existing_user = UserFactory.create_user()
|
|
data = self.user_data.copy()
|
|
data["username"] = existing_user.username
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("username", serializer.errors)
|
|
|
|
def test_create_user(self):
|
|
"""Test user creation through serializer"""
|
|
serializer = UserRegistrationSerializer(data=self.user_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
user = serializer.save()
|
|
|
|
self.assertIsInstance(user, User)
|
|
self.assertEqual(user.email, self.user_data["email"])
|
|
self.assertEqual(user.username, self.user_data["username"])
|
|
self.assertTrue(user.check_password(self.user_data["password"]))
|
|
|
|
|
|
class UserSerializerTest(TestCase):
|
|
"""Tests for UserSerializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
ProfileFactory.create_profile(user=self.user)
|
|
|
|
def test_user_serialization(self):
|
|
"""Test user serialization"""
|
|
serializer = UserSerializer(self.user)
|
|
data = serializer.data
|
|
|
|
self.assertEqual(data["id"], self.user.id)
|
|
self.assertEqual(data["email"], self.user.email)
|
|
self.assertEqual(data["username"], self.user.username)
|
|
self.assertEqual(data["phone"], self.user.phone)
|
|
self.assertEqual(data["is_verified"], self.user.is_verified)
|
|
self.assertIn("profile", data)
|
|
self.assertIn("created_at", data)
|
|
self.assertIn("updated_at", data)
|
|
|
|
def test_read_only_fields(self):
|
|
"""Test that read-only fields are not writable"""
|
|
read_only_fields = ["id", "is_verified", "created_at", "updated_at"]
|
|
serializer = UserSerializer()
|
|
|
|
for field_name in read_only_fields:
|
|
self.assertIn(field_name, serializer.Meta.read_only_fields)
|
|
|
|
|
|
class CurrentUserProfileSerializerTest(TestCase):
|
|
"""Tests for current user profile serializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
self.profile = ProfileFactory.create_profile(
|
|
user=self.user,
|
|
first_name="Ivan",
|
|
mid_name=None,
|
|
last_name="Petrov",
|
|
)
|
|
|
|
def test_middle_name_falls_back_to_empty_string(self):
|
|
serializer = CurrentUserProfileSerializer(self.profile)
|
|
|
|
self.assertEqual(serializer.data["middle_name"], "")
|
|
|
|
|
|
class CurrentUserSerializerTest(TestCase):
|
|
"""Tests for current user serializer fields."""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
|
|
def test_current_user_contains_is_active(self):
|
|
serializer = CurrentUserSerializer(self.user)
|
|
|
|
self.assertIn("is_active", serializer.data)
|
|
self.assertEqual(serializer.data["is_active"], self.user.is_active)
|
|
|
|
|
|
class UserManagementSerializerTest(TestCase):
|
|
"""Tests for user management serializer."""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
self.user.profile.first_name = None
|
|
self.user.profile.mid_name = None
|
|
self.user.profile.last_name = None
|
|
self.user.profile.save()
|
|
|
|
def test_profile_fields_fallback_to_empty_string(self):
|
|
serializer = UserManagementSerializer(self.user)
|
|
|
|
self.assertEqual(serializer.data["first_name"], "")
|
|
self.assertEqual(serializer.data["middle_name"], "")
|
|
self.assertEqual(serializer.data["last_name"], "")
|
|
|
|
def test_metric_fields_are_derived_from_latest_job(self):
|
|
now = timezone.make_aware(datetime(2026, 4, 14, 10, 0, 0))
|
|
latest_job = BackgroundJob.objects.create(
|
|
task_id="admin-management-latest",
|
|
task_name="apps.forms.process",
|
|
user_id=self.user.id,
|
|
status=JobStatus.SUCCESS,
|
|
progress=100,
|
|
progress_message="Готово",
|
|
result={"processed": 10},
|
|
started_at=now,
|
|
completed_at=now + timedelta(minutes=3),
|
|
created_at=now,
|
|
updated_at=now + timedelta(minutes=3),
|
|
)
|
|
BackgroundJob.objects.create(
|
|
task_id="admin-management-old",
|
|
task_name="apps.forms.process",
|
|
user_id=self.user.id,
|
|
status=JobStatus.FAILURE,
|
|
progress=100,
|
|
progress_message="Ошибка",
|
|
error="old-error",
|
|
started_at=now - timedelta(minutes=15),
|
|
completed_at=now - timedelta(minutes=10),
|
|
created_at=now - timedelta(minutes=15),
|
|
updated_at=now - timedelta(minutes=10),
|
|
)
|
|
self.user.latest_job = latest_job
|
|
|
|
serializer = UserManagementSerializer(self.user)
|
|
|
|
self.assertEqual(serializer.data["progress_message"], "Готово")
|
|
self.assertEqual(serializer.data["result"], {"processed": 10})
|
|
self.assertIsNone(serializer.data["error"])
|
|
self.assertEqual(serializer.data["is_successful"], True)
|
|
self.assertEqual(serializer.data["duration"], 180.0)
|
|
|
|
|
|
class UserUpdateSerializerTest(TestCase):
|
|
"""Tests for UserUpdateSerializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
|
|
def test_valid_update_data(self):
|
|
"""Test valid update data"""
|
|
update_data = {
|
|
"username": fake.unique.user_name(),
|
|
"phone": f"+7{fake.numerify('##########')}",
|
|
}
|
|
|
|
serializer = UserUpdateSerializer(self.user, data=update_data, partial=True)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
updated_user = serializer.save()
|
|
self.assertEqual(updated_user.username, update_data["username"])
|
|
self.assertEqual(updated_user.phone, update_data["phone"])
|
|
|
|
def test_fields_allowed(self):
|
|
"""Test only allowed fields can be updated"""
|
|
serializer = UserUpdateSerializer()
|
|
allowed_fields = ["username", "phone"]
|
|
|
|
self.assertEqual(set(serializer.Meta.fields), set(allowed_fields))
|
|
|
|
|
|
class ProfileUpdateSerializerTest(TestCase):
|
|
"""Tests for ProfileUpdateSerializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
self.profile = ProfileFactory.create_profile(user=self.user)
|
|
|
|
def test_valid_profile_update_data(self):
|
|
"""Test valid profile update data"""
|
|
update_data = {
|
|
"first_name": fake.first_name(),
|
|
"mid_name": fake.first_name(),
|
|
"last_name": fake.last_name(),
|
|
"bio": fake.text(max_nb_chars=200),
|
|
"date_of_birth": str(fake.date_of_birth(minimum_age=18, maximum_age=80)),
|
|
}
|
|
|
|
serializer = ProfileUpdateSerializer(
|
|
self.profile, data=update_data, partial=True
|
|
)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
updated_profile = serializer.save()
|
|
self.assertEqual(updated_profile.first_name, update_data["first_name"])
|
|
self.assertEqual(updated_profile.mid_name, update_data["mid_name"])
|
|
self.assertEqual(updated_profile.last_name, update_data["last_name"])
|
|
self.assertEqual(updated_profile.bio, update_data["bio"])
|
|
|
|
def test_fields_allowed(self):
|
|
"""Test only allowed fields can be updated"""
|
|
serializer = ProfileUpdateSerializer()
|
|
allowed_fields = [
|
|
"first_name",
|
|
"mid_name",
|
|
"last_name",
|
|
"bio",
|
|
"avatar",
|
|
"date_of_birth",
|
|
]
|
|
|
|
self.assertEqual(set(serializer.Meta.fields), set(allowed_fields))
|
|
|
|
|
|
class LoginSerializerTest(TestCase):
|
|
"""Tests for LoginSerializer"""
|
|
|
|
def setUp(self):
|
|
self.login_data = {
|
|
"username": fake.user_name(),
|
|
"password": fake.password(length=12, special_chars=False),
|
|
}
|
|
|
|
def test_valid_login_data(self):
|
|
"""Test valid login data"""
|
|
serializer = LoginSerializer(data=self.login_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_missing_username(self):
|
|
"""Test validation fails without username"""
|
|
data = {"password": fake.password(length=12, special_chars=False)}
|
|
serializer = LoginSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("username", serializer.errors)
|
|
|
|
def test_missing_password(self):
|
|
"""Test validation fails without password"""
|
|
data = {"username": fake.user_name()}
|
|
serializer = LoginSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("password", serializer.errors)
|
|
|
|
|
|
class TokenSerializerTest(TestCase):
|
|
"""Tests for TokenSerializer"""
|
|
|
|
def test_valid_token_data(self):
|
|
"""Test valid token data"""
|
|
token_data = {
|
|
"access": fake.pystr(min_chars=50, max_chars=100),
|
|
"refresh": fake.pystr(min_chars=50, max_chars=100),
|
|
}
|
|
|
|
serializer = TokenSerializer(data=token_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_missing_access_token(self):
|
|
"""Test validation fails without access token"""
|
|
data = {"refresh": fake.pystr(min_chars=50, max_chars=100)}
|
|
serializer = TokenSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("access", serializer.errors)
|
|
|
|
def test_missing_refresh_token(self):
|
|
"""Test validation fails without refresh token"""
|
|
data = {"access": fake.pystr(min_chars=50, max_chars=100)}
|
|
serializer = TokenSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("refresh", serializer.errors)
|
|
|
|
|
|
class PasswordChangeSerializerTest(TestCase):
|
|
"""Tests for PasswordChangeSerializer"""
|
|
|
|
def setUp(self):
|
|
self.old_password = fake.password(length=12, special_chars=False)
|
|
self.new_password = fake.password(length=12, special_chars=False)
|
|
self.password_data = {
|
|
"old_password": self.old_password,
|
|
"new_password": self.new_password,
|
|
"new_password_confirm": self.new_password,
|
|
}
|
|
|
|
def test_valid_password_change_data(self):
|
|
"""Test valid password change data"""
|
|
serializer = PasswordChangeSerializer(data=self.password_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_passwords_do_not_match(self):
|
|
"""Test validation fails when new passwords don't match"""
|
|
data = self.password_data.copy()
|
|
data["new_password_confirm"] = fake.password(length=12, special_chars=False)
|
|
|
|
serializer = PasswordChangeSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("non_field_errors", serializer.errors)
|
|
|
|
def test_short_new_password(self):
|
|
"""Test validation fails with short new password"""
|
|
short_password = fake.pystr(min_chars=3, max_chars=5)
|
|
data = self.password_data.copy()
|
|
data["new_password"] = short_password
|
|
data["new_password_confirm"] = short_password
|
|
|
|
serializer = PasswordChangeSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("new_password", serializer.errors)
|
|
|
|
def test_missing_old_password(self):
|
|
"""Test validation fails without old password"""
|
|
new_password = fake.password(length=12, special_chars=False)
|
|
data = {"new_password": new_password, "new_password_confirm": new_password}
|
|
serializer = PasswordChangeSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("old_password", serializer.errors)
|