Skip to content

Commit

Permalink
feat: refactor existing tests for new IDV source
Browse files Browse the repository at this point in the history
  • Loading branch information
zacharis278 committed Sep 30, 2024
1 parent 71a4051 commit 278cc6e
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 86 deletions.
14 changes: 11 additions & 3 deletions edx_name_affirmation/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from openedx_events.learning.signals import (
IDV_ATTEMPT_APPROVED,
IDV_ATTEMPT_CREATED,
IDV_ATTEMPT_DENIED,
IDV_ATTEMPT_PENDING,
)
Expand Down Expand Up @@ -42,23 +43,29 @@ def verified_name_approved(sender, instance, **kwargs): # pylint: disable=unuse


@receiver(IDV_ATTEMPT_APPROVED)
@receiver(IDV_ATTEMPT_CREATED)
@receiver(IDV_ATTEMPT_DENIED)
@receiver(IDV_ATTEMPT_PENDING)
def handle_idv_attempt_approved(sender, signal, **kwargs):
def handle_idv_event(sender, signal, **kwargs): # pylint: disable=unused-argument
"""
Trigger update to verified names based on open edX IDV events.
"""
event_data = kwargs.get('idv_attempt')
user = User.objects.get(id=event_data.user.id)

# If the user has a pending name change, use that as the full name
try:
user_full_name = user.pending_name_change
except AttributeError:
user_full_name = user.profile.name
user_full_name = event_data.user.pii.name

status = None
if signal == IDV_ATTEMPT_APPROVED:
status = VerifiedNameStatus.APPROVED
elif signal == IDV_ATTEMPT_PENDING:
elif signal == IDV_ATTEMPT_CREATED:
status = VerifiedNameStatus.PENDING
elif signal == IDV_ATTEMPT_PENDING:
status = VerifiedNameStatus.SUBMITTED
elif signal == IDV_ATTEMPT_DENIED:
status = VerifiedNameStatus.DENIED
else:
Expand All @@ -77,6 +84,7 @@ def handle_idv_attempt_approved(sender, signal, **kwargs):

def platform_verification_delete_handler(sender, instance, signal, **kwargs): # pylint: disable=unused-argument
"""
Receiver for VerificationAttempt deletions
"""
platform_verification_attempt_id = instance.id
log.info(
Expand Down
1 change: 0 additions & 1 deletion edx_name_affirmation/statuses.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class VerifiedNameStatus(str, Enum):
APPROVED = "approved"
DENIED = "denied"


@classmethod
def trigger_state_change_from_proctoring(cls, proctoring_status):
"""
Expand Down
134 changes: 57 additions & 77 deletions edx_name_affirmation/tests/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@
from django.contrib.auth import get_user_model
from django.test import TestCase

from openedx_events.learning.data import UserData, UserPersonalData, VerificationAttemptData
from openedx_events.learning.signals import (
IDV_ATTEMPT_APPROVED,
IDV_ATTEMPT_CREATED,
IDV_ATTEMPT_DENIED,
IDV_ATTEMPT_PENDING,
)

from edx_name_affirmation.handlers import (
idv_attempt_handler,
idv_delete_handler,
handle_idv_event,
platform_verification_delete_handler,
proctoring_attempt_handler,
proctoring_delete_handler
)
Expand Down Expand Up @@ -73,34 +81,49 @@ class IDVSignalTests(SignalTestCase):
"""
Test for idv_attempt_handler
"""
def _handle_idv_event(self, idv_signal, attempt_id):
""" Call IDV handler with a mock event """
user_data = UserData(
id=self.user.id,
is_active=True,
pii=UserPersonalData(
username=self.user.username,
email=self.user.email,
name=self.profile_name,
)
)
event_data = VerificationAttemptData(
attempt_id=attempt_id,
user=user_data,
status='mock-platform-status',
name=self.verified_name,
)
event_kwargs = {
'idv_attempt': event_data
}
handle_idv_event(None, idv_signal, **event_kwargs)

def test_idv_create_verified_name(self):
"""
Test that if no verified name exists for the name or attempt id, create one
"""
idv_attempt_handler(
self.idv_attempt_id,
self.user.id,
'created',
self.verified_name,
self.profile_name
)
self._handle_idv_event(IDV_ATTEMPT_CREATED, self.idv_attempt_id)

# make sure that verifiedname is created with relevant data
verified_name = VerifiedName.objects.get(verification_attempt_id=self.idv_attempt_id)
verified_name = VerifiedName.objects.get(platform_verification_attempt_id=self.idv_attempt_id)
self.assertEqual(verified_name.status, VerifiedNameStatus.PENDING)
self.assertEqual(verified_name.verification_attempt_id, self.idv_attempt_id)
self.assertEqual(verified_name.platform_verification_attempt_id, self.idv_attempt_id)
self.assertEqual(verified_name.verified_name, self.verified_name)
self.assertEqual(verified_name.profile_name, self.profile_name)

@ddt.data(
('created', VerifiedNameStatus.PENDING),
('submitted', VerifiedNameStatus.SUBMITTED),
('approved', VerifiedNameStatus.APPROVED),
('denied', VerifiedNameStatus.DENIED)
(IDV_ATTEMPT_CREATED, VerifiedNameStatus.PENDING),
(IDV_ATTEMPT_PENDING, VerifiedNameStatus.SUBMITTED),
(IDV_ATTEMPT_APPROVED, VerifiedNameStatus.APPROVED),
(IDV_ATTEMPT_DENIED, VerifiedNameStatus.DENIED)
)
@ddt.unpack
def test_idv_update_multiple_verified_names(self, idv_status, expected_status):
def test_idv_update_multiple_verified_names(self, idv_signal, expected_status):
"""
If a VerifiedName(s) for a user and verified name exist, ensure that it is updated properly
"""
Expand All @@ -119,19 +142,13 @@ def test_idv_update_multiple_verified_names(self, idv_status, expected_status):
user=self.user,
verified_name=self.verified_name,
profile_name=self.profile_name,
verification_attempt_id=self.idv_attempt_id
platform_verification_attempt_id=self.idv_attempt_id
)

idv_attempt_handler(
self.idv_attempt_id,
self.user.id,
idv_status,
self.verified_name,
self.profile_name
)
self._handle_idv_event(idv_signal, self.idv_attempt_id)

# check that the attempt id and status have been updated for all three VerifiedNames
self.assertEqual(len(VerifiedName.objects.filter(verification_attempt_id=self.idv_attempt_id)), 3)
self.assertEqual(len(VerifiedName.objects.filter(platform_verification_attempt_id=self.idv_attempt_id)), 3)
self.assertEqual(len(VerifiedName.objects.filter(status=expected_status)), 3)

def test_idv_create_with_existing_verified_names(self):
Expand All @@ -144,23 +161,17 @@ def test_idv_create_with_existing_verified_names(self):
user=self.user,
verified_name=self.verified_name,
profile_name=self.profile_name,
verification_attempt_id=previous_id,
platform_verification_attempt_id=previous_id,
status='denied'
)

# create an IDV attempt with the same user and names as above, but change the attempt ID to a unique value
idv_attempt_handler(
self.idv_attempt_id,
self.user.id,
'submitted',
self.verified_name,
self.profile_name
)
self._handle_idv_event(IDV_ATTEMPT_PENDING, self.idv_attempt_id)

verified_name = VerifiedName.objects.get(verification_attempt_id=self.idv_attempt_id)
verified_name = VerifiedName.objects.get(platform_verification_attempt_id=self.idv_attempt_id)
self.assertEqual(verified_name.status, VerifiedNameStatus.SUBMITTED)

previous_name = VerifiedName.objects.get(verification_attempt_id=previous_id)
previous_name = VerifiedName.objects.get(platform_verification_attempt_id=previous_id)
self.assertEqual(previous_name.status, VerifiedNameStatus.DENIED)

def test_idv_does_not_update_verified_name_by_proctoring(self):
Expand All @@ -181,27 +192,21 @@ def test_idv_does_not_update_verified_name_by_proctoring(self):
profile_name=self.profile_name
)

idv_attempt_handler(
self.idv_attempt_id,
self.user.id,
'submitted',
self.verified_name,
self.profile_name
)
self._handle_idv_event(IDV_ATTEMPT_PENDING, self.idv_attempt_id)

# check that the attempt id and status have only been updated for the record that does not have a proctored
# exam attempt id
self.assertEqual(len(VerifiedName.objects.filter(verification_attempt_id=self.idv_attempt_id)), 1)
self.assertEqual(len(VerifiedName.objects.filter(platform_verification_attempt_id=self.idv_attempt_id)), 1)
self.assertEqual(len(VerifiedName.objects.filter(status=VerifiedNameStatus.SUBMITTED)), 1)

@ddt.data(
('created', VerifiedNameStatus.PENDING),
('submitted', VerifiedNameStatus.SUBMITTED),
('approved', VerifiedNameStatus.APPROVED),
('denied', VerifiedNameStatus.DENIED)
(IDV_ATTEMPT_CREATED, VerifiedNameStatus.PENDING),
(IDV_ATTEMPT_PENDING, VerifiedNameStatus.SUBMITTED),
(IDV_ATTEMPT_APPROVED, VerifiedNameStatus.APPROVED),
(IDV_ATTEMPT_DENIED, VerifiedNameStatus.DENIED)
)
@ddt.unpack
def test_idv_update_one_verified_name(self, idv_status, expected_status):
def test_idv_update_one_verified_name(self, idv_signal, expected_status):
"""
If a VerifiedName(s) for a user and verified name exist, ensure that it is updated properly
"""
Expand All @@ -210,19 +215,13 @@ def test_idv_update_one_verified_name(self, idv_status, expected_status):
user=self.user,
verified_name=self.verified_name,
profile_name=self.profile_name,
verification_attempt_id=self.idv_attempt_id
platform_verification_attempt_id=self.idv_attempt_id
)

idv_attempt_handler(
self.idv_attempt_id,
self.user.id,
idv_status,
self.verified_name,
self.profile_name
)
self._handle_idv_event(idv_signal, self.idv_attempt_id)

# check that the attempt id and status have been updated for all three VerifiedNames
self.assertEqual(len(VerifiedName.objects.filter(verification_attempt_id=self.idv_attempt_id)), 1)
self.assertEqual(len(VerifiedName.objects.filter(platform_verification_attempt_id=self.idv_attempt_id)), 1)
self.assertEqual(len(VerifiedName.objects.filter(status=expected_status)), 1)

# If the status is approved, ensure that the post_save signal is called
Expand All @@ -231,33 +230,14 @@ def test_idv_update_one_verified_name(self, idv_status, expected_status):
else:
mock_signal.assert_not_called()

@ddt.data(
'ready',
'must_retry',
)
@patch('edx_name_affirmation.tasks.idv_update_verified_name_task.delay')
def test_idv_non_trigger_status(self, status, mock_task):
"""
Test that a celery task is not triggered if a non-relevant status is received
"""
idv_attempt_handler(
self.idv_attempt_id,
self.user.id,
status,
self.verified_name,
self.profile_name
)

mock_task.assert_not_called()

@patch('edx_name_affirmation.tasks.delete_verified_name_task.delay')
def test_idv_delete_handler(self, mock_task):
"""
Test that a celery task is triggered if an idv delete signal is received
"""
mock_idv_object = MagicMock()
mock_idv_object.id = 'abcdef'
idv_delete_handler(
platform_verification_delete_handler(
{},
mock_idv_object,
'',
Expand Down
10 changes: 5 additions & 5 deletions edx_name_affirmation/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_idv_delete(self):
Assert that only relevant VerifiedNames are deleted for a given idv_attempt_id
"""
# associated test object with an idv attempt
self.verified_name_obj.verification_attempt_id = self.idv_attempt_id
self.verified_name_obj.platform_verification_attempt_id = self.idv_attempt_id
self.verified_name_obj.save()

other_attempt_id = 123456
Expand All @@ -73,15 +73,15 @@ def test_idv_delete(self):
user=self.user,
verified_name='Jonathan X Doe',
profile_name='Jon D',
verification_attempt_id=self.idv_attempt_id
platform_verification_attempt_id=self.idv_attempt_id
).save()

# create VerifiedName not associated with idv attempt
other_verified_name_obj = VerifiedName(
user=self.user,
verified_name='Jonathan X Doe',
profile_name='Jon D',
verification_attempt_id=other_attempt_id
platform_verification_attempt_id=other_attempt_id
)
other_verified_name_obj.save()

Expand All @@ -91,8 +91,8 @@ def test_idv_delete(self):
)

# check that there is only VerifiedName object
self.assertEqual(len(VerifiedName.objects.filter(verification_attempt_id=self.idv_attempt_id)), 0)
self.assertEqual(len(VerifiedName.objects.filter(verification_attempt_id=other_attempt_id)), 1)
self.assertEqual(len(VerifiedName.objects.filter(platform_verification_attempt_id=self.idv_attempt_id)), 0)
self.assertEqual(len(VerifiedName.objects.filter(platform_verification_attempt_id=other_attempt_id)), 1)

def test_proctoring_delete(self):
"""
Expand Down

0 comments on commit 278cc6e

Please sign in to comment.