Merge pull request #528 from edx/dhm/rename_revision
Rename CourseLocator.revision to branch
This commit is contained in:
@@ -127,7 +127,7 @@ class TemplateTests(unittest.TestCase):
|
||||
persistent_factories.ItemFactory.create(display_name='chapter 1',
|
||||
parent_location=test_course.location)
|
||||
|
||||
id_locator = CourseLocator(course_id=test_course.location.course_id, revision='draft')
|
||||
id_locator = CourseLocator(course_id=test_course.location.course_id, branch='draft')
|
||||
guid_locator = CourseLocator(version_guid=test_course.location.version_guid)
|
||||
# verify it can be retireved by id
|
||||
self.assertIsInstance(modulestore('split').get_course(id_locator), CourseDescriptor)
|
||||
|
||||
@@ -45,7 +45,7 @@ class Locator(object):
|
||||
|
||||
def __repr__(self):
|
||||
'''
|
||||
repr(self) returns something like this: CourseLocator("edu.mit.eecs.6002x")
|
||||
repr(self) returns something like this: CourseLocator("mit.eecs.6002x")
|
||||
'''
|
||||
classname = self.__class__.__name__
|
||||
if classname.find('.') != -1:
|
||||
@@ -54,13 +54,13 @@ class Locator(object):
|
||||
|
||||
def __str__(self):
|
||||
'''
|
||||
str(self) returns something like this: "edu.mit.eecs.6002x"
|
||||
str(self) returns something like this: "mit.eecs.6002x"
|
||||
'''
|
||||
return unicode(self).encode('utf8')
|
||||
|
||||
def __unicode__(self):
|
||||
'''
|
||||
unicode(self) returns something like this: "edu.mit.eecs.6002x"
|
||||
unicode(self) returns something like this: "mit.eecs.6002x"
|
||||
'''
|
||||
return self.url()
|
||||
|
||||
@@ -89,15 +89,15 @@ class CourseLocator(Locator):
|
||||
"""
|
||||
Examples of valid CourseLocator specifications:
|
||||
CourseLocator(version_guid=ObjectId('519665f6223ebd6980884f2b'))
|
||||
CourseLocator(course_id='edu.mit.eecs.6002x')
|
||||
CourseLocator(course_id='edu.mit.eecs.6002x;published')
|
||||
CourseLocator(course_id='edu.mit.eecs.6002x', revision='published')
|
||||
CourseLocator(course_id='mit.eecs.6002x')
|
||||
CourseLocator(course_id='mit.eecs.6002x;published')
|
||||
CourseLocator(course_id='mit.eecs.6002x', branch='published')
|
||||
CourseLocator(url='edx://@519665f6223ebd6980884f2b')
|
||||
CourseLocator(url='edx://edu.mit.eecs.6002x')
|
||||
CourseLocator(url='edx://edu.mit.eecs.6002x;published')
|
||||
CourseLocator(url='edx://mit.eecs.6002x')
|
||||
CourseLocator(url='edx://mit.eecs.6002x;published')
|
||||
|
||||
Should have at lease a specific course_id (id for the course as if it were a project w/
|
||||
versions) with optional 'revision' (must be 'draft', 'published', or None),
|
||||
versions) with optional 'branch',
|
||||
or version_guid (which points to a specific version). Can contain both in which case
|
||||
the persistence layer may raise exceptions if the given version != the current such version
|
||||
of the course.
|
||||
@@ -106,7 +106,7 @@ class CourseLocator(Locator):
|
||||
# Default values
|
||||
version_guid = None
|
||||
course_id = None
|
||||
revision = None
|
||||
branch = None
|
||||
|
||||
def __unicode__(self):
|
||||
"""
|
||||
@@ -114,8 +114,8 @@ class CourseLocator(Locator):
|
||||
"""
|
||||
if self.course_id:
|
||||
result = self.course_id
|
||||
if self.revision:
|
||||
result += ';' + self.revision
|
||||
if self.branch:
|
||||
result += ';' + self.branch
|
||||
return result
|
||||
elif self.version_guid:
|
||||
return '@' + str(self.version_guid)
|
||||
@@ -131,7 +131,7 @@ class CourseLocator(Locator):
|
||||
|
||||
# -- unused args which are used via inspect
|
||||
# pylint: disable= W0613
|
||||
def validate_args(self, url, version_guid, course_id, revision):
|
||||
def validate_args(self, url, version_guid, course_id, branch):
|
||||
"""
|
||||
Validate provided arguments.
|
||||
"""
|
||||
@@ -144,12 +144,12 @@ class CourseLocator(Locator):
|
||||
|
||||
def is_fully_specified(self):
|
||||
"""
|
||||
Returns True if either version_guid is specified, or course_id+revision
|
||||
Returns True if either version_guid is specified, or course_id+branch
|
||||
are specified.
|
||||
This should always return True, since this should be validated in the constructor.
|
||||
"""
|
||||
return self.version_guid is not None \
|
||||
or (self.course_id is not None and self.revision is not None)
|
||||
or (self.course_id is not None and self.branch is not None)
|
||||
|
||||
def set_course_id(self, new):
|
||||
"""
|
||||
@@ -158,12 +158,12 @@ class CourseLocator(Locator):
|
||||
"""
|
||||
self.set_property('course_id', new)
|
||||
|
||||
def set_revision(self, new):
|
||||
def set_branch(self, new):
|
||||
"""
|
||||
Initialize revision to new value.
|
||||
If revision has already been initialized to a different value, raise an exception.
|
||||
Initialize branch to new value.
|
||||
If branch has already been initialized to a different value, raise an exception.
|
||||
"""
|
||||
self.set_property('revision', new)
|
||||
self.set_property('branch', new)
|
||||
|
||||
def set_version_guid(self, new):
|
||||
"""
|
||||
@@ -181,29 +181,29 @@ class CourseLocator(Locator):
|
||||
"""
|
||||
return CourseLocator(course_id=self.course_id,
|
||||
version_guid=self.version_guid,
|
||||
revision=self.revision)
|
||||
branch=self.branch)
|
||||
|
||||
def __init__(self, url=None, version_guid=None, course_id=None, revision=None):
|
||||
def __init__(self, url=None, version_guid=None, course_id=None, branch=None):
|
||||
"""
|
||||
Construct a CourseLocator
|
||||
Caller may provide url (but no other parameters).
|
||||
Caller may provide version_guid (but no other parameters).
|
||||
Caller may provide course_id (optionally provide revision).
|
||||
Caller may provide course_id (optionally provide branch).
|
||||
|
||||
Resulting CourseLocator will have either a version_guid property
|
||||
or a course_id (with optional revision) property, or both.
|
||||
or a course_id (with optional branch) property, or both.
|
||||
|
||||
version_guid must be an instance of bson.objectid.ObjectId or None
|
||||
url, course_id, and revision must be strings or None
|
||||
url, course_id, and branch must be strings or None
|
||||
|
||||
"""
|
||||
self.validate_args(url, version_guid, course_id, revision)
|
||||
self.validate_args(url, version_guid, course_id, branch)
|
||||
if url:
|
||||
self.init_from_url(url)
|
||||
if version_guid:
|
||||
self.init_from_version_guid(version_guid)
|
||||
if course_id or revision:
|
||||
self.init_from_course_id(course_id, revision)
|
||||
if course_id or branch:
|
||||
self.init_from_course_id(course_id, branch)
|
||||
assert self.version_guid or self.course_id, \
|
||||
"Either version_guid or course_id should be set."
|
||||
|
||||
@@ -223,7 +223,7 @@ class CourseLocator(Locator):
|
||||
def init_from_url(self, url):
|
||||
"""
|
||||
url must be a string beginning with 'edx://' and containing
|
||||
either a valid version_guid or course_id (with optional revision)
|
||||
either a valid version_guid or course_id (with optional branch)
|
||||
If a block ('#HW3') is present, it is ignored.
|
||||
"""
|
||||
if isinstance(url, Locator):
|
||||
@@ -237,7 +237,7 @@ class CourseLocator(Locator):
|
||||
self.set_version_guid(self.as_object_id(new_guid))
|
||||
else:
|
||||
self.set_course_id(parse['id'])
|
||||
self.set_revision(parse['revision'])
|
||||
self.set_branch(parse['branch'])
|
||||
|
||||
def init_from_version_guid(self, version_guid):
|
||||
"""
|
||||
@@ -251,14 +251,14 @@ class CourseLocator(Locator):
|
||||
'%s is not an instance of ObjectId' % version_guid
|
||||
self.set_version_guid(version_guid)
|
||||
|
||||
def init_from_course_id(self, course_id, explicit_revision=None):
|
||||
def init_from_course_id(self, course_id, explicit_branch=None):
|
||||
"""
|
||||
Course_id is a string like 'edu.mit.eecs.6002x' or 'edu.mit.eecs.6002x;published'.
|
||||
Course_id is a string like 'mit.eecs.6002x' or 'mit.eecs.6002x;published'.
|
||||
|
||||
Revision (optional) is a string like 'published'.
|
||||
It may be provided explicitly (explicit_revision) or embedded into course_id.
|
||||
If revision is part of course_id ("...;published"), parse it out separately.
|
||||
If revision is provided both ways, that's ok as long as they are the same value.
|
||||
It may be provided explicitly (explicit_branch) or embedded into course_id.
|
||||
If branch is part of course_id ("...;published"), parse it out separately.
|
||||
If branch is provided both ways, that's ok as long as they are the same value.
|
||||
|
||||
If a block ('#HW3') is a part of course_id, it is ignored.
|
||||
|
||||
@@ -272,11 +272,11 @@ class CourseLocator(Locator):
|
||||
parse = parse_course_id(course_id)
|
||||
assert parse, 'Could not parse "%s" as a course_id' % course_id
|
||||
self.set_course_id(parse['id'])
|
||||
rev = parse['revision']
|
||||
rev = parse['branch']
|
||||
if rev:
|
||||
self.set_revision(rev)
|
||||
if explicit_revision:
|
||||
self.set_revision(explicit_revision)
|
||||
self.set_branch(rev)
|
||||
if explicit_branch:
|
||||
self.set_branch(explicit_branch)
|
||||
|
||||
def version(self):
|
||||
"""
|
||||
@@ -305,37 +305,37 @@ class BlockUsageLocator(CourseLocator):
|
||||
the defined element in the course. Courses can be a version of an offering, the
|
||||
current draft head, or the current production version.
|
||||
|
||||
Locators can contain both a version and a course_id w/ revision. The split mongo functions
|
||||
may raise errors if these conflict w/ the current db state (i.e., the course's revision !=
|
||||
Locators can contain both a version and a course_id w/ branch. The split mongo functions
|
||||
may raise errors if these conflict w/ the current db state (i.e., the course's branch !=
|
||||
the version_guid)
|
||||
|
||||
Locations can express as urls as well as dictionaries. They consist of
|
||||
course_identifier: course_guid | version_guid
|
||||
block : guid
|
||||
revision : 'draft' | 'published' (optional)
|
||||
branch : string
|
||||
"""
|
||||
|
||||
# Default value
|
||||
usage_id = None
|
||||
|
||||
def __init__(self, url=None, version_guid=None, course_id=None,
|
||||
revision=None, usage_id=None):
|
||||
branch=None, usage_id=None):
|
||||
"""
|
||||
Construct a BlockUsageLocator
|
||||
Caller may provide url, version_guid, or course_id, and optionally provide revision.
|
||||
Caller may provide url, version_guid, or course_id, and optionally provide branch.
|
||||
|
||||
The usage_id may be specified, either explictly or as part of
|
||||
the url or course_id. If omitted, the locator is created but it
|
||||
has not yet been initialized.
|
||||
|
||||
Resulting BlockUsageLocator will have a usage_id property.
|
||||
It will have either a version_guid property or a course_id (with optional revision) property, or both.
|
||||
It will have either a version_guid property or a course_id (with optional branch) property, or both.
|
||||
|
||||
version_guid must be an instance of bson.objectid.ObjectId or None
|
||||
url, course_id, revision, and usage_id must be strings or None
|
||||
url, course_id, branch, and usage_id must be strings or None
|
||||
|
||||
"""
|
||||
self.validate_args(url, version_guid, course_id, revision)
|
||||
self.validate_args(url, version_guid, course_id, branch)
|
||||
if url:
|
||||
self.init_block_ref_from_url(url)
|
||||
if course_id:
|
||||
@@ -346,7 +346,7 @@ class BlockUsageLocator(CourseLocator):
|
||||
url=url,
|
||||
version_guid=version_guid,
|
||||
course_id=course_id,
|
||||
revision=revision)
|
||||
branch=branch)
|
||||
|
||||
def is_initialized(self):
|
||||
"""
|
||||
@@ -366,11 +366,11 @@ class BlockUsageLocator(CourseLocator):
|
||||
"""
|
||||
if self.course_id and self.version_guid:
|
||||
return BlockUsageLocator(version_guid=self.version_guid,
|
||||
revision=self.revision,
|
||||
branch=self.branch,
|
||||
usage_id=self.usage_id)
|
||||
else:
|
||||
return BlockUsageLocator(course_id=self.course_id,
|
||||
revision=self.revision,
|
||||
branch=self.branch,
|
||||
usage_id=self.usage_id)
|
||||
|
||||
def set_usage_id(self, new):
|
||||
|
||||
@@ -20,7 +20,7 @@ def parse_url(string):
|
||||
with key 'version_guid' and the value,
|
||||
|
||||
If it can be parsed as a course_id, returns a dict
|
||||
with keys 'id' and 'revision' (value of 'revision' may be None),
|
||||
with keys 'id' and 'branch' (value of 'branch' may be None),
|
||||
|
||||
"""
|
||||
match = URL_RE.match(string)
|
||||
@@ -69,14 +69,14 @@ def parse_guid(string):
|
||||
return None
|
||||
|
||||
|
||||
COURSE_ID_RE = re.compile(r'^(?P<id>(\w+)(\.\w+\w*)*)(;(?P<revision>\w+))?(#(?P<block>\w+))?$', re.IGNORECASE)
|
||||
COURSE_ID_RE = re.compile(r'^(?P<id>(\w+)(\.\w+\w*)*)(;(?P<branch>\w+))?(#(?P<block>\w+))?$', re.IGNORECASE)
|
||||
|
||||
|
||||
def parse_course_id(string):
|
||||
r"""
|
||||
|
||||
A course_id has a main id component.
|
||||
There may also be an optional revision (;published or ;draft).
|
||||
There may also be an optional branch (;published or ;draft).
|
||||
There may also be an optional block (#HW3 or #Quiz2).
|
||||
|
||||
Examples of valid course_ids:
|
||||
@@ -89,11 +89,11 @@ def parse_course_id(string):
|
||||
|
||||
Syntax:
|
||||
|
||||
course_id = main_id [; revision] [# block]
|
||||
course_id = main_id [; branch] [# block]
|
||||
|
||||
main_id = name [. name]*
|
||||
|
||||
revision = name
|
||||
branch = name
|
||||
|
||||
block = name
|
||||
|
||||
@@ -104,8 +104,8 @@ def parse_course_id(string):
|
||||
and the underscore. (see definition of \w in python regular expressions,
|
||||
at http://docs.python.org/dev/library/re.html)
|
||||
|
||||
If string is a course_id, returns a dict with keys 'id', 'revision', and 'block'.
|
||||
Revision is optional: if missing returned_dict['revision'] is None.
|
||||
If string is a course_id, returns a dict with keys 'id', 'branch', and 'block'.
|
||||
Revision is optional: if missing returned_dict['branch'] is None.
|
||||
Block is optional: if missing returned_dict['block'] is None.
|
||||
Else returns None.
|
||||
"""
|
||||
|
||||
@@ -81,7 +81,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
|
||||
version_guid=course_entry_override['_id'],
|
||||
usage_id=usage_id,
|
||||
course_id=course_entry_override.get('course_id'),
|
||||
revision=course_entry_override.get('revision')
|
||||
branch=course_entry_override.get('branch')
|
||||
)
|
||||
|
||||
kvs = SplitMongoKVS(
|
||||
|
||||
@@ -186,8 +186,8 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
return the CourseDescriptor! It returns the actual db json from
|
||||
structures.
|
||||
|
||||
Semantics: if course_id and revision given, then it will get that revision. If
|
||||
also give a version_guid, it will see if the current head of that revision == that guid. If not
|
||||
Semantics: if course_id and branch given, then it will get that branch. If
|
||||
also give a version_guid, it will see if the current head of that branch == that guid. If not
|
||||
it raises VersionConflictError (the version now differs from what it was when you got your
|
||||
reference)
|
||||
|
||||
@@ -198,19 +198,19 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
if not course_locator.is_fully_specified():
|
||||
raise InsufficientSpecificationError('Not fully specified: %s' % course_locator)
|
||||
|
||||
if course_locator.course_id is not None and course_locator.revision is not None:
|
||||
if course_locator.course_id is not None and course_locator.branch is not None:
|
||||
# use the course_id
|
||||
index = self.course_index.find_one({'_id': course_locator.course_id})
|
||||
if index is None:
|
||||
raise ItemNotFoundError(course_locator)
|
||||
if course_locator.revision not in index['versions']:
|
||||
if course_locator.branch not in index['versions']:
|
||||
raise ItemNotFoundError(course_locator)
|
||||
version_guid = index['versions'][course_locator.revision]
|
||||
version_guid = index['versions'][course_locator.branch]
|
||||
if course_locator.version_guid is not None and version_guid != course_locator.version_guid:
|
||||
# This may be a bit too touchy but it's hard to infer intent
|
||||
raise VersionConflictError(course_locator, CourseLocator(course_locator, version_guid=version_guid))
|
||||
else:
|
||||
# TODO should this raise an exception if revision was provided?
|
||||
# TODO should this raise an exception if branch was provided?
|
||||
version_guid = course_locator.version_guid
|
||||
|
||||
# cast string to ObjectId if necessary
|
||||
@@ -223,29 +223,29 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
|
||||
if course_locator.course_id:
|
||||
entry['course_id'] = course_locator.course_id
|
||||
entry['revision'] = course_locator.revision
|
||||
entry['branch'] = course_locator.branch
|
||||
return entry
|
||||
|
||||
def get_courses(self, revision, qualifiers=None):
|
||||
def get_courses(self, branch, qualifiers=None):
|
||||
'''
|
||||
Returns a list of course descriptors matching any given qualifiers.
|
||||
|
||||
qualifiers should be a dict of keywords matching the db fields or any
|
||||
legal query for mongo to use against the active_versions collection.
|
||||
|
||||
Note, this is to find the current head of the named revision type
|
||||
Note, this is to find the current head of the named branch type
|
||||
(e.g., 'draft'). To get specific versions via guid use get_course.
|
||||
'''
|
||||
if qualifiers is None:
|
||||
qualifiers = {}
|
||||
qualifiers.update({"versions.{}".format(revision): {"$exists": True}})
|
||||
qualifiers.update({"versions.{}".format(branch): {"$exists": True}})
|
||||
matching = self.course_index.find(qualifiers)
|
||||
|
||||
# collect ids and then query for those
|
||||
version_guids = []
|
||||
id_version_map = {}
|
||||
for course_entry in matching:
|
||||
version_guid = course_entry['versions'][revision]
|
||||
version_guid = course_entry['versions'][branch]
|
||||
version_guids.append(version_guid)
|
||||
id_version_map[version_guid] = course_entry['_id']
|
||||
|
||||
@@ -667,7 +667,7 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
|
||||
# update the index entry if appropriate
|
||||
if index_entry is not None:
|
||||
self._update_head(index_entry, course_or_parent_locator.revision, new_id)
|
||||
self._update_head(index_entry, course_or_parent_locator.branch, new_id)
|
||||
course_parent = course_or_parent_locator.as_course_locator()
|
||||
else:
|
||||
course_parent = None
|
||||
@@ -786,7 +786,7 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
'edited_on': datetime.datetime.utcnow(),
|
||||
'versions': versions_dict}
|
||||
new_id = self.course_index.insert(index_entry)
|
||||
return self.get_course(CourseLocator(course_id=new_id, revision=master_version))
|
||||
return self.get_course(CourseLocator(course_id=new_id, branch=master_version))
|
||||
|
||||
def update_item(self, descriptor, user_id, force=False):
|
||||
"""
|
||||
@@ -835,7 +835,7 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
|
||||
# update the index entry if appropriate
|
||||
if index_entry is not None:
|
||||
self._update_head(index_entry, descriptor.location.revision, new_id)
|
||||
self._update_head(index_entry, descriptor.location.branch, new_id)
|
||||
|
||||
# fetch and return the new item--fetching is unnecessary but a good qc step
|
||||
return self.get_item(BlockUsageLocator(descriptor.location, version_guid=new_id))
|
||||
@@ -876,7 +876,7 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
|
||||
# update the index entry if appropriate
|
||||
if index_entry is not None:
|
||||
self._update_head(index_entry, xblock.location.revision, new_id)
|
||||
self._update_head(index_entry, xblock.location.branch, new_id)
|
||||
|
||||
# fetch and return the new item--fetching is unnecessary but a good qc step
|
||||
return self.get_item(BlockUsageLocator(xblock.location, version_guid=new_id))
|
||||
@@ -1028,9 +1028,9 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
|
||||
# update the index entry if appropriate
|
||||
if index_entry is not None:
|
||||
self._update_head(index_entry, usage_locator.revision, new_id)
|
||||
self._update_head(index_entry, usage_locator.branch, new_id)
|
||||
result.course_id = usage_locator.course_id
|
||||
result.revision = usage_locator.revision
|
||||
result.branch = usage_locator.branch
|
||||
|
||||
return result
|
||||
|
||||
@@ -1186,19 +1186,19 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
|
||||
:param locator:
|
||||
"""
|
||||
if locator.course_id is None or locator.revision is None:
|
||||
if locator.course_id is None or locator.branch is None:
|
||||
return None
|
||||
else:
|
||||
index_entry = self.course_index.find_one({'_id': locator.course_id})
|
||||
if (locator.version_guid is not None
|
||||
and index_entry['versions'][locator.revision] != locator.version_guid
|
||||
and index_entry['versions'][locator.branch] != locator.version_guid
|
||||
and not force):
|
||||
raise VersionConflictError(
|
||||
locator,
|
||||
CourseLocator(
|
||||
course_id=index_entry['_id'],
|
||||
version_guid=index_entry['versions'][locator.revision],
|
||||
revision=locator.revision))
|
||||
version_guid=index_entry['versions'][locator.branch],
|
||||
branch=locator.branch))
|
||||
else:
|
||||
return index_entry
|
||||
|
||||
@@ -1227,9 +1227,9 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
return False
|
||||
|
||||
|
||||
def _update_head(self, index_entry, revision, new_id):
|
||||
def _update_head(self, index_entry, branch, new_id):
|
||||
"""
|
||||
Update the active index for the given course's revision to point to new_id
|
||||
Update the active index for the given course's branch to point to new_id
|
||||
|
||||
:param index_entry:
|
||||
:param course_locator:
|
||||
@@ -1237,4 +1237,4 @@ class SplitMongoModuleStore(ModuleStoreBase):
|
||||
"""
|
||||
self.course_index.update(
|
||||
{"_id": index_entry["_id"]},
|
||||
{"$set": {"versions.{}".format(revision): new_id}})
|
||||
{"$set": {"versions.{}".format(branch): new_id}})
|
||||
|
||||
@@ -4,12 +4,10 @@ Created on Mar 14, 2013
|
||||
@author: dmitchell
|
||||
'''
|
||||
from unittest import TestCase
|
||||
from nose.plugins.skip import SkipTest
|
||||
|
||||
from bson.objectid import ObjectId
|
||||
from xmodule.modulestore.locator import Locator, CourseLocator, BlockUsageLocator
|
||||
from xmodule.modulestore.exceptions import InvalidLocationError, \
|
||||
InsufficientSpecificationError, OverSpecificationError
|
||||
from xmodule.modulestore.exceptions import InsufficientSpecificationError, OverSpecificationError
|
||||
|
||||
|
||||
class LocatorTest(TestCase):
|
||||
@@ -21,30 +19,30 @@ class LocatorTest(TestCase):
|
||||
self.assertRaises(
|
||||
OverSpecificationError,
|
||||
CourseLocator,
|
||||
url='edx://edu.mit.eecs.6002x',
|
||||
course_id='edu.harvard.history',
|
||||
revision='published',
|
||||
url='edx://mit.eecs.6002x',
|
||||
course_id='harvard.history',
|
||||
branch='published',
|
||||
version_guid=ObjectId())
|
||||
self.assertRaises(
|
||||
OverSpecificationError,
|
||||
CourseLocator,
|
||||
url='edx://edu.mit.eecs.6002x',
|
||||
course_id='edu.harvard.history',
|
||||
url='edx://mit.eecs.6002x',
|
||||
course_id='harvard.history',
|
||||
version_guid=ObjectId())
|
||||
self.assertRaises(
|
||||
OverSpecificationError,
|
||||
CourseLocator,
|
||||
url='edx://edu.mit.eecs.6002x;published',
|
||||
revision='draft')
|
||||
url='edx://mit.eecs.6002x;published',
|
||||
branch='draft')
|
||||
self.assertRaises(
|
||||
OverSpecificationError,
|
||||
CourseLocator,
|
||||
course_id='edu.mit.eecs.6002x;published',
|
||||
revision='draft')
|
||||
course_id='mit.eecs.6002x;published',
|
||||
branch='draft')
|
||||
|
||||
def test_course_constructor_underspecified(self):
|
||||
self.assertRaises(InsufficientSpecificationError, CourseLocator)
|
||||
self.assertRaises(InsufficientSpecificationError, CourseLocator, revision='published')
|
||||
self.assertRaises(InsufficientSpecificationError, CourseLocator, branch='published')
|
||||
|
||||
def test_course_constructor_bad_version_guid(self):
|
||||
self.assertRaises(ValueError, CourseLocator, version_guid="012345")
|
||||
@@ -73,467 +71,128 @@ class LocatorTest(TestCase):
|
||||
"""
|
||||
Test all sorts of badly-formed course_ids (and urls with those course_ids)
|
||||
"""
|
||||
for bad_id in ('edu.mit.',
|
||||
' edu.mit.eecs',
|
||||
'edu.mit.eecs ',
|
||||
'@edu.mit.eecs',
|
||||
'#edu.mit.eecs',
|
||||
'edu.mit.ee cs',
|
||||
'edu.mit.ee,cs',
|
||||
'edu.mit.ee/cs',
|
||||
'edu.mit.ee$cs',
|
||||
'edu.mit.ee&cs',
|
||||
'edu.mit.ee()cs',
|
||||
for bad_id in ('mit.',
|
||||
' mit.eecs',
|
||||
'mit.eecs ',
|
||||
'@mit.eecs',
|
||||
'#mit.eecs',
|
||||
'mit.ee cs',
|
||||
'mit.ee,cs',
|
||||
'mit.ee/cs',
|
||||
'mit.ee$cs',
|
||||
'mit.ee&cs',
|
||||
'mit.ee()cs',
|
||||
';this',
|
||||
'edu.mit.eecs;',
|
||||
'edu.mit.eecs;this;that',
|
||||
'edu.mit.eecs;this;',
|
||||
'edu.mit.eecs;this ',
|
||||
'edu.mit.eecs;th%is ',
|
||||
'mit.eecs;',
|
||||
'mit.eecs;this;that',
|
||||
'mit.eecs;this;',
|
||||
'mit.eecs;this ',
|
||||
'mit.eecs;th%is ',
|
||||
):
|
||||
self.assertRaises(AssertionError, CourseLocator, course_id=bad_id)
|
||||
self.assertRaises(AssertionError, CourseLocator, url='edx://' + bad_id)
|
||||
|
||||
def test_course_constructor_bad_url(self):
|
||||
for bad_url in ('edx://',
|
||||
'edx:/edu.mit.eecs',
|
||||
'http://edu.mit.eecs',
|
||||
'edu.mit.eecs',
|
||||
'edx//edu.mit.eecs'):
|
||||
'edx:/mit.eecs',
|
||||
'http://mit.eecs',
|
||||
'mit.eecs',
|
||||
'edx//mit.eecs'):
|
||||
self.assertRaises(AssertionError, CourseLocator, url=bad_url)
|
||||
|
||||
def test_course_constructor_redundant_001(self):
|
||||
testurn = 'edu.mit.eecs.6002x'
|
||||
testurn = 'mit.eecs.6002x'
|
||||
testobj = CourseLocator(course_id=testurn, url='edx://' + testurn)
|
||||
self.check_course_locn_fields(testobj, 'course_id', course_id=testurn)
|
||||
|
||||
def test_course_constructor_redundant_002(self):
|
||||
testurn = 'edu.mit.eecs.6002x;published'
|
||||
expected_urn = 'edu.mit.eecs.6002x'
|
||||
testurn = 'mit.eecs.6002x;published'
|
||||
expected_urn = 'mit.eecs.6002x'
|
||||
expected_rev = 'published'
|
||||
testobj = CourseLocator(course_id=testurn, url='edx://' + testurn)
|
||||
self.check_course_locn_fields(testobj, 'course_id',
|
||||
course_id=expected_urn,
|
||||
revision=expected_rev)
|
||||
branch=expected_rev)
|
||||
|
||||
def test_course_constructor_course_id_no_revision(self):
|
||||
testurn = 'edu.mit.eecs.6002x'
|
||||
def test_course_constructor_course_id_no_branch(self):
|
||||
testurn = 'mit.eecs.6002x'
|
||||
testobj = CourseLocator(course_id=testurn)
|
||||
self.check_course_locn_fields(testobj, 'course_id', course_id=testurn)
|
||||
self.assertEqual(testobj.course_id, testurn)
|
||||
self.assertEqual(str(testobj), testurn)
|
||||
self.assertEqual(testobj.url(), 'edx://' + testurn)
|
||||
|
||||
def test_course_constructor_course_id_with_revision(self):
|
||||
testurn = 'edu.mit.eecs.6002x;published'
|
||||
expected_id = 'edu.mit.eecs.6002x'
|
||||
expected_revision = 'published'
|
||||
def test_course_constructor_course_id_with_branch(self):
|
||||
testurn = 'mit.eecs.6002x;published'
|
||||
expected_id = 'mit.eecs.6002x'
|
||||
expected_branch = 'published'
|
||||
testobj = CourseLocator(course_id=testurn)
|
||||
self.check_course_locn_fields(testobj, 'course_id with revision',
|
||||
self.check_course_locn_fields(testobj, 'course_id with branch',
|
||||
course_id=expected_id,
|
||||
revision=expected_revision,
|
||||
branch=expected_branch,
|
||||
)
|
||||
self.assertEqual(testobj.course_id, expected_id)
|
||||
self.assertEqual(testobj.revision, expected_revision)
|
||||
self.assertEqual(testobj.branch, expected_branch)
|
||||
self.assertEqual(str(testobj), testurn)
|
||||
self.assertEqual(testobj.url(), 'edx://' + testurn)
|
||||
|
||||
def test_course_constructor_course_id_separate_revision(self):
|
||||
test_id = 'edu.mit.eecs.6002x'
|
||||
test_revision = 'published'
|
||||
expected_urn = 'edu.mit.eecs.6002x;published'
|
||||
testobj = CourseLocator(course_id=test_id, revision=test_revision)
|
||||
self.check_course_locn_fields(testobj, 'course_id with separate revision',
|
||||
def test_course_constructor_course_id_separate_branch(self):
|
||||
test_id = 'mit.eecs.6002x'
|
||||
test_branch = 'published'
|
||||
expected_urn = 'mit.eecs.6002x;published'
|
||||
testobj = CourseLocator(course_id=test_id, branch=test_branch)
|
||||
self.check_course_locn_fields(testobj, 'course_id with separate branch',
|
||||
course_id=test_id,
|
||||
revision=test_revision,
|
||||
branch=test_branch,
|
||||
)
|
||||
self.assertEqual(testobj.course_id, test_id)
|
||||
self.assertEqual(testobj.revision, test_revision)
|
||||
self.assertEqual(testobj.branch, test_branch)
|
||||
self.assertEqual(str(testobj), expected_urn)
|
||||
self.assertEqual(testobj.url(), 'edx://' + expected_urn)
|
||||
|
||||
def test_course_constructor_course_id_repeated_revision(self):
|
||||
def test_course_constructor_course_id_repeated_branch(self):
|
||||
"""
|
||||
The same revision appears in the course_id and the revision field.
|
||||
The same branch appears in the course_id and the branch field.
|
||||
"""
|
||||
test_id = 'edu.mit.eecs.6002x;published'
|
||||
test_revision = 'published'
|
||||
expected_id = 'edu.mit.eecs.6002x'
|
||||
expected_urn = 'edu.mit.eecs.6002x;published'
|
||||
testobj = CourseLocator(course_id=test_id, revision=test_revision)
|
||||
self.check_course_locn_fields(testobj, 'course_id with repeated revision',
|
||||
test_id = 'mit.eecs.6002x;published'
|
||||
test_branch = 'published'
|
||||
expected_id = 'mit.eecs.6002x'
|
||||
expected_urn = 'mit.eecs.6002x;published'
|
||||
testobj = CourseLocator(course_id=test_id, branch=test_branch)
|
||||
self.check_course_locn_fields(testobj, 'course_id with repeated branch',
|
||||
course_id=expected_id,
|
||||
revision=test_revision,
|
||||
branch=test_branch,
|
||||
)
|
||||
self.assertEqual(testobj.course_id, expected_id)
|
||||
self.assertEqual(testobj.revision, test_revision)
|
||||
self.assertEqual(testobj.branch, test_branch)
|
||||
self.assertEqual(str(testobj), expected_urn)
|
||||
self.assertEqual(testobj.url(), 'edx://' + expected_urn)
|
||||
|
||||
def test_block_constructor(self):
|
||||
testurn = 'edu.mit.eecs.6002x;published#HW3'
|
||||
expected_id = 'edu.mit.eecs.6002x'
|
||||
expected_revision = 'published'
|
||||
testurn = 'mit.eecs.6002x;published#HW3'
|
||||
expected_id = 'mit.eecs.6002x'
|
||||
expected_branch = 'published'
|
||||
expected_block_ref = 'HW3'
|
||||
testobj = BlockUsageLocator(course_id=testurn)
|
||||
self.check_block_locn_fields(testobj, 'test_block constructor',
|
||||
course_id=expected_id,
|
||||
revision=expected_revision,
|
||||
branch=expected_branch,
|
||||
block=expected_block_ref)
|
||||
self.assertEqual(str(testobj), testurn)
|
||||
self.assertEqual(testobj.url(), 'edx://' + testurn)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Disabled tests
|
||||
|
||||
def test_course_urls(self):
|
||||
'''
|
||||
Test constructor and property accessors.
|
||||
'''
|
||||
raise SkipTest()
|
||||
self.assertRaises(TypeError, CourseLocator, 'empty constructor')
|
||||
|
||||
# url inits
|
||||
testurn = 'edx://org/course/category/name'
|
||||
self.assertRaises(InvalidLocationError, CourseLocator, url=testurn)
|
||||
testurn = 'unknown/versionid/blockid'
|
||||
self.assertRaises(InvalidLocationError, CourseLocator, url=testurn)
|
||||
|
||||
testurn = 'cvx/versionid'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, 'versionid')
|
||||
self.assertEqual(testobj, CourseLocator(testobj),
|
||||
'initialization from another instance')
|
||||
|
||||
testurn = 'cvx/versionid/'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, 'versionid')
|
||||
|
||||
testurn = 'cvx/versionid/blockid'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, 'versionid')
|
||||
|
||||
testurn = 'cvx/versionid/blockid/extraneousstuff?including=args'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, 'versionid')
|
||||
|
||||
testurn = 'cvx://versionid/blockid'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, 'versionid')
|
||||
|
||||
testurn = 'crx/courseid/blockid'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, course_id='courseid')
|
||||
|
||||
testurn = 'crx/courseid@revision/blockid'
|
||||
testobj = CourseLocator(testurn)
|
||||
self.check_course_locn_fields(testobj, testurn, course_id='courseid',
|
||||
revision='revision')
|
||||
self.assertEqual(testobj, CourseLocator(testobj),
|
||||
'run initialization from another instance')
|
||||
|
||||
def test_course_keyword_setters(self):
|
||||
raise SkipTest()
|
||||
# arg list inits
|
||||
testobj = CourseLocator(version_guid='versionid')
|
||||
self.check_course_locn_fields(testobj, 'versionid arg', 'versionid')
|
||||
|
||||
testobj = CourseLocator(course_id='courseid')
|
||||
self.check_course_locn_fields(testobj, 'courseid arg',
|
||||
course_id='courseid')
|
||||
|
||||
testobj = CourseLocator(course_id='courseid', revision='rev')
|
||||
self.check_course_locn_fields(testobj, 'rev arg',
|
||||
course_id='courseid',
|
||||
revision='rev')
|
||||
# ignores garbage
|
||||
testobj = CourseLocator(course_id='courseid', revision='rev',
|
||||
potato='spud')
|
||||
self.check_course_locn_fields(testobj, 'extra keyword arg',
|
||||
course_id='courseid',
|
||||
revision='rev')
|
||||
|
||||
# url w/ keyword override
|
||||
testurn = 'crx/courseid@revision/blockid'
|
||||
testobj = CourseLocator(testurn, revision='rev')
|
||||
self.check_course_locn_fields(testobj, 'rev override',
|
||||
course_id='courseid',
|
||||
revision='rev')
|
||||
|
||||
def test_course_dict(self):
|
||||
raise SkipTest()
|
||||
# dict init w/ keyword overwrites
|
||||
testobj = CourseLocator({"version_guid": 'versionid'})
|
||||
self.check_course_locn_fields(testobj, 'versionid dict', 'versionid')
|
||||
|
||||
testobj = CourseLocator({"course_id": 'courseid'})
|
||||
self.check_course_locn_fields(testobj, 'courseid dict',
|
||||
course_id='courseid')
|
||||
|
||||
testobj = CourseLocator({"course_id": 'courseid', "revision": 'rev'})
|
||||
self.check_course_locn_fields(testobj, 'rev dict',
|
||||
course_id='courseid',
|
||||
revision='rev')
|
||||
# ignores garbage
|
||||
testobj = CourseLocator({"course_id": 'courseid', "revision": 'rev',
|
||||
"potato": 'spud'})
|
||||
self.check_course_locn_fields(testobj, 'extra keyword dict',
|
||||
course_id='courseid',
|
||||
revision='rev')
|
||||
testobj = CourseLocator({"course_id": 'courseid', "revision": 'rev'},
|
||||
revision='alt')
|
||||
self.check_course_locn_fields(testobj, 'rev dict',
|
||||
course_id='courseid',
|
||||
revision='alt')
|
||||
|
||||
# urn init w/ dict & keyword overwrites
|
||||
testobj = CourseLocator('crx/notcourse@notthis',
|
||||
{"course_id": 'courseid'},
|
||||
revision='alt')
|
||||
self.check_course_locn_fields(testobj, 'rev dict',
|
||||
course_id='courseid',
|
||||
revision='alt')
|
||||
|
||||
def test_url(self):
|
||||
'''
|
||||
Ensure CourseLocator generates expected urls.
|
||||
'''
|
||||
raise SkipTest()
|
||||
|
||||
testobj = CourseLocator(version_guid='versionid')
|
||||
self.assertEqual(testobj.url(), 'cvx/versionid', 'versionid')
|
||||
self.assertEqual(testobj, CourseLocator(testobj.url()),
|
||||
'versionid conversion through url')
|
||||
|
||||
testobj = CourseLocator(course_id='courseid')
|
||||
self.assertEqual(testobj.url(), 'crx/courseid', 'courseid')
|
||||
self.assertEqual(testobj, CourseLocator(testobj.url()),
|
||||
'courseid conversion through url')
|
||||
|
||||
testobj = CourseLocator(course_id='courseid', revision='rev')
|
||||
self.assertEqual(testobj.url(), 'crx/courseid@rev', 'rev')
|
||||
self.assertEqual(testobj, CourseLocator(testobj.url()),
|
||||
'rev conversion through url')
|
||||
|
||||
def test_html(self):
|
||||
'''
|
||||
Ensure CourseLocator generates expected urls.
|
||||
'''
|
||||
raise SkipTest()
|
||||
testobj = CourseLocator(version_guid='versionid')
|
||||
self.assertEqual(testobj.html_id(), 'cvx/versionid', 'versionid')
|
||||
self.assertEqual(testobj, CourseLocator(testobj.html_id()),
|
||||
'versionid conversion through html_id')
|
||||
|
||||
testobj = CourseLocator(course_id='courseid')
|
||||
self.assertEqual(testobj.html_id(), 'crx/courseid', 'courseid')
|
||||
self.assertEqual(testobj, CourseLocator(testobj.html_id()),
|
||||
'courseid conversion through html_id')
|
||||
|
||||
testobj = CourseLocator(course_id='courseid', revision='rev')
|
||||
self.assertEqual(testobj.html_id(), 'crx/courseid%40rev', 'rev')
|
||||
self.assertEqual(testobj, CourseLocator(testobj.html_id()),
|
||||
'rev conversion through html_id')
|
||||
|
||||
def test_block_locator(self):
|
||||
'''
|
||||
Test constructor and property accessors.
|
||||
'''
|
||||
raise SkipTest()
|
||||
self.assertIsInstance(BlockUsageLocator(), BlockUsageLocator,
|
||||
'empty constructor')
|
||||
|
||||
# url inits
|
||||
testurn = 'edx://org/course/category/name'
|
||||
self.assertRaises(InvalidLocationError, BlockUsageLocator, testurn)
|
||||
testurn = 'unknown/versionid/blockid'
|
||||
self.assertRaises(InvalidLocationError, BlockUsageLocator, testurn)
|
||||
|
||||
testurn = 'cvx/versionid'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, 'versionid')
|
||||
self.assertEqual(testobj, BlockUsageLocator(testobj),
|
||||
'initialization from another instance')
|
||||
|
||||
testurn = 'cvx/versionid/'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, 'versionid')
|
||||
|
||||
testurn = 'cvx/versionid/blockid'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, 'versionid',
|
||||
block='blockid')
|
||||
|
||||
testurn = 'cvx/versionid/blockid/extraneousstuff?including=args'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, 'versionid',
|
||||
block='blockid')
|
||||
|
||||
testurn = 'cvx://versionid/blockid'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, 'versionid',
|
||||
block='blockid')
|
||||
|
||||
testurn = 'crx/courseid/blockid'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, course_id='courseid',
|
||||
block='blockid')
|
||||
|
||||
testurn = 'crx/courseid@revision/blockid'
|
||||
testobj = BlockUsageLocator(testurn)
|
||||
self.check_block_locn_fields(testobj, testurn, course_id='courseid',
|
||||
revision='revision', block='blockid')
|
||||
self.assertEqual(testobj, BlockUsageLocator(testobj),
|
||||
'run initialization from another instance')
|
||||
|
||||
def test_block_keyword_init(self):
|
||||
# arg list inits
|
||||
raise SkipTest()
|
||||
testobj = BlockUsageLocator(version_guid='versionid')
|
||||
self.check_block_locn_fields(testobj, 'versionid arg', 'versionid')
|
||||
|
||||
testobj = BlockUsageLocator(version_guid='versionid', usage_id='myblock')
|
||||
self.check_block_locn_fields(testobj, 'versionid arg', 'versionid',
|
||||
block='myblock')
|
||||
|
||||
testobj = BlockUsageLocator(course_id='courseid')
|
||||
self.check_block_locn_fields(testobj, 'courseid arg',
|
||||
course_id='courseid')
|
||||
|
||||
testobj = BlockUsageLocator(course_id='courseid', revision='rev')
|
||||
self.check_block_locn_fields(testobj, 'rev arg',
|
||||
course_id='courseid',
|
||||
revision='rev')
|
||||
# ignores garbage
|
||||
testobj = BlockUsageLocator(course_id='courseid', revision='rev',
|
||||
usage_id='this_block', potato='spud')
|
||||
self.check_block_locn_fields(testobj, 'extra keyword arg',
|
||||
course_id='courseid', block='this_block', revision='rev')
|
||||
|
||||
# url w/ keyword override
|
||||
testurn = 'crx/courseid@revision/blockid'
|
||||
testobj = BlockUsageLocator(testurn, revision='rev')
|
||||
self.check_block_locn_fields(testobj, 'rev override',
|
||||
course_id='courseid', block='blockid',
|
||||
revision='rev')
|
||||
|
||||
def test_block_keywords(self):
|
||||
# dict init w/ keyword overwrites
|
||||
raise SkipTest()
|
||||
testobj = BlockUsageLocator({"version_guid": 'versionid',
|
||||
'usage_id': 'dictblock'})
|
||||
self.check_block_locn_fields(testobj, 'versionid dict', 'versionid',
|
||||
block='dictblock')
|
||||
|
||||
testobj = BlockUsageLocator({"course_id": 'courseid',
|
||||
'usage_id': 'dictblock'})
|
||||
self.check_block_locn_fields(testobj, 'courseid dict',
|
||||
block='dictblock', course_id='courseid')
|
||||
|
||||
testobj = BlockUsageLocator({"course_id": 'courseid', "revision": 'rev',
|
||||
'usage_id': 'dictblock'})
|
||||
self.check_block_locn_fields(testobj, 'rev dict',
|
||||
course_id='courseid', block='dictblock',
|
||||
revision='rev')
|
||||
# ignores garbage
|
||||
testobj = BlockUsageLocator({"course_id": 'courseid', "revision": 'rev',
|
||||
'usage_id': 'dictblock', "potato": 'spud'})
|
||||
self.check_block_locn_fields(testobj, 'extra keyword dict',
|
||||
course_id='courseid', block='dictblock',
|
||||
revision='rev')
|
||||
testobj = BlockUsageLocator({"course_id": 'courseid', "revision": 'rev',
|
||||
'usage_id': 'dictblock'}, revision='alt', usage_id='anotherblock')
|
||||
self.check_block_locn_fields(testobj, 'rev dict',
|
||||
course_id='courseid', block='anotherblock',
|
||||
revision='alt')
|
||||
|
||||
# urn init w/ dict & keyword overwrites
|
||||
testobj = BlockUsageLocator('crx/notcourse@notthis/northis',
|
||||
{"course_id": 'courseid'}, revision='alt', usage_id='anotherblock')
|
||||
self.check_block_locn_fields(testobj, 'rev dict',
|
||||
course_id='courseid', block='anotherblock',
|
||||
revision='alt')
|
||||
|
||||
def test_ensure_fully_specd(self):
|
||||
'''
|
||||
Test constructor and property accessors.
|
||||
'''
|
||||
raise SkipTest()
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
BlockUsageLocator.ensure_fully_specified, BlockUsageLocator())
|
||||
|
||||
# url inits
|
||||
testurn = 'edx://org/course/category/name'
|
||||
self.assertRaises(InvalidLocationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testurn)
|
||||
testurn = 'unknown/versionid/blockid'
|
||||
self.assertRaises(InvalidLocationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testurn)
|
||||
|
||||
testurn = 'cvx/versionid'
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testurn)
|
||||
|
||||
testurn = 'cvx/versionid/'
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testurn)
|
||||
|
||||
testurn = 'cvx/versionid/blockid'
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
testurn = 'cvx/versionid/blockid/extraneousstuff?including=args'
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
testurn = 'cvx://versionid/blockid'
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
testurn = 'crx/courseid/blockid'
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
testurn = 'crx/courseid@revision/blockid'
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
def test_ensure_fully_via_keyword(self):
|
||||
# arg list inits
|
||||
raise SkipTest()
|
||||
testobj = BlockUsageLocator(version_guid='versionid')
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testobj)
|
||||
|
||||
testurn = 'crx/courseid@revision/blockid'
|
||||
testobj = BlockUsageLocator(version_guid='versionid', usage_id='myblock')
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
testobj = BlockUsageLocator(course_id='courseid')
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testobj)
|
||||
|
||||
testobj = BlockUsageLocator(course_id='courseid', revision='rev')
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
BlockUsageLocator.ensure_fully_specified, testobj)
|
||||
|
||||
testobj = BlockUsageLocator(course_id='courseid', revision='rev',
|
||||
usage_id='this_block')
|
||||
self.assertIsInstance(BlockUsageLocator.ensure_fully_specified(testurn),
|
||||
BlockUsageLocator, testurn)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Utilities
|
||||
|
||||
def check_course_locn_fields(self, testobj, msg, version_guid=None,
|
||||
course_id=None, revision=None):
|
||||
course_id=None, branch=None):
|
||||
self.assertEqual(testobj.version_guid, version_guid, msg)
|
||||
self.assertEqual(testobj.course_id, course_id, msg)
|
||||
self.assertEqual(testobj.revision, revision, msg)
|
||||
self.assertEqual(testobj.branch, branch, msg)
|
||||
|
||||
def check_block_locn_fields(self, testobj, msg, version_guid=None,
|
||||
course_id=None, revision=None, block=None):
|
||||
course_id=None, branch=None, block=None):
|
||||
self.check_course_locn_fields(testobj, msg, version_guid, course_id,
|
||||
revision)
|
||||
branch)
|
||||
self.assertEqual(testobj.usage_id, block)
|
||||
|
||||
@@ -136,8 +136,8 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
self.assertEqual(str(course.previous_version), self.GUID_D1)
|
||||
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.45})
|
||||
|
||||
def test_revision_requests(self):
|
||||
# query w/ revision qualifier (both draft and published)
|
||||
def test_branch_requests(self):
|
||||
# query w/ branch qualifier (both draft and published)
|
||||
courses_published = modulestore().get_courses('published')
|
||||
self.assertEqual(len(courses_published), 1, len(courses_published))
|
||||
course = self.findByIdInResult(courses_published, "head23456")
|
||||
@@ -189,7 +189,7 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
self.assertEqual(course.edited_by, "testassist@edx.org")
|
||||
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.55})
|
||||
|
||||
locator = CourseLocator(course_id='GreekHero', revision='draft')
|
||||
locator = CourseLocator(course_id='GreekHero', branch='draft')
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertEqual(course.location.course_id, "GreekHero")
|
||||
self.assertEqual(str(course.location.version_guid), self.GUID_D0)
|
||||
@@ -202,12 +202,12 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
self.assertEqual(course.edited_by, "testassist@edx.org")
|
||||
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.45})
|
||||
|
||||
locator = CourseLocator(course_id='wonderful', revision='published')
|
||||
locator = CourseLocator(course_id='wonderful', branch='published')
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertEqual(course.location.course_id, "wonderful")
|
||||
self.assertEqual(str(course.location.version_guid), self.GUID_P)
|
||||
|
||||
locator = CourseLocator(course_id='wonderful', revision='draft')
|
||||
locator = CourseLocator(course_id='wonderful', branch='draft')
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertEqual(str(course.location.version_guid), self.GUID_D2)
|
||||
|
||||
@@ -216,10 +216,10 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
self.assertRaises(InsufficientSpecificationError,
|
||||
modulestore().get_course, CourseLocator(course_id='edu.meh.blah'))
|
||||
self.assertRaises(ItemNotFoundError,
|
||||
modulestore().get_course, CourseLocator(course_id='nosuchthing', revision='draft'))
|
||||
modulestore().get_course, CourseLocator(course_id='nosuchthing', branch='draft'))
|
||||
self.assertRaises(ItemNotFoundError,
|
||||
modulestore().get_course,
|
||||
CourseLocator(course_id='GreekHero', revision='published'))
|
||||
CourseLocator(course_id='GreekHero', branch='published'))
|
||||
|
||||
def test_course_successors(self):
|
||||
"""
|
||||
@@ -257,7 +257,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
self.assertTrue(modulestore().has_item(locator),
|
||||
"couldn't find in %s" % self.GUID_D1)
|
||||
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='head12345', revision='draft')
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='head12345', branch='draft')
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator),
|
||||
"couldn't find in 12345"
|
||||
@@ -265,7 +265,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
self.assertTrue(
|
||||
modulestore().has_item(BlockUsageLocator(
|
||||
course_id=locator.course_id,
|
||||
revision='draft',
|
||||
branch='draft',
|
||||
usage_id=locator.usage_id
|
||||
)),
|
||||
"couldn't find in draft 12345"
|
||||
@@ -273,38 +273,38 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
self.assertFalse(
|
||||
modulestore().has_item(BlockUsageLocator(
|
||||
course_id=locator.course_id,
|
||||
revision='published',
|
||||
branch='published',
|
||||
usage_id=locator.usage_id)),
|
||||
"found in published 12345"
|
||||
)
|
||||
locator.revision = 'draft'
|
||||
locator.branch = 'draft'
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator),
|
||||
"not found in draft 12345"
|
||||
)
|
||||
|
||||
# not a course obj
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='chapter1', revision='draft')
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='chapter1', branch='draft')
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator),
|
||||
"couldn't find chapter1"
|
||||
)
|
||||
|
||||
# in published course
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="head23456", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="head23456", branch='draft')
|
||||
self.assertTrue(modulestore().has_item(BlockUsageLocator(course_id=locator.course_id,
|
||||
usage_id=locator.usage_id,
|
||||
revision='published')),
|
||||
branch='published')),
|
||||
"couldn't find in 23456")
|
||||
locator.revision = 'published'
|
||||
locator.branch = 'published'
|
||||
self.assertTrue(modulestore().has_item(locator), "couldn't find in 23456")
|
||||
|
||||
def test_negative_has_item(self):
|
||||
# negative tests--not found
|
||||
# no such course or block
|
||||
locator = BlockUsageLocator(course_id="doesnotexist", usage_id="head23456", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="doesnotexist", usage_id="head23456", branch='draft')
|
||||
self.assertFalse(modulestore().has_item(locator))
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="doesnotexist", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="doesnotexist", branch='draft')
|
||||
self.assertFalse(modulestore().has_item(locator))
|
||||
|
||||
# negative tests--insufficient specification
|
||||
@@ -323,7 +323,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
block = modulestore().get_item(locator)
|
||||
self.assertIsInstance(block, CourseDescriptor)
|
||||
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='head12345', revision='draft')
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='head12345', branch='draft')
|
||||
block = modulestore().get_item(locator)
|
||||
self.assertEqual(block.location.course_id, "GreekHero")
|
||||
# look at this one in detail
|
||||
@@ -338,13 +338,13 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
block.grade_cutoffs, {"Pass": 0.45},
|
||||
)
|
||||
|
||||
# try to look up other revisions
|
||||
# try to look up other branches
|
||||
self.assertRaises(ItemNotFoundError,
|
||||
modulestore().get_item,
|
||||
BlockUsageLocator(course_id=locator.as_course_locator(),
|
||||
usage_id=locator.usage_id,
|
||||
revision='published'))
|
||||
locator.revision = 'draft'
|
||||
branch='published'))
|
||||
locator.branch = 'draft'
|
||||
self.assertIsInstance(
|
||||
modulestore().get_item(locator),
|
||||
CourseDescriptor
|
||||
@@ -352,7 +352,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
|
||||
def test_get_non_root(self):
|
||||
# not a course obj
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='chapter1', revision='draft')
|
||||
locator = BlockUsageLocator(course_id='GreekHero', usage_id='chapter1', branch='draft')
|
||||
block = modulestore().get_item(locator)
|
||||
self.assertEqual(block.location.course_id, "GreekHero")
|
||||
self.assertEqual(block.category, 'chapter')
|
||||
@@ -361,7 +361,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
self.assertEqual(block.edited_by, "testassist@edx.org")
|
||||
|
||||
# in published course
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="head23456", revision='published')
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="head23456", branch='published')
|
||||
self.assertIsInstance(
|
||||
modulestore().get_item(locator),
|
||||
CourseDescriptor
|
||||
@@ -369,10 +369,10 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
|
||||
# negative tests--not found
|
||||
# no such course or block
|
||||
locator = BlockUsageLocator(course_id="doesnotexist", usage_id="head23456", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="doesnotexist", usage_id="head23456", branch='draft')
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
modulestore().get_item(locator)
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="doesnotexist", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="doesnotexist", branch='draft')
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
modulestore().get_item(locator)
|
||||
|
||||
@@ -380,7 +380,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
with self.assertRaises(InsufficientSpecificationError):
|
||||
modulestore().get_item(BlockUsageLocator(version_guid=self.GUID_D1))
|
||||
with self.assertRaises(InsufficientSpecificationError):
|
||||
modulestore().get_item(BlockUsageLocator(course_id='GreekHero', revision='draft'))
|
||||
modulestore().get_item(BlockUsageLocator(course_id='GreekHero', branch='draft'))
|
||||
|
||||
# pylint: disable=W0212
|
||||
def test_matching(self):
|
||||
@@ -411,7 +411,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
|
||||
def test_get_items(self):
|
||||
'''
|
||||
get_items(locator, qualifiers, [revision])
|
||||
get_items(locator, qualifiers, [branch])
|
||||
'''
|
||||
locator = CourseLocator(version_guid=self.GUID_D0)
|
||||
# get all modules
|
||||
@@ -436,9 +436,9 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
|
||||
def test_get_parents(self):
|
||||
'''
|
||||
get_parent_locations(locator, [usage_id], [revision]): [BlockUsageLocator]
|
||||
get_parent_locations(locator, [usage_id], [branch]): [BlockUsageLocator]
|
||||
'''
|
||||
locator = CourseLocator(course_id="GreekHero", revision='draft')
|
||||
locator = CourseLocator(course_id="GreekHero", branch='draft')
|
||||
parents = modulestore().get_parent_locations(locator, usage_id='chapter1')
|
||||
self.assertEqual(len(parents), 1)
|
||||
self.assertEqual(parents[0].usage_id, 'head12345')
|
||||
@@ -454,7 +454,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
"""
|
||||
Test the existing get_children method on xdescriptors
|
||||
"""
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="head12345", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="head12345", branch='draft')
|
||||
block = modulestore().get_item(locator)
|
||||
children = block.get_children()
|
||||
expected_ids = [
|
||||
@@ -497,7 +497,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
metadata=None): new_desciptor
|
||||
"""
|
||||
# grab link to course to ensure new versioning works
|
||||
locator = CourseLocator(course_id="GreekHero", revision='draft')
|
||||
locator = CourseLocator(course_id="GreekHero", branch='draft')
|
||||
premod_course = modulestore().get_course(locator)
|
||||
premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1)
|
||||
# add minimal one w/o a parent
|
||||
@@ -534,7 +534,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
"""
|
||||
Test create_item w/ specifying the parent of the new item
|
||||
"""
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="head23456", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="wonderful", usage_id="head23456", branch='draft')
|
||||
premod_course = modulestore().get_course(locator)
|
||||
category = 'chapter'
|
||||
new_module = modulestore().create_item(
|
||||
@@ -554,7 +554,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
a definition id and new def data that it branches the definition in the db.
|
||||
Actually, this tries to test all create_item features not tested above.
|
||||
"""
|
||||
locator = BlockUsageLocator(course_id="contender", usage_id="head345679", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="contender", usage_id="head345679", branch='draft')
|
||||
category = 'problem'
|
||||
premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1)
|
||||
new_payload = "<problem>empty</problem>"
|
||||
@@ -592,7 +592,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
"""
|
||||
test updating an items metadata ensuring the definition doesn't version but the course does if it should
|
||||
"""
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="problem3_2", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="problem3_2", branch='draft')
|
||||
problem = modulestore().get_item(locator)
|
||||
pre_def_id = problem.definition_locator.definition_id
|
||||
pre_version_guid = problem.location.version_guid
|
||||
@@ -629,7 +629,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
"""
|
||||
test updating an item's children ensuring the definition doesn't version but the course does if it should
|
||||
"""
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="chapter3", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="chapter3", branch='draft')
|
||||
block = modulestore().get_item(locator)
|
||||
pre_def_id = block.definition_locator.definition_id
|
||||
pre_version_guid = block.location.version_guid
|
||||
@@ -653,7 +653,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
"""
|
||||
test updating an item's definition: ensure it gets versioned as well as the course getting versioned
|
||||
"""
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="head12345", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="head12345", branch='draft')
|
||||
block = modulestore().get_item(locator)
|
||||
pre_def_id = block.definition_locator.definition_id
|
||||
pre_version_guid = block.location.version_guid
|
||||
@@ -670,7 +670,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
Test updating metadata, children, and definition in a single call ensuring all the versioning occurs
|
||||
"""
|
||||
# first add 2 children to the course for the update to manipulate
|
||||
locator = BlockUsageLocator(course_id="contender", usage_id="head345679", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="contender", usage_id="head345679", branch='draft')
|
||||
category = 'problem'
|
||||
new_payload = "<problem>empty</problem>"
|
||||
modulestore().create_item(
|
||||
@@ -714,14 +714,14 @@ class TestItemCrud(SplitModuleTest):
|
||||
reusable_location = BlockUsageLocator(
|
||||
course_id=course.location.course_id,
|
||||
usage_id=course.location.usage_id,
|
||||
revision='draft')
|
||||
branch='draft')
|
||||
|
||||
# delete a leaf
|
||||
problems = modulestore().get_items(reusable_location, {'category': 'problem'})
|
||||
locn_to_del = problems[0].location
|
||||
new_course_loc = modulestore().delete_item(locn_to_del, 'deleting_user')
|
||||
deleted = BlockUsageLocator(course_id=reusable_location.course_id,
|
||||
revision=reusable_location.revision,
|
||||
branch=reusable_location.branch,
|
||||
usage_id=locn_to_del.usage_id)
|
||||
self.assertFalse(modulestore().has_item(deleted))
|
||||
self.assertRaises(VersionConflictError, modulestore().has_item, locn_to_del)
|
||||
@@ -743,7 +743,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
self.assertFalse(modulestore().has_item(
|
||||
BlockUsageLocator(
|
||||
course_id=node_loc.course_id,
|
||||
revision=node_loc.revision,
|
||||
branch=node_loc.branch,
|
||||
usage_id=node.location.usage_id)))
|
||||
locator = BlockUsageLocator(
|
||||
version_guid=node.location.version_guid,
|
||||
@@ -759,7 +759,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
root = BlockUsageLocator(
|
||||
course_id=course.location.course_id,
|
||||
usage_id=course.location.usage_id,
|
||||
revision='draft')
|
||||
branch='draft')
|
||||
for _ in range(4):
|
||||
self.create_subtree_for_deletion(root, ['chapter', 'vertical', 'problem'])
|
||||
return modulestore().get_item(root)
|
||||
@@ -814,7 +814,7 @@ class TestCourseCreation(SplitModuleTest):
|
||||
Test making a course which points to an existing draft and published but not making any changes to either.
|
||||
"""
|
||||
pre_time = datetime.datetime.now(UTC)
|
||||
original_locator = CourseLocator(course_id="wonderful", revision='draft')
|
||||
original_locator = CourseLocator(course_id="wonderful", branch='draft')
|
||||
original_index = modulestore().get_course_index_info(original_locator)
|
||||
new_draft = modulestore().create_course(
|
||||
'leech', 'best_course', 'leech_master', id_root='best',
|
||||
@@ -831,7 +831,7 @@ class TestCourseCreation(SplitModuleTest):
|
||||
self.assertLessEqual(new_index["edited_on"], datetime.datetime.now(UTC))
|
||||
self.assertEqual(new_index['edited_by'], 'leech_master')
|
||||
|
||||
new_published_locator = CourseLocator(course_id=new_draft_locator.course_id, revision='published')
|
||||
new_published_locator = CourseLocator(course_id=new_draft_locator.course_id, branch='published')
|
||||
new_published = modulestore().get_course(new_published_locator)
|
||||
self.assertEqual(new_published.edited_by, 'test@edx.org')
|
||||
self.assertLess(new_published.edited_on, pre_time)
|
||||
@@ -870,7 +870,7 @@ class TestCourseCreation(SplitModuleTest):
|
||||
Create a new course which overrides metadata and course_data
|
||||
"""
|
||||
pre_time = datetime.datetime.now(UTC)
|
||||
original_locator = CourseLocator(course_id="contender", revision='draft')
|
||||
original_locator = CourseLocator(course_id="contender", branch='draft')
|
||||
original = modulestore().get_course(original_locator)
|
||||
original_index = modulestore().get_course_index_info(original_locator)
|
||||
data_payload = {}
|
||||
@@ -909,7 +909,7 @@ class TestCourseCreation(SplitModuleTest):
|
||||
"""
|
||||
Test changing the org, pretty id, etc of a course. Test that it doesn't allow changing the id, etc.
|
||||
"""
|
||||
locator = CourseLocator(course_id="GreekHero", revision='draft')
|
||||
locator = CourseLocator(course_id="GreekHero", branch='draft')
|
||||
modulestore().update_course_index(locator, {'org': 'funkyU'})
|
||||
course_info = modulestore().get_course_index_info(locator)
|
||||
self.assertEqual(course_info['org'], 'funkyU')
|
||||
@@ -945,7 +945,7 @@ class TestCourseCreation(SplitModuleTest):
|
||||
# an allowed but not recommended way to publish a course
|
||||
versions['published'] = self.GUID_D1
|
||||
modulestore().update_course_index(locator, {'versions': versions}, update_versions=True)
|
||||
course = modulestore().get_course(CourseLocator(course_id=locator.course_id, revision="published"))
|
||||
course = modulestore().get_course(CourseLocator(course_id=locator.course_id, branch="published"))
|
||||
self.assertEqual(str(course.location.version_guid), self.GUID_D1)
|
||||
|
||||
|
||||
@@ -959,11 +959,11 @@ class TestInheritance(SplitModuleTest):
|
||||
"""
|
||||
# Note, not testing value where defined (course) b/c there's no
|
||||
# defined accessor for it on CourseDescriptor.
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="problem3_2", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="problem3_2", branch='draft')
|
||||
node = modulestore().get_item(locator)
|
||||
# inherited
|
||||
self.assertEqual(node.graceperiod, datetime.timedelta(hours=2))
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="problem1", revision='draft')
|
||||
locator = BlockUsageLocator(course_id="GreekHero", usage_id="problem1", branch='draft')
|
||||
node = modulestore().get_item(locator)
|
||||
# overridden
|
||||
self.assertEqual(node.graceperiod, datetime.timedelta(hours=4))
|
||||
|
||||
Reference in New Issue
Block a user