test: Remove external tests that exercise the internal certificates code. Update tests in preparation for enabling V2 of course certificates globally. (#27881)

MICROBA-1082
This commit is contained in:
Christie Rice
2021-06-08 15:29:05 -04:00
committed by GitHub
parent e7900160e8
commit 97f6d0fce8
4 changed files with 40 additions and 169 deletions

View File

@@ -23,7 +23,7 @@ from lms.djangoapps.certificates.tasks import CERTIFICATE_DELAY_SECONDS
from lms.djangoapps.certificates.tests.factories import CertificateAllowlistFactory, GeneratedCertificateFactory
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from lms.djangoapps.verify_student.models import IDVerificationAttempt, SoftwareSecurePhotoVerification
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from openedx.core.djangoapps.certificates.config import waffle
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@@ -147,28 +147,7 @@ class PassingGradeCertsTest(ModuleStoreTestCase):
)
attempt.approve()
def test_cert_generation_on_passing_self_paced(self):
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None
) as mock_generate_certificate_apply_async:
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION_SWITCH, active=True):
grade_factory = CourseGradeFactory()
# Not passing
grade_factory.update(self.user, self.course)
mock_generate_certificate_apply_async.assert_not_called()
# Certs fired after passing
with mock_passing_grade():
grade_factory.update(self.user, self.course)
mock_generate_certificate_apply_async.assert_called_with(
countdown=CERTIFICATE_DELAY_SECONDS,
kwargs={
'student': str(self.user.id),
'course_key': str(self.course.id),
}
)
def test_cert_generation_on_passing_instructor_paced(self):
def test_cert_generation_on_passing_v1(self):
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None
@@ -377,9 +356,9 @@ class FailingGradeCertsTest(ModuleStoreTestCase):
assert cert.status == CertificateStatuses.downloadable
class LearnerTrackChangeCertsTest(ModuleStoreTestCase):
class LearnerIdVerificationTest(ModuleStoreTestCase):
"""
Tests for certificate generation task firing on learner verification
Tests for certificate generation task firing on learner id verification
"""
def setUp(self):
@@ -405,45 +384,37 @@ class LearnerTrackChangeCertsTest(ModuleStoreTestCase):
grade_factory.update(self.user_one, self.course_one)
grade_factory.update(self.user_two, self.course_two)
def test_cert_generation_on_photo_verification_self_paced(self):
@override_waffle_flag(CERTIFICATES_USE_UPDATED, active=True)
def test_cert_generation_on_photo_verification(self):
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
'lms.djangoapps.certificates.signals.generate_certificate_task',
return_value=None
) as mock_generate_certificate_apply_async:
) as mock_cert_task:
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION_SWITCH, active=True):
mock_generate_certificate_apply_async.assert_not_called()
attempt = SoftwareSecurePhotoVerification.objects.create(
user=self.user_one,
status='submitted'
)
attempt.approve()
mock_generate_certificate_apply_async.assert_called_with(
countdown=CERTIFICATE_DELAY_SECONDS,
kwargs={
'student': str(self.user_one.id),
'course_key': str(self.course_one.id),
'expected_verification_status': IDVerificationAttempt.STATUS.approved,
}
)
def test_cert_generation_on_photo_verification_instructor_paced(self):
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None
) as mock_generate_certificate_apply_async:
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION_SWITCH, active=True):
mock_generate_certificate_apply_async.assert_not_called()
attempt = SoftwareSecurePhotoVerification.objects.create(
user=self.user_two,
status='submitted'
)
attempt.approve()
mock_generate_certificate_apply_async.assert_called_with(
mock_cert_task.assert_called_with(self.user_two, self.course_two.id)
def test_cert_generation_on_photo_verification_v1(self):
with mock.patch(
'lms.djangoapps.certificates.signals.generate_certificate.apply_async',
return_value=None
) as mock_cert_task:
with override_waffle_switch(AUTO_CERTIFICATE_GENERATION_SWITCH, active=True):
attempt = SoftwareSecurePhotoVerification.objects.create(
user=self.user_two,
status='submitted'
)
attempt.approve()
mock_cert_task.assert_called_with(
countdown=CERTIFICATE_DELAY_SECONDS,
kwargs={
'student': str(self.user_two.id),
'course_key': str(self.course_two.id),
'expected_verification_status': IDVerificationAttempt.STATUS.approved,
'expected_verification_status': 'approved'
}
)

View File

@@ -27,7 +27,6 @@ from edx_toggles.toggles.testutils import override_waffle_flag
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import UsageKey
from pytz import UTC
from testfixtures import LogCapture
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.course_modes.tests.factories import CourseModeFactory
@@ -59,7 +58,6 @@ from common.djangoapps.student.tests.factories import InstructorFactory
from common.djangoapps.student.tests.factories import StaffFactory
from common.djangoapps.student.tests.factories import UserFactory
from lms.djangoapps.bulk_email.models import BulkEmailFlag, CourseEmail, CourseEmailTemplate
from lms.djangoapps.certificates.api import generate_user_certificates
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.tests.factories import (
GeneratedCertificateFactory
@@ -1904,20 +1902,6 @@ class TestInstructorAPIBulkBetaEnrollment(SharedModuleStoreTestCase, LoginEnroll
# (comment because pylint C0103(invalid-name))
# self.maxDiff = None
def test_beta_tester_must_not_earn_cert(self):
"""
Test to ensure that beta tester must not earn certificate in a course
in which he/she is a beta-tester.
"""
with LogCapture() as capture:
message = (
f'Canceling Certificate Generation task for user {self.beta_tester.id} : {self.course.id}. User is a '
'Beta Tester.'
)
generate_user_certificates(self.beta_tester, self.course.id)
capture.check_present(('lms.djangoapps.certificates.generation_handler', 'INFO', message))
def test_missing_params(self):
""" Test missing all query parameters. """
url = reverse('bulk_beta_modify_access', kwargs={'course_id': str(self.course.id)})

View File

@@ -4,12 +4,10 @@
import contextlib
import io
import json
from datetime import datetime, timedelta
from unittest import mock
import ddt
import pytest
import pytz
from config_models.models import cache
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
@@ -17,8 +15,6 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.test.utils import override_settings
from django.urls import reverse
from capa.xqueue_interface import XQueueInterface
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import GlobalStaffFactory
from common.djangoapps.student.tests.factories import InstructorFactory
@@ -35,9 +31,6 @@ from lms.djangoapps.certificates.tests.factories import (
CertificateInvalidationFactory,
GeneratedCertificateFactory
)
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from lms.djangoapps.verify_student.services import IDVerificationService
from lms.djangoapps.verify_student.tests.factories import SoftwareSecurePhotoVerificationFactory
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@@ -47,7 +40,7 @@ class CertificatesInstructorDashTest(SharedModuleStoreTestCase):
"""Tests for the certificate panel of the instructor dash. """
ERROR_REASON = "An error occurred!"
DOWNLOAD_URL = "http://www.example.com/abcd123/cert.pdf"
DOWNLOAD_URL = "https://www.example.com/abcd123/cert.pdf"
@classmethod
def setUpClass(cls):
@@ -359,77 +352,6 @@ class CertificatesInstructorApiTest(SharedModuleStoreTestCase):
'Certificate regeneration task has been started.' \
' You can view the status of the generation task in the "Pending Tasks" section.'
@override_settings(AUDIT_CERT_CUTOFF_DATE=datetime.now(pytz.UTC) - timedelta(days=1))
@ddt.data(
(CertificateStatuses.generating, 'ID Verified', 'approved'),
(CertificateStatuses.unverified, 'Not ID Verified', 'denied'),
)
@ddt.unpack
def test_verified_users_with_audit_certs(self, expected_cert_status, verification_output, id_verification_status):
"""
Test certificate regeneration for verified users with audit certificates.
Scenario:
Enroll user in a course in audit mode,
User passed the course and now he has `audit_passing` certificate status,
User switched to verified mode and is ID verified,
Regenerate certificate for it,
Modified certificate status is `generating` if user is ID verified otherwise `unverified`.
"""
# Check that user is enrolled in audit mode.
enrollment = CourseEnrollment.get_enrollment(self.user, self.course.id)
assert enrollment.mode == CourseMode.AUDIT
with mock_passing_grade():
# Generate certificate for user and check that user has a audit passing certificate.
cert_status = certs_api.generate_user_certificates(student=self.user, course_key=self.course.id)
# Check that certificate status is 'audit_passing'.
assert cert_status == CertificateStatuses.audit_passing
# Update user enrollment mode to verified mode.
enrollment.update_enrollment(mode=CourseMode.VERIFIED)
assert enrollment.mode == CourseMode.VERIFIED
# Create and assert user's ID verification record.
SoftwareSecurePhotoVerificationFactory.create(user=self.user, status=id_verification_status)
actual_verification_status = IDVerificationService.verification_status_for_user(
self.user,
enrollment.mode
)
assert actual_verification_status == verification_output
# Login the client and access the url with 'audit_passing' status.
self.client.login(username=self.global_staff.username, password='test')
url = reverse(
'start_certificate_regeneration',
kwargs={'course_id': str(self.course.id)}
)
with mock.patch.object(XQueueInterface, 'send_to_queue') as mock_send:
mock_send.return_value = (0, None)
response = self.client.post(
url,
{'certificate_statuses': [CertificateStatuses.audit_passing]}
)
# Assert 200 status code in response
assert response.status_code == 200
res_json = json.loads(response.content.decode('utf-8'))
# Assert request is successful
assert res_json['success']
# Assert success message
assert res_json['message'] ==\
'Certificate regeneration task has been started.' \
' You can view the status of the generation task in the "Pending Tasks" section.'
# Now, check whether user has audit certificate.
cert = certs_api.get_certificate_for_user(self.user.username, self.course.id)
assert cert['status'] != CertificateStatuses.audit_passing
assert cert['status'] == expected_cert_status
def test_certificate_regeneration_error(self):
"""
Test certificate regeneration errors out when accessed with either empty list of 'certificate_statuses' or

View File

@@ -22,11 +22,9 @@ from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.tests.factories import CourseEnrollmentFactory
from common.djangoapps.util.milestones_helpers import set_prerequisite_courses
from common.djangoapps.util.testing import UrlResetMixin
from lms.djangoapps.certificates.api import generate_user_certificates
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.certificates.tests.factories import GeneratedCertificateFactory
from lms.djangoapps.courseware.access_response import MilestoneAccessError, StartDateError, VisibilityError
from lms.djangoapps.grades.tests.utils import mock_passing_grade
from lms.djangoapps.mobile_api.testutils import (
MobileAPITestCase,
MobileAuthTestMixin,
@@ -309,10 +307,10 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
)
@ddt.unpack
def test_enrollment_with_gating(self, api_version, expired, num_courses_returned):
'''
"""
Test that expired courses are only returned in v1 of API
when waffle flag enabled, and un-expired courses always returned
'''
"""
CourseDurationLimitConfig.objects.create(enabled=True, enabled_as_of=datetime.datetime(2015, 1, 1))
courses = self._get_enrollment_data(api_version, expired)
self._assert_enrollment_results(api_version, courses, num_courses_returned, True)
@@ -325,10 +323,10 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest
)
@ddt.unpack
def test_enrollment_no_gating(self, api_version, expired, num_courses_returned):
'''
Test that expired and non-expired courses returned if waffle flag is disabled
regarless of version of API
'''
"""
Test that expired and non-expired courses are returned if the waffle flag is disabled,
regardless of the API version
"""
CourseDurationLimitConfig.objects.create(enabled=False)
courses = self._get_enrollment_data(api_version, expired)
self._assert_enrollment_results(api_version, courses, num_courses_returned, False)
@@ -349,7 +347,7 @@ class TestUserEnrollmentCertificates(UrlResetMixin, MobileAPITestCase, Milestone
"""
self.login_and_enroll()
certificate_url = "http://test_certificate_url"
certificate_url = "https://test_certificate_url"
GeneratedCertificateFactory.create(
user=self.user,
course_id=self.course.id,
@@ -386,17 +384,13 @@ class TestUserEnrollmentCertificates(UrlResetMixin, MobileAPITestCase, Milestone
@patch.dict(settings.FEATURES, {'CERTIFICATES_HTML_VIEW': True, 'ENABLE_MKTG_SITE': True})
def test_web_certificate(self):
CourseMode.objects.create(
course_id=self.course.id,
mode_display_name="Honor",
mode_slug=CourseMode.HONOR,
)
self.login_and_enroll()
self.course.cert_html_view_enabled = True
self.store.update_item(self.course, self.user.id)
with mock_passing_grade():
generate_user_certificates(self.user, self.course.id)
GeneratedCertificateFactory.create(
user=self.user,
course_id=self.course.id,
status=CertificateStatuses.downloadable
)
response = self.api_response()
certificate_data = response.data[0]['certificate']
@@ -559,9 +553,9 @@ class TestCourseEnrollmentSerializer(MobileAPITestCase, MilestonesTestCaseMixin)
self.request.user = self.user
def get_serialized_data(self, api_version):
'''
"""
Return data from CourseEnrollmentSerializer
'''
"""
if api_version == API_V05:
serializer = CourseEnrollmentSerializerv05
else:
@@ -573,10 +567,10 @@ class TestCourseEnrollmentSerializer(MobileAPITestCase, MilestonesTestCaseMixin)
).data
def _expiration_in_response(self, response, api_version):
'''
"""
Assert that audit_access_expires field in present in response
based on version of api being used
'''
"""
if api_version != API_V05:
assert 'audit_access_expires' in response
else: