from django.test import TestCase from django.urls import reverse from django.core.cache import caches from unittest.mock import patch, MagicMock from rest_framework.test import APIClient from rest_framework import status from user.models import FUser from utils.slider_captcha import generate_slider_captcha, verify_slider_captcha from utils.captcha import check_captcha_required, record_failure default_cache = caches['default'] class TestLoginWithSliderCaptcha(TestCase): def setUp(self): self.client = APIClient() self.login_url = reverse('login_with_slider') self.user = FUser.objects.create_user( username='testuser', email='test@example.com', password='testpass123' ) def _post(self, data): return self.client.post( self.login_url, data, format='json' ) def test_login_without_captcha_required(self): response = self._post({ 'account': 'testuser', 'password': 'testpass123' }) self.assertNotEqual(response.status_code, 20022) @patch('user.views.user.check_captcha_required') def test_login_with_captcha_required_no_captcha_provided(self, mock_check): mock_check.return_value = True response = self._post({ 'account': 'testuser', 'password': 'testpass123' }) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.data['code'], 20022) @patch('user.views.user.check_captcha_required') @patch('user.views.user.verify_slider_captcha') def test_login_with_valid_captcha(self, mock_verify, mock_check): mock_check.return_value = True mock_verify.return_value = True response = self._post({ 'account': 'testuser', 'password': 'testpass123', 'slider_captcha_key': 'test-key', 'slider_captcha_x': 100 }) mock_verify.assert_called_once_with('test-key', 100) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIn('access', response.data['data']) self.assertIn('refresh', response.data['data']) @patch('user.views.user.check_captcha_required') @patch('user.views.user.verify_slider_captcha') def test_login_with_invalid_captcha(self, mock_verify, mock_check): mock_check.return_value = True mock_verify.return_value = False response = self._post({ 'account': 'testuser', 'password': 'testpass123', 'slider_captcha_key': 'test-key', 'slider_captcha_x': 50 }) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.data['code'], 20020) @patch('user.views.user.check_captcha_required') @patch('user.views.user.verify_slider_captcha') def test_login_with_expired_captcha(self, mock_verify, mock_check): mock_check.return_value = True from utils.slider_captcha import SliderCaptchaError mock_verify.side_effect = SliderCaptchaError('验证码已过期') response = self._post({ 'account': 'testuser', 'password': 'testpass123', 'slider_captcha_key': 'expired-key', 'slider_captcha_x': 100 }) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.data['code'], 20021) def test_get_identifier_with_ip(self): from user.views.user import LoginView view = LoginView() request = MagicMock() request.META = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} identifier = view._get_identifier(request) self.assertEqual(identifier, '192.168.1.1') def test_get_identifier_without_forwarded_for(self): from user.views.user import LoginView view = LoginView() request = MagicMock() request.META = {'REMOTE_ADDR': '127.0.0.1'} identifier = view._get_identifier(request) self.assertEqual(identifier, '127.0.0.1')