summaryrefslogtreecommitdiff
path: root/tests/settings_tests
diff options
context:
space:
mode:
authorSÅ‚awek Ehlert <slafs@op.pl>2018-06-19 23:10:55 +0200
committerTim Graham <timograham@gmail.com>2018-07-30 15:59:37 -0400
commitc6238bf02b7ca5cf0f31f893a951f257dc557600 (patch)
treec02d11f07f188a9dad211d469a159206dca9320e /tests/settings_tests
parentcebbcaa1baa6eb7f9ec3e223abdc496a983ea482 (diff)
downloaddjango-c6238bf02b7ca5cf0f31f893a951f257dc557600.tar.gz
Fixed #29467 -- Made override_settings handle errors in setting_changed signal receivers.
Diffstat (limited to 'tests/settings_tests')
-rw-r--r--tests/settings_tests/tests.py103
1 files changed, 103 insertions, 0 deletions
diff --git a/tests/settings_tests/tests.py b/tests/settings_tests/tests.py
index 383345494d..bfd580b600 100644
--- a/tests/settings_tests/tests.py
+++ b/tests/settings_tests/tests.py
@@ -441,3 +441,106 @@ class TestListSettings(unittest.TestCase):
finally:
del sys.modules['fake_settings_module']
delattr(settings_module, setting)
+
+
+class SettingChangeEnterException(Exception):
+ pass
+
+
+class SettingChangeExitException(Exception):
+ pass
+
+
+class OverrideSettingsIsolationOnExceptionTests(SimpleTestCase):
+ """
+ The override_settings context manager restore settings if one of the
+ receivers of "setting_changed" signal fails. Check the three cases of
+ receiver failure detailed in receiver(). In each case, ALL receivers are
+ called when exiting the context manager.
+ """
+ def setUp(self):
+ signals.setting_changed.connect(self.receiver)
+ self.addCleanup(signals.setting_changed.disconnect, self.receiver)
+ # Create a spy that's connected to the `setting_changed` signal and
+ # executed AFTER `self.receiver`.
+ self.spy_receiver = mock.Mock()
+ signals.setting_changed.connect(self.spy_receiver)
+ self.addCleanup(signals.setting_changed.disconnect, self.spy_receiver)
+
+ def receiver(self, **kwargs):
+ """
+ A receiver that fails while certain settings are being changed.
+ - SETTING_BOTH raises an error while receiving the signal
+ on both entering and exiting the context manager.
+ - SETTING_ENTER raises an error only on enter.
+ - SETTING_EXIT raises an error only on exit.
+ """
+ setting = kwargs['setting']
+ enter = kwargs['enter']
+ if setting in ('SETTING_BOTH', 'SETTING_ENTER') and enter:
+ raise SettingChangeEnterException
+ if setting in ('SETTING_BOTH', 'SETTING_EXIT') and not enter:
+ raise SettingChangeExitException
+
+ def check_settings(self):
+ """Assert that settings for these tests aren't present."""
+ self.assertFalse(hasattr(settings, 'SETTING_BOTH'))
+ self.assertFalse(hasattr(settings, 'SETTING_ENTER'))
+ self.assertFalse(hasattr(settings, 'SETTING_EXIT'))
+ self.assertFalse(hasattr(settings, 'SETTING_PASS'))
+
+ def check_spy_receiver_exit_calls(self, call_count):
+ """
+ Assert that `self.spy_receiver` was called exactly `call_count` times
+ with the ``enter=False`` keyword argument.
+ """
+ kwargs_with_exit = [
+ kwargs for args, kwargs in self.spy_receiver.call_args_list
+ if ('enter', False) in kwargs.items()
+ ]
+ self.assertEqual(len(kwargs_with_exit), call_count)
+
+ def test_override_settings_both(self):
+ """Receiver fails on both enter and exit."""
+ with self.assertRaises(SettingChangeEnterException):
+ with override_settings(SETTING_PASS='BOTH', SETTING_BOTH='BOTH'):
+ pass
+
+ self.check_settings()
+ # Two settings were touched, so expect two calls of `spy_receiver`.
+ self.check_spy_receiver_exit_calls(call_count=2)
+
+ def test_override_settings_enter(self):
+ """Receiver fails on enter only."""
+ with self.assertRaises(SettingChangeEnterException):
+ with override_settings(SETTING_PASS='ENTER', SETTING_ENTER='ENTER'):
+ pass
+
+ self.check_settings()
+ # Two settings were touched, so expect two calls of `spy_receiver`.
+ self.check_spy_receiver_exit_calls(call_count=2)
+
+ def test_override_settings_exit(self):
+ """Receiver fails on exit only."""
+ with self.assertRaises(SettingChangeExitException):
+ with override_settings(SETTING_PASS='EXIT', SETTING_EXIT='EXIT'):
+ pass
+
+ self.check_settings()
+ # Two settings were touched, so expect two calls of `spy_receiver`.
+ self.check_spy_receiver_exit_calls(call_count=2)
+
+ def test_override_settings_reusable_on_enter(self):
+ """
+ Error is raised correctly when reusing the same override_settings
+ instance.
+ """
+ @override_settings(SETTING_ENTER='ENTER')
+ def decorated_function():
+ pass
+
+ with self.assertRaises(SettingChangeEnterException):
+ decorated_function()
+ signals.setting_changed.disconnect(self.receiver)
+ # This call shouldn't raise any errors.
+ decorated_function()