diff options
author | DjLegolas <djlegolas@protonmail.com> | 2022-02-11 12:40:47 +0200 |
---|---|---|
committer | Calum Lind <calumlind+deluge@gmail.com> | 2022-02-12 17:14:19 +0000 |
commit | f8f997a6ebe74409c824b4b56e9ba19e015e9013 (patch) | |
tree | 5317276b2f2b287fec3c8f1f9e89d1e9240a745c | |
parent | 374997a8d7fec910a3a63d4171a6a64bab08d3ef (diff) | |
download | deluge-f8f997a6ebe74409c824b4b56e9ba19e015e9013.tar.gz deluge-f8f997a6ebe74409c824b4b56e9ba19e015e9013.tar.bz2 deluge-f8f997a6ebe74409c824b4b56e9ba19e015e9013.zip |
[Config] Fix callLater func missing args
In a6840296, a refactor to the `config` class was introduced.
The change included an internal wrapper for `reactor.callLater`, for lazy
import, but didn't wrap it correctly and therefor, no args/kwargs were
passed to the wrapped method.
Furthermore, the exception was silently ignored.
This caused changes to be ignored and not applied, including
`preferencesmanager._on_config_value_change` callback.
Closes: https://github.com/deluge-torrent/deluge/pull/372
-rw-r--r-- | deluge/config.py | 4 | ||||
-rw-r--r-- | deluge/conftest.py | 27 | ||||
-rw-r--r-- | deluge/tests/test_config.py | 28 |
3 files changed, 56 insertions, 3 deletions
diff --git a/deluge/config.py b/deluge/config.py index 8671bc330..abf46d71b 100644 --- a/deluge/config.py +++ b/deluge/config.py @@ -144,11 +144,11 @@ class Config: self.load() - def callLater(self, period, func): # noqa: N802 ignore camelCase + def callLater(self, period, func, *args, **kwargs): # noqa: N802 ignore camelCase """Wrapper around reactor.callLater for test purpose.""" from twisted.internet import reactor - return reactor.callLater(period, func) + return reactor.callLater(period, func, *args, **kwargs) def __contains__(self, item): return item in self.__config diff --git a/deluge/conftest.py b/deluge/conftest.py index ad7c8b30f..4266938fa 100644 --- a/deluge/conftest.py +++ b/deluge/conftest.py @@ -4,11 +4,13 @@ # See LICENSE for more details. # +import unittest.mock import warnings import pytest import pytest_twisted -from twisted.internet.defer import maybeDeferred +from twisted.internet import reactor +from twisted.internet.defer import Deferred, maybeDeferred from twisted.internet.error import CannotListenError from twisted.python.failure import Failure @@ -32,6 +34,29 @@ def listen_port(request): @pytest.fixture +def mock_callback(): + """Returns a `Mock` object which can be registered as a callback to test against. + + If callback was not called within `timeout` seconds, it will raise a TimeoutError. + The returned Mock instance will have a `deferred` attribute which will complete when the callback has been called. + """ + + def reset(): + if mock.called: + original_reset_mock() + deferred = Deferred() + deferred.addTimeout(0.5, reactor) + mock.side_effect = lambda *args, **kw: deferred.callback((args, kw)) + mock.deferred = deferred + + mock = unittest.mock.Mock() + original_reset_mock = mock.reset_mock + mock.reset_mock = reset + mock.reset_mock() + return mock + + +@pytest.fixture def config_dir(tmp_path): deluge.configmanager.set_config_dir(tmp_path) yield tmp_path diff --git a/deluge/tests/test_config.py b/deluge/tests/test_config.py index 8bf470dbc..2840dbf5b 100644 --- a/deluge/tests/test_config.py +++ b/deluge/tests/test_config.py @@ -10,6 +10,7 @@ import os from codecs import getwriter import pytest +import pytest_twisted from twisted.internet import task from deluge.common import JSON_FORMAT @@ -83,6 +84,33 @@ class TestConfig: config._save_timer.cancel() + @pytest_twisted.ensureDeferred + async def test_on_changed_callback(self, mock_callback): + config = Config('test.conf', config_dir=self.config_dir) + config.register_change_callback(mock_callback) + config['foo'] = 1 + assert config['foo'] == 1 + await mock_callback.deferred + mock_callback.assert_called_once_with('foo', 1) + + @pytest_twisted.ensureDeferred + async def test_key_function_callback(self, mock_callback): + config = Config( + 'test.conf', defaults={'foo': 1, 'bar': 1}, config_dir=self.config_dir + ) + + assert config['foo'] == 1 + config.register_set_function('foo', mock_callback) + await mock_callback.deferred + mock_callback.assert_called_once_with('foo', 1) + + mock_callback.reset_mock() + config.register_set_function('bar', mock_callback, apply_now=False) + mock_callback.assert_not_called() + config['bar'] = 2 + await mock_callback.deferred + mock_callback.assert_called_once_with('bar', 2) + def test_get(self): config = Config('test.conf', config_dir=self.config_dir) config['foo'] = 1 |