Files
edx-platform/lms/djangoapps/lms_xblock/test/test_runtime.py
Amit b8b910d132 INCR-460: Make compatible with Python 3.x and disable: import-error f… (#20989)
* INCR-460: Make compatible with Python 3.x and disable: import-error for urlparse

* INCR-460: Fixes for useless suppression
2019-07-16 14:28:03 -04:00

290 lines
11 KiB
Python

"""
Tests of the LMS XBlock Runtime and associated utilities
"""
from __future__ import absolute_import
from ddt import data, ddt
from django.conf import settings
from django.test import TestCase
from mock import Mock, patch
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locations import BlockUsageLocator, CourseLocator
from six.moves.urllib.parse import urlparse # pylint: disable=import-error
from xblock.exceptions import NoSuchServiceError
from xblock.fields import ScopeIds
from badges.tests.factories import BadgeClassFactory
from badges.tests.test_models import get_image
from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem
from student.tests.factories import UserFactory
from xmodule.modulestore.django import ModuleI18nService
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
class BlockMock(Mock):
"""Mock class that we fill with our "handler" methods."""
def handler(self, _context):
"""
A test handler method.
"""
pass
def handler1(self, _context):
"""
A test handler method.
"""
pass
def handler_a(self, _context):
"""
A test handler method.
"""
pass
@property
def location(self):
"""Create a functional BlockUsageLocator for testing URL generation."""
course_key = CourseLocator(org="mockx", course="100", run="2015")
return BlockUsageLocator(course_key, block_type='mock_type', block_id="mock_id")
class TestHandlerUrl(TestCase):
"""Test the LMS handler_url"""
def setUp(self):
super(TestHandlerUrl, self).setUp()
self.block = BlockMock(name='block', scope_ids=ScopeIds(None, None, None, 'dummy'))
self.course_key = CourseLocator("org", "course", "run")
self.runtime = LmsModuleSystem(
static_url='/static',
track_function=Mock(),
get_module=Mock(),
render_template=Mock(),
replace_urls=str,
course_id=self.course_key,
descriptor_runtime=Mock(),
)
def test_trailing_characters(self):
self.assertFalse(self.runtime.handler_url(self.block, 'handler').endswith('?'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler').endswith('/'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler', 'suffix').endswith('?'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler', 'suffix').endswith('/'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler', 'suffix', 'query').endswith('?'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler', 'suffix', 'query').endswith('/'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler', query='query').endswith('?'))
self.assertFalse(self.runtime.handler_url(self.block, 'handler', query='query').endswith('/'))
def _parsed_query(self, query_string):
"""Return the parsed query string from a handler_url generated with the supplied query_string"""
return urlparse(self.runtime.handler_url(self.block, 'handler', query=query_string)).query
def test_query_string(self):
self.assertIn('foo=bar', self._parsed_query('foo=bar'))
self.assertIn('foo=bar&baz=true', self._parsed_query('foo=bar&baz=true'))
self.assertIn('foo&bar&baz', self._parsed_query('foo&bar&baz'))
def _parsed_path(self, handler_name='handler', suffix=''):
"""Return the parsed path from a handler_url with the supplied handler_name and suffix"""
return urlparse(self.runtime.handler_url(self.block, handler_name, suffix=suffix)).path
def test_suffix(self):
self.assertTrue(self._parsed_path(suffix="foo").endswith('foo'))
self.assertTrue(self._parsed_path(suffix="foo/bar").endswith('foo/bar'))
self.assertTrue(self._parsed_path(suffix="/foo/bar").endswith('/foo/bar'))
def test_handler_name(self):
self.assertIn('handler1', self._parsed_path('handler1'))
self.assertIn('handler_a', self._parsed_path('handler_a'))
def test_thirdparty_fq(self):
"""Testing the Fully-Qualified URL returned by thirdparty=True"""
parsed_fq_url = urlparse(self.runtime.handler_url(self.block, 'handler', thirdparty=True))
self.assertEqual(parsed_fq_url.scheme, 'https')
self.assertEqual(parsed_fq_url.hostname, settings.SITE_NAME)
def test_not_thirdparty_rel(self):
"""Testing the Fully-Qualified URL returned by thirdparty=False"""
parsed_fq_url = urlparse(self.runtime.handler_url(self.block, 'handler', thirdparty=False))
self.assertEqual(parsed_fq_url.scheme, '')
self.assertIsNone(parsed_fq_url.hostname)
class TestUserServiceAPI(TestCase):
"""Test the user service interface"""
def setUp(self):
super(TestUserServiceAPI, self).setUp()
self.course_id = CourseLocator("org", "course", "run")
self.user = UserFactory.create()
def mock_get_real_user(_anon_id):
"""Just returns the test user"""
return self.user
self.runtime = LmsModuleSystem(
static_url='/static',
track_function=Mock(),
get_module=Mock(),
render_template=Mock(),
replace_urls=str,
course_id=self.course_id,
get_real_user=mock_get_real_user,
descriptor_runtime=Mock(),
)
self.scope = 'course'
self.key = 'key1'
self.mock_block = Mock()
self.mock_block.service_declaration.return_value = 'needs'
def test_get_set_tag(self):
# test for when we haven't set the tag yet
tag = self.runtime.service(self.mock_block, 'user_tags').get_tag(self.scope, self.key)
self.assertIsNone(tag)
# set the tag
set_value = 'value'
self.runtime.service(self.mock_block, 'user_tags').set_tag(self.scope, self.key, set_value)
tag = self.runtime.service(self.mock_block, 'user_tags').get_tag(self.scope, self.key)
self.assertEqual(tag, set_value)
# Try to set tag in wrong scope
with self.assertRaises(ValueError):
self.runtime.service(self.mock_block, 'user_tags').set_tag('fake_scope', self.key, set_value)
# Try to get tag in wrong scope
with self.assertRaises(ValueError):
self.runtime.service(self.mock_block, 'user_tags').get_tag('fake_scope', self.key)
@ddt
class TestBadgingService(ModuleStoreTestCase):
"""Test the badging service interface"""
def setUp(self):
super(TestBadgingService, self).setUp()
self.course_id = CourseKey.from_string('course-v1:org+course+run')
self.mock_block = Mock()
self.mock_block.service_declaration.return_value = 'needs'
def create_runtime(self):
"""
Create the testing runtime.
"""
def mock_get_real_user(_anon_id):
"""Just returns the test user"""
return self.user
return LmsModuleSystem(
static_url='/static',
track_function=Mock(),
get_module=Mock(),
render_template=Mock(),
replace_urls=str,
course_id=self.course_id,
get_real_user=mock_get_real_user,
descriptor_runtime=Mock(),
)
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
def test_service_rendered(self):
runtime = self.create_runtime()
self.assertTrue(runtime.service(self.mock_block, 'badging'))
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': False})
def test_no_service_rendered(self):
runtime = self.create_runtime()
self.assertFalse(runtime.service(self.mock_block, 'badging'))
@data(True, False)
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
def test_course_badges_toggle(self, toggle):
self.course_id = CourseFactory.create(metadata={'issue_badges': toggle}).location.course_key
runtime = self.create_runtime()
self.assertIs(runtime.service(self.mock_block, 'badging').course_badges_enabled, toggle)
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
def test_get_badge_class(self):
runtime = self.create_runtime()
badge_service = runtime.service(self.mock_block, 'badging')
premade_badge_class = BadgeClassFactory.create()
# Ignore additional parameters. This class already exists.
# We should get back the first class we created, rather than a new one.
badge_class = badge_service.get_badge_class(
slug='test_slug', issuing_component='test_component', description='Attempted override',
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.")
# File name won't always be the same.
self.assertEqual(badge_class.image.path, premade_badge_class.image.path)
class TestI18nService(ModuleStoreTestCase):
""" Test ModuleI18nService """
def setUp(self):
""" Setting up tests """
super(TestI18nService, self).setUp()
self.course = CourseFactory.create()
self.test_language = 'dummy language'
self.runtime = LmsModuleSystem(
static_url='/static',
track_function=Mock(),
get_module=Mock(),
render_template=Mock(),
replace_urls=str,
course_id=self.course.id,
descriptor_runtime=Mock(),
)
self.mock_block = Mock()
self.mock_block.service_declaration.return_value = 'need'
def test_module_i18n_lms_service(self):
"""
Test: module i18n service in LMS
"""
i18n_service = self.runtime.service(self.mock_block, 'i18n')
self.assertIsNotNone(i18n_service)
self.assertIsInstance(i18n_service, ModuleI18nService)
def test_no_service_exception_with_none_declaration_(self):
"""
Test: NoSuchServiceError should be raised block declaration returns none
"""
self.mock_block.service_declaration.return_value = None
with self.assertRaises(NoSuchServiceError):
self.runtime.service(self.mock_block, 'i18n')
def test_no_service_exception_(self):
"""
Test: NoSuchServiceError should be raised if i18n service is none.
"""
self.runtime._services['i18n'] = None # pylint: disable=protected-access
with self.assertRaises(NoSuchServiceError):
self.runtime.service(self.mock_block, 'i18n')
def test_i18n_service_callable(self):
"""
Test: _services dict should contain the callable i18n service in LMS.
"""
self.assertTrue(callable(self.runtime._services.get('i18n'))) # pylint: disable=protected-access
def test_i18n_service_not_callable(self):
"""
Test: i18n service should not be callable in LMS after initialization.
"""
self.assertFalse(callable(self.runtime.service(self.mock_block, 'i18n')))