Merge pull request #18771 from edx/youngstrom/fix-xdist-test-errors

Fix commonlib-unit test collection errors in xdist
This commit is contained in:
Michael Youngstrom
2018-08-13 14:01:31 -04:00
committed by GitHub
5 changed files with 83 additions and 42 deletions

View File

@@ -93,6 +93,10 @@ class TestMongoAssetMetadataStorage(TestCase):
Tests for storing/querying course asset metadata.
"""
shard = 1
XML_MODULESTORE_MAP = {
'XML_MODULESTORE_BUILDER': XmlModulestoreBuilder(),
'MIXED_MODULESTORE_BUILDER': MixedModulestoreBuilder([('xml', XmlModulestoreBuilder())])
}
def setUp(self):
super(TestMongoAssetMetadataStorage, self).setUp()
@@ -641,11 +645,12 @@ class TestMongoAssetMetadataStorage(TestCase):
)
self.assertEquals(len(asset_page), 2)
@ddt.data(XmlModulestoreBuilder(), MixedModulestoreBuilder([('xml', XmlModulestoreBuilder())]))
def test_xml_not_yet_implemented(self, storebuilder):
@ddt.data('XML_MODULESTORE_BUILDER', 'MIXED_MODULESTORE_BUILDER')
def test_xml_not_yet_implemented(self, storebuilderName):
"""
Test coverage which shows that for now xml read operations are not implemented
"""
storebuilder = self.XML_MODULESTORE_MAP[storebuilderName]
with storebuilder.build(contentstore=None) as (__, store):
course_key = store.make_course_key("org", "course", "run")
asset_key = course_key.make_asset_key('asset', 'foo.jpg')

View File

@@ -13,6 +13,14 @@ from xmodule.modulestore.split_mongo.mongo_connection import MongoConnection
from opaque_keys.edx.locator import CourseLocator
VERSION_GUID_DICT = {
'SAMPLE_VERSION_GUID': 'deadbeef1234' * 2,
'SAMPLE_UNICODE_VERSION_GUID': u'deadbeef1234' * 2,
'BSON_OBJECTID': ObjectId()
}
SAMPLE_GUIDS_LIST = ['SAMPLE_VERSION_GUID', 'SAMPLE_UNICODE_VERSION_GUID', 'BSON_OBJECTID']
class TestBulkWriteMixin(unittest.TestCase):
shard = 2
@@ -58,10 +66,11 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin):
"""
shard = 2
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_no_bulk_read_structure(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_no_bulk_read_structure(self, version_guid_name):
# Reading a structure when no bulk operation is active should just call
# through to the db_connection
version_guid = VERSION_GUID_DICT[version_guid_name]
result = self.bulk.get_structure(self.course_key, version_guid)
self.assertConnCalls(
call.get_structure(self.course_key.as_object_id(version_guid), self.course_key)
@@ -77,10 +86,11 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin):
self.assertConnCalls(call.insert_structure(self.structure, self.course_key))
self.clear_cache.assert_called_once_with(self.structure['_id'])
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_no_bulk_read_definition(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_no_bulk_read_definition(self, version_guid_name):
# Reading a definition when no bulk operation is active should just call
# through to the db_connection
version_guid = VERSION_GUID_DICT[version_guid_name]
result = self.bulk.get_definition(self.course_key, version_guid)
self.assertConnCalls(
call.get_definition(
@@ -584,38 +594,42 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
super(TestBulkWriteMixinOpen, self).setUp()
self.bulk._begin_bulk_operation(self.course_key)
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_structure_without_write_from_db(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_structure_without_write_from_db(self, version_guid_name):
# Reading a structure before it's been written (while in bulk operation mode)
# returns the structure from the database
version_guid = VERSION_GUID_DICT[version_guid_name]
result = self.bulk.get_structure(self.course_key, version_guid)
self.assertEquals(self.conn.get_structure.call_count, 1)
self.assertEqual(result, self.conn.get_structure.return_value)
self.assertCacheNotCleared()
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_structure_without_write_only_reads_once(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_structure_without_write_only_reads_once(self, version_guid_name):
# Reading the same structure multiple times shouldn't hit the database
# more than once
version_guid = VERSION_GUID_DICT[version_guid_name]
for _ in xrange(2):
result = self.bulk.get_structure(self.course_key, version_guid)
self.assertEquals(self.conn.get_structure.call_count, 1)
self.assertEqual(result, self.conn.get_structure.return_value)
self.assertCacheNotCleared()
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_structure_after_write_no_db(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_structure_after_write_no_db(self, version_guid_name):
# Reading a structure that's already been written shouldn't hit the db at all
version_guid = VERSION_GUID_DICT[version_guid_name]
self.structure['_id'] = version_guid
self.bulk.update_structure(self.course_key, self.structure)
result = self.bulk.get_structure(self.course_key, version_guid)
self.assertEquals(self.conn.get_structure.call_count, 0)
self.assertEqual(result, self.structure)
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_structure_after_write_after_read(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_structure_after_write_after_read(self, version_guid_name):
# Reading a structure that's been updated after being pulled from the db should
# still get the updated value
version_guid = VERSION_GUID_DICT[version_guid_name]
self.structure['_id'] = version_guid
self.bulk.get_structure(self.course_key, version_guid)
self.bulk.update_structure(self.course_key, self.structure)
@@ -623,38 +637,42 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
self.assertEquals(self.conn.get_structure.call_count, 1)
self.assertEqual(result, self.structure)
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_definition_without_write_from_db(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_definition_without_write_from_db(self, version_guid_name):
# Reading a definition before it's been written (while in bulk operation mode)
# returns the definition from the database
version_guid = VERSION_GUID_DICT[version_guid_name]
result = self.bulk.get_definition(self.course_key, version_guid)
self.assertEquals(self.conn.get_definition.call_count, 1)
self.assertEqual(result, self.conn.get_definition.return_value)
self.assertCacheNotCleared()
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_definition_without_write_only_reads_once(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_definition_without_write_only_reads_once(self, version_guid_name):
# Reading the same definition multiple times shouldn't hit the database
# more than once
version_guid = VERSION_GUID_DICT[version_guid_name]
for _ in xrange(2):
result = self.bulk.get_definition(self.course_key, version_guid)
self.assertEquals(self.conn.get_definition.call_count, 1)
self.assertEqual(result, self.conn.get_definition.return_value)
self.assertCacheNotCleared()
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_definition_after_write_no_db(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_definition_after_write_no_db(self, version_guid_name):
# Reading a definition that's already been written shouldn't hit the db at all
version_guid = VERSION_GUID_DICT[version_guid_name]
self.definition['_id'] = version_guid
self.bulk.update_definition(self.course_key, self.definition)
result = self.bulk.get_definition(self.course_key, version_guid)
self.assertEquals(self.conn.get_definition.call_count, 0)
self.assertEqual(result, self.definition)
@ddt.data('deadbeef1234' * 2, u'deadbeef1234' * 2, ObjectId())
def test_read_definition_after_write_after_read(self, version_guid):
@ddt.data(*SAMPLE_GUIDS_LIST)
def test_read_definition_after_write_after_read(self, version_guid_name):
# Reading a definition that's been updated after being pulled from the db should
# still get the updated value
version_guid = VERSION_GUID_DICT[version_guid_name]
self.definition['_id'] = version_guid
self.bulk.get_definition(self.course_key, version_guid)
self.bulk.update_definition(self.course_key, self.definition)

View File

@@ -52,22 +52,21 @@ class TestUtils(unittest.TestCase):
shard = 2
ONLY_ROOTS = [
draft_node_constructor(Mock(), 'url1', 'vertical'),
draft_node_constructor(Mock(), 'url2', 'sequential'),
('url1', 'vertical'),
('url2', 'sequential'),
]
ONLY_ROOTS_URLS = ['url1', 'url2']
SOME_TREES = [
draft_node_constructor(Mock(), 'child_1', 'vertical_1'),
draft_node_constructor(Mock(), 'child_2', 'vertical_1'),
draft_node_constructor(Mock(), 'vertical_1', 'sequential_1'),
('child_1', 'vertical_1'),
('child_2', 'vertical_1'),
('vertical_1', 'sequential_1'),
draft_node_constructor(Mock(), 'child_3', 'vertical_2'),
draft_node_constructor(Mock(), 'child_4', 'vertical_2'),
draft_node_constructor(Mock(), 'vertical_2', 'grandparent_vertical'),
draft_node_constructor(Mock(), 'grandparent_vertical', 'great_grandparent_vertical'),
('child_3', 'vertical_2'),
('child_4', 'vertical_2'),
('vertical_2', 'grandparent_vertical'),
('grandparent_vertical', 'great_grandparent_vertical'),
]
SOME_TREES_ROOTS_URLS = ['vertical_1', 'grandparent_vertical']
@ddt.data(
@@ -75,8 +74,11 @@ class TestUtils(unittest.TestCase):
(SOME_TREES, SOME_TREES_ROOTS_URLS),
)
@ddt.unpack
def test_get_draft_subtree_roots(self, module_nodes, expected_roots_urls):
def test_get_draft_subtree_roots(self, node_arguments_list, expected_roots_urls):
"""tests for get_draft_subtree_roots"""
module_nodes = []
for node_args in node_arguments_list:
module_nodes.append(draft_node_constructor(Mock(), node_args[0], node_args[1]))
subtree_roots_urls = [root.url for root in get_draft_subtree_roots(module_nodes)]
# check that we return the expected urls
self.assertEqual(set(subtree_roots_urls), set(expected_roots_urls))

View File

@@ -2,6 +2,10 @@ import ddt
import itertools
from xmodule.tests import BulkAssertionTest, BulkAssertionError
ASSERTION_METHODS_DICT = {
"GETITEM_SPECIAL_METHOD": {}.__getitem__,
"LAMBDA": lambda: None
}
STATIC_PASSING_ASSERTIONS = (
('assertTrue', True),
@@ -36,13 +40,13 @@ STATIC_FAILING_ASSERTIONS = (
)
CONTEXT_PASSING_ASSERTIONS = (
('assertRaises', KeyError, {}.__getitem__, '1'),
('assertRaisesRegexp', KeyError, "1", {}.__getitem__, '1'),
('assertRaises', KeyError, "GETITEM_SPECIAL_METHOD", '1'),
('assertRaisesRegexp', KeyError, "1", "GETITEM_SPECIAL_METHOD", '1'),
)
CONTEXT_FAILING_ASSERTIONS = (
('assertRaises', ValueError, lambda: None),
('assertRaisesRegexp', KeyError, "2", {}.__getitem__, '1'),
('assertRaises', ValueError, "LAMBDA"),
('assertRaisesRegexp', KeyError, "2", "GETITEM_SPECIAL_METHOD", '1'),
)
@@ -55,11 +59,22 @@ class TestBulkAssertionTestCase(BulkAssertionTest):
# pylint: disable=bad-super-call
def _is_arg_in_assertion_methods_dict(self, argument):
"""
Takes in an argument, and returns whether
"""
return type(argument) == str and argument in ASSERTION_METHODS_DICT
def _run_assertion(self, assertion_tuple):
"""
Run the supplied tuple of (assertion, *args) as a method on this class.
"""
assertion, args = assertion_tuple[0], assertion_tuple[1:]
args_list = list(args)
for index, argument in enumerate(args_list):
if self._is_arg_in_assertion_methods_dict(argument):
args_list[index] = ASSERTION_METHODS_DICT[argument]
args = tuple(args_list)
getattr(self, assertion)(*args)
def _raw_assert(self, assertion_name, *args, **kwargs):
@@ -88,10 +103,10 @@ class TestBulkAssertionTestCase(BulkAssertionTest):
exception = args.pop(0)
while not callable(args[0]):
while not self._is_arg_in_assertion_methods_dict(args[0]):
assertion_args.append(args.pop(0))
function = args.pop(0)
function = ASSERTION_METHODS_DICT[args.pop(0)]
with getattr(self, assertion)(exception, *assertion_args):
function(*args)
@@ -104,10 +119,10 @@ class TestBulkAssertionTestCase(BulkAssertionTest):
exception = args.pop(0)
while not callable(args[0]):
while not self._is_arg_in_assertion_methods_dict(args[0]):
assertion_args.append(args.pop(0))
function = args.pop(0)
function = ASSERTION_METHODS_DICT[args.pop(0)]
with self._raw_assert('Raises', AssertionError) as context:
with getattr(self, assertion)(exception, *assertion_args):

View File

@@ -80,7 +80,8 @@ def flatten(class_dict):
Flatten a dict from cls -> [fields, ...] and yields values of the form (cls, fields)
for each entry in the dictionary value.
"""
for cls, fields_list in class_dict.items():
for cls in sorted(class_dict, key=lambda err: err.__name__):
fields_list = class_dict[cls]
for fields in fields_list:
yield (cls, fields)