Files
edx-platform/lms/djangoapps/certificates/tests/test_generation.py
Bianca Severino d2fa7f7239 feat: use verified name for certs if enabled
If the verified name feature is enabled and the user has their
preference set to use verified name for certificates, create and
display certificates with their verified name rather than their
profile name.
2021-08-06 14:28:06 -04:00

227 lines
9.3 KiB
Python

"""
Tests for certificate generation
"""
import ddt
import logging
from unittest import mock
from edx_name_affirmation.api import create_verified_name, create_verified_name_config
from edx_name_affirmation.toggles import VERIFIED_NAME_FLAG
from edx_toggles.toggles.testutils import override_waffle_flag
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import UserProfile
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory
from common.djangoapps.util.testing import EventTestMixin
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.generation import generate_course_certificate
from lms.djangoapps.certificates.models import GeneratedCertificate
from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
log = logging.getLogger(__name__)
PROFILE_NAME_METHOD = 'common.djangoapps.student.models_api.get_name'
@ddt.ddt
class CertificateTests(EventTestMixin, ModuleStoreTestCase):
"""
Tests for certificate generation
"""
def setUp(self): # pylint: disable=arguments-differ
super().setUp('lms.djangoapps.certificates.utils.tracker')
# Create user, a course run, and an enrollment
self.u = UserFactory()
self.profile = UserProfile.objects.get(user_id=self.u.id)
self.name = self.profile.name
self.cr = CourseFactory()
self.key = self.cr.id # pylint: disable=no-member
CourseEnrollmentFactory(
user=self.u,
course_id=self.key,
is_active=True,
mode=CourseMode.VERIFIED,
)
self.gen_mode = 'batch'
self.grade = '.85'
self.enrollment_mode = CourseMode.VERIFIED
def test_generation(self):
"""
Test certificate generation
"""
certs = GeneratedCertificate.objects.filter(user=self.u, course_id=self.key)
assert len(certs) == 0
generated_cert = generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable,
self.enrollment_mode, self.grade, self.gen_mode)
self.assert_event_emitted(
'edx.certificate.created',
user_id=self.u.id,
course_id=str(self.key),
certificate_id=generated_cert.verify_uuid,
enrollment_mode=generated_cert.mode,
certificate_url='',
generation_mode=self.gen_mode
)
certs = GeneratedCertificate.objects.filter(user=self.u, course_id=self.key)
assert len(certs) == 1
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
assert cert.status == CertificateStatuses.downloadable
assert cert.mode == self.enrollment_mode
assert cert.grade == self.grade
assert cert.name == self.name
def test_generation_existing_unverified(self):
"""
Test certificate generation when a certificate already exists and we want to mark it as unverified
"""
error_reason = 'Some PDF error'
GeneratedCertificateFactory(
user=self.u,
course_id=self.key,
mode=CourseMode.AUDIT,
status=CertificateStatuses.error,
error_reason=error_reason
)
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
assert cert.error_reason == error_reason
assert cert.mode == CourseMode.AUDIT
assert cert.status == CertificateStatuses.error
generate_course_certificate(self.u, self.key, CertificateStatuses.unverified, self.enrollment_mode, self.grade,
self.gen_mode)
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
assert cert.error_reason == ''
assert cert.status == CertificateStatuses.unverified
assert cert.mode == self.enrollment_mode
assert cert.grade == ''
def test_generation_existing_downloadable(self):
"""
Test certificate generation when a certificate already exists and we want to mark it as downloadable
"""
error_reason = 'Some PDF error'
GeneratedCertificateFactory(
user=self.u,
course_id=self.key,
mode=CourseMode.AUDIT,
status=CertificateStatuses.error,
error_reason=error_reason
)
generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable, self.enrollment_mode,
self.grade, self.gen_mode)
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
assert cert.error_reason == ''
assert cert.status == CertificateStatuses.downloadable
assert cert.mode == self.enrollment_mode
assert cert.grade == self.grade
def test_generation_uuid_persists_through_revocation(self):
"""
Test that the `verify_uuid` value of a certificate does not change when it is revoked and re-awarded.
"""
generated_cert = generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable,
self.enrollment_mode, self.grade, self.gen_mode)
assert generated_cert.status, CertificateStatuses.downloadable
verify_uuid = generated_cert.verify_uuid
generated_cert.invalidate()
assert generated_cert.status, CertificateStatuses.unavailable
assert generated_cert.verify_uuid, verify_uuid
generated_cert = generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable,
self.enrollment_mode, self.grade, self.gen_mode)
assert generated_cert.status, CertificateStatuses.downloadable
assert generated_cert.verify_uuid, verify_uuid
generated_cert.mark_notpassing(mode=generated_cert.mode, grade=50.00)
assert generated_cert.status, CertificateStatuses.notpassing
assert generated_cert.verify_uuid, verify_uuid
generated_cert = generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable,
self.enrollment_mode, self.grade, self.gen_mode)
assert generated_cert.status, CertificateStatuses.downloadable
assert generated_cert.verify_uuid, verify_uuid
def test_generation_creates_verify_uuid_when_needed(self):
"""
Test that ensures we will create a verify_uuid when needed.
"""
GeneratedCertificateFactory(
user=self.u,
course_id=self.key,
mode=CourseMode.VERIFIED,
status=CertificateStatuses.unverified,
verify_uuid=''
)
generated_cert = generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable,
self.enrollment_mode, self.grade, self.gen_mode)
assert generated_cert.status, CertificateStatuses.downloadable
assert generated_cert.verify_uuid != ''
def test_generation_missing_profile(self):
"""
Test certificate generation when the user profile is missing
"""
GeneratedCertificateFactory(
user=self.u,
course_id=self.key,
mode=CourseMode.AUDIT,
status=CertificateStatuses.unverified
)
with mock.patch(PROFILE_NAME_METHOD, return_value=None):
generate_course_certificate(self.u, self.key, CertificateStatuses.downloadable, self.enrollment_mode,
self.grade, self.gen_mode)
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
assert cert.status == CertificateStatuses.downloadable
assert cert.mode == self.enrollment_mode
assert cert.grade == self.grade
assert cert.name == ''
@override_waffle_flag(VERIFIED_NAME_FLAG, active=True)
@ddt.data((True, True), (True, False), (False, False))
@ddt.unpack
def test_generation_verified_name(self, should_use_verified_name_for_certs, is_verified):
"""
Test that if verified name functionality is enabled and the user has their preference set to use
verified name for certificates, their verified name will appear on the certificate rather than
their profile name.
"""
verified_name = 'Jonathan Doe'
create_verified_name(self.u, verified_name, self.name, is_verified=is_verified)
create_verified_name_config(self.u, use_verified_name_for_certs=should_use_verified_name_for_certs)
GeneratedCertificateFactory(
user=self.u,
course_id=self.key,
mode=CourseMode.AUDIT,
status=CertificateStatuses.unverified
)
generate_course_certificate(
self.u, self.key, CertificateStatuses.downloadable, self.enrollment_mode, self.grade, self.gen_mode,
)
cert = GeneratedCertificate.objects.get(user=self.u, course_id=self.key)
if should_use_verified_name_for_certs and is_verified:
assert cert.name == verified_name
else:
assert cert.name == self.name