diff --git a/openedx/core/djangoapps/content/block_structure/models.py b/openedx/core/djangoapps/content/block_structure/models.py index f8dc317fde..31ad25f303 100644 --- a/openedx/core/djangoapps/content/block_structure/models.py +++ b/openedx/core/djangoapps/content/block_structure/models.py @@ -4,6 +4,7 @@ Models used by the block structure framework. from __future__ import absolute_import +import errno from contextlib import contextmanager from datetime import datetime from logging import getLogger @@ -117,7 +118,9 @@ def _storage_error_handling(bs_model, operation, is_read_operation=False): yield except Exception as error: # pylint: disable=broad-except log.exception(u'BlockStructure: Exception %s on store %s; %s.', error.__class__, operation, bs_model) - if is_read_operation and isinstance(error, (IOError, SuspiciousOperation)): + if isinstance(error, OSError) and error.errno in (errno.EACCES, errno.EPERM): # pylint: disable=no-member + raise + elif is_read_operation and isinstance(error, (IOError, SuspiciousOperation)): # May have been caused by one of the possible error # situations listed above. Raise BlockStructureNotFound # so the block structure can be regenerated and restored. diff --git a/openedx/core/djangoapps/content/block_structure/tests/test_models.py b/openedx/core/djangoapps/content/block_structure/tests/test_models.py index f944fb57b5..5939a428ab 100644 --- a/openedx/core/djangoapps/content/block_structure/tests/test_models.py +++ b/openedx/core/djangoapps/content/block_structure/tests/test_models.py @@ -4,6 +4,7 @@ Unit tests for Block Structure models. # pylint: disable=protected-access from __future__ import absolute_import +import errno from itertools import product from uuid import uuid4 @@ -147,19 +148,23 @@ class BlockStructureModelTestCase(TestCase): self._assert_file_count_equal(min(num_prior_edits + 1, prune_keep_count)) @ddt.data( - (IOError, BlockStructureNotFound, True), - (IOError, IOError, False), - (SuspiciousOperation, BlockStructureNotFound, True), - (SuspiciousOperation, SuspiciousOperation, False), - (OSError, OSError, True), - (OSError, OSError, False), + (IOError, errno.ENOENT, u'No such file or directory', BlockStructureNotFound, True), + (IOError, errno.ENOENT, u'No such file or directory', IOError, False), + (SuspiciousOperation, None, None, BlockStructureNotFound, True), + (SuspiciousOperation, None, None, SuspiciousOperation, False), + (OSError, errno.EACCES, u'Permission denied', OSError, True), + (OSError, errno.EACCES, u'Permission denied', OSError, False), ) @ddt.unpack - def test_error_handling(self, error_raised_in_operation, expected_error_raised, is_read_operation): + def test_error_handling(self, error_raised_in_operation, errno_raised, message_raised, + expected_error_raised, is_read_operation): bs_model, _ = BlockStructureModel.update_or_create('test data', **self.params) with self.assertRaises(expected_error_raised): with _storage_error_handling(bs_model, 'operation', is_read_operation): - raise error_raised_in_operation + if errno_raised is not None: + raise error_raised_in_operation(errno_raised, message_raised) + else: + raise error_raised_in_operation @patch('openedx.core.djangoapps.content.block_structure.models.log') def test_old_mongo_keys(self, mock_log):