* feat: add idv events to api - moved what was in signals.py to a handlers.py (which is what their file should have been called) * chore: quality * fix: rename test file + imports * fix: change handler reverse url in other tests * fix: refactor signals and handlers pattern - following OEP-49 pattern for signals directory - user removed as param for update function - event now emitted after save * fix: unpin edx-name-affirmation * chore: add init to signals dir * fix: compile requirements * chore: quality * chore: fix some imports * chore: quality * test: added signal emissions to test_api * chore: lint
232 lines
8.2 KiB
Python
232 lines
8.2 KiB
Python
"""
|
|
Tests of API module.
|
|
"""
|
|
from unittest.mock import patch
|
|
|
|
from datetime import datetime, timezone
|
|
import ddt
|
|
from django.conf import settings
|
|
from django.core import mail
|
|
from django.test import TestCase
|
|
|
|
from common.djangoapps.student.tests.factories import UserFactory
|
|
from lms.djangoapps.verify_student.api import (
|
|
create_verification_attempt,
|
|
send_approval_email,
|
|
update_verification_attempt,
|
|
)
|
|
from lms.djangoapps.verify_student.exceptions import VerificationAttemptInvalidStatus
|
|
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification, VerificationAttempt
|
|
from lms.djangoapps.verify_student.statuses import VerificationAttemptStatus
|
|
|
|
|
|
@ddt.ddt
|
|
class TestSendApprovalEmail(TestCase):
|
|
"""
|
|
Test cases for the send_approval_email API method.
|
|
"""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self.user = UserFactory.create()
|
|
self.attempt = SoftwareSecurePhotoVerification(
|
|
status="submitted",
|
|
user=self.user
|
|
)
|
|
self.attempt.save()
|
|
|
|
def _assert_verification_approved_email(self, expiration_date):
|
|
"""Check that a verification approved email was sent."""
|
|
assert len(mail.outbox) == 1
|
|
email = mail.outbox[0]
|
|
assert email.subject == 'Your édX ID verification was approved!'
|
|
assert 'Your édX ID verification photos have been approved' in email.body
|
|
assert expiration_date.strftime("%m/%d/%Y") in email.body
|
|
|
|
@ddt.data(True, False)
|
|
def test_send_approval(self, use_ace):
|
|
with patch.dict(settings.VERIFY_STUDENT, {'USE_DJANGO_MAIL': use_ace}):
|
|
send_approval_email(self.attempt)
|
|
self._assert_verification_approved_email(self.attempt.expiration_datetime)
|
|
|
|
|
|
@ddt.ddt
|
|
class CreateVerificationAttempt(TestCase):
|
|
"""
|
|
Test cases for the create_verification_attempt API method.
|
|
"""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self.user = UserFactory.create()
|
|
self.attempt = VerificationAttempt(
|
|
user=self.user,
|
|
name='Tester McTest',
|
|
status=VerificationAttemptStatus.CREATED,
|
|
expiration_datetime=datetime(2024, 12, 31, tzinfo=timezone.utc)
|
|
)
|
|
self.attempt.save()
|
|
|
|
@patch('lms.djangoapps.verify_student.api.emit_idv_attempt_created_event')
|
|
def test_create_verification_attempt(self, mock_created_event):
|
|
expected_id = 2
|
|
self.assertEqual(
|
|
create_verification_attempt(
|
|
user=self.user,
|
|
name='Tester McTest',
|
|
status=VerificationAttemptStatus.CREATED,
|
|
expiration_datetime=datetime(2024, 12, 31, tzinfo=timezone.utc)
|
|
),
|
|
expected_id
|
|
)
|
|
verification_attempt = VerificationAttempt.objects.get(id=expected_id)
|
|
|
|
self.assertEqual(verification_attempt.user, self.user)
|
|
self.assertEqual(verification_attempt.name, 'Tester McTest')
|
|
self.assertEqual(verification_attempt.status, VerificationAttemptStatus.CREATED)
|
|
self.assertEqual(verification_attempt.expiration_datetime, datetime(2024, 12, 31, tzinfo=timezone.utc))
|
|
mock_created_event.assert_called_with(
|
|
attempt_id=verification_attempt.id,
|
|
user=self.user,
|
|
status=VerificationAttemptStatus.CREATED,
|
|
name='Tester McTest',
|
|
expiration_date=datetime(2024, 12, 31, tzinfo=timezone.utc),
|
|
)
|
|
|
|
def test_create_verification_attempt_no_expiration_datetime(self):
|
|
expected_id = 2
|
|
self.assertEqual(
|
|
create_verification_attempt(
|
|
user=self.user,
|
|
name='Tester McTest',
|
|
status=VerificationAttemptStatus.CREATED,
|
|
),
|
|
expected_id
|
|
)
|
|
verification_attempt = VerificationAttempt.objects.get(id=expected_id)
|
|
|
|
self.assertEqual(verification_attempt.user, self.user)
|
|
self.assertEqual(verification_attempt.name, 'Tester McTest')
|
|
self.assertEqual(verification_attempt.status, VerificationAttemptStatus.CREATED)
|
|
self.assertEqual(verification_attempt.expiration_datetime, None)
|
|
|
|
|
|
@ddt.ddt
|
|
class UpdateVerificationAttempt(TestCase):
|
|
"""
|
|
Test cases for the update_verification_attempt API method.
|
|
"""
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self.user = UserFactory.create()
|
|
self.attempt = VerificationAttempt(
|
|
user=self.user,
|
|
name='Tester McTest',
|
|
status=VerificationAttemptStatus.CREATED,
|
|
expiration_datetime=datetime(2024, 12, 31, tzinfo=timezone.utc)
|
|
)
|
|
self.attempt.save()
|
|
|
|
@ddt.data(
|
|
('Tester McTest', VerificationAttemptStatus.PENDING, datetime(2024, 12, 31, tzinfo=timezone.utc)),
|
|
('Tester McTest2', VerificationAttemptStatus.APPROVED, datetime(2025, 12, 31, tzinfo=timezone.utc)),
|
|
('Tester McTest3', VerificationAttemptStatus.DENIED, datetime(2026, 12, 31, tzinfo=timezone.utc)),
|
|
)
|
|
@ddt.unpack
|
|
@patch('lms.djangoapps.verify_student.api.emit_idv_attempt_pending_event')
|
|
@patch('lms.djangoapps.verify_student.api.emit_idv_attempt_approved_event')
|
|
@patch('lms.djangoapps.verify_student.api.emit_idv_attempt_denied_event')
|
|
def test_update_verification_attempt(
|
|
self,
|
|
name,
|
|
status,
|
|
expiration_datetime,
|
|
mock_denied_event,
|
|
mock_approved_event,
|
|
mock_pending_event,
|
|
):
|
|
update_verification_attempt(
|
|
attempt_id=self.attempt.id,
|
|
name=name,
|
|
status=status,
|
|
expiration_datetime=expiration_datetime,
|
|
)
|
|
|
|
verification_attempt = VerificationAttempt.objects.get(id=self.attempt.id)
|
|
|
|
# Values should change as a result of this update.
|
|
self.assertEqual(verification_attempt.user, self.user)
|
|
self.assertEqual(verification_attempt.name, name)
|
|
self.assertEqual(verification_attempt.status, status)
|
|
self.assertEqual(verification_attempt.expiration_datetime, expiration_datetime)
|
|
|
|
if status == VerificationAttemptStatus.PENDING:
|
|
mock_pending_event.assert_called_with(
|
|
attempt_id=verification_attempt.id,
|
|
user=self.user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|
|
elif status == VerificationAttemptStatus.APPROVED:
|
|
mock_approved_event.assert_called_with(
|
|
attempt_id=verification_attempt.id,
|
|
user=self.user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|
|
elif status == VerificationAttemptStatus.DENIED:
|
|
mock_denied_event.assert_called_with(
|
|
attempt_id=verification_attempt.id,
|
|
user=self.user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|
|
|
|
def test_update_verification_attempt_none_values(self):
|
|
update_verification_attempt(
|
|
attempt_id=self.attempt.id,
|
|
name=None,
|
|
status=None,
|
|
expiration_datetime=None,
|
|
)
|
|
|
|
verification_attempt = VerificationAttempt.objects.get(id=self.attempt.id)
|
|
|
|
# Values should not change as a result of the values passed in being None, except for expiration_datetime.
|
|
self.assertEqual(verification_attempt.user, self.user)
|
|
self.assertEqual(verification_attempt.name, self.attempt.name)
|
|
self.assertEqual(verification_attempt.status, self.attempt.status)
|
|
self.assertEqual(verification_attempt.expiration_datetime, None)
|
|
|
|
def test_update_verification_attempt_not_found(self):
|
|
self.assertRaises(
|
|
VerificationAttempt.DoesNotExist,
|
|
update_verification_attempt,
|
|
attempt_id=999999,
|
|
name=None,
|
|
status=VerificationAttemptStatus.APPROVED,
|
|
)
|
|
|
|
@ddt.data(
|
|
'completed',
|
|
'failed',
|
|
'submitted',
|
|
'expired',
|
|
)
|
|
def test_update_verification_attempt_invalid(self, status):
|
|
self.assertRaises(
|
|
VerificationAttemptInvalidStatus,
|
|
update_verification_attempt,
|
|
attempt_id=self.attempt.id,
|
|
name=None,
|
|
status=status,
|
|
expiration_datetime=None,
|
|
)
|