refactor: rename module -> block within xmodule
This commit is contained in:
@@ -42,7 +42,7 @@ def mock_render_template(*args, **kwargs):
|
||||
|
||||
class StubMakoService:
|
||||
"""
|
||||
Stub MakoService for testing modules that use mako templates.
|
||||
Stub MakoService for testing blocks that use mako templates.
|
||||
"""
|
||||
|
||||
def __init__(self, render_template=None):
|
||||
@@ -57,7 +57,7 @@ class StubMakoService:
|
||||
|
||||
class StubUserService(UserService):
|
||||
"""
|
||||
Stub UserService for testing the sequence module.
|
||||
Stub UserService for testing the sequence block.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
@@ -101,7 +101,7 @@ class StubUserService(UserService):
|
||||
|
||||
class StubReplaceURLService:
|
||||
"""
|
||||
Stub ReplaceURLService for testing modules.
|
||||
Stub ReplaceURLService for testing blocks.
|
||||
"""
|
||||
|
||||
def replace_urls(self, text, static_replace_only=False):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Module annotatable tests"""
|
||||
"""Annotatable block tests"""
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
@@ -42,7 +42,7 @@ from . import get_test_system
|
||||
|
||||
class CapaFactory:
|
||||
"""
|
||||
A helper class to create problem modules with various parameters for testing.
|
||||
A helper class to create problem blocks with various parameters for testing.
|
||||
"""
|
||||
|
||||
sample_problem_xml = textwrap.dedent("""\
|
||||
@@ -93,8 +93,7 @@ class CapaFactory:
|
||||
force_save_button:
|
||||
rerandomize: all strings, as specified in the policy for the problem
|
||||
|
||||
problem_state: a dict to to be serialized into the instance_state of the
|
||||
module.
|
||||
problem_state: a dict to be serialized into the instance_state of the block.
|
||||
|
||||
attempts: also added to instance state. Will be converted to an int.
|
||||
|
||||
@@ -122,23 +121,23 @@ class CapaFactory:
|
||||
user_is_staff=kwargs.get('user_is_staff', False),
|
||||
render_template=render_template or Mock(return_value="<div>Test Template HTML</div>"),
|
||||
)
|
||||
module = ProblemBlock(
|
||||
block = ProblemBlock(
|
||||
system,
|
||||
DictFieldData(field_data),
|
||||
ScopeIds(None, 'problem', location, location),
|
||||
)
|
||||
assert module.lcp
|
||||
assert block.lcp
|
||||
|
||||
if override_get_score:
|
||||
if correct:
|
||||
# TODO: probably better to actually set the internal state properly, but...
|
||||
module.score = Score(raw_earned=1, raw_possible=1)
|
||||
block.score = Score(raw_earned=1, raw_possible=1)
|
||||
else:
|
||||
module.score = Score(raw_earned=0, raw_possible=1)
|
||||
block.score = Score(raw_earned=0, raw_possible=1)
|
||||
|
||||
module.graded = 'False'
|
||||
module.weight = 1
|
||||
return module
|
||||
block.graded = 'False'
|
||||
block.weight = 1
|
||||
return block
|
||||
|
||||
|
||||
class CapaFactoryWithFiles(CapaFactory):
|
||||
@@ -198,22 +197,22 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
self.two_day_delta_str = "2 days"
|
||||
|
||||
def test_import(self):
|
||||
module = CapaFactory.create()
|
||||
assert module.get_score().raw_earned == 0
|
||||
block = CapaFactory.create()
|
||||
assert block.get_score().raw_earned == 0
|
||||
|
||||
other_module = CapaFactory.create()
|
||||
assert module.get_score().raw_earned == 0
|
||||
assert module.url_name != other_module.url_name, 'Factory should be creating unique names for each problem'
|
||||
other_block = CapaFactory.create()
|
||||
assert block.get_score().raw_earned == 0
|
||||
assert block.url_name != other_block.url_name, 'Factory should be creating unique names for each problem'
|
||||
|
||||
def test_correct(self):
|
||||
"""
|
||||
Check that the factory creates correct and incorrect problems properly.
|
||||
"""
|
||||
module = CapaFactory.create()
|
||||
assert module.get_score().raw_earned == 0
|
||||
block = CapaFactory.create()
|
||||
assert block.get_score().raw_earned == 0
|
||||
|
||||
other_module = CapaFactory.create(correct=True)
|
||||
assert other_module.get_score().raw_earned == 1
|
||||
other_block = CapaFactory.create(correct=True)
|
||||
assert other_block.get_score().raw_earned == 1
|
||||
|
||||
def test_get_score(self):
|
||||
"""
|
||||
@@ -223,20 +222,20 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
student_answers = {'1_2_1': 'abcd'}
|
||||
correct_map = CorrectMap(answer_id='1_2_1', correctness="correct", npoints=0.9)
|
||||
module = CapaFactory.create(correct=True, override_get_score=False)
|
||||
module.lcp.correct_map = correct_map
|
||||
module.lcp.student_answers = student_answers
|
||||
assert module.get_score().raw_earned == 0.0
|
||||
module.set_score(module.score_from_lcp(module.lcp))
|
||||
assert module.get_score().raw_earned == 0.9
|
||||
block = CapaFactory.create(correct=True, override_get_score=False)
|
||||
block.lcp.correct_map = correct_map
|
||||
block.lcp.student_answers = student_answers
|
||||
assert block.get_score().raw_earned == 0.0
|
||||
block.set_score(block.score_from_lcp(block.lcp))
|
||||
assert block.get_score().raw_earned == 0.9
|
||||
|
||||
other_correct_map = CorrectMap(answer_id='1_2_1', correctness="incorrect", npoints=0.1)
|
||||
other_module = CapaFactory.create(correct=False, override_get_score=False)
|
||||
other_module.lcp.correct_map = other_correct_map
|
||||
other_module.lcp.student_answers = student_answers
|
||||
assert other_module.get_score().raw_earned == 0.0
|
||||
other_module.set_score(other_module.score_from_lcp(other_module.lcp))
|
||||
assert other_module.get_score().raw_earned == 0.1
|
||||
other_block = CapaFactory.create(correct=False, override_get_score=False)
|
||||
other_block.lcp.correct_map = other_correct_map
|
||||
other_block.lcp.student_answers = student_answers
|
||||
assert other_block.get_score().raw_earned == 0.0
|
||||
other_block.set_score(other_block.score_from_lcp(other_block.lcp))
|
||||
assert other_block.get_score().raw_earned == 0.1
|
||||
|
||||
def test_showanswer_default(self):
|
||||
"""
|
||||
@@ -625,29 +624,29 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
def test_closed(self):
|
||||
|
||||
# Attempts < Max attempts --> NOT closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="0")
|
||||
assert not module.closed()
|
||||
block = CapaFactory.create(max_attempts="1", attempts="0")
|
||||
assert not block.closed()
|
||||
|
||||
# Attempts < Max attempts --> NOT closed
|
||||
module = CapaFactory.create(max_attempts="2", attempts="1")
|
||||
assert not module.closed()
|
||||
block = CapaFactory.create(max_attempts="2", attempts="1")
|
||||
assert not block.closed()
|
||||
|
||||
# Attempts = Max attempts --> closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="1")
|
||||
assert module.closed()
|
||||
block = CapaFactory.create(max_attempts="1", attempts="1")
|
||||
assert block.closed()
|
||||
|
||||
# Attempts > Max attempts --> closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="2")
|
||||
assert module.closed()
|
||||
block = CapaFactory.create(max_attempts="1", attempts="2")
|
||||
assert block.closed()
|
||||
|
||||
# Max attempts = 0 --> closed
|
||||
module = CapaFactory.create(max_attempts="0", attempts="2")
|
||||
assert module.closed()
|
||||
block = CapaFactory.create(max_attempts="0", attempts="2")
|
||||
assert block.closed()
|
||||
|
||||
# Past due --> closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="0",
|
||||
due=self.yesterday_str)
|
||||
assert module.closed()
|
||||
block = CapaFactory.create(max_attempts="1", attempts="0",
|
||||
due=self.yesterday_str)
|
||||
assert block.closed()
|
||||
|
||||
def test_parse_get_params(self):
|
||||
|
||||
@@ -699,7 +698,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
def test_submit_problem_correct(self):
|
||||
|
||||
module = CapaFactory.create(attempts=1)
|
||||
block = CapaFactory.create(attempts=1)
|
||||
|
||||
# Simulate that all answers are marked correct, no matter
|
||||
# what the input is, by patching CorrectMap.is_correct()
|
||||
@@ -711,7 +710,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem is marked correct
|
||||
assert result['success'] == 'correct'
|
||||
@@ -720,13 +719,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
assert result['contents'] == 'Test HTML'
|
||||
|
||||
# Expect that the number of attempts is incremented by 1
|
||||
assert module.attempts == 2
|
||||
assert block.attempts == 2
|
||||
# and that this was considered attempt number 2 for grading purposes
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
assert block.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_incorrect(self):
|
||||
|
||||
module = CapaFactory.create(attempts=0)
|
||||
block = CapaFactory.create(attempts=0)
|
||||
|
||||
# Simulate marking the input incorrect
|
||||
with patch('xmodule.capa.correctmap.CorrectMap.is_correct') as mock_is_correct:
|
||||
@@ -734,18 +733,18 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '0'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem is marked correct
|
||||
assert result['success'] == 'incorrect'
|
||||
|
||||
# Expect that the number of attempts is incremented by 1
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# and that this is considered the first attempt
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_submit_problem_closed(self):
|
||||
module = CapaFactory.create(attempts=3)
|
||||
block = CapaFactory.create(attempts=3)
|
||||
|
||||
# Problem closed -- cannot submit
|
||||
# Simulate that ProblemBlock.closed() always returns True
|
||||
@@ -753,10 +752,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
mock_closed.return_value = True
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that number of attempts NOT incremented
|
||||
assert module.attempts == 3
|
||||
assert block.attempts == 3
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.ALWAYS,
|
||||
@@ -764,18 +763,18 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
)
|
||||
def test_submit_problem_resubmitted_with_randomize(self, rerandomize):
|
||||
# Randomize turned on
|
||||
module = CapaFactory.create(rerandomize=rerandomize, attempts=0)
|
||||
block = CapaFactory.create(rerandomize=rerandomize, attempts=0)
|
||||
|
||||
# Simulate that the problem is completed
|
||||
module.done = True
|
||||
block.done = True
|
||||
|
||||
# Expect that we cannot submit
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that number of attempts NOT incremented
|
||||
assert module.attempts == 0
|
||||
assert block.attempts == 0
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.NEVER,
|
||||
@@ -784,20 +783,20 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
)
|
||||
def test_submit_problem_resubmitted_no_randomize(self, rerandomize):
|
||||
# Randomize turned off
|
||||
module = CapaFactory.create(rerandomize=rerandomize, attempts=0, done=True)
|
||||
block = CapaFactory.create(rerandomize=rerandomize, attempts=0, done=True)
|
||||
|
||||
# Expect that we can submit successfully
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
assert result['success'] == 'correct'
|
||||
|
||||
# Expect that number of attempts IS incremented, still same attempt
|
||||
assert module.attempts == 1
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.attempts == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_submit_problem_queued(self):
|
||||
module = CapaFactory.create(attempts=1)
|
||||
block = CapaFactory.create(attempts=1)
|
||||
|
||||
# Simulate that the problem is queued
|
||||
multipatch = patch.multiple(
|
||||
@@ -810,13 +809,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
values['get_recentmost_queuetime'].return_value = datetime.datetime.now(UTC)
|
||||
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
assert 'You must wait' in result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
|
||||
@patch.object(XQueueInterface, '_http_post')
|
||||
def test_submit_problem_with_files(self, mock_xqueue_post):
|
||||
@@ -830,7 +829,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
for fileobj in fileobjs:
|
||||
self.addCleanup(fileobj.close)
|
||||
|
||||
module = CapaFactoryWithFiles.create()
|
||||
block = CapaFactoryWithFiles.create()
|
||||
|
||||
# Mock the XQueueInterface post method
|
||||
mock_xqueue_post.return_value = (0, "ok")
|
||||
@@ -841,7 +840,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
CapaFactoryWithFiles.input_key(response_num=3): 'None',
|
||||
}
|
||||
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
# _http_post is called like this:
|
||||
@@ -880,7 +879,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
for fileobj in fileobjs:
|
||||
self.addCleanup(fileobj.close)
|
||||
|
||||
module = CapaFactoryWithFiles.create()
|
||||
block = CapaFactoryWithFiles.create()
|
||||
|
||||
# Mock the XQueueInterface post method
|
||||
mock_xqueue_post.return_value = (0, "ok")
|
||||
@@ -892,7 +891,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
post_data.append((CapaFactoryWithFiles.input_key(response_num=3), 'None'))
|
||||
request = webob.Request.blank("/some/fake/url", POST=post_data, content_type='multipart/form-data')
|
||||
|
||||
module.handle('xmodule_handler', request, 'problem_check')
|
||||
block.handle('xmodule_handler', request, 'problem_check')
|
||||
|
||||
assert mock_xqueue_post.call_count == 1
|
||||
_, kwargs = mock_xqueue_post.call_args
|
||||
@@ -907,15 +906,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
LoncapaProblemError,
|
||||
ResponseError]
|
||||
for exception_class in exception_classes:
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
|
||||
# Simulate answering a problem that raises the exception
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade:
|
||||
mock_grade.side_effect = exception_class('test error')
|
||||
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
expected_msg = 'test error'
|
||||
@@ -923,9 +922,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
assert expected_msg == result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# but that this was considered attempt number 2 for grading purposes
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
assert block.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_error_with_codejail_exception(self):
|
||||
|
||||
@@ -935,8 +934,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
ResponseError]
|
||||
for exception_class in exception_classes:
|
||||
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
|
||||
# Simulate a codejail exception "Exception: Couldn't execute jailed code"
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade:
|
||||
@@ -951,16 +950,16 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
except ResponseError as err:
|
||||
mock_grade.side_effect = exception_class(str(err))
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success' without the text of the stack trace
|
||||
expected_msg = 'Couldn\'t execute jailed code'
|
||||
assert expected_msg == result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# but that this was considered the second attempt for grading purposes
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
assert block.lcp.context['attempt'] == 2
|
||||
|
||||
@override_settings(DEBUG=True)
|
||||
def test_submit_problem_other_errors(self):
|
||||
@@ -969,8 +968,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
See also `test_submit_problem_error` for the "expected kinds" or errors.
|
||||
"""
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
|
||||
# Simulate answering a problem that raises the exception
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade:
|
||||
@@ -978,7 +977,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
mock_grade.side_effect = Exception(error_msg)
|
||||
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
assert error_msg in result['success']
|
||||
@@ -987,15 +986,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
Test that a capa problem with a max grade of zero doesn't generate an error.
|
||||
"""
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1)
|
||||
|
||||
# Override the problem score to have a total of zero.
|
||||
module.lcp.get_score = lambda: {'score': 0, 'total': 0}
|
||||
block.lcp.get_score = lambda: {'score': 0, 'total': 0}
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
|
||||
def test_submit_problem_error_nonascii(self):
|
||||
|
||||
@@ -1004,15 +1003,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
LoncapaProblemError,
|
||||
ResponseError]
|
||||
for exception_class in exception_classes:
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1, user_is_staff=False)
|
||||
|
||||
# Simulate answering a problem that raises the exception
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade:
|
||||
mock_grade.side_effect = exception_class("ȧƈƈḗƞŧḗḓ ŧḗẋŧ ƒǿř ŧḗşŧīƞɠ")
|
||||
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
expected_msg = 'ȧƈƈḗƞŧḗḓ ŧḗẋŧ ƒǿř ŧḗşŧīƞɠ'
|
||||
@@ -1020,9 +1019,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
assert expected_msg == result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# but that this was considered the second attempt for grading purposes
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
assert block.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_error_with_staff_user(self):
|
||||
|
||||
@@ -1030,15 +1029,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
for exception_class in [StudentInputError,
|
||||
LoncapaProblemError,
|
||||
ResponseError]:
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1, user_is_staff=True)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1, user_is_staff=True)
|
||||
|
||||
# Simulate answering a problem that raises an exception
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.grade_answers') as mock_grade:
|
||||
mock_grade.side_effect = exception_class('test error')
|
||||
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
assert 'test error' in result['success']
|
||||
@@ -1047,9 +1046,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
assert 'Traceback' in result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# but that it was considered the second attempt for grading purposes
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
assert block.lcp.context['attempt'] == 2
|
||||
|
||||
@ddt.data(
|
||||
("never", True, None, 'submitted'),
|
||||
@@ -1061,9 +1060,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_handle_ajax_show_correctness(self, show_correctness, is_correct, expected_score, expected_success):
|
||||
module = CapaFactory.create(show_correctness=show_correctness,
|
||||
due=self.tomorrow_str,
|
||||
correct=is_correct)
|
||||
block = CapaFactory.create(show_correctness=show_correctness,
|
||||
due=self.tomorrow_str,
|
||||
correct=is_correct)
|
||||
|
||||
# Simulate marking the input correct/incorrect
|
||||
with patch('xmodule.capa.correctmap.CorrectMap.is_correct') as mock_is_correct:
|
||||
@@ -1071,7 +1070,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '0'}
|
||||
json_result = module.handle_ajax('problem_check', get_request_dict)
|
||||
json_result = block.handle_ajax('problem_check', get_request_dict)
|
||||
result = json.loads(json_result)
|
||||
|
||||
# Expect that the AJAX result withholds correctness and score
|
||||
@@ -1079,13 +1078,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
assert result['success'] == expected_success
|
||||
|
||||
# Expect that the number of attempts is incremented by 1
|
||||
assert module.attempts == 1
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.attempts == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_reset_problem(self):
|
||||
module = CapaFactory.create(done=True)
|
||||
module.new_lcp = Mock(wraps=module.new_lcp)
|
||||
module.choose_new_seed = Mock(wraps=module.choose_new_seed)
|
||||
block = CapaFactory.create(done=True)
|
||||
block.new_lcp = Mock(wraps=block.new_lcp)
|
||||
block.choose_new_seed = Mock(wraps=block.choose_new_seed)
|
||||
|
||||
# Stub out HTML rendering
|
||||
with patch('xmodule.capa_block.ProblemBlock.get_problem_html') as mock_html:
|
||||
@@ -1093,7 +1092,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Reset the problem
|
||||
get_request_dict = {}
|
||||
result = module.reset_problem(get_request_dict)
|
||||
result = block.reset_problem(get_request_dict)
|
||||
|
||||
# Expect that the request was successful
|
||||
assert (('success' in result) and result['success'])
|
||||
@@ -1103,11 +1102,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
assert result['html'] == '<div>Test HTML</div>'
|
||||
|
||||
# Expect that the problem was reset
|
||||
module.new_lcp.assert_called_once_with(None)
|
||||
block.new_lcp.assert_called_once_with(None)
|
||||
|
||||
def test_reset_problem_closed(self):
|
||||
# pre studio default
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS)
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS)
|
||||
|
||||
# Simulate that the problem is closed
|
||||
with patch('xmodule.capa_block.ProblemBlock.closed') as mock_closed:
|
||||
@@ -1115,25 +1114,25 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Try to reset the problem
|
||||
get_request_dict = {}
|
||||
result = module.reset_problem(get_request_dict)
|
||||
result = block.reset_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem was NOT reset
|
||||
assert (('success' in result) and (not result['success']))
|
||||
|
||||
def test_reset_problem_not_done(self):
|
||||
# Simulate that the problem is NOT done
|
||||
module = CapaFactory.create(done=False)
|
||||
block = CapaFactory.create(done=False)
|
||||
|
||||
# Try to reset the problem
|
||||
get_request_dict = {}
|
||||
result = module.reset_problem(get_request_dict)
|
||||
result = block.reset_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem was NOT reset
|
||||
assert (('success' in result) and (not result['success']))
|
||||
|
||||
def test_rescore_problem_correct(self):
|
||||
|
||||
module = CapaFactory.create(attempts=0, done=True)
|
||||
block = CapaFactory.create(attempts=0, done=True)
|
||||
|
||||
# Simulate that all answers are marked correct, no matter
|
||||
# what the input is, by patching LoncapaResponse.evaluate_answers()
|
||||
@@ -1148,91 +1147,91 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '1'}
|
||||
module.submit_problem(get_request_dict)
|
||||
module.rescore(only_if_higher=False)
|
||||
block.submit_problem(get_request_dict)
|
||||
block.rescore(only_if_higher=False)
|
||||
|
||||
# Expect that the problem is marked correct
|
||||
assert module.is_correct() is True
|
||||
assert block.is_correct() is True
|
||||
|
||||
# Expect that the number of attempts is not incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# and that this was considered attempt number 1 for grading purposes
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_additional_correct(self):
|
||||
# make sure it also works when new correct answer has been added
|
||||
module = CapaFactory.create(attempts=0)
|
||||
block = CapaFactory.create(attempts=0)
|
||||
answer_id = CapaFactory.answer_key()
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '1'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem is marked incorrect and user didn't earn score
|
||||
assert result['success'] == 'incorrect'
|
||||
assert module.get_score() == (0, 1)
|
||||
assert module.correct_map[answer_id]['correctness'] == 'incorrect'
|
||||
assert block.get_score() == (0, 1)
|
||||
assert block.correct_map[answer_id]['correctness'] == 'incorrect'
|
||||
|
||||
# Expect that the number of attempts has incremented to 1
|
||||
assert module.attempts == 1
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.attempts == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
# Simulate that after making an incorrect answer to the correct answer
|
||||
# the new calculated score is (1,1)
|
||||
# by patching CorrectMap.is_correct() and NumericalResponse.get_staff_ans()
|
||||
# In case of rescore with only_if_higher=True it should update score of module
|
||||
# In case of rescore with only_if_higher=True it should update score of block
|
||||
# if previous score was lower
|
||||
|
||||
with patch('xmodule.capa.correctmap.CorrectMap.is_correct') as mock_is_correct:
|
||||
mock_is_correct.return_value = True
|
||||
module.set_score(module.score_from_lcp(module.lcp))
|
||||
block.set_score(block.score_from_lcp(block.lcp))
|
||||
with patch('xmodule.capa.responsetypes.NumericalResponse.get_staff_ans') as get_staff_ans:
|
||||
get_staff_ans.return_value = 1 + 0j
|
||||
module.rescore(only_if_higher=True)
|
||||
block.rescore(only_if_higher=True)
|
||||
|
||||
# Expect that the problem is marked correct and user earned the score
|
||||
assert module.get_score() == (1, 1)
|
||||
assert module.correct_map[answer_id]['correctness'] == 'correct'
|
||||
assert block.get_score() == (1, 1)
|
||||
assert block.correct_map[answer_id]['correctness'] == 'correct'
|
||||
# Expect that the number of attempts is not incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# and hence that this was still considered the first attempt for grading purposes
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_incorrect(self):
|
||||
# make sure it also works when attempts have been reset,
|
||||
# so add this to the test:
|
||||
module = CapaFactory.create(attempts=0, done=True)
|
||||
block = CapaFactory.create(attempts=0, done=True)
|
||||
|
||||
# Simulate that all answers are marked incorrect, no matter
|
||||
# what the input is, by patching LoncapaResponse.evaluate_answers()
|
||||
with patch('xmodule.capa.responsetypes.LoncapaResponse.evaluate_answers') as mock_evaluate_answers:
|
||||
mock_evaluate_answers.return_value = CorrectMap(CapaFactory.answer_key(), 'incorrect')
|
||||
module.rescore(only_if_higher=False)
|
||||
block.rescore(only_if_higher=False)
|
||||
|
||||
# Expect that the problem is marked incorrect
|
||||
assert module.is_correct() is False
|
||||
assert block.is_correct() is False
|
||||
|
||||
# Expect that the number of attempts is not incremented
|
||||
assert module.attempts == 0
|
||||
assert block.attempts == 0
|
||||
# and that this is treated as the first attempt for grading purposes
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_not_done(self):
|
||||
# Simulate that the problem is NOT done
|
||||
module = CapaFactory.create(done=False)
|
||||
block = CapaFactory.create(done=False)
|
||||
|
||||
# Try to rescore the problem, and get exception
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
module.rescore(only_if_higher=False)
|
||||
block.rescore(only_if_higher=False)
|
||||
|
||||
def test_rescore_problem_not_supported(self):
|
||||
module = CapaFactory.create(done=True)
|
||||
block = CapaFactory.create(done=True)
|
||||
|
||||
# Try to rescore the problem, and get exception
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.supports_rescoring') as mock_supports_rescoring:
|
||||
mock_supports_rescoring.return_value = False
|
||||
with pytest.raises(NotImplementedError):
|
||||
module.rescore(only_if_higher=False)
|
||||
block.rescore(only_if_higher=False)
|
||||
|
||||
def capa_factory_for_problem_xml(self, xml): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
class CustomCapaFactory(CapaFactory):
|
||||
@@ -1261,19 +1260,19 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
def _rescore_problem_error_helper(self, exception_class):
|
||||
"""Helper to allow testing all errors that rescoring might return."""
|
||||
# Create the module
|
||||
module = CapaFactory.create(attempts=1, done=True)
|
||||
# Create the block
|
||||
block = CapaFactory.create(attempts=1, done=True)
|
||||
|
||||
# Simulate answering a problem that raises the exception
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.get_grade_from_current_answers') as mock_rescore:
|
||||
mock_rescore.side_effect = exception_class('test error \u03a9')
|
||||
with pytest.raises(exception_class):
|
||||
module.rescore(only_if_higher=False)
|
||||
block.rescore(only_if_higher=False)
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
assert module.attempts == 1
|
||||
assert block.attempts == 1
|
||||
# and that this was considered the first attempt for grading purposes
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
assert block.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_student_input_error(self):
|
||||
self._rescore_problem_error_helper(StudentInputError)
|
||||
@@ -1285,21 +1284,21 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
self._rescore_problem_error_helper(ResponseError)
|
||||
|
||||
def test_save_problem(self):
|
||||
module = CapaFactory.create(done=False)
|
||||
block = CapaFactory.create(done=False)
|
||||
|
||||
# Save the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.save_problem(get_request_dict)
|
||||
result = block.save_problem(get_request_dict)
|
||||
|
||||
# Expect that answers are saved to the problem
|
||||
expected_answers = {CapaFactory.answer_key(): '3.14'}
|
||||
assert module.lcp.student_answers == expected_answers
|
||||
assert block.lcp.student_answers == expected_answers
|
||||
|
||||
# Expect that the result is success
|
||||
assert (('success' in result) and result['success'])
|
||||
|
||||
def test_save_problem_closed(self):
|
||||
module = CapaFactory.create(done=False)
|
||||
block = CapaFactory.create(done=False)
|
||||
|
||||
# Simulate that the problem is closed
|
||||
with patch('xmodule.capa_block.ProblemBlock.closed') as mock_closed:
|
||||
@@ -1307,7 +1306,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Try to save the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.save_problem(get_request_dict)
|
||||
result = block.save_problem(get_request_dict)
|
||||
|
||||
# Expect that the result is failure
|
||||
assert (('success' in result) and (not result['success']))
|
||||
@@ -1318,11 +1317,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
)
|
||||
def test_save_problem_submitted_with_randomize(self, rerandomize):
|
||||
# Capa XModule treats 'always' and 'true' equivalently
|
||||
module = CapaFactory.create(rerandomize=rerandomize, done=True)
|
||||
block = CapaFactory.create(rerandomize=rerandomize, done=True)
|
||||
|
||||
# Try to save
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.save_problem(get_request_dict)
|
||||
result = block.save_problem(get_request_dict)
|
||||
|
||||
# Expect that we cannot save
|
||||
assert (('success' in result) and (not result['success']))
|
||||
@@ -1333,198 +1332,198 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
RANDOMIZATION.PER_STUDENT
|
||||
)
|
||||
def test_save_problem_submitted_no_randomize(self, rerandomize):
|
||||
# Capa XModule treats 'false' and 'per_student' equivalently
|
||||
module = CapaFactory.create(rerandomize=rerandomize, done=True)
|
||||
# Capa XBlock treats 'false' and 'per_student' equivalently
|
||||
block = CapaFactory.create(rerandomize=rerandomize, done=True)
|
||||
|
||||
# Try to save
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.save_problem(get_request_dict)
|
||||
result = block.save_problem(get_request_dict)
|
||||
|
||||
# Expect that we succeed
|
||||
assert (('success' in result) and result['success'])
|
||||
|
||||
def test_submit_button_name(self):
|
||||
module = CapaFactory.create(attempts=0)
|
||||
assert module.submit_button_name() == 'Submit'
|
||||
block = CapaFactory.create(attempts=0)
|
||||
assert block.submit_button_name() == 'Submit'
|
||||
|
||||
def test_submit_button_submitting_name(self):
|
||||
module = CapaFactory.create(attempts=1, max_attempts=10)
|
||||
assert module.submit_button_submitting_name() == 'Submitting'
|
||||
block = CapaFactory.create(attempts=1, max_attempts=10)
|
||||
assert block.submit_button_submitting_name() == 'Submitting'
|
||||
|
||||
def test_should_enable_submit_button(self):
|
||||
|
||||
attempts = random.randint(1, 10)
|
||||
|
||||
# If we're after the deadline, disable the submit button
|
||||
module = CapaFactory.create(due=self.yesterday_str)
|
||||
assert not module.should_enable_submit_button()
|
||||
block = CapaFactory.create(due=self.yesterday_str)
|
||||
assert not block.should_enable_submit_button()
|
||||
|
||||
# If user is out of attempts, disable the submit button
|
||||
module = CapaFactory.create(attempts=attempts, max_attempts=attempts)
|
||||
assert not module.should_enable_submit_button()
|
||||
block = CapaFactory.create(attempts=attempts, max_attempts=attempts)
|
||||
assert not block.should_enable_submit_button()
|
||||
|
||||
# If survey question (max_attempts = 0), disable the submit button
|
||||
module = CapaFactory.create(max_attempts=0)
|
||||
assert not module.should_enable_submit_button()
|
||||
block = CapaFactory.create(max_attempts=0)
|
||||
assert not block.should_enable_submit_button()
|
||||
|
||||
# If user submitted a problem but hasn't reset,
|
||||
# disable the submit button
|
||||
# Note: we can only reset when rerandomize="always" or "true"
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
assert not module.should_enable_submit_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
assert not block.should_enable_submit_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="true", done=True)
|
||||
assert not module.should_enable_submit_button()
|
||||
block = CapaFactory.create(rerandomize="true", done=True)
|
||||
assert not block.should_enable_submit_button()
|
||||
|
||||
# Otherwise, enable the submit button
|
||||
module = CapaFactory.create()
|
||||
assert module.should_enable_submit_button()
|
||||
block = CapaFactory.create()
|
||||
assert block.should_enable_submit_button()
|
||||
|
||||
# If the user has submitted the problem
|
||||
# and we do NOT have a reset button, then we can enable the submit button
|
||||
# Setting rerandomize to "never" or "false" ensures that the reset button
|
||||
# is not shown
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, done=True)
|
||||
assert module.should_enable_submit_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, done=True)
|
||||
assert block.should_enable_submit_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="false", done=True)
|
||||
assert module.should_enable_submit_button()
|
||||
block = CapaFactory.create(rerandomize="false", done=True)
|
||||
assert block.should_enable_submit_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.PER_STUDENT, done=True)
|
||||
assert module.should_enable_submit_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.PER_STUDENT, done=True)
|
||||
assert block.should_enable_submit_button()
|
||||
|
||||
def test_should_show_reset_button(self):
|
||||
|
||||
attempts = random.randint(1, 10)
|
||||
|
||||
# If we're after the deadline, do NOT show the reset button
|
||||
module = CapaFactory.create(due=self.yesterday_str, done=True)
|
||||
assert not module.should_show_reset_button()
|
||||
block = CapaFactory.create(due=self.yesterday_str, done=True)
|
||||
assert not block.should_show_reset_button()
|
||||
|
||||
# If the user is out of attempts, do NOT show the reset button
|
||||
module = CapaFactory.create(attempts=attempts, max_attempts=attempts, done=True)
|
||||
assert not module.should_show_reset_button()
|
||||
block = CapaFactory.create(attempts=attempts, max_attempts=attempts, done=True)
|
||||
assert not block.should_show_reset_button()
|
||||
|
||||
# pre studio default value, DO show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
assert module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
assert block.should_show_reset_button()
|
||||
|
||||
# If survey question for capa (max_attempts = 0),
|
||||
# DO show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True)
|
||||
assert module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True)
|
||||
assert block.should_show_reset_button()
|
||||
|
||||
# If the question is not correct
|
||||
# DO show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True, correct=False)
|
||||
assert module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True, correct=False)
|
||||
assert block.should_show_reset_button()
|
||||
|
||||
# If the question is correct and randomization is never
|
||||
# DO not show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, max_attempts=0, done=True, correct=True)
|
||||
assert not module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, max_attempts=0, done=True, correct=True)
|
||||
assert not block.should_show_reset_button()
|
||||
|
||||
# If the question is correct and randomization is always
|
||||
# Show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True, correct=True)
|
||||
assert module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True, correct=True)
|
||||
assert block.should_show_reset_button()
|
||||
|
||||
# Don't show reset button if randomization is turned on and the question is not done
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, show_reset_button=False, done=False)
|
||||
assert not module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, show_reset_button=False, done=False)
|
||||
assert not block.should_show_reset_button()
|
||||
|
||||
# Show reset button if randomization is turned on and the problem is done
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, show_reset_button=False, done=True)
|
||||
assert module.should_show_reset_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, show_reset_button=False, done=True)
|
||||
assert block.should_show_reset_button()
|
||||
|
||||
def test_should_show_save_button(self):
|
||||
|
||||
attempts = random.randint(1, 10)
|
||||
|
||||
# If we're after the deadline, do NOT show the save button
|
||||
module = CapaFactory.create(due=self.yesterday_str, done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(due=self.yesterday_str, done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
# If the user is out of attempts, do NOT show the save button
|
||||
module = CapaFactory.create(attempts=attempts, max_attempts=attempts, done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(attempts=attempts, max_attempts=attempts, done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
# If user submitted a problem but hasn't reset, do NOT show the save button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="true", done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(rerandomize="true", done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
# If the user has unlimited attempts and we are not randomizing,
|
||||
# then do NOT show a save button
|
||||
# because they can keep using "Check"
|
||||
module = CapaFactory.create(max_attempts=None, rerandomize=RANDOMIZATION.NEVER, done=False)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(max_attempts=None, rerandomize=RANDOMIZATION.NEVER, done=False)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(max_attempts=None, rerandomize="false", done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(max_attempts=None, rerandomize="false", done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(max_attempts=None, rerandomize=RANDOMIZATION.PER_STUDENT, done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(max_attempts=None, rerandomize=RANDOMIZATION.PER_STUDENT, done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
# pre-studio default, DO show the save button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=False)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=False)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
# If we're not randomizing and we have limited attempts, then we can save
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, max_attempts=2, done=True)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, max_attempts=2, done=True)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="false", max_attempts=2, done=True)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(rerandomize="false", max_attempts=2, done=True)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.PER_STUDENT, max_attempts=2, done=True)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(rerandomize=RANDOMIZATION.PER_STUDENT, max_attempts=2, done=True)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
# If survey question for capa (max_attempts = 0),
|
||||
# DO show the save button
|
||||
module = CapaFactory.create(max_attempts=0, done=False)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(max_attempts=0, done=False)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
def test_should_show_save_button_force_save_button(self):
|
||||
# If we're after the deadline, do NOT show the save button
|
||||
# even though we're forcing a save
|
||||
module = CapaFactory.create(due=self.yesterday_str,
|
||||
force_save_button="true",
|
||||
done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(due=self.yesterday_str,
|
||||
force_save_button="true",
|
||||
done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
# If the user is out of attempts, do NOT show the save button
|
||||
attempts = random.randint(1, 10)
|
||||
module = CapaFactory.create(attempts=attempts,
|
||||
max_attempts=attempts,
|
||||
force_save_button="true",
|
||||
done=True)
|
||||
assert not module.should_show_save_button()
|
||||
block = CapaFactory.create(attempts=attempts,
|
||||
max_attempts=attempts,
|
||||
force_save_button="true",
|
||||
done=True)
|
||||
assert not block.should_show_save_button()
|
||||
|
||||
# Otherwise, if we force the save button,
|
||||
# then show it even if we would ordinarily
|
||||
# require a reset first
|
||||
module = CapaFactory.create(force_save_button="true",
|
||||
rerandomize=RANDOMIZATION.ALWAYS,
|
||||
done=True)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(force_save_button="true",
|
||||
rerandomize=RANDOMIZATION.ALWAYS,
|
||||
done=True)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(force_save_button="true",
|
||||
rerandomize="true",
|
||||
done=True)
|
||||
assert module.should_show_save_button()
|
||||
block = CapaFactory.create(force_save_button="true",
|
||||
rerandomize="true",
|
||||
done=True)
|
||||
assert block.should_show_save_button()
|
||||
|
||||
def test_no_max_attempts(self):
|
||||
module = CapaFactory.create(max_attempts='')
|
||||
html = module.get_problem_html()
|
||||
block = CapaFactory.create(max_attempts='')
|
||||
html = block.get_problem_html()
|
||||
assert html is not None
|
||||
# assert that we got here without exploding
|
||||
|
||||
def test_get_problem_html(self):
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(render_template=render_template)
|
||||
block = CapaFactory.create(render_template=render_template)
|
||||
|
||||
# We've tested the show/hide button logic in other tests,
|
||||
# so here we hard-wire the values
|
||||
@@ -1532,19 +1531,19 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
show_reset_button = bool(random.randint(0, 1) % 2)
|
||||
show_save_button = bool(random.randint(0, 1) % 2)
|
||||
|
||||
module.should_enable_submit_button = Mock(return_value=enable_submit_button)
|
||||
module.should_show_reset_button = Mock(return_value=show_reset_button)
|
||||
module.should_show_save_button = Mock(return_value=show_save_button)
|
||||
block.should_enable_submit_button = Mock(return_value=enable_submit_button)
|
||||
block.should_show_reset_button = Mock(return_value=show_reset_button)
|
||||
block.should_show_save_button = Mock(return_value=show_save_button)
|
||||
|
||||
# Patch the capa problem's HTML rendering
|
||||
with patch('xmodule.capa.capa_problem.LoncapaProblem.get_html') as mock_html:
|
||||
mock_html.return_value = "<div>Test Problem HTML</div>"
|
||||
|
||||
# Render the problem HTML
|
||||
html = module.get_problem_html(encapsulate=False)
|
||||
html = block.get_problem_html(encapsulate=False)
|
||||
|
||||
# Also render the problem encapsulated in a <div>
|
||||
html_encapsulated = module.get_problem_html(encapsulate=True)
|
||||
html_encapsulated = block.get_problem_html(encapsulate=True)
|
||||
|
||||
# Expect that we get the rendered template back
|
||||
assert html == '<div>Test Template HTML</div>'
|
||||
@@ -1586,22 +1585,22 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# HTML generation is mocked out to be meaningless here, so instead we check
|
||||
# the context dict passed into HTML generation.
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(xml=self.demand_xml, render_template=render_template)
|
||||
module.get_problem_html() # ignoring html result
|
||||
block = CapaFactory.create(xml=self.demand_xml, render_template=render_template)
|
||||
block.get_problem_html() # ignoring html result
|
||||
context = render_template.call_args[0][1]
|
||||
assert context['demand_hint_possible']
|
||||
assert context['should_enable_next_hint']
|
||||
|
||||
# Check the AJAX call that gets the hint by index
|
||||
result = module.get_demand_hint(0)
|
||||
result = block.get_demand_hint(0)
|
||||
assert result['hint_index'] == 0
|
||||
assert result['should_enable_next_hint']
|
||||
|
||||
result = module.get_demand_hint(1)
|
||||
result = block.get_demand_hint(1)
|
||||
assert result['hint_index'] == 1
|
||||
assert not result['should_enable_next_hint']
|
||||
|
||||
result = module.get_demand_hint(2) # here the server wraps around to index 0
|
||||
result = block.get_demand_hint(2) # here the server wraps around to index 0
|
||||
assert result['hint_index'] == 0
|
||||
assert result['should_enable_next_hint']
|
||||
|
||||
@@ -1624,14 +1623,14 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
</demandhint>
|
||||
</problem>"""
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(xml=test_xml, render_template=render_template)
|
||||
module.get_problem_html() # ignoring html result
|
||||
block = CapaFactory.create(xml=test_xml, render_template=render_template)
|
||||
block.get_problem_html() # ignoring html result
|
||||
context = render_template.call_args[0][1]
|
||||
assert context['demand_hint_possible']
|
||||
assert context['should_enable_next_hint']
|
||||
|
||||
# Check the AJAX call that gets the hint by index
|
||||
result = module.get_demand_hint(0)
|
||||
result = block.get_demand_hint(0)
|
||||
assert result['hint_index'] == 0
|
||||
assert not result['should_enable_next_hint']
|
||||
|
||||
@@ -1656,14 +1655,14 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
</demandhint>
|
||||
</problem>"""
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(xml=test_xml, render_template=render_template)
|
||||
module.get_problem_html() # ignoring html result
|
||||
block = CapaFactory.create(xml=test_xml, render_template=render_template)
|
||||
block.get_problem_html() # ignoring html result
|
||||
context = render_template.call_args[0][1]
|
||||
assert context['demand_hint_possible']
|
||||
assert context['should_enable_next_hint']
|
||||
|
||||
# Check the AJAX call that gets the hint by index
|
||||
result = module.get_demand_hint(0)
|
||||
result = block.get_demand_hint(0)
|
||||
assert result['hint_index'] == 0
|
||||
assert not result['should_enable_next_hint']
|
||||
|
||||
@@ -1671,27 +1670,27 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
Test calling get_demand_hunt() results in an event being published.
|
||||
"""
|
||||
module = CapaFactory.create(xml=self.demand_xml)
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
module.get_problem_html()
|
||||
module.get_demand_hint(0)
|
||||
block = CapaFactory.create(xml=self.demand_xml)
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
block.get_problem_html()
|
||||
block.get_demand_hint(0)
|
||||
mock_publish.assert_called_with(
|
||||
module, 'edx.problem.hint.demandhint_displayed',
|
||||
{'hint_index': 0, 'module_id': str(module.location),
|
||||
block, 'edx.problem.hint.demandhint_displayed',
|
||||
{'hint_index': 0, 'module_id': str(block.location),
|
||||
'hint_text': 'Demand 1', 'hint_len': 2}
|
||||
)
|
||||
|
||||
def test_input_state_consistency(self):
|
||||
module1 = CapaFactory.create()
|
||||
module2 = CapaFactory.create()
|
||||
block1 = CapaFactory.create()
|
||||
block2 = CapaFactory.create()
|
||||
|
||||
# check to make sure that the input_state and the keys have the same values
|
||||
module1.set_state_from_lcp()
|
||||
assert list(module1.lcp.inputs.keys()) == list(module1.input_state.keys())
|
||||
block1.set_state_from_lcp()
|
||||
assert list(block1.lcp.inputs.keys()) == list(block1.input_state.keys())
|
||||
|
||||
module2.set_state_from_lcp()
|
||||
block2.set_state_from_lcp()
|
||||
|
||||
intersection = set(module2.input_state.keys()).intersection(set(module1.input_state.keys()))
|
||||
intersection = set(block2.input_state.keys()).intersection(set(block1.input_state.keys()))
|
||||
assert len(intersection) == 0
|
||||
|
||||
def test_get_problem_html_error(self):
|
||||
@@ -1701,17 +1700,17 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
message to display to the user.
|
||||
"""
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(render_template=render_template)
|
||||
block = CapaFactory.create(render_template=render_template)
|
||||
|
||||
# Save the original problem so we can compare it later
|
||||
original_problem = module.lcp
|
||||
original_problem = block.lcp
|
||||
|
||||
# Simulate throwing an exception when the capa problem
|
||||
# is asked to render itself as HTML
|
||||
module.lcp.get_html = Mock(side_effect=Exception("Test"))
|
||||
block.lcp.get_html = Mock(side_effect=Exception("Test"))
|
||||
|
||||
# Try to render the module with DEBUG turned off
|
||||
html = module.get_problem_html()
|
||||
# Try to render the block with DEBUG turned off
|
||||
html = block.get_problem_html()
|
||||
|
||||
assert html is not None
|
||||
|
||||
@@ -1720,25 +1719,25 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
context = render_args[1]
|
||||
assert 'error' in context['problem']['html']
|
||||
|
||||
# Expect that the module has created a new dummy problem with the error
|
||||
assert original_problem != module.lcp
|
||||
# Expect that the block has created a new dummy problem with the error
|
||||
assert original_problem != block.lcp
|
||||
|
||||
def test_get_problem_html_error_preview(self):
|
||||
"""
|
||||
Test the html response when an error occurs with DEBUG off in Studio.
|
||||
"""
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(render_template=render_template)
|
||||
block = CapaFactory.create(render_template=render_template)
|
||||
|
||||
# Simulate throwing an exception when the capa problem
|
||||
# is asked to render itself as HTML
|
||||
error_msg = "Superterrible error happened: ☠"
|
||||
module.lcp.get_html = Mock(side_effect=Exception(error_msg))
|
||||
block.lcp.get_html = Mock(side_effect=Exception(error_msg))
|
||||
|
||||
module.system.is_author_mode = True
|
||||
block.system.is_author_mode = True
|
||||
|
||||
# Try to render the module with the author mode turned on
|
||||
html = module.get_problem_html()
|
||||
# Try to render the block with the author mode turned on
|
||||
html = block.get_problem_html()
|
||||
|
||||
assert html is not None
|
||||
|
||||
@@ -1753,15 +1752,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Test the html response when an error occurs with DEBUG on
|
||||
"""
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(render_template=render_template)
|
||||
block = CapaFactory.create(render_template=render_template)
|
||||
|
||||
# Simulate throwing an exception when the capa problem
|
||||
# is asked to render itself as HTML
|
||||
error_msg = "Superterrible error happened: ☠"
|
||||
module.lcp.get_html = Mock(side_effect=Exception(error_msg))
|
||||
block.lcp.get_html = Mock(side_effect=Exception(error_msg))
|
||||
|
||||
# Try to render the module with DEBUG turned on
|
||||
html = module.get_problem_html()
|
||||
# Try to render the block with DEBUG turned on
|
||||
html = block.get_problem_html()
|
||||
|
||||
assert html is not None
|
||||
|
||||
@@ -1782,11 +1781,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Run the test for each possible rerandomize value
|
||||
|
||||
module = CapaFactory.create(rerandomize=rerandomize)
|
||||
block = CapaFactory.create(rerandomize=rerandomize)
|
||||
|
||||
# Get the seed
|
||||
# By this point, the module should have persisted the seed
|
||||
seed = module.seed
|
||||
# By this point, the block should have persisted the seed
|
||||
seed = block.seed
|
||||
assert seed is not None
|
||||
|
||||
# If we're not rerandomizing, the seed is always set
|
||||
@@ -1796,16 +1795,16 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the seed is the same
|
||||
assert seed == module.seed
|
||||
assert seed == block.seed
|
||||
|
||||
# Save the problem
|
||||
module.save_problem(get_request_dict)
|
||||
block.save_problem(get_request_dict)
|
||||
|
||||
# Expect that the seed is the same
|
||||
assert seed == module.seed
|
||||
assert seed == block.seed
|
||||
|
||||
@ddt.data(
|
||||
'false',
|
||||
@@ -1820,22 +1819,22 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Run the test for each possible rerandomize value
|
||||
"""
|
||||
|
||||
def _reset_and_get_seed(module):
|
||||
def _reset_and_get_seed(block):
|
||||
"""
|
||||
Reset the XModule and return the module's seed
|
||||
Reset the XBlock and return the block's seed
|
||||
"""
|
||||
|
||||
# Simulate submitting an attempt
|
||||
# We need to do this, or reset_problem() will
|
||||
# fail because it won't re-randomize until the problem has been submitted
|
||||
# the problem yet.
|
||||
module.done = True
|
||||
block.done = True
|
||||
|
||||
# Reset the problem
|
||||
module.reset_problem({})
|
||||
block.reset_problem({})
|
||||
|
||||
# Return the seed
|
||||
return module.seed
|
||||
return block.seed
|
||||
|
||||
def _retry_and_check(num_tries, test_func):
|
||||
'''
|
||||
@@ -1852,11 +1851,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
break
|
||||
return success
|
||||
|
||||
module = CapaFactory.create(rerandomize=rerandomize, done=True)
|
||||
block = CapaFactory.create(rerandomize=rerandomize, done=True)
|
||||
|
||||
# Get the seed
|
||||
# By this point, the module should have persisted the seed
|
||||
seed = module.seed
|
||||
# By this point, the block should have persisted the seed
|
||||
seed = block.seed
|
||||
assert seed is not None
|
||||
|
||||
# We do NOT want the seed to reset if rerandomize
|
||||
@@ -1866,7 +1865,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
if rerandomize in [RANDOMIZATION.NEVER,
|
||||
'false',
|
||||
RANDOMIZATION.PER_STUDENT]:
|
||||
assert seed == _reset_and_get_seed(module)
|
||||
assert seed == _reset_and_get_seed(block)
|
||||
|
||||
# Otherwise, we expect the seed to change
|
||||
# to another valid seed
|
||||
@@ -1875,9 +1874,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Since there's a small chance (expected) we might get the
|
||||
# same seed again, give it 10 chances
|
||||
# to generate a different seed
|
||||
success = _retry_and_check(10, lambda: _reset_and_get_seed(module) != seed)
|
||||
success = _retry_and_check(10, lambda: _reset_and_get_seed(block) != seed)
|
||||
|
||||
assert module.seed is not None
|
||||
assert block.seed is not None
|
||||
msg = 'Could not get a new seed from reset after 10 tries'
|
||||
assert success, msg
|
||||
|
||||
@@ -1894,27 +1893,27 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Run the test for each possible rerandomize value
|
||||
"""
|
||||
|
||||
def _reset_and_get_seed(module):
|
||||
def _reset_and_get_seed(block):
|
||||
"""
|
||||
Reset the XModule and return the module's seed
|
||||
Reset the XBlock and return the block's seed
|
||||
"""
|
||||
|
||||
# Reset the problem
|
||||
# By default, the problem is instantiated as unsubmitted
|
||||
module.reset_problem({})
|
||||
block.reset_problem({})
|
||||
|
||||
# Return the seed
|
||||
return module.seed
|
||||
return block.seed
|
||||
|
||||
module = CapaFactory.create(rerandomize=rerandomize, done=False)
|
||||
block = CapaFactory.create(rerandomize=rerandomize, done=False)
|
||||
|
||||
# Get the seed
|
||||
# By this point, the module should have persisted the seed
|
||||
seed = module.seed
|
||||
# By this point, the block should have persisted the seed
|
||||
seed = block.seed
|
||||
assert seed is not None
|
||||
|
||||
# the seed should never change because the student hasn't finished the problem
|
||||
assert seed == _reset_and_get_seed(module)
|
||||
assert seed == _reset_and_get_seed(block)
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.ALWAYS,
|
||||
@@ -1927,8 +1926,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Get a bunch of seeds, they should all be in 0-999.
|
||||
i = 200
|
||||
while i > 0:
|
||||
module = CapaFactory.create(rerandomize=rerandomize)
|
||||
assert 0 <= module.seed < 1000
|
||||
block = CapaFactory.create(rerandomize=rerandomize)
|
||||
assert 0 <= block.seed < 1000
|
||||
i -= 1
|
||||
|
||||
@patch('xmodule.capa_block.log')
|
||||
@@ -1940,8 +1939,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
error_types = [TypeError, ValueError]
|
||||
for error_type in error_types:
|
||||
mock_progress.side_effect = error_type
|
||||
module = CapaFactory.create()
|
||||
assert module.get_progress() is None
|
||||
block = CapaFactory.create()
|
||||
assert block.get_progress() is None
|
||||
mock_log.exception.assert_called_once_with('Got bad progress')
|
||||
mock_log.reset_mock()
|
||||
|
||||
@@ -1951,9 +1950,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Check that if the weight is 0 get_progress does not try to create a Progress object.
|
||||
"""
|
||||
mock_progress.return_value = True
|
||||
module = CapaFactory.create()
|
||||
module.weight = 0
|
||||
progress = module.get_progress()
|
||||
block = CapaFactory.create()
|
||||
block.weight = 0
|
||||
progress = block.get_progress()
|
||||
assert progress is None
|
||||
assert not mock_progress.called
|
||||
|
||||
@@ -1962,14 +1961,14 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
Check that score and total are calculated correctly for the progress fraction.
|
||||
"""
|
||||
module = CapaFactory.create()
|
||||
module.weight = 1
|
||||
module.get_progress()
|
||||
block = CapaFactory.create()
|
||||
block.weight = 1
|
||||
block.get_progress()
|
||||
mock_progress.assert_called_with(0, 1)
|
||||
|
||||
other_module = CapaFactory.create(correct=True)
|
||||
other_module.weight = 1
|
||||
other_module.get_progress()
|
||||
other_block = CapaFactory.create(correct=True)
|
||||
other_block.weight = 1
|
||||
other_block.get_progress()
|
||||
mock_progress.assert_called_with(1, 1)
|
||||
|
||||
@ddt.data(
|
||||
@@ -1985,11 +1984,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
Check that score and total are calculated correctly for the progress fraction.
|
||||
"""
|
||||
module = CapaFactory.create(correct=is_correct,
|
||||
show_correctness=show_correctness,
|
||||
due=self.tomorrow_str)
|
||||
module.weight = 1
|
||||
score, total = module.get_display_progress()
|
||||
block = CapaFactory.create(correct=is_correct,
|
||||
show_correctness=show_correctness,
|
||||
due=self.tomorrow_str)
|
||||
block.weight = 1
|
||||
score, total = block.get_display_progress()
|
||||
assert score == expected_score
|
||||
assert total == 1
|
||||
|
||||
@@ -1997,17 +1996,17 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
Check that get_html() calls get_progress() with no arguments.
|
||||
"""
|
||||
module = CapaFactory.create()
|
||||
module.get_progress = Mock(wraps=module.get_progress)
|
||||
module.get_html()
|
||||
module.get_progress.assert_called_with()
|
||||
block = CapaFactory.create()
|
||||
block.get_progress = Mock(wraps=block.get_progress)
|
||||
block.get_html()
|
||||
block.get_progress.assert_called_with()
|
||||
|
||||
def test_get_problem(self):
|
||||
"""
|
||||
Check that get_problem() returns the expected dictionary.
|
||||
"""
|
||||
module = CapaFactory.create()
|
||||
assert module.get_problem('data') == {'html': module.get_problem_html(encapsulate=False)}
|
||||
block = CapaFactory.create()
|
||||
assert block.get_problem('data') == {'html': block.get_problem_html(encapsulate=False)}
|
||||
|
||||
# Standard question with shuffle="true" used by a few tests
|
||||
common_shuffle_xml = textwrap.dedent("""
|
||||
@@ -2028,10 +2027,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Check that shuffle unmasking is plumbed through: when submit_problem is called,
|
||||
unmasked names should appear in the publish event_info.
|
||||
"""
|
||||
module = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
block = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
get_request_dict = {CapaFactory.input_key(): 'choice_3'} # the correct choice
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
mock_call = mock_publish.mock_calls[1]
|
||||
event_info = mock_call[1][2]
|
||||
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_3'
|
||||
@@ -2043,10 +2042,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
@unittest.skip("masking temporarily disabled")
|
||||
def test_save_unmask(self):
|
||||
"""On problem save, unmasked data should appear on publish."""
|
||||
module = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
block = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
get_request_dict = {CapaFactory.input_key(): 'mask_0'}
|
||||
module.save_problem(get_request_dict)
|
||||
block.save_problem(get_request_dict)
|
||||
mock_call = mock_publish.mock_calls[0]
|
||||
event_info = mock_call[1][1]
|
||||
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_2'
|
||||
@@ -2055,12 +2054,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
@unittest.skip("masking temporarily disabled")
|
||||
def test_reset_unmask(self):
|
||||
"""On problem reset, unmask names should appear publish."""
|
||||
module = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
block = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
get_request_dict = {CapaFactory.input_key(): 'mask_0'}
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
# On reset, 'old_state' should use unmasked names
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
module.reset_problem(None)
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
block.reset_problem(None)
|
||||
mock_call = mock_publish.mock_calls[0]
|
||||
event_info = mock_call[1][1]
|
||||
assert mock_call[1][0] == 'reset_problem'
|
||||
@@ -2070,12 +2069,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
@unittest.skip("masking temporarily disabled")
|
||||
def test_rescore_unmask(self):
|
||||
"""On problem rescore, unmasked names should appear on publish."""
|
||||
module = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
block = CapaFactory.create(xml=self.common_shuffle_xml)
|
||||
get_request_dict = {CapaFactory.input_key(): 'mask_0'}
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
# On rescore, state/student_answers should use unmasked names
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
module.rescore_problem(only_if_higher=False) # lint-amnesty, pylint: disable=no-member
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
block.rescore_problem(only_if_higher=False) # lint-amnesty, pylint: disable=no-member
|
||||
mock_call = mock_publish.mock_calls[0]
|
||||
event_info = mock_call[1][1]
|
||||
assert mock_call[1][0] == 'problem_rescore'
|
||||
@@ -2096,10 +2095,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
</multiplechoiceresponse>
|
||||
</problem>
|
||||
""")
|
||||
module = CapaFactory.create(xml=xml)
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
block = CapaFactory.create(xml=xml)
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
get_request_dict = {CapaFactory.input_key(): 'choice_2'} # mask_X form when masking enabled
|
||||
module.submit_problem(get_request_dict)
|
||||
block.submit_problem(get_request_dict)
|
||||
mock_call = mock_publish.mock_calls[1]
|
||||
event_info = mock_call[1][2]
|
||||
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_2'
|
||||
@@ -2119,8 +2118,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
"""
|
||||
Verify that display_name_with_default works as expected.
|
||||
"""
|
||||
module = CapaFactory.create(display_name=display_name)
|
||||
assert module.display_name_with_default == expected_display_name
|
||||
block = CapaFactory.create(display_name=display_name)
|
||||
assert block.display_name_with_default == expected_display_name
|
||||
|
||||
@ddt.data(
|
||||
'',
|
||||
@@ -2131,11 +2130,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Verify that if problem display name is not provided then a default name is used.
|
||||
"""
|
||||
render_template = Mock(return_value="<div>Test Template HTML</div>")
|
||||
module = CapaFactory.create(display_name=display_name, render_template=render_template)
|
||||
module.get_problem_html()
|
||||
block = CapaFactory.create(display_name=display_name, render_template=render_template)
|
||||
block.get_problem_html()
|
||||
render_args, _ = render_template.call_args
|
||||
context = render_args[1]
|
||||
assert context['problem']['name'] == module.location.block_type
|
||||
assert context['problem']['name'] == block.location.block_type
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -2941,14 +2940,14 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
# Whitespace screws up comparisons
|
||||
xml = ''.join(line.strip() for line in xml.split('\n'))
|
||||
factory = self.capa_factory_for_problem_xml(xml)
|
||||
module = factory.create()
|
||||
block = factory.create()
|
||||
|
||||
answer_input_dict = {
|
||||
factory.input_key(2): 'blue',
|
||||
factory.input_key(3): 'choice_0',
|
||||
factory.input_key(4): ['choice_0', 'choice_1'],
|
||||
}
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
event = self.get_event_for_answers(block, answer_input_dict)
|
||||
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': 'What color is the open ocean on a sunny day?',
|
||||
@@ -2981,9 +2980,9 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
|
||||
return CustomCapaFactory
|
||||
|
||||
def get_event_for_answers(self, module, answer_input_dict): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
with patch.object(module.runtime, 'publish') as mock_publish:
|
||||
module.submit_problem(answer_input_dict)
|
||||
def get_event_for_answers(self, block, answer_input_dict): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
with patch.object(block.runtime, 'publish') as mock_publish:
|
||||
block.submit_problem(answer_input_dict)
|
||||
|
||||
assert len(mock_publish.mock_calls) >= 2
|
||||
# There are potentially 2 track logs: answers and hint. [-1]=answers.
|
||||
@@ -2994,13 +2993,13 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
|
||||
def test_numerical_textline(self):
|
||||
factory = CapaFactory
|
||||
module = factory.create()
|
||||
block = factory.create()
|
||||
|
||||
answer_input_dict = {
|
||||
factory.input_key(2): '3.14'
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
event = self.get_event_for_answers(block, answer_input_dict)
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': '', 'answer': '3.14',
|
||||
'response_type': 'numericalresponse',
|
||||
@@ -3022,13 +3021,13 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
</optionresponse>
|
||||
</problem>
|
||||
""".format(group_label, input1_label, input2_label))
|
||||
module = factory.create()
|
||||
block = factory.create()
|
||||
answer_input_dict = {
|
||||
factory.input_key(2, 1): 'blue',
|
||||
factory.input_key(2, 2): 'yellow',
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
event = self.get_event_for_answers(block, answer_input_dict)
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2, 1): {'group_label': group_label,
|
||||
'question': input1_label,
|
||||
@@ -3084,14 +3083,14 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
</optionresponse>
|
||||
</problem>
|
||||
""".format(group_label, input1_label, input2_label))
|
||||
module = factory.create()
|
||||
block = factory.create()
|
||||
|
||||
answer_input_dict = {
|
||||
factory.input_key(2, 1): 'apple',
|
||||
factory.input_key(2, 2): 'cucumber',
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
event = self.get_event_for_answers(block, answer_input_dict)
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2, 1): {'group_label': group_label,
|
||||
'question': input1_label,
|
||||
@@ -3108,13 +3107,13 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
|
||||
def test_rerandomized_inputs(self):
|
||||
factory = CapaFactory
|
||||
module = factory.create(rerandomize=RANDOMIZATION.ALWAYS)
|
||||
block = factory.create(rerandomize=RANDOMIZATION.ALWAYS)
|
||||
|
||||
answer_input_dict = {
|
||||
factory.input_key(2): '3.14'
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
event = self.get_event_for_answers(block, answer_input_dict)
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': '',
|
||||
'answer': '3.14',
|
||||
@@ -3122,7 +3121,7 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
'input_type': 'textline',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': module.seed}}
|
||||
'variant': block.seed}}
|
||||
|
||||
@patch.object(XQueueInterface, '_http_post')
|
||||
def test_file_inputs(self, mock_xqueue_post):
|
||||
@@ -3133,7 +3132,7 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
self.addCleanup(fileobj.close)
|
||||
|
||||
factory = CapaFactoryWithFiles
|
||||
module = factory.create()
|
||||
block = factory.create()
|
||||
|
||||
# Mock the XQueueInterface post method
|
||||
mock_xqueue_post.return_value = (0, "ok")
|
||||
@@ -3143,7 +3142,7 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
CapaFactoryWithFiles.input_key(response_num=3): 'None',
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
event = self.get_event_for_answers(block, answer_input_dict)
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': '',
|
||||
'answer': fpaths,
|
||||
|
||||
@@ -29,16 +29,16 @@ COURSE = 'conditional' # name of directory with course data
|
||||
class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
|
||||
|
||||
@patch('xmodule.modulestore.xml.OSFS', lambda directory: MemoryFS())
|
||||
def __init__(self, load_error_modules):
|
||||
def __init__(self, load_error_blocks):
|
||||
|
||||
xmlstore = XMLModuleStore("data_dir", source_dirs=[], load_error_modules=load_error_modules)
|
||||
xmlstore = XMLModuleStore("data_dir", source_dirs=[], load_error_blocks=load_error_blocks)
|
||||
|
||||
super().__init__(
|
||||
xmlstore=xmlstore,
|
||||
course_id=CourseKey.from_string('/'.join([ORG, COURSE, 'test_run'])),
|
||||
course_dir='test_dir',
|
||||
error_tracker=Mock(),
|
||||
load_error_modules=load_error_modules,
|
||||
load_error_blocks=load_error_blocks,
|
||||
)
|
||||
|
||||
def render_template(self, template, context): # lint-amnesty, pylint: disable=method-hidden
|
||||
@@ -58,20 +58,20 @@ class ConditionalFactory:
|
||||
to allow for testing.
|
||||
"""
|
||||
@staticmethod
|
||||
def create(system, source_is_error_module=False, source_visible_to_staff_only=False):
|
||||
def create(system, source_is_error_block=False, source_visible_to_staff_only=False):
|
||||
"""
|
||||
return a dict of modules: the conditional with a single source and a single child.
|
||||
Keys are 'cond_module', 'source_module', and 'child_module'.
|
||||
return a dict of blocks: the conditional with a single source and a single child.
|
||||
Keys are 'cond_block', 'source_block', and 'child_block'.
|
||||
|
||||
if the source_is_error_module flag is set, create a real ErrorBlock for the source.
|
||||
if the source_is_error_block flag is set, create a real ErrorBlock for the source.
|
||||
"""
|
||||
descriptor_system = get_test_descriptor_system()
|
||||
|
||||
# construct source descriptor and module:
|
||||
source_location = BlockUsageLocator(CourseLocator("edX", "conditional_test", "test_run", deprecated=True),
|
||||
"problem", "SampleProblem", deprecated=True)
|
||||
if source_is_error_module:
|
||||
# Make an error descriptor and module
|
||||
if source_is_error_block:
|
||||
# Make an error descriptor and block
|
||||
source_descriptor = ErrorBlock.from_xml(
|
||||
'some random xml data',
|
||||
system,
|
||||
@@ -136,9 +136,9 @@ class ConditionalFactory:
|
||||
]
|
||||
|
||||
# return dict:
|
||||
return {'cond_module': cond_descriptor,
|
||||
'source_module': source_descriptor,
|
||||
'child_module': child_descriptor}
|
||||
return {'cond_block': cond_descriptor,
|
||||
'source_block': source_descriptor,
|
||||
'child_block': child_descriptor}
|
||||
|
||||
|
||||
class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
@@ -153,38 +153,38 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
|
||||
def test_icon_class(self):
|
||||
'''verify that get_icon_class works independent of condition satisfaction'''
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
blocks = ConditionalFactory.create(self.test_system)
|
||||
for attempted in ["false", "true"]:
|
||||
for icon_class in ['other', 'problem', 'video']:
|
||||
modules['source_module'].is_attempted = attempted
|
||||
modules['child_module'].get_icon_class = lambda: icon_class # lint-amnesty, pylint: disable=cell-var-from-loop
|
||||
assert modules['cond_module'].get_icon_class() == icon_class
|
||||
blocks['source_block'].is_attempted = attempted
|
||||
blocks['child_block'].get_icon_class = lambda: icon_class # lint-amnesty, pylint: disable=cell-var-from-loop
|
||||
assert blocks['cond_block'].get_icon_class() == icon_class
|
||||
|
||||
def test_get_html(self):
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
blocks = ConditionalFactory.create(self.test_system)
|
||||
# because get_test_system returns the repr of the context dict passed to render_template,
|
||||
# we reverse it here
|
||||
html = modules['cond_module'].render(STUDENT_VIEW).content
|
||||
mako_service = modules['cond_module'].xmodule_runtime.service(modules['cond_module'], 'mako')
|
||||
html = blocks['cond_block'].render(STUDENT_VIEW).content
|
||||
mako_service = blocks['cond_block'].xmodule_runtime.service(blocks['cond_block'], 'mako')
|
||||
expected = mako_service.render_template('conditional_ajax.html', {
|
||||
'ajax_url': modules['cond_module'].ajax_url,
|
||||
'ajax_url': blocks['cond_block'].ajax_url,
|
||||
'element_id': 'i4x-edX-conditional_test-conditional-SampleConditional',
|
||||
'depends': 'i4x-edX-conditional_test-problem-SampleProblem',
|
||||
})
|
||||
assert expected == html
|
||||
|
||||
def test_handle_ajax(self):
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
modules['cond_module'].save()
|
||||
modules['source_module'].is_attempted = "false"
|
||||
ajax = json.loads(modules['cond_module'].handle_ajax('', ''))
|
||||
blocks = ConditionalFactory.create(self.test_system)
|
||||
blocks['cond_block'].save()
|
||||
blocks['source_block'].is_attempted = "false"
|
||||
ajax = json.loads(blocks['cond_block'].handle_ajax('', ''))
|
||||
fragments = ajax['fragments']
|
||||
assert not any(('This is a secret' in item['content']) for item in fragments)
|
||||
|
||||
# now change state of the capa problem to make it completed
|
||||
modules['source_module'].is_attempted = "true"
|
||||
ajax = json.loads(modules['cond_module'].handle_ajax('', ''))
|
||||
modules['cond_module'].save()
|
||||
blocks['source_block'].is_attempted = "true"
|
||||
ajax = json.loads(blocks['cond_block'].handle_ajax('', ''))
|
||||
blocks['cond_block'].save()
|
||||
fragments = ajax['fragments']
|
||||
assert any(('This is a secret' in item['content']) for item in fragments)
|
||||
|
||||
@@ -193,24 +193,24 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
Check that handle_ajax works properly if the source is really an ErrorBlock,
|
||||
and that the condition is not satisfied.
|
||||
'''
|
||||
modules = ConditionalFactory.create(self.test_system, source_is_error_module=True)
|
||||
modules['cond_module'].save()
|
||||
ajax = json.loads(modules['cond_module'].handle_ajax('', ''))
|
||||
blocks = ConditionalFactory.create(self.test_system, source_is_error_block=True)
|
||||
blocks['cond_block'].save()
|
||||
ajax = json.loads(blocks['cond_block'].handle_ajax('', ''))
|
||||
fragments = ajax['fragments']
|
||||
assert not any(('This is a secret' in item['content']) for item in fragments)
|
||||
|
||||
@patch('xmodule.conditional_block.log')
|
||||
def test_conditional_with_staff_only_source_module(self, mock_log):
|
||||
modules = ConditionalFactory.create(
|
||||
def test_conditional_with_staff_only_source_block(self, mock_log):
|
||||
blocks = ConditionalFactory.create(
|
||||
self.test_system,
|
||||
source_visible_to_staff_only=True,
|
||||
)
|
||||
cond_module = modules['cond_module']
|
||||
cond_module.save()
|
||||
cond_module.is_attempted = "false"
|
||||
cond_module.handle_ajax('', '')
|
||||
cond_block = blocks['cond_block']
|
||||
cond_block.save()
|
||||
cond_block.is_attempted = "false"
|
||||
cond_block.handle_ajax('', '')
|
||||
assert not mock_log.warn.called
|
||||
assert None in cond_module.get_required_blocks
|
||||
assert None in cond_block.get_required_blocks
|
||||
|
||||
|
||||
class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
@@ -226,7 +226,7 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
assert len(courses) == 1
|
||||
self.course = courses[0]
|
||||
|
||||
def get_module_for_location(self, location):
|
||||
def get_block_for_location(self, location):
|
||||
descriptor = self.modulestore.get_item(location, depth=None)
|
||||
return self.test_system.get_block_for_descriptor(descriptor)
|
||||
|
||||
@@ -239,9 +239,9 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
location = BlockUsageLocator(CourseLocator("HarvardX", "ER22x", "2013_Spring", deprecated=True),
|
||||
"conditional", "condone", deprecated=True)
|
||||
|
||||
module = self.get_module_for_location(location)
|
||||
html = module.render(STUDENT_VIEW).content
|
||||
mako_service = module.xmodule_runtime.service(module, 'mako')
|
||||
block = self.get_block_for_location(location)
|
||||
html = block.render(STUDENT_VIEW).content
|
||||
mako_service = block.xmodule_runtime.service(block, 'mako')
|
||||
html_expect = mako_service.render_template(
|
||||
'conditional_ajax.html',
|
||||
{
|
||||
@@ -253,17 +253,17 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
)
|
||||
assert html == html_expect
|
||||
|
||||
ajax = json.loads(module.handle_ajax('', ''))
|
||||
ajax = json.loads(block.handle_ajax('', ''))
|
||||
fragments = ajax['fragments']
|
||||
assert not any(('This is a secret' in item['content']) for item in fragments)
|
||||
|
||||
# Now change state of the capa problem to make it completed
|
||||
inner_module = self.get_module_for_location(location.replace(category="problem", name='choiceprob'))
|
||||
inner_module.attempts = 1
|
||||
inner_block = self.get_block_for_location(location.replace(category="problem", name='choiceprob'))
|
||||
inner_block.attempts = 1
|
||||
# Save our modifications to the underlying KeyValueStore so they can be persisted
|
||||
inner_module.save()
|
||||
inner_block.save()
|
||||
|
||||
ajax = json.loads(module.handle_ajax('', ''))
|
||||
ajax = json.loads(block.handle_ajax('', ''))
|
||||
fragments = ajax['fragments']
|
||||
assert any(('This is a secret' in item['content']) for item in fragments)
|
||||
|
||||
@@ -323,15 +323,15 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
assert definition == expected_definition
|
||||
|
||||
def test_presence_attributes_in_xml_attributes(self):
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
modules['cond_module'].save()
|
||||
modules['cond_module'].definition_to_xml(Mock())
|
||||
blocks = ConditionalFactory.create(self.test_system)
|
||||
blocks['cond_block'].save()
|
||||
blocks['cond_block'].definition_to_xml(Mock())
|
||||
expected_xml_attributes = {
|
||||
'attempted': 'true',
|
||||
'message': 'You must complete {link} before you can access this unit.',
|
||||
'sources': ''
|
||||
}
|
||||
self.assertDictEqual(modules['cond_module'].xml_attributes, expected_xml_attributes)
|
||||
self.assertDictEqual(blocks['cond_block'].xml_attributes, expected_xml_attributes)
|
||||
|
||||
|
||||
class ConditionalBlockStudioTest(XModuleXmlImportTest):
|
||||
|
||||
@@ -40,10 +40,10 @@ class CourseFieldsTestCase(unittest.TestCase):
|
||||
|
||||
class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
|
||||
@patch('xmodule.modulestore.xml.OSFS', lambda dir: MemoryFS())
|
||||
def __init__(self, load_error_modules, course_id=None):
|
||||
def __init__(self, load_error_blocks, course_id=None):
|
||||
|
||||
xmlstore = XMLModuleStore("data_dir", source_dirs=[],
|
||||
load_error_modules=load_error_modules)
|
||||
load_error_blocks=load_error_blocks)
|
||||
if course_id is None:
|
||||
course_id = CourseKey.from_string('/'.join([ORG, COURSE, 'test_run']))
|
||||
course_dir = "test_dir"
|
||||
@@ -54,7 +54,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho
|
||||
course_id=course_id,
|
||||
course_dir=course_dir,
|
||||
error_tracker=error_tracker,
|
||||
load_error_modules=load_error_modules,
|
||||
load_error_blocks=load_error_blocks,
|
||||
services={'field-data': KvsFieldData(DictKeyValueStore())},
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ def get_dummy_course(
|
||||
):
|
||||
"""Get a dummy course"""
|
||||
|
||||
system = DummySystem(load_error_modules=True)
|
||||
system = DummySystem(load_error_blocks=True)
|
||||
|
||||
def to_attrb(n, v):
|
||||
return '' if v is None else f'{n}="{v}"'.lower()
|
||||
@@ -112,7 +112,7 @@ class HasEndedMayCertifyTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
system = DummySystem(load_error_modules=True) # lint-amnesty, pylint: disable=unused-variable
|
||||
system = DummySystem(load_error_blocks=True) # lint-amnesty, pylint: disable=unused-variable
|
||||
|
||||
past_end = (datetime.now() - timedelta(days=12)).strftime("%Y-%m-%dT%H:%M:00")
|
||||
future_end = (datetime.now() + timedelta(days=12)).strftime("%Y-%m-%dT%H:%M:00")
|
||||
|
||||
@@ -28,7 +28,7 @@ from . import get_test_system
|
||||
|
||||
class CapaFactoryWithDelay:
|
||||
"""
|
||||
Create problem modules class, specialized for delay_between_attempts
|
||||
Create problem blocks class, specialized for delay_between_attempts
|
||||
test cases. This factory seems different enough from the one in
|
||||
test_capa_block that unifying them is unattractive.
|
||||
Removed the unused optional arguments.
|
||||
@@ -104,7 +104,7 @@ class CapaFactoryWithDelay:
|
||||
field_data['attempts'] = int(attempts)
|
||||
|
||||
system = get_test_system(render_template=Mock(return_value="<div>Test Template HTML</div>"))
|
||||
module = ProblemBlock(
|
||||
block = ProblemBlock(
|
||||
system,
|
||||
DictFieldData(field_data),
|
||||
ScopeIds(None, None, location, location),
|
||||
@@ -112,11 +112,11 @@ class CapaFactoryWithDelay:
|
||||
|
||||
if correct:
|
||||
# Could set the internal state formally, but here we just jam in the score.
|
||||
module.score = Score(raw_earned=1, raw_possible=1)
|
||||
block.score = Score(raw_earned=1, raw_possible=1)
|
||||
else:
|
||||
module.score = Score(raw_earned=0, raw_possible=1)
|
||||
block.score = Score(raw_earned=0, raw_possible=1)
|
||||
|
||||
return module
|
||||
return block
|
||||
|
||||
|
||||
class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
@@ -131,37 +131,37 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
considered_now=None,
|
||||
skip_submit_problem=False):
|
||||
"""Unified create and check code for the tests here."""
|
||||
module = CapaFactoryWithDelay.create(
|
||||
block = CapaFactoryWithDelay.create(
|
||||
attempts=num_attempts,
|
||||
max_attempts=99,
|
||||
last_submission_time=last_submission_time,
|
||||
submission_wait_seconds=submission_wait_seconds
|
||||
)
|
||||
module.done = False
|
||||
block.done = False
|
||||
get_request_dict = {CapaFactoryWithDelay.input_key(): "3.14"}
|
||||
if skip_submit_problem:
|
||||
return (module, None)
|
||||
return (block, None)
|
||||
if considered_now is not None:
|
||||
result = module.submit_problem(get_request_dict, considered_now)
|
||||
result = block.submit_problem(get_request_dict, considered_now)
|
||||
else:
|
||||
result = module.submit_problem(get_request_dict)
|
||||
return (module, result)
|
||||
result = block.submit_problem(get_request_dict)
|
||||
return (block, result)
|
||||
|
||||
def test_first_submission(self):
|
||||
# Not attempted yet
|
||||
num_attempts = 0
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=None
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
assert block.attempts == (num_attempts + 1)
|
||||
|
||||
def test_no_wait_time(self):
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime.now(UTC),
|
||||
submission_wait_seconds=0
|
||||
@@ -169,12 +169,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
assert block.attempts == (num_attempts + 1)
|
||||
|
||||
def test_submit_quiz_in_rapid_succession(self):
|
||||
# Already attempted once (just now) and thus has a submitted time
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime.now(UTC),
|
||||
submission_wait_seconds=123
|
||||
@@ -182,12 +182,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least.*")
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_too_soon(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
@@ -196,12 +196,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 3 minutes between submissions. 2 minutes remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_1_second_too_soon(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
@@ -210,12 +210,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 3 minutes between submissions. 1 second remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_as_soon_as_allowed(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
@@ -224,12 +224,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
assert block.attempts == (num_attempts + 1)
|
||||
|
||||
def test_submit_quiz_after_delay_expired(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
@@ -238,14 +238,14 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
assert block.attempts == (num_attempts + 1)
|
||||
|
||||
def test_still_cannot_submit_after_max_attempts(self):
|
||||
# Already attempted once (just now) and thus has a submitted time
|
||||
num_attempts = 99
|
||||
# Regular create_and_check should fail
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
(module, unused_result) = self.create_and_check(
|
||||
(block, unused_result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
@@ -253,7 +253,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
# Now try it without the submit_problem
|
||||
(module, unused_result) = self.create_and_check(
|
||||
(block, unused_result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=180,
|
||||
@@ -261,12 +261,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
skip_submit_problem=True
|
||||
)
|
||||
# Expect that number of attempts NOT incremented
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_with_long_delay(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=60 * 60 * 2,
|
||||
@@ -275,12 +275,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 2 hours between submissions. 2 minutes 1 second remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_with_involved_pretty_print(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=60 * 60 * 2 + 63,
|
||||
@@ -289,12 +289,12 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 2 hours 1 minute 3 seconds between submissions. 1 hour 2 minutes 59 seconds remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_with_nonplural_pretty_print(self):
|
||||
# Already attempted once (just now)
|
||||
num_attempts = 1
|
||||
(module, result) = self.create_and_check(
|
||||
(block, result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
submission_wait_seconds=60,
|
||||
@@ -303,4 +303,4 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 1 minute between submissions. 1 minute remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
assert module.attempts == num_attempts
|
||||
assert block.attempts == num_attempts
|
||||
|
||||
@@ -140,7 +140,7 @@ class RoundTripTestCase(unittest.TestCase):
|
||||
list(second_import.modules[course_id].keys())
|
||||
)
|
||||
|
||||
print("Checking module equality")
|
||||
print("Checking block equality")
|
||||
for location in initial_import.modules[course_id].keys():
|
||||
print(("Checking", location))
|
||||
assert blocks_are_equivalent(initial_import.modules[course_id][location],
|
||||
|
||||
@@ -48,10 +48,10 @@ class HtmlBlockCourseApiTestCase(unittest.TestCase):
|
||||
"""
|
||||
field_data = DictFieldData({'data': '<h1>Some HTML</h1>'})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
|
||||
with override_settings(**settings):
|
||||
assert module.student_view_data() ==\
|
||||
assert block.student_view_data() ==\
|
||||
dict(enabled=False, message='To enable, set FEATURES["ENABLE_HTML_XBLOCK_STUDENT_VIEW_DATA"]')
|
||||
|
||||
@ddt.data(
|
||||
@@ -76,8 +76,8 @@ class HtmlBlockCourseApiTestCase(unittest.TestCase):
|
||||
"""
|
||||
field_data = DictFieldData({'data': html})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
assert module.student_view_data() == dict(enabled=True, html=html)
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
assert block.student_view_data() == dict(enabled=True, html=html)
|
||||
|
||||
@ddt.data(
|
||||
STUDENT_VIEW,
|
||||
@@ -90,8 +90,8 @@ class HtmlBlockCourseApiTestCase(unittest.TestCase):
|
||||
html = '<p>This is a test</p>'
|
||||
field_data = DictFieldData({'data': html})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
rendered = module_system.render(module, view, {}).content
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
rendered = module_system.render(block, view, {}).content
|
||||
assert html in rendered
|
||||
|
||||
|
||||
@@ -101,14 +101,14 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
sample_xml = '''%%USER_ID%%'''
|
||||
field_data = DictFieldData({'data': sample_xml})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
assert module.get_html() == str(module_system.anonymous_student_id)
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
assert block.get_html() == str(module_system.anonymous_student_id)
|
||||
|
||||
def test_substitution_course_id(self):
|
||||
sample_xml = '''%%COURSE_ID%%'''
|
||||
field_data = DictFieldData({'data': sample_xml})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
course_key = CourseLocator(
|
||||
org='some_org',
|
||||
course='some_course',
|
||||
@@ -119,8 +119,8 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
block_type='problem',
|
||||
block_id='block_id'
|
||||
)
|
||||
module.scope_ids.usage_id = usage_key
|
||||
assert module.get_html() == str(course_key)
|
||||
block.scope_ids.usage_id = usage_key
|
||||
assert block.get_html() == str(course_key)
|
||||
|
||||
def test_substitution_without_magic_string(self):
|
||||
sample_xml = '''
|
||||
@@ -130,15 +130,15 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
'''
|
||||
field_data = DictFieldData({'data': sample_xml})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
assert module.get_html() == sample_xml
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
assert block.get_html() == sample_xml
|
||||
|
||||
def test_substitution_without_anonymous_student_id(self):
|
||||
sample_xml = '''%%USER_ID%%'''
|
||||
field_data = DictFieldData({'data': sample_xml})
|
||||
module_system = get_test_system(user=AnonymousUser())
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
assert module.get_html() == sample_xml
|
||||
block = HtmlBlock(module_system, field_data, Mock())
|
||||
assert block.get_html() == sample_xml
|
||||
|
||||
|
||||
class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
@@ -229,7 +229,7 @@ class CourseInfoBlockTestCase(unittest.TestCase):
|
||||
|
||||
def test_updates_render(self):
|
||||
"""
|
||||
Tests that a course info module will render its updates, even if they are malformed.
|
||||
Tests that a course info block will render its updates, even if they are malformed.
|
||||
"""
|
||||
sample_update_data = [
|
||||
{
|
||||
@@ -246,7 +246,7 @@ class CourseInfoBlockTestCase(unittest.TestCase):
|
||||
]
|
||||
)
|
||||
]
|
||||
info_module = CourseInfoBlock(
|
||||
info_block = CourseInfoBlock(
|
||||
get_test_system(),
|
||||
DictFieldData({'items': sample_update_data, 'data': ""}),
|
||||
Mock()
|
||||
@@ -254,13 +254,13 @@ class CourseInfoBlockTestCase(unittest.TestCase):
|
||||
|
||||
# Prior to TNL-4115, an exception would be raised when trying to parse invalid dates in this method
|
||||
try:
|
||||
info_module.get_html()
|
||||
info_block.get_html()
|
||||
except ValueError:
|
||||
self.fail("CourseInfoBlock could not parse an invalid date!")
|
||||
|
||||
def test_updates_order(self):
|
||||
"""
|
||||
Tests that a course info module will render its updates in the correct order.
|
||||
Tests that a course info block will render its updates in the correct order.
|
||||
"""
|
||||
sample_update_data = [
|
||||
{
|
||||
@@ -282,7 +282,7 @@ class CourseInfoBlockTestCase(unittest.TestCase):
|
||||
"status": CourseInfoBlock.STATUS_VISIBLE,
|
||||
}
|
||||
]
|
||||
info_module = CourseInfoBlock(
|
||||
info_block = CourseInfoBlock(
|
||||
Mock(),
|
||||
DictFieldData({'items': sample_update_data, 'data': ""}),
|
||||
Mock()
|
||||
@@ -312,10 +312,10 @@ class CourseInfoBlockTestCase(unittest.TestCase):
|
||||
],
|
||||
'hidden_updates': [],
|
||||
}
|
||||
template_name = f"{info_module.TEMPLATE_DIR}/course_updates.html"
|
||||
info_module.get_html()
|
||||
template_name = f"{info_block.TEMPLATE_DIR}/course_updates.html"
|
||||
info_block.get_html()
|
||||
# Assertion to validate that render function is called with the expected context
|
||||
info_module.runtime.service(info_module, 'mako').render_template.assert_called_once_with(
|
||||
info_block.runtime.service(info_block, 'mako').render_template.assert_called_once_with(
|
||||
template_name,
|
||||
expected_context
|
||||
)
|
||||
|
||||
@@ -32,12 +32,12 @@ RUN = 'test_run'
|
||||
class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
|
||||
|
||||
@patch('xmodule.modulestore.xml.OSFS', lambda dir: OSFS(mkdtemp()))
|
||||
def __init__(self, load_error_modules, library=False):
|
||||
def __init__(self, load_error_blocks, library=False):
|
||||
|
||||
if library:
|
||||
xmlstore = LibraryXMLModuleStore("data_dir", source_dirs=[], load_error_modules=load_error_modules)
|
||||
xmlstore = LibraryXMLModuleStore("data_dir", source_dirs=[], load_error_blocks=load_error_blocks)
|
||||
else:
|
||||
xmlstore = XMLModuleStore("data_dir", source_dirs=[], load_error_modules=load_error_modules)
|
||||
xmlstore = XMLModuleStore("data_dir", source_dirs=[], load_error_blocks=load_error_blocks)
|
||||
course_id = CourseKey.from_string('/'.join([ORG, COURSE, RUN]))
|
||||
course_dir = "test_dir"
|
||||
error_tracker = Mock()
|
||||
@@ -47,7 +47,7 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho
|
||||
course_id=course_id,
|
||||
course_dir=course_dir,
|
||||
error_tracker=error_tracker,
|
||||
load_error_modules=load_error_modules,
|
||||
load_error_blocks=load_error_blocks,
|
||||
mixins=(InheritanceMixin, XModuleMixin),
|
||||
services={'field-data': KvsFieldData(DictKeyValueStore())},
|
||||
)
|
||||
@@ -57,12 +57,12 @@ class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-metho
|
||||
|
||||
|
||||
class BaseCourseTestCase(TestCase):
|
||||
'''Make sure module imports work properly, including for malformed inputs'''
|
||||
'''Make sure block imports work properly, including for malformed inputs'''
|
||||
|
||||
@staticmethod
|
||||
def get_system(load_error_modules=True, library=False):
|
||||
def get_system(load_error_blocks=True, library=False):
|
||||
'''Get a dummy system'''
|
||||
return DummySystem(load_error_modules, library=library)
|
||||
return DummySystem(load_error_blocks, library=library)
|
||||
|
||||
def get_course(self, name):
|
||||
"""Get a test course by directory name. If there's more than one, error."""
|
||||
@@ -110,7 +110,7 @@ class PureXBlockImportTest(BaseCourseTestCase):
|
||||
)
|
||||
@patch('xmodule.x_module.XModuleMixin.location')
|
||||
def test_parsing_pure_xblock(self, xml, mock_location):
|
||||
system = self.get_system(load_error_modules=False)
|
||||
system = self.get_system(load_error_blocks=False)
|
||||
descriptor = system.process_xml(xml)
|
||||
assert isinstance(descriptor, GenericXBlock)
|
||||
self.assert_xblocks_are_good(descriptor)
|
||||
@@ -488,7 +488,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
|
||||
def test_definition_loading(self):
|
||||
"""When two courses share the same org and course name and
|
||||
both have a module with the same url_name, the definitions shouldn't clash.
|
||||
both have a block with the same url_name, the definitions shouldn't clash.
|
||||
|
||||
TODO (vshnayder): once we have a CMS, this shouldn't
|
||||
happen--locations should uniquely name definitions. But in
|
||||
@@ -592,20 +592,20 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
assert len(sections) == 1
|
||||
|
||||
conditional_location = course.id.make_usage_key('conditional', 'condone')
|
||||
module = modulestore.get_item(conditional_location)
|
||||
assert len(module.children) == 1
|
||||
block = modulestore.get_item(conditional_location)
|
||||
assert len(block.children) == 1
|
||||
|
||||
poll_location = course.id.make_usage_key('poll_question', 'first_poll')
|
||||
module = modulestore.get_item(poll_location)
|
||||
assert len(module.get_children()) == 0
|
||||
assert module.voted is False
|
||||
assert module.poll_answer == ''
|
||||
assert module.poll_answers == {}
|
||||
assert module.answers ==\
|
||||
block = modulestore.get_item(poll_location)
|
||||
assert len(block.get_children()) == 0
|
||||
assert block.voted is False
|
||||
assert block.poll_answer == ''
|
||||
assert block.poll_answers == {}
|
||||
assert block.answers ==\
|
||||
[{'text': 'Yes', 'id': 'Yes'}, {'text': 'No', 'id': 'No'}, {'text': "Don't know", 'id': 'Dont_know'}]
|
||||
|
||||
def test_error_on_import(self):
|
||||
'''Check that when load_error_module is false, an exception is raised, rather than returning an ErrorBlock'''
|
||||
'''Check that when load_error_block is false, an exception is raised, rather than returning an ErrorBlock'''
|
||||
|
||||
bad_xml = '''<sequential display_name="oops"><video url="hi"></sequential>'''
|
||||
system = self.get_system(False)
|
||||
@@ -623,10 +623,10 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
assert len(sections) == 1
|
||||
|
||||
location = course.id.make_usage_key('word_cloud', 'cloud1')
|
||||
module = modulestore.get_item(location)
|
||||
assert len(module.get_children()) == 0
|
||||
assert module.num_inputs == 5
|
||||
assert module.num_top_words == 250
|
||||
block = modulestore.get_item(location)
|
||||
assert len(block.get_children()) == 0
|
||||
assert block.num_inputs == 5
|
||||
assert block.num_top_words == 250
|
||||
|
||||
def test_cohort_config(self):
|
||||
"""
|
||||
|
||||
@@ -54,24 +54,24 @@ class LibraryContentTest(MixedSplitTestCase):
|
||||
source_library_id=str(self.library.location.library_key)
|
||||
)
|
||||
|
||||
def _bind_course_block(self, module):
|
||||
def _bind_course_block(self, block):
|
||||
"""
|
||||
Bind a module (part of self.course) so we can access student-specific data.
|
||||
Bind a block (part of self.course) so we can access student-specific data.
|
||||
"""
|
||||
module_system = get_test_system(course_id=module.location.course_key)
|
||||
module_system.descriptor_runtime = module.runtime._descriptor_system # pylint: disable=protected-access
|
||||
module_system = get_test_system(course_id=block.location.course_key)
|
||||
module_system.descriptor_runtime = block.runtime._descriptor_system # pylint: disable=protected-access
|
||||
module_system._services['library_tools'] = self.tools # pylint: disable=protected-access
|
||||
|
||||
def get_block(descriptor):
|
||||
"""Mocks module_system get_block function"""
|
||||
sub_module_system = get_test_system(course_id=module.location.course_key)
|
||||
sub_module_system = get_test_system(course_id=block.location.course_key)
|
||||
sub_module_system.get_block_for_descriptor = get_block
|
||||
sub_module_system.descriptor_runtime = descriptor._runtime # pylint: disable=protected-access
|
||||
descriptor.bind_for_student(sub_module_system, self.user_id)
|
||||
return descriptor
|
||||
|
||||
module_system.get_block_for_descriptor = get_block
|
||||
module.xmodule_runtime = module_system
|
||||
block.xmodule_runtime = module_system
|
||||
|
||||
|
||||
class TestLibraryContentExportImport(LibraryContentTest):
|
||||
@@ -102,7 +102,7 @@ class TestLibraryContentExportImport(LibraryContentTest):
|
||||
self.lc_block.runtime._descriptor_system.export_fs = self.export_fs # pylint: disable=protected-access
|
||||
|
||||
# Prepare runtime for the import.
|
||||
self.runtime = TestImportSystem(load_error_modules=True, course_id=self.lc_block.location.course_key)
|
||||
self.runtime = TestImportSystem(load_error_blocks=True, course_id=self.lc_block.location.course_key)
|
||||
self.runtime.resources_fs = self.export_fs
|
||||
self.id_generator = Mock()
|
||||
|
||||
@@ -207,7 +207,7 @@ class LibraryContentBlockTestMixin:
|
||||
# Normally the children get added when the "source_libraries" setting
|
||||
# is updated, but the way we do it through a factory doesn't do that.
|
||||
assert len(self.lc_block.children) == 0
|
||||
# Update the LibraryContent module:
|
||||
# Update the LibraryContent block:
|
||||
self.lc_block.refresh_children()
|
||||
self.lc_block = self.store.get_item(self.lc_block.location)
|
||||
# Check that all blocks from the library are now children of the block:
|
||||
|
||||
@@ -29,10 +29,10 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
self.runtime.publish = Mock()
|
||||
self.runtime._services['rebind_user'] = Mock() # pylint: disable=protected-access
|
||||
|
||||
self.xmodule = LTIBlock(self.runtime, DictFieldData({}), Mock())
|
||||
self.lti_id = self.xmodule.lti_id
|
||||
self.xmodule.due = None
|
||||
self.xmodule.graceperiod = None
|
||||
self.xblock = LTIBlock(self.runtime, DictFieldData({}), Mock())
|
||||
self.lti_id = self.xblock.lti_id
|
||||
self.xblock.due = None
|
||||
self.xblock.graceperiod = None
|
||||
|
||||
def test_sanitize_get_context(self):
|
||||
"""Tests that the get_context function does basic sanitization"""
|
||||
@@ -40,8 +40,8 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
mocked_course = Mock(name='mocked_course', lti_passports=['lti_id:test_client:test_secret'])
|
||||
modulestore = Mock(name='modulestore')
|
||||
modulestore.get_course.return_value = mocked_course
|
||||
self.xmodule.runtime.modulestore = modulestore
|
||||
self.xmodule.lti_id = "lti_id"
|
||||
self.xblock.runtime.modulestore = modulestore
|
||||
self.xblock.lti_id = "lti_id"
|
||||
|
||||
test_cases = ( # (before sanitize, after sanitize)
|
||||
("plaintext", "plaintext"),
|
||||
@@ -49,8 +49,8 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
("<b>bold 包</b>", "<b>bold 包</b>"), # unicode, and <b> tags pass through
|
||||
)
|
||||
for case in test_cases:
|
||||
self.xmodule.score_comment = case[0]
|
||||
assert case[1] == self.xmodule.get_context()['comment']
|
||||
self.xblock.score_comment = case[0]
|
||||
assert case[1] == self.xblock.get_context()['comment']
|
||||
|
||||
def test_lti20_rest_bad_contenttype(self):
|
||||
"""
|
||||
@@ -58,28 +58,28 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
with self.assertRaisesRegex(LTIError, "Content-Type must be"):
|
||||
request = Mock(headers={'Content-Type': 'Non-existent'})
|
||||
self.xmodule.verify_lti_2_0_result_rest_headers(request)
|
||||
self.xblock.verify_lti_2_0_result_rest_headers(request)
|
||||
|
||||
def test_lti20_rest_failed_oauth_body_verify(self):
|
||||
"""
|
||||
Input with bad oauth body hash verification
|
||||
"""
|
||||
err_msg = "OAuth body verification failed"
|
||||
self.xmodule.verify_oauth_body_sign = Mock(side_effect=LTIError(err_msg))
|
||||
self.xblock.verify_oauth_body_sign = Mock(side_effect=LTIError(err_msg))
|
||||
with self.assertRaisesRegex(LTIError, err_msg):
|
||||
request = Mock(headers={'Content-Type': 'application/vnd.ims.lis.v2.result+json'})
|
||||
self.xmodule.verify_lti_2_0_result_rest_headers(request)
|
||||
self.xblock.verify_lti_2_0_result_rest_headers(request)
|
||||
|
||||
def test_lti20_rest_good_headers(self):
|
||||
"""
|
||||
Input with good oauth body hash verification
|
||||
"""
|
||||
self.xmodule.verify_oauth_body_sign = Mock(return_value=True)
|
||||
self.xblock.verify_oauth_body_sign = Mock(return_value=True)
|
||||
|
||||
request = Mock(headers={'Content-Type': 'application/vnd.ims.lis.v2.result+json'})
|
||||
self.xmodule.verify_lti_2_0_result_rest_headers(request)
|
||||
self.xblock.verify_lti_2_0_result_rest_headers(request)
|
||||
# We just want the above call to complete without exceptions, and to have called verify_oauth_body_sign
|
||||
assert self.xmodule.verify_oauth_body_sign.called
|
||||
assert self.xblock.verify_oauth_body_sign.called
|
||||
|
||||
BAD_DISPATCH_INPUTS = [
|
||||
None,
|
||||
@@ -100,7 +100,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
for einput in self.BAD_DISPATCH_INPUTS:
|
||||
with self.assertRaisesRegex(LTIError, "No valid user id found in endpoint URL"):
|
||||
self.xmodule.parse_lti_2_0_handler_suffix(einput)
|
||||
self.xblock.parse_lti_2_0_handler_suffix(einput)
|
||||
|
||||
GOOD_DISPATCH_INPUTS = [
|
||||
("user/abcd3", "abcd3"),
|
||||
@@ -113,7 +113,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
fit the form user/<anon_id>
|
||||
"""
|
||||
for ginput, expected in self.GOOD_DISPATCH_INPUTS:
|
||||
assert self.xmodule.parse_lti_2_0_handler_suffix(ginput) == expected
|
||||
assert self.xblock.parse_lti_2_0_handler_suffix(ginput) == expected
|
||||
|
||||
BAD_JSON_INPUTS = [
|
||||
# (bad inputs, error message expected)
|
||||
@@ -161,7 +161,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
for error_inputs, error_message in self.BAD_JSON_INPUTS:
|
||||
for einput in error_inputs:
|
||||
with self.assertRaisesRegex(LTIError, error_message):
|
||||
self.xmodule.parse_lti_2_0_result_json(einput)
|
||||
self.xblock.parse_lti_2_0_result_json(einput)
|
||||
|
||||
GOOD_JSON_INPUTS = [
|
||||
('''
|
||||
@@ -185,7 +185,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
Test the parsing of good comments
|
||||
"""
|
||||
for json_str, expected_comment in self.GOOD_JSON_INPUTS:
|
||||
score, comment = self.xmodule.parse_lti_2_0_result_json(json_str)
|
||||
score, comment = self.xblock.parse_lti_2_0_result_json(json_str)
|
||||
assert score == 0.1
|
||||
assert comment == expected_comment
|
||||
|
||||
@@ -226,30 +226,30 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
mock_request.body = body
|
||||
return mock_request
|
||||
|
||||
def setup_system_xmodule_mocks_for_lti20_request_test(self):
|
||||
def setup_system_xblock_mocks_for_lti20_request_test(self):
|
||||
"""
|
||||
Helper fn to set up mocking for lti 2.0 request test
|
||||
"""
|
||||
self.xmodule.max_score = Mock(return_value=1.0)
|
||||
self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xmodule.verify_oauth_body_sign = Mock()
|
||||
self.xblock.max_score = Mock(return_value=1.0)
|
||||
self.xblock.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xblock.verify_oauth_body_sign = Mock()
|
||||
|
||||
def test_lti20_put_like_delete_success(self):
|
||||
"""
|
||||
The happy path for LTI 2.0 PUT that acts like a delete
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
SCORE = 0.55 # pylint: disable=invalid-name
|
||||
COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name
|
||||
self.xmodule.module_score = SCORE
|
||||
self.xmodule.score_comment = COMMENT
|
||||
self.xblock.module_score = SCORE
|
||||
self.xblock.score_comment = COMMENT
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT_LIKE_DELETE)
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
# Now assert there's no score
|
||||
assert response.status_code == 200
|
||||
assert self.xmodule.module_score is None
|
||||
assert self.xmodule.score_comment == ''
|
||||
assert self.xblock.module_score is None
|
||||
assert self.xblock.score_comment == ''
|
||||
(_, evt_type, called_grade_obj), _ = self.runtime.publish.call_args # pylint: disable=unpacking-non-sequence
|
||||
assert called_grade_obj ==\
|
||||
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True}
|
||||
@@ -259,18 +259,18 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
The happy path for LTI 2.0 DELETE
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
SCORE = 0.55 # pylint: disable=invalid-name
|
||||
COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name
|
||||
self.xmodule.module_score = SCORE
|
||||
self.xmodule.score_comment = COMMENT
|
||||
self.xblock.module_score = SCORE
|
||||
self.xblock.score_comment = COMMENT
|
||||
mock_request = self.get_signed_lti20_mock_request(b"", method='DELETE')
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
# Now assert there's no score
|
||||
assert response.status_code == 200
|
||||
assert self.xmodule.module_score is None
|
||||
assert self.xmodule.score_comment == ''
|
||||
assert self.xblock.module_score is None
|
||||
assert self.xblock.score_comment == ''
|
||||
(_, evt_type, called_grade_obj), _ = self.runtime.publish.call_args # pylint: disable=unpacking-non-sequence
|
||||
assert called_grade_obj ==\
|
||||
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True}
|
||||
@@ -280,14 +280,14 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
The happy path for LTI 2.0 PUT that sets a score
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
# Now assert
|
||||
assert response.status_code == 200
|
||||
assert self.xmodule.module_score == 0.1
|
||||
assert self.xmodule.score_comment == 'ಠ益ಠ'
|
||||
assert self.xblock.module_score == 0.1
|
||||
assert self.xblock.score_comment == 'ಠ益ಠ'
|
||||
(_, evt_type, called_grade_obj), _ = self.runtime.publish.call_args # pylint: disable=unpacking-non-sequence
|
||||
assert evt_type == 'grade'
|
||||
assert called_grade_obj ==\
|
||||
@@ -297,10 +297,10 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
The happy path for LTI 2.0 GET when there's no score
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
mock_request = self.get_signed_lti20_mock_request(b"", method='GET')
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
# Now assert
|
||||
assert response.status_code == 200
|
||||
assert response.json == {'@context': 'http://purl.imsglobal.org/ctx/lis/v2/Result', '@type': 'Result'}
|
||||
@@ -309,14 +309,14 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
The happy path for LTI 2.0 GET when there is a score
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
SCORE = 0.55 # pylint: disable=invalid-name
|
||||
COMMENT = "ಠ益ಠ" # pylint: disable=invalid-name
|
||||
self.xmodule.module_score = SCORE
|
||||
self.xmodule.score_comment = COMMENT
|
||||
self.xblock.module_score = SCORE
|
||||
self.xblock.score_comment = COMMENT
|
||||
mock_request = self.get_signed_lti20_mock_request(b"", method='GET')
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
# Now assert
|
||||
assert response.status_code == 200
|
||||
assert response.json ==\
|
||||
@@ -329,59 +329,59 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
Test we get a 404 when we don't GET or PUT
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
for bad_method in self.UNSUPPORTED_HTTP_METHODS:
|
||||
mock_request.method = bad_method
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_bad_headers(self):
|
||||
"""
|
||||
Test that we get a 401 when header verification fails
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.xmodule.verify_lti_2_0_result_rest_headers = Mock(side_effect=LTIError())
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
self.xblock.verify_lti_2_0_result_rest_headers = Mock(side_effect=LTIError())
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_lti20_request_handler_bad_dispatch_user(self):
|
||||
"""
|
||||
Test that we get a 404 when there's no (or badly formatted) user specified in the url
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, None)
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, None)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_bad_json(self):
|
||||
"""
|
||||
Test that we get a 404 when json verification fails
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.xmodule.parse_lti_2_0_result_json = Mock(side_effect=LTIError())
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
self.xblock.parse_lti_2_0_result_json = Mock(side_effect=LTIError())
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_bad_user(self):
|
||||
"""
|
||||
Test that we get a 404 when the supplied user does not exist
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
self.runtime._services['user'] = StubUserService(user=None) # pylint: disable=protected-access
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_grade_past_due(self):
|
||||
"""
|
||||
Test that we get a 404 when accept_grades_past_due is False and it is past due
|
||||
"""
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
self.xmodule.due = datetime.datetime.now(UTC)
|
||||
self.xmodule.accept_grades_past_due = False
|
||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||
self.xblock.due = datetime.datetime.now(UTC)
|
||||
self.xblock.accept_grades_past_due = False
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||
assert response.status_code == 404
|
||||
|
||||
@@ -67,14 +67,14 @@ class LTIBlockTest(TestCase):
|
||||
self.system.publish = Mock()
|
||||
self.system._services['rebind_user'] = Mock() # pylint: disable=protected-access
|
||||
|
||||
self.xmodule = LTIBlock(
|
||||
self.xblock = LTIBlock(
|
||||
self.system,
|
||||
DictFieldData({}),
|
||||
ScopeIds(None, None, None, BlockUsageLocator(self.course_id, 'lti', 'name'))
|
||||
)
|
||||
current_user = self.system.service(self.xmodule, 'user').get_current_user()
|
||||
current_user = self.system.service(self.xblock, 'user').get_current_user()
|
||||
self.user_id = current_user.opt_attrs.get(ATTR_KEY_ANONYMOUS_USER_ID)
|
||||
self.lti_id = self.xmodule.lti_id
|
||||
self.lti_id = self.xblock.lti_id
|
||||
|
||||
self.unquoted_resource_link_id = '{}-i4x-2-3-lti-31de800015cf4afb973356dbe81496df'.format(
|
||||
settings.LMS_BASE
|
||||
@@ -90,8 +90,8 @@ class LTIBlockTest(TestCase):
|
||||
'messageIdentifier': '528243ba5241b',
|
||||
}
|
||||
|
||||
self.xmodule.due = None
|
||||
self.xmodule.graceperiod = None
|
||||
self.xblock.due = None
|
||||
self.xblock.graceperiod = None
|
||||
|
||||
def get_request_body(self, params=None):
|
||||
"""Fetches the body of a request specified by params"""
|
||||
@@ -138,7 +138,7 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body()
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
expected_response = {
|
||||
'action': None,
|
||||
@@ -163,7 +163,7 @@ class LTIBlockTest(TestCase):
|
||||
request = Request(self.environ)
|
||||
request.authorization = "bad authorization header"
|
||||
request.body = self.get_request_body()
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
expected_response = {
|
||||
'action': None,
|
||||
@@ -179,11 +179,11 @@ class LTIBlockTest(TestCase):
|
||||
If we have no real user, we should send back failure response.
|
||||
"""
|
||||
self.system._services['user'] = StubUserService(user=None) # pylint: disable=protected-access
|
||||
self.xmodule.verify_oauth_body_sign = Mock()
|
||||
self.xmodule.has_score = True
|
||||
self.xblock.verify_oauth_body_sign = Mock()
|
||||
self.xblock.has_score = True
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body()
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
expected_response = {
|
||||
'action': None,
|
||||
@@ -198,12 +198,12 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
Should fail if we do not accept past due grades, and it is past due.
|
||||
"""
|
||||
self.xmodule.accept_grades_past_due = False
|
||||
self.xmodule.due = datetime.datetime.now(UTC)
|
||||
self.xmodule.graceperiod = Timedelta().from_json("0 seconds")
|
||||
self.xblock.accept_grades_past_due = False
|
||||
self.xblock.due = datetime.datetime.now(UTC)
|
||||
self.xblock.graceperiod = Timedelta().from_json("0 seconds")
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body()
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
expected_response = {
|
||||
'action': None,
|
||||
@@ -218,10 +218,10 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
Grade returned from Tool Provider is outside the range 0.0-1.0.
|
||||
"""
|
||||
self.xmodule.verify_oauth_body_sign = Mock()
|
||||
self.xblock.verify_oauth_body_sign = Mock()
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body(params={'grade': '10'})
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
expected_response = {
|
||||
'action': None,
|
||||
@@ -236,10 +236,10 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
Grade returned from Tool Provider doesn't use a period as the decimal point.
|
||||
"""
|
||||
self.xmodule.verify_oauth_body_sign = Mock()
|
||||
self.xblock.verify_oauth_body_sign = Mock()
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body(params={'grade': '0,5'})
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
msg = "could not convert string to float: '0,5'"
|
||||
expected_response = {
|
||||
@@ -256,10 +256,10 @@ class LTIBlockTest(TestCase):
|
||||
Action returned from Tool Provider isn't supported.
|
||||
`replaceResultRequest` is supported only.
|
||||
"""
|
||||
self.xmodule.verify_oauth_body_sign = Mock()
|
||||
self.xblock.verify_oauth_body_sign = Mock()
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body({'action': 'wrongAction'})
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
real_response = self.get_response_values(response)
|
||||
expected_response = {
|
||||
'action': None,
|
||||
@@ -274,11 +274,11 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
Response from Tool Provider is correct.
|
||||
"""
|
||||
self.xmodule.verify_oauth_body_sign = Mock()
|
||||
self.xmodule.has_score = True
|
||||
self.xblock.verify_oauth_body_sign = Mock()
|
||||
self.xblock.has_score = True
|
||||
request = Request(self.environ)
|
||||
request.body = self.get_request_body()
|
||||
response = self.xmodule.grade_handler(request, '')
|
||||
response = self.xblock.grade_handler(request, '')
|
||||
description_expected = 'Score for {sourcedId} is now {score}'.format(
|
||||
sourcedId=self.defaults['sourcedId'],
|
||||
score=self.defaults['grade'],
|
||||
@@ -293,11 +293,11 @@ class LTIBlockTest(TestCase):
|
||||
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
assert self.xmodule.module_score == float(self.defaults['grade'])
|
||||
assert self.xblock.module_score == float(self.defaults['grade'])
|
||||
|
||||
def test_user_id(self):
|
||||
expected_user_id = str(parse.quote(self.xmodule.runtime.anonymous_student_id))
|
||||
real_user_id = self.xmodule.get_user_id()
|
||||
expected_user_id = str(parse.quote(self.xblock.runtime.anonymous_student_id))
|
||||
real_user_id = self.xblock.get_user_id()
|
||||
assert real_user_id == expected_user_id
|
||||
|
||||
def test_outcome_service_url(self):
|
||||
@@ -308,24 +308,24 @@ class LTIBlockTest(TestCase):
|
||||
"""Mock function for returning fully-qualified handler urls"""
|
||||
return mock_url_prefix + handler_name
|
||||
|
||||
self.xmodule.runtime.handler_url = Mock(side_effect=mock_handler_url)
|
||||
real_outcome_service_url = self.xmodule.get_outcome_service_url(service_name=test_service_name)
|
||||
self.xblock.runtime.handler_url = Mock(side_effect=mock_handler_url)
|
||||
real_outcome_service_url = self.xblock.get_outcome_service_url(service_name=test_service_name)
|
||||
assert real_outcome_service_url == (mock_url_prefix + test_service_name)
|
||||
|
||||
def test_resource_link_id(self):
|
||||
with patch('xmodule.lti_block.LTIBlock.location', new_callable=PropertyMock):
|
||||
self.xmodule.location.html_id = lambda: 'i4x-2-3-lti-31de800015cf4afb973356dbe81496df'
|
||||
self.xblock.location.html_id = lambda: 'i4x-2-3-lti-31de800015cf4afb973356dbe81496df'
|
||||
expected_resource_link_id = str(parse.quote(self.unquoted_resource_link_id))
|
||||
real_resource_link_id = self.xmodule.get_resource_link_id()
|
||||
real_resource_link_id = self.xblock.get_resource_link_id()
|
||||
assert real_resource_link_id == expected_resource_link_id
|
||||
|
||||
def test_lis_result_sourcedid(self):
|
||||
expected_sourced_id = ':'.join(parse.quote(i) for i in (
|
||||
str(self.course_id),
|
||||
self.xmodule.get_resource_link_id(),
|
||||
self.xblock.get_resource_link_id(),
|
||||
self.user_id
|
||||
))
|
||||
real_lis_result_sourcedid = self.xmodule.get_lis_result_sourcedid()
|
||||
real_lis_result_sourcedid = self.xblock.get_lis_result_sourcedid()
|
||||
assert real_lis_result_sourcedid == expected_sourced_id
|
||||
|
||||
def test_client_key_secret(self):
|
||||
@@ -337,9 +337,9 @@ class LTIBlockTest(TestCase):
|
||||
modulestore = Mock()
|
||||
modulestore.get_course.return_value = mocked_course
|
||||
runtime = Mock(modulestore=modulestore)
|
||||
self.xmodule.runtime = runtime
|
||||
self.xmodule.lti_id = "lti_id"
|
||||
key, secret = self.xmodule.get_client_key_secret()
|
||||
self.xblock.runtime = runtime
|
||||
self.xblock.lti_id = "lti_id"
|
||||
key, secret = self.xblock.get_client_key_secret()
|
||||
expected = ('test_client', 'test_secret')
|
||||
assert expected == (key, secret)
|
||||
|
||||
@@ -355,10 +355,10 @@ class LTIBlockTest(TestCase):
|
||||
modulestore = Mock()
|
||||
modulestore.get_course.return_value = mocked_course
|
||||
runtime = Mock(modulestore=modulestore)
|
||||
self.xmodule.runtime = runtime
|
||||
self.xblock.runtime = runtime
|
||||
# set another lti_id
|
||||
self.xmodule.lti_id = "another_lti_id"
|
||||
key_secret = self.xmodule.get_client_key_secret()
|
||||
self.xblock.lti_id = "another_lti_id"
|
||||
key_secret = self.xblock.get_client_key_secret()
|
||||
expected = ('', '')
|
||||
assert expected == key_secret
|
||||
|
||||
@@ -373,10 +373,10 @@ class LTIBlockTest(TestCase):
|
||||
modulestore = Mock()
|
||||
modulestore.get_course.return_value = mocked_course
|
||||
runtime = Mock(modulestore=modulestore)
|
||||
self.xmodule.runtime = runtime
|
||||
self.xmodule.lti_id = 'lti_id'
|
||||
self.xblock.runtime = runtime
|
||||
self.xblock.lti_id = 'lti_id'
|
||||
with pytest.raises(LTIError):
|
||||
self.xmodule.get_client_key_secret()
|
||||
self.xblock.get_client_key_secret()
|
||||
|
||||
@patch('xmodule.lti_block.signature.verify_hmac_sha1', Mock(return_value=True))
|
||||
@patch(
|
||||
@@ -387,7 +387,7 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
Test if OAuth signing was successful.
|
||||
"""
|
||||
self.xmodule.verify_oauth_body_sign(self.get_signed_grade_mock_request())
|
||||
self.xblock.verify_oauth_body_sign(self.get_signed_grade_mock_request())
|
||||
|
||||
@patch('xmodule.lti_block.LTIBlock.get_outcome_service_url', Mock(return_value='https://testurl/'))
|
||||
@patch('xmodule.lti_block.LTIBlock.get_client_key_secret',
|
||||
@@ -397,12 +397,12 @@ class LTIBlockTest(TestCase):
|
||||
Oauth signing verify fail.
|
||||
"""
|
||||
request = self.get_signed_grade_mock_request_with_correct_signature()
|
||||
self.xmodule.verify_oauth_body_sign(request)
|
||||
self.xblock.verify_oauth_body_sign(request)
|
||||
# we should verify against get_outcome_service_url not
|
||||
# request url proxy and load balancer along the way may
|
||||
# change url presented to the method
|
||||
request.url = 'http://testurl/'
|
||||
self.xmodule.verify_oauth_body_sign(request)
|
||||
self.xblock.verify_oauth_body_sign(request)
|
||||
|
||||
def get_signed_grade_mock_request_with_correct_signature(self):
|
||||
"""
|
||||
@@ -445,7 +445,7 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
with pytest.raises(IndexError):
|
||||
mocked_request = self.get_signed_grade_mock_request(namespace_lti_v1p1=False)
|
||||
self.xmodule.parse_grade_xml_body(mocked_request.body)
|
||||
self.xblock.parse_grade_xml_body(mocked_request.body)
|
||||
|
||||
def test_parse_grade_xml_body(self):
|
||||
"""
|
||||
@@ -454,7 +454,7 @@ class LTIBlockTest(TestCase):
|
||||
Tests that xml body was parsed successfully.
|
||||
"""
|
||||
mocked_request = self.get_signed_grade_mock_request()
|
||||
message_identifier, sourced_id, grade, action = self.xmodule.parse_grade_xml_body(mocked_request.body)
|
||||
message_identifier, sourced_id, grade, action = self.xblock.parse_grade_xml_body(mocked_request.body)
|
||||
assert self.defaults['messageIdentifier'] == message_identifier
|
||||
assert self.defaults['sourcedId'] == sourced_id
|
||||
assert self.defaults['grade'] == grade
|
||||
@@ -471,7 +471,7 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
with pytest.raises(LTIError):
|
||||
req = self.get_signed_grade_mock_request()
|
||||
self.xmodule.verify_oauth_body_sign(req)
|
||||
self.xblock.verify_oauth_body_sign(req)
|
||||
|
||||
def get_signed_grade_mock_request(self, namespace_lti_v1p1=True):
|
||||
"""
|
||||
@@ -507,11 +507,11 @@ class LTIBlockTest(TestCase):
|
||||
"""
|
||||
Custom parameters are presented in right format.
|
||||
"""
|
||||
self.xmodule.custom_parameters = ['test_custom_params=test_custom_param_value']
|
||||
self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xmodule.oauth_params = Mock()
|
||||
self.xmodule.get_input_fields()
|
||||
self.xmodule.oauth_params.assert_called_with(
|
||||
self.xblock.custom_parameters = ['test_custom_params=test_custom_param_value']
|
||||
self.xblock.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xblock.oauth_params = Mock()
|
||||
self.xblock.get_input_fields()
|
||||
self.xblock.oauth_params.assert_called_with(
|
||||
{'custom_test_custom_params': 'test_custom_param_value'},
|
||||
'test_client_key', 'test_client_secret'
|
||||
)
|
||||
@@ -521,24 +521,24 @@ class LTIBlockTest(TestCase):
|
||||
Custom parameters are presented in wrong format.
|
||||
"""
|
||||
bad_custom_params = ['test_custom_params: test_custom_param_value']
|
||||
self.xmodule.custom_parameters = bad_custom_params
|
||||
self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xmodule.oauth_params = Mock()
|
||||
self.xblock.custom_parameters = bad_custom_params
|
||||
self.xblock.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xblock.oauth_params = Mock()
|
||||
with pytest.raises(LTIError):
|
||||
self.xmodule.get_input_fields()
|
||||
self.xblock.get_input_fields()
|
||||
|
||||
def test_max_score(self):
|
||||
self.xmodule.weight = 100.0
|
||||
self.xblock.weight = 100.0
|
||||
|
||||
assert not self.xmodule.has_score
|
||||
assert self.xmodule.max_score() is None
|
||||
assert not self.xblock.has_score
|
||||
assert self.xblock.max_score() is None
|
||||
|
||||
self.xmodule.has_score = True
|
||||
self.xblock.has_score = True
|
||||
|
||||
assert self.xmodule.max_score() == 100.0
|
||||
assert self.xblock.max_score() == 100.0
|
||||
|
||||
def test_context_id(self):
|
||||
"""
|
||||
Tests that LTI parameter context_id is equal to course_id.
|
||||
"""
|
||||
assert str(self.course_id) == self.xmodule.context_id
|
||||
assert str(self.course_id) == self.xblock.context_id
|
||||
|
||||
@@ -30,13 +30,13 @@ class PollBlockTest(unittest.TestCase):
|
||||
usage_key = course_key.make_usage_key(PollBlock.category, 'test_loc')
|
||||
# ScopeIds has 4 fields: user_id, block_type, def_id, usage_id
|
||||
self.scope_ids = ScopeIds(1, PollBlock.category, usage_key, usage_key)
|
||||
self.xmodule = PollBlock(
|
||||
self.xblock = PollBlock(
|
||||
self.system, DictFieldData(self.raw_field_data), self.scope_ids
|
||||
)
|
||||
|
||||
def ajax_request(self, dispatch, data):
|
||||
"""Call Xmodule.handle_ajax."""
|
||||
return json.loads(self.xmodule.handle_ajax(dispatch, data))
|
||||
return json.loads(self.xblock.handle_ajax(dispatch, data))
|
||||
|
||||
def test_bad_ajax_request(self):
|
||||
# Make sure that answer for incorrect request is error json.
|
||||
@@ -54,16 +54,16 @@ class PollBlockTest(unittest.TestCase):
|
||||
self.assertDictEqual(poll_answers, {'Yes': 1, 'Dont_know': 0, 'No': 1})
|
||||
assert total == 2
|
||||
self.assertDictEqual(callback, {'objectName': 'Conditional'})
|
||||
assert self.xmodule.poll_answer == 'No'
|
||||
assert self.xblock.poll_answer == 'No'
|
||||
|
||||
def test_poll_export_with_unescaped_characters_xml(self):
|
||||
"""
|
||||
Make sure that poll_block will export fine if its xml contains
|
||||
unescaped characters.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
id_generator = Mock()
|
||||
id_generator.target_course_id = self.xmodule.course_id
|
||||
id_generator.target_course_id = self.xblock.course_id
|
||||
sample_poll_xml = '''
|
||||
<poll_question display_name="Poll Question">
|
||||
<p>How old are you?</p>
|
||||
|
||||
@@ -80,7 +80,7 @@ class RandomizeBlockTest(MixedSplitTestCase):
|
||||
# And compare.
|
||||
assert exported_olx == expected_olx
|
||||
|
||||
runtime = TestImportSystem(load_error_modules=True, course_id=randomize_block.location.course_key)
|
||||
runtime = TestImportSystem(load_error_blocks=True, course_id=randomize_block.location.course_key)
|
||||
runtime.resources_fs = export_fs
|
||||
|
||||
# Now import it.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Tests for sequence module.
|
||||
Tests for sequence block.
|
||||
"""
|
||||
# pylint: disable=no-member
|
||||
|
||||
@@ -34,7 +34,7 @@ COURSE_END_DATE = TODAY + timedelta(days=21)
|
||||
@ddt.ddt
|
||||
class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
"""
|
||||
Base class for tests of Sequence Module.
|
||||
Base class for tests of Sequence Block.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@@ -88,7 +88,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
|
||||
def _set_up_block(self, parent, index_in_parent):
|
||||
"""
|
||||
Sets up the stub sequence module for testing.
|
||||
Sets up the stub sequence block for testing.
|
||||
"""
|
||||
block = parent.get_children()[index_in_parent]
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Tests for the Split Testing Module
|
||||
Tests for the Split Testing Block
|
||||
"""
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
@@ -35,7 +35,7 @@ class SplitTestBlockFactory(xml.XmlImportFactory):
|
||||
|
||||
class SplitTestUtilitiesTest(PartitionTestCase):
|
||||
"""
|
||||
Tests for utility methods related to split_test module.
|
||||
Tests for utility methods related to split_test block.
|
||||
"""
|
||||
|
||||
def test_split_user_partitions(self):
|
||||
@@ -585,7 +585,7 @@ class SplitTestBlockExportImportTest(MixedSplitTestCase):
|
||||
# And compare.
|
||||
assert exported_olx == expected_olx
|
||||
|
||||
runtime = TestImportSystem(load_error_modules=True, course_id=split_test_block.location.course_key)
|
||||
runtime = TestImportSystem(load_error_blocks=True, course_id=split_test_block.location.course_key)
|
||||
runtime.resources_fs = export_fs
|
||||
|
||||
# Now import it.
|
||||
|
||||
@@ -104,7 +104,7 @@ class YoutubeVideoHTMLResponse:
|
||||
|
||||
class TranscriptsUtilsTest(TestCase):
|
||||
"""
|
||||
Tests utility fucntions for transcripts (in video_module)
|
||||
Tests utility fucntions for transcripts (in video_block)
|
||||
"""
|
||||
|
||||
@mock.patch('requests.get')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Tests for vertical module.
|
||||
Tests for vertical block.
|
||||
"""
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@@ -89,7 +89,7 @@ class BaseVerticalBlockTest(XModuleXmlImportTest):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# construct module: course/sequence/vertical - problems
|
||||
# construct block: course/sequence/vertical - problems
|
||||
# \_ nested_vertical / problems
|
||||
course = xml.CourseFactory.build()
|
||||
sequence = xml.SequenceFactory.build(parent=course)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# pylint: disable=protected-access
|
||||
"""Test for Video Xmodule functional logic.
|
||||
"""Test for Video XBlock functional logic.
|
||||
These test data read from xml, not from mongo.
|
||||
|
||||
We have a ModuleStoreTestCase class defined in
|
||||
@@ -282,7 +282,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
})
|
||||
|
||||
def test_parse_xml(self):
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '''
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8"
|
||||
@@ -327,7 +327,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
Test that if handout link is course_asset then it will contain targeted course_id in handout link.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
course_id = CourseKey.from_string(course_id_string)
|
||||
xml_data = '''
|
||||
<video display_name="Test Video"
|
||||
@@ -371,7 +371,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
Ensure that attributes have the right values if they aren't
|
||||
explicitly set in XML.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '''
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:p2Q6BrNhdh8,1.25:1EeWXzPdhSA"
|
||||
@@ -402,7 +402,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
Ensure that attributes have the right values if they aren't
|
||||
explicitly set in XML.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '''
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:p2Q6BrNhdh8,1.25:1EeWXzPdhSA"
|
||||
@@ -433,7 +433,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
Make sure settings are correct if none are explicitly set in XML.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '<video></video>'
|
||||
xml_object = etree.fromstring(xml_data)
|
||||
output = VideoBlock.parse_xml(xml_object, module_system, None, Mock())
|
||||
@@ -459,7 +459,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
Make sure we can handle the double-quoted string format (which was used for exporting for
|
||||
a few weeks).
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '''
|
||||
<video display_name=""display_name""
|
||||
html5_sources="["source_1", "source_2"]"
|
||||
@@ -494,7 +494,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
})
|
||||
|
||||
def test_parse_xml_double_quote_concatenated_youtube(self):
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = '''
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:"p2Q6BrNhdh8",1.25:"1EeWXzPdhSA"">
|
||||
@@ -522,7 +522,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
Test backwards compatibility with VideoBlock's XML format.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = """
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8"
|
||||
@@ -554,7 +554,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
Ensure that Video is able to read VideoBlock's model data.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = """
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8"
|
||||
@@ -585,7 +585,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
Ensure that Video is able to read VideoBlock's model data.
|
||||
"""
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
xml_data = """
|
||||
<video display_name="Test Video"
|
||||
youtube="1.0:p2Q6BrNhdh8,0.75:izygArpw-Qo,1.25:1EeWXzPdhSA,1.5:rABDYkeK0x8"
|
||||
@@ -630,7 +630,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
|
||||
edx_video_id = 'test_edx_video_id'
|
||||
mock_val_api.import_from_xml = Mock(wraps=mock_val_import)
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
|
||||
# Create static directory in import file system and place transcript files inside it.
|
||||
module_system.resources_fs.makedirs(EXPORT_IMPORT_STATIC_DIR, recreate=True)
|
||||
@@ -662,7 +662,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
def test_import_val_data_invalid(self, mock_val_api):
|
||||
mock_val_api.ValCannotCreateError = _MockValCannotCreateError
|
||||
mock_val_api.import_from_xml = Mock(side_effect=mock_val_api.ValCannotCreateError)
|
||||
module_system = DummySystem(load_error_modules=True)
|
||||
module_system = DummySystem(load_error_blocks=True)
|
||||
|
||||
# Negative duration is invalid
|
||||
xml_data = """
|
||||
|
||||
Reference in New Issue
Block a user