"""Tests for Authentica OTP provider implementation.""" import os from unittest.mock import MagicMock, patch import pytest from django.contrib.auth.hashers import make_password from apps.accounts.models import OtpChannel, OtpPurpose, PhoneOTP from apps.accounts.services.otp import AuthenticaOtpProvider, verify_otp @patch("requests.post") def test_authentica_send_otp_sms_calls_api(mock_post): mock_response = MagicMock(ok=True) mock_response.json.return_value = {"success": True} mock_post.return_value = mock_response with patch.dict( os.environ, { "AUTHENTICA_API_KEY": "api-key", "AUTHENTICA_BASE_URL": "https://api.authentica.sa", "AUTHENTICA_TIMEOUT_SECONDS": "7", }, ): provider = AuthenticaOtpProvider() provider.send_otp("+966512345678", OtpChannel.SMS) mock_post.assert_called_once() url = mock_post.call_args[0][0] kwargs = mock_post.call_args[1] assert url == "https://api.authentica.sa/api/v2/send-otp" assert kwargs["json"] == {"method": "sms", "phone": "+966512345678"} assert kwargs["headers"]["X-Authorization"] == "api-key" assert kwargs["timeout"] == 7.0 @patch("requests.post") def test_authentica_send_sms_calls_api(mock_post): mock_response = MagicMock(ok=True) mock_response.json.return_value = {"success": True} mock_post.return_value = mock_response with patch.dict( os.environ, { "AUTHENTICA_API_KEY": "api-key", "AUTHENTICA_SENDER_NAME": "Salon", }, ): provider = AuthenticaOtpProvider() provider.send_sms("+966512345678", "Hello") mock_post.assert_called_once() url = mock_post.call_args[0][0] kwargs = mock_post.call_args[1] assert url == "https://api.authentica.sa/api/v2/send-sms" assert kwargs["json"] == { "phone": "+966512345678", "message": "Hello", "sender_name": "Salon", } @patch("requests.post") def test_authentica_verify_otp_calls_api(mock_post): mock_response = MagicMock(ok=True) mock_response.json.return_value = {"verified": True} mock_post.return_value = mock_response with patch.dict(os.environ, {"AUTHENTICA_API_KEY": "api-key"}): provider = AuthenticaOtpProvider() assert provider.verify_otp("+966512345678", "123456") is True mock_post.assert_called_once() url = mock_post.call_args[0][0] kwargs = mock_post.call_args[1] assert url == "https://api.authentica.sa/api/v2/verify-otp" assert kwargs["json"] == {"phone": "+966512345678", "otp": "123456"} @pytest.mark.django_db def test_verify_otp_uses_provider_for_authentica(): otp = PhoneOTP.objects.create( phone_number="+966512345678", channel=OtpChannel.SMS, purpose=OtpPurpose.AUTH, provider="authentica", code_hash=make_password("unused"), expires_at=PhoneOTP.expiry_at(), ) with patch("apps.accounts.services.otp.AuthenticaOtpProvider.verify_otp", return_value=True) as mock_verify: assert verify_otp(otp, "123456") is True mock_verify.assert_called_once_with("+966512345678", "123456") otp.refresh_from_db() assert otp.verified_at is not None assert otp.attempt_count == 1