Files
edx-platform/lms/djangoapps/badges/api/tests.py
2017-06-11 21:48:06 -04:00

227 lines
9.2 KiB
Python

"""
Tests for the badges API views.
"""
from ddt import data, ddt, unpack
from django.conf import settings
from django.test.utils import override_settings
from nose.plugins.attrib import attr
from badges.tests.factories import BadgeAssertionFactory, BadgeClassFactory, RandomBadgeClassFactory
from openedx.core.lib.api.test_utils import ApiTestCase
from student.tests.factories import UserFactory
from util.testing import UrlResetMixin
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
FEATURES_WITH_BADGES_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_BADGES_ENABLED['ENABLE_OPENBADGES'] = True
@override_settings(FEATURES=FEATURES_WITH_BADGES_ENABLED)
class UserAssertionTestCase(UrlResetMixin, ModuleStoreTestCase, ApiTestCase):
"""
Mixin for badge API tests.
"""
def setUp(self, *args, **kwargs):
super(UserAssertionTestCase, self).setUp(*args, **kwargs)
self.course = CourseFactory.create()
self.user = UserFactory.create()
# Password defined by factory.
self.client.login(username=self.user.username, password='test')
def url(self):
"""
Return the URL to look up the current user's assertions.
"""
return '/api/badges/v1/assertions/user/{}/'.format(self.user.username)
def check_class_structure(self, badge_class, json_class):
"""
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 unicode(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'])
self.check_class_structure(assertion.badge_class, json_assertion['badge_class'])
def get_course_id(self, wildcard, badge_class):
"""
Used for tests which may need to test for a course_id or a wildcard.
"""
if wildcard:
return '*'
else:
return unicode(badge_class.course_id)
def create_badge_class(self, check_course, **kwargs):
"""
Create a badge class, using a course id if it's relevant to the URL pattern.
"""
if check_course:
return RandomBadgeClassFactory.create(course_id=self.course.location.course_key, **kwargs)
return RandomBadgeClassFactory.create(**kwargs)
def get_qs_args(self, check_course, wildcard, badge_class):
"""
Get a dictionary to be serialized into querystring params based on class settings.
"""
qs_args = {
'issuing_component': badge_class.issuing_component,
'slug': badge_class.slug,
}
if check_course:
qs_args['course_id'] = self.get_course_id(wildcard, badge_class)
return qs_args
class TestUserBadgeAssertions(UserAssertionTestCase):
"""
Test the general badge assertions retrieval view.
"""
def test_get_assertions(self):
"""
Verify we can get all of a user's badge assertions.
"""
for dummy in range(3):
BadgeAssertionFactory(user=self.user)
# Add in a course scoped badge-- these should not be excluded from the full listing.
BadgeAssertionFactory(user=self.user, badge_class=BadgeClassFactory(course_id=self.course.location.course_key))
# Should not be included.
for dummy in range(3):
self.create_badge_class(False)
response = self.get_json(self.url())
# pylint: disable=no-member
self.assertEqual(len(response['results']), 4)
def test_assertion_structure(self):
badge_class = self.create_badge_class(False)
assertion = BadgeAssertionFactory.create(user=self.user, badge_class=badge_class)
response = self.get_json(self.url())
# pylint: disable=no-member
self.check_assertion_structure(assertion, response['results'][0])
class TestUserCourseBadgeAssertions(UserAssertionTestCase):
"""
Test the Badge Assertions view with the course_id filter.
"""
def test_get_assertions(self):
"""
Verify we can get assertions via the course_id and username.
"""
course_key = self.course.location.course_key
badge_class = BadgeClassFactory.create(course_id=course_key)
for dummy in range(3):
BadgeAssertionFactory.create(user=self.user, badge_class=badge_class)
# Should not be included, as they don't share the target badge class.
for dummy in range(3):
BadgeAssertionFactory.create(user=self.user)
# Also should not be included, as they don't share the same user.
for dummy in range(6):
BadgeAssertionFactory.create(badge_class=badge_class)
response = self.get_json(self.url(), data={'course_id': course_key})
# pylint: disable=no-member
self.assertEqual(len(response['results']), 3)
unused_course = CourseFactory.create()
response = self.get_json(self.url(), data={'course_id': unused_course.location.course_key})
# pylint: disable=no-member
self.assertEqual(len(response['results']), 0)
def test_assertion_structure(self):
"""
Verify the badge assertion structure is as expected when a course is involved.
"""
course_key = self.course.location.course_key
badge_class = BadgeClassFactory.create(course_id=course_key)
assertion = BadgeAssertionFactory.create(badge_class=badge_class, user=self.user)
response = self.get_json(self.url())
# pylint: disable=no-member
self.check_assertion_structure(assertion, response['results'][0])
@attr(shard=3)
@ddt
class TestUserBadgeAssertionsByClass(UserAssertionTestCase):
"""
Test the Badge Assertions view with the badge class filter.
"""
@unpack
@data((False, False), (True, False), (True, True))
def test_get_assertions(self, check_course, wildcard):
"""
Verify we can get assertions via the badge class and username.
"""
badge_class = self.create_badge_class(check_course)
for dummy in range(3):
BadgeAssertionFactory.create(user=self.user, badge_class=badge_class)
if badge_class.course_id:
# Also create a version of this badge under a different course.
alt_class = BadgeClassFactory.create(
slug=badge_class.slug, issuing_component=badge_class.issuing_component,
course_id=CourseFactory.create().location.course_key
)
BadgeAssertionFactory.create(user=self.user, badge_class=alt_class)
# Same badge class, but different user. Should not show up in the list.
for dummy in range(5):
BadgeAssertionFactory.create(badge_class=badge_class)
# Different badge class AND different user. Certainly shouldn't show up in the list!
for dummy in range(6):
BadgeAssertionFactory.create()
response = self.get_json(
self.url(),
data=self.get_qs_args(check_course, wildcard, badge_class),
)
if wildcard:
expected_length = 4
else:
expected_length = 3
# pylint: disable=no-member
self.assertEqual(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),
)
# pylint: disable=no-member
self.assertEqual(len(response['results']), 0)
def check_badge_class_assertion(self, check_course, wildcard, badge_class):
"""
Given a badge class, create an assertion for the current user and fetch it, checking the structure.
"""
assertion = BadgeAssertionFactory.create(badge_class=badge_class, user=self.user)
response = self.get_json(
self.url(),
data=self.get_qs_args(check_course, wildcard, badge_class),
)
# pylint: disable=no-member
self.check_assertion_structure(assertion, response['results'][0])
@unpack
@data((False, False), (True, False), (True, True))
def test_assertion_structure(self, check_course, wildcard):
self.check_badge_class_assertion(check_course, wildcard, self.create_badge_class(check_course))
@unpack
@data((False, False), (True, False), (True, True))
def test_empty_issuing_component(self, check_course, wildcard):
self.check_badge_class_assertion(
check_course, wildcard, self.create_badge_class(check_course, issuing_component='')
)