104 lines
3.2 KiB
Python
104 lines
3.2 KiB
Python
"""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
|