replaced unittest assertions pytest assertions (#26540)

This commit is contained in:
Aarif
2021-02-18 19:13:47 +05:00
committed by GitHub
parent 874436b720
commit f35ff6a1eb
26 changed files with 827 additions and 955 deletions

View File

@@ -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):
"""

View File

@@ -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': {

View File

@@ -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)

View File

@@ -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

View File

@@ -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.

View File

@@ -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):

View File

@@ -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']

View File

@@ -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() == {}

View File

@@ -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()

View File

@@ -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')

View File

@@ -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())

View File

@@ -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):

View File

@@ -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'):

View File

@@ -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()

View File

@@ -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("&lt;script&gt;alert(&#39;Course Title!&#39;);&lt;/alert&gt;", message)
self.assertIn("&lt;script&gt;alert(&#39;Profile Name!&#39;);&lt;/alert&gt;", message)
assert '<script>' not in message
assert '&lt;script&gt;alert(&#39;Course Title!&#39;);&lt;/alert&gt;' in message
assert '&lt;script&gt;alert(&#39;Profile Name!&#39;);&lt;/alert&gt;' 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("&lt;script&gt;", message)
self.assertIn(context['course_title'], message)
self.assertIn(context['name'], message)
assert '&lt;script&gt;' 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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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