Files
edx-platform/lms/djangoapps/verify_student/tests/test_api.py
Isaac Lee 575e240961 feat: add idv events to api (#35468)
* 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
2024-09-17 15:59:33 -04:00

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,
)