replaced unittest assertions pytest assertions (#26540)
This commit is contained in:
@@ -43,19 +43,19 @@ class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase):
|
||||
"""
|
||||
Check a JSON response against a known badge class.
|
||||
"""
|
||||
self.assertEqual(badge_class.issuing_component, json_class['issuing_component'])
|
||||
self.assertEqual(badge_class.slug, json_class['slug'])
|
||||
self.assertIn(badge_class.image.url, json_class['image_url'])
|
||||
self.assertEqual(badge_class.description, json_class['description'])
|
||||
self.assertEqual(badge_class.criteria, json_class['criteria'])
|
||||
self.assertEqual(badge_class.course_id and six.text_type(badge_class.course_id), json_class['course_id'])
|
||||
assert badge_class.issuing_component == json_class['issuing_component']
|
||||
assert badge_class.slug == json_class['slug']
|
||||
assert badge_class.image.url in json_class['image_url']
|
||||
assert badge_class.description == json_class['description']
|
||||
assert badge_class.criteria == json_class['criteria']
|
||||
assert (badge_class.course_id and six.text_type(badge_class.course_id)) == json_class['course_id']
|
||||
|
||||
def check_assertion_structure(self, assertion, json_assertion):
|
||||
"""
|
||||
Check a JSON response against a known assertion object.
|
||||
"""
|
||||
self.assertEqual(assertion.image_url, json_assertion['image_url'])
|
||||
self.assertEqual(assertion.assertion_url, json_assertion['assertion_url'])
|
||||
assert assertion.image_url == json_assertion['image_url']
|
||||
assert assertion.assertion_url == json_assertion['assertion_url']
|
||||
self.check_class_structure(assertion.badge_class, json_assertion['badge_class'])
|
||||
|
||||
def get_course_id(self, wildcard, badge_class):
|
||||
@@ -105,7 +105,7 @@ class TestUserBadgeAssertions(UserAssertionTestCase):
|
||||
for dummy in range(3):
|
||||
self.create_badge_class(False)
|
||||
response = self.get_json(self.url())
|
||||
self.assertEqual(len(response['results']), 4)
|
||||
assert len(response['results']) == 4
|
||||
|
||||
def test_assertion_structure(self):
|
||||
badge_class = self.create_badge_class(False)
|
||||
@@ -134,10 +134,10 @@ class TestUserCourseBadgeAssertions(UserAssertionTestCase):
|
||||
for dummy in range(6):
|
||||
BadgeAssertionFactory.create(badge_class=badge_class)
|
||||
response = self.get_json(self.url(), data={'course_id': str(course_key)})
|
||||
self.assertEqual(len(response['results']), 3)
|
||||
assert len(response['results']) == 3
|
||||
unused_course = CourseFactory.create()
|
||||
response = self.get_json(self.url(), data={'course_id': str(unused_course.location.course_key)})
|
||||
self.assertEqual(len(response['results']), 0)
|
||||
assert len(response['results']) == 0
|
||||
|
||||
def test_assertion_structure(self):
|
||||
"""
|
||||
@@ -187,14 +187,14 @@ class TestUserBadgeAssertionsByClass(UserAssertionTestCase):
|
||||
expected_length = 4
|
||||
else:
|
||||
expected_length = 3
|
||||
self.assertEqual(len(response['results']), expected_length)
|
||||
assert len(response['results']) == expected_length
|
||||
unused_class = self.create_badge_class(check_course, slug='unused_slug', issuing_component='unused_component')
|
||||
|
||||
response = self.get_json(
|
||||
self.url(),
|
||||
data=self.get_qs_args(check_course, wildcard, unused_class),
|
||||
)
|
||||
self.assertEqual(len(response['results']), 0)
|
||||
assert len(response['results']) == 0
|
||||
|
||||
def check_badge_class_assertion(self, check_course, wildcard, badge_class):
|
||||
"""
|
||||
|
||||
@@ -72,22 +72,20 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
"""
|
||||
Make sure the handler generates the correct URLs for different API tasks.
|
||||
"""
|
||||
self.assertEqual(self.handler._base_url, 'https://example.com/v1/issuer/issuers/test-issuer') # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(self.handler._badge_create_url, 'https://example.com/v1/issuer/issuers/test-issuer/badges') # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(
|
||||
self.handler._badge_url('test_slug_here'), # lint-amnesty, pylint: disable=no-member
|
||||
'https://example.com/v1/issuer/issuers/test-issuer/badges/test_slug_here'
|
||||
)
|
||||
self.assertEqual(
|
||||
self.handler._assertion_url('another_test_slug'), # lint-amnesty, pylint: disable=no-member
|
||||
'https://example.com/v1/issuer/issuers/test-issuer/badges/another_test_slug/assertions'
|
||||
)
|
||||
assert self.handler._base_url == 'https://example.com/v1/issuer/issuers/test-issuer'
|
||||
# lint-amnesty, pylint: disable=no-member
|
||||
assert self.handler._badge_create_url == 'https://example.com/v1/issuer/issuers/test-issuer/badges'
|
||||
# lint-amnesty, pylint: disable=no-member
|
||||
assert self.handler._badge_url('test_slug_here') ==\
|
||||
'https://example.com/v1/issuer/issuers/test-issuer/badges/test_slug_here'
|
||||
assert self.handler._assertion_url('another_test_slug') ==\
|
||||
'https://example.com/v1/issuer/issuers/test-issuer/badges/another_test_slug/assertions'
|
||||
|
||||
def check_headers(self, headers):
|
||||
"""
|
||||
Verify the a headers dict from a requests call matches the proper auth info.
|
||||
"""
|
||||
self.assertEqual(headers, {'Authorization': 'Token 12345'})
|
||||
assert headers == {'Authorization': 'Token 12345'}
|
||||
|
||||
def test_get_headers(self):
|
||||
"""
|
||||
@@ -102,20 +100,16 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
"""
|
||||
self.handler._create_badge(self.badge_class)
|
||||
args, kwargs = post.call_args
|
||||
self.assertEqual(args[0], 'https://example.com/v1/issuer/issuers/test-issuer/badges')
|
||||
self.assertEqual(kwargs['files']['image'][0], self.badge_class.image.name)
|
||||
self.assertIsInstance(kwargs['files']['image'][1], ImageFieldFile)
|
||||
self.assertEqual(kwargs['files']['image'][2], 'image/png')
|
||||
assert args[0] == 'https://example.com/v1/issuer/issuers/test-issuer/badges'
|
||||
assert kwargs['files']['image'][0] == self.badge_class.image.name
|
||||
assert isinstance(kwargs['files']['image'][1], ImageFieldFile)
|
||||
assert kwargs['files']['image'][2] == 'image/png'
|
||||
self.check_headers(kwargs['headers'])
|
||||
self.assertEqual(
|
||||
kwargs['data'],
|
||||
{
|
||||
'name': 'Test Badge',
|
||||
assert kwargs['data'] ==\
|
||||
{'name': 'Test Badge',
|
||||
'slug': EXAMPLE_SLUG,
|
||||
'criteria': 'https://example.com/syllabus',
|
||||
'description': "Yay! It's a test badge.",
|
||||
}
|
||||
)
|
||||
'description': "Yay! It's a test badge."}
|
||||
|
||||
def test_ensure_badge_created_cache(self):
|
||||
"""
|
||||
@@ -124,7 +118,7 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
BadgrBackend.badges.append(EXAMPLE_SLUG)
|
||||
self.handler._create_badge = Mock()
|
||||
self.handler._ensure_badge_created(self.badge_class) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertFalse(self.handler._create_badge.called)
|
||||
assert not self.handler._create_badge.called
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -133,38 +127,35 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
('no_course_badge_class', 'test_componenttest_slug')
|
||||
)
|
||||
def test_slugs(self, badge_class_type, slug):
|
||||
self.assertEqual(self.handler._slugify(getattr(self, badge_class_type)), slug) # lint-amnesty, pylint: disable=no-member
|
||||
assert self.handler._slugify(getattr(self, badge_class_type)) == slug
|
||||
# lint-amnesty, pylint: disable=no-member
|
||||
|
||||
@patch('requests.get')
|
||||
def test_ensure_badge_created_checks(self, get):
|
||||
response = Mock()
|
||||
response.status_code = 200
|
||||
get.return_value = response
|
||||
self.assertNotIn('test_componenttest_slug', BadgrBackend.badges)
|
||||
assert 'test_componenttest_slug' not in BadgrBackend.badges
|
||||
self.handler._create_badge = Mock()
|
||||
self.handler._ensure_badge_created(self.badge_class) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertTrue(get.called)
|
||||
assert get.called
|
||||
args, kwargs = get.call_args
|
||||
self.assertEqual(
|
||||
args[0],
|
||||
'https://example.com/v1/issuer/issuers/test-issuer/badges/' +
|
||||
EXAMPLE_SLUG
|
||||
)
|
||||
assert args[0] == ('https://example.com/v1/issuer/issuers/test-issuer/badges/' + EXAMPLE_SLUG)
|
||||
self.check_headers(kwargs['headers'])
|
||||
self.assertIn(EXAMPLE_SLUG, BadgrBackend.badges)
|
||||
self.assertFalse(self.handler._create_badge.called)
|
||||
assert EXAMPLE_SLUG in BadgrBackend.badges
|
||||
assert not self.handler._create_badge.called
|
||||
|
||||
@patch('requests.get')
|
||||
def test_ensure_badge_created_creates(self, get):
|
||||
response = Mock()
|
||||
response.status_code = 404
|
||||
get.return_value = response
|
||||
self.assertNotIn(EXAMPLE_SLUG, BadgrBackend.badges)
|
||||
assert EXAMPLE_SLUG not in BadgrBackend.badges
|
||||
self.handler._create_badge = Mock()
|
||||
self.handler._ensure_badge_created(self.badge_class) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertTrue(self.handler._create_badge.called)
|
||||
self.assertEqual(self.handler._create_badge.call_args, call(self.badge_class))
|
||||
self.assertIn(EXAMPLE_SLUG, BadgrBackend.badges)
|
||||
assert self.handler._create_badge.called
|
||||
assert self.handler._create_badge.call_args == call(self.badge_class)
|
||||
assert EXAMPLE_SLUG in BadgrBackend.badges
|
||||
|
||||
@patch('requests.post')
|
||||
def test_badge_creation_event(self, post):
|
||||
@@ -180,21 +171,13 @@ class BadgrBackendTestCase(ModuleStoreTestCase, EventTrackingTestCase):
|
||||
self.recreate_tracker()
|
||||
self.handler._create_assertion(self.badge_class, self.user, 'https://example.com/irrefutable_proof') # lint-amnesty, pylint: disable=no-member
|
||||
args, kwargs = post.call_args
|
||||
self.assertEqual(
|
||||
args[0],
|
||||
'https://example.com/v1/issuer/issuers/test-issuer/badges/' +
|
||||
EXAMPLE_SLUG +
|
||||
'/assertions'
|
||||
)
|
||||
assert args[0] == (('https://example.com/v1/issuer/issuers/test-issuer/badges/' + EXAMPLE_SLUG) + '/assertions')
|
||||
self.check_headers(kwargs['headers'])
|
||||
assertion = BadgeAssertion.objects.get(user=self.user, badge_class__course_id=self.course.location.course_key)
|
||||
self.assertEqual(assertion.data, result)
|
||||
self.assertEqual(assertion.image_url, 'http://www.example.com/example.png')
|
||||
self.assertEqual(assertion.assertion_url, 'http://www.example.com/example')
|
||||
self.assertEqual(kwargs['data'], {
|
||||
'email': 'example@example.com',
|
||||
'evidence': 'https://example.com/irrefutable_proof'
|
||||
})
|
||||
assert assertion.data == result
|
||||
assert assertion.image_url == 'http://www.example.com/example.png'
|
||||
assert assertion.assertion_url == 'http://www.example.com/example'
|
||||
assert kwargs['data'] == {'email': 'example@example.com', 'evidence': 'https://example.com/irrefutable_proof'}
|
||||
assert_event_matches({
|
||||
'name': 'edx.badge.assertion.created',
|
||||
'data': {
|
||||
|
||||
@@ -31,33 +31,22 @@ class CourseCompleteTestCase(ModuleStoreTestCase):
|
||||
Verify slug generation is working as expected. If this test fails, the algorithm has changed, and it will cause
|
||||
the handler to lose track of all badges it made in the past.
|
||||
"""
|
||||
self.assertEqual(
|
||||
course_complete.course_slug(self.course_key, 'honor'),
|
||||
'edxcourse_testtest_run_honor_fc5519b'
|
||||
)
|
||||
self.assertEqual(
|
||||
course_complete.course_slug(self.course_key, 'verified'),
|
||||
'edxcourse_testtest_run_verified_a199ec0'
|
||||
)
|
||||
assert course_complete.course_slug(self.course_key, 'honor') == 'edxcourse_testtest_run_honor_fc5519b'
|
||||
assert course_complete.course_slug(self.course_key, 'verified') == 'edxcourse_testtest_run_verified_a199ec0'
|
||||
|
||||
def test_dated_description(self):
|
||||
"""
|
||||
Verify that a course with start/end dates contains a description with them.
|
||||
"""
|
||||
self.assertEqual(
|
||||
course_complete.badge_description(self.course, 'honor'),
|
||||
'Completed the course "Badged" (honor, 2015-05-19 - 2015-05-20)'
|
||||
)
|
||||
assert course_complete.badge_description(self.course, 'honor') ==\
|
||||
'Completed the course "Badged" (honor, 2015-05-19 - 2015-05-20)'
|
||||
|
||||
def test_self_paced_description(self):
|
||||
"""
|
||||
Verify that a badge created for a course with no end date gets a different description.
|
||||
"""
|
||||
self.course.end = None
|
||||
self.assertEqual(
|
||||
course_complete.badge_description(self.course, 'honor'),
|
||||
'Completed the course "Badged" (honor)'
|
||||
)
|
||||
assert course_complete.badge_description(self.course, 'honor') == 'Completed the course "Badged" (honor)'
|
||||
|
||||
def test_evidence_url(self):
|
||||
"""
|
||||
@@ -76,7 +65,5 @@ class CourseCompleteTestCase(ModuleStoreTestCase):
|
||||
name=user.profile.name,
|
||||
verify_uuid=uuid4().hex
|
||||
)
|
||||
self.assertEqual(
|
||||
'https://edx.org/certificates/{}?evidence_visit=1'.format(cert.verify_uuid),
|
||||
course_complete.evidence_url(user.id, self.course_key)
|
||||
)
|
||||
assert f'https://edx.org/certificates/{cert.verify_uuid}?evidence_visit=1' ==\
|
||||
course_complete.evidence_url(user.id, self.course_key)
|
||||
|
||||
@@ -51,7 +51,7 @@ class CourseEnrollmentBadgeTest(ModuleStoreTestCase):
|
||||
user = UserFactory()
|
||||
course = CourseFactory()
|
||||
CourseEnrollment.enroll(user, course_key=course.location.course_key)
|
||||
self.assertFalse(user.badgeassertion_set.all())
|
||||
assert not user.badgeassertion_set.all()
|
||||
|
||||
@unpack
|
||||
@data((1, 3), (2, 5), (3, 8))
|
||||
@@ -64,8 +64,8 @@ class CourseEnrollmentBadgeTest(ModuleStoreTestCase):
|
||||
for course in courses:
|
||||
CourseEnrollment.enroll(user, course_key=course.location.course_key)
|
||||
assertions = user.badgeassertion_set.all().order_by('id')
|
||||
self.assertEqual(user.badgeassertion_set.all().count(), checkpoint)
|
||||
self.assertEqual(assertions[checkpoint - 1].badge_class, self.badge_classes[checkpoint - 1])
|
||||
assert user.badgeassertion_set.all().count() == checkpoint
|
||||
assert assertions[(checkpoint - 1)].badge_class == self.badge_classes[(checkpoint - 1)]
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -104,7 +104,7 @@ class CourseCompletionBadgeTest(ModuleStoreTestCase):
|
||||
GeneratedCertificate(
|
||||
user=user, course_id=course.location.course_key, status=CertificateStatuses.downloadable
|
||||
).save()
|
||||
self.assertFalse(user.badgeassertion_set.all())
|
||||
assert not user.badgeassertion_set.all()
|
||||
|
||||
@unpack
|
||||
@data((1, 2), (2, 6), (3, 9))
|
||||
@@ -119,8 +119,8 @@ class CourseCompletionBadgeTest(ModuleStoreTestCase):
|
||||
user=user, course_id=course.location.course_key, status=CertificateStatuses.downloadable
|
||||
).save()
|
||||
assertions = user.badgeassertion_set.all().order_by('id')
|
||||
self.assertEqual(user.badgeassertion_set.all().count(), checkpoint)
|
||||
self.assertEqual(assertions[checkpoint - 1].badge_class, self.badge_classes[checkpoint - 1])
|
||||
assert user.badgeassertion_set.all().count() == checkpoint
|
||||
assert assertions[(checkpoint - 1)].badge_class == self.badge_classes[(checkpoint - 1)]
|
||||
|
||||
|
||||
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
|
||||
@@ -161,7 +161,7 @@ class CourseGroupBadgeTest(ModuleStoreTestCase):
|
||||
GeneratedCertificate(
|
||||
user=user, course_id=course.location.course_key, status=CertificateStatuses.downloadable
|
||||
).save()
|
||||
self.assertFalse(user.badgeassertion_set.all())
|
||||
assert not user.badgeassertion_set.all()
|
||||
|
||||
def test_group_matches(self):
|
||||
"""
|
||||
@@ -176,9 +176,9 @@ class CourseGroupBadgeTest(ModuleStoreTestCase):
|
||||
).save()
|
||||
# We don't award badges until all three are set.
|
||||
if i + 1 == len(course_keys):
|
||||
self.assertTrue(badge_class.get_for_user(user))
|
||||
assert badge_class.get_for_user(user)
|
||||
else:
|
||||
self.assertFalse(badge_class.get_for_user(user))
|
||||
assert not badge_class.get_for_user(user)
|
||||
classes = [badge.badge_class.id for badge in user.badgeassertion_set.all()]
|
||||
source_classes = [badge.id for badge in self.badge_classes]
|
||||
self.assertEqual(classes, source_classes)
|
||||
assert classes == source_classes
|
||||
|
||||
@@ -76,6 +76,7 @@ class BadgeClass(models.Model):
|
||||
cls, slug, issuing_component, display_name=None, description=None, criteria=None, image_file_handle=None,
|
||||
mode='', course_id=None, create=True
|
||||
):
|
||||
# TODO method should be renamed to getorcreate instead
|
||||
"""
|
||||
Looks up a badge class by its slug, issuing component, and course_id and returns it should it exist.
|
||||
If it does not exist, and create is True, creates it according to the arguments. Otherwise, returns None.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Tests for the Badges app models.
|
||||
"""
|
||||
|
||||
|
||||
import pytest
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.images import ImageFile
|
||||
from django.core.files.storage import default_storage
|
||||
@@ -49,19 +49,15 @@ class BadgeImageConfigurationTest(TestCase):
|
||||
Verify that creating two configurations as default is not permitted.
|
||||
"""
|
||||
CourseCompleteImageConfiguration(mode='test', icon=get_image('good'), default=True).save()
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
CourseCompleteImageConfiguration(mode='test2', icon=get_image('good'), default=True).full_clean
|
||||
)
|
||||
pytest.raises(ValidationError, CourseCompleteImageConfiguration(mode='test2', icon=get_image('good'),
|
||||
default=True).full_clean)
|
||||
|
||||
def test_runs_validator(self):
|
||||
"""
|
||||
Verify that the image validator is triggered when cleaning the model.
|
||||
"""
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
CourseCompleteImageConfiguration(mode='test2', icon=get_image('unbalanced')).full_clean
|
||||
)
|
||||
pytest.raises(ValidationError, CourseCompleteImageConfiguration(mode='test2', icon=get_image('unbalanced'))
|
||||
.full_clean)
|
||||
|
||||
|
||||
class DummyBackend(object):
|
||||
@@ -97,7 +93,7 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
"""
|
||||
Verify the BadgeClass fetches the backend properly.
|
||||
"""
|
||||
self.assertIsInstance(BadgeClass().backend, DummyBackend)
|
||||
assert isinstance(BadgeClass().backend, DummyBackend)
|
||||
|
||||
def test_get_badge_class_preexisting(self):
|
||||
"""
|
||||
@@ -110,11 +106,11 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
criteria='test', display_name='Testola', image_file_handle=get_image('good')
|
||||
)
|
||||
# These defaults are set on the factory.
|
||||
self.assertEqual(badge_class.criteria, 'https://example.com/syllabus')
|
||||
self.assertEqual(badge_class.display_name, 'Test Badge')
|
||||
self.assertEqual(badge_class.description, "Yay! It's a test badge.")
|
||||
assert badge_class.criteria == 'https://example.com/syllabus'
|
||||
assert badge_class.display_name == 'Test Badge'
|
||||
assert badge_class.description == "Yay! It's a test badge."
|
||||
# File name won't always be the same.
|
||||
self.assertEqual(badge_class.image.path, premade_badge_class.image.path)
|
||||
assert badge_class.image.path == premade_badge_class.image.path
|
||||
|
||||
def test_unique_for_course(self):
|
||||
"""
|
||||
@@ -131,8 +127,8 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
criteria='test', display_name='Testola', image_file_handle=get_image('good'),
|
||||
course_id=course_key,
|
||||
)
|
||||
self.assertNotEqual(badge_class.id, course_badge_class.id)
|
||||
self.assertEqual(course_badge_class.id, premade_badge_class.id)
|
||||
assert badge_class.id != course_badge_class.id
|
||||
assert course_badge_class.id == premade_badge_class.id
|
||||
|
||||
def test_get_badge_class_course_disabled(self):
|
||||
"""
|
||||
@@ -140,7 +136,7 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
exception.
|
||||
"""
|
||||
course_key = CourseFactory.create(metadata={'issue_badges': False}).location.course_key
|
||||
with self.assertRaises(CourseBadgesDisabledError):
|
||||
with pytest.raises(CourseBadgesDisabledError):
|
||||
BadgeClass.get_badge_class(
|
||||
slug='test_slug', issuing_component='test_component', description='Attempted override',
|
||||
criteria='test', display_name='Testola', image_file_handle=get_image('good'),
|
||||
@@ -157,13 +153,13 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
image_file_handle=get_image('good')
|
||||
)
|
||||
# This should have been saved before being passed back.
|
||||
self.assertTrue(badge_class.id)
|
||||
self.assertEqual(badge_class.slug, 'new_slug')
|
||||
self.assertEqual(badge_class.issuing_component, 'new_component')
|
||||
self.assertEqual(badge_class.description, 'This is a test')
|
||||
self.assertEqual(badge_class.criteria, 'https://example.com/test_criteria')
|
||||
self.assertEqual(badge_class.display_name, 'Super Badge')
|
||||
self.assertTrue('good' in badge_class.image.name.rsplit('/', 1)[-1]) # lint-amnesty, pylint: disable=wrong-assert-type
|
||||
assert badge_class.id
|
||||
assert badge_class.slug == 'new_slug'
|
||||
assert badge_class.issuing_component == 'new_component'
|
||||
assert badge_class.description == 'This is a test'
|
||||
assert badge_class.criteria == 'https://example.com/test_criteria'
|
||||
assert badge_class.display_name == 'Super Badge'
|
||||
assert 'good' in badge_class.image.name.rsplit('/', 1)[(- 1)]
|
||||
|
||||
def test_get_badge_class_nocreate(self):
|
||||
"""
|
||||
@@ -172,19 +168,20 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
badge_class = BadgeClass.get_badge_class(
|
||||
slug='new_slug', issuing_component='new_component', create=False
|
||||
)
|
||||
self.assertIsNone(badge_class)
|
||||
assert badge_class is None
|
||||
# Run this twice to verify there wasn't a background creation of the badge.
|
||||
badge_class = BadgeClass.get_badge_class(
|
||||
slug='new_slug', issuing_component='new_component', description=None,
|
||||
criteria=None, display_name=None,
|
||||
image_file_handle=None, create=False
|
||||
)
|
||||
self.assertIsNone(badge_class)
|
||||
assert badge_class is None
|
||||
|
||||
def test_get_badge_class_image_validate(self):
|
||||
"""
|
||||
Verify handing a broken image to get_badge_class raises a validation error upon creation.
|
||||
"""
|
||||
# TODO Test should be updated, this doc doesn't makes sense, the object eventually gets created
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
BadgeClass.get_badge_class,
|
||||
@@ -197,12 +194,9 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
"""
|
||||
Verify handing incomplete data for required fields when making a badge class raises an Integrity error.
|
||||
"""
|
||||
self.assertRaises(
|
||||
IntegrityError,
|
||||
BadgeClass.get_badge_class,
|
||||
slug='new_slug', issuing_component='new_component',
|
||||
image_file_handle=get_image('good')
|
||||
)
|
||||
image = get_image('good')
|
||||
pytest.raises(IntegrityError, BadgeClass.get_badge_class, slug='new_slug', issuing_component='new_component',
|
||||
image_file_handle=image)
|
||||
|
||||
def test_get_for_user(self):
|
||||
"""
|
||||
@@ -210,9 +204,9 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
"""
|
||||
user = UserFactory.create()
|
||||
badge_class = BadgeClassFactory.create()
|
||||
self.assertFalse(badge_class.get_for_user(user))
|
||||
assert not badge_class.get_for_user(user)
|
||||
assertion = BadgeAssertionFactory.create(badge_class=badge_class, user=user)
|
||||
self.assertEqual(list(badge_class.get_for_user(user)), [assertion])
|
||||
assert list(badge_class.get_for_user(user)) == [assertion]
|
||||
|
||||
@override_settings(BADGING_BACKEND='lms.djangoapps.badges.backends.badgr.BadgrBackend', BADGR_API_TOKEN='test')
|
||||
@patch('lms.djangoapps.badges.backends.badgr.BadgrBackend.award')
|
||||
@@ -223,20 +217,15 @@ class BadgeClassTest(ModuleStoreTestCase):
|
||||
user = UserFactory.create()
|
||||
badge_class = BadgeClassFactory.create()
|
||||
badge_class.award(user, evidence_url='http://example.com/evidence')
|
||||
self.assertTrue(mock_award.called)
|
||||
assert mock_award.called
|
||||
mock_award.assert_called_with(badge_class, user, evidence_url='http://example.com/evidence')
|
||||
|
||||
def test_runs_validator(self):
|
||||
"""
|
||||
Verify that the image validator is triggered when cleaning the model.
|
||||
"""
|
||||
self.assertRaises(
|
||||
ValidationError,
|
||||
BadgeClass(
|
||||
slug='test', issuing_component='test2', criteria='test3',
|
||||
description='test4', image=get_image('unbalanced')
|
||||
).full_clean
|
||||
)
|
||||
pytest.raises(ValidationError, BadgeClass(slug='test', issuing_component='test2', criteria='test3',
|
||||
description='test4', image=get_image('unbalanced')).full_clean)
|
||||
|
||||
|
||||
class BadgeAssertionTest(ModuleStoreTestCase):
|
||||
@@ -262,12 +251,12 @@ class BadgeAssertionTest(ModuleStoreTestCase):
|
||||
assertions.sort()
|
||||
assertions_for_user = [badge.id for badge in BadgeAssertion.assertions_for_user(user)]
|
||||
assertions_for_user.sort()
|
||||
self.assertEqual(assertions_for_user, assertions)
|
||||
assert assertions_for_user == assertions
|
||||
course_scoped_assertions = [
|
||||
badge.id for badge in BadgeAssertion.assertions_for_user(user, course_id=course_key)
|
||||
]
|
||||
course_scoped_assertions.sort()
|
||||
self.assertEqual(course_scoped_assertions, course_assertions)
|
||||
assert course_scoped_assertions == course_assertions
|
||||
|
||||
|
||||
class ValidBadgeImageTest(TestCase):
|
||||
|
||||
@@ -34,11 +34,11 @@ class TestHeader(TestCase):
|
||||
with mock.patch('lms.djangoapps.branding.api.staticfiles_storage.url', return_value=cdn_url):
|
||||
logo_url = get_logo_url()
|
||||
|
||||
self.assertEqual(logo_url, cdn_url)
|
||||
assert logo_url == cdn_url
|
||||
|
||||
def test_home_url(self):
|
||||
expected_url = get_home_url()
|
||||
self.assertEqual(reverse('dashboard'), expected_url)
|
||||
assert reverse('dashboard') == expected_url
|
||||
|
||||
|
||||
class TestFooter(TestCase):
|
||||
@@ -169,7 +169,7 @@ class TestFooter(TestCase):
|
||||
'text': 'Take free online courses at edX.org',
|
||||
},
|
||||
}
|
||||
self.assertEqual(actual_footer, expected_footer)
|
||||
assert actual_footer == expected_footer
|
||||
|
||||
@with_site_configuration(configuration=test_config_disabled_contact_us)
|
||||
def test_get_footer_disabled_contact_form(self):
|
||||
@@ -177,8 +177,8 @@ class TestFooter(TestCase):
|
||||
Test retrieving the footer with disabled contact form.
|
||||
"""
|
||||
actual_footer = get_footer(is_secure=True)
|
||||
self.assertEqual(any(l['name'] == 'contact' for l in actual_footer['connect_links']), False)
|
||||
self.assertEqual(any(l['name'] == 'contact' for l in actual_footer['navigation_links']), False)
|
||||
assert any(((l['name'] == 'contact') for l in actual_footer['connect_links'])) is False
|
||||
assert any(((l['name'] == 'contact') for l in actual_footer['navigation_links'])) is False
|
||||
|
||||
@with_site_configuration(configuration=test_config_custom_url_contact_us)
|
||||
def test_get_footer_custom_contact_url(self):
|
||||
@@ -187,13 +187,7 @@ class TestFooter(TestCase):
|
||||
"""
|
||||
actual_footer = get_footer(is_secure=True)
|
||||
contact_us_link = [l for l in actual_footer['connect_links'] if l['name'] == 'contact'][0]
|
||||
self.assertEqual(
|
||||
contact_us_link['url'],
|
||||
test_config_custom_url_contact_us['CONTACT_US_CUSTOM_LINK']
|
||||
)
|
||||
assert contact_us_link['url'] == test_config_custom_url_contact_us['CONTACT_US_CUSTOM_LINK']
|
||||
|
||||
navigation_link_contact_us = [l for l in actual_footer['navigation_links'] if l['name'] == 'contact'][0]
|
||||
self.assertEqual(
|
||||
navigation_link_contact_us['url'],
|
||||
test_config_custom_url_contact_us['CONTACT_US_CUSTOM_LINK']
|
||||
)
|
||||
assert navigation_link_contact_us['url'] == test_config_custom_url_contact_us['CONTACT_US_CUSTOM_LINK']
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Tests for the Video Branding configuration.
|
||||
"""
|
||||
|
||||
|
||||
import pytest
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.test import TestCase
|
||||
|
||||
@@ -30,14 +30,14 @@ class BrandingInfoConfigTest(TestCase):
|
||||
Tests creation of configuration.
|
||||
"""
|
||||
self.config.save()
|
||||
self.assertEqual(self.config.configuration, self.configuration_string)
|
||||
assert self.config.configuration == self.configuration_string
|
||||
|
||||
def test_clean_bad_json(self):
|
||||
"""
|
||||
Tests if bad Json string was given.
|
||||
"""
|
||||
self.config = BrandingInfoConfig(configuration='{"bad":"test"')
|
||||
self.assertRaises(ValidationError, self.config.clean)
|
||||
pytest.raises(ValidationError, self.config.clean)
|
||||
|
||||
def test_get(self):
|
||||
"""
|
||||
@@ -52,7 +52,7 @@ class BrandingInfoConfigTest(TestCase):
|
||||
"logo_tag": "Video hosted by XuetangX.com"
|
||||
}
|
||||
}
|
||||
self.assertEqual(self.config.get_config(), expected_config)
|
||||
assert self.config.get_config() == expected_config
|
||||
|
||||
def test_get_not_enabled(self):
|
||||
"""
|
||||
@@ -60,4 +60,4 @@ class BrandingInfoConfigTest(TestCase):
|
||||
"""
|
||||
self.config.enabled = False
|
||||
self.config.save()
|
||||
self.assertEqual(self.config.get_config(), {})
|
||||
assert self.config.get_config() == {}
|
||||
|
||||
@@ -61,17 +61,17 @@ class AnonymousIndexPageTest(ModuleStoreTestCase):
|
||||
"""
|
||||
self.client.logout()
|
||||
response = self.client.get(reverse('root'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WITH_STARTDATE)
|
||||
def test_anon_user_with_startdate_index(self):
|
||||
response = self.client.get('/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
@override_settings(FEATURES=FEATURES_WO_STARTDATE)
|
||||
def test_anon_user_no_startdate_index(self):
|
||||
response = self.client.get('/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
@override_settings(X_FRAME_OPTIONS='ALLOW')
|
||||
def test_allow_x_frame_options(self):
|
||||
@@ -81,7 +81,7 @@ class AnonymousIndexPageTest(ModuleStoreTestCase):
|
||||
|
||||
# check to see that the override value is honored
|
||||
resp = self.client.get('/')
|
||||
self.assertEqual(resp['X-Frame-Options'], 'ALLOW')
|
||||
assert resp['X-Frame-Options'] == 'ALLOW'
|
||||
|
||||
def test_deny_x_frame_options(self):
|
||||
"""
|
||||
@@ -90,7 +90,7 @@ class AnonymousIndexPageTest(ModuleStoreTestCase):
|
||||
|
||||
# check to see that the default setting is to DENY iframing
|
||||
resp = self.client.get('/')
|
||||
self.assertEqual(resp['X-Frame-Options'], 'DENY')
|
||||
assert resp['X-Frame-Options'] == 'DENY'
|
||||
|
||||
def test_edge_redirect_to_login(self):
|
||||
"""
|
||||
@@ -105,9 +105,9 @@ class AnonymousIndexPageTest(ModuleStoreTestCase):
|
||||
response = index(request)
|
||||
|
||||
# Response should be instance of HttpResponseRedirect.
|
||||
self.assertIsInstance(response, HttpResponseRedirect)
|
||||
assert isinstance(response, HttpResponseRedirect)
|
||||
# Location should be "/login".
|
||||
self.assertEqual(response._headers.get("location")[1], "/login") # pylint: disable=protected-access
|
||||
assert response._headers.get('location')[1] == '/login' # pylint: disable=protected-access
|
||||
|
||||
|
||||
class PreRequisiteCourseCatalog(ModuleStoreTestCase, LoginEnrollmentTestCase, MilestonesTestCaseMixin):
|
||||
@@ -199,13 +199,13 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
|
||||
feature flag settings
|
||||
"""
|
||||
response = self.client.get('/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# assert that the course discovery UI is not present
|
||||
self.assertNotContains(response, 'Search for a course')
|
||||
|
||||
# check the /courses view
|
||||
response = self.client.get(reverse('courses'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# assert that the course discovery UI is not present
|
||||
self.assertNotContains(response, 'Search for a course')
|
||||
@@ -223,13 +223,13 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
|
||||
feature flag settings
|
||||
"""
|
||||
response = self.client.get('/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# assert that the course discovery UI is not present
|
||||
self.assertContains(response, 'Search for a course')
|
||||
|
||||
# check the /courses view
|
||||
response = self.client.get(reverse('courses'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# assert that the course discovery UI is present
|
||||
self.assertContains(response, 'Search for a course')
|
||||
@@ -241,25 +241,25 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_COURSE_DISCOVERY': False})
|
||||
def test_course_cards_sorted_by_default_sorting(self):
|
||||
response = self.client.get('/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(template, 'index.html')
|
||||
assert template == 'index.html'
|
||||
|
||||
# by default the courses will be sorted by their creation dates, earliest first.
|
||||
self.assertEqual(context['courses'][0].id, self.starting_earlier.id)
|
||||
self.assertEqual(context['courses'][1].id, self.starting_later.id)
|
||||
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
|
||||
assert context['courses'][0].id == self.starting_earlier.id
|
||||
assert context['courses'][1].id == self.starting_later.id
|
||||
assert context['courses'][2].id == self.course_with_default_start_date.id
|
||||
|
||||
# check the /courses view
|
||||
response = self.client.get(reverse('courses'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(template, 'courseware/courses.html')
|
||||
assert template == 'courseware/courses.html'
|
||||
|
||||
# by default the courses will be sorted by their creation dates, earliest first.
|
||||
self.assertEqual(context['courses'][0].id, self.starting_earlier.id)
|
||||
self.assertEqual(context['courses'][1].id, self.starting_later.id)
|
||||
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
|
||||
assert context['courses'][0].id == self.starting_earlier.id
|
||||
assert context['courses'][1].id == self.starting_later.id
|
||||
assert context['courses'][2].id == self.course_with_default_start_date.id
|
||||
|
||||
@patch('common.djangoapps.student.views.management.render_to_response', RENDER_MOCK)
|
||||
@patch('lms.djangoapps.courseware.views.views.render_to_response', RENDER_MOCK)
|
||||
@@ -267,25 +267,25 @@ class IndexPageCourseCardsSortingTests(ModuleStoreTestCase):
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_COURSE_DISCOVERY': False})
|
||||
def test_course_cards_sorted_by_start_date_disabled(self):
|
||||
response = self.client.get('/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(template, 'index.html')
|
||||
assert template == 'index.html'
|
||||
|
||||
# now the courses will be sorted by their announcement dates.
|
||||
self.assertEqual(context['courses'][0].id, self.starting_later.id)
|
||||
self.assertEqual(context['courses'][1].id, self.starting_earlier.id)
|
||||
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
|
||||
assert context['courses'][0].id == self.starting_later.id
|
||||
assert context['courses'][1].id == self.starting_earlier.id
|
||||
assert context['courses'][2].id == self.course_with_default_start_date.id
|
||||
|
||||
# check the /courses view as well
|
||||
response = self.client.get(reverse('courses'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
((template, context), _) = RENDER_MOCK.call_args # pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(template, 'courseware/courses.html')
|
||||
assert template == 'courseware/courses.html'
|
||||
|
||||
# now the courses will be sorted by their announcement dates.
|
||||
self.assertEqual(context['courses'][0].id, self.starting_later.id)
|
||||
self.assertEqual(context['courses'][1].id, self.starting_earlier.id)
|
||||
self.assertEqual(context['courses'][2].id, self.course_with_default_start_date.id)
|
||||
assert context['courses'][0].id == self.starting_later.id
|
||||
assert context['courses'][1].id == self.starting_earlier.id
|
||||
assert context['courses'][2].id == self.course_with_default_start_date.id
|
||||
|
||||
|
||||
class IndexPageProgramsTests(SiteMixin, ModuleStoreTestCase):
|
||||
@@ -300,5 +300,5 @@ class IndexPageProgramsTests(SiteMixin, ModuleStoreTestCase):
|
||||
for url, dotted_path in views:
|
||||
with patch(dotted_path) as mock_get_programs_with_type:
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
mock_get_programs_with_type.assert_called_once()
|
||||
|
||||
@@ -29,7 +29,7 @@ class TestFooter(CacheIsolationTestCase):
|
||||
def test_feature_flag(self, accepts):
|
||||
self._set_feature_flag(False)
|
||||
resp = self._get_footer(accepts=accepts)
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
assert resp.status_code == 404
|
||||
|
||||
@ddt.data(
|
||||
# Open source version
|
||||
@@ -48,7 +48,7 @@ class TestFooter(CacheIsolationTestCase):
|
||||
with with_comprehensive_theme_context(theme):
|
||||
resp = self._get_footer(accepts=accepts)
|
||||
|
||||
self.assertEqual(resp["Content-Type"], content_type)
|
||||
assert resp['Content-Type'] == content_type
|
||||
self.assertContains(resp, content)
|
||||
|
||||
@mock.patch.dict(settings.FEATURES, {'ENABLE_FOOTER_MOBILE_APP_LINKS': True})
|
||||
@@ -58,52 +58,52 @@ class TestFooter(CacheIsolationTestCase):
|
||||
with with_comprehensive_theme_context(theme):
|
||||
resp = self._get_footer()
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
assert resp.status_code == 200
|
||||
json_data = json.loads(resp.content.decode('utf-8'))
|
||||
self.assertTrue(isinstance(json_data, dict))
|
||||
assert isinstance(json_data, dict)
|
||||
|
||||
# Logo
|
||||
self.assertIn("logo_image", json_data)
|
||||
assert 'logo_image' in json_data
|
||||
|
||||
# Links
|
||||
self.assertIn("navigation_links", json_data)
|
||||
assert 'navigation_links' in json_data
|
||||
for link in json_data["navigation_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
assert 'name' in link
|
||||
assert 'title' in link
|
||||
assert 'url' in link
|
||||
|
||||
# Social links
|
||||
self.assertIn("social_links", json_data)
|
||||
assert 'social_links' in json_data
|
||||
for link in json_data["social_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
self.assertIn("icon-class", link)
|
||||
self.assertIn("action", link)
|
||||
assert 'name' in link
|
||||
assert 'title' in link
|
||||
assert 'url' in link
|
||||
assert 'icon-class' in link
|
||||
assert 'action' in link
|
||||
|
||||
# Mobile links
|
||||
self.assertIn("mobile_links", json_data)
|
||||
assert 'mobile_links' in json_data
|
||||
for link in json_data["mobile_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
self.assertIn("image", link)
|
||||
assert 'name' in link
|
||||
assert 'title' in link
|
||||
assert 'url' in link
|
||||
assert 'image' in link
|
||||
|
||||
# Legal links
|
||||
self.assertIn("legal_links", json_data)
|
||||
assert 'legal_links' in json_data
|
||||
for link in json_data["legal_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
assert 'name' in link
|
||||
assert 'title' in link
|
||||
assert 'url' in link
|
||||
|
||||
# OpenEdX
|
||||
self.assertIn("openedx_link", json_data)
|
||||
self.assertIn("url", json_data["openedx_link"])
|
||||
self.assertIn("title", json_data["openedx_link"])
|
||||
self.assertIn("image", json_data["openedx_link"])
|
||||
assert 'openedx_link' in json_data
|
||||
assert 'url' in json_data['openedx_link']
|
||||
assert 'title' in json_data['openedx_link']
|
||||
assert 'image' in json_data['openedx_link']
|
||||
|
||||
# Copyright
|
||||
self.assertIn("copyright", json_data)
|
||||
assert 'copyright' in json_data
|
||||
|
||||
def test_absolute_urls_with_cdn(self):
|
||||
self._set_feature_flag(True)
|
||||
@@ -117,13 +117,13 @@ class TestFooter(CacheIsolationTestCase):
|
||||
with mock.patch('lms.djangoapps.branding.api.staticfiles_storage.url', return_value=cdn_url):
|
||||
resp = self._get_footer()
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
assert resp.status_code == 200
|
||||
json_data = json.loads(resp.content.decode('utf-8'))
|
||||
|
||||
self.assertEqual(json_data["logo_image"], cdn_url)
|
||||
assert json_data['logo_image'] == cdn_url
|
||||
|
||||
for link in json_data["mobile_links"]:
|
||||
self.assertEqual(link["url"], cdn_url)
|
||||
assert link['url'] == cdn_url
|
||||
|
||||
@ddt.data(
|
||||
("en", "registered trademarks"),
|
||||
@@ -136,11 +136,11 @@ class TestFooter(CacheIsolationTestCase):
|
||||
|
||||
# Load the footer with the specified language
|
||||
resp = self._get_footer(params={'language': language})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
assert resp.status_code == 200
|
||||
json_data = json.loads(resp.content.decode('utf-8'))
|
||||
|
||||
# Verify that the translation occurred
|
||||
self.assertIn(expected_copyright, json_data['copyright'])
|
||||
assert expected_copyright in json_data['copyright']
|
||||
|
||||
@ddt.data(
|
||||
# OpenEdX
|
||||
@@ -227,7 +227,7 @@ class TestFooter(CacheIsolationTestCase):
|
||||
}
|
||||
resp = self._get_footer(accepts="text/html", params=params)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
assert resp.status_code == 200
|
||||
|
||||
if include_language_selector:
|
||||
selected_language = language if language else 'en'
|
||||
@@ -238,7 +238,7 @@ class TestFooter(CacheIsolationTestCase):
|
||||
def test_no_supported_accept_type(self):
|
||||
self._set_feature_flag(True)
|
||||
resp = self._get_footer(accepts="application/x-shockwave-flash")
|
||||
self.assertEqual(resp.status_code, 406)
|
||||
assert resp.status_code == 406
|
||||
|
||||
def _set_feature_flag(self, enabled):
|
||||
"""Enable or disable the feature flag for the branding API end-points. """
|
||||
@@ -261,16 +261,16 @@ class TestFooter(CacheIsolationTestCase):
|
||||
""" Verify that the language selector is present and correctly configured."""
|
||||
# Verify the selector is included
|
||||
content = response.content.decode(response.charset)
|
||||
self.assertIn('footer-language-selector', content)
|
||||
assert 'footer-language-selector' in content
|
||||
|
||||
# Verify the correct language is selected
|
||||
self.assertIn(u'<option value="{}" selected="selected">'.format(selected_language), content)
|
||||
assert u'<option value="{}" selected="selected">'.format(selected_language) in content
|
||||
|
||||
# Verify the language choices
|
||||
for language in released_languages():
|
||||
if language.code == selected_language:
|
||||
continue
|
||||
self.assertIn(u'<option value="{}">'.format(language.code), content)
|
||||
assert u'<option value="{}">'.format(language.code) in content
|
||||
|
||||
|
||||
class TestIndex(SiteMixin, TestCase):
|
||||
@@ -289,7 +289,7 @@ class TestIndex(SiteMixin, TestCase):
|
||||
def test_index_does_not_redirect_without_site_override(self):
|
||||
""" Test index view does not redirect if MKTG_URLS['ROOT'] is not set """
|
||||
response = self.client.get(reverse("root"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_index_redirects_to_marketing_site_with_site_override(self):
|
||||
""" Test index view redirects if MKTG_URLS['ROOT'] is set in SiteConfiguration """
|
||||
@@ -309,4 +309,4 @@ class TestIndex(SiteMixin, TestCase):
|
||||
self.use_site(self.site_other)
|
||||
self.client.login(username=self.user.username, password="password")
|
||||
response = self.client.get(reverse("dashboard"))
|
||||
self.assertIn(self.site_configuration_other.site_values["MKTG_URLS"]["ROOT"], response.content.decode('utf-8'))
|
||||
assert self.site_configuration_other.site_values['MKTG_URLS']['ROOT'] in response.content.decode('utf-8')
|
||||
|
||||
@@ -69,7 +69,7 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
|
||||
# This is a checkbox, so on the post of opting out (that is, an Un-check of the box),
|
||||
# the Post that is sent will not contain 'receive_emails'
|
||||
response = self.client.post(url, {'course_id': text_type(self.course.id)})
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), {'success': True})
|
||||
assert json.loads(response.content.decode('utf-8')) == {'success': True}
|
||||
|
||||
self.client.logout()
|
||||
|
||||
@@ -83,11 +83,11 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# Assert that self.student.email not in mail.to, outbox should only contain "myself" target
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to[0], self.instructor.email)
|
||||
assert len(mail.outbox) == 1
|
||||
assert mail.outbox[0].to[0] == self.instructor.email
|
||||
|
||||
def test_optout_using_unsubscribe_link_in_email(self):
|
||||
"""
|
||||
@@ -100,7 +100,7 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
|
||||
unsubscribe_link = get_unsubscribed_link(self.student.username, text_type(self.course.id))
|
||||
response = self.client.post(unsubscribe_link, {'unsubscribe': True})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertContains(response, 'You have successfully unsubscribed from')
|
||||
|
||||
test_email = {
|
||||
@@ -110,8 +110,8 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
assert len(mail.outbox) == 1
|
||||
|
||||
def test_optin_course(self):
|
||||
"""
|
||||
@@ -119,11 +119,11 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
|
||||
"""
|
||||
url = reverse('change_email_settings')
|
||||
response = self.client.post(url, {'course_id': text_type(self.course.id), 'receive_emails': 'on'})
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), {'success': True})
|
||||
assert json.loads(response.content.decode('utf-8')) == {'success': True}
|
||||
|
||||
self.client.logout()
|
||||
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.student, self.course.id))
|
||||
assert CourseEnrollment.is_enrolled(self.student, self.course.id)
|
||||
|
||||
self.client.login(username=self.instructor.username, password="test")
|
||||
self.navigate_to_email_view()
|
||||
@@ -135,13 +135,13 @@ class TestOptoutCourseEmails(ModuleStoreTestCase):
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# Assert that self.student.email in mail.to, along with "myself" target
|
||||
self.assertEqual(len(mail.outbox), 2)
|
||||
assert len(mail.outbox) == 2
|
||||
sent_addresses = [message.to[0] for message in mail.outbox]
|
||||
self.assertIn(self.student.email, sent_addresses)
|
||||
self.assertIn(self.instructor.email, sent_addresses)
|
||||
assert self.student.email in sent_addresses
|
||||
assert self.instructor.email in sent_addresses
|
||||
|
||||
|
||||
@patch('lms.djangoapps.bulk_email.models.html_to_text', Mock(return_value='Mocking CourseEmail.text_message', autospec=True)) # lint-amnesty, pylint: disable=line-too-long
|
||||
@@ -173,7 +173,7 @@ class TestACEOptoutCourseEmails(ModuleStoreTestCase):
|
||||
post_data['receive_emails'] = 'on'
|
||||
|
||||
response = self.client.post(url, post_data)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), {'success': True})
|
||||
assert json.loads(response.content.decode('utf-8')) == {'success': True}
|
||||
|
||||
def test_policy_optedout(self):
|
||||
"""
|
||||
@@ -182,7 +182,7 @@ class TestACEOptoutCourseEmails(ModuleStoreTestCase):
|
||||
self._set_email_optout(True)
|
||||
|
||||
channel_mods = self.policy.check(self.create_test_message())
|
||||
self.assertEqual(channel_mods, PolicyResult(deny={ChannelType.EMAIL}))
|
||||
assert channel_mods == PolicyResult(deny={ChannelType.EMAIL})
|
||||
|
||||
def create_test_message(self):
|
||||
return Message(
|
||||
@@ -202,7 +202,7 @@ class TestACEOptoutCourseEmails(ModuleStoreTestCase):
|
||||
Make sure the policy allows ACE emails if the user is opted-in.
|
||||
"""
|
||||
channel_mods = self.policy.check(self.create_test_message())
|
||||
self.assertEqual(channel_mods, PolicyResult(deny=set()))
|
||||
assert channel_mods == PolicyResult(deny=set())
|
||||
|
||||
def test_policy_no_course_id(self):
|
||||
"""
|
||||
@@ -211,4 +211,4 @@ class TestACEOptoutCourseEmails(ModuleStoreTestCase):
|
||||
message = self.create_test_message()
|
||||
message.context = {}
|
||||
channel_mods = self.policy.check(message)
|
||||
self.assertEqual(channel_mods, PolicyResult(deny=set()))
|
||||
assert channel_mods == PolicyResult(deny=set())
|
||||
|
||||
@@ -183,7 +183,8 @@ class LocalizedFromAddressPlatformLangTestCase(SendEmailWithMockedUgettextMixin,
|
||||
"""
|
||||
Ensures that the source-code language (English) works well.
|
||||
"""
|
||||
self.assertIsNone(self.course.language) # Sanity check
|
||||
assert self.course.language is None
|
||||
# Sanity check
|
||||
message = self.send_email()
|
||||
self.assertRegex(message.from_email, '.*Course Staff.*')
|
||||
|
||||
@@ -192,7 +193,8 @@ class LocalizedFromAddressPlatformLangTestCase(SendEmailWithMockedUgettextMixin,
|
||||
"""
|
||||
Tests the fake Esperanto language to ensure proper gettext calls.
|
||||
"""
|
||||
self.assertIsNone(self.course.language) # Sanity check
|
||||
assert self.course.language is None
|
||||
# Sanity check
|
||||
message = self.send_email()
|
||||
self.assertRegex(message.from_email, 'EO .* Course Staff')
|
||||
|
||||
@@ -261,20 +263,15 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for myself'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# Check that outbox is as expected
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(len(mail.outbox[0].to), 1)
|
||||
self.assertEqual(mail.outbox[0].to[0], self.instructor.email)
|
||||
self.assertEqual(mail.outbox[0].subject, 'test subject for myself')
|
||||
self.assertEqual(
|
||||
mail.outbox[0].from_email,
|
||||
u'"{course_display_name}" Course Staff <{course_name}-no-reply@example.com>'.format(
|
||||
course_display_name=self.course.display_name,
|
||||
course_name=self.course.id.course
|
||||
)
|
||||
)
|
||||
assert len(mail.outbox) == 1
|
||||
assert len(mail.outbox[0].to) == 1
|
||||
assert mail.outbox[0].to[0] == self.instructor.email
|
||||
assert mail.outbox[0].subject == 'test subject for myself'
|
||||
assert mail.outbox[0].from_email == \
|
||||
f'"{self.course.display_name}" Course Staff <{self.course.id.course}-no-reply@example.com>'
|
||||
|
||||
def test_send_to_staff(self):
|
||||
"""
|
||||
@@ -287,10 +284,10 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for subject'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# the 1 is for the instructor in this test and others
|
||||
self.assertEqual(len(mail.outbox), 1 + len(self.staff))
|
||||
assert len(mail.outbox) == (1 + len(self.staff))
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
[e.to[0] for e in mail.outbox],
|
||||
@@ -311,7 +308,7 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for cohort'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
@@ -334,10 +331,10 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for cohort'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertEqual(len(mail.outbox), len(self.students) - 1)
|
||||
self.assertNotIn(self.students[-1].email, [e.to[0] for e in mail.outbox])
|
||||
assert len(mail.outbox) == (len(self.students) - 1)
|
||||
assert self.students[(- 1)].email not in [e.to[0] for e in mail.outbox]
|
||||
|
||||
def test_send_to_track(self):
|
||||
"""
|
||||
@@ -353,7 +350,7 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for test track',
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
@@ -391,12 +388,12 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for test_mode track',
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# Only the the student in the test mode in the course the email was
|
||||
# sent from should receive an email
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to[0], test_mode_student.email)
|
||||
assert len(mail.outbox) == 1
|
||||
assert mail.outbox[0].to[0] == test_mode_student.email
|
||||
|
||||
def test_send_to_all(self):
|
||||
"""
|
||||
@@ -410,10 +407,10 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# the 1 is for the instructor
|
||||
self.assertEqual(len(mail.outbox), 1 + len(self.staff) + len(self.students))
|
||||
assert len(mail.outbox) == ((1 + len(self.staff)) + len(self.students))
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
[e.to[0] for e in mail.outbox],
|
||||
@@ -451,7 +448,7 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
course_1 = CourseFactory.create()
|
||||
course_2 = CourseFactory.create()
|
||||
# make sure self.instructor isn't enrolled in the course
|
||||
self.assertFalse(CourseEnrollment.is_enrolled(self.instructor, self.course.id))
|
||||
assert not CourseEnrollment.is_enrolled(self.instructor, self.course.id)
|
||||
CourseEnrollment.enroll(self.instructor, course_1.id)
|
||||
CourseEnrollment.enroll(self.instructor, course_2.id)
|
||||
self.test_send_to_all()
|
||||
@@ -469,15 +466,15 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1 + len(self.staff) + len(self.students))
|
||||
assert len(mail.outbox) == ((1 + len(self.staff)) + len(self.students))
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
[e.to[0] for e in mail.outbox],
|
||||
[self.instructor.email] + [s.email for s in self.staff] + [s.email for s in self.students]
|
||||
)
|
||||
self.assertEqual(mail.outbox[0].subject, uni_subject)
|
||||
assert mail.outbox[0].subject == uni_subject
|
||||
|
||||
def test_unicode_students_send_to_all(self):
|
||||
"""
|
||||
@@ -496,9 +493,9 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1 + len(self.staff) + len(self.students))
|
||||
assert len(mail.outbox) == ((1 + len(self.staff)) + len(self.students))
|
||||
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
@@ -541,29 +538,26 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
escaped_encoded_unexpected_from_addr = escape(encoded_unexpected_from_addr)
|
||||
|
||||
# it's shorter than 320 characters when just encoded
|
||||
self.assertEqual(len(encoded_unexpected_from_addr), 318)
|
||||
assert len(encoded_unexpected_from_addr) == 318
|
||||
# escaping it brings it over that limit
|
||||
self.assertEqual(len(escaped_encoded_unexpected_from_addr), 324)
|
||||
assert len(escaped_encoded_unexpected_from_addr) == 324
|
||||
# when not escaped or encoded, it's well below 320 characters
|
||||
self.assertEqual(len(unexpected_from_addr), 137)
|
||||
assert len(unexpected_from_addr) == 137
|
||||
|
||||
self.login_as_user(instructor)
|
||||
send_mail_url = reverse('send_email', kwargs={'course_id': six.text_type(course.id)})
|
||||
response = self.client.post(send_mail_url, test_email)
|
||||
self.assertTrue(json.loads(response.content.decode('utf-8'))['success'])
|
||||
assert json.loads(response.content.decode('utf-8'))['success']
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
assert len(mail.outbox) == 1
|
||||
from_email = mail.outbox[0].from_email
|
||||
|
||||
expected_from_addr = (
|
||||
u'"{course_name}" Course Staff <{course_name}-no-reply@courseupdates.edx.org>'
|
||||
).format(course_name=course.id.course)
|
||||
|
||||
self.assertEqual(
|
||||
from_email,
|
||||
expected_from_addr
|
||||
)
|
||||
self.assertEqual(len(from_email), 61)
|
||||
assert from_email == expected_from_addr
|
||||
assert len(from_email) == 61
|
||||
|
||||
@override_settings(BULK_EMAIL_EMAILS_PER_TASK=3)
|
||||
@patch('lms.djangoapps.bulk_email.tasks.update_subtask_status')
|
||||
@@ -593,10 +587,10 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertEqual(mock_factory.emails_sent,
|
||||
1 + len(self.staff) + len(self.students) + LARGE_NUM_EMAILS - len(optouts))
|
||||
assert mock_factory.emails_sent == \
|
||||
((((1 + len(self.staff)) + len(self.students)) + LARGE_NUM_EMAILS) - len(optouts))
|
||||
outbox_contents = [e.to[0] for e in mail.outbox]
|
||||
should_send_contents = ([self.instructor.email] +
|
||||
[s.email for s in self.staff] +
|
||||
@@ -616,7 +610,7 @@ class TestEmailSendFromDashboardMockedHtmlToText(EmailSendFromDashboardTestCase)
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# check unsubscribe link in template
|
||||
for m in mail.outbox:
|
||||
@@ -649,9 +643,9 @@ class TestEmailSendFromDashboard(EmailSendFromDashboardTestCase):
|
||||
'message': uni_message
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1 + len(self.staff) + len(self.students))
|
||||
assert len(mail.outbox) == ((1 + len(self.staff)) + len(self.students))
|
||||
six.assertCountEqual(
|
||||
self,
|
||||
[e.to[0] for e in mail.outbox],
|
||||
@@ -659,7 +653,7 @@ class TestEmailSendFromDashboard(EmailSendFromDashboardTestCase):
|
||||
)
|
||||
|
||||
message_body = mail.outbox[0].body
|
||||
self.assertIn(uni_message, message_body)
|
||||
assert uni_message in message_body
|
||||
|
||||
|
||||
class TestCourseEmailContext(SharedModuleStoreTestCase):
|
||||
@@ -688,19 +682,14 @@ class TestCourseEmailContext(SharedModuleStoreTestCase):
|
||||
"""
|
||||
This test tests that the bulk email context uses http or https urls as appropriate.
|
||||
"""
|
||||
self.assertEqual(email_context['platform_name'], settings.PLATFORM_NAME)
|
||||
self.assertEqual(email_context['course_title'], self.course_title)
|
||||
self.assertEqual(email_context['course_url'],
|
||||
'{}://edx.org/courses/{}/{}/{}/'.format(scheme,
|
||||
self.course_org,
|
||||
self.course_number,
|
||||
self.course_run))
|
||||
self.assertEqual(email_context['course_image_url'],
|
||||
'{}://edx.org/c4x/{}/{}/asset/images_course_image.jpg'.format(scheme,
|
||||
self.course_org,
|
||||
self.course_number))
|
||||
self.assertEqual(email_context['email_settings_url'], '{}://edx.org/dashboard'.format(scheme))
|
||||
self.assertEqual(email_context['account_settings_url'], '{}://edx.org/account/settings'.format(scheme))
|
||||
assert email_context['platform_name'] == settings.PLATFORM_NAME
|
||||
assert email_context['course_title'] == self.course_title
|
||||
assert email_context['course_url'] == \
|
||||
f'{scheme}://edx.org/courses/{self.course_org}/{self.course_number}/{self.course_run}/'
|
||||
assert email_context['course_image_url'] == \
|
||||
f'{scheme}://edx.org/c4x/{self.course_org}/{self.course_number}/asset/images_course_image.jpg'
|
||||
assert email_context['email_settings_url'] == '{}://edx.org/dashboard'.format(scheme)
|
||||
assert email_context['account_settings_url'] == '{}://edx.org/account/settings'.format(scheme)
|
||||
|
||||
@override_settings(LMS_ROOT_URL="http://edx.org")
|
||||
def test_insecure_email_context(self):
|
||||
|
||||
@@ -7,7 +7,7 @@ Unit tests for handling email sending errors
|
||||
import json
|
||||
from itertools import cycle
|
||||
from smtplib import SMTPConnectError, SMTPDataError, SMTPServerDisconnected
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
from celery.states import RETRY, SUCCESS
|
||||
from django.conf import settings
|
||||
@@ -90,13 +90,13 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
'message': 'test message for myself'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# Test that we retry upon hitting a 4xx error
|
||||
self.assertTrue(retry.called)
|
||||
assert retry.called
|
||||
(__, kwargs) = retry.call_args
|
||||
exc = kwargs['exc']
|
||||
self.assertIsInstance(exc, SMTPDataError)
|
||||
assert isinstance(exc, SMTPDataError)
|
||||
|
||||
@patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True)
|
||||
@patch('lms.djangoapps.bulk_email.tasks.update_subtask_status')
|
||||
@@ -120,16 +120,16 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
# We shouldn't retry when hitting a 5xx error
|
||||
self.assertFalse(retry.called)
|
||||
assert not retry.called
|
||||
# Test that after the rejected email, the rest still successfully send
|
||||
((_entry_id, _current_task_id, subtask_status), _kwargs) = result.call_args
|
||||
self.assertEqual(subtask_status.skipped, 0)
|
||||
assert subtask_status.skipped == 0
|
||||
expected_fails = int((settings.BULK_EMAIL_EMAILS_PER_TASK + 3) / 4.0)
|
||||
self.assertEqual(subtask_status.failed, expected_fails)
|
||||
self.assertEqual(subtask_status.succeeded, settings.BULK_EMAIL_EMAILS_PER_TASK - expected_fails)
|
||||
assert subtask_status.failed == expected_fails
|
||||
assert subtask_status.succeeded == (settings.BULK_EMAIL_EMAILS_PER_TASK - expected_fails)
|
||||
|
||||
@patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True)
|
||||
@patch('lms.djangoapps.bulk_email.tasks.send_course_email.retry')
|
||||
@@ -145,12 +145,12 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
'message': 'test message for myself'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertTrue(retry.called)
|
||||
assert retry.called
|
||||
(__, kwargs) = retry.call_args
|
||||
exc = kwargs['exc']
|
||||
self.assertIsInstance(exc, SMTPServerDisconnected)
|
||||
assert isinstance(exc, SMTPServerDisconnected)
|
||||
|
||||
@patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True)
|
||||
@patch('lms.djangoapps.bulk_email.tasks.send_course_email.retry')
|
||||
@@ -167,12 +167,12 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
'message': 'test message for myself'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
self.assertTrue(retry.called)
|
||||
assert retry.called
|
||||
(__, kwargs) = retry.call_args
|
||||
exc = kwargs['exc']
|
||||
self.assertIsInstance(exc, SMTPConnectError)
|
||||
assert isinstance(exc, SMTPConnectError)
|
||||
|
||||
@patch('lms.djangoapps.bulk_email.tasks.SubtaskStatus.increment')
|
||||
@patch('lms.djangoapps.bulk_email.tasks.log')
|
||||
@@ -184,13 +184,13 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
course_id = self.course.id
|
||||
entry = InstructorTask.create(course_id, "task_type", "task_key", "task_input", self.instructor)
|
||||
task_input = {"email_id": -1}
|
||||
with self.assertRaises(CourseEmail.DoesNotExist):
|
||||
with pytest.raises(CourseEmail.DoesNotExist):
|
||||
perform_delegate_email_batches(entry.id, course_id, task_input, "action_name")
|
||||
((log_str, __, email_id), __) = mock_log.warning.call_args
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
self.assertIn('Failed to get CourseEmail with id', log_str)
|
||||
self.assertEqual(email_id, -1)
|
||||
self.assertFalse(result.called)
|
||||
assert mock_log.warning.called
|
||||
assert 'Failed to get CourseEmail with id' in log_str
|
||||
assert email_id == (- 1)
|
||||
assert not result.called
|
||||
|
||||
def test_nonexistent_course(self):
|
||||
"""
|
||||
@@ -201,7 +201,7 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
email.save()
|
||||
entry = InstructorTask.create(course_id, "task_type", "task_key", "task_input", self.instructor)
|
||||
task_input = {"email_id": email.id}
|
||||
with self.assertRaises(CourseRunNotFound):
|
||||
with pytest.raises(CourseRunNotFound):
|
||||
perform_delegate_email_batches(entry.id, course_id, task_input, "action_name")
|
||||
|
||||
def test_nonexistent_to_option(self):
|
||||
@@ -351,9 +351,9 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
global_email_context = {'course_title': 'dummy course'}
|
||||
with patch('lms.djangoapps.instructor_task.subtasks.InstructorTask.save') as mock_task_save:
|
||||
mock_task_save.side_effect = DatabaseError
|
||||
with self.assertRaises(DatabaseError):
|
||||
with pytest.raises(DatabaseError):
|
||||
send_course_email(entry_id, bogus_email_id, to_list, global_email_context, subtask_status.to_dict())
|
||||
self.assertEqual(mock_task_save.call_count, MAX_DATABASE_LOCK_RETRIES)
|
||||
assert mock_task_save.call_count == MAX_DATABASE_LOCK_RETRIES
|
||||
|
||||
def test_send_email_undefined_email(self):
|
||||
# test at a lower level, to ensure that the course gets checked down below too.
|
||||
@@ -365,7 +365,7 @@ class TestEmailErrors(ModuleStoreTestCase):
|
||||
initialize_subtask_info(entry, "emailed", 100, [subtask_id])
|
||||
subtask_status = SubtaskStatus.create(subtask_id)
|
||||
bogus_email_id = 1001
|
||||
with self.assertRaises(CourseEmail.DoesNotExist):
|
||||
with pytest.raises(CourseEmail.DoesNotExist):
|
||||
# we skip the call that updates subtask status, since we've not set up the InstructorTask
|
||||
# for the subtask, and it's not important to the test.
|
||||
with patch('lms.djangoapps.bulk_email.tasks.update_subtask_status'):
|
||||
|
||||
@@ -29,37 +29,35 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
|
||||
|
||||
def test_authorize_mongo_course(self):
|
||||
# Initially course shouldn't be authorized
|
||||
self.assertFalse(is_bulk_email_feature_enabled(self.course.id))
|
||||
assert not is_bulk_email_feature_enabled(self.course.id)
|
||||
# Test authorizing the course, which should totally work
|
||||
form_data = {'course_id': text_type(self.course.id), 'email_enabled': True}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
# Validation should work
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
# Check that this course is authorized
|
||||
self.assertTrue(is_bulk_email_feature_enabled(self.course.id))
|
||||
assert is_bulk_email_feature_enabled(self.course.id)
|
||||
|
||||
def test_repeat_course(self):
|
||||
# Initially course shouldn't be authorized
|
||||
self.assertFalse(is_bulk_email_feature_enabled(self.course.id))
|
||||
assert not is_bulk_email_feature_enabled(self.course.id)
|
||||
# Test authorizing the course, which should totally work
|
||||
form_data = {'course_id': text_type(self.course.id), 'email_enabled': True}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
# Validation should work
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
# Check that this course is authorized
|
||||
self.assertTrue(is_bulk_email_feature_enabled(self.course.id))
|
||||
assert is_bulk_email_feature_enabled(self.course.id)
|
||||
|
||||
# Now make a new course authorization with the same course id that tries to turn email off
|
||||
form_data = {'course_id': text_type(self.course.id), 'email_enabled': False}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
# Validation should not work because course_id field is unique
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertEqual(
|
||||
"Course authorization with this Course id already exists.",
|
||||
form._errors['course_id'][0] # pylint: disable=protected-access
|
||||
)
|
||||
assert not form.is_valid()
|
||||
assert 'Course authorization with this Course id already exists.' == form._errors['course_id'][0] # pylint: disable=protected-access, line-too-long
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
"The CourseAuthorization could not be created because the data didn't validate."
|
||||
@@ -67,7 +65,7 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
|
||||
form.save()
|
||||
|
||||
# Course should still be authorized (invalid attempt had no effect)
|
||||
self.assertTrue(is_bulk_email_feature_enabled(self.course.id))
|
||||
assert is_bulk_email_feature_enabled(self.course.id)
|
||||
|
||||
def test_form_typo(self):
|
||||
# Munge course id
|
||||
@@ -76,11 +74,11 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
|
||||
form_data = {'course_id': text_type(bad_id), 'email_enabled': True}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
# Validation shouldn't work
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
msg = u'Course not found.'
|
||||
msg += u' Entered course id was: "{0}".'.format(text_type(bad_id))
|
||||
self.assertEqual(msg, form._errors['course_id'][0]) # pylint: disable=protected-access
|
||||
assert msg == form._errors['course_id'][0] # pylint: disable=protected-access
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
@@ -92,11 +90,11 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
|
||||
form_data = {'course_id': "asd::**!@#$%^&*())//foobar!!", 'email_enabled': True}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
# Validation shouldn't work
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
msg = u'Course id invalid.'
|
||||
msg += u' Entered course id was: "asd::**!@#$%^&*())//foobar!!".'
|
||||
self.assertEqual(msg, form._errors['course_id'][0]) # pylint: disable=protected-access
|
||||
assert msg == form._errors['course_id'][0] # pylint: disable=protected-access
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
@@ -109,10 +107,10 @@ class CourseAuthorizationFormTest(ModuleStoreTestCase):
|
||||
form_data = {'course_id': self.course.id.run, 'email_enabled': True}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
# Validation shouldn't work
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
error_msg = form._errors['course_id'][0] # pylint: disable=protected-access
|
||||
self.assertIn(u'Entered course id was: "{0}".'.format(self.course.id.run), error_msg)
|
||||
assert u'Entered course id was: "{0}".'.format(self.course.id.run) in error_msg
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
@@ -135,7 +133,7 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': ''
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
def test_missing_message_body_in_plain(self):
|
||||
"""
|
||||
@@ -148,7 +146,7 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': ''
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
def test_blank_name_is_null(self):
|
||||
"""
|
||||
@@ -161,13 +159,13 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': ''
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
|
||||
# now inspect the database and make sure the blank name was stored as a NULL
|
||||
# Note this will throw an exception if it is not found
|
||||
cet = CourseEmailTemplate.objects.get(name=None)
|
||||
self.assertIsNotNone(cet)
|
||||
assert cet is not None
|
||||
|
||||
def test_name_with_only_spaces_is_null(self):
|
||||
"""
|
||||
@@ -180,13 +178,13 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': ' '
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
|
||||
# now inspect the database and make sure the whitespace only name was stored as a NULL
|
||||
# Note this will throw an exception if it is not found
|
||||
cet = CourseEmailTemplate.objects.get(name=None)
|
||||
self.assertIsNotNone(cet)
|
||||
assert cet is not None
|
||||
|
||||
def test_name_with_spaces_is_trimmed(self):
|
||||
"""
|
||||
@@ -199,13 +197,13 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': ' foo '
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
|
||||
# now inspect the database and make sure the name is properly
|
||||
# stripped
|
||||
cet = CourseEmailTemplate.objects.get(name='foo')
|
||||
self.assertIsNotNone(cet)
|
||||
assert cet is not None
|
||||
|
||||
def test_non_blank_name(self):
|
||||
"""
|
||||
@@ -218,13 +216,13 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': 'foo'
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
|
||||
# now inspect the database and make sure the blank name was stored as a NULL
|
||||
# Note this will throw an exception if it is not found
|
||||
cet = CourseEmailTemplate.objects.get(name='foo')
|
||||
self.assertIsNotNone(cet)
|
||||
assert cet is not None
|
||||
|
||||
def test_duplicate_name(self):
|
||||
"""
|
||||
@@ -239,12 +237,12 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': 'foo'
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
|
||||
# try to submit form with the same name
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
# try again with a name with extra whitespace
|
||||
# this should fail as we strip the whitespace away
|
||||
@@ -254,7 +252,7 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': ' foo '
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
# then try a different name
|
||||
form_data = {
|
||||
@@ -263,8 +261,8 @@ class CourseEmailTemplateFormTest(ModuleStoreTestCase):
|
||||
'name': 'bar'
|
||||
}
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
assert form.is_valid()
|
||||
form.save()
|
||||
|
||||
form = CourseEmailTemplateForm(form_data)
|
||||
self.assertFalse(form.is_valid())
|
||||
assert not form.is_valid()
|
||||
|
||||
@@ -5,6 +5,7 @@ Unit tests for bulk-email-related models.
|
||||
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
from django.core.management import call_command
|
||||
from django.test import TestCase
|
||||
@@ -42,11 +43,11 @@ class CourseEmailTest(ModuleStoreTestCase):
|
||||
subject = "dummy subject"
|
||||
html_message = "<html>dummy message</html>"
|
||||
email = CourseEmail.create(course_id, sender, [to_option], subject, html_message)
|
||||
self.assertEqual(email.course_id, course_id)
|
||||
self.assertIn(SEND_TO_STAFF, [target.target_type for target in email.targets.all()])
|
||||
self.assertEqual(email.subject, subject)
|
||||
self.assertEqual(email.html_message, html_message)
|
||||
self.assertEqual(email.sender, sender)
|
||||
assert email.course_id == course_id
|
||||
assert SEND_TO_STAFF in [target.target_type for target in email.targets.all()]
|
||||
assert email.subject == subject
|
||||
assert email.html_message == html_message
|
||||
assert email.sender == sender
|
||||
|
||||
def test_creation_with_optional_attributes(self):
|
||||
course_id = CourseKey.from_string('abc/123/doremi')
|
||||
@@ -59,13 +60,13 @@ class CourseEmailTest(ModuleStoreTestCase):
|
||||
email = CourseEmail.create(
|
||||
course_id, sender, [to_option], subject, html_message, template_name=template_name, from_addr=from_addr
|
||||
)
|
||||
self.assertEqual(email.course_id, course_id)
|
||||
self.assertEqual(email.targets.all()[0].target_type, SEND_TO_STAFF)
|
||||
self.assertEqual(email.subject, subject)
|
||||
self.assertEqual(email.html_message, html_message)
|
||||
self.assertEqual(email.sender, sender)
|
||||
self.assertEqual(email.template_name, template_name)
|
||||
self.assertEqual(email.from_addr, from_addr)
|
||||
assert email.course_id == course_id
|
||||
assert email.targets.all()[0].target_type == SEND_TO_STAFF
|
||||
assert email.subject == subject
|
||||
assert email.html_message == html_message
|
||||
assert email.sender == sender
|
||||
assert email.template_name == template_name
|
||||
assert email.from_addr == from_addr
|
||||
|
||||
def test_bad_to_option(self):
|
||||
course_id = CourseKey.from_string('abc/123/doremi')
|
||||
@@ -73,7 +74,7 @@ class CourseEmailTest(ModuleStoreTestCase):
|
||||
to_option = "fake"
|
||||
subject = "dummy subject"
|
||||
html_message = "<html>dummy message</html>"
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
CourseEmail.create(course_id, sender, to_option, subject, html_message)
|
||||
|
||||
@ddt.data(
|
||||
@@ -98,11 +99,11 @@ class CourseEmailTest(ModuleStoreTestCase):
|
||||
expiration_datetime=expiration_datetime,
|
||||
)
|
||||
email = CourseEmail.create(course_id, sender, [to_option], subject, html_message)
|
||||
self.assertEqual(len(email.targets.all()), 1)
|
||||
assert len(email.targets.all()) == 1
|
||||
target = email.targets.all()[0]
|
||||
self.assertEqual(target.target_type, SEND_TO_TRACK)
|
||||
self.assertEqual(target.short_display(), 'track-test')
|
||||
self.assertEqual(target.long_display(), 'Course mode: Test, Currency: usd')
|
||||
assert target.target_type == SEND_TO_TRACK
|
||||
assert target.short_display() == 'track-test'
|
||||
assert target.long_display() == 'Course mode: Test, Currency: usd'
|
||||
|
||||
@ddt.data(
|
||||
CourseMode.AUDIT,
|
||||
@@ -127,11 +128,11 @@ class CourseEmailTest(ModuleStoreTestCase):
|
||||
)
|
||||
|
||||
email = CourseEmail.create(course_id, sender, [to_option], subject, html_message)
|
||||
self.assertEqual(len(email.targets.all()), 1)
|
||||
assert len(email.targets.all()) == 1
|
||||
target = email.targets.all()[0]
|
||||
self.assertEqual(target.target_type, SEND_TO_TRACK)
|
||||
self.assertEqual(target.short_display(), 'track-{}'.format(free_mode))
|
||||
self.assertEqual(target.long_display(), u'Course mode: {}'.format(mode_display_name))
|
||||
assert target.target_type == SEND_TO_TRACK
|
||||
assert target.short_display() == 'track-{}'.format(free_mode)
|
||||
assert target.long_display() == u'Course mode: {}'.format(mode_display_name)
|
||||
|
||||
def test_cohort_target(self):
|
||||
course_id = CourseKey.from_string('abc/123/doremi')
|
||||
@@ -141,11 +142,11 @@ class CourseEmailTest(ModuleStoreTestCase):
|
||||
html_message = "<html>dummy message</html>"
|
||||
CourseCohort.create(cohort_name='test cohort', course_id=course_id)
|
||||
email = CourseEmail.create(course_id, sender, [to_option], subject, html_message)
|
||||
self.assertEqual(len(email.targets.all()), 1)
|
||||
assert len(email.targets.all()) == 1
|
||||
target = email.targets.all()[0]
|
||||
self.assertEqual(target.target_type, SEND_TO_COHORT)
|
||||
self.assertEqual(target.short_display(), 'cohort-test cohort')
|
||||
self.assertEqual(target.long_display(), 'Cohort: test cohort')
|
||||
assert target.target_type == SEND_TO_COHORT
|
||||
assert target.short_display() == 'cohort-test cohort'
|
||||
assert target.long_display() == 'Cohort: test cohort'
|
||||
|
||||
|
||||
class OptoutTest(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -153,21 +154,21 @@ class OptoutTest(TestCase): # lint-amnesty, pylint: disable=missing-class-docst
|
||||
user = UserFactory.create()
|
||||
course_id = CourseKey.from_string('abc/123/doremi')
|
||||
|
||||
self.assertFalse(Optout.is_user_opted_out_for_course(user, course_id))
|
||||
assert not Optout.is_user_opted_out_for_course(user, course_id)
|
||||
|
||||
Optout.objects.create(
|
||||
user=user,
|
||||
course_id=course_id,
|
||||
)
|
||||
|
||||
self.assertTrue(Optout.is_user_opted_out_for_course(user, course_id))
|
||||
assert Optout.is_user_opted_out_for_course(user, course_id)
|
||||
|
||||
|
||||
class NoCourseEmailTemplateTest(TestCase):
|
||||
"""Test the CourseEmailTemplate model without loading the template data."""
|
||||
|
||||
def test_get_missing_template(self):
|
||||
with self.assertRaises(CourseEmailTemplate.DoesNotExist):
|
||||
with pytest.raises(CourseEmailTemplate.DoesNotExist):
|
||||
CourseEmailTemplate.get_template()
|
||||
|
||||
|
||||
@@ -210,16 +211,16 @@ class CourseEmailTemplateTest(TestCase):
|
||||
def test_get_template(self):
|
||||
# Get the default template, which has name=None
|
||||
template = CourseEmailTemplate.get_template()
|
||||
self.assertIsNotNone(template.html_template)
|
||||
self.assertIsNotNone(template.plain_template)
|
||||
assert template.html_template is not None
|
||||
assert template.plain_template is not None
|
||||
|
||||
def test_get_branded_template(self):
|
||||
# Get a branded (non default) template and make sure we get what we expect
|
||||
template = CourseEmailTemplate.get_template(name="branded.template")
|
||||
self.assertIsNotNone(template.html_template)
|
||||
self.assertIsNotNone(template.plain_template)
|
||||
self.assertIn(u"THIS IS A BRANDED HTML TEMPLATE", template.html_template)
|
||||
self.assertIn(u"THIS IS A BRANDED TEXT TEMPLATE", template.plain_template)
|
||||
assert template.html_template is not None
|
||||
assert template.plain_template is not None
|
||||
assert u'THIS IS A BRANDED HTML TEMPLATE' in template.html_template
|
||||
assert u'THIS IS A BRANDED TEXT TEMPLATE' in template.plain_template
|
||||
|
||||
def test_render_html_without_context(self):
|
||||
template = CourseEmailTemplate.get_template()
|
||||
@@ -227,7 +228,7 @@ class CourseEmailTemplateTest(TestCase):
|
||||
for keyname in base_context:
|
||||
context = dict(base_context)
|
||||
del context[keyname]
|
||||
with self.assertRaises(KeyError):
|
||||
with pytest.raises(KeyError):
|
||||
template.render_htmltext("My new html text.", context)
|
||||
|
||||
def test_render_plaintext_without_context(self):
|
||||
@@ -236,7 +237,7 @@ class CourseEmailTemplateTest(TestCase):
|
||||
for keyname in base_context:
|
||||
context = dict(base_context)
|
||||
del context[keyname]
|
||||
with self.assertRaises(KeyError):
|
||||
with pytest.raises(KeyError):
|
||||
template.render_plaintext("My new plain text.", context)
|
||||
|
||||
def test_render_html(self):
|
||||
@@ -250,9 +251,9 @@ class CourseEmailTemplateTest(TestCase):
|
||||
message = template.render_htmltext(
|
||||
u"Dear %%USER_FULLNAME%%, thanks for enrolling in %%COURSE_DISPLAY_NAME%%.", context
|
||||
)
|
||||
self.assertNotIn("<script>", message)
|
||||
self.assertIn("<script>alert('Course Title!');</alert>", message)
|
||||
self.assertIn("<script>alert('Profile Name!');</alert>", message)
|
||||
assert '<script>' not in message
|
||||
assert '<script>alert('Course Title!');</alert>' in message
|
||||
assert '<script>alert('Profile Name!');</alert>' in message
|
||||
|
||||
def test_render_plain(self):
|
||||
template = CourseEmailTemplate.get_template()
|
||||
@@ -265,9 +266,9 @@ class CourseEmailTemplateTest(TestCase):
|
||||
message = template.render_plaintext(
|
||||
u"Dear %%USER_FULLNAME%%, thanks for enrolling in %%COURSE_DISPLAY_NAME%%.", context
|
||||
)
|
||||
self.assertNotIn("<script>", message)
|
||||
self.assertIn(context['course_title'], message)
|
||||
self.assertIn(context['name'], message)
|
||||
assert '<script>' not in message
|
||||
assert context['course_title'] in message
|
||||
assert context['name'] in message
|
||||
|
||||
|
||||
class CourseAuthorizationTest(TestCase):
|
||||
@@ -281,37 +282,31 @@ class CourseAuthorizationTest(TestCase):
|
||||
BulkEmailFlag.objects.create(enabled=True, require_course_email_auth=True)
|
||||
course_id = CourseKey.from_string('abc/123/doremi')
|
||||
# Test that course is not authorized by default
|
||||
self.assertFalse(is_bulk_email_feature_enabled(course_id))
|
||||
assert not is_bulk_email_feature_enabled(course_id)
|
||||
|
||||
# Authorize
|
||||
cauth = CourseAuthorization(course_id=course_id, email_enabled=True)
|
||||
cauth.save()
|
||||
# Now, course should be authorized
|
||||
self.assertTrue(is_bulk_email_feature_enabled(course_id))
|
||||
self.assertEqual(
|
||||
str(cauth),
|
||||
"Course 'abc/123/doremi': Instructor Email Enabled"
|
||||
)
|
||||
assert is_bulk_email_feature_enabled(course_id)
|
||||
assert str(cauth) == "Course 'abc/123/doremi': Instructor Email Enabled"
|
||||
|
||||
# Unauthorize by explicitly setting email_enabled to False
|
||||
cauth.email_enabled = False
|
||||
cauth.save()
|
||||
# Test that course is now unauthorized
|
||||
self.assertFalse(is_bulk_email_feature_enabled(course_id))
|
||||
self.assertEqual(
|
||||
str(cauth),
|
||||
"Course 'abc/123/doremi': Instructor Email Not Enabled"
|
||||
)
|
||||
assert not is_bulk_email_feature_enabled(course_id)
|
||||
assert str(cauth) == "Course 'abc/123/doremi': Instructor Email Not Enabled"
|
||||
|
||||
def test_creation_auth_off(self):
|
||||
BulkEmailFlag.objects.create(enabled=True, require_course_email_auth=False)
|
||||
course_id = CourseKey.from_string('blahx/blah101/ehhhhhhh')
|
||||
# Test that course is authorized by default, since auth is turned off
|
||||
self.assertTrue(is_bulk_email_feature_enabled(course_id))
|
||||
assert is_bulk_email_feature_enabled(course_id)
|
||||
|
||||
# Use the admin interface to unauthorize the course
|
||||
cauth = CourseAuthorization(course_id=course_id, email_enabled=False)
|
||||
cauth.save()
|
||||
|
||||
# Now, course should STILL be authorized!
|
||||
self.assertTrue(is_bulk_email_feature_enabled(course_id))
|
||||
assert is_bulk_email_feature_enabled(course_id)
|
||||
|
||||
@@ -48,7 +48,7 @@ class TestOptoutCourseEmailsBySignal(ModuleStoreTestCase):
|
||||
Make sure the correct row is created for a user enrolled in a course
|
||||
"""
|
||||
force_optout_all(sender=self.__class__, user=self.student)
|
||||
self.assertEqual(Optout.objects.filter(user=self.student, course_id=self.course.id).count(), 1)
|
||||
assert Optout.objects.filter(user=self.student, course_id=self.course.id).count() == 1
|
||||
|
||||
def send_test_email(self):
|
||||
"""
|
||||
@@ -69,7 +69,7 @@ class TestOptoutCourseEmailsBySignal(ModuleStoreTestCase):
|
||||
'message': 'test message for all'
|
||||
}
|
||||
response = self.client.post(self.send_mail_url, test_email)
|
||||
self.assertEqual(json.loads(response.content.decode('utf-8')), self.success_content)
|
||||
assert json.loads(response.content.decode('utf-8')) == self.success_content
|
||||
|
||||
def test_optout_course(self):
|
||||
"""
|
||||
@@ -83,6 +83,6 @@ class TestOptoutCourseEmailsBySignal(ModuleStoreTestCase):
|
||||
self.send_test_email()
|
||||
|
||||
# Assert that self.student.email not in mail.to, outbox should only contain "myself" target
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(len(mail.outbox[0].to), 1)
|
||||
self.assertEqual(mail.outbox[0].to[0], self.instructor.email)
|
||||
assert len(mail.outbox) == 1
|
||||
assert len(mail.outbox[0].to) == 1
|
||||
assert mail.outbox[0].to[0] == self.instructor.email
|
||||
|
||||
@@ -12,7 +12,7 @@ import json
|
||||
from itertools import chain, cycle, repeat
|
||||
from smtplib import SMTPAuthenticationError, SMTPConnectError, SMTPDataError, SMTPServerDisconnected
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from boto.exception import AWSConnectionError
|
||||
from boto.ses.exceptions import (
|
||||
SESAddressBlacklistedError,
|
||||
@@ -116,13 +116,13 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
|
||||
def test_email_missing_current_task(self):
|
||||
task_entry = self._create_input_entry()
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
send_bulk_course_email(task_entry.id, {})
|
||||
|
||||
def test_email_undefined_course(self):
|
||||
# Check that we fail when passing in a course that doesn't exist.
|
||||
task_entry = self._create_input_entry(course_id=CourseLocator("bogus", "course", "id"))
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
self._run_task_with_mock_celery(send_bulk_course_email, task_entry.id, task_entry.task_id)
|
||||
|
||||
def test_bad_task_id_on_update(self):
|
||||
@@ -133,7 +133,7 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
bogus_task_id = "this-is-bogus"
|
||||
update_subtask_status(entry_id, bogus_task_id, new_subtask_status)
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
with patch('lms.djangoapps.bulk_email.tasks.update_subtask_status', dummy_update_subtask_status):
|
||||
send_bulk_course_email(task_entry.id, {})
|
||||
|
||||
@@ -145,24 +145,24 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
"""Compare counts with 'subtasks' entry in InstructorTask table."""
|
||||
subtask_info = json.loads(entry.subtasks)
|
||||
# verify subtask-level counts:
|
||||
self.assertEqual(subtask_info.get('total'), 1)
|
||||
self.assertEqual(subtask_info.get('succeeded'), 1 if succeeded > 0 else 0)
|
||||
self.assertEqual(subtask_info.get('failed'), 0 if succeeded > 0 else 1)
|
||||
assert subtask_info.get('total') == 1
|
||||
assert subtask_info.get('succeeded') == (1 if (succeeded > 0) else 0)
|
||||
assert subtask_info.get('failed') == (0 if (succeeded > 0) else 1)
|
||||
# verify individual subtask status:
|
||||
subtask_status_info = subtask_info.get('status')
|
||||
task_id_list = list(subtask_status_info.keys())
|
||||
self.assertEqual(len(task_id_list), 1)
|
||||
assert len(task_id_list) == 1
|
||||
task_id = task_id_list[0]
|
||||
subtask_status = subtask_status_info.get(task_id)
|
||||
print(u"Testing subtask status: {}".format(subtask_status))
|
||||
self.assertEqual(subtask_status.get('task_id'), task_id)
|
||||
self.assertEqual(subtask_status.get('attempted'), succeeded + failed)
|
||||
self.assertEqual(subtask_status.get('succeeded'), succeeded)
|
||||
self.assertEqual(subtask_status.get('skipped'), skipped)
|
||||
self.assertEqual(subtask_status.get('failed'), failed)
|
||||
self.assertEqual(subtask_status.get('retried_nomax'), retried_nomax)
|
||||
self.assertEqual(subtask_status.get('retried_withmax'), retried_withmax)
|
||||
self.assertEqual(subtask_status.get('state'), SUCCESS if succeeded > 0 else FAILURE)
|
||||
assert subtask_status.get('task_id') == task_id
|
||||
assert subtask_status.get('attempted') == (succeeded + failed)
|
||||
assert subtask_status.get('succeeded') == succeeded
|
||||
assert subtask_status.get('skipped') == skipped
|
||||
assert subtask_status.get('failed') == failed
|
||||
assert subtask_status.get('retried_nomax') == retried_nomax
|
||||
assert subtask_status.get('retried_withmax') == retried_withmax
|
||||
assert subtask_status.get('state') == (SUCCESS if (succeeded > 0) else FAILURE)
|
||||
|
||||
def _test_run_with_task(
|
||||
self, task_class, action_name, total, succeeded,
|
||||
@@ -172,20 +172,20 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
parent_status = self._run_task_with_mock_celery(task_class, task_entry.id, task_entry.task_id)
|
||||
|
||||
# check return value
|
||||
self.assertEqual(parent_status.get('total'), total)
|
||||
self.assertEqual(parent_status.get('action_name'), action_name)
|
||||
assert parent_status.get('total') == total
|
||||
assert parent_status.get('action_name') == action_name
|
||||
|
||||
# compare with task_output entry in InstructorTask table:
|
||||
entry = InstructorTask.objects.get(id=task_entry.id)
|
||||
status = json.loads(entry.task_output)
|
||||
self.assertEqual(status.get('attempted'), succeeded + failed)
|
||||
self.assertEqual(status.get('succeeded'), succeeded)
|
||||
self.assertEqual(status.get('skipped'), skipped)
|
||||
self.assertEqual(status.get('failed'), failed)
|
||||
self.assertEqual(status.get('total'), total)
|
||||
self.assertEqual(status.get('action_name'), action_name)
|
||||
self.assertGreater(status.get('duration_ms'), 0)
|
||||
self.assertEqual(entry.task_state, SUCCESS)
|
||||
assert status.get('attempted') == (succeeded + failed)
|
||||
assert status.get('succeeded') == succeeded
|
||||
assert status.get('skipped') == skipped
|
||||
assert status.get('failed') == failed
|
||||
assert status.get('total') == total
|
||||
assert status.get('action_name') == action_name
|
||||
assert status.get('duration_ms') > 0
|
||||
assert entry.task_state == SUCCESS
|
||||
self._assert_single_subtask_status(entry, succeeded, failed, skipped, retried_nomax, retried_withmax)
|
||||
return entry
|
||||
|
||||
@@ -211,9 +211,9 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
with patch('lms.djangoapps.bulk_email.tasks.get_connection', autospec=True) as get_conn:
|
||||
get_conn.return_value.send_messages.side_effect = cycle([Exception("This should not happen!")])
|
||||
parent_status = self._run_task_with_mock_celery(send_bulk_course_email, task_entry.id, task_entry.task_id)
|
||||
self.assertEqual(parent_status.get('total'), num_emails)
|
||||
self.assertEqual(parent_status.get('succeeded'), num_emails)
|
||||
self.assertEqual(parent_status.get('failed'), 0)
|
||||
assert parent_status.get('total') == num_emails
|
||||
assert parent_status.get('succeeded') == num_emails
|
||||
assert parent_status.get('failed') == 0
|
||||
|
||||
def test_unactivated_user(self):
|
||||
# Select number of emails to fit into a single subtask.
|
||||
@@ -464,12 +464,12 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
|
||||
def test_get_course_email_context_has_correct_keys(self):
|
||||
result = _get_course_email_context(self.course)
|
||||
self.assertIn('course_title', result)
|
||||
self.assertIn('course_root', result)
|
||||
self.assertIn('course_language', result)
|
||||
self.assertIn('course_url', result)
|
||||
self.assertIn('course_image_url', result)
|
||||
self.assertIn('course_end_date', result)
|
||||
self.assertIn('account_settings_url', result)
|
||||
self.assertIn('email_settings_url', result)
|
||||
self.assertIn('platform_name', result)
|
||||
assert 'course_title' in result
|
||||
assert 'course_root' in result
|
||||
assert 'course_language' in result
|
||||
assert 'course_url' in result
|
||||
assert 'course_image_url' in result
|
||||
assert 'course_end_date' in result
|
||||
assert 'account_settings_url' in result
|
||||
assert 'email_settings_url' in result
|
||||
assert 'platform_name' in result
|
||||
|
||||
@@ -4,6 +4,7 @@ Test the bulk email opt out view.
|
||||
"""
|
||||
|
||||
import ddt
|
||||
import pytest
|
||||
from django.http import Http404
|
||||
from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
@@ -36,7 +37,7 @@ class OptOutEmailUpdatesViewTest(ModuleStoreTestCase):
|
||||
self.url = reverse('bulk_email_opt_out', args=[self.token, text_type(self.course.id)])
|
||||
|
||||
# Ensure we start with no opt-out records
|
||||
self.assertEqual(Optout.objects.count(), 0)
|
||||
assert Optout.objects.count() == 0
|
||||
|
||||
def test_opt_out_email_confirm(self):
|
||||
"""
|
||||
@@ -44,7 +45,7 @@ class OptOutEmailUpdatesViewTest(ModuleStoreTestCase):
|
||||
"""
|
||||
response = self.client.get(self.url)
|
||||
self.assertContains(response, "confirm unsubscribe from")
|
||||
self.assertEqual(Optout.objects.count(), 0)
|
||||
assert Optout.objects.count() == 0
|
||||
|
||||
def test_opt_out_email_unsubscribe(self):
|
||||
"""
|
||||
@@ -52,7 +53,7 @@ class OptOutEmailUpdatesViewTest(ModuleStoreTestCase):
|
||||
"""
|
||||
response = self.client.post(self.url, {'unsubscribe': True})
|
||||
self.assertContains(response, "You have successfully unsubscribed from")
|
||||
self.assertEqual(Optout.objects.count(), 1)
|
||||
assert Optout.objects.count() == 1
|
||||
|
||||
def test_opt_out_email_cancel(self):
|
||||
"""
|
||||
@@ -60,7 +61,7 @@ class OptOutEmailUpdatesViewTest(ModuleStoreTestCase):
|
||||
"""
|
||||
response = self.client.post(self.url)
|
||||
self.assertContains(response, "You have not been unsubscribed from")
|
||||
self.assertEqual(Optout.objects.count(), 0)
|
||||
assert Optout.objects.count() == 0
|
||||
|
||||
@ddt.data(
|
||||
("ZOMG INVALID BASE64 CHARS!!!", "base64url", False),
|
||||
@@ -78,6 +79,6 @@ class OptOutEmailUpdatesViewTest(ModuleStoreTestCase):
|
||||
Make sure that view returns 404 in case token is not valid
|
||||
"""
|
||||
request = self.request_factory.get("dummy")
|
||||
with self.assertRaises(Http404) as err:
|
||||
with pytest.raises(Http404) as err:
|
||||
opt_out_email_updates(request, token, course)
|
||||
self.assertIn(message, err)
|
||||
assert message in err
|
||||
|
||||
@@ -97,19 +97,19 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'email_students': False,
|
||||
'courses': key,
|
||||
})
|
||||
self.assertTrue(serializer.is_valid())
|
||||
assert serializer.is_valid()
|
||||
|
||||
def test_non_staff(self):
|
||||
""" Test that non global staff users are forbidden from API use. """
|
||||
self.staff.is_staff = False
|
||||
self.staff.save()
|
||||
response = self.request_bulk_enroll()
|
||||
self.assertEqual(response.status_code, 403)
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_missing_params(self):
|
||||
""" Test the response when missing all query parameters. """
|
||||
response = self.request_bulk_enroll()
|
||||
self.assertEqual(response.status_code, 400)
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_bad_action(self):
|
||||
""" Test the response given an invalid action """
|
||||
@@ -118,7 +118,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'action': 'invalid-action',
|
||||
'courses': self.course_key,
|
||||
})
|
||||
self.assertEqual(response.status_code, 400)
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_invalid_email(self):
|
||||
""" Test the response given an invalid email. """
|
||||
@@ -128,7 +128,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'email_students': False,
|
||||
'courses': self.course_key,
|
||||
})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -150,7 +150,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
def test_invalid_username(self):
|
||||
""" Test the response given an invalid username. """
|
||||
@@ -160,7 +160,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'email_students': False,
|
||||
'courses': self.course_key,
|
||||
})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -182,7 +182,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
def test_enroll_with_username(self):
|
||||
""" Test enrolling using a username as the identifier. """
|
||||
@@ -192,7 +192,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'email_students': False,
|
||||
'courses': self.course_key,
|
||||
})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -224,10 +224,10 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
}
|
||||
manual_enrollments = ManualEnrollmentAudit.objects.all()
|
||||
self.assertEqual(manual_enrollments.count(), 1)
|
||||
self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED)
|
||||
assert manual_enrollments.count() == 1
|
||||
assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
@ddt.data(False, True)
|
||||
def test_enroll_with_email(self, use_json):
|
||||
@@ -238,11 +238,11 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'email_students': False,
|
||||
'courses': self.course_key,
|
||||
}, use_json=use_json)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test that the user is now enrolled
|
||||
user = User.objects.get(email=self.notenrolled_student.email)
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(user, self.course.id))
|
||||
assert CourseEnrollment.is_enrolled(user, self.course.id)
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -275,13 +275,13 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
|
||||
manual_enrollments = ManualEnrollmentAudit.objects.all()
|
||||
self.assertEqual(manual_enrollments.count(), 1)
|
||||
self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED)
|
||||
assert manual_enrollments.count() == 1
|
||||
assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
# Check the outbox
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
assert len(mail.outbox) == 0
|
||||
|
||||
@ddt.data(False, True)
|
||||
def test_unenroll(self, use_json):
|
||||
@@ -292,11 +292,11 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'email_students': False,
|
||||
'courses': self.course_key,
|
||||
}, use_json=use_json)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test that the user is now unenrolled
|
||||
user = User.objects.get(email=self.enrolled_student.email)
|
||||
self.assertFalse(CourseEnrollment.is_enrolled(user, self.course.id))
|
||||
assert not CourseEnrollment.is_enrolled(user, self.course.id)
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -330,13 +330,13 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
|
||||
manual_enrollments = ManualEnrollmentAudit.objects.all()
|
||||
self.assertEqual(manual_enrollments.count(), 1)
|
||||
self.assertEqual(manual_enrollments[0].state_transition, ENROLLED_TO_UNENROLLED)
|
||||
assert manual_enrollments.count() == 1
|
||||
assert manual_enrollments[0].state_transition == ENROLLED_TO_UNENROLLED
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
# Check the outbox
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
assert len(mail.outbox) == 0
|
||||
|
||||
def test_fail_on_unequal_cohorts(self):
|
||||
"""
|
||||
@@ -398,7 +398,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'cohorts': "cohort1"
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -432,12 +432,12 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
}
|
||||
manual_enrollments = ManualEnrollmentAudit.objects.all()
|
||||
self.assertEqual(manual_enrollments.count(), 1)
|
||||
self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED)
|
||||
assert manual_enrollments.count() == 1
|
||||
assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertIsNotNone(get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)))
|
||||
assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
|
||||
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
def test_readd_to_different_cohort(self):
|
||||
config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
|
||||
@@ -449,7 +449,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'cohorts': "cohort1"
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -483,11 +483,11 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
}
|
||||
manual_enrollments = ManualEnrollmentAudit.objects.all()
|
||||
self.assertEqual(manual_enrollments.count(), 1)
|
||||
self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED)
|
||||
assert manual_enrollments.count() == 1
|
||||
assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertIsNotNone(get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)))
|
||||
self.assertEqual(res_json, expected)
|
||||
assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
|
||||
assert res_json == expected
|
||||
|
||||
response2 = self.request_bulk_enroll({
|
||||
'identifiers': self.notenrolled_student.username,
|
||||
@@ -497,7 +497,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'cohorts': "cohort2"
|
||||
})
|
||||
|
||||
self.assertEqual(response2.status_code, 200)
|
||||
assert response2.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected2 = {
|
||||
@@ -531,8 +531,8 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
}
|
||||
res2_json = json.loads(response2.content.decode('utf-8'))
|
||||
self.assertIsNotNone(get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)))
|
||||
self.assertEqual(res2_json, expected2)
|
||||
assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
|
||||
assert res2_json == expected2
|
||||
|
||||
def test_readd_to_same_cohort(self):
|
||||
config_course_cohorts(self.course, is_cohorted=True, manual_cohorts=["cohort1", "cohort2"])
|
||||
@@ -544,7 +544,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'cohorts': "cohort1"
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected = {
|
||||
@@ -578,12 +578,12 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
}
|
||||
manual_enrollments = ManualEnrollmentAudit.objects.all()
|
||||
self.assertEqual(manual_enrollments.count(), 1)
|
||||
self.assertEqual(manual_enrollments[0].state_transition, UNENROLLED_TO_ENROLLED)
|
||||
assert manual_enrollments.count() == 1
|
||||
assert manual_enrollments[0].state_transition == UNENROLLED_TO_ENROLLED
|
||||
res_json = json.loads(response.content.decode('utf-8'))
|
||||
self.assertIsNotNone(get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)))
|
||||
assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
|
||||
|
||||
self.assertEqual(res_json, expected)
|
||||
assert res_json == expected
|
||||
|
||||
response2 = self.request_bulk_enroll({
|
||||
'identifiers': self.notenrolled_student.username,
|
||||
@@ -593,7 +593,7 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
'cohorts': "cohort1"
|
||||
})
|
||||
|
||||
self.assertEqual(response2.status_code, 200)
|
||||
assert response2.status_code == 200
|
||||
|
||||
# test the response data
|
||||
expected2 = {
|
||||
@@ -627,5 +627,5 @@ class BulkEnrollmentTest(ModuleStoreTestCase, LoginEnrollmentTestCase, APITestCa
|
||||
}
|
||||
}
|
||||
res2_json = json.loads(response2.content.decode('utf-8'))
|
||||
self.assertIsNotNone(get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)))
|
||||
self.assertEqual(res2_json, expected2)
|
||||
assert get_cohort_id(self.notenrolled_student, CourseKey.from_string(self.course_key)) is not None
|
||||
assert res2_json == expected2
|
||||
|
||||
@@ -7,7 +7,7 @@ import json
|
||||
import math
|
||||
import string
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import mock
|
||||
import six
|
||||
@@ -105,22 +105,22 @@ class CcxRestApiTest(CcxTestCase, APITestCase):
|
||||
Helper function that checks that the response object
|
||||
has a body with the provided error
|
||||
"""
|
||||
self.assertEqual(resp_obj.status_code, http_code)
|
||||
self.assertIn('error_code', resp_obj.data)
|
||||
self.assertEqual(resp_obj.data['error_code'], error_code_str)
|
||||
assert resp_obj.status_code == http_code
|
||||
assert 'error_code' in resp_obj.data
|
||||
assert resp_obj.data['error_code'] == error_code_str
|
||||
|
||||
def expect_error_fields(self, expected_field_errors, resp_obj):
|
||||
"""
|
||||
Helper function that checks that the response object
|
||||
has a body with the provided field errors
|
||||
"""
|
||||
self.assertEqual(resp_obj.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertIn('field_errors', resp_obj.data)
|
||||
assert resp_obj.status_code == status.HTTP_400_BAD_REQUEST
|
||||
assert 'field_errors' in resp_obj.data
|
||||
# restructure the error dictionary for a easier comparison
|
||||
resp_dict_error = {}
|
||||
for field_name, error_dict in six.iteritems(resp_obj.data['field_errors']):
|
||||
resp_dict_error[field_name] = error_dict.get('error_code', '')
|
||||
self.assertEqual(expected_field_errors, resp_dict_error)
|
||||
assert expected_field_errors == resp_dict_error
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -159,10 +159,10 @@ class CcxListTest(CcxRestApiTest):
|
||||
# all the auths in the list fail to authorize
|
||||
for auth in auth_list:
|
||||
resp = self.client.get(self.list_url_master_course, {}, HTTP_AUTHORIZATION=auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
assert resp.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
resp = self.client.get(self.list_url_master_course, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
|
||||
def test_authorization_no_oauth_staff(self):
|
||||
"""
|
||||
@@ -186,9 +186,9 @@ class CcxListTest(CcxRestApiTest):
|
||||
# the staff user can perform the request
|
||||
self.client.login(username=staff_user.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.list_url_master_course)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
resp = self.client.post(self.list_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||
assert resp.status_code == status.HTTP_201_CREATED
|
||||
|
||||
def test_authorization_no_oauth_instructor(self):
|
||||
"""
|
||||
@@ -211,9 +211,9 @@ class CcxListTest(CcxRestApiTest):
|
||||
# the instructor user can perform the request
|
||||
self.client.login(username=instructor_user.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.list_url_master_course)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
resp = self.client.post(self.list_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||
assert resp.status_code == status.HTTP_201_CREATED
|
||||
|
||||
def test_authorization_no_oauth(self):
|
||||
"""
|
||||
@@ -235,9 +235,9 @@ class CcxListTest(CcxRestApiTest):
|
||||
# the coach user cannot perform the request: this type of user can only get her own CCX
|
||||
self.client.login(username=coach_user.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.list_url_master_course)
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
resp = self.client.post(self.list_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
def test_get_list_wrong_master_course(self):
|
||||
"""
|
||||
@@ -272,19 +272,19 @@ class CcxListTest(CcxRestApiTest):
|
||||
"""
|
||||
# there are no CCX courses
|
||||
resp = self.client.get(self.list_url_master_course, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertIn('count', resp.data)
|
||||
self.assertEqual(resp.data['count'], 0)
|
||||
assert 'count' in resp.data
|
||||
assert resp.data['count'] == 0
|
||||
|
||||
# create few ccx courses
|
||||
num_ccx = 10
|
||||
for _ in range(num_ccx):
|
||||
self.make_ccx()
|
||||
resp = self.client.get(self.list_url_master_course, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('count', resp.data)
|
||||
self.assertEqual(resp.data['count'], num_ccx)
|
||||
self.assertIn('results', resp.data)
|
||||
self.assertEqual(len(resp.data['results']), num_ccx)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
assert 'count' in resp.data
|
||||
assert resp.data['count'] == num_ccx
|
||||
assert 'results' in resp.data
|
||||
assert len(resp.data['results']) == num_ccx
|
||||
|
||||
def test_get_sorted_list(self):
|
||||
"""
|
||||
@@ -297,7 +297,7 @@ class CcxListTest(CcxRestApiTest):
|
||||
# update the display_name fields
|
||||
all_ccx = CustomCourseForEdX.objects.all()
|
||||
all_ccx = all_ccx.order_by('id')
|
||||
self.assertEqual(len(all_ccx), num_ccx)
|
||||
assert len(all_ccx) == num_ccx
|
||||
title_str = u'Title CCX {0}'
|
||||
for num, ccx in enumerate(all_ccx):
|
||||
ccx.display_name = title_str.format(string.ascii_lowercase[-(num + 1)])
|
||||
@@ -306,11 +306,11 @@ class CcxListTest(CcxRestApiTest):
|
||||
# sort by display name
|
||||
url = '{0}&order_by=display_name'.format(self.list_url_master_course)
|
||||
resp = self.client.get(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(resp.data['results']), num_ccx)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
assert len(resp.data['results']) == num_ccx
|
||||
# the display_name should be sorted as "Title CCX x", "Title CCX y", "Title CCX z"
|
||||
for num, ccx in enumerate(resp.data['results']):
|
||||
self.assertEqual(title_str.format(string.ascii_lowercase[-(num_ccx - num)]), ccx['display_name'])
|
||||
assert title_str.format(string.ascii_lowercase[(- (num_ccx - num))]) == ccx['display_name']
|
||||
|
||||
# add sort order desc
|
||||
url = '{0}&order_by=display_name&sort_order=desc'.format(self.list_url_master_course)
|
||||
@@ -318,7 +318,7 @@ class CcxListTest(CcxRestApiTest):
|
||||
# the only thing I can check is that the display name is in alphabetically reversed order
|
||||
# in the same way when the field has been updated above, so with the id asc
|
||||
for num, ccx in enumerate(resp.data['results']):
|
||||
self.assertEqual(title_str.format(string.ascii_lowercase[-(num + 1)]), ccx['display_name'])
|
||||
assert title_str.format(string.ascii_lowercase[(- (num + 1))]) == ccx['display_name']
|
||||
|
||||
def test_get_paginated_list(self):
|
||||
"""
|
||||
@@ -332,40 +332,40 @@ class CcxListTest(CcxRestApiTest):
|
||||
num_pages = int(math.ceil(num_ccx / float(page_size)))
|
||||
# get first page
|
||||
resp = self.client.get(self.list_url_master_course, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(resp.data['count'], num_ccx)
|
||||
self.assertEqual(resp.data['num_pages'], num_pages)
|
||||
self.assertEqual(resp.data['current_page'], 1)
|
||||
self.assertEqual(resp.data['start'], 0)
|
||||
self.assertIsNotNone(resp.data['next'])
|
||||
self.assertIsNone(resp.data['previous'])
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
assert resp.data['count'] == num_ccx
|
||||
assert resp.data['num_pages'] == num_pages
|
||||
assert resp.data['current_page'] == 1
|
||||
assert resp.data['start'] == 0
|
||||
assert resp.data['next'] is not None
|
||||
assert resp.data['previous'] is None
|
||||
|
||||
# get a page in the middle
|
||||
url = '{0}&page=24'.format(self.list_url_master_course)
|
||||
resp = self.client.get(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(resp.data['count'], num_ccx)
|
||||
self.assertEqual(resp.data['num_pages'], num_pages)
|
||||
self.assertEqual(resp.data['current_page'], 24)
|
||||
self.assertEqual(resp.data['start'], (resp.data['current_page'] - 1) * page_size)
|
||||
self.assertIsNotNone(resp.data['next'])
|
||||
self.assertIsNotNone(resp.data['previous'])
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
assert resp.data['count'] == num_ccx
|
||||
assert resp.data['num_pages'] == num_pages
|
||||
assert resp.data['current_page'] == 24
|
||||
assert resp.data['start'] == ((resp.data['current_page'] - 1) * page_size)
|
||||
assert resp.data['next'] is not None
|
||||
assert resp.data['previous'] is not None
|
||||
|
||||
# get last page
|
||||
url = '{0}&page={1}'.format(self.list_url_master_course, num_pages)
|
||||
resp = self.client.get(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(resp.data['count'], num_ccx)
|
||||
self.assertEqual(resp.data['num_pages'], num_pages)
|
||||
self.assertEqual(resp.data['current_page'], num_pages)
|
||||
self.assertEqual(resp.data['start'], (resp.data['current_page'] - 1) * page_size)
|
||||
self.assertIsNone(resp.data['next'])
|
||||
self.assertIsNotNone(resp.data['previous'])
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
assert resp.data['count'] == num_ccx
|
||||
assert resp.data['num_pages'] == num_pages
|
||||
assert resp.data['current_page'] == num_pages
|
||||
assert resp.data['start'] == ((resp.data['current_page'] - 1) * page_size)
|
||||
assert resp.data['next'] is None
|
||||
assert resp.data['previous'] is not None
|
||||
|
||||
# last page + 1
|
||||
url = '{0}&page={1}'.format(self.list_url_master_course, num_pages + 1)
|
||||
resp = self.client.get(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
|
||||
assert resp.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
@ddt.data(
|
||||
(
|
||||
@@ -581,29 +581,25 @@ class CcxListTest(CcxRestApiTest):
|
||||
'course_modules': self.master_course_chapters[0:1]
|
||||
}
|
||||
resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||
assert resp.status_code == status.HTTP_201_CREATED
|
||||
# check if the response has at least the same data of the request
|
||||
for key, val in six.iteritems(data):
|
||||
self.assertEqual(resp.data.get(key), val)
|
||||
self.assertIn('ccx_course_id', resp.data)
|
||||
assert resp.data.get(key) == val
|
||||
assert 'ccx_course_id' in resp.data
|
||||
# check that the new CCX actually exists
|
||||
course_key = CourseKey.from_string(resp.data.get('ccx_course_id'))
|
||||
ccx_course = CustomCourseForEdX.objects.get(pk=course_key.ccx)
|
||||
self.assertEqual(
|
||||
six.text_type(CCXLocator.from_course_locator(ccx_course.course.id, ccx_course.id)),
|
||||
resp.data.get('ccx_course_id')
|
||||
)
|
||||
assert six.text_type(CCXLocator.from_course_locator(ccx_course.course.id, ccx_course.id)) ==\
|
||||
resp.data.get('ccx_course_id')
|
||||
# check that the coach user has coach role on the master course
|
||||
coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key)
|
||||
self.assertTrue(coach_role_on_master_course.has_user(self.coach))
|
||||
assert coach_role_on_master_course.has_user(self.coach)
|
||||
# check that the coach has been enrolled in the ccx
|
||||
ccx_course_object = courses.get_course_by_id(course_key)
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=self.coach).exists()
|
||||
)
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=self.coach).exists()
|
||||
# check that an email has been sent to the coach
|
||||
self.assertEqual(len(outbox), 1)
|
||||
self.assertIn(self.coach.email, outbox[0].recipients())
|
||||
assert len(outbox) == 1
|
||||
assert self.coach.email in outbox[0].recipients()
|
||||
|
||||
@ddt.data(
|
||||
True,
|
||||
@@ -626,9 +622,9 @@ class CcxListTest(CcxRestApiTest):
|
||||
resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
|
||||
if not user_is_active:
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
else:
|
||||
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||
assert resp.status_code == status.HTTP_201_CREATED
|
||||
|
||||
def test_post_list_duplicated_modules(self):
|
||||
"""
|
||||
@@ -644,8 +640,8 @@ class CcxListTest(CcxRestApiTest):
|
||||
'course_modules': duplicated_chapters
|
||||
}
|
||||
resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(resp.data.get('course_modules'), chapters)
|
||||
assert resp.status_code == status.HTTP_201_CREATED
|
||||
assert resp.data.get('course_modules') == chapters
|
||||
|
||||
def test_post_list_staff_master_course_in_ccx(self):
|
||||
"""
|
||||
@@ -660,10 +656,10 @@ class CcxListTest(CcxRestApiTest):
|
||||
'coach_email': self.coach.email
|
||||
}
|
||||
resp = self.client.post(self.list_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
|
||||
assert resp.status_code == status.HTTP_201_CREATED
|
||||
# check that only one email has been sent and it is to to the coach
|
||||
self.assertEqual(len(outbox), 1)
|
||||
self.assertIn(self.coach.email, outbox[0].recipients())
|
||||
assert len(outbox) == 1
|
||||
assert self.coach.email in outbox[0].recipients()
|
||||
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
list_instructor_master_course = list_with_level(self.course, 'instructor')
|
||||
@@ -674,15 +670,15 @@ class CcxListTest(CcxRestApiTest):
|
||||
|
||||
# The "Coach" in the parent course becomes "Staff" on the CCX, so the CCX should have 1 "Staff"
|
||||
# user more than the parent course
|
||||
self.assertEqual(len(list_staff_master_course) + 1, len(list_staff_ccx_course))
|
||||
assert (len(list_staff_master_course) + 1) == len(list_staff_ccx_course)
|
||||
# Make sure all of the existing course staff are passed to the CCX
|
||||
for course_user in list_staff_master_course:
|
||||
self.assertIn(course_user, list_staff_ccx_course)
|
||||
assert course_user in list_staff_ccx_course
|
||||
# Make sure the "Coach" on the parent course is "Staff" on the CCX
|
||||
self.assertIn(self.coach, list_staff_ccx_course)
|
||||
self.assertEqual(len(list_instructor_master_course), len(list_instructor_ccx_course))
|
||||
assert self.coach in list_staff_ccx_course
|
||||
assert len(list_instructor_master_course) == len(list_instructor_ccx_course)
|
||||
for course_user, ccx_user in zip(sorted(list_instructor_master_course), sorted(list_instructor_ccx_course)):
|
||||
self.assertEqual(course_user, ccx_user)
|
||||
assert course_user == ccx_user
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -754,10 +750,10 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
# all the auths in the list fail to authorize
|
||||
for auth in auth_list:
|
||||
resp = self.client.get(self.detail_url, {}, HTTP_AUTHORIZATION=auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
assert resp.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
resp = self.client.get(self.detail_url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
|
||||
def test_authorization_no_oauth_staff(self):
|
||||
"""
|
||||
@@ -772,9 +768,9 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
# the staff user can perform the request
|
||||
self.client.login(username=staff_user.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.detail_url)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
resp = self.client.patch(self.detail_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
def test_authorization_no_oauth_instructor(self):
|
||||
"""
|
||||
@@ -789,9 +785,9 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
# the instructor user can perform the request
|
||||
self.client.login(username=instructor_user.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.detail_url)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
resp = self.client.patch(self.detail_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
|
||||
def test_authorization_no_oauth_other_coach(self):
|
||||
"""
|
||||
@@ -806,9 +802,9 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
# the coach user cannot perform the request: this type of user can only get her own CCX
|
||||
self.client.login(username=coach_user.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.detail_url)
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
resp = self.client.patch(self.detail_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
def test_authorization_no_oauth_ccx_coach(self):
|
||||
"""
|
||||
@@ -818,9 +814,9 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
# the coach owner of the CCX can perform the request only if it is a get
|
||||
self.client.login(username=self.coach.username, password=USER_PASSWORD)
|
||||
resp = self.client.get(self.detail_url)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
resp = self.client.patch(self.detail_url, data, format='json')
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
def test_resolve_get_detail(self):
|
||||
"""
|
||||
@@ -831,20 +827,20 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
base_url = '{0}/'.format(self.detail_url.rsplit('/', 1)[0])
|
||||
# this url should be the same of the ccx list view
|
||||
resolver = resolve(base_url)
|
||||
self.assertEqual(views.CCXListView.__name__, resolver.func.__name__)
|
||||
self.assertEqual(views.CCXListView.__module__, resolver.func.__module__)
|
||||
assert views.CCXListView.__name__ == resolver.func.__name__
|
||||
assert views.CCXListView.__module__ == resolver.func.__module__
|
||||
# invalid urls
|
||||
for invalid_ccx_id in ('foo', 'ccx-v1:org.0', 'ccx-v1:org.0+course_0'):
|
||||
with self.assertRaises(Resolver404):
|
||||
with pytest.raises(Resolver404):
|
||||
resolve('{0}{1}'.format(base_url, invalid_ccx_id))
|
||||
# the following course ID works even if it is not a CCX valid course id (the regex matches course ID strings)
|
||||
resolver = resolve('{0}{1}'.format(base_url, 'ccx-v1:org.0+course_0+Run_0'))
|
||||
self.assertEqual(views.CCXDetailView.__name__, resolver.func.__name__)
|
||||
self.assertEqual(views.CCXDetailView.__module__, resolver.func.__module__)
|
||||
assert views.CCXDetailView.__name__ == resolver.func.__name__
|
||||
assert views.CCXDetailView.__module__ == resolver.func.__module__
|
||||
# and of course a valid ccx course id
|
||||
resolver = resolve('{0}{1}'.format(base_url, self.ccx_key_str))
|
||||
self.assertEqual(views.CCXDetailView.__name__, resolver.func.__name__)
|
||||
self.assertEqual(views.CCXDetailView.__module__, resolver.func.__module__)
|
||||
assert views.CCXDetailView.__name__ == resolver.func.__name__
|
||||
assert views.CCXDetailView.__module__ == resolver.func.__module__
|
||||
|
||||
@ddt.data(
|
||||
'get',
|
||||
@@ -863,7 +859,7 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
|
||||
# the permission class will give a 403 error because will not find the CCX
|
||||
resp = client_request(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
# bypassing the permission class we get another kind of error
|
||||
with mock.patch(mock_class_str, autospec=True) as mocked_perm_class:
|
||||
@@ -875,7 +871,7 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
url = reverse('ccx_api:v0:ccx:detail', kwargs={'ccx_course_id': 'ccx-v1:foo.0+course_bar_0+Run_0+ccx@1'})
|
||||
# the permission class will give a 403 error because will not find the CCX
|
||||
resp = client_request(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
# bypassing the permission class we get another kind of error
|
||||
with mock.patch(mock_class_str, autospec=True) as mocked_perm_class:
|
||||
@@ -888,7 +884,7 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
url = reverse('ccx_api:v0:ccx:detail', kwargs={'ccx_course_id': ccx_key_str})
|
||||
# the permission class will give a 403 error because will not find the CCX
|
||||
resp = client_request(url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
# bypassing the permission class we get another kind of error
|
||||
with mock.patch(mock_class_str, autospec=True) as mocked_perm_class:
|
||||
@@ -901,15 +897,12 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
Test for getting detail of a ccx course
|
||||
"""
|
||||
resp = self.client.get(self.detail_url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(resp.data.get('ccx_course_id'), self.ccx_key_str)
|
||||
self.assertEqual(resp.data.get('display_name'), self.ccx.display_name)
|
||||
self.assertEqual(
|
||||
resp.data.get('max_students_allowed'),
|
||||
self.ccx.max_student_enrollments_allowed
|
||||
)
|
||||
self.assertEqual(resp.data.get('coach_email'), self.ccx.coach.email)
|
||||
self.assertEqual(resp.data.get('master_course_id'), six.text_type(self.ccx.course_id))
|
||||
assert resp.status_code == status.HTTP_200_OK
|
||||
assert resp.data.get('ccx_course_id') == self.ccx_key_str
|
||||
assert resp.data.get('display_name') == self.ccx.display_name
|
||||
assert resp.data.get('max_students_allowed') == self.ccx.max_student_enrollments_allowed
|
||||
assert resp.data.get('coach_email') == self.ccx.coach.email
|
||||
assert resp.data.get('master_course_id') == six.text_type(self.ccx.course_id)
|
||||
six.assertCountEqual(self, resp.data.get('course_modules'), self.master_course_chapters)
|
||||
|
||||
def test_delete_detail(self):
|
||||
@@ -917,17 +910,17 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
Test for deleting a ccx course
|
||||
"""
|
||||
# check that there are overrides
|
||||
self.assertGreater(CcxFieldOverride.objects.filter(ccx=self.ccx).count(), 0)
|
||||
self.assertGreater(CourseEnrollment.objects.filter(course_id=self.ccx_key).count(), 0)
|
||||
assert CcxFieldOverride.objects.filter(ccx=self.ccx).count() > 0
|
||||
assert CourseEnrollment.objects.filter(course_id=self.ccx_key).count() > 0
|
||||
resp = self.client.delete(self.detail_url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertIsNone(resp.data)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert resp.data is None
|
||||
# the CCX does not exist any more
|
||||
with self.assertRaises(CustomCourseForEdX.DoesNotExist):
|
||||
with pytest.raises(CustomCourseForEdX.DoesNotExist):
|
||||
CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
# check that there are no overrides
|
||||
self.assertEqual(CcxFieldOverride.objects.filter(ccx=self.ccx).count(), 0)
|
||||
self.assertEqual(CourseEnrollment.objects.filter(course_id=self.ccx_key).count(), 0)
|
||||
assert CcxFieldOverride.objects.filter(ccx=self.ccx).count() == 0
|
||||
assert CourseEnrollment.objects.filter(course_id=self.ccx_key).count() == 0
|
||||
|
||||
def test_patch_detail_change_master_course(self):
|
||||
"""
|
||||
@@ -994,12 +987,12 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
coach_email = self.ccx.coach.email
|
||||
ccx_structure = self.ccx.structure
|
||||
resp = self.client.patch(self.detail_url, {}, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
self.assertEqual(display_name, ccx.display_name)
|
||||
self.assertEqual(max_students_allowed, ccx.max_student_enrollments_allowed)
|
||||
self.assertEqual(coach_email, ccx.coach.email)
|
||||
self.assertEqual(ccx_structure, ccx.structure)
|
||||
assert display_name == ccx.display_name
|
||||
assert max_students_allowed == ccx.max_student_enrollments_allowed
|
||||
assert coach_email == ccx.coach.email
|
||||
assert ccx_structure == ccx.structure
|
||||
|
||||
def test_patch_detail_coach_does_not_exist(self):
|
||||
"""
|
||||
@@ -1052,22 +1045,20 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
'coach_email': new_coach.email
|
||||
}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
self.assertEqual(ccx_from_db.max_student_enrollments_allowed, data['max_students_allowed'])
|
||||
self.assertEqual(ccx_from_db.display_name, data['display_name'])
|
||||
self.assertEqual(ccx_from_db.coach.email, data['coach_email'])
|
||||
assert ccx_from_db.max_student_enrollments_allowed == data['max_students_allowed']
|
||||
assert ccx_from_db.display_name == data['display_name']
|
||||
assert ccx_from_db.coach.email == data['coach_email']
|
||||
# check that the coach user has coach role on the master course
|
||||
coach_role_on_master_course = CourseCcxCoachRole(self.master_course_key)
|
||||
self.assertTrue(coach_role_on_master_course.has_user(new_coach))
|
||||
assert coach_role_on_master_course.has_user(new_coach)
|
||||
# check that the coach has been enrolled in the ccx
|
||||
ccx_course_object = courses.get_course_by_id(self.ccx_key)
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=new_coach).exists()
|
||||
)
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_object.id, user=new_coach).exists()
|
||||
# check that an email has been sent to the coach
|
||||
self.assertEqual(len(outbox), 1)
|
||||
self.assertIn(new_coach.email, outbox[0].recipients())
|
||||
assert len(outbox) == 1
|
||||
assert new_coach.email in outbox[0].recipients()
|
||||
|
||||
def test_patch_detail_modules(self):
|
||||
"""
|
||||
@@ -1075,32 +1066,32 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
"""
|
||||
data = {'course_modules': self.master_course_chapters[0:1]}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
six.assertCountEqual(self, ccx_from_db.structure, data['course_modules'])
|
||||
|
||||
data = {'course_modules': []}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
six.assertCountEqual(self, ccx_from_db.structure, [])
|
||||
|
||||
data = {'course_modules': self.master_course_chapters}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
six.assertCountEqual(self, ccx_from_db.structure, self.master_course_chapters)
|
||||
|
||||
data = {'course_modules': None}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
self.assertEqual(ccx_from_db.structure, None)
|
||||
assert ccx_from_db.structure is None
|
||||
|
||||
chapters = self.master_course_chapters[0:1]
|
||||
data = {'course_modules': chapters * 3}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
six.assertCountEqual(self, ccx_from_db.structure, chapters)
|
||||
|
||||
@@ -1119,9 +1110,9 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
data = {'course_modules': chapters * 3}
|
||||
resp = self.client.patch(self.detail_url, data, format='json', HTTP_AUTHORIZATION=self.auth)
|
||||
if not user_is_active:
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
else:
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
ccx_from_db = CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
six.assertCountEqual(self, ccx_from_db.structure, chapters)
|
||||
|
||||
@@ -1137,18 +1128,18 @@ class CcxDetailTest(CcxRestApiTest):
|
||||
self.app_user.save()
|
||||
|
||||
# check that there are overrides
|
||||
self.assertGreater(CcxFieldOverride.objects.filter(ccx=self.ccx).count(), 0)
|
||||
self.assertGreater(CourseEnrollment.objects.filter(course_id=self.ccx_key).count(), 0)
|
||||
assert CcxFieldOverride.objects.filter(ccx=self.ccx).count() > 0
|
||||
assert CourseEnrollment.objects.filter(course_id=self.ccx_key).count() > 0
|
||||
resp = self.client.delete(self.detail_url, {}, HTTP_AUTHORIZATION=self.auth)
|
||||
|
||||
if not user_is_active:
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
assert resp.status_code == status.HTTP_403_FORBIDDEN
|
||||
else:
|
||||
self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertIsNone(resp.data)
|
||||
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
||||
assert resp.data is None
|
||||
# the CCX does not exist any more
|
||||
with self.assertRaises(CustomCourseForEdX.DoesNotExist):
|
||||
with pytest.raises(CustomCourseForEdX.DoesNotExist):
|
||||
CustomCourseForEdX.objects.get(id=self.ccx.id)
|
||||
# check that there are no overrides
|
||||
self.assertEqual(CcxFieldOverride.objects.filter(ccx=self.ccx).count(), 0)
|
||||
self.assertEqual(CourseEnrollment.objects.filter(course_id=self.ccx_key).count(), 0)
|
||||
assert CcxFieldOverride.objects.filter(ccx=self.ccx).count() == 0
|
||||
assert CourseEnrollment.objects.filter(course_id=self.ccx_key).count() == 0
|
||||
|
||||
@@ -85,10 +85,8 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
"""retrieving a course with a ccx key works"""
|
||||
expected = self.get_course(self.ccx_locator.to_course_locator())
|
||||
actual = self.get_course(self.ccx_locator)
|
||||
self.assertEqual(
|
||||
expected.location.course_key,
|
||||
actual.location.course_key.to_course_locator())
|
||||
self.assertEqual(expected.display_name, actual.display_name)
|
||||
assert expected.location.course_key == actual.location.course_key.to_course_locator()
|
||||
assert expected.display_name == actual.display_name
|
||||
|
||||
def test_get_children(self):
|
||||
"""the children of retrieved courses should be the same with course and ccx keys
|
||||
@@ -104,9 +102,9 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
self.fail('course children exhausted before ccx children')
|
||||
if actual is None:
|
||||
self.fail('ccx children exhausted before course children')
|
||||
self.assertEqual(expected.display_name, actual.display_name)
|
||||
self.assertEqual(expected.location.course_key, course_key)
|
||||
self.assertEqual(actual.location.course_key, self.ccx_locator)
|
||||
assert expected.display_name == actual.display_name
|
||||
assert expected.location.course_key == course_key
|
||||
assert actual.location.course_key == self.ccx_locator
|
||||
|
||||
def test_has_item(self):
|
||||
"""can verify that a location exists, using ccx block usage key"""
|
||||
@@ -114,7 +112,7 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
block_key = self.ccx_locator.make_usage_key(
|
||||
item.location.block_type, item.location.block_id
|
||||
)
|
||||
self.assertTrue(self.store.has_item(block_key))
|
||||
assert self.store.has_item(block_key)
|
||||
|
||||
def test_get_item(self):
|
||||
"""can retrieve an item by a location key, using a ccx block usage key
|
||||
@@ -127,8 +125,8 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
expected.location.block_type, expected.location.block_id
|
||||
)
|
||||
actual = self.store.get_item(block_key)
|
||||
self.assertEqual(expected.display_name, actual.display_name)
|
||||
self.assertEqual(expected.location, actual.location.to_block_locator())
|
||||
assert expected.display_name == actual.display_name
|
||||
assert expected.location == actual.location.to_block_locator()
|
||||
|
||||
def test_publication_api(self):
|
||||
"""verify that we can correctly discern a published item by ccx key"""
|
||||
@@ -137,8 +135,8 @@ class TestCCXModulestoreWrapper(SharedModuleStoreTestCase):
|
||||
block_key = self.ccx_locator.make_usage_key(
|
||||
expected.location.block_type, expected.location.block_id
|
||||
)
|
||||
self.assertTrue(self.store.has_published_version(expected))
|
||||
assert self.store.has_published_version(expected)
|
||||
self.store.unpublish(block_key, self.user.id)
|
||||
self.assertFalse(self.store.has_published_version(expected))
|
||||
assert not self.store.has_published_version(expected)
|
||||
self.store.publish(block_key, self.user.id)
|
||||
self.assertTrue(self.store.has_published_version(expected))
|
||||
assert self.store.has_published_version(expected)
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
"""verify that the course property of a ccx returns the right course"""
|
||||
expected = self.course
|
||||
actual = self.ccx.course
|
||||
self.assertEqual(expected, actual)
|
||||
assert expected == actual
|
||||
|
||||
def test_ccx_course_caching(self):
|
||||
"""verify that caching the propery works to limit queries"""
|
||||
@@ -66,7 +66,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
self.set_ccx_override('start', expected)
|
||||
actual = self.ccx.start
|
||||
diff = expected - actual
|
||||
self.assertLess(abs(diff.total_seconds()), 1)
|
||||
assert abs(diff.total_seconds()) < 1
|
||||
|
||||
def test_ccx_start_caching(self):
|
||||
"""verify that caching the start property works to limit queries"""
|
||||
@@ -83,7 +83,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
def test_ccx_due_without_override(self):
|
||||
"""verify that due returns None when the field has not been set"""
|
||||
actual = self.ccx.due
|
||||
self.assertIsNone(actual)
|
||||
assert actual is None
|
||||
|
||||
def test_ccx_due_is_correct(self):
|
||||
"""verify that the due datetime for a ccx is correctly retrieved"""
|
||||
@@ -91,7 +91,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
self.set_ccx_override('due', expected)
|
||||
actual = self.ccx.due
|
||||
diff = expected - actual
|
||||
self.assertLess(abs(diff.total_seconds()), 1)
|
||||
assert abs(diff.total_seconds()) < 1
|
||||
|
||||
def test_ccx_due_caching(self):
|
||||
"""verify that caching the due property works to limit queries"""
|
||||
@@ -111,7 +111,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
delta = timedelta(1)
|
||||
then = now - delta
|
||||
self.set_ccx_override('start', then)
|
||||
self.assertTrue(self.ccx.has_started())
|
||||
assert self.ccx.has_started()
|
||||
|
||||
def test_ccx_has_not_started(self):
|
||||
"""verify that a ccx marked as starting tomorrow has not started"""
|
||||
@@ -119,7 +119,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
delta = timedelta(1)
|
||||
then = now + delta
|
||||
self.set_ccx_override('start', then)
|
||||
self.assertFalse(self.ccx.has_started())
|
||||
assert not self.ccx.has_started()
|
||||
|
||||
def test_ccx_has_ended(self):
|
||||
"""verify that a ccx that has a due date in the past has ended"""
|
||||
@@ -127,7 +127,7 @@ class TestCCX(ModuleStoreTestCase):
|
||||
delta = timedelta(1)
|
||||
then = now - delta
|
||||
self.set_ccx_override('due', then)
|
||||
self.assertTrue(self.ccx.has_ended())
|
||||
assert self.ccx.has_ended()
|
||||
|
||||
def test_ccx_has_not_ended(self):
|
||||
"""verify that a ccx that has a due date in the future has not eneded
|
||||
@@ -136,11 +136,11 @@ class TestCCX(ModuleStoreTestCase):
|
||||
delta = timedelta(1)
|
||||
then = now + delta
|
||||
self.set_ccx_override('due', then)
|
||||
self.assertFalse(self.ccx.has_ended())
|
||||
assert not self.ccx.has_ended()
|
||||
|
||||
def test_ccx_without_due_date_has_not_ended(self):
|
||||
"""verify that a ccx without a due date has not ended"""
|
||||
self.assertFalse(self.ccx.has_ended())
|
||||
assert not self.ccx.has_ended()
|
||||
|
||||
def test_ccx_max_student_enrollment_correct(self):
|
||||
"""
|
||||
@@ -149,14 +149,14 @@ class TestCCX(ModuleStoreTestCase):
|
||||
expected = 200
|
||||
self.set_ccx_override('max_student_enrollments_allowed', expected)
|
||||
actual = self.ccx.max_student_enrollments_allowed
|
||||
self.assertEqual(expected, actual)
|
||||
assert expected == actual
|
||||
|
||||
def test_structure_json_default_empty(self):
|
||||
"""
|
||||
By default structure_json does not contain anything
|
||||
"""
|
||||
self.assertEqual(self.ccx.structure_json, None)
|
||||
self.assertEqual(self.ccx.structure, None)
|
||||
assert self.ccx.structure_json is None
|
||||
assert self.ccx.structure is None
|
||||
|
||||
def test_structure_json(self):
|
||||
"""
|
||||
@@ -173,12 +173,12 @@ class TestCCX(ModuleStoreTestCase):
|
||||
coach=self.coach,
|
||||
structure_json=json_struct
|
||||
)
|
||||
self.assertEqual(ccx.structure_json, json_struct)
|
||||
self.assertEqual(ccx.structure, dummy_struct)
|
||||
assert ccx.structure_json == json_struct
|
||||
assert ccx.structure == dummy_struct
|
||||
|
||||
def test_locator_property(self):
|
||||
"""
|
||||
Verify that the locator helper property returns a correct CCXLocator
|
||||
"""
|
||||
locator = self.ccx.locator
|
||||
self.assertEqual(self.ccx.id, int(locator.ccx))
|
||||
assert self.ccx.id == int(locator.ccx)
|
||||
|
||||
@@ -98,7 +98,7 @@ class TestFieldOverrides(FieldOverrideTestMixin, SharedModuleStoreTestCase):
|
||||
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
|
||||
chapter = self.ccx_course.get_children()[0]
|
||||
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
|
||||
self.assertEqual(chapter.start, ccx_start)
|
||||
assert chapter.start == ccx_start
|
||||
|
||||
def test_override_num_queries_new_field(self):
|
||||
"""
|
||||
@@ -156,8 +156,8 @@ class TestFieldOverrides(FieldOverrideTestMixin, SharedModuleStoreTestCase):
|
||||
ccx_start = datetime.datetime(2014, 12, 25, 00, 00, tzinfo=pytz.UTC)
|
||||
chapter = self.ccx_course.get_children()[0]
|
||||
override_field_for_ccx(self.ccx, chapter, 'start', ccx_start)
|
||||
self.assertEqual(chapter.get_children()[0].start, ccx_start)
|
||||
self.assertEqual(chapter.get_children()[1].start, ccx_start)
|
||||
assert chapter.get_children()[0].start == ccx_start
|
||||
assert chapter.get_children()[1].start == ccx_start
|
||||
|
||||
def test_override_is_inherited_even_if_set_in_mooc(self):
|
||||
"""
|
||||
@@ -170,4 +170,4 @@ class TestFieldOverrides(FieldOverrideTestMixin, SharedModuleStoreTestCase):
|
||||
chapter.display_name = 'itsme!'
|
||||
override_field_for_ccx(self.ccx, chapter, 'due', ccx_due)
|
||||
vertical = chapter.get_children()[0].get_children()[0]
|
||||
self.assertEqual(vertical.due, ccx_due)
|
||||
assert vertical.due == ccx_due
|
||||
|
||||
@@ -63,7 +63,7 @@ class TestSendCCXCoursePublished(ModuleStoreTestCase):
|
||||
course_key = CCXLocator.from_course_locator(self.course.id, self.ccx.id)
|
||||
with mock_signal_receiver(SignalHandler.course_published) as receiver:
|
||||
self.call_fut(course_key)
|
||||
self.assertEqual(receiver.call_count, 0)
|
||||
assert receiver.call_count == 0
|
||||
|
||||
def test_signal_sent_for_ccx(self):
|
||||
"""
|
||||
@@ -73,7 +73,7 @@ class TestSendCCXCoursePublished(ModuleStoreTestCase):
|
||||
"""
|
||||
with mock_signal_receiver(SignalHandler.course_published) as receiver:
|
||||
self.call_fut(self.course.id)
|
||||
self.assertEqual(receiver.call_count, 3)
|
||||
assert receiver.call_count == 3
|
||||
|
||||
def test_course_overview_cached(self):
|
||||
"""
|
||||
@@ -81,9 +81,9 @@ class TestSendCCXCoursePublished(ModuleStoreTestCase):
|
||||
"""
|
||||
course_key = CCXLocator.from_course_locator(self.course.id, self.ccx.id)
|
||||
overview = CourseOverview.objects.filter(id=course_key)
|
||||
self.assertEqual(len(overview), 0)
|
||||
assert len(overview) == 0
|
||||
with mock_signal_receiver(SignalHandler.course_published) as receiver:
|
||||
self.call_fut(self.course.id)
|
||||
self.assertEqual(receiver.call_count, 3)
|
||||
assert receiver.call_count == 3
|
||||
overview = CourseOverview.objects.filter(id=course_key)
|
||||
self.assertEqual(len(overview), 1)
|
||||
assert len(overview) == 1
|
||||
|
||||
@@ -42,7 +42,7 @@ class TestGetCCXFromCCXLocator(ModuleStoreTestCase):
|
||||
"""verify that nothing is returned if locator is not a ccx locator
|
||||
"""
|
||||
result = self.call_fut(self.course.id)
|
||||
self.assertEqual(result, None)
|
||||
assert result is None
|
||||
|
||||
def test_ccx_locator(self):
|
||||
"""verify that the ccx is retuned if using a ccx locator
|
||||
@@ -50,7 +50,7 @@ class TestGetCCXFromCCXLocator(ModuleStoreTestCase):
|
||||
ccx = CcxFactory(course_id=self.course.id, coach=self.coach)
|
||||
course_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
|
||||
result = self.call_fut(course_key)
|
||||
self.assertEqual(result, ccx)
|
||||
assert result == ccx
|
||||
|
||||
|
||||
class TestStaffOnCCX(CcxTestCase):
|
||||
@@ -78,11 +78,11 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
"""
|
||||
# adding staff to master course.
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name)
|
||||
|
||||
@@ -92,12 +92,12 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
|
||||
with ccx_course(self.ccx_locator) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
self.assertEqual(list_staff_master_course[0].email, list_staff_ccx_course[0].email)
|
||||
assert len(list_staff_master_course) == len(list_staff_ccx_course)
|
||||
assert list_staff_master_course[0].email == list_staff_ccx_course[0].email
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
self.assertEqual(list_instructor_ccx_course[0].email, list_instructor_master_course[0].email)
|
||||
assert len(list_instructor_ccx_course) == len(list_instructor_master_course)
|
||||
assert list_instructor_ccx_course[0].email == list_instructor_master_course[0].email
|
||||
|
||||
def test_add_master_course_staff_to_ccx_with_exception(self):
|
||||
"""
|
||||
@@ -105,42 +105,34 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
instructor.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
|
||||
with mock.patch.object(CourseEnrollment, 'enroll_by_email', side_effect=CourseEnrollmentException()):
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name)
|
||||
|
||||
self.assertFalse(
|
||||
CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=staff).exists()
|
||||
)
|
||||
self.assertFalse(
|
||||
CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=instructor).exists()
|
||||
)
|
||||
assert not CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=staff).exists()
|
||||
assert not CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=instructor).exists()
|
||||
|
||||
with mock.patch.object(CourseEnrollment, 'enroll_by_email', side_effect=SMTPException()):
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name)
|
||||
|
||||
self.assertFalse(
|
||||
CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=staff).exists()
|
||||
)
|
||||
self.assertFalse(
|
||||
CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=instructor).exists()
|
||||
)
|
||||
assert not CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=staff).exists()
|
||||
assert not CourseEnrollment.objects.filter(course_id=self.ccx_locator, user=instructor).exists()
|
||||
|
||||
def test_remove_master_course_staff_from_ccx(self):
|
||||
"""
|
||||
Test remove staff of master course to ccx course
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name, send_email=False)
|
||||
|
||||
@@ -149,41 +141,41 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
|
||||
with ccx_course(self.ccx_locator) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
self.assertEqual(list_staff_master_course[0].email, list_staff_ccx_course[0].email)
|
||||
assert len(list_staff_master_course) == len(list_staff_ccx_course)
|
||||
assert list_staff_master_course[0].email == list_staff_ccx_course[0].email
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
self.assertEqual(list_instructor_ccx_course[0].email, list_instructor_master_course[0].email)
|
||||
assert len(list_instructor_ccx_course) == len(list_instructor_master_course)
|
||||
assert list_instructor_ccx_course[0].email == list_instructor_master_course[0].email
|
||||
|
||||
# assert that role of staff and instructors of master course removed from ccx.
|
||||
remove_master_course_staff_from_ccx(
|
||||
self.course, self.ccx_locator, self.ccx.display_name, send_email=False
|
||||
)
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertNotEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
assert len(list_staff_master_course) != len(list_staff_ccx_course)
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertNotEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
assert len(list_instructor_ccx_course) != len(list_instructor_master_course)
|
||||
|
||||
for user in list_staff_master_course:
|
||||
self.assertNotIn(user, list_staff_ccx_course)
|
||||
assert user not in list_staff_ccx_course
|
||||
for user in list_instructor_master_course:
|
||||
self.assertNotIn(user, list_instructor_ccx_course)
|
||||
assert user not in list_instructor_ccx_course
|
||||
|
||||
def test_remove_master_course_staff_from_ccx_idempotent(self):
|
||||
"""
|
||||
Test remove staff of master course from ccx course
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
|
||||
outbox = self.get_outbox()
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name, send_email=False)
|
||||
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
@@ -191,45 +183,45 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
|
||||
with ccx_course(self.ccx_locator) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
self.assertEqual(list_staff_master_course[0].email, list_staff_ccx_course[0].email)
|
||||
assert len(list_staff_master_course) == len(list_staff_ccx_course)
|
||||
assert list_staff_master_course[0].email == list_staff_ccx_course[0].email
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
self.assertEqual(list_instructor_ccx_course[0].email, list_instructor_master_course[0].email)
|
||||
assert len(list_instructor_ccx_course) == len(list_instructor_master_course)
|
||||
assert list_instructor_ccx_course[0].email == list_instructor_master_course[0].email
|
||||
|
||||
# assert that role of staff and instructors of master course removed from ccx.
|
||||
remove_master_course_staff_from_ccx(
|
||||
self.course, self.ccx_locator, self.ccx.display_name, send_email=True
|
||||
)
|
||||
self.assertEqual(len(outbox), len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
assert len(outbox) == (len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertNotEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
assert len(list_staff_master_course) != len(list_staff_ccx_course)
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertNotEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
assert len(list_instructor_ccx_course) != len(list_instructor_master_course)
|
||||
|
||||
for user in list_staff_master_course:
|
||||
self.assertNotIn(user, list_staff_ccx_course)
|
||||
assert user not in list_staff_ccx_course
|
||||
for user in list_instructor_master_course:
|
||||
self.assertNotIn(user, list_instructor_ccx_course)
|
||||
assert user not in list_instructor_ccx_course
|
||||
|
||||
# Run again
|
||||
remove_master_course_staff_from_ccx(self.course, self.ccx_locator, self.ccx.display_name)
|
||||
self.assertEqual(len(outbox), len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
assert len(outbox) == (len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
|
||||
with ccx_course(self.ccx_locator) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
self.assertNotEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
assert len(list_staff_master_course) != len(list_staff_ccx_course)
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertNotEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
assert len(list_instructor_ccx_course) != len(list_instructor_master_course)
|
||||
|
||||
for user in list_staff_master_course:
|
||||
self.assertNotIn(user, list_staff_ccx_course)
|
||||
assert user not in list_staff_ccx_course
|
||||
for user in list_instructor_master_course:
|
||||
self.assertNotIn(user, list_instructor_ccx_course)
|
||||
assert user not in list_instructor_ccx_course
|
||||
|
||||
def test_add_master_course_staff_to_ccx_display_name(self):
|
||||
"""
|
||||
@@ -238,22 +230,22 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
subject of the email sent to the enrolled users.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
outbox = self.get_outbox()
|
||||
# create a unique display name
|
||||
display_name = 'custom_display_{}'.format(uuid.uuid4())
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
list_instructor_master_course = list_with_level(self.course, 'instructor')
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
# give access to the course staff/instructor
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, display_name)
|
||||
self.assertEqual(len(outbox), len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
assert len(outbox) == (len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
for email in outbox:
|
||||
self.assertIn(display_name, email.subject)
|
||||
assert display_name in email.subject
|
||||
|
||||
def test_remove_master_course_staff_from_ccx_display_name(self):
|
||||
"""
|
||||
@@ -262,23 +254,23 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
subject of the email sent to the unenrolled users.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
outbox = self.get_outbox()
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name, send_email=False)
|
||||
# create a unique display name
|
||||
display_name = 'custom_display_{}'.format(uuid.uuid4())
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
list_instructor_master_course = list_with_level(self.course, 'instructor')
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
# give access to the course staff/instructor
|
||||
remove_master_course_staff_from_ccx(self.course, self.ccx_locator, display_name)
|
||||
self.assertEqual(len(outbox), len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
assert len(outbox) == (len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
for email in outbox:
|
||||
self.assertIn(display_name, email.subject)
|
||||
assert display_name in email.subject
|
||||
|
||||
def test_add_master_course_staff_to_ccx_idempotent(self):
|
||||
"""
|
||||
@@ -286,43 +278,43 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
not result in multiple enrollments.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
outbox = self.get_outbox()
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
list_instructor_master_course = list_with_level(self.course, 'instructor')
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
|
||||
# run the assignment the first time
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name)
|
||||
self.assertEqual(len(outbox), len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
assert len(outbox) == (len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
with ccx_course(self.ccx_locator) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
assert len(list_staff_master_course) == len(list_staff_ccx_course)
|
||||
for user in list_staff_master_course:
|
||||
self.assertIn(user, list_staff_ccx_course)
|
||||
self.assertEqual(len(list_instructor_master_course), len(list_instructor_ccx_course))
|
||||
assert user in list_staff_ccx_course
|
||||
assert len(list_instructor_master_course) == len(list_instructor_ccx_course)
|
||||
for user in list_instructor_master_course:
|
||||
self.assertIn(user, list_instructor_ccx_course)
|
||||
assert user in list_instructor_ccx_course
|
||||
|
||||
# run the assignment again
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name)
|
||||
# there are no new duplicated email
|
||||
self.assertEqual(len(outbox), len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
assert len(outbox) == (len(list_staff_master_course) + len(list_instructor_master_course))
|
||||
# there are no duplicated staffs
|
||||
with ccx_course(self.ccx_locator) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertEqual(len(list_staff_master_course), len(list_staff_ccx_course))
|
||||
assert len(list_staff_master_course) == len(list_staff_ccx_course)
|
||||
for user in list_staff_master_course:
|
||||
self.assertIn(user, list_staff_ccx_course)
|
||||
self.assertEqual(len(list_instructor_master_course), len(list_instructor_ccx_course))
|
||||
assert user in list_staff_ccx_course
|
||||
assert len(list_instructor_master_course) == len(list_instructor_ccx_course)
|
||||
for user in list_instructor_master_course:
|
||||
self.assertIn(user, list_instructor_ccx_course)
|
||||
assert user in list_instructor_ccx_course
|
||||
|
||||
def test_add_master_course_staff_to_ccx_no_email(self):
|
||||
"""
|
||||
@@ -330,15 +322,15 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
sending enrollment email.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
outbox = self.get_outbox()
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name, send_email=False)
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
|
||||
def test_remove_master_course_staff_from_ccx_no_email(self):
|
||||
"""
|
||||
@@ -346,12 +338,12 @@ class TestStaffOnCCX(CcxTestCase):
|
||||
sending enrollment email.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = self.make_instructor()
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
outbox = self.get_outbox()
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
remove_master_course_staff_from_ccx(self.course, self.ccx_locator, self.ccx.display_name, send_email=False)
|
||||
self.assertEqual(len(outbox), 0)
|
||||
assert len(outbox) == 0
|
||||
|
||||
@@ -146,7 +146,7 @@ class TestAdminAccessCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
self.client.login(username=staff.username, password="test")
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_instructor_access_coach_dashboard(self):
|
||||
"""
|
||||
@@ -157,7 +157,7 @@ class TestAdminAccessCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
|
||||
# Now access URL
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_forbidden_user_access_coach_dashboard(self):
|
||||
"""
|
||||
@@ -166,7 +166,7 @@ class TestAdminAccessCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
user = UserFactory.create(password="test")
|
||||
self.client.login(username=user.username, password="test")
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
@override_settings(
|
||||
@@ -221,9 +221,7 @@ class TestCCXProgressChanges(CcxTestCase, LoginEnrollmentTestCase):
|
||||
"""
|
||||
student = UserFactory.create(is_staff=False, password="test")
|
||||
CourseEnrollment.enroll(student, ccx_course_key)
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=student).exists()
|
||||
)
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_key, user=student).exists()
|
||||
|
||||
# login as student
|
||||
self.client.login(username=student.username, password="test")
|
||||
@@ -234,7 +232,7 @@ class TestCCXProgressChanges(CcxTestCase, LoginEnrollmentTestCase):
|
||||
chapter = grade_summary[0]
|
||||
section = chapter['sections'][0]
|
||||
progress_page_due_date = section.due.strftime(u"%Y-%m-%d %H:%M")
|
||||
self.assertEqual(progress_page_due_date, due)
|
||||
assert progress_page_due_date == due
|
||||
|
||||
@patch('lms.djangoapps.ccx.views.render_to_response', intercept_renderer)
|
||||
@patch('lms.djangoapps.courseware.views.views.render_to_response', intercept_renderer)
|
||||
@@ -252,7 +250,7 @@ class TestCCXProgressChanges(CcxTestCase, LoginEnrollmentTestCase):
|
||||
response = self.client.get(url)
|
||||
|
||||
schedule = json.loads(response.mako_context['schedule'])
|
||||
self.assertEqual(len(schedule), 1)
|
||||
assert len(schedule) == 1
|
||||
|
||||
unhide(schedule[0])
|
||||
|
||||
@@ -270,15 +268,15 @@ class TestCCXProgressChanges(CcxTestCase, LoginEnrollmentTestCase):
|
||||
url = reverse('save_ccx', kwargs={'course_id': ccx_course_key})
|
||||
response = self.client.post(url, json.dumps(schedule), content_type='application/json')
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
schedule = json.loads(response.content.decode('utf-8'))['schedule']
|
||||
self.assertEqual(schedule[0]['hidden'], False)
|
||||
self.assertEqual(schedule[0]['start'], start)
|
||||
self.assertEqual(schedule[0]['children'][0]['start'], start)
|
||||
self.assertEqual(schedule[0]['children'][0]['due'], due)
|
||||
self.assertEqual(schedule[0]['children'][0]['children'][0]['due'], due)
|
||||
self.assertEqual(schedule[0]['children'][0]['children'][0]['start'], start)
|
||||
assert schedule[0]['hidden'] is False
|
||||
assert schedule[0]['start'] == start
|
||||
assert schedule[0]['children'][0]['start'] == start
|
||||
assert schedule[0]['children'][0]['due'] == due
|
||||
assert schedule[0]['children'][0]['children'][0]['due'] == due
|
||||
assert schedule[0]['children'][0]['children'][0]['start'] == start
|
||||
|
||||
self.assert_progress_summary(ccx_course_key, due)
|
||||
|
||||
@@ -310,12 +308,12 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
# adding staff to master course.
|
||||
staff = UserFactory()
|
||||
allow_access(self.course, staff, 'staff')
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = UserFactory()
|
||||
allow_access(self.course, instructor, 'instructor')
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
|
||||
def test_not_a_coach(self):
|
||||
"""
|
||||
@@ -331,7 +329,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
'ccx_coach_dashboard',
|
||||
kwargs={'course_id': CCXLocator.from_course_locator(self.course.id, ccx.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_no_ccx_created(self):
|
||||
"""
|
||||
@@ -342,10 +340,8 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
'ccx_coach_dashboard',
|
||||
kwargs={'course_id': six.text_type(self.course.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(re.search(
|
||||
'<form action=".+create_ccx"',
|
||||
response.content.decode('utf-8')))
|
||||
assert response.status_code == 200
|
||||
assert re.search('<form action=".+create_ccx"', response.content.decode('utf-8'))
|
||||
|
||||
def test_create_ccx_with_ccx_connector_set(self):
|
||||
"""
|
||||
@@ -359,12 +355,12 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
kwargs={'course_id': six.text_type(self.course_with_ccx_connect_set.id)})
|
||||
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
error_message = _(
|
||||
"A CCX can only be created on this course through an external service."
|
||||
" Contact a course admin to give you access."
|
||||
)
|
||||
self.assertTrue(re.search(error_message, response.content.decode('utf-8')))
|
||||
assert re.search(error_message, response.content.decode('utf-8'))
|
||||
|
||||
def test_create_ccx(self, ccx_name='New CCX'):
|
||||
"""
|
||||
@@ -378,10 +374,10 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
kwargs={'course_id': six.text_type(self.course.id)})
|
||||
|
||||
response = self.client.post(url, {'name': ccx_name})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
assert response.status_code == 302
|
||||
url = response.get('location')
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
# Get the ccx_key
|
||||
path = six.moves.urllib.parse.urlparse(url).path
|
||||
@@ -390,45 +386,45 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
|
||||
course_key = CourseKey.from_string(ccx_key)
|
||||
|
||||
self.assertTrue(CourseEnrollment.is_enrolled(self.coach, course_key))
|
||||
self.assertTrue(re.search('id="ccx-schedule"', response.content.decode('utf-8')))
|
||||
assert CourseEnrollment.is_enrolled(self.coach, course_key)
|
||||
assert re.search('id="ccx-schedule"', response.content.decode('utf-8'))
|
||||
|
||||
# check if the max amount of student that can be enrolled has been overridden
|
||||
ccx = CustomCourseForEdX.objects.get()
|
||||
course_enrollments = get_override_for_ccx(ccx, self.course, 'max_student_enrollments_allowed')
|
||||
self.assertEqual(course_enrollments, settings.CCX_MAX_STUDENTS_ALLOWED)
|
||||
assert course_enrollments == settings.CCX_MAX_STUDENTS_ALLOWED
|
||||
# check if the course display name is properly set
|
||||
course_display_name = get_override_for_ccx(ccx, self.course, 'display_name')
|
||||
self.assertEqual(course_display_name, ccx_name)
|
||||
assert course_display_name == ccx_name
|
||||
|
||||
# check if the course display name is properly set in modulestore
|
||||
course_display_name = self.mstore.get_course(ccx.locator).display_name
|
||||
self.assertEqual(course_display_name, ccx_name)
|
||||
assert course_display_name == ccx_name
|
||||
|
||||
# assert ccx creator has role=staff
|
||||
role = CourseStaffRole(course_key)
|
||||
self.assertTrue(role.has_user(self.coach))
|
||||
assert role.has_user(self.coach)
|
||||
|
||||
# assert that staff and instructors of master course has staff and instructor roles on ccx
|
||||
list_staff_master_course = list_with_level(self.course, 'staff')
|
||||
list_instructor_master_course = list_with_level(self.course, 'instructor')
|
||||
|
||||
# assert that forum roles are seeded
|
||||
self.assertTrue(are_permissions_roles_seeded(course_key))
|
||||
self.assertTrue(has_forum_access(self.coach.username, course_key, FORUM_ROLE_ADMINISTRATOR))
|
||||
assert are_permissions_roles_seeded(course_key)
|
||||
assert has_forum_access(self.coach.username, course_key, FORUM_ROLE_ADMINISTRATOR)
|
||||
|
||||
with ccx_course(course_key) as course_ccx:
|
||||
list_staff_ccx_course = list_with_level(course_ccx, 'staff')
|
||||
# The "Coach" in the parent course becomes "Staff" on the CCX, so the CCX should have 1 "Staff"
|
||||
# user more than the parent course
|
||||
self.assertEqual(len(list_staff_master_course) + 1, len(list_staff_ccx_course))
|
||||
self.assertIn(list_staff_master_course[0].email, [ccx_staff.email for ccx_staff in list_staff_ccx_course])
|
||||
assert (len(list_staff_master_course) + 1) == len(list_staff_ccx_course)
|
||||
assert list_staff_master_course[0].email in [ccx_staff.email for ccx_staff in list_staff_ccx_course]
|
||||
# Make sure the "Coach" on the parent course is "Staff" on the CCX
|
||||
self.assertIn(self.coach, list_staff_ccx_course)
|
||||
assert self.coach in list_staff_ccx_course
|
||||
|
||||
list_instructor_ccx_course = list_with_level(course_ccx, 'instructor')
|
||||
self.assertEqual(len(list_instructor_ccx_course), len(list_instructor_master_course))
|
||||
self.assertEqual(list_instructor_ccx_course[0].email, list_instructor_master_course[0].email)
|
||||
assert len(list_instructor_ccx_course) == len(list_instructor_master_course)
|
||||
assert list_instructor_ccx_course[0].email == list_instructor_master_course[0].email
|
||||
|
||||
@ddt.data("CCX demo 1", "CCX demo 2", "CCX demo 3")
|
||||
def test_create_multiple_ccx(self, ccx_name):
|
||||
@@ -443,7 +439,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
'ccx_coach_dashboard',
|
||||
kwargs={'course_id': CCXLocator.from_course_locator(self.course_disable_ccx.id, ccx.id)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_dashboard_access_with_invalid_ccx_id(self):
|
||||
"""
|
||||
@@ -454,7 +450,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
'ccx_coach_dashboard',
|
||||
kwargs={'course_id': CCXLocator.from_course_locator(self.course_disable_ccx.id, 700)})
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_get_date(self):
|
||||
"""
|
||||
@@ -462,14 +458,14 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
"""
|
||||
ccx = self.make_ccx()
|
||||
for section in self.course.get_children():
|
||||
self.assertEqual(get_date(ccx, section, 'start'), self.mooc_start)
|
||||
self.assertEqual(get_date(ccx, section, 'due'), None)
|
||||
assert get_date(ccx, section, 'start') == self.mooc_start
|
||||
assert get_date(ccx, section, 'due') is None
|
||||
for subsection in section.get_children():
|
||||
self.assertEqual(get_date(ccx, subsection, 'start'), self.mooc_start)
|
||||
self.assertEqual(get_date(ccx, subsection, 'due'), self.mooc_due)
|
||||
assert get_date(ccx, subsection, 'start') == self.mooc_start
|
||||
assert get_date(ccx, subsection, 'due') == self.mooc_due
|
||||
for unit in subsection.get_children():
|
||||
self.assertEqual(get_date(ccx, unit, 'start', parent_node=subsection), self.mooc_start)
|
||||
self.assertEqual(get_date(ccx, unit, 'due', parent_node=subsection), self.mooc_due)
|
||||
assert get_date(ccx, unit, 'start', parent_node=subsection) == self.mooc_start
|
||||
assert get_date(ccx, unit, 'due', parent_node=subsection) == self.mooc_due
|
||||
|
||||
@patch('lms.djangoapps.ccx.views.render_to_response', intercept_renderer)
|
||||
@patch('lms.djangoapps.ccx.views.TODAY')
|
||||
@@ -486,23 +482,17 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
response = self.client.get(url)
|
||||
schedule = json.loads(response.mako_context['schedule'])
|
||||
|
||||
self.assertEqual(len(schedule), 2)
|
||||
self.assertEqual(schedule[0]['hidden'], False)
|
||||
assert len(schedule) == 2
|
||||
assert schedule[0]['hidden'] is False
|
||||
# If a coach does not override dates, then dates will be imported from master course.
|
||||
self.assertEqual(
|
||||
schedule[0]['start'],
|
||||
self.chapters[0].start.strftime(u'%Y-%m-%d %H:%M')
|
||||
)
|
||||
self.assertEqual(
|
||||
schedule[0]['children'][0]['start'],
|
||||
self.sequentials[0].start.strftime(u'%Y-%m-%d %H:%M')
|
||||
)
|
||||
assert schedule[0]['start'] == self.chapters[0].start.strftime(u'%Y-%m-%d %H:%M')
|
||||
assert schedule[0]['children'][0]['start'] == self.sequentials[0].start.strftime(u'%Y-%m-%d %H:%M')
|
||||
|
||||
if self.sequentials[0].due:
|
||||
expected_due = self.sequentials[0].due.strftime(u'%Y-%m-%d %H:%M')
|
||||
else:
|
||||
expected_due = None
|
||||
self.assertEqual(schedule[0]['children'][0]['due'], expected_due)
|
||||
assert schedule[0]['children'][0]['due'] == expected_due
|
||||
|
||||
url = reverse(
|
||||
'save_ccx',
|
||||
@@ -519,36 +509,30 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
)
|
||||
|
||||
schedule = json.loads(response.content.decode('utf-8'))['schedule']
|
||||
self.assertEqual(schedule[0]['hidden'], False)
|
||||
self.assertEqual(schedule[0]['start'], u'2014-11-20 00:00')
|
||||
self.assertEqual(
|
||||
schedule[0]['children'][0]['due'], u'2014-12-25 00:00'
|
||||
)
|
||||
assert schedule[0]['hidden'] is False
|
||||
assert schedule[0]['start'] == u'2014-11-20 00:00'
|
||||
assert schedule[0]['children'][0]['due'] == u'2014-12-25 00:00'
|
||||
|
||||
self.assertEqual(
|
||||
schedule[0]['children'][0]['children'][0]['due'], u'2014-12-25 00:00'
|
||||
)
|
||||
self.assertEqual(
|
||||
schedule[0]['children'][0]['children'][0]['start'], u'2014-12-20 00:00'
|
||||
)
|
||||
assert schedule[0]['children'][0]['children'][0]['due'] == u'2014-12-25 00:00'
|
||||
assert schedule[0]['children'][0]['children'][0]['start'] == u'2014-12-20 00:00'
|
||||
|
||||
# Make sure start date set on course, follows start date of earliest
|
||||
# scheduled chapter
|
||||
ccx = CustomCourseForEdX.objects.get()
|
||||
course_start = get_override_for_ccx(ccx, self.course, 'start')
|
||||
self.assertEqual(str(course_start)[:-9], self.chapters[0].start.strftime(u'%Y-%m-%d %H:%M'))
|
||||
assert str(course_start)[:(- 9)] == self.chapters[0].start.strftime(u'%Y-%m-%d %H:%M')
|
||||
|
||||
# Make sure grading policy adjusted
|
||||
policy = get_override_for_ccx(ccx, self.course, 'grading_policy',
|
||||
self.course.grading_policy)
|
||||
self.assertEqual(policy['GRADER'][0]['type'], 'Homework')
|
||||
self.assertEqual(policy['GRADER'][0]['min_count'], 8)
|
||||
self.assertEqual(policy['GRADER'][1]['type'], 'Lab')
|
||||
self.assertEqual(policy['GRADER'][1]['min_count'], 0)
|
||||
self.assertEqual(policy['GRADER'][2]['type'], 'Midterm Exam')
|
||||
self.assertEqual(policy['GRADER'][2]['min_count'], 0)
|
||||
self.assertEqual(policy['GRADER'][3]['type'], 'Final Exam')
|
||||
self.assertEqual(policy['GRADER'][3]['min_count'], 0)
|
||||
assert policy['GRADER'][0]['type'] == 'Homework'
|
||||
assert policy['GRADER'][0]['min_count'] == 8
|
||||
assert policy['GRADER'][1]['type'] == 'Lab'
|
||||
assert policy['GRADER'][1]['min_count'] == 0
|
||||
assert policy['GRADER'][2]['type'] == 'Midterm Exam'
|
||||
assert policy['GRADER'][2]['min_count'] == 0
|
||||
assert policy['GRADER'][3]['type'] == 'Final Exam'
|
||||
assert policy['GRADER'][3]['min_count'] == 0
|
||||
|
||||
@patch('lms.djangoapps.ccx.views.render_to_response', intercept_renderer)
|
||||
def test_save_without_min_count(self):
|
||||
@@ -580,7 +564,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
response = self.client.post(
|
||||
save_policy_url, {"policy": json.dumps(policy)}
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
assert response.status_code == 302
|
||||
|
||||
ccx = CustomCourseForEdX.objects.get()
|
||||
|
||||
@@ -588,9 +572,9 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
policy = get_override_for_ccx(
|
||||
ccx, self.course, 'grading_policy', self.course.grading_policy
|
||||
)
|
||||
self.assertEqual(len(policy['GRADER']), 1)
|
||||
self.assertEqual(policy['GRADER'][0]['type'], 'Homework')
|
||||
self.assertNotIn('min_count', policy['GRADER'][0])
|
||||
assert len(policy['GRADER']) == 1
|
||||
assert policy['GRADER'][0]['type'] == 'Homework'
|
||||
assert 'min_count' not in policy['GRADER'][0]
|
||||
|
||||
save_ccx_url = reverse('save_ccx', kwargs={'course_id': course_id})
|
||||
coach_dashboard_url = reverse(
|
||||
@@ -602,7 +586,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
response = self.client.post(
|
||||
save_ccx_url, json.dumps(schedule), content_type='application/json'
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
@ddt.data(
|
||||
('ccx-manage-students', True, 1, 'student-ids', ('enrollment-button', 'Enroll')),
|
||||
@@ -622,7 +606,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
enrollment = CourseEnrollmentFactory(course_id=self.course.id)
|
||||
student = enrollment.user
|
||||
outbox = self.get_outbox()
|
||||
self.assertEqual(outbox, [])
|
||||
assert outbox == []
|
||||
|
||||
url = reverse(
|
||||
view_name,
|
||||
@@ -635,17 +619,15 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
if send_email:
|
||||
data['email-students'] = 'Notify-students-by-email'
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# we were redirected to our current location
|
||||
self.assertEqual(len(response.redirect_chain), 1)
|
||||
self.assertIn(302, response.redirect_chain[0])
|
||||
self.assertEqual(len(outbox), outbox_count)
|
||||
assert len(response.redirect_chain) == 1
|
||||
assert 302 in response.redirect_chain[0]
|
||||
assert len(outbox) == outbox_count
|
||||
if send_email:
|
||||
self.assertIn(student.email, outbox[0].recipients())
|
||||
assert student.email in outbox[0].recipients()
|
||||
# a CcxMembership exists for this student
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=self.course.id, user=student).exists()
|
||||
)
|
||||
assert CourseEnrollment.objects.filter(course_id=self.course.id, user=student).exists()
|
||||
|
||||
def test_ccx_invite_enroll_up_to_limit(self):
|
||||
"""
|
||||
@@ -675,28 +657,16 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
'student-ids': u','.join([student.email for student in students]),
|
||||
}
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# even if course is coach can enroll staff and admins of master course into ccx
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=instructor).exists()
|
||||
)
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=staff).exists()
|
||||
)
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=self.coach).exists()
|
||||
)
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_key, user=instructor).exists()
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_key, user=staff).exists()
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_key, user=self.coach).exists()
|
||||
|
||||
# a CcxMembership exists for the first five students but not the sixth
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[3]).exists()
|
||||
)
|
||||
self.assertTrue(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[4]).exists()
|
||||
)
|
||||
self.assertFalse(
|
||||
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[5]).exists()
|
||||
)
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[3]).exists()
|
||||
assert CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[4]).exists()
|
||||
assert not CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[5]).exists()
|
||||
|
||||
@ddt.data(
|
||||
('ccx-manage-students', True, 1, 'student-ids', ('enrollment-button', 'Unenroll')),
|
||||
@@ -718,7 +688,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
enrollment = CourseEnrollmentFactory(course_id=course_key)
|
||||
student = enrollment.user
|
||||
outbox = self.get_outbox()
|
||||
self.assertEqual(outbox, [])
|
||||
assert outbox == []
|
||||
|
||||
url = reverse(
|
||||
view_name,
|
||||
@@ -731,17 +701,15 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
if send_email:
|
||||
data['email-students'] = 'Notify-students-by-email'
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# we were redirected to our current location
|
||||
self.assertEqual(len(response.redirect_chain), 1)
|
||||
self.assertIn(302, response.redirect_chain[0])
|
||||
self.assertEqual(len(outbox), outbox_count)
|
||||
assert len(response.redirect_chain) == 1
|
||||
assert 302 in response.redirect_chain[0]
|
||||
assert len(outbox) == outbox_count
|
||||
if send_email:
|
||||
self.assertIn(student.email, outbox[0].recipients())
|
||||
assert student.email in outbox[0].recipients()
|
||||
# a CcxMembership does not exists for this student
|
||||
self.assertFalse(
|
||||
CourseEnrollment.objects.filter(course_id=self.course.id, user=student).exists()
|
||||
)
|
||||
assert not CourseEnrollment.objects.filter(course_id=self.course.id, user=student).exists()
|
||||
|
||||
@ddt.data(
|
||||
('ccx-manage-students', True, 1, 'student-ids', ('enrollment-button', 'Enroll'), 'nobody@nowhere.com'),
|
||||
@@ -762,7 +730,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
ccx = self.make_ccx()
|
||||
course_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
|
||||
outbox = self.get_outbox()
|
||||
self.assertEqual(outbox, [])
|
||||
assert outbox == []
|
||||
|
||||
url = reverse(
|
||||
view_name,
|
||||
@@ -775,11 +743,11 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
if send_email:
|
||||
data['email-students'] = 'Notify-students-by-email'
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# we were redirected to our current location
|
||||
self.assertEqual(len(response.redirect_chain), 1)
|
||||
self.assertIn(302, response.redirect_chain[0])
|
||||
self.assertEqual(len(outbox), outbox_count)
|
||||
assert len(response.redirect_chain) == 1
|
||||
assert 302 in response.redirect_chain[0]
|
||||
assert len(outbox) == outbox_count
|
||||
|
||||
# some error messages are returned for one of the views only
|
||||
if view_name == 'ccx_manage_student' and not is_email(identifier):
|
||||
@@ -787,14 +755,10 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
|
||||
if is_email(identifier):
|
||||
if send_email:
|
||||
self.assertIn(identifier, outbox[0].recipients())
|
||||
self.assertTrue(
|
||||
CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=identifier).exists()
|
||||
)
|
||||
assert identifier in outbox[0].recipients()
|
||||
assert CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=identifier).exists()
|
||||
else:
|
||||
self.assertFalse(
|
||||
CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=identifier).exists()
|
||||
)
|
||||
assert not CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=identifier).exists()
|
||||
|
||||
@ddt.data(
|
||||
('ccx-manage-students', True, 0, 'student-ids', ('enrollment-button', 'Unenroll'), 'nobody@nowhere.com'),
|
||||
@@ -814,7 +778,7 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
course_key = CCXLocator.from_course_locator(course.id, ccx.id)
|
||||
outbox = self.get_outbox()
|
||||
CourseEnrollmentAllowed(course_id=course_key, email=identifier)
|
||||
self.assertEqual(outbox, [])
|
||||
assert outbox == []
|
||||
|
||||
url = reverse(
|
||||
view_name,
|
||||
@@ -827,16 +791,12 @@ class TestCoachDashboard(CcxTestCase, LoginEnrollmentTestCase):
|
||||
if send_email:
|
||||
data['email-students'] = 'Notify-students-by-email'
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# we were redirected to our current location
|
||||
self.assertEqual(len(response.redirect_chain), 1)
|
||||
self.assertIn(302, response.redirect_chain[0])
|
||||
self.assertEqual(len(outbox), outbox_count)
|
||||
self.assertFalse(
|
||||
CourseEnrollmentAllowed.objects.filter(
|
||||
course_id=course_key, email=identifier
|
||||
).exists()
|
||||
)
|
||||
assert len(response.redirect_chain) == 1
|
||||
assert 302 in response.redirect_chain[0]
|
||||
assert len(outbox) == outbox_count
|
||||
assert not CourseEnrollmentAllowed.objects.filter(course_id=course_key, email=identifier).exists()
|
||||
|
||||
|
||||
class TestCoachDashboardSchedule(CcxTestCase, LoginEnrollmentTestCase, ModuleStoreTestCase):
|
||||
@@ -894,29 +854,29 @@ class TestCoachDashboardSchedule(CcxTestCase, LoginEnrollmentTestCase, ModuleSto
|
||||
# adding staff to master course.
|
||||
staff = UserFactory()
|
||||
allow_access(self.course, staff, 'staff')
|
||||
self.assertTrue(CourseStaffRole(self.course.id).has_user(staff))
|
||||
assert CourseStaffRole(self.course.id).has_user(staff)
|
||||
|
||||
# adding instructor to master course.
|
||||
instructor = UserFactory()
|
||||
allow_access(self.course, instructor, 'instructor')
|
||||
self.assertTrue(CourseInstructorRole(self.course.id).has_user(instructor))
|
||||
assert CourseInstructorRole(self.course.id).has_user(instructor)
|
||||
|
||||
self.assertTrue(modulestore().has_course(self.course.id))
|
||||
assert modulestore().has_course(self.course.id)
|
||||
|
||||
def assert_elements_in_schedule(self, url, n_chapters=2, n_sequentials=4, n_verticals=8):
|
||||
"""
|
||||
Helper function to count visible elements in the schedule
|
||||
"""
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# the schedule contains chapters
|
||||
chapters = json.loads(response.mako_context['schedule'])
|
||||
sequentials = flatten([chapter.get('children', []) for chapter in chapters])
|
||||
verticals = flatten([sequential.get('children', []) for sequential in sequentials])
|
||||
# check that the numbers of nodes at different level are the expected ones
|
||||
self.assertEqual(n_chapters, len(chapters))
|
||||
self.assertEqual(n_sequentials, len(sequentials))
|
||||
self.assertEqual(n_verticals, len(verticals))
|
||||
assert n_chapters == len(chapters)
|
||||
assert n_sequentials == len(sequentials)
|
||||
assert n_verticals == len(verticals)
|
||||
# extract the locations of all the nodes
|
||||
all_elements = chapters + sequentials + verticals
|
||||
return [elem['location'] for elem in all_elements if 'location' in elem]
|
||||
@@ -953,17 +913,17 @@ class TestCoachDashboardSchedule(CcxTestCase, LoginEnrollmentTestCase, ModuleSto
|
||||
vertical = self.verticals[0]
|
||||
self.hide_node(vertical)
|
||||
locations = self.assert_elements_in_schedule(url, n_verticals=7)
|
||||
self.assertNotIn(six.text_type(vertical.location), locations)
|
||||
assert six.text_type(vertical.location) not in locations
|
||||
# hide a sequential
|
||||
sequential = self.sequentials[0]
|
||||
self.hide_node(sequential)
|
||||
locations = self.assert_elements_in_schedule(url, n_sequentials=3, n_verticals=6)
|
||||
self.assertNotIn(six.text_type(sequential.location), locations)
|
||||
assert six.text_type(sequential.location) not in locations
|
||||
# hide a chapter
|
||||
chapter = self.chapters[0]
|
||||
self.hide_node(chapter)
|
||||
locations = self.assert_elements_in_schedule(url, n_chapters=1, n_sequentials=2, n_verticals=4)
|
||||
self.assertNotIn(six.text_type(chapter.location), locations)
|
||||
assert six.text_type(chapter.location) not in locations
|
||||
|
||||
|
||||
GET_CHILDREN = XModuleMixin.get_children
|
||||
@@ -1080,13 +1040,13 @@ class TestCCXGrades(FieldOverrideTestMixin, SharedModuleStoreTestCase, LoginEnro
|
||||
kwargs={'course_id': self.ccx_key}
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# Max number of student per page is one. Patched setting MAX_STUDENTS_PER_PAGE_GRADE_BOOK = 1
|
||||
self.assertEqual(len(response.mako_context['students']), 1)
|
||||
assert len(response.mako_context['students']) == 1
|
||||
student_info = response.mako_context['students'][0]
|
||||
self.assertEqual(student_info['grade_summary']['percent'], 0.5)
|
||||
self.assertEqual(list(student_info['grade_summary']['grade_breakdown'].values())[0]['percent'], 0.5)
|
||||
self.assertEqual(len(student_info['grade_summary']['section_breakdown']), 4)
|
||||
assert student_info['grade_summary']['percent'] == 0.5
|
||||
assert list(student_info['grade_summary']['grade_breakdown'].values())[0]['percent'] == 0.5
|
||||
assert len(student_info['grade_summary']['section_breakdown']) == 4
|
||||
|
||||
def test_grades_csv(self):
|
||||
self.course.enable_ccx = True
|
||||
@@ -1097,21 +1057,18 @@ class TestCCXGrades(FieldOverrideTestMixin, SharedModuleStoreTestCase, LoginEnro
|
||||
kwargs={'course_id': self.ccx_key}
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
# Are the grades downloaded as an attachment?
|
||||
self.assertEqual(
|
||||
response['content-disposition'],
|
||||
'attachment'
|
||||
)
|
||||
assert response['content-disposition'] == 'attachment'
|
||||
rows = response.content.decode('utf-8').strip().split('\r')
|
||||
headers = rows[0]
|
||||
# picking first student records
|
||||
data = dict(list(zip(headers.strip().split(','), rows[1].strip().split(','))))
|
||||
self.assertNotIn('HW 04', data)
|
||||
self.assertEqual(data['HW 01'], '0.75')
|
||||
self.assertEqual(data['HW 02'], '0.5')
|
||||
self.assertEqual(data['HW 03'], '0.25')
|
||||
self.assertEqual(data['HW Avg'], '0.5')
|
||||
assert 'HW 04' not in data
|
||||
assert data['HW 01'] == '0.75'
|
||||
assert data['HW 02'] == '0.5'
|
||||
assert data['HW 03'] == '0.25'
|
||||
assert data['HW Avg'] == '0.5'
|
||||
|
||||
@patch('lms.djangoapps.courseware.views.views.render_to_response', intercept_renderer)
|
||||
def test_student_progress(self):
|
||||
@@ -1127,11 +1084,11 @@ class TestCCXGrades(FieldOverrideTestMixin, SharedModuleStoreTestCase, LoginEnro
|
||||
kwargs={'course_id': self.ccx_key}
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
grades = response.mako_context['grade_summary']
|
||||
self.assertEqual(grades['percent'], 0.5)
|
||||
self.assertEqual(list(grades['grade_breakdown'].values())[0]['percent'], 0.5)
|
||||
self.assertEqual(len(grades['section_breakdown']), 4)
|
||||
assert grades['percent'] == 0.5
|
||||
assert list(grades['grade_breakdown'].values())[0]['percent'] == 0.5
|
||||
assert len(grades['section_breakdown']) == 4
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -1172,17 +1129,14 @@ class CCXCoachTabTestCase(CcxTestCase):
|
||||
"""
|
||||
with self.settings(FEATURES={'CUSTOM_COURSES_EDX': ccx_feature_flag}):
|
||||
course = self.ccx_enabled_course if enable_ccx else self.ccx_disabled_course
|
||||
self.assertEqual(
|
||||
expected_result,
|
||||
self.check_ccx_tab(course, self.user)
|
||||
)
|
||||
assert expected_result == self.check_ccx_tab(course, self.user)
|
||||
|
||||
def test_ccx_tab_visibility_for_staff_when_not_coach_master_course(self):
|
||||
"""
|
||||
Staff cannot view ccx coach dashboard on master course by default.
|
||||
"""
|
||||
staff = self.make_staff()
|
||||
self.assertFalse(self.check_ccx_tab(self.course, staff))
|
||||
assert not self.check_ccx_tab(self.course, staff)
|
||||
|
||||
def test_ccx_tab_visibility_for_staff_when_coach_master_course(self):
|
||||
"""
|
||||
@@ -1191,7 +1145,7 @@ class CCXCoachTabTestCase(CcxTestCase):
|
||||
staff = self.make_staff()
|
||||
role = CourseCcxCoachRole(self.course.id)
|
||||
role.add_users(staff)
|
||||
self.assertTrue(self.check_ccx_tab(self.course, staff))
|
||||
assert self.check_ccx_tab(self.course, staff)
|
||||
|
||||
def test_ccx_tab_visibility_for_staff_ccx_course(self):
|
||||
"""
|
||||
@@ -1204,14 +1158,14 @@ class CCXCoachTabTestCase(CcxTestCase):
|
||||
|
||||
with ccx_course(ccx_key) as course_ccx:
|
||||
allow_access(course_ccx, staff, 'staff')
|
||||
self.assertTrue(self.check_ccx_tab(course_ccx, staff))
|
||||
assert self.check_ccx_tab(course_ccx, staff)
|
||||
|
||||
def test_ccx_tab_visibility_for_instructor_when_not_coach_master_course(self):
|
||||
"""
|
||||
Instructor cannot view ccx coach dashboard on master course by default.
|
||||
"""
|
||||
instructor = self.make_instructor()
|
||||
self.assertFalse(self.check_ccx_tab(self.course, instructor))
|
||||
assert not self.check_ccx_tab(self.course, instructor)
|
||||
|
||||
def test_ccx_tab_visibility_for_instructor_when_coach_master_course(self):
|
||||
"""
|
||||
@@ -1220,7 +1174,7 @@ class CCXCoachTabTestCase(CcxTestCase):
|
||||
instructor = self.make_instructor()
|
||||
role = CourseCcxCoachRole(self.course.id)
|
||||
role.add_users(instructor)
|
||||
self.assertTrue(self.check_ccx_tab(self.course, instructor))
|
||||
assert self.check_ccx_tab(self.course, instructor)
|
||||
|
||||
def test_ccx_tab_visibility_for_instructor_ccx_course(self):
|
||||
"""
|
||||
@@ -1233,7 +1187,7 @@ class CCXCoachTabTestCase(CcxTestCase):
|
||||
|
||||
with ccx_course(ccx_key) as course_ccx:
|
||||
allow_access(course_ccx, instructor, 'instructor')
|
||||
self.assertTrue(self.check_ccx_tab(course_ccx, instructor))
|
||||
assert self.check_ccx_tab(course_ccx, instructor)
|
||||
|
||||
|
||||
class TestStudentViewsWithCCX(ModuleStoreTestCase):
|
||||
@@ -1271,10 +1225,10 @@ class TestStudentViewsWithCCX(ModuleStoreTestCase):
|
||||
def test_load_student_dashboard(self):
|
||||
self.client.login(username=self.student.username, password=self.student_password)
|
||||
response = self.client.get(reverse('dashboard'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(re.search('Test CCX', response.content.decode('utf-8')))
|
||||
assert response.status_code == 200
|
||||
assert re.search('Test CCX', response.content.decode('utf-8'))
|
||||
|
||||
def test_load_courseware(self):
|
||||
self.client.login(username=self.student.username, password=self.student_password)
|
||||
response = self.client.get(reverse('courseware', kwargs={'course_id': six.text_type(self.ccx_course_key)}))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
|
||||
Reference in New Issue
Block a user