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:
@@ -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'
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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)})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user