Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
edx-platform-release
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Hsin-Yu Chien
edx-platform-release
Commits
2314c609
Commit
2314c609
authored
12 years ago
by
brianhw
Browse files
Options
Downloads
Plain Diff
Merge pull request #1859 from MITx/fix/brian/conditional-error
cope with ErrorModule as source (or required) module, and add tests.
parents
976b7192
7486e0f6
Loading
Loading
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
common/lib/xmodule/xmodule/conditional_module.py
+16
-13
16 additions, 13 deletions
common/lib/xmodule/xmodule/conditional_module.py
common/lib/xmodule/xmodule/tests/test_conditional.py
+117
-12
117 additions, 12 deletions
common/lib/xmodule/xmodule/tests/test_conditional.py
with
133 additions
and
25 deletions
common/lib/xmodule/xmodule/conditional_module.py
+
16
−
13
View file @
2314c609
...
...
@@ -92,9 +92,13 @@ class ConditionalModule(ConditionalFields, XModule):
if
xml_value
and
self
.
required_modules
:
for
module
in
self
.
required_modules
:
if
not
hasattr
(
module
,
attr_name
):
raise
Exception
(
'
Error in conditional module:
\
required module {module} has no {module_attr}
'
.
format
(
module
=
module
,
module_attr
=
attr_name
))
# We don't throw an exception here because it is possible for
# the descriptor of a required module to have a property but
# for the resulting module to be a (flavor of) ErrorModule.
# So just log and return false.
log
.
warn
(
'
Error in conditional module:
\
required module {module} has no {module_attr}
'
.
format
(
module
=
module
,
module_attr
=
attr_name
))
return
False
attr
=
getattr
(
module
,
attr_name
)
if
callable
(
attr
):
...
...
@@ -137,16 +141,15 @@ class ConditionalModule(ConditionalFields, XModule):
def
get_icon_class
(
self
):
new_class
=
'
other
'
if
self
.
is_condition_satisfied
():
# HACK: This shouldn't be hard-coded to two types
# OBSOLETE: This obsoletes 'type'
class_priority
=
[
'
video
'
,
'
problem
'
]
child_classes
=
[
self
.
system
.
get_module
(
child_descriptor
).
get_icon_class
()
for
child_descriptor
in
self
.
descriptor
.
get_children
()]
for
c
in
class_priority
:
if
c
in
child_classes
:
new_class
=
c
# HACK: This shouldn't be hard-coded to two types
# OBSOLETE: This obsoletes 'type'
class_priority
=
[
'
video
'
,
'
problem
'
]
child_classes
=
[
self
.
system
.
get_module
(
child_descriptor
).
get_icon_class
()
for
child_descriptor
in
self
.
descriptor
.
get_children
()]
for
c
in
class_priority
:
if
c
in
child_classes
:
new_class
=
c
return
new_class
...
...
This diff is collapsed.
Click to expand it.
common/lib/xmodule/xmodule/tests/test_conditional.py
+
117
−
12
View file @
2314c609
import
json
from
path
import
path
import
unittest
from
fs.memoryfs
import
MemoryFS
from
lxml
import
etree
from
ast
import
literal_eval
from
mock
import
Mock
,
patch
from
collections
import
defaultdict
from
xmodule.x_module
import
XMLParsingSystem
,
XModuleDescriptor
from
xmodule.xml_module
import
is_pointer_tag
from
xmodule.errortracker
import
make_error_tracker
from
xmodule.error_module
import
NonStaffErrorDescriptor
from
xmodule.modulestore
import
Location
from
xmodule.modulestore.xml
import
ImportSystem
,
XMLModuleStore
from
xmodule.
modulestore.exceptions
import
ItemNotFoundError
from
xmodule.
conditional_module
import
ConditionalModule
from
.test_export
import
DATA_DIR
from
xmodule.tests
.test_export
import
DATA_DIR
ORG
=
'
test_org
'
COURSE
=
'
conditional
'
# name of directory with course data
COURSE
=
'
conditional
'
# name of directory with course data
from
.
import
test_system
...
...
@@ -47,10 +43,118 @@ class DummySystem(ImportSystem):
def
render_template
(
self
,
template
,
context
):
raise
Exception
(
"
Shouldn
'
t be called
"
)
class
ConditionalFactory
(
object
):
"""
A helper class to create a conditional module and associated source and child modules
to allow for testing.
"""
@staticmethod
def
create
(
system
,
source_is_error_module
=
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
'
.
if the source_is_error_module flag is set, create a real ErrorModule for the source.
"""
# construct source descriptor and module:
source_location
=
Location
([
"
i4x
"
,
"
edX
"
,
"
conditional_test
"
,
"
problem
"
,
"
SampleProblem
"
])
if
source_is_error_module
:
# Make an error descriptor and module
source_descriptor
=
NonStaffErrorDescriptor
.
from_xml
(
'
some random xml data
'
,
system
,
org
=
source_location
.
org
,
course
=
source_location
.
course
,
error_msg
=
'
random error message
'
)
source_module
=
source_descriptor
.
xmodule
(
system
)
else
:
source_descriptor
=
Mock
()
source_descriptor
.
location
=
source_location
source_module
=
Mock
()
# construct other descriptors:
child_descriptor
=
Mock
()
cond_descriptor
=
Mock
()
cond_descriptor
.
get_required_module_descriptors
=
lambda
:
[
source_descriptor
,
]
cond_descriptor
.
get_children
=
lambda
:
[
child_descriptor
,
]
cond_descriptor
.
xml_attributes
=
{
"
attempted
"
:
"
true
"
}
# create child module:
child_module
=
Mock
()
child_module
.
get_html
=
lambda
:
'
<p>This is a secret</p>
'
child_module
.
displayable_items
=
lambda
:
[
child_module
]
module_map
=
{
source_descriptor
:
source_module
,
child_descriptor
:
child_module
}
system
.
get_module
=
lambda
descriptor
:
module_map
[
descriptor
]
# construct conditional module:
cond_location
=
Location
([
"
i4x
"
,
"
edX
"
,
"
conditional_test
"
,
"
conditional
"
,
"
SampleConditional
"
])
model_data
=
{
'
data
'
:
'
<conditional/>
'
}
cond_module
=
ConditionalModule
(
system
,
cond_location
,
cond_descriptor
,
model_data
)
# return dict:
return
{
'
cond_module
'
:
cond_module
,
'
source_module
'
:
source_module
,
'
child_module
'
:
child_module
}
class
ConditionalModuleBasicTest
(
unittest
.
TestCase
):
"""
Make sure that conditional module works, using mocks for
other modules.
"""
def
setUp
(
self
):
self
.
test_system
=
test_system
()
def
test_icon_class
(
self
):
'''
verify that get_icon_class works independent of condition satisfaction
'''
modules
=
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
self
.
assertEqual
(
modules
[
'
cond_module
'
].
get_icon_class
(),
icon_class
)
def
test_get_html
(
self
):
modules
=
ConditionalFactory
.
create
(
self
.
test_system
)
# because test_system returns the repr of the context dict passed to render_template,
# we reverse it here
html
=
modules
[
'
cond_module
'
].
get_html
()
html_dict
=
literal_eval
(
html
)
self
.
assertEqual
(
html_dict
[
'
element_id
'
],
'
i4x-edX-conditional_test-conditional-SampleConditional
'
)
self
.
assertEqual
(
html_dict
[
'
id
'
],
'
i4x://edX/conditional_test/conditional/SampleConditional
'
)
self
.
assertEqual
(
html_dict
[
'
depends
'
],
'
i4x-edX-conditional_test-problem-SampleProblem
'
)
def
test_handle_ajax
(
self
):
modules
=
ConditionalFactory
.
create
(
self
.
test_system
)
modules
[
'
source_module
'
].
is_attempted
=
"
false
"
ajax
=
json
.
loads
(
modules
[
'
cond_module
'
].
handle_ajax
(
''
,
''
))
print
"
ajax:
"
,
ajax
html
=
ajax
[
'
html
'
]
self
.
assertFalse
(
any
([
'
This is a secret
'
in
item
for
item
in
html
]))
# 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
(
''
,
''
))
print
"
post-attempt ajax:
"
,
ajax
html
=
ajax
[
'
html
'
]
self
.
assertTrue
(
any
([
'
This is a secret
'
in
item
for
item
in
html
]))
def
test_error_as_source
(
self
):
'''
Check that handle_ajax works properly if the source is really an ErrorModule,
and that the condition is not satisfied.
'''
modules
=
ConditionalFactory
.
create
(
self
.
test_system
,
source_is_error_module
=
True
)
ajax
=
json
.
loads
(
modules
[
'
cond_module
'
].
handle_ajax
(
''
,
''
))
html
=
ajax
[
'
html
'
]
self
.
assertFalse
(
any
([
'
This is a secret
'
in
item
for
item
in
html
]))
class
ConditionalModuleTest
(
unittest
.
TestCase
):
class
ConditionalModuleXmlTest
(
unittest
.
TestCase
):
"""
Make sure ConditionalModule works, by loading data in from an XML-defined course.
"""
@staticmethod
def
get_system
(
load_error_modules
=
True
):
'''
Get a dummy system
'''
...
...
@@ -106,7 +210,7 @@ class ConditionalModuleTest(unittest.TestCase):
html_expect
=
"
{
'
ajax_url
'
:
'
courses/course_id/modx/a_location
'
,
'
element_id
'
:
'
i4x-HarvardX-ER22x-conditional-condone
'
,
'
id
'
:
'
i4x://HarvardX/ER22x/conditional/condone
'
,
'
depends
'
:
'
i4x-HarvardX-ER22x-problem-choiceprob
'
}
"
self
.
assertEqual
(
html
,
html_expect
)
gdi
=
module
.
get_display_items
()
gdi
=
module
.
get_display_items
()
print
"
gdi=
"
,
gdi
ajax
=
json
.
loads
(
module
.
handle_ajax
(
''
,
''
))
...
...
@@ -121,3 +225,4 @@ class ConditionalModuleTest(unittest.TestCase):
print
"
post-attempt ajax:
"
,
ajax
html
=
ajax
[
'
html
'
]
self
.
assertTrue
(
any
([
'
This is a secret
'
in
item
for
item
in
html
]))
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment