diff --git a/deluge/conftest.py b/deluge/conftest.py new file mode 100644 index 000000000..ad7c8b30f --- /dev/null +++ b/deluge/conftest.py @@ -0,0 +1,158 @@ +# +# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with +# the additional special exception to link portions of this program with the OpenSSL library. +# See LICENSE for more details. +# + +import warnings + +import pytest +import pytest_twisted +from twisted.internet.defer import maybeDeferred +from twisted.internet.error import CannotListenError +from twisted.python.failure import Failure + +import deluge.component as _component +import deluge.configmanager +from deluge.common import get_localhost_auth +from deluge.tests import common +from deluge.ui.client import client as _client + +DEFAULT_LISTEN_PORT = 58900 + + +@pytest.fixture +def listen_port(request): + if request and 'daemon' in request.fixturenames: + try: + return request.getfixturevalue('daemon').listen_port + except Exception: + pass + return DEFAULT_LISTEN_PORT + + +@pytest.fixture +def config_dir(tmp_path): + deluge.configmanager.set_config_dir(tmp_path) + yield tmp_path + + +@pytest_twisted.async_yield_fixture() +async def client(request, config_dir, monkeypatch, listen_port): + # monkeypatch.setattr( + # _client, 'connect', functools.partial(_client.connect, port=listen_port) + # ) + try: + username, password = get_localhost_auth() + except Exception: + username, password = '', '' + await _client.connect( + 'localhost', + port=listen_port, + username=username, + password=password, + ) + yield _client + if _client.connected(): + await _client.disconnect() + + +@pytest_twisted.async_yield_fixture +async def daemon(request, config_dir): + listen_port = DEFAULT_LISTEN_PORT + logfile = f'daemon_{request.node.name}.log' + if hasattr(request.cls, 'daemon_custom_script'): + custom_script = request.cls.daemon_custom_script + else: + custom_script = '' + + for dummy in range(10): + try: + d, daemon = common.start_core( + listen_port=listen_port, + logfile=logfile, + timeout=5, + timeout_msg='Timeout!', + custom_script=custom_script, + print_stdout=True, + print_stderr=True, + config_directory=config_dir, + ) + await d + except CannotListenError as ex: + exception_error = ex + listen_port += 1 + except (KeyboardInterrupt, SystemExit): + raise + else: + break + else: + raise exception_error + daemon.listen_port = listen_port + yield daemon + await daemon.kill() + + +@pytest.fixture(autouse=True) +def common_fixture(config_dir, request, monkeypatch, listen_port): + """Adds some instance attributes to test classes for backwards compatibility with old testing.""" + + def fail(self, reason): + if isinstance(reason, Failure): + reason = reason.value + return pytest.fail(str(reason)) + + if request.instance: + request.instance.patch = monkeypatch.setattr + request.instance.config_dir = config_dir + request.instance.listen_port = listen_port + request.instance.id = lambda: request.node.name + request.cls.fail = fail + + +@pytest_twisted.async_yield_fixture(scope='function') +async def component(request): + """Verify component registry is clean, and clean up after test.""" + if len(_component._ComponentRegistry.components) != 0: + warnings.warn( + 'The component._ComponentRegistry.components is not empty on test setup.\n' + 'This is probably caused by another test that did not clean up after finishing!: %s' + % _component._ComponentRegistry.components + ) + + yield _component + + await _component.shutdown() + _component._ComponentRegistry.components.clear() + _component._ComponentRegistry.dependents.clear() + + +@pytest_twisted.async_yield_fixture(scope='function') +async def base_fixture(common_fixture, component, request): + """This fixture is autoused on all tests that subclass BaseTestCase""" + self = request.instance + + if hasattr(self, 'set_up'): + try: + await maybeDeferred(self.set_up) + except Exception as exc: + warnings.warn('Error caught in test setup!\n%s' % exc) + pytest.fail('Error caught in test setup!\n%s' % exc) + + yield + + if hasattr(self, 'tear_down'): + try: + await maybeDeferred(self.tear_down) + except Exception as exc: + pytest.fail('Error caught in test teardown!\n%s' % exc) + + +@pytest.mark.usefixtures('base_fixture') +class BaseTestCase: + """This is the base class that should be used for all test classes + that create classes that inherit from deluge.component.Component. It + ensures that the component registry has been cleaned up when tests + have finished. + + """ diff --git a/deluge/httpdownloader.py b/deluge/httpdownloader.py index 43b32b6b9..700ade06b 100644 --- a/deluge/httpdownloader.py +++ b/deluge/httpdownloader.py @@ -16,7 +16,7 @@ from twisted.internet.defer import Deferred from twisted.python.failure import Failure from twisted.web import client, http from twisted.web._newclient import HTTPClientParser -from twisted.web.error import PageRedirect +from twisted.web.error import Error, PageRedirect from twisted.web.http_headers import Headers from twisted.web.iweb import IAgent from zope.interface import implementer @@ -122,6 +122,9 @@ class HTTPDownloaderAgent: location = response.headers.getRawHeaders(b'location')[0] error = PageRedirect(response.code, location=location) finished.errback(Failure(error)) + elif response.code >= 400: + error = Error(response.code) + finished.errback(Failure(error)) else: headers = response.headers body_length = int(headers.getRawHeaders(b'content-length', default=[0])[0]) diff --git a/deluge/plugins/Stats/deluge_stats/tests/test_stats.py b/deluge/plugins/Stats/deluge_stats/tests/test_stats.py index f40497b15..ce3bafa1f 100644 --- a/deluge/plugins/Stats/deluge_stats/tests/test_stats.py +++ b/deluge/plugins/Stats/deluge_stats/tests/test_stats.py @@ -4,13 +4,12 @@ # See LICENSE for more details. # import pytest +import pytest_twisted from twisted.internet import defer from twisted.trial import unittest import deluge.component as component from deluge.common import fsize, fspeed -from deluge.tests import common as tests_common -from deluge.tests.basetest import BaseTestCase from deluge.ui.client import client @@ -23,17 +22,17 @@ def print_totals(totals): print('down:', fsize(totals['total_download'] - totals['total_payload_download'])) -class StatsTestCase(BaseTestCase): - def set_up(self): +@pytest.mark.usefixtures('component') +class TestStatsPlugin: + @pytest_twisted.async_yield_fixture(autouse=True) + async def set_up(self): defer.setDebugging(True) - tests_common.set_tmp_config_dir() client.start_standalone() client.core.enable_plugin('Stats') - return component.start() - - def tear_down(self): + await component.start() + yield client.stop_standalone() - return component.shutdown() + await component.shutdown() @defer.inlineCallbacks def test_client_totals(self): @@ -42,10 +41,10 @@ class StatsTestCase(BaseTestCase): raise unittest.SkipTest('WebUi plugin not available for testing') totals = yield client.stats.get_totals() - self.assertEqual(totals['total_upload'], 0) - self.assertEqual(totals['total_payload_upload'], 0) - self.assertEqual(totals['total_payload_download'], 0) - self.assertEqual(totals['total_download'], 0) + assert totals['total_upload'] == 0 + assert totals['total_payload_upload'] == 0 + assert totals['total_payload_download'] == 0 + assert totals['total_download'] == 0 # print_totals(totals) @defer.inlineCallbacks @@ -55,10 +54,10 @@ class StatsTestCase(BaseTestCase): raise unittest.SkipTest('WebUi plugin not available for testing') totals = yield client.stats.get_session_totals() - self.assertEqual(totals['total_upload'], 0) - self.assertEqual(totals['total_payload_upload'], 0) - self.assertEqual(totals['total_payload_download'], 0) - self.assertEqual(totals['total_download'], 0) + assert totals['total_upload'] == 0 + assert totals['total_payload_upload'] == 0 + assert totals['total_payload_download'] == 0 + assert totals['total_download'] == 0 # print_totals(totals) @pytest.mark.gtkui diff --git a/deluge/plugins/WebUi/deluge_webui/tests/test_plugin_webui.py b/deluge/plugins/WebUi/deluge_webui/tests/test_plugin_webui.py index 260d18daa..986ccb970 100644 --- a/deluge/plugins/WebUi/deluge_webui/tests/test_plugin_webui.py +++ b/deluge/plugins/WebUi/deluge_webui/tests/test_plugin_webui.py @@ -5,31 +5,34 @@ # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # - +import pytest +import pytest_twisted from twisted.trial import unittest import deluge.component as component from deluge.core.core import Core from deluge.core.rpcserver import RPCServer from deluge.tests import common -from deluge.tests.basetest import BaseTestCase common.disable_new_release_check() -class WebUIPluginTestCase(BaseTestCase): - def set_up(self): - common.set_tmp_config_dir() +@pytest.mark.usefixtures('component') +class TestWebUIPlugin: + @pytest_twisted.async_yield_fixture(autouse=True) + async def set_up(self, request): + self = request.instance self.rpcserver = RPCServer(listen=False) self.core = Core() - return component.start() + await component.start() + + yield - def tear_down(self): def on_shutdown(result): del self.rpcserver del self.core - return component.shutdown().addCallback(on_shutdown) + await component.shutdown().addCallback(on_shutdown) def test_enable_webui(self): if 'WebUi' not in self.core.get_available_plugins(): @@ -40,7 +43,7 @@ class WebUIPluginTestCase(BaseTestCase): def result_cb(result): if 'WebUi' not in self.core.get_enabled_plugins(): self.fail('Failed to enable WebUi plugin') - self.assertTrue(result) + assert result d.addBoth(result_cb) return d diff --git a/deluge/tests/basetest.py b/deluge/tests/basetest.py deleted file mode 100644 index c1719c132..000000000 --- a/deluge/tests/basetest.py +++ /dev/null @@ -1,55 +0,0 @@ -# -# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with -# the additional special exception to link portions of this program with the OpenSSL library. -# See LICENSE for more details. -# - -import warnings - -from twisted.internet.defer import maybeDeferred -from twisted.trial import unittest - -import deluge.component as component - - -class BaseTestCase(unittest.TestCase): - """This is the base class that should be used for all test classes - that create classes that inherit from deluge.component.Component. It - ensures that the component registry has been cleaned up when tests - have finished. - - """ - - def setUp(self): # NOQA: N803 - - if len(component._ComponentRegistry.components) != 0: - warnings.warn( - 'The component._ComponentRegistry.components is not empty on test setup.\n' - 'This is probably caused by another test that did not clean up after finishing!: %s' - % component._ComponentRegistry.components - ) - d = maybeDeferred(self.set_up) - - def on_setup_error(error): - warnings.warn('Error caught in test setup!\n%s' % error.getTraceback()) - self.fail() - - return d.addErrback(on_setup_error) - - def tearDown(self): # NOQA: N803 - d = maybeDeferred(self.tear_down) - - def on_teardown_failed(error): - self.fail('Error caught in test teardown!\n%s' % error.getTraceback()) - - def on_teardown_complete(result): - component._ComponentRegistry.components.clear() - component._ComponentRegistry.dependents.clear() - - return d.addCallbacks(on_teardown_complete, on_teardown_failed) - - def set_up(self): - pass - - def tear_down(self): - pass diff --git a/deluge/tests/common.py b/deluge/tests/common.py index 7e73f1dd3..bed054b9f 100644 --- a/deluge/tests/common.py +++ b/deluge/tests/common.py @@ -8,13 +8,12 @@ import os import sys -import tempfile import traceback +import pytest from twisted.internet import defer, protocol, reactor from twisted.internet.defer import Deferred from twisted.internet.error import CannotListenError -from twisted.trial import unittest import deluge.configmanager import deluge.core.preferencesmanager @@ -31,12 +30,6 @@ def disable_new_release_check(): deluge.core.preferencesmanager.DEFAULT_PREFS['new_release_check'] = False -def set_tmp_config_dir(): - config_directory = tempfile.mkdtemp() - deluge.configmanager.set_config_dir(config_directory) - return config_directory - - def setup_test_logger(level='info', prefix='deluge'): deluge.log.setup_logger(level, filename='%s.log' % prefix, twisted_observer=False) @@ -54,7 +47,7 @@ def todo_test(caller): filename = os.path.basename(traceback.extract_stack(None, 2)[0][0]) funcname = traceback.extract_stack(None, 2)[0][2] - raise unittest.SkipTest(f'TODO: {filename}:{funcname}') + pytest.skip(f'TODO: {filename}:{funcname}') def add_watchdog(deferred, timeout=0.05, message=None): @@ -219,7 +212,7 @@ class ProcessOutputHandler(protocol.ProcessProtocol): def start_core( - listen_port=58846, + listen_port=58900, logfile=None, timeout=10, timeout_msg=None, @@ -227,6 +220,7 @@ def start_core( print_stdout=True, print_stderr=True, extra_callbacks=None, + config_directory='', ): """Start the deluge core as a daemon. @@ -248,7 +242,6 @@ def start_core( or upon timeout expiry. The ProcessOutputHandler is the handler for the deluged process. """ - config_directory = set_tmp_config_dir() daemon_script = """ import sys import deluge.core.daemon_entry @@ -268,7 +261,7 @@ except Exception: import traceback sys.stderr.write('Exception raised:\\n %%s' %% traceback.format_exc()) """ % { - 'dir': config_directory.replace('\\', '\\\\'), + 'dir': config_directory.as_posix(), 'port': listen_port, 'script': custom_script, } diff --git a/deluge/tests/common_web.py b/deluge/tests/common_web.py index 5a7f40fc6..8db49d243 100644 --- a/deluge/tests/common_web.py +++ b/deluge/tests/common_web.py @@ -6,19 +6,20 @@ # See LICENSE for more details. # +import pytest + import deluge.common -import deluge.component as component import deluge.ui.web.auth import deluge.ui.web.server from deluge import configmanager +from deluge.conftest import BaseTestCase from deluge.ui.web.server import DelugeWeb -from .basetest import BaseTestCase from .common import ReactorOverride -from .daemon_base import DaemonBase -class WebServerTestBase(BaseTestCase, DaemonBase): +@pytest.mark.usefixtures('daemon', 'component') +class WebServerTestBase(BaseTestCase): """ Base class for tests that need a running webapi @@ -27,10 +28,7 @@ class WebServerTestBase(BaseTestCase, DaemonBase): def set_up(self): self.host_id = None deluge.ui.web.server.reactor = ReactorOverride() - d = self.common_set_up() - d.addCallback(self.start_core) - d.addCallback(self.start_webapi) - return d + return self.start_webapi(None) def start_webapi(self, arg): self.webserver_listen_port = 8999 @@ -47,11 +45,6 @@ class WebServerTestBase(BaseTestCase, DaemonBase): self.host_id = host[0] self.deluge_web.start() - def tear_down(self): - d = component.shutdown() - d.addCallback(self.terminate_core) - return d - class WebServerMockBase: """ diff --git a/deluge/tests/daemon_base.py b/deluge/tests/daemon_base.py index 5d1d3f5f6..3ae86c4ca 100644 --- a/deluge/tests/daemon_base.py +++ b/deluge/tests/daemon_base.py @@ -15,16 +15,9 @@ import deluge.component as component from . import common -@pytest.mark.usefixtures('get_pytest_basetemp') +@pytest.mark.usefixtures('config_dir') class DaemonBase: - basetemp = None - - @pytest.fixture - def get_pytest_basetemp(self, request): - self.basetemp = request.config.option.basetemp - def common_set_up(self): - common.set_tmp_config_dir() self.listen_port = 58900 self.core = None return component.start() @@ -71,6 +64,7 @@ class DaemonBase: print_stdout=print_stdout, print_stderr=print_stderr, extra_callbacks=extra_callbacks, + config_directory=self.config_dir, ) yield d except CannotListenError as ex: diff --git a/deluge/tests/test_alertmanager.py b/deluge/tests/test_alertmanager.py index 85512d47b..5e63864e8 100644 --- a/deluge/tests/test_alertmanager.py +++ b/deluge/tests/test_alertmanager.py @@ -5,12 +5,11 @@ # import deluge.component as component +from deluge.conftest import BaseTestCase from deluge.core.core import Core -from .basetest import BaseTestCase - -class AlertManagerTestCase(BaseTestCase): +class TestAlertManager(BaseTestCase): def set_up(self): self.core = Core() self.core.config.config['lsd'] = False @@ -25,7 +24,7 @@ class AlertManagerTestCase(BaseTestCase): return self.am.register_handler('dummy_alert', handler) - self.assertEqual(self.am.handlers['dummy_alert'], [handler]) + assert self.am.handlers['dummy_alert'] == [handler] def test_deregister_handler(self): def handler(alert): @@ -33,4 +32,4 @@ class AlertManagerTestCase(BaseTestCase): self.am.register_handler('dummy_alert', handler) self.am.deregister_handler(handler) - self.assertEqual(self.am.handlers['dummy_alert'], []) + assert self.am.handlers['dummy_alert'] == [] diff --git a/deluge/tests/test_authmanager.py b/deluge/tests/test_authmanager.py index cee399890..aa86fdbac 100644 --- a/deluge/tests/test_authmanager.py +++ b/deluge/tests/test_authmanager.py @@ -6,12 +6,11 @@ import deluge.component as component from deluge.common import get_localhost_auth +from deluge.conftest import BaseTestCase from deluge.core.authmanager import AUTH_LEVEL_ADMIN, AuthManager -from .basetest import BaseTestCase - -class AuthManagerTestCase(BaseTestCase): +class TestAuthManager(BaseTestCase): def set_up(self): self.auth = AuthManager() self.auth.start() @@ -21,4 +20,4 @@ class AuthManagerTestCase(BaseTestCase): return component.shutdown() def test_authorize(self): - self.assertEqual(self.auth.authorize(*get_localhost_auth()), AUTH_LEVEL_ADMIN) + assert self.auth.authorize(*get_localhost_auth()) == AUTH_LEVEL_ADMIN diff --git a/deluge/tests/test_bencode.py b/deluge/tests/test_bencode.py index 05c6814b2..a4a76818f 100644 --- a/deluge/tests/test_bencode.py +++ b/deluge/tests/test_bencode.py @@ -3,14 +3,15 @@ # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # -from twisted.trial import unittest + +import pytest from deluge import bencode from . import common -class BencodeTestCase(unittest.TestCase): +class TestBencode: def test_bencode_unicode_metainfo(self): filename = common.get_test_data_file('test.torrent') with open(filename, 'rb') as _file: @@ -18,14 +19,14 @@ class BencodeTestCase(unittest.TestCase): bencode.bencode({b'info': metainfo}) def test_bencode_unicode_value(self): - self.assertEqual(bencode.bencode(b'abc'), b'3:abc') - self.assertEqual(bencode.bencode('abc'), b'3:abc') + assert bencode.bencode(b'abc') == b'3:abc' + assert bencode.bencode('abc') == b'3:abc' def test_bdecode(self): - self.assertEqual(bencode.bdecode(b'3:dEf'), b'dEf') - with self.assertRaises(bencode.BTFailure): + assert bencode.bdecode(b'3:dEf') == b'dEf' + with pytest.raises(bencode.BTFailure): bencode.bdecode('dEf') - with self.assertRaises(bencode.BTFailure): + with pytest.raises(bencode.BTFailure): bencode.bdecode(b'dEf') - with self.assertRaises(bencode.BTFailure): + with pytest.raises(bencode.BTFailure): bencode.bdecode({'dEf': 123}) diff --git a/deluge/tests/test_client.py b/deluge/tests/test_client.py index 901bb85b0..5a6727907 100644 --- a/deluge/tests/test_client.py +++ b/deluge/tests/test_client.py @@ -3,18 +3,15 @@ # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # - +import pytest +import pytest_twisted from twisted.internet import defer -import deluge.component as component from deluge import error from deluge.common import AUTH_LEVEL_NORMAL, get_localhost_auth from deluge.core.authmanager import AUTH_LEVEL_ADMIN from deluge.ui.client import Client, DaemonSSLProxy, client -from .basetest import BaseTestCase -from .daemon_base import DaemonBase - class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy): def authenticate(self, username, password): @@ -75,24 +72,13 @@ class NoVersionSendingClient(Client): self.disconnect_callback() -class ClientTestCase(BaseTestCase, DaemonBase): - def set_up(self): - d = self.common_set_up() - d.addCallback(self.start_core) - d.addErrback(self.terminate_core) - return d - - def tear_down(self): - d = component.shutdown() - d.addCallback(self.terminate_core) - return d - +@pytest.mark.usefixtures('daemon', 'client') +class TestClient: def test_connect_no_credentials(self): d = client.connect('localhost', self.listen_port, username='', password='') def on_connect(result): - self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN) - self.addCleanup(client.disconnect) + assert client.get_auth_level() == AUTH_LEVEL_ADMIN return result d.addCallbacks(on_connect, self.fail) @@ -105,8 +91,7 @@ class ClientTestCase(BaseTestCase, DaemonBase): ) def on_connect(result): - self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN) - self.addCleanup(client.disconnect) + assert client.get_auth_level() == AUTH_LEVEL_ADMIN return result d.addCallbacks(on_connect, self.fail) @@ -119,21 +104,18 @@ class ClientTestCase(BaseTestCase, DaemonBase): ) def on_failure(failure): - self.assertEqual(failure.trap(error.BadLoginError), error.BadLoginError) - self.assertEqual(failure.value.message, 'Password does not match') - self.addCleanup(client.disconnect) + assert failure.trap(error.BadLoginError) == error.BadLoginError + assert failure.value.message == 'Password does not match' d.addCallbacks(self.fail, on_failure) return d def test_connect_invalid_user(self): - username, password = get_localhost_auth() d = client.connect('localhost', self.listen_port, username='invalid-user') def on_failure(failure): - self.assertEqual(failure.trap(error.BadLoginError), error.BadLoginError) - self.assertEqual(failure.value.message, 'Username does not exist') - self.addCleanup(client.disconnect) + assert failure.trap(error.BadLoginError) == error.BadLoginError + assert failure.value.message == 'Username does not exist' d.addCallbacks(self.fail, on_failure) return d @@ -143,16 +125,16 @@ class ClientTestCase(BaseTestCase, DaemonBase): d = client.connect('localhost', self.listen_port, username=username) def on_failure(failure): - self.assertEqual( - failure.trap(error.AuthenticationRequired), error.AuthenticationRequired + assert ( + failure.trap(error.AuthenticationRequired) + == error.AuthenticationRequired ) - self.assertEqual(failure.value.username, username) - self.addCleanup(client.disconnect) + assert failure.value.username == username d.addCallbacks(self.fail, on_failure) return d - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_connect_with_password(self): username, password = get_localhost_auth() yield client.connect( @@ -163,19 +145,15 @@ class ClientTestCase(BaseTestCase, DaemonBase): ret = yield client.connect( 'localhost', self.listen_port, username='testuser', password='testpw' ) - self.assertEqual(ret, AUTH_LEVEL_NORMAL) - yield + assert ret == AUTH_LEVEL_NORMAL - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_invalid_rpc_method_call(self): yield client.connect('localhost', self.listen_port, username='', password='') d = client.core.invalid_method() def on_failure(failure): - self.assertEqual( - failure.trap(error.WrappedException), error.WrappedException - ) - self.addCleanup(client.disconnect) + assert failure.trap(error.WrappedException) == error.WrappedException d.addCallbacks(self.fail, on_failure) yield d @@ -188,10 +166,7 @@ class ClientTestCase(BaseTestCase, DaemonBase): ) def on_failure(failure): - self.assertEqual( - failure.trap(error.IncompatibleClient), error.IncompatibleClient - ) - self.addCleanup(no_version_sending_client.disconnect) + assert failure.trap(error.IncompatibleClient) == error.IncompatibleClient d.addCallbacks(self.fail, on_failure) return d diff --git a/deluge/tests/test_common.py b/deluge/tests/test_common.py index 26d72e1ac..6129f679d 100644 --- a/deluge/tests/test_common.py +++ b/deluge/tests/test_common.py @@ -8,7 +8,7 @@ import os import sys import tarfile -from twisted.trial import unittest +import pytest from deluge.common import ( VersionSplit, @@ -30,93 +30,83 @@ from deluge.common import ( is_url, windows_check, ) -from deluge.i18n import setup_translation -from .common import get_test_data_file, set_tmp_config_dir +from .common import get_test_data_file -class CommonTestCase(unittest.TestCase): - def setUp(self): # NOQA - self.config_dir = set_tmp_config_dir() - setup_translation() - - def tearDown(self): # NOQA - pass - +class TestCommon: def test_fsize(self): - self.assertEqual(fsize(0), '0 B') - self.assertEqual(fsize(100), '100 B') - self.assertEqual(fsize(1023), '1023 B') - self.assertEqual(fsize(1024), '1.0 KiB') - self.assertEqual(fsize(1048575), '1024.0 KiB') - self.assertEqual(fsize(1048576), '1.0 MiB') - self.assertEqual(fsize(1073741823), '1024.0 MiB') - self.assertEqual(fsize(1073741824), '1.0 GiB') - self.assertEqual(fsize(112245), '109.6 KiB') - self.assertEqual(fsize(110723441824), '103.1 GiB') - self.assertEqual(fsize(1099511627775), '1024.0 GiB') - self.assertEqual(fsize(1099511627777), '1.0 TiB') - self.assertEqual(fsize(766148267453245), '696.8 TiB') + assert fsize(0) == '0 B' + assert fsize(100) == '100 B' + assert fsize(1023) == '1023 B' + assert fsize(1024) == '1.0 KiB' + assert fsize(1048575) == '1024.0 KiB' + assert fsize(1048576) == '1.0 MiB' + assert fsize(1073741823) == '1024.0 MiB' + assert fsize(1073741824) == '1.0 GiB' + assert fsize(112245) == '109.6 KiB' + assert fsize(110723441824) == '103.1 GiB' + assert fsize(1099511627775) == '1024.0 GiB' + assert fsize(1099511627777) == '1.0 TiB' + assert fsize(766148267453245) == '696.8 TiB' def test_fpcnt(self): - self.assertTrue(fpcnt(0.9311) == '93.11%') + assert fpcnt(0.9311) == '93.11%' def test_fspeed(self): - self.assertTrue(fspeed(43134) == '42.1 KiB/s') + assert fspeed(43134) == '42.1 KiB/s' def test_fpeer(self): - self.assertTrue(fpeer(10, 20) == '10 (20)') - self.assertTrue(fpeer(10, -1) == '10') + assert fpeer(10, 20) == '10 (20)' + assert fpeer(10, -1) == '10' def test_ftime(self): - self.assertEqual(ftime(0), '') - self.assertEqual(ftime(5), '5s') - self.assertEqual(ftime(100), '1m 40s') - self.assertEqual(ftime(3789), '1h 3m') - self.assertEqual(ftime(23011), '6h 23m') - self.assertEqual(ftime(391187), '4d 12h') - self.assertEqual(ftime(604800), '1w 0d') - self.assertEqual(ftime(13893086), '22w 6d') - self.assertEqual(ftime(59740269), '1y 46w') - self.assertEqual(ftime(61.25), '1m 1s') - self.assertEqual(ftime(119.9), '1m 59s') + assert ftime(0) == '' + assert ftime(5) == '5s' + assert ftime(100) == '1m 40s' + assert ftime(3789) == '1h 3m' + assert ftime(23011) == '6h 23m' + assert ftime(391187) == '4d 12h' + assert ftime(604800) == '1w 0d' + assert ftime(13893086) == '22w 6d' + assert ftime(59740269) == '1y 46w' + assert ftime(61.25) == '1m 1s' + assert ftime(119.9) == '1m 59s' def test_fdate(self): - self.assertTrue(fdate(-1) == '') + assert fdate(-1) == '' def test_is_url(self): - self.assertTrue(is_url('http://deluge-torrent.org')) - self.assertFalse(is_url('file://test.torrent')) + assert is_url('http://deluge-torrent.org') + assert not is_url('file://test.torrent') def test_is_magnet(self): - self.assertTrue( - is_magnet('magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN') - ) - self.assertFalse(is_magnet(None)) + assert is_magnet('magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN') + assert not is_magnet(None) def test_is_infohash(self): - self.assertTrue(is_infohash('2dc5d0e71a66fe69649a640d39cb00a259704973')) + assert is_infohash('2dc5d0e71a66fe69649a640d39cb00a259704973') def test_get_path_size(self): if windows_check() and sys.version_info < (3, 8): # https://bugs.python.org/issue1311 - raise unittest.SkipTest('os.devnull returns False on Windows') - self.assertTrue(get_path_size(os.devnull) == 0) - self.assertTrue(get_path_size('non-existant.file') == -1) + pytest.skip('os.devnull returns False on Windows') + assert get_path_size(os.devnull) == 0 + assert get_path_size('non-existant.file') == -1 def test_is_ip(self): - self.assertTrue(is_ip('192.0.2.0')) - self.assertFalse(is_ip('192..0.0')) - self.assertTrue(is_ip('2001:db8::')) - self.assertFalse(is_ip('2001:db8:')) + assert is_ip('192.0.2.0') + assert not is_ip('192..0.0') + assert is_ip('2001:db8::') + assert not is_ip('2001:db8:') def test_is_ipv4(self): - self.assertTrue(is_ipv4('192.0.2.0')) - self.assertFalse(is_ipv4('192..0.0')) + assert is_ipv4('192.0.2.0') + assert not is_ipv4('192..0.0') def test_is_ipv6(self): - self.assertTrue(is_ipv6('2001:db8::')) - self.assertFalse(is_ipv6('2001:db8:')) + assert is_ipv6('2001:db8::') + assert not is_ipv6('2001:db8:') def get_windows_interface_name(self): import winreg @@ -126,9 +116,7 @@ class CommonTestCase(unittest.TestCase): winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards', ) as key: - self.assertTrue( - winreg.QueryInfoKey(key)[0] > 0 - ) # must have at least 1 network card + assert winreg.QueryInfoKey(key)[0] > 0 # must have at least 1 network card network_card = winreg.EnumKey(key, 0) # get GUID of network card with winreg.OpenKey( @@ -144,48 +132,46 @@ class CommonTestCase(unittest.TestCase): def test_is_interface_name(self): if windows_check(): interface_name = self.get_windows_interface_name() - self.assertFalse(is_interface_name('2001:db8:')) - self.assertFalse( - is_interface_name('{THIS0000-IS00-ONLY-FOR0-TESTING00000}') - ) - self.assertTrue(is_interface_name(interface_name)) + assert not is_interface_name('2001:db8:') + assert not is_interface_name('{THIS0000-IS00-ONLY-FOR0-TESTING00000}') + assert is_interface_name(interface_name) else: - self.assertTrue(is_interface_name('lo')) - self.assertFalse(is_interface_name('127.0.0.1')) - self.assertFalse(is_interface_name('eth01101')) + assert is_interface_name('lo') + assert not is_interface_name('127.0.0.1') + assert not is_interface_name('eth01101') def test_is_interface(self): if windows_check(): interface_name = self.get_windows_interface_name() - self.assertTrue(is_interface('127.0.0.1')) - self.assertTrue(is_interface(interface_name)) - self.assertFalse(is_interface('127')) - self.assertFalse(is_interface('{THIS0000-IS00-ONLY-FOR0-TESTING00000}')) + assert is_interface('127.0.0.1') + assert is_interface(interface_name) + assert not is_interface('127') + assert not is_interface('{THIS0000-IS00-ONLY-FOR0-TESTING00000}') else: - self.assertTrue(is_interface('lo')) - self.assertTrue(is_interface('127.0.0.1')) - self.assertFalse(is_interface('127.')) - self.assertFalse(is_interface('eth01101')) + assert is_interface('lo') + assert is_interface('127.0.0.1') + assert not is_interface('127.') + assert not is_interface('eth01101') def test_version_split(self): - self.assertTrue(VersionSplit('1.2.2') == VersionSplit('1.2.2')) - self.assertTrue(VersionSplit('1.2.1') < VersionSplit('1.2.2')) - self.assertTrue(VersionSplit('1.1.9') < VersionSplit('1.2.2')) - self.assertTrue(VersionSplit('1.2.2') > VersionSplit('1.2.1')) - self.assertTrue(VersionSplit('1.2.2') > VersionSplit('1.2.2-dev0')) - self.assertTrue(VersionSplit('1.2.2-dev') < VersionSplit('1.3.0-rc2')) - self.assertTrue(VersionSplit('1.2.2') > VersionSplit('1.2.2-rc2')) - self.assertTrue(VersionSplit('1.2.2-rc2-dev') < VersionSplit('1.2.2-rc2')) - self.assertTrue(VersionSplit('1.2.2-rc3') > VersionSplit('1.2.2-rc2')) - self.assertTrue(VersionSplit('0.14.9') == VersionSplit('0.14.9')) - self.assertTrue(VersionSplit('0.14.9') > VersionSplit('0.14.5')) - self.assertTrue(VersionSplit('0.14.10') >= VersionSplit('0.14.9')) - self.assertTrue(VersionSplit('1.4.0') > VersionSplit('1.3.900.dev123')) - self.assertTrue(VersionSplit('1.3.2rc2.dev1') < VersionSplit('1.3.2-rc2')) - self.assertTrue(VersionSplit('1.3.900.dev888') > VersionSplit('1.3.900.dev123')) - self.assertTrue(VersionSplit('1.4.0') > VersionSplit('1.4.0.dev123')) - self.assertTrue(VersionSplit('1.4.0.dev1') < VersionSplit('1.4.0')) - self.assertTrue(VersionSplit('1.4.0a1') < VersionSplit('1.4.0')) + assert VersionSplit('1.2.2') == VersionSplit('1.2.2') + assert VersionSplit('1.2.1') < VersionSplit('1.2.2') + assert VersionSplit('1.1.9') < VersionSplit('1.2.2') + assert VersionSplit('1.2.2') > VersionSplit('1.2.1') + assert VersionSplit('1.2.2') > VersionSplit('1.2.2-dev0') + assert VersionSplit('1.2.2-dev') < VersionSplit('1.3.0-rc2') + assert VersionSplit('1.2.2') > VersionSplit('1.2.2-rc2') + assert VersionSplit('1.2.2-rc2-dev') < VersionSplit('1.2.2-rc2') + assert VersionSplit('1.2.2-rc3') > VersionSplit('1.2.2-rc2') + assert VersionSplit('0.14.9') == VersionSplit('0.14.9') + assert VersionSplit('0.14.9') > VersionSplit('0.14.5') + assert VersionSplit('0.14.10') >= VersionSplit('0.14.9') + assert VersionSplit('1.4.0') > VersionSplit('1.3.900.dev123') + assert VersionSplit('1.3.2rc2.dev1') < VersionSplit('1.3.2-rc2') + assert VersionSplit('1.3.900.dev888') > VersionSplit('1.3.900.dev123') + assert VersionSplit('1.4.0') > VersionSplit('1.4.0.dev123') + assert VersionSplit('1.4.0.dev1') < VersionSplit('1.4.0') + assert VersionSplit('1.4.0a1') < VersionSplit('1.4.0') def test_parse_human_size(self): from deluge.common import parse_human_size @@ -206,9 +192,7 @@ class CommonTestCase(unittest.TestCase): for human_size, byte_size in sizes: parsed = parse_human_size(human_size) - self.assertEqual( - parsed, byte_size, 'Mismatch when converting: %s' % human_size - ) + assert parsed == byte_size, 'Mismatch when converting: %s' % human_size def test_archive_files(self): arc_filelist = [ @@ -219,10 +203,10 @@ class CommonTestCase(unittest.TestCase): with tarfile.open(arc_filepath, 'r') as tar: for tar_info in tar: - self.assertTrue(tar_info.isfile()) - self.assertTrue( - tar_info.name in [os.path.basename(arcf) for arcf in arc_filelist] - ) + assert tar_info.isfile() + assert tar_info.name in [ + os.path.basename(arcf) for arcf in arc_filelist + ] def test_archive_files_missing(self): """Archive exists even with file not found.""" @@ -233,8 +217,8 @@ class CommonTestCase(unittest.TestCase): filelist.remove('missing.file') with tarfile.open(arc_filepath, 'r') as tar: - self.assertEqual(tar.getnames(), filelist) - self.assertTrue(all(tarinfo.isfile() for tarinfo in tar)) + assert tar.getnames() == filelist + assert all(tarinfo.isfile() for tarinfo in tar) def test_archive_files_message(self): filelist = ['test.torrent', 'deluge.png'] @@ -244,9 +228,9 @@ class CommonTestCase(unittest.TestCase): result_files = filelist + ['archive_message.txt'] with tarfile.open(arc_filepath, 'r') as tar: - self.assertEqual(tar.getnames(), result_files) + assert tar.getnames() == result_files for tar_info in tar: - self.assertTrue(tar_info.isfile()) + assert tar_info.isfile() if tar_info.name == 'archive_message.txt': result = tar.extractfile(tar_info).read().decode() - self.assertEqual(result, 'test') + assert result == 'test' diff --git a/deluge/tests/test_component.py b/deluge/tests/test_component.py index 37cee03eb..0345e24d3 100644 --- a/deluge/tests/test_component.py +++ b/deluge/tests/test_component.py @@ -4,13 +4,12 @@ # See LICENSE for more details. # +import pytest +import pytest_twisted from twisted.internet import defer, threads -from twisted.trial.unittest import SkipTest import deluge.component as component -from .basetest import BaseTestCase - class ComponentTester(component.Component): def __init__(self, name, depend=None): @@ -67,14 +66,15 @@ class ComponentTesterShutdown(component.Component): self.stop_count += 1 -class ComponentTestClass(BaseTestCase): +@pytest.mark.usefixtures('component') +class TestComponent: def tear_down(self): return component.shutdown() def test_start_component(self): def on_start(result, c): - self.assertEqual(c._component_state, 'Started') - self.assertEqual(c.start_count, 1) + assert c._component_state == 'Started' + assert c.start_count == 1 c = ComponentTester('test_start_c1') d = component.start(['test_start_c1']) @@ -83,16 +83,16 @@ class ComponentTestClass(BaseTestCase): def test_start_stop_depends(self): def on_stop(result, c1, c2): - self.assertEqual(c1._component_state, 'Stopped') - self.assertEqual(c2._component_state, 'Stopped') - self.assertEqual(c1.stop_count, 1) - self.assertEqual(c2.stop_count, 1) + assert c1._component_state == 'Stopped' + assert c2._component_state == 'Stopped' + assert c1.stop_count == 1 + assert c2.stop_count == 1 def on_start(result, c1, c2): - self.assertEqual(c1._component_state, 'Started') - self.assertEqual(c2._component_state, 'Started') - self.assertEqual(c1.start_count, 1) - self.assertEqual(c2.start_count, 1) + assert c1._component_state == 'Started' + assert c2._component_state == 'Started' + assert c1.start_count == 1 + assert c2.start_count == 1 return component.stop(['test_start_depends_c1']).addCallback( on_stop, c1, c2 ) @@ -123,8 +123,8 @@ class ComponentTestClass(BaseTestCase): def test_start_all(self): def on_start(*args): for c in args[1:]: - self.assertEqual(c._component_state, 'Started') - self.assertEqual(c.start_count, 1) + assert c._component_state == 'Started' + assert c.start_count == 1 ret = self.start_with_depends() ret[0].addCallback(on_start, *ret[1:]) @@ -133,20 +133,19 @@ class ComponentTestClass(BaseTestCase): def test_register_exception(self): ComponentTester('test_register_exception_c1') - self.assertRaises( - component.ComponentAlreadyRegistered, - ComponentTester, - 'test_register_exception_c1', - ) + with pytest.raises(component.ComponentAlreadyRegistered): + ComponentTester( + 'test_register_exception_c1', + ) def test_stop_component(self): def on_stop(result, c): - self.assertEqual(c._component_state, 'Stopped') - self.assertFalse(c._component_timer.running) - self.assertEqual(c.stop_count, 1) + assert c._component_state == 'Stopped' + assert not c._component_timer.running + assert c.stop_count == 1 def on_start(result, c): - self.assertEqual(c._component_state, 'Started') + assert c._component_state == 'Started' return component.stop(['test_stop_component_c1']).addCallback(on_stop, c) c = ComponentTesterUpdate('test_stop_component_c1') @@ -157,12 +156,12 @@ class ComponentTestClass(BaseTestCase): def test_stop_all(self): def on_stop(result, *args): for c in args: - self.assertEqual(c._component_state, 'Stopped') - self.assertEqual(c.stop_count, 1) + assert c._component_state == 'Stopped' + assert c.stop_count == 1 def on_start(result, *args): for c in args: - self.assertEqual(c._component_state, 'Started') + assert c._component_state == 'Started' return component.stop().addCallback(on_stop, *args) ret = self.start_with_depends() @@ -172,9 +171,9 @@ class ComponentTestClass(BaseTestCase): def test_update(self): def on_start(result, c1, counter): - self.assertTrue(c1._component_timer) - self.assertTrue(c1._component_timer.running) - self.assertNotEqual(c1.counter, counter) + assert c1._component_timer + assert c1._component_timer.running + assert c1.counter != counter return component.stop() c1 = ComponentTesterUpdate('test_update_c1') @@ -186,13 +185,13 @@ class ComponentTestClass(BaseTestCase): def test_pause(self): def on_pause(result, c1, counter): - self.assertEqual(c1._component_state, 'Paused') - self.assertNotEqual(c1.counter, counter) - self.assertFalse(c1._component_timer.running) + assert c1._component_state == 'Paused' + assert c1.counter != counter + assert not c1._component_timer.running def on_start(result, c1, counter): - self.assertTrue(c1._component_timer) - self.assertNotEqual(c1.counter, counter) + assert c1._component_timer + assert c1.counter != counter d = component.pause(['test_pause_c1']) d.addCallback(on_pause, c1, counter) return d @@ -204,23 +203,16 @@ class ComponentTestClass(BaseTestCase): d.addCallback(on_start, c1, cnt) return d - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_component_start_error(self): ComponentTesterUpdate('test_pause_c1') yield component.start(['test_pause_c1']) yield component.pause(['test_pause_c1']) test_comp = component.get('test_pause_c1') - try: - result = self.failureResultOf(test_comp._component_start()) - except AttributeError: - raise SkipTest( - 'This test requires trial failureResultOf() in Twisted version >= 13' - ) - self.assertEqual( - result.check(component.ComponentException), component.ComponentException - ) + with pytest.raises(component.ComponentException, match='Current state: Paused'): + yield test_comp._component_start() - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_start_paused_error(self): ComponentTesterUpdate('test_pause_c1') yield component.start(['test_pause_c1']) @@ -229,29 +221,26 @@ class ComponentTestClass(BaseTestCase): # Deferreds that fail in component have to error handler which results in # twisted doing a log.err call which causes the test to fail. # Prevent failure by ignoring the exception - self._observer._ignoreErrors(component.ComponentException) + # self._observer._ignoreErrors(component.ComponentException) result = yield component.start() - self.assertEqual( - [(result[0][0], result[0][1].value)], - [ - ( - defer.FAILURE, - component.ComponentException( - 'Trying to start component "%s" but it is ' - 'not in a stopped state. Current state: %s' - % ('test_pause_c1', 'Paused'), - '', - ), - ) - ], - ) + assert [(result[0][0], result[0][1].value)] == [ + ( + defer.FAILURE, + component.ComponentException( + 'Trying to start component "%s" but it is ' + 'not in a stopped state. Current state: %s' + % ('test_pause_c1', 'Paused'), + '', + ), + ) + ] def test_shutdown(self): def on_shutdown(result, c1): - self.assertTrue(c1.shutdowned) - self.assertEqual(c1._component_state, 'Stopped') - self.assertEqual(c1.stop_count, 1) + assert c1.shutdowned + assert c1._component_state == 'Stopped' + assert c1.stop_count == 1 def on_start(result, c1): d = component.shutdown() diff --git a/deluge/tests/test_config.py b/deluge/tests/test_config.py index e8a267185..3ee6b9f33 100644 --- a/deluge/tests/test_config.py +++ b/deluge/tests/test_config.py @@ -7,15 +7,13 @@ import os from codecs import getwriter +import pytest from twisted.internet import task -from twisted.trial import unittest import deluge.config from deluge.common import JSON_FORMAT from deluge.config import Config -from .common import set_tmp_config_dir - DEFAULTS = { 'string': 'foobar', 'int': 1, @@ -26,34 +24,32 @@ DEFAULTS = { } -class ConfigTestCase(unittest.TestCase): - def setUp(self): # NOQA: N803 - self.config_dir = set_tmp_config_dir() - +class TestConfig: def test_init(self): config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir) - self.assertEqual(DEFAULTS, config.config) + assert DEFAULTS == config.config config = Config('test.conf', config_dir=self.config_dir) - self.assertEqual({}, config.config) + assert {} == config.config def test_set_get_item(self): config = Config('test.conf', config_dir=self.config_dir) config['foo'] = 1 - self.assertEqual(config['foo'], 1) - self.assertRaises(ValueError, config.set_item, 'foo', 'bar') + assert config['foo'] == 1 + with pytest.raises(ValueError): + config.set_item('foo', 'bar') config['foo'] = 2 - self.assertEqual(config.get_item('foo'), 2) + assert config.get_item('foo') == 2 config['foo'] = '3' - self.assertEqual(config.get_item('foo'), 3) + assert config.get_item('foo') == 3 config['unicode'] = 'ВИДЕОФИЛЬМЫ' - self.assertEqual(config['unicode'], 'ВИДЕОФИЛЬМЫ') + assert config['unicode'] == 'ВИДЕОФИЛЬМЫ' config['unicode'] = b'foostring' - self.assertFalse(isinstance(config.get_item('unicode'), bytes)) + assert not isinstance(config.get_item('unicode'), bytes) config._save_timer.cancel() @@ -61,39 +57,39 @@ class ConfigTestCase(unittest.TestCase): config = Config('test.conf', config_dir=self.config_dir) config['foo'] = None - self.assertIsNone(config['foo']) - self.assertIsInstance(config['foo'], type(None)) + assert config['foo'] is None + assert isinstance(config['foo'], type(None)) config['foo'] = 1 - self.assertEqual(config.get('foo'), 1) + assert config.get('foo') == 1 config['foo'] = None - self.assertIsNone(config['foo']) + assert config['foo'] is None config['bar'] = None - self.assertIsNone(config['bar']) + assert config['bar'] is None config['bar'] = None - self.assertIsNone(config['bar']) + assert config['bar'] is None config._save_timer.cancel() def test_get(self): config = Config('test.conf', config_dir=self.config_dir) config['foo'] = 1 - self.assertEqual(config.get('foo'), 1) - self.assertEqual(config.get('foobar'), None) - self.assertEqual(config.get('foobar', 2), 2) + assert config.get('foo') == 1 + assert config.get('foobar') is None + assert config.get('foobar', 2) == 2 config['foobar'] = 5 - self.assertEqual(config.get('foobar', 2), 5) + assert config.get('foobar', 2) == 5 def test_load(self): def check_config(): config = Config('test.conf', config_dir=self.config_dir) - self.assertEqual(config['string'], 'foobar') - self.assertEqual(config['float'], 0.435) - self.assertEqual(config['password'], 'abc123*\\[!]?/<>#{@}=|"+$%(^)~') + assert config['string'] == 'foobar' + assert config['float'] == 0.435 + assert config['password'] == 'abc123*\\[!]?/<>#{@}=|"+$%(^)~' # Test opening a previous 1.2 config file of just a json object import json @@ -125,19 +121,19 @@ class ConfigTestCase(unittest.TestCase): # We do this twice because the first time we need to save the file to disk # and the second time we do a compare and we should not write ret = config.save() - self.assertTrue(ret) + assert ret ret = config.save() - self.assertTrue(ret) + assert ret config['string'] = 'baz' config['int'] = 2 ret = config.save() - self.assertTrue(ret) + assert ret del config config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir) - self.assertEqual(config['string'], 'baz') - self.assertEqual(config['int'], 2) + assert config['string'] == 'baz' + assert config['int'] == 2 def test_save_timer(self): self.clock = task.Clock() @@ -146,17 +142,17 @@ class ConfigTestCase(unittest.TestCase): config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir) config['string'] = 'baz' config['int'] = 2 - self.assertTrue(config._save_timer.active()) + assert config._save_timer.active() # Timeout set for 5 seconds in config, so lets move clock by 5 seconds self.clock.advance(5) def check_config(config): - self.assertTrue(not config._save_timer.active()) + assert not config._save_timer.active() del config config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir) - self.assertEqual(config['string'], 'baz') - self.assertEqual(config['int'], 2) + assert config['string'] == 'baz' + assert config['int'] == 2 check_config(config) @@ -173,7 +169,7 @@ class ConfigTestCase(unittest.TestCase): from deluge.config import find_json_objects objects = find_json_objects(s) - self.assertEqual(len(objects), 2) + assert len(objects) == 2 def test_find_json_objects_curly_brace(self): """Test with string containing curly brace""" @@ -190,7 +186,7 @@ class ConfigTestCase(unittest.TestCase): from deluge.config import find_json_objects objects = find_json_objects(s) - self.assertEqual(len(objects), 2) + assert len(objects) == 2 def test_find_json_objects_double_quote(self): """Test with string containing double quote""" @@ -208,4 +204,4 @@ class ConfigTestCase(unittest.TestCase): from deluge.config import find_json_objects objects = find_json_objects(s) - self.assertEqual(len(objects), 2) + assert len(objects) == 2 diff --git a/deluge/tests/test_core.py b/deluge/tests/test_core.py index f24fb2e0d..b0392c720 100644 --- a/deluge/tests/test_core.py +++ b/deluge/tests/test_core.py @@ -8,9 +8,9 @@ from base64 import b64encode from hashlib import sha1 as sha import pytest +import pytest_twisted from twisted.internet import defer, reactor, task from twisted.internet.error import CannotListenError -from twisted.python.failure import Failure from twisted.web.http import FORBIDDEN from twisted.web.resource import EncodingResourceWrapper, Resource from twisted.web.server import GzipEncoderFactory, Site @@ -20,12 +20,12 @@ import deluge.common import deluge.component as component import deluge.core.torrent from deluge._libtorrent import lt +from deluge.conftest import BaseTestCase from deluge.core.core import Core from deluge.core.rpcserver import RPCServer from deluge.error import AddTorrentError, InvalidTorrentError from . import common -from .basetest import BaseTestCase common.disable_new_release_check() @@ -76,9 +76,8 @@ class TopLevelResource(Resource): ) -class CoreTestCase(BaseTestCase): +class TestCore(BaseTestCase): def set_up(self): - common.set_tmp_config_dir() self.rpcserver = RPCServer(listen=False) self.core = Core() self.core.config.config['lsd'] = False @@ -127,7 +126,7 @@ class CoreTestCase(BaseTestCase): torrent_id = self.core.add_torrent_file(filename, filedump, options) return torrent_id - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_add_torrent_files(self): options = {} filenames = ['test.torrent', 'test_torrent.file.torrent'] @@ -138,9 +137,9 @@ class CoreTestCase(BaseTestCase): filedump = b64encode(_file.read()) files_to_add.append((filename, filedump, options)) errors = yield self.core.add_torrent_files(files_to_add) - self.assertEqual(len(errors), 0) + assert len(errors) == 0 - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_add_torrent_files_error_duplicate(self): options = {} filenames = ['test.torrent', 'test.torrent'] @@ -151,10 +150,10 @@ class CoreTestCase(BaseTestCase): filedump = b64encode(_file.read()) files_to_add.append((filename, filedump, options)) errors = yield self.core.add_torrent_files(files_to_add) - self.assertEqual(len(errors), 1) - self.assertTrue(str(errors[0]).startswith('Torrent already in session')) + assert len(errors) == 1 + assert str(errors[0]).startswith('Torrent already in session') - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_add_torrent_file(self): options = {} filename = common.get_test_data_file('test.torrent') @@ -167,16 +166,15 @@ class CoreTestCase(BaseTestCase): with open(filename, 'rb') as _file: info_hash = sha(bencode(bdecode(_file.read())[b'info'])).hexdigest() - self.assertEqual(torrent_id, info_hash) + assert torrent_id == info_hash def test_add_torrent_file_invalid_filedump(self): options = {} filename = common.get_test_data_file('test.torrent') - self.assertRaises( - AddTorrentError, self.core.add_torrent_file, filename, False, options - ) + with pytest.raises(AddTorrentError): + self.core.add_torrent_file(filename, False, options) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_add_torrent_url(self): url = ( 'http://localhost:%d/ubuntu-9.04-desktop-i386.iso.torrent' @@ -186,78 +184,77 @@ class CoreTestCase(BaseTestCase): info_hash = '60d5d82328b4547511fdeac9bf4d0112daa0ce00' torrent_id = yield self.core.add_torrent_url(url, options) - self.assertEqual(torrent_id, info_hash) + assert torrent_id == info_hash - def test_add_torrent_url_with_cookie(self): + @pytest_twisted.ensureDeferred + async def test_add_torrent_url_with_cookie(self): url = 'http://localhost:%d/cookie' % self.listen_port options = {} headers = {'Cookie': 'password=deluge'} info_hash = '60d5d82328b4547511fdeac9bf4d0112daa0ce00' - d = self.core.add_torrent_url(url, options) - d.addCallbacks(self.fail, self.assertIsInstance, errbackArgs=(Failure,)) + with pytest.raises(Exception): + await self.core.add_torrent_url(url, options) - d = self.core.add_torrent_url(url, options, headers) - d.addCallbacks(self.assertEqual, self.fail, callbackArgs=(info_hash,)) + result = await self.core.add_torrent_url(url, options, headers) + assert result == info_hash - return d - - def test_add_torrent_url_with_redirect(self): + @pytest_twisted.ensureDeferred + async def test_add_torrent_url_with_redirect(self): url = 'http://localhost:%d/redirect' % self.listen_port options = {} info_hash = '60d5d82328b4547511fdeac9bf4d0112daa0ce00' - d = self.core.add_torrent_url(url, options) - d.addCallback(self.assertEqual, info_hash) - return d + result = await self.core.add_torrent_url(url, options) + assert result == info_hash - def test_add_torrent_url_with_partial_download(self): + @pytest_twisted.ensureDeferred + async def test_add_torrent_url_with_partial_download(self): url = 'http://localhost:%d/partial' % self.listen_port options = {} info_hash = '60d5d82328b4547511fdeac9bf4d0112daa0ce00' - d = self.core.add_torrent_url(url, options) - d.addCallback(self.assertEqual, info_hash) - return d + result = await self.core.add_torrent_url(url, options) + assert result == info_hash - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_add_torrent_magnet(self): info_hash = '60d5d82328b4547511fdeac9bf4d0112daa0ce00' uri = deluge.common.create_magnet_uri(info_hash) options = {} torrent_id = yield self.core.add_torrent_magnet(uri, options) - self.assertEqual(torrent_id, info_hash) + assert torrent_id == info_hash def test_resume_torrent(self): tid1 = self.add_torrent('test.torrent', paused=True) tid2 = self.add_torrent('test_torrent.file.torrent', paused=True) # Assert paused r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertTrue(r1['paused']) + assert r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertTrue(r2['paused']) + assert r2['paused'] self.core.resume_torrent(tid2) r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertTrue(r1['paused']) + assert r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertFalse(r2['paused']) + assert not r2['paused'] def test_resume_torrent_list(self): """Backward compatibility for list of torrent_ids.""" torrent_id = self.add_torrent('test.torrent', paused=True) self.core.resume_torrent([torrent_id]) result = self.core.get_torrent_status(torrent_id, ['paused']) - self.assertFalse(result['paused']) + assert not result['paused'] def test_resume_torrents(self): tid1 = self.add_torrent('test.torrent', paused=True) tid2 = self.add_torrent('test_torrent.file.torrent', paused=True) self.core.resume_torrents([tid1, tid2]) r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertFalse(r1['paused']) + assert not r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertFalse(r2['paused']) + assert not r2['paused'] def test_resume_torrents_all(self): """With no torrent_ids param, resume all torrents""" @@ -265,33 +262,33 @@ class CoreTestCase(BaseTestCase): tid2 = self.add_torrent('test_torrent.file.torrent', paused=True) self.core.resume_torrents() r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertFalse(r1['paused']) + assert not r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertFalse(r2['paused']) + assert not r2['paused'] def test_pause_torrent(self): tid1 = self.add_torrent('test.torrent') tid2 = self.add_torrent('test_torrent.file.torrent') # Assert not paused r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertFalse(r1['paused']) + assert not r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertFalse(r2['paused']) + assert not r2['paused'] self.core.pause_torrent(tid2) r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertFalse(r1['paused']) + assert not r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertTrue(r2['paused']) + assert r2['paused'] def test_pause_torrent_list(self): """Backward compatibility for list of torrent_ids.""" torrent_id = self.add_torrent('test.torrent') result = self.core.get_torrent_status(torrent_id, ['paused']) - self.assertFalse(result['paused']) + assert not result['paused'] self.core.pause_torrent([torrent_id]) result = self.core.get_torrent_status(torrent_id, ['paused']) - self.assertTrue(result['paused']) + assert result['paused'] def test_pause_torrents(self): tid1 = self.add_torrent('test.torrent') @@ -299,9 +296,9 @@ class CoreTestCase(BaseTestCase): self.core.pause_torrents([tid1, tid2]) r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertTrue(r1['paused']) + assert r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertTrue(r2['paused']) + assert r2['paused'] def test_pause_torrents_all(self): """With no torrent_ids param, pause all torrents""" @@ -310,9 +307,9 @@ class CoreTestCase(BaseTestCase): self.core.pause_torrents() r1 = self.core.get_torrent_status(tid1, ['paused']) - self.assertTrue(r1['paused']) + assert r1['paused'] r2 = self.core.get_torrent_status(tid2, ['paused']) - self.assertTrue(r2['paused']) + assert r2['paused'] def test_prefetch_metadata_existing(self): """Check another call with same magnet returns existing deferred.""" @@ -320,7 +317,7 @@ class CoreTestCase(BaseTestCase): expected = ('ab570cdd5a17ea1b61e970bb72047de141bce173', b'') def on_result(result): - self.assertEqual(result, expected) + assert result == expected d = self.core.prefetch_magnet_metadata(magnet) d.addCallback(on_result) @@ -329,7 +326,7 @@ class CoreTestCase(BaseTestCase): self.clock.advance(30) return defer.DeferredList([d, d2]) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_remove_torrent(self): options = {} filename = common.get_test_data_file('test.torrent') @@ -337,18 +334,17 @@ class CoreTestCase(BaseTestCase): filedump = b64encode(_file.read()) torrent_id = yield self.core.add_torrent_file_async(filename, filedump, options) removed = self.core.remove_torrent(torrent_id, True) - self.assertTrue(removed) - self.assertEqual(len(self.core.get_session_state()), 0) + assert removed + assert len(self.core.get_session_state()) == 0 def test_remove_torrent_invalid(self): - self.assertRaises( - InvalidTorrentError, - self.core.remove_torrent, - 'torrentidthatdoesntexist', - True, - ) + with pytest.raises(InvalidTorrentError): + self.core.remove_torrent( + 'torrentidthatdoesntexist', + True, + ) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_remove_torrents(self): options = {} filename = common.get_test_data_file('test.torrent') @@ -365,17 +361,17 @@ class CoreTestCase(BaseTestCase): d = self.core.remove_torrents([torrent_id, torrent_id2], True) def test_ret(val): - self.assertTrue(val == []) + assert val == [] d.addCallback(test_ret) def test_session_state(val): - self.assertEqual(len(self.core.get_session_state()), 0) + assert len(self.core.get_session_state()) == 0 d.addCallback(test_session_state) yield d - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_remove_torrents_invalid(self): options = {} filename = common.get_test_data_file('test.torrent') @@ -387,57 +383,53 @@ class CoreTestCase(BaseTestCase): val = yield self.core.remove_torrents( ['invalidid1', 'invalidid2', torrent_id], False ) - self.assertEqual(len(val), 2) - self.assertEqual( - val[0], ('invalidid1', 'torrent_id invalidid1 not in session.') - ) - self.assertEqual( - val[1], ('invalidid2', 'torrent_id invalidid2 not in session.') - ) + assert len(val) == 2 + assert val[0] == ('invalidid1', 'torrent_id invalidid1 not in session.') + assert val[1] == ('invalidid2', 'torrent_id invalidid2 not in session.') def test_get_session_status(self): status = self.core.get_session_status( ['net.recv_tracker_bytes', 'net.sent_tracker_bytes'] ) - self.assertIsInstance(status, dict) - self.assertEqual(status['net.recv_tracker_bytes'], 0) - self.assertEqual(status['net.sent_tracker_bytes'], 0) + assert isinstance(status, dict) + assert status['net.recv_tracker_bytes'] == 0 + assert status['net.sent_tracker_bytes'] == 0 def test_get_session_status_all(self): status = self.core.get_session_status([]) - self.assertIsInstance(status, dict) - self.assertIn('upload_rate', status) - self.assertIn('net.recv_bytes', status) + assert isinstance(status, dict) + assert 'upload_rate' in status + assert 'net.recv_bytes' in status def test_get_session_status_depr(self): status = self.core.get_session_status(['num_peers', 'num_unchoked']) - self.assertIsInstance(status, dict) - self.assertEqual(status['num_peers'], 0) - self.assertEqual(status['num_unchoked'], 0) + assert isinstance(status, dict) + assert status['num_peers'] == 0 + assert status['num_unchoked'] == 0 def test_get_session_status_rates(self): status = self.core.get_session_status(['upload_rate', 'download_rate']) - self.assertIsInstance(status, dict) - self.assertEqual(status['upload_rate'], 0) + assert isinstance(status, dict) + assert status['upload_rate'] == 0 def test_get_session_status_ratio(self): status = self.core.get_session_status(['write_hit_ratio', 'read_hit_ratio']) - self.assertIsInstance(status, dict) - self.assertEqual(status['write_hit_ratio'], 0.0) - self.assertEqual(status['read_hit_ratio'], 0.0) + assert isinstance(status, dict) + assert status['write_hit_ratio'] == 0.0 + assert status['read_hit_ratio'] == 0.0 def test_get_free_space(self): space = self.core.get_free_space('.') - self.assertTrue(isinstance(space, int)) - self.assertTrue(space >= 0) - self.assertEqual(self.core.get_free_space('/someinvalidpath'), -1) + assert isinstance(space, int) + assert space >= 0 + assert self.core.get_free_space('/someinvalidpath') == -1 @pytest.mark.slow def test_test_listen_port(self): d = self.core.test_listen_port() def result(r): - self.assertTrue(r in (True, False)) + assert r in (True, False) d.addCallback(result) return d @@ -455,24 +447,22 @@ class CoreTestCase(BaseTestCase): } for key in pathlist: - self.assertEqual( - deluge.core.torrent.sanitize_filepath(key, folder=False), pathlist[key] + assert ( + deluge.core.torrent.sanitize_filepath(key, folder=False) + == pathlist[key] ) - self.assertEqual( - deluge.core.torrent.sanitize_filepath(key, folder=True), - pathlist[key] + '/', + + assert ( + deluge.core.torrent.sanitize_filepath(key, folder=True) + == pathlist[key] + '/' ) def test_get_set_config_values(self): - self.assertEqual( - self.core.get_config_values(['abc', 'foo']), {'foo': None, 'abc': None} - ) - self.assertEqual(self.core.get_config_value('foobar'), None) + assert self.core.get_config_values(['abc', 'foo']) == {'foo': None, 'abc': None} + assert self.core.get_config_value('foobar') is None self.core.set_config({'abc': 'def', 'foo': 10, 'foobar': 'barfoo'}) - self.assertEqual( - self.core.get_config_values(['foo', 'abc']), {'foo': 10, 'abc': 'def'} - ) - self.assertEqual(self.core.get_config_value('foobar'), 'barfoo') + assert self.core.get_config_values(['foo', 'abc']) == {'foo': 10, 'abc': 'def'} + assert self.core.get_config_value('foobar') == 'barfoo' def test_read_only_config_keys(self): key = 'max_upload_speed' @@ -481,13 +471,13 @@ class CoreTestCase(BaseTestCase): old_value = self.core.get_config_value(key) self.core.set_config({key: old_value + 10}) new_value = self.core.get_config_value(key) - self.assertEqual(old_value, new_value) + assert old_value == new_value self.core.read_only_config_keys = None def test__create_peer_id(self): - self.assertEqual(self.core._create_peer_id('2.0.0'), '-DE200s-') - self.assertEqual(self.core._create_peer_id('2.0.0.dev15'), '-DE200D-') - self.assertEqual(self.core._create_peer_id('2.0.1rc1'), '-DE201r-') - self.assertEqual(self.core._create_peer_id('2.11.0b2'), '-DE2B0b-') - self.assertEqual(self.core._create_peer_id('2.4.12b2.dev3'), '-DE24CD-') + assert self.core._create_peer_id('2.0.0') == '-DE200s-' + assert self.core._create_peer_id('2.0.0.dev15') == '-DE200D-' + assert self.core._create_peer_id('2.0.1rc1') == '-DE201r-' + assert self.core._create_peer_id('2.11.0b2') == '-DE2B0b-' + assert self.core._create_peer_id('2.4.12b2.dev3') == '-DE24CD-' diff --git a/deluge/tests/test_decorators.py b/deluge/tests/test_decorators.py index fc279f05f..d2ecd1a2b 100644 --- a/deluge/tests/test_decorators.py +++ b/deluge/tests/test_decorators.py @@ -4,12 +4,11 @@ # See LICENSE for more details. # -from twisted.trial import unittest from deluge.decorators import proxy -class DecoratorsTestCase(unittest.TestCase): +class TestDecorators: def test_proxy_with_simple_functions(self): def negate(func, *args, **kwargs): return not func(*args, **kwargs) @@ -23,10 +22,10 @@ class DecoratorsTestCase(unittest.TestCase): def double_nothing(_bool): return _bool - self.assertTrue(something(False)) - self.assertFalse(something(True)) - self.assertTrue(double_nothing(True)) - self.assertFalse(double_nothing(False)) + assert something(False) + assert not something(True) + assert double_nothing(True) + assert not double_nothing(False) def test_proxy_with_class_method(self): def negate(func, *args, **kwargs): @@ -45,5 +44,5 @@ class DecoratorsTestCase(unittest.TestCase): return self.diff(number) t = Test(5) - self.assertEqual(t.diff(1), -4) - self.assertEqual(t.no_diff(1), 4) + assert t.diff(1) == -4 + assert t.no_diff(1) == 4 diff --git a/deluge/tests/test_error.py b/deluge/tests/test_error.py index 1c2ff5f4b..a87d6a2d8 100644 --- a/deluge/tests/test_error.py +++ b/deluge/tests/test_error.py @@ -4,48 +4,36 @@ # See LICENSE for more details. # -from twisted.trial import unittest - import deluge.error -class ErrorTestCase(unittest.TestCase): - def setUp(self): # NOQA: N803 - pass - - def tearDown(self): # NOQA: N803 - pass - +class TestError: def test_deluge_error(self): msg = 'Some message' e = deluge.error.DelugeError(msg) - self.assertEqual(str(e), msg) + assert str(e) == msg from twisted.internet.defer import DebugInfo del DebugInfo.__del__ # Hides all errors - self.assertEqual(e._args, (msg,)) - self.assertEqual(e._kwargs, {}) + assert e._args == (msg,) + assert e._kwargs == {} def test_incompatible_client(self): version = '1.3.6' e = deluge.error.IncompatibleClient(version) - self.assertEqual( - str(e), - 'Your deluge client is not compatible with the daemon. \ -Please upgrade your client to %s' - % version, + assert ( + str(e) == 'Your deluge client is not compatible with the daemon. ' + 'Please upgrade your client to %s' % version ) def test_not_authorized_error(self): current_level = 5 required_level = 10 e = deluge.error.NotAuthorizedError(current_level, required_level) - self.assertEqual( - str(e), 'Auth level too low: %d < %d' % (current_level, required_level) - ) + assert str(e) == 'Auth level too low: %d < %d' % (current_level, required_level) def test_bad_login_error(self): message = 'Login failed' username = 'deluge' e = deluge.error.BadLoginError(message, username) - self.assertEqual(str(e), message) + assert str(e) == message diff --git a/deluge/tests/test_files_tab.py b/deluge/tests/test_files_tab.py index 416c7bc0b..5578c00d5 100644 --- a/deluge/tests/test_files_tab.py +++ b/deluge/tests/test_files_tab.py @@ -5,15 +5,12 @@ # import pytest -from twisted.trial import unittest import deluge.component as component from deluge.configmanager import ConfigManager +from deluge.conftest import BaseTestCase from deluge.i18n import setup_translation -from . import common -from .basetest import BaseTestCase - libs_available = True # Allow running other tests without GTKUI dependencies available try: @@ -28,12 +25,11 @@ setup_translation() @pytest.mark.gtkui -class FilesTabTestCase(BaseTestCase): +class TestFilesTab(BaseTestCase): def set_up(self): if libs_available is False: - raise unittest.SkipTest('GTKUI dependencies not available') + pytest.skip('GTKUI dependencies not available') - common.set_tmp_config_dir() ConfigManager('gtk3ui.conf', defaults=DEFAULT_PREFS) self.mainwindow = MainWindow() self.filestab = FilesTab() @@ -94,7 +90,7 @@ class FilesTabTestCase(BaseTestCase): ) if not ret: self.print_treestore('Treestore not expected:', self.filestab.treestore) - self.assertTrue(ret) + assert ret def test_files_tab2(self): self.filestab.files_list[self.t_id] = ( @@ -112,7 +108,7 @@ class FilesTabTestCase(BaseTestCase): ) if not ret: self.print_treestore('Treestore not expected:', self.filestab.treestore) - self.assertTrue(ret) + assert ret def test_files_tab3(self): self.filestab.files_list[self.t_id] = ( @@ -129,7 +125,7 @@ class FilesTabTestCase(BaseTestCase): ) if not ret: self.print_treestore('Treestore not expected:', self.filestab.treestore) - self.assertTrue(ret) + assert ret def test_files_tab4(self): self.filestab.files_list[self.t_id] = ( @@ -147,7 +143,7 @@ class FilesTabTestCase(BaseTestCase): ) if not ret: self.print_treestore('Treestore not expected:', self.filestab.treestore) - self.assertTrue(ret) + assert ret def test_files_tab5(self): self.filestab.files_list[self.t_id] = ( @@ -164,4 +160,4 @@ class FilesTabTestCase(BaseTestCase): ) if not ret: self.print_treestore('Treestore not expected:', self.filestab.treestore) - self.assertTrue(ret) + assert ret diff --git a/deluge/tests/test_httpdownloader.py b/deluge/tests/test_httpdownloader.py index 69291fc7b..8c491b68a 100644 --- a/deluge/tests/test_httpdownloader.py +++ b/deluge/tests/test_httpdownloader.py @@ -8,11 +8,11 @@ import os import tempfile from email.utils import formatdate +import pytest +import pytest_twisted from twisted.internet import reactor from twisted.internet.error import CannotListenError -from twisted.python.failure import Failure -from twisted.trial import unittest -from twisted.web.error import PageRedirect +from twisted.web.error import Error, PageRedirect from twisted.web.http import NOT_MODIFIED from twisted.web.resource import EncodingResourceWrapper, Resource from twisted.web.server import GzipEncoderFactory, Site @@ -134,11 +134,13 @@ class TopLevelResource(Resource): return b'

Deluge HTTP Downloader tests webserver here

' -class DownloadFileTestCase(unittest.TestCase): +class TestDownloadFile: def get_url(self, path=''): return 'http://localhost:%d/%s' % (self.listen_port, path) - def setUp(self): # NOQA + @pytest_twisted.async_yield_fixture(autouse=True) + async def setUp(self, request): # NOQA + self = request.instance setup_logger('warning', fname('log_file')) self.website = Site(TopLevelResource()) self.listen_port = 51242 @@ -154,140 +156,136 @@ class DownloadFileTestCase(unittest.TestCase): else: raise error - def tearDown(self): # NOQA - return self.webserver.stopListening() + yield - def assertContains(self, filename, contents): # NOQA + await self.webserver.stopListening() + + def assert_contains(self, filename, contents): with open(filename, encoding='utf8') as _file: try: - self.assertEqual(_file.read(), contents) + assert _file.read() == contents except Exception as ex: - self.fail(ex) + pytest.fail(ex) return filename - def assertNotContains(self, filename, contents, file_mode=''): # NOQA + def assert_not_contains(self, filename, contents, file_mode=''): with open(filename, encoding='utf8') as _file: try: - self.assertNotEqual(_file.read(), contents) + assert _file.read() != contents except Exception as ex: - self.fail(ex) + pytest.fail(ex) return filename - def test_download(self): - d = download_file(self.get_url(), fname('index.html')) - d.addCallback(self.assertEqual, fname('index.html')) - return d + @pytest_twisted.ensureDeferred + async def test_download(self): + filename = await download_file(self.get_url(), fname('index.html')) + assert filename == fname('index.html') - def test_download_without_required_cookies(self): + @pytest_twisted.ensureDeferred + async def test_download_without_required_cookies(self): url = self.get_url('cookie') - d = download_file(url, fname('none')) - d.addCallback(self.fail) - d.addErrback(self.assertIsInstance, Failure) - return d + filename = await download_file(url, fname('none')) + self.assert_contains(filename, 'Password cookie not set!') - def test_download_with_required_cookies(self): + @pytest_twisted.ensureDeferred + async def test_download_with_required_cookies(self): url = self.get_url('cookie') cookie = {'cookie': 'password=deluge'} - d = download_file(url, fname('monster'), headers=cookie) - d.addCallback(self.assertEqual, fname('monster')) - d.addCallback(self.assertContains, 'COOKIE MONSTER!') - return d + filename = await download_file(url, fname('monster'), headers=cookie) + assert filename == fname('monster') + self.assert_contains(filename, 'COOKIE MONSTER!') - def test_download_with_rename(self): + @pytest_twisted.ensureDeferred + async def test_download_with_rename(self): url = self.get_url('rename?filename=renamed') - d = download_file(url, fname('original')) - d.addCallback(self.assertEqual, fname('renamed')) - d.addCallback(self.assertContains, 'This file should be called renamed') - return d + filename = await download_file(url, fname('original')) + assert filename == fname('renamed') + self.assert_contains(filename, 'This file should be called renamed') - def test_download_with_rename_exists(self): + @pytest_twisted.ensureDeferred + async def test_download_with_rename_exists(self): open(fname('renamed'), 'w').close() url = self.get_url('rename?filename=renamed') - d = download_file(url, fname('original')) - d.addCallback(self.assertEqual, fname('renamed-1')) - d.addCallback(self.assertContains, 'This file should be called renamed') - return d + filename = await download_file(url, fname('original')) + assert filename == fname('renamed-1') + self.assert_contains(filename, 'This file should be called renamed') - def test_download_with_rename_sanitised(self): + @pytest_twisted.ensureDeferred + async def test_download_with_rename_sanitised(self): url = self.get_url('rename?filename=/etc/passwd') - d = download_file(url, fname('original')) - d.addCallback(self.assertEqual, fname('passwd')) - d.addCallback(self.assertContains, 'This file should be called /etc/passwd') - return d + filename = await download_file(url, fname('original')) + assert filename == fname('passwd') + self.assert_contains(filename, 'This file should be called /etc/passwd') - def test_download_with_attachment_no_filename(self): + @pytest_twisted.ensureDeferred + async def test_download_with_attachment_no_filename(self): url = self.get_url('attachment') - d = download_file(url, fname('original')) - d.addCallback(self.assertEqual, fname('original')) - d.addCallback(self.assertContains, 'Attachment with no filename set') - return d + filename = await download_file(url, fname('original')) + assert filename == fname('original') + self.assert_contains(filename, 'Attachment with no filename set') - def test_download_with_rename_prevented(self): + @pytest_twisted.ensureDeferred + async def test_download_with_rename_prevented(self): url = self.get_url('rename?filename=spam') - d = download_file(url, fname('forced'), force_filename=True) - d.addCallback(self.assertEqual, fname('forced')) - d.addCallback(self.assertContains, 'This file should be called spam') - return d + filename = await download_file(url, fname('forced'), force_filename=True) + assert filename == fname('forced') + self.assert_contains(filename, 'This file should be called spam') - def test_download_with_gzip_encoding(self): + @pytest_twisted.ensureDeferred + async def test_download_with_gzip_encoding(self): url = self.get_url('gzip?msg=success') - d = download_file(url, fname('gzip_encoded')) - d.addCallback(self.assertContains, 'success') - return d + filename = await download_file(url, fname('gzip_encoded')) + self.assert_contains(filename, 'success') - def test_download_with_gzip_encoding_disabled(self): + @pytest_twisted.ensureDeferred + async def test_download_with_gzip_encoding_disabled(self): url = self.get_url('gzip?msg=unzip') - d = download_file(url, fname('gzip_encoded'), allow_compression=False) - d.addCallback(self.assertContains, 'unzip') - return d + filename = await download_file( + url, fname('gzip_encoded'), allow_compression=False + ) + self.assert_contains(filename, 'unzip') - def test_page_redirect_unhandled(self): + @pytest_twisted.ensureDeferred + async def test_page_redirect_unhandled(self): url = self.get_url('redirect') - d = download_file(url, fname('none')) - d.addCallback(self.fail) + with pytest.raises(PageRedirect): + await download_file(url, fname('none'), handle_redirects=False) - def on_redirect(failure): - self.assertTrue(type(failure), PageRedirect) - - d.addErrback(on_redirect) - return d - - def test_page_redirect(self): + @pytest_twisted.ensureDeferred + async def test_page_redirect(self): url = self.get_url('redirect') - d = download_file(url, fname('none'), handle_redirects=True) - d.addCallback(self.assertEqual, fname('none')) - d.addErrback(self.fail) - return d + filename = await download_file(url, fname('none'), handle_redirects=True) + assert filename == fname('none') - def test_page_not_found(self): - d = download_file(self.get_url('page/not/found'), fname('none')) - d.addCallback(self.fail) - d.addErrback(self.assertIsInstance, Failure) - return d + @pytest_twisted.ensureDeferred + async def test_page_not_found(self): + with pytest.raises(Error): + await download_file(self.get_url('page/not/found'), fname('none')) - def test_page_not_modified(self): + @pytest.mark.xfail(reason="Doesn't seem like httpdownloader ever implemented this.") + @pytest_twisted.ensureDeferred + async def test_page_not_modified(self): headers = {'If-Modified-Since': formatdate(usegmt=True)} - d = download_file(self.get_url(), fname('index.html'), headers=headers) - d.addCallback(self.fail) - d.addErrback(self.assertIsInstance, Failure) - return d + with pytest.raises(Error) as exc_info: + await download_file(self.get_url(), fname('index.html'), headers=headers) + assert exc_info.value.status == NOT_MODIFIED - def test_download_text_reencode_charset(self): + @pytest_twisted.ensureDeferred + async def test_download_text_reencode_charset(self): """Re-encode as UTF-8 specified charset for text content-type header""" url = self.get_url('attachment') filepath = fname('test.txt') headers = {'content-charset': 'Windows-1251', 'content-append': 'бвгде'} - d = download_file(url, filepath, headers=headers) - d.addCallback(self.assertEqual, filepath) - d.addCallback(self.assertContains, 'Attachment with no filename setбвгде') - return d + filename = await download_file(url, filepath, headers=headers) + assert filename == filepath + self.assert_contains(filename, 'Attachment with no filename setбвгде') - def test_download_binary_ignore_charset(self): + @pytest_twisted.ensureDeferred + async def test_download_binary_ignore_charset(self): """Ignore charset for binary content-type header e.g. torrent files""" url = self.get_url('torrent') headers = {'content-charset': 'Windows-1251'} filepath = fname('test.torrent') - d = download_file(url, fname('test.torrent'), headers=headers) - d.addCallback(self.assertEqual, filepath) - d.addCallback(self.assertContains, 'Binary attachment ignore charset 世丕且\n') - return d + filename = await download_file(url, fname('test.torrent'), headers=headers) + assert filename == filepath + self.assert_contains(filename, 'Binary attachment ignore charset 世丕且\n') diff --git a/deluge/tests/test_json_api.py b/deluge/tests/test_json_api.py index 765eb0e0b..c6eedd331 100644 --- a/deluge/tests/test_json_api.py +++ b/deluge/tests/test_json_api.py @@ -9,59 +9,32 @@ import json as json_lib from unittest.mock import MagicMock -from twisted.internet import defer +import pytest +import pytest_twisted from twisted.web import server from twisted.web.http import Request import deluge.common -import deluge.component as component import deluge.ui.web.auth import deluge.ui.web.json_api from deluge.error import DelugeError -from deluge.ui.client import client from deluge.ui.web.auth import Auth from deluge.ui.web.json_api import JSON, JSONException from . import common -from .basetest import BaseTestCase from .common_web import WebServerMockBase -from .daemon_base import DaemonBase common.disable_new_release_check() -class JSONBase(BaseTestCase, DaemonBase): - def connect_client(self, *args, **kwargs): - return client.connect( - 'localhost', - self.listen_port, - username=kwargs.get('user', ''), - password=kwargs.get('password', ''), - ) - - def disconnect_client(self, *args): - return client.disconnect() - - def tear_down(self): - d = component.shutdown() - d.addCallback(self.disconnect_client) - d.addCallback(self.terminate_core) - return d - - -class JSONTestCase(JSONBase): - def set_up(self): - d = self.common_set_up() - d.addCallback(self.start_core) - d.addCallbacks(self.connect_client, self.terminate_core) - return d - - @defer.inlineCallbacks - def test_get_remote_methods(self): +@pytest.mark.usefixtures('daemon', 'client', 'component') +class TestJSON: + @pytest_twisted.ensureDeferred + async def test_get_remote_methods(self): json = JSON() - methods = yield json.get_remote_methods() - self.assertEqual(type(methods), tuple) - self.assertTrue(len(methods) > 0) + methods = await json.get_remote_methods() + assert type(methods) == tuple + assert len(methods) > 0 def test_render_fail_disconnected(self): json = JSON() @@ -69,7 +42,7 @@ class JSONTestCase(JSONBase): request.method = b'POST' request._disconnected = True # When disconnected, returns empty string - self.assertEqual(json.render(request), '') + assert json.render(request) == '' def test_render_fail(self): json = JSON() @@ -79,19 +52,17 @@ class JSONTestCase(JSONBase): def write(response_str): request.write_was_called = True response = json_lib.loads(response_str.decode()) - self.assertEqual(response['result'], None) - self.assertEqual(response['id'], None) - self.assertEqual( - response['error']['message'], 'JSONException: JSON not decodable' - ) - self.assertEqual(response['error']['code'], 5) + assert response['result'] is None + assert response['id'] is None + assert response['error']['message'] == 'JSONException: JSON not decodable' + assert response['error']['code'] == 5 request.write = write request.write_was_called = False request._disconnected = False request.getHeader.return_value = b'application/json' - self.assertEqual(json.render(request), server.NOT_DONE_YET) - self.assertTrue(request.write_was_called) + assert json.render(request) == server.NOT_DONE_YET + assert request.write_was_called def test_handle_request_invalid_method(self): json = JSON() @@ -99,20 +70,23 @@ class JSONTestCase(JSONBase): json_data = {'method': 'no-existing-module.test', 'id': 0, 'params': []} request.json = json_lib.dumps(json_data).encode() request_id, result, error = json._handle_request(request) - self.assertEqual(error, {'message': 'Unknown method', 'code': 2}) + assert error == {'message': 'Unknown method', 'code': 2} def test_handle_request_invalid_json_request(self): json = JSON() request = MagicMock() json_data = {'id': 0, 'params': []} request.json = json_lib.dumps(json_data).encode() - self.assertRaises(JSONException, json._handle_request, request) + with pytest.raises(JSONException): + json._handle_request(request) json_data = {'method': 'some.method', 'params': []} request.json = json_lib.dumps(json_data).encode() - self.assertRaises(JSONException, json._handle_request, request) + with pytest.raises(JSONException): + json._handle_request(request) json_data = {'method': 'some.method', 'id': 0} request.json = json_lib.dumps(json_data).encode() - self.assertRaises(JSONException, json._handle_request, request) + with pytest.raises(JSONException): + json._handle_request(request) def test_on_json_request_invalid_content_type(self): """Test for exception with content type not application/json""" @@ -121,18 +95,14 @@ class JSONTestCase(JSONBase): request.getHeader.return_value = b'text/plain' json_data = {'method': 'some.method', 'id': 0, 'params': []} request.json = json_lib.dumps(json_data).encode() - self.assertRaises(JSONException, json._on_json_request, request) + with pytest.raises(JSONException): + json._on_json_request(request) -class JSONCustomUserTestCase(JSONBase): - def set_up(self): - d = self.common_set_up() - d.addCallback(self.start_core) - return d - - @defer.inlineCallbacks +@pytest.mark.usefixtures('daemon', 'client', 'component') +class TestJSONCustomUserTestCase: + @pytest_twisted.inlineCallbacks def test_handle_request_auth_error(self): - yield self.connect_client() json = JSON() auth_conf = {'session_timeout': 10, 'sessions': {}} Auth(auth_conf) # Must create the component @@ -145,13 +115,12 @@ class JSONCustomUserTestCase(JSONBase): json_data = {'method': 'core.get_libtorrent_version', 'id': 0, 'params': []} request.json = json_lib.dumps(json_data).encode() request_id, result, error = json._handle_request(request) - self.assertEqual(error, {'message': 'Not authenticated', 'code': 1}) + assert error == {'message': 'Not authenticated', 'code': 1} -class RPCRaiseDelugeErrorJSONTestCase(JSONBase): - def set_up(self): - d = self.common_set_up() - custom_script = """ +@pytest.mark.usefixtures('daemon', 'client', 'component') +class TestRPCRaiseDelugeErrorJSON: + daemon_custom_script = """ from deluge.error import DelugeError from deluge.core.rpcserver import export class TestClass(object): @@ -162,12 +131,9 @@ class RPCRaiseDelugeErrorJSONTestCase(JSONBase): test = TestClass() daemon.rpcserver.register_object(test) """ - d.addCallback(self.start_core, custom_script=custom_script) - d.addCallbacks(self.connect_client, self.terminate_core) - return d - @defer.inlineCallbacks - def test_handle_request_method_raise_delugeerror(self): + @pytest_twisted.ensureDeferred + async def test_handle_request_method_raise_delugeerror(self): json = JSON() def get_session_id(s_id): @@ -179,9 +145,9 @@ class RPCRaiseDelugeErrorJSONTestCase(JSONBase): request = Request(MagicMock(), False) request.base = b'' auth._create_session(request) - methods = yield json.get_remote_methods() + methods = await json.get_remote_methods() # Verify the function has been registered - self.assertTrue('testclass.test' in methods) + assert 'testclass.test' in methods request = MagicMock() session_id = list(auth.config['sessions'])[0] @@ -189,18 +155,13 @@ class RPCRaiseDelugeErrorJSONTestCase(JSONBase): json_data = {'method': 'testclass.test', 'id': 0, 'params': []} request.json = json_lib.dumps(json_data).encode() request_id, result, error = json._handle_request(request) - result.addCallback(self.fail) - - def on_error(error): - self.assertEqual(error.type, DelugeError) - - result.addErrback(on_error) - yield result + with pytest.raises(DelugeError): + await result -class JSONRequestFailedTestCase(JSONBase, WebServerMockBase): - def set_up(self): - d = self.common_set_up() +class TestJSONRequestFailed(WebServerMockBase): + @pytest_twisted.async_yield_fixture(autouse=True) + async def set_up(self, config_dir): custom_script = """ from deluge.error import DelugeError from deluge.core.rpcserver import export @@ -231,28 +192,29 @@ class JSONRequestFailedTestCase(JSONBase, WebServerMockBase): } def on_test_raise(*args): - self.assertTrue('Unhandled error in Deferred:' in self.core.stderr_out) - self.assertTrue('in test_raise_error' in self.core.stderr_out) + assert 'Unhandled error in Deferred:' in self.core.stderr_out + assert 'in test_raise_error' in self.core.stderr_out extra_callback['deferred'].addCallback(on_test_raise) - d.addCallback( - self.start_core, + d, daemon = common.start_core( custom_script=custom_script, print_stdout=False, print_stderr=False, timeout=5, extra_callbacks=[extra_callback], + config_directory=config_dir, ) - d.addCallbacks(self.connect_client, self.terminate_core) - return d + await d + yield + await daemon.kill() - @defer.inlineCallbacks - def test_render_on_rpc_request_failed(self): + @pytest_twisted.inlineCallbacks + def test_render_on_rpc_request_failed(self, component, client): json = JSON() methods = yield json.get_remote_methods() # Verify the function has been registered - self.assertTrue('testclass.test' in methods) + assert 'testclass.test' in methods request = MagicMock() @@ -263,14 +225,14 @@ class JSONRequestFailedTestCase(JSONBase, WebServerMockBase): def write(response_str): request.write_was_called = True response = json_lib.loads(response_str.decode()) - self.assertEqual(response['result'], None, 'BAD RESULT') - self.assertEqual(response['id'], 0) - self.assertEqual( - response['error']['message'], - 'Failure: [Failure instance: Traceback (failure with no frames):' - " : DelugeERROR\n]", + assert response['result'] is None, 'BAD RESULT' + assert response['id'] == 0 + assert ( + response['error']['message'] + == 'Failure: [Failure instance: Traceback (failure with no frames):' + " : DelugeERROR\n]" ) - self.assertEqual(response['error']['code'], 4) + assert response['error']['code'] == 4 request.write = write request.write_was_called = False @@ -281,8 +243,8 @@ class JSONRequestFailedTestCase(JSONBase, WebServerMockBase): d = json._on_json_request(request) def on_success(arg): - self.assertEqual(arg, server.NOT_DONE_YET) + assert arg == server.NOT_DONE_YET return True - d.addCallbacks(on_success, self.fail) + d.addCallbacks(on_success, pytest.fail) yield d diff --git a/deluge/tests/test_log.py b/deluge/tests/test_log.py index 424fd4720..f0dcbee86 100644 --- a/deluge/tests/test_log.py +++ b/deluge/tests/test_log.py @@ -10,12 +10,11 @@ import logging import warnings +from deluge.conftest import BaseTestCase from deluge.log import setup_logger -from .basetest import BaseTestCase - -class LogTestCase(BaseTestCase): +class TestLog(BaseTestCase): def set_up(self): setup_logger(logging.DEBUG) @@ -29,7 +28,7 @@ class LogTestCase(BaseTestCase): # Cause all warnings to always be triggered. warnings.simplefilter('always') LOG.debug('foo') - self.assertEqual(w[-1].category, DeprecationWarning) + assert w[-1].category == DeprecationWarning # def test_twisted_error_log(self): # from twisted.internet import defer diff --git a/deluge/tests/test_maketorrent.py b/deluge/tests/test_maketorrent.py index 76239b82c..a2e473f00 100644 --- a/deluge/tests/test_maketorrent.py +++ b/deluge/tests/test_maketorrent.py @@ -7,8 +7,6 @@ import os import tempfile -from twisted.trial import unittest - from deluge import maketorrent @@ -24,7 +22,7 @@ def check_torrent(filename): TorrentInfo(filename) -class MakeTorrentTestCase(unittest.TestCase): +class TestMakeTorrent: def test_save_multifile(self): # Create a temporary folder for torrent creation tmp_path = tempfile.mkdtemp() diff --git a/deluge/tests/test_metafile.py b/deluge/tests/test_metafile.py index 5aa1400a7..fda1cb73e 100644 --- a/deluge/tests/test_metafile.py +++ b/deluge/tests/test_metafile.py @@ -7,8 +7,6 @@ import os import tempfile -from twisted.trial import unittest - from deluge import metafile @@ -24,7 +22,7 @@ def check_torrent(filename): TorrentInfo(filename) -class MetafileTestCase(unittest.TestCase): +class TestMetafile: def test_save_multifile(self): # Create a temporary folder for torrent creation tmp_path = tempfile.mkdtemp() diff --git a/deluge/tests/test_plugin_metadata.py b/deluge/tests/test_plugin_metadata.py index 58e410ad5..adf115d1b 100644 --- a/deluge/tests/test_plugin_metadata.py +++ b/deluge/tests/test_plugin_metadata.py @@ -8,26 +8,20 @@ from deluge.pluginmanagerbase import PluginManagerBase -from . import common -from .basetest import BaseTestCase - - -class PluginManagerBaseTestCase(BaseTestCase): - def set_up(self): - common.set_tmp_config_dir() +class TestPluginManagerBase: def test_get_plugin_info(self): pm = PluginManagerBase('core.conf', 'deluge.plugin.core') for p in pm.get_available_plugins(): for key, value in pm.get_plugin_info(p).items(): - self.assertIsInstance(key, str) - self.assertIsInstance(value, str) + assert isinstance(key, str) + assert isinstance(value, str) def test_get_plugin_info_invalid_name(self): pm = PluginManagerBase('core.conf', 'deluge.plugin.core') for key, value in pm.get_plugin_info('random').items(): result = 'not available' if key in ('Name', 'Version') else '' - self.assertEqual(value, result) + assert value == result def test_parse_pkg_info_metadata_2_1(self): pkg_info = """Metadata-Version: 2.1 @@ -44,6 +38,6 @@ Monitors folders for .torrent files. """ plugin_info = PluginManagerBase.parse_pkg_info(pkg_info) for value in plugin_info.values(): - self.assertNotEqual(value, '') + assert value != '' result = 'Monitors folders for .torrent files.' - self.assertEqual(plugin_info['Description'], result) + assert plugin_info['Description'] == result diff --git a/deluge/tests/test_rpcserver.py b/deluge/tests/test_rpcserver.py index ab0844038..982d1d5f1 100644 --- a/deluge/tests/test_rpcserver.py +++ b/deluge/tests/test_rpcserver.py @@ -9,13 +9,12 @@ import deluge.component as component import deluge.error from deluge.common import get_localhost_auth +from deluge.conftest import BaseTestCase from deluge.core import rpcserver from deluge.core.authmanager import AuthManager from deluge.core.rpcserver import DelugeRPCProtocol, RPCServer from deluge.log import setup_logger -from .basetest import BaseTestCase - setup_logger('none') @@ -27,7 +26,7 @@ class DelugeRPCProtocolTester(DelugeRPCProtocol): self.messages.append(data) -class RPCServerTestCase(BaseTestCase): +class TestRPCServer(BaseTestCase): def set_up(self): self.rpcserver = RPCServer(listen=False) self.rpcserver.factory.protocol = DelugeRPCProtocolTester @@ -57,15 +56,15 @@ class RPCServerTestCase(BaseTestCase): e = TorrentFolderRenamedEvent(*data) self.rpcserver.emit_event_for_session_id(self.session_id, e) msg = self.protocol.messages.pop() - self.assertEqual(msg[0], rpcserver.RPC_EVENT, str(msg)) - self.assertEqual(msg[1], 'TorrentFolderRenamedEvent', str(msg)) - self.assertEqual(msg[2], data, str(msg)) + assert msg[0] == rpcserver.RPC_EVENT, str(msg) + assert msg[1] == 'TorrentFolderRenamedEvent', str(msg) + assert msg[2] == data, str(msg) def test_invalid_client_login(self): self.protocol.dispatch(self.request_id, 'daemon.login', [1], {}) msg = self.protocol.messages.pop() - self.assertEqual(msg[0], rpcserver.RPC_ERROR) - self.assertEqual(msg[1], self.request_id) + assert msg[0] == rpcserver.RPC_ERROR + assert msg[1] == self.request_id def test_valid_client_login(self): self.authmanager = AuthManager() @@ -74,9 +73,9 @@ class RPCServerTestCase(BaseTestCase): self.request_id, 'daemon.login', auth, {'client_version': 'Test'} ) msg = self.protocol.messages.pop() - self.assertEqual(msg[0], rpcserver.RPC_RESPONSE, str(msg)) - self.assertEqual(msg[1], self.request_id, str(msg)) - self.assertEqual(msg[2], rpcserver.AUTH_LEVEL_ADMIN, str(msg)) + assert msg[0] == rpcserver.RPC_RESPONSE, str(msg) + assert msg[1] == self.request_id, str(msg) + assert msg[2] == rpcserver.AUTH_LEVEL_ADMIN, str(msg) def test_client_login_error(self): # This test causes error log prints while running the test... @@ -87,24 +86,24 @@ class RPCServerTestCase(BaseTestCase): self.request_id, 'daemon.login', auth, {'client_version': 'Test'} ) msg = self.protocol.messages.pop() - self.assertEqual(msg[0], rpcserver.RPC_ERROR) - self.assertEqual(msg[1], self.request_id) - self.assertEqual(msg[2], 'WrappedException') - self.assertEqual(msg[3][1], 'AttributeError') + assert msg[0] == rpcserver.RPC_ERROR + assert msg[1] == self.request_id + assert msg[2] == 'WrappedException' + assert msg[3][1] == 'AttributeError' def test_client_invalid_method_call(self): self.authmanager = AuthManager() auth = get_localhost_auth() self.protocol.dispatch(self.request_id, 'invalid_function', auth, {}) msg = self.protocol.messages.pop() - self.assertEqual(msg[0], rpcserver.RPC_ERROR) - self.assertEqual(msg[1], self.request_id) - self.assertEqual(msg[2], 'WrappedException') - self.assertEqual(msg[3][1], 'AttributeError') + assert msg[0] == rpcserver.RPC_ERROR + assert msg[1] == self.request_id + assert msg[2] == 'WrappedException' + assert msg[3][1] == 'AttributeError' def test_daemon_info(self): self.protocol.dispatch(self.request_id, 'daemon.info', [], {}) msg = self.protocol.messages.pop() - self.assertEqual(msg[0], rpcserver.RPC_RESPONSE, str(msg)) - self.assertEqual(msg[1], self.request_id, str(msg)) - self.assertEqual(msg[2], deluge.common.get_version(), str(msg)) + assert msg[0] == rpcserver.RPC_RESPONSE, str(msg) + assert msg[1] == self.request_id, str(msg) + assert msg[2] == deluge.common.get_version(), str(msg) diff --git a/deluge/tests/test_security.py b/deluge/tests/test_security.py index 6fac802e8..e3e434433 100644 --- a/deluge/tests/test_security.py +++ b/deluge/tests/test_security.py @@ -13,9 +13,9 @@ import deluge.component as component import deluge.ui.web.server from deluge import configmanager from deluge.common import windows_check +from deluge.conftest import BaseTestCase from deluge.ui.web.server import DelugeWeb -from .basetest import BaseTestCase from .common import get_test_data_file from .common_web import WebServerTestBase from .daemon_base import DaemonBase @@ -23,15 +23,10 @@ from .daemon_base import DaemonBase SECURITY_TESTS = bool(os.getenv('SECURITY_TESTS', False)) +# TODO: This whole module has not been tested since migrating tests fully to pytest class SecurityBaseTestCase: - if windows_check(): - skip = 'windows cannot run .sh files' - elif not SECURITY_TESTS: - skip = 'Skipping security tests' - - http_err = 'cannot run http tests on daemon' - - def __init__(self): + @pytest.fixture(autouse=True) + def setvars(self): self.home_dir = os.path.expanduser('~') self.port = 8112 @@ -54,10 +49,10 @@ class SecurityBaseTestCase: if test == '-e': results = results[0].split(b'\n')[7:-6] - self.assertTrue(len(results) > 3) + assert len(results) > 3 else: - self.assertIn(b'OK', results[0]) - self.assertNotIn(b'NOT ok', results[0]) + assert b'OK' in results[0] + assert b'NOT ok' not in results[0] d.addCallback(on_result) return d @@ -74,18 +69,12 @@ class SecurityBaseTestCase: def test_secured_webserver_css_injection_vulnerability(self): return self._run_test('-I') - def test_secured_webserver_ticketbleed_vulnerability(self): - return self._run_test('-T') - def test_secured_webserver_renegotiation_vulnerabilities(self): return self._run_test('-R') def test_secured_webserver_crime_vulnerability(self): return self._run_test('-C') - def test_secured_webserver_breach_vulnerability(self): - return self._run_test('-B') - def test_secured_webserver_poodle_vulnerability(self): return self._run_test('-O') @@ -119,33 +108,14 @@ class SecurityBaseTestCase: def test_secured_webserver_preference(self): return self._run_test('-P') - def test_secured_webserver_headers(self): - return self._run_test('-h') - def test_secured_webserver_ciphers(self): return self._run_test('-e') +@pytest.mark.skipif(windows_check(), reason='windows cannot run .sh files') +@pytest.mark.skipif(not SECURITY_TESTS, reason='skipping security tests') @pytest.mark.security -class DaemonSecurityTestCase(BaseTestCase, DaemonBase, SecurityBaseTestCase): - - if windows_check(): - skip = 'windows cannot start_core not enough arguments for format string' - - def __init__(self, testname): - super().__init__(testname) - DaemonBase.__init__(self) - SecurityBaseTestCase.__init__(self) - - def setUp(self): - skip = False - for not_http_test in ('breach', 'headers', 'ticketbleed'): - if not_http_test in self.id().split('.')[-1]: - self.skipTest(SecurityBaseTestCase.http_err) - skip = True - if not skip: - super().setUp() - +class TestDaemonSecurity(BaseTestCase, DaemonBase, SecurityBaseTestCase): def set_up(self): d = self.common_set_up() self.port = self.listen_port @@ -159,12 +129,10 @@ class DaemonSecurityTestCase(BaseTestCase, DaemonBase, SecurityBaseTestCase): return d +@pytest.mark.skipif(windows_check(), reason='windows cannot run .sh files') +@pytest.mark.skipif(not SECURITY_TESTS, reason='skipping security tests') @pytest.mark.security -class WebUISecurityTestBase(WebServerTestBase, SecurityBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - SecurityBaseTestCase.__init__(self) - +class TestWebUISecurity(WebServerTestBase, SecurityBaseTestCase): def start_webapi(self, arg): self.port = self.webserver_listen_port = 8999 @@ -180,3 +148,12 @@ class WebUISecurityTestBase(WebServerTestBase, SecurityBaseTestCase): self.deluge_web.web_api.hostlist.config['hosts'][0] = tuple(host) self.host_id = host[0] self.deluge_web.start() + + def test_secured_webserver_headers(self): + return self._run_test('-h') + + def test_secured_webserver_breach_vulnerability(self): + return self._run_test('-B') + + def test_secured_webserver_ticketbleed_vulnerability(self): + return self._run_test('-T') diff --git a/deluge/tests/test_sessionproxy.py b/deluge/tests/test_sessionproxy.py index f73e522f1..6fbbb248b 100644 --- a/deluge/tests/test_sessionproxy.py +++ b/deluge/tests/test_sessionproxy.py @@ -5,14 +5,13 @@ # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # - +import pytest_twisted from twisted.internet.defer import maybeDeferred, succeed from twisted.internet.task import Clock import deluge.component as component import deluge.ui.sessionproxy - -from .basetest import BaseTestCase +from deluge.conftest import BaseTestCase class Core: @@ -102,7 +101,7 @@ class Client: client = Client() -class SessionProxyTestCase(BaseTestCase): +class TestSessionProxy(BaseTestCase): def set_up(self): self.clock = Clock() self.patch(deluge.ui.sessionproxy, 'time', self.clock.seconds) @@ -124,38 +123,38 @@ class SessionProxyTestCase(BaseTestCase): return component.deregister(self.sp) def test_startup(self): - self.assertEqual(client.core.torrents['a'], self.sp.torrents['a'][1]) + assert client.core.torrents['a'] == self.sp.torrents['a'][1] - def test_get_torrent_status_no_change(self): - d = self.sp.get_torrent_status('a', []) - d.addCallback(self.assertEqual, client.core.torrents['a']) - return d + @pytest_twisted.ensureDeferred + async def test_get_torrent_status_no_change(self): + result = await self.sp.get_torrent_status('a', []) + assert result == client.core.torrents['a'] - def test_get_torrent_status_change_with_cache(self): + @pytest_twisted.ensureDeferred + async def test_get_torrent_status_change_with_cache(self): client.core.torrents['a']['key1'] = 2 - d = self.sp.get_torrent_status('a', ['key1']) - d.addCallback(self.assertEqual, {'key1': 1}) - return d + result = await self.sp.get_torrent_status('a', ['key1']) + assert result == {'key1': 1} - def test_get_torrent_status_change_without_cache(self): + @pytest_twisted.ensureDeferred + async def test_get_torrent_status_change_without_cache(self): client.core.torrents['a']['key1'] = 2 self.clock.advance(self.sp.cache_time + 0.1) - d = self.sp.get_torrent_status('a', []) - d.addCallback(self.assertEqual, client.core.torrents['a']) - return d + result = await self.sp.get_torrent_status('a', []) + assert result == client.core.torrents['a'] - def test_get_torrent_status_key_not_updated(self): + @pytest_twisted.ensureDeferred + async def test_get_torrent_status_key_not_updated(self): self.clock.advance(self.sp.cache_time + 0.1) self.sp.get_torrent_status('a', ['key1']) client.core.torrents['a']['key2'] = 99 - d = self.sp.get_torrent_status('a', ['key2']) - d.addCallback(self.assertEqual, {'key2': 99}) - return d + result = await self.sp.get_torrent_status('a', ['key2']) + assert result == {'key2': 99} - def test_get_torrents_status_key_not_updated(self): + @pytest_twisted.ensureDeferred + async def test_get_torrents_status_key_not_updated(self): self.clock.advance(self.sp.cache_time + 0.1) self.sp.get_torrents_status({'id': ['a']}, ['key1']) client.core.torrents['a']['key2'] = 99 - d = self.sp.get_torrents_status({'id': ['a']}, ['key2']) - d.addCallback(self.assertEqual, {'a': {'key2': 99}}) - return d + result = await self.sp.get_torrents_status({'id': ['a']}, ['key2']) + assert result == {'a': {'key2': 99}} diff --git a/deluge/tests/test_torrent.py b/deluge/tests/test_torrent.py index 99069f9c9..d84b9b46c 100644 --- a/deluge/tests/test_torrent.py +++ b/deluge/tests/test_torrent.py @@ -9,30 +9,28 @@ import time from base64 import b64encode from unittest import mock +import pytest from twisted.internet import defer, reactor from twisted.internet.task import deferLater -from twisted.trial import unittest import deluge.component as component import deluge.core.torrent import deluge.tests.common as common from deluge._libtorrent import lt from deluge.common import VersionSplit, utf8_encode_structure +from deluge.conftest import BaseTestCase from deluge.core.core import Core from deluge.core.rpcserver import RPCServer from deluge.core.torrent import Torrent from deluge.core.torrentmanager import TorrentManager, TorrentState -from .basetest import BaseTestCase - -class TorrentTestCase(BaseTestCase): +class TestTorrent(BaseTestCase): def setup_config(self): - config_dir = common.set_tmp_config_dir() core_config = deluge.config.Config( 'core.conf', defaults=deluge.core.preferencesmanager.DEFAULT_PREFS, - config_dir=config_dir, + config_dir=self.config_dir, ) core_config.save() @@ -64,7 +62,7 @@ class TorrentTestCase(BaseTestCase): def assert_state(self, torrent, state): torrent.update_state() - self.assertEqual(torrent.state, state) + assert torrent.state == state def get_torrent_atp(self, filename): filename = common.get_test_data_file(filename) @@ -88,11 +86,11 @@ class TorrentTestCase(BaseTestCase): torrent = Torrent(handle, {}) result = torrent.get_file_priorities() - self.assertTrue(all(x == 4 for x in result)) + assert all(x == 4 for x in result) new_priorities = [3, 1, 2, 0, 5, 6, 7] torrent.set_file_priorities(new_priorities) - self.assertEqual(torrent.get_file_priorities(), new_priorities) + assert torrent.get_file_priorities() == new_priorities # Test with handle.piece_priorities as handle.file_priorities async # updates and will return old value. Also need to remove a priority @@ -100,7 +98,7 @@ class TorrentTestCase(BaseTestCase): time.sleep(0.6) # Delay to wait for alert from lt piece_prio = handle.piece_priorities() result = all(p in piece_prio for p in [3, 2, 0, 5, 6, 7]) - self.assertTrue(result) + assert result def test_set_prioritize_first_last_pieces(self): piece_indexes = [ @@ -145,14 +143,14 @@ class TorrentTestCase(BaseTestCase): priorities = handle.piece_priorities() # The length of the list of new priorites is the same as the original - self.assertEqual(len(priorities_original), len(priorities)) + assert len(priorities_original) == len(priorities) # Test the priority of all the pieces against the calculated indexes. for idx, priority in enumerate(priorities): if idx in prioritized_piece_indexes: - self.assertEqual(priorities[idx], 7) + assert priorities[idx] == 7 else: - self.assertEqual(priorities[idx], 4) + assert priorities[idx] == 4 # self.print_priority_list(priorities) @@ -168,7 +166,7 @@ class TorrentTestCase(BaseTestCase): # Test the priority of the prioritized pieces for i in priorities: - self.assertEqual(priorities[i], 4) + assert priorities[i] == 4 # self.print_priority_list(priorities) @@ -209,7 +207,7 @@ class TorrentTestCase(BaseTestCase): def test_torrent_error_resume_data_unaltered(self): if VersionSplit(lt.__version__) >= VersionSplit('1.2.0.0'): - raise unittest.SkipTest('Test not working as expected on lt 1.2 or greater') + pytest.skip('Test not working as expected on lt 1.2 or greater') resume_data = { 'active_time': 13399, @@ -277,7 +275,7 @@ class TorrentTestCase(BaseTestCase): tm_resume_data = lt.bdecode( self.core.torrentmanager.resume_data[torrent.torrent_id] ) - self.assertEqual(tm_resume_data, resume_data) + assert tm_resume_data == resume_data return deferLater(reactor, 0.5, assert_resume_data) @@ -285,7 +283,7 @@ class TorrentTestCase(BaseTestCase): atp = self.get_torrent_atp('test_torrent.file.torrent') handle = self.session.add_torrent(atp) self.torrent = Torrent(handle, {}) - self.assertEqual(self.torrent.get_eta(), 0) + assert self.torrent.get_eta() == 0 self.torrent.status = mock.MagicMock() self.torrent.status.upload_payload_rate = 5000 @@ -295,18 +293,18 @@ class TorrentTestCase(BaseTestCase): self.torrent.is_finished = True self.torrent.options = {'stop_at_ratio': False} # Test finished and uploading but no stop_at_ratio set. - self.assertEqual(self.torrent.get_eta(), 0) + assert self.torrent.get_eta() == 0 self.torrent.options = {'stop_at_ratio': True, 'stop_ratio': 1.5} result = self.torrent.get_eta() - self.assertEqual(result, 2) - self.assertIsInstance(result, int) + assert result == 2 + assert isinstance(result, int) def test_get_eta_downloading(self): atp = self.get_torrent_atp('test_torrent.file.torrent') handle = self.session.add_torrent(atp) self.torrent = Torrent(handle, {}) - self.assertEqual(self.torrent.get_eta(), 0) + assert self.torrent.get_eta() == 0 self.torrent.status = mock.MagicMock() self.torrent.status.download_payload_rate = 50 @@ -314,15 +312,15 @@ class TorrentTestCase(BaseTestCase): self.torrent.status.total_wanted_done = 5000 result = self.torrent.get_eta() - self.assertEqual(result, 100) - self.assertIsInstance(result, int) + assert result == 100 + assert isinstance(result, int) def test_get_name_unicode(self): """Test retrieving a unicode torrent name from libtorrent.""" atp = self.get_torrent_atp('unicode_file.torrent') handle = self.session.add_torrent(atp) self.torrent = Torrent(handle, {}) - self.assertEqual(self.torrent.get_name(), 'সুকুমার রায়.txt') + assert self.torrent.get_name() == 'সুকুমার রায়.txt' def test_rename_unicode(self): """Test renaming file/folders with unicode filenames.""" @@ -333,15 +331,15 @@ class TorrentTestCase(BaseTestCase): TorrentManager.save_resume_data = mock.MagicMock result = self.torrent.rename_folder('unicode_filenames', 'Горбачёв') - self.assertIsInstance(result, defer.DeferredList) + assert isinstance(result, defer.DeferredList) result = self.torrent.rename_files([[0, 'new_рбачёв']]) - self.assertIsNone(result) + assert result is None def test_connect_peer_port(self): """Test to ensure port is int for libtorrent""" atp = self.get_torrent_atp('test_torrent.file.torrent') handle = self.session.add_torrent(atp) self.torrent = Torrent(handle, {}) - self.assertFalse(self.torrent.connect_peer('127.0.0.1', 'text')) - self.assertTrue(self.torrent.connect_peer('127.0.0.1', '1234')) + assert not self.torrent.connect_peer('127.0.0.1', 'text') + assert self.torrent.connect_peer('127.0.0.1', '1234') diff --git a/deluge/tests/test_torrentmanager.py b/deluge/tests/test_torrentmanager.py index 9cfca328f..e1eaa6e50 100644 --- a/deluge/tests/test_torrentmanager.py +++ b/deluge/tests/test_torrentmanager.py @@ -11,24 +11,24 @@ from base64 import b64encode from unittest import mock import pytest -from twisted.internet import defer, task +import pytest_twisted +from twisted.internet import task from deluge import component from deluge.bencode import bencode +from deluge.conftest import BaseTestCase from deluge.core.core import Core from deluge.core.rpcserver import RPCServer from deluge.error import InvalidTorrentError from . import common -from .basetest import BaseTestCase warnings.filterwarnings('ignore', category=RuntimeWarning) warnings.resetwarnings() -class TorrentmanagerTestCase(BaseTestCase): +class TestTorrentmanager(BaseTestCase): def set_up(self): - self.config_dir = common.set_tmp_config_dir() self.rpcserver = RPCServer(listen=False) self.core = Core() self.core.config.config['lsd'] = False @@ -44,7 +44,7 @@ class TorrentmanagerTestCase(BaseTestCase): return component.shutdown().addCallback(on_shutdown) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_remove_torrent(self): filename = common.get_test_data_file('test.torrent') with open(filename, 'rb') as _file: @@ -52,9 +52,9 @@ class TorrentmanagerTestCase(BaseTestCase): torrent_id = yield self.core.add_torrent_file_async( filename, b64encode(filedump), {} ) - self.assertTrue(self.tm.remove(torrent_id, False)) + assert self.tm.remove(torrent_id, False) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_remove_magnet(self): """Test remove magnet before received metadata and delete_copies is True""" magnet = 'magnet:?xt=urn:btih:ab570cdd5a17ea1b61e970bb72047de141bce173' @@ -62,9 +62,10 @@ class TorrentmanagerTestCase(BaseTestCase): self.core.config.config['copy_torrent_file'] = True self.core.config.config['del_copy_torrent_file'] = True torrent_id = yield self.core.add_torrent_magnet(magnet, options) - self.assertTrue(self.tm.remove(torrent_id, False)) + assert self.tm.remove(torrent_id, False) - def test_prefetch_metadata(self): + @pytest_twisted.ensureDeferred + async def test_prefetch_metadata(self): from deluge._libtorrent import lt with open(common.get_test_data_file('test.torrent'), 'rb') as _file: @@ -114,14 +115,16 @@ class TorrentmanagerTestCase(BaseTestCase): ) ), ) - self.assertEqual(expected, self.successResultOf(d)) + assert expected == await d - def test_prefetch_metadata_timeout(self): + @pytest_twisted.ensureDeferred + async def test_prefetch_metadata_timeout(self): magnet = 'magnet:?xt=urn:btih:ab570cdd5a17ea1b61e970bb72047de141bce173' d = self.tm.prefetch_metadata(magnet, 30) self.clock.advance(30) + result = await d expected = ('ab570cdd5a17ea1b61e970bb72047de141bce173', b'') - return d.addCallback(self.assertEqual, expected) + assert result == expected @pytest.mark.todo def test_remove_torrent_false(self): @@ -129,9 +132,8 @@ class TorrentmanagerTestCase(BaseTestCase): common.todo_test(self) def test_remove_invalid_torrent(self): - self.assertRaises( - InvalidTorrentError, self.tm.remove, 'torrentidthatdoesntexist' - ) + with pytest.raises(InvalidTorrentError): + self.tm.remove('torrentidthatdoesntexist') def test_open_state(self): """Open a state with a UTF-8 encoded torrent filename.""" @@ -141,4 +143,4 @@ class TorrentmanagerTestCase(BaseTestCase): ) state = self.tm.open_state() - self.assertEqual(len(state.torrents), 1) + assert len(state.torrents) == 1 diff --git a/deluge/tests/test_torrentview.py b/deluge/tests/test_torrentview.py index e34c1c9e5..8d0568866 100644 --- a/deluge/tests/test_torrentview.py +++ b/deluge/tests/test_torrentview.py @@ -8,15 +8,12 @@ # import pytest -from twisted.trial import unittest import deluge.component as component from deluge.configmanager import ConfigManager +from deluge.conftest import BaseTestCase from deluge.i18n import setup_translation -from . import common -from .basetest import BaseTestCase - # Allow running other tests without GTKUI dependencies available try: # pylint: disable=ungrouped-imports @@ -37,7 +34,7 @@ setup_translation() @pytest.mark.gtkui -class TorrentviewTestCase(BaseTestCase): +class TestTorrentview(BaseTestCase): default_column_index = [ 'filter', @@ -107,9 +104,8 @@ class TorrentviewTestCase(BaseTestCase): def set_up(self): if libs_available is False: - raise unittest.SkipTest('GTKUI dependencies not available') + pytest.skip('GTKUI dependencies not available') - common.set_tmp_config_dir() # MainWindow loads this config file, so lets make sure it contains the defaults ConfigManager('gtk3ui.conf', defaults=DEFAULT_PREFS) self.mainwindow = MainWindow() @@ -121,36 +117,23 @@ class TorrentviewTestCase(BaseTestCase): return component.shutdown() def test_torrentview_columns(self): - - self.assertEqual( - self.torrentview.column_index, TorrentviewTestCase.default_column_index - ) - self.assertEqual( - self.torrentview.liststore_columns, - TorrentviewTestCase.default_liststore_columns, - ) - self.assertEqual( - self.torrentview.columns['Download Folder'].column_indices, [30] - ) + assert self.torrentview.column_index == self.default_column_index + assert self.torrentview.liststore_columns == self.default_liststore_columns + assert self.torrentview.columns['Download Folder'].column_indices == [30] def test_add_column(self): - # Add a text column test_col = 'Test column' self.torrentview.add_text_column(test_col, status_field=['label']) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns) + 1, + assert ( + len(self.torrentview.liststore_columns) + == len(self.default_liststore_columns) + 1 ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index) + 1, - ) - self.assertEqual(self.torrentview.column_index[-1], test_col) - self.assertEqual(self.torrentview.columns[test_col].column_indices, [33]) + assert len(self.torrentview.column_index) == len(self.default_column_index) + 1 + assert self.torrentview.column_index[-1] == test_col + assert self.torrentview.columns[test_col].column_indices == [33] def test_add_columns(self): - # Add a text column test_col = 'Test column' self.torrentview.add_text_column(test_col, status_field=['label']) @@ -159,50 +142,35 @@ class TorrentviewTestCase(BaseTestCase): test_col2 = 'Test column2' self.torrentview.add_text_column(test_col2, status_field=['label2']) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns) + 2, - ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index) + 2, + assert ( + len(self.torrentview.liststore_columns) + == len(self.default_liststore_columns) + 2 ) + assert len(self.torrentview.column_index) == len(self.default_column_index) + 2 # test_col - self.assertEqual(self.torrentview.column_index[-2], test_col) - self.assertEqual(self.torrentview.columns[test_col].column_indices, [33]) + assert self.torrentview.column_index[-2] == test_col + assert self.torrentview.columns[test_col].column_indices == [33] # test_col2 - self.assertEqual(self.torrentview.column_index[-1], test_col2) - self.assertEqual(self.torrentview.columns[test_col2].column_indices, [34]) + assert self.torrentview.column_index[-1] == test_col2 + assert self.torrentview.columns[test_col2].column_indices == [34] def test_remove_column(self): - # Add and remove text column test_col = 'Test column' self.torrentview.add_text_column(test_col, status_field=['label']) self.torrentview.remove_column(test_col) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns), - ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index), - ) - self.assertEqual( - self.torrentview.column_index[-1], - TorrentviewTestCase.default_column_index[-1], - ) - self.assertEqual( - self.torrentview.columns[ - TorrentviewTestCase.default_column_index[-1] - ].column_indices, - [32], + assert len(self.torrentview.liststore_columns) == len( + self.default_liststore_columns ) + assert len(self.torrentview.column_index) == len(self.default_column_index) + assert self.torrentview.column_index[-1] == self.default_column_index[-1] + assert self.torrentview.columns[ + self.default_column_index[-1] + ].column_indices == [32] def test_remove_columns(self): - # Add two columns test_col = 'Test column' self.torrentview.add_text_column(test_col, status_field=['label']) @@ -211,74 +179,47 @@ class TorrentviewTestCase(BaseTestCase): # Remove test_col self.torrentview.remove_column(test_col) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns) + 1, + assert ( + len(self.torrentview.liststore_columns) + == len(self.default_liststore_columns) + 1 ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index) + 1, - ) - self.assertEqual(self.torrentview.column_index[-1], test_col2) - self.assertEqual(self.torrentview.columns[test_col2].column_indices, [33]) + assert len(self.torrentview.column_index) == len(self.default_column_index) + 1 + assert self.torrentview.column_index[-1] == test_col2 + assert self.torrentview.columns[test_col2].column_indices == [33] # Remove test_col2 self.torrentview.remove_column(test_col2) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns), - ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index), - ) - self.assertEqual( - self.torrentview.column_index[-1], - TorrentviewTestCase.default_column_index[-1], - ) - self.assertEqual( - self.torrentview.columns[ - TorrentviewTestCase.default_column_index[-1] - ].column_indices, - [32], + assert len(self.torrentview.liststore_columns) == len( + self.default_liststore_columns ) + assert len(self.torrentview.column_index) == len(self.default_column_index) + assert self.torrentview.column_index[-1] == self.default_column_index[-1] + assert self.torrentview.columns[ + self.default_column_index[-1] + ].column_indices == [32] def test_add_remove_column_multiple_types(self): - # Add a column with multiple column types test_col3 = 'Test column3' self.torrentview.add_progress_column( test_col3, status_field=['progress', 'label3'], col_types=[float, str] ) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns) + 2, + assert ( + len(self.torrentview.liststore_columns) + == len(self.default_liststore_columns) + 2 ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index) + 1, - ) - self.assertEqual(self.torrentview.column_index[-1], test_col3) - self.assertEqual(self.torrentview.columns[test_col3].column_indices, [33, 34]) + assert len(self.torrentview.column_index) == len(self.default_column_index) + 1 + assert self.torrentview.column_index[-1] == test_col3 + assert self.torrentview.columns[test_col3].column_indices == [33, 34] # Remove multiple column-types column self.torrentview.remove_column(test_col3) - self.assertEqual( - len(self.torrentview.liststore_columns), - len(TorrentviewTestCase.default_liststore_columns), - ) - self.assertEqual( - len(self.torrentview.column_index), - len(TorrentviewTestCase.default_column_index), - ) - self.assertEqual( - self.torrentview.column_index[-1], - TorrentviewTestCase.default_column_index[-1], - ) - self.assertEqual( - self.torrentview.columns[ - TorrentviewTestCase.default_column_index[-1] - ].column_indices, - [32], + assert len(self.torrentview.liststore_columns) == len( + self.default_liststore_columns ) + assert len(self.torrentview.column_index) == len(self.default_column_index) + assert self.torrentview.column_index[-1] == self.default_column_index[-1] + assert self.torrentview.columns[ + self.default_column_index[-1] + ].column_indices == [32] diff --git a/deluge/tests/test_tracker_icons.py b/deluge/tests/test_tracker_icons.py index b7158bc1e..0e328e06c 100644 --- a/deluge/tests/test_tracker_icons.py +++ b/deluge/tests/test_tracker_icons.py @@ -5,20 +5,20 @@ # import pytest +import pytest_twisted import deluge.component as component import deluge.ui.tracker_icons +from deluge.conftest import BaseTestCase from deluge.ui.tracker_icons import TrackerIcon, TrackerIcons from . import common -from .basetest import BaseTestCase -common.set_tmp_config_dir() common.disable_new_release_check() @pytest.mark.internet -class TrackerIconsTestCase(BaseTestCase): +class TestTrackerIcons(BaseTestCase): def set_up(self): # Disable resizing with Pillow for consistency. self.patch(deluge.ui.tracker_icons, 'Image', None) @@ -27,48 +27,43 @@ class TrackerIconsTestCase(BaseTestCase): def tear_down(self): return component.shutdown() - def test_get_deluge_png(self): + @pytest_twisted.ensureDeferred + async def test_get_deluge_png(self): # Deluge has a png favicon link icon = TrackerIcon(common.get_test_data_file('deluge.png')) - d = self.icons.fetch('deluge-torrent.org') - d.addCallback(self.assertNotIdentical, None) - d.addCallback(self.assertEqual, icon) - return d + result = await self.icons.fetch('deluge-torrent.org') + assert result == icon - def test_get_google_ico(self): + @pytest_twisted.ensureDeferred + async def test_get_google_ico(self): # Google doesn't have any icon links # So instead we'll grab its favicon.ico icon = TrackerIcon(common.get_test_data_file('google.ico')) - d = self.icons.fetch('www.google.com') - d.addCallback(self.assertNotIdentical, None) - d.addCallback(self.assertEqual, icon) - return d + result = await self.icons.fetch('www.google.com') + assert result == icon - def test_get_google_ico_hebrew(self): + @pytest_twisted.ensureDeferred + async def test_get_google_ico_hebrew(self): """Test that Google.co.il page is read as UTF-8""" icon = TrackerIcon(common.get_test_data_file('google.ico')) - d = self.icons.fetch('www.google.co.il') - d.addCallback(self.assertNotIdentical, None) - d.addCallback(self.assertEqual, icon) - return d + result = await self.icons.fetch('www.google.co.il') + assert result == icon - def test_get_google_ico_with_redirect(self): + @pytest_twisted.ensureDeferred + async def test_get_google_ico_with_redirect(self): # google.com redirects to www.google.com icon = TrackerIcon(common.get_test_data_file('google.ico')) - d = self.icons.fetch('google.com') - d.addCallback(self.assertNotIdentical, None) - d.addCallback(self.assertEqual, icon) - return d + result = await self.icons.fetch('google.com') + assert result == icon - def test_get_seo_svg_with_sni(self): + @pytest_twisted.ensureDeferred + async def test_get_seo_svg_with_sni(self): # seo using certificates with SNI support only icon = TrackerIcon(common.get_test_data_file('seo.svg')) - d = self.icons.fetch('www.seo.com') - d.addCallback(self.assertNotIdentical, None) - d.addCallback(self.assertEqual, icon) - return d + result = await self.icons.fetch('www.seo.com') + assert result == icon - def test_get_empty_string_tracker(self): - d = self.icons.fetch('') - d.addCallback(self.assertIdentical, None) - return d + @pytest_twisted.ensureDeferred + async def test_get_empty_string_tracker(self): + result = await self.icons.fetch('') + assert result is None diff --git a/deluge/tests/test_transfer.py b/deluge/tests/test_transfer.py index a67e0da03..17a951b9a 100644 --- a/deluge/tests/test_transfer.py +++ b/deluge/tests/test_transfer.py @@ -8,8 +8,8 @@ import base64 +import pytest import rencode -from twisted.trial import unittest import deluge.log from deluge.transfer import DelugeTransferProtocol @@ -109,8 +109,9 @@ class TransferTestClass(DelugeTransferProtocol): self.message_received(request) -class DelugeTransferProtocolTestCase(unittest.TestCase): - def setUp(self): # NOQA: N803 +class TestDelugeTransferProtocol: + @pytest.fixture(autouse=True) + def set_up(self): """ The expected messages corresponds to the test messages (msg1, msg2) after they've been processed by DelugeTransferProtocol.send, which means that they've first been encoded with rencode, @@ -157,7 +158,7 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): # Get the data as sent by DelugeTransferProtocol messages = self.transfer.get_messages_out_joined() base64_encoded = base64.b64encode(messages) - self.assertEqual(base64_encoded, self.msg1_expected_compressed_base64) + assert base64_encoded == self.msg1_expected_compressed_base64 def test_receive_one_message(self): """ @@ -170,7 +171,7 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): ) # Get the data as sent by DelugeTransferProtocol messages = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(messages)) + assert rencode.dumps(self.msg1) == rencode.dumps(messages) def test_receive_old_message(self): """ @@ -178,9 +179,9 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): """ self.transfer.dataReceived(rencode.dumps(self.msg1)) - self.assertEqual(len(self.transfer.get_messages_in()), 0) - self.assertEqual(self.transfer._message_length, 0) - self.assertEqual(len(self.transfer._buffer), 0) + assert len(self.transfer.get_messages_in()) == 0 + assert self.transfer._message_length == 0 + assert len(self.transfer._buffer) == 0 def test_receive_two_concatenated_messages(self): """ @@ -195,9 +196,9 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): # Get the data as sent by DelugeTransferProtocol message1 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(message1)) + assert rencode.dumps(self.msg1) == rencode.dumps(message1) message2 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg2), rencode.dumps(message2)) + assert rencode.dumps(self.msg2) == rencode.dumps(message2) def test_receive_three_messages_in_parts(self): """ @@ -234,17 +235,15 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): else: expected_msgs_received_count = 0 # Verify that the expected number of complete messages has arrived - self.assertEqual( - expected_msgs_received_count, len(self.transfer.get_messages_in()) - ) + assert expected_msgs_received_count == len(self.transfer.get_messages_in()) # Get the data as received by DelugeTransferProtocol message1 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(message1)) + assert rencode.dumps(self.msg1) == rencode.dumps(message1) message2 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg2), rencode.dumps(message2)) + assert rencode.dumps(self.msg2) == rencode.dumps(message2) message3 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(message3)) + assert rencode.dumps(self.msg1) == rencode.dumps(message3) # Remove underscore to enable test, or run the test directly: # tests $ trial test_transfer.DelugeTransferProtocolTestCase._test_rencode_fail_protocol @@ -314,11 +313,11 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): # Get the data as received by DelugeTransferProtocol message1 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(message1)) + assert rencode.dumps(self.msg1) == rencode.dumps(message1) message2 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg2), rencode.dumps(message2)) + assert rencode.dumps(self.msg2) == rencode.dumps(message2) message3 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(message3)) + assert rencode.dumps(self.msg1) == rencode.dumps(message3) def test_receive_middle_of_header(self): """ @@ -341,19 +340,19 @@ class DelugeTransferProtocolTestCase(unittest.TestCase): self.transfer.dataReceived(two_concatenated[: first_len + 2]) # Should be 1 message in the list - self.assertEqual(1, len(self.transfer.get_messages_in())) + assert 1 == len(self.transfer.get_messages_in()) # Send the rest self.transfer.dataReceived(two_concatenated[first_len + 2 :]) # Should be 2 messages in the list - self.assertEqual(2, len(self.transfer.get_messages_in())) + assert 2 == len(self.transfer.get_messages_in()) # Get the data as sent by DelugeTransferProtocol message1 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg1), rencode.dumps(message1)) + assert rencode.dumps(self.msg1) == rencode.dumps(message1) message2 = self.transfer.get_messages_in().pop(0) - self.assertEqual(rencode.dumps(self.msg2), rencode.dumps(message2)) + assert rencode.dumps(self.msg2) == rencode.dumps(message2) # Needs file containing big data structure e.g. like thetorrent list as it is transfered by the daemon # def test_simulate_big_transfer(self): diff --git a/deluge/tests/test_ui_common.py b/deluge/tests/test_ui_common.py index 6625549e8..ee97259de 100644 --- a/deluge/tests/test_ui_common.py +++ b/deluge/tests/test_ui_common.py @@ -5,26 +5,19 @@ # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # -from twisted.trial import unittest from deluge.ui.common import TorrentInfo from . import common -class UICommonTestCase(unittest.TestCase): - def setUp(self): # NOQA: N803 - pass - - def tearDown(self): # NOQA: N803 - pass - +class TestUICommon: def test_hash_optional_single_file(self): """Ensure single file with `ed2k` and `sha1` keys are not in filetree output.""" filename = common.get_test_data_file('test.torrent') files_tree = {'azcvsupdater_2.6.2.jar': (0, 307949, True)} ti = TorrentInfo(filename, filetree=1) - self.assertEqual(ti.files_tree, files_tree) + assert ti.files_tree == files_tree files_tree2 = { 'contents': { @@ -37,7 +30,7 @@ class UICommonTestCase(unittest.TestCase): } } ti = TorrentInfo(filename, filetree=2) - self.assertEqual(ti.files_tree, files_tree2) + assert ti.files_tree == files_tree2 def test_hash_optional_multi_file(self): """Ensure multi-file with `filehash` and `ed2k` are keys not in filetree output.""" @@ -49,7 +42,7 @@ class UICommonTestCase(unittest.TestCase): } } ti = TorrentInfo(filename, filetree=1) - self.assertEqual(ti.files_tree, files_tree) + assert ti.files_tree == files_tree filestree2 = { 'contents': { @@ -78,14 +71,14 @@ class UICommonTestCase(unittest.TestCase): 'type': 'dir', } ti = TorrentInfo(filename, filetree=2) - self.assertEqual(ti.files_tree, filestree2) + assert ti.files_tree == filestree2 def test_hash_optional_md5sum(self): # Ensure `md5sum` key is not included in filetree output filename = common.get_test_data_file('md5sum.torrent') files_tree = {'test': {'lol': (0, 4, True), 'rofl': (1, 5, True)}} ti = TorrentInfo(filename, filetree=1) - self.assertEqual(ti.files_tree, files_tree) + assert ti.files_tree == files_tree ti = TorrentInfo(filename, filetree=2) files_tree2 = { 'contents': { @@ -113,12 +106,12 @@ class UICommonTestCase(unittest.TestCase): }, 'type': 'dir', } - self.assertEqual(ti.files_tree, files_tree2) + assert ti.files_tree == files_tree2 def test_utf8_encoded_paths(self): filename = common.get_test_data_file('test.torrent') ti = TorrentInfo(filename) - self.assertTrue('azcvsupdater_2.6.2.jar' in ti.files_tree) + assert 'azcvsupdater_2.6.2.jar' in ti.files_tree def test_utf8_encoded_paths2(self): filename = common.get_test_data_file('unicode_filenames.torrent') @@ -133,11 +126,11 @@ class UICommonTestCase(unittest.TestCase): ti = TorrentInfo(filename) files_tree = ti.files_tree['unicode_filenames'] - self.assertIn(filepath1, files_tree) - self.assertIn(filepath2, files_tree) - self.assertIn(filepath3, files_tree) - self.assertIn(filepath4, files_tree) - self.assertIn(filepath5, files_tree) + assert filepath1 in files_tree + assert filepath2 in files_tree + assert filepath3 in files_tree + assert filepath4 in files_tree + assert filepath5 in files_tree result_files = [ { @@ -163,4 +156,4 @@ class UICommonTestCase(unittest.TestCase): {'download': True, 'path': 'unicode_filenames/' + filepath1, 'size': 1771}, ] - self.assertCountEqual(ti.files, result_files) + assert len(ti.files) == len(result_files) diff --git a/deluge/tests/test_ui_console.py b/deluge/tests/test_ui_console.py index 201feee70..34398ee19 100644 --- a/deluge/tests/test_ui_console.py +++ b/deluge/tests/test_ui_console.py @@ -6,12 +6,12 @@ import argparse +import pytest + from deluge.ui.console.cmdline.commands.add import Command from deluge.ui.console.cmdline.commands.config import json_eval from deluge.ui.console.widgets.fields import TextInput -from .basetest import BaseTestCase - class MockParent: def __init__(self): @@ -20,13 +20,11 @@ class MockParent: self.encoding = 'utf8' -class UIConsoleFieldTestCase(BaseTestCase): - def setUp(self): # NOQA: N803 +class TestUIConsoleField: + @pytest.fixture(autouse=True) + def set_up(self): self.parent = MockParent() - def tearDown(self): # NOQA: N803 - pass - def test_text_input(self): def move_func(self, r, c): self._cursor_row = r @@ -41,48 +39,42 @@ class UIConsoleFieldTestCase(BaseTestCase): '/text/field/file/path', complete=False, ) - self.assertTrue(t) - self.assertTrue(t.handle_read(33)) + assert t + assert t.handle_read(33) -class UIConsoleCommandsTestCase(BaseTestCase): - def setUp(self): - pass - - def tearDown(self): - pass - +class TestUIConsoleCommands: def test_add_move_completed(self): completed_path = 'completed_path' parser = argparse.ArgumentParser() cmd = Command() cmd.add_arguments(parser) args = parser.parse_args(['torrent', '-m', completed_path]) - self.assertEqual(args.move_completed_path, completed_path) + assert args.move_completed_path == completed_path args = parser.parse_args(['torrent', '--move-path', completed_path]) - self.assertEqual(args.move_completed_path, completed_path) + assert args.move_completed_path == completed_path def test_config_json_eval(self): - self.assertEqual(json_eval('/downloads'), '/downloads') - self.assertEqual(json_eval('/dir/with space'), '/dir/with space') - self.assertEqual(json_eval('c:\\\\downloads'), 'c:\\\\downloads') - self.assertEqual(json_eval('c:/downloads'), 'c:/downloads') + assert json_eval('/downloads') == '/downloads' + assert json_eval('/dir/with space') == '/dir/with space' + assert json_eval('c:\\\\downloads') == 'c:\\\\downloads' + assert json_eval('c:/downloads') == 'c:/downloads' # Ensure newlines are split and only first setting is used. - self.assertEqual(json_eval('setting\nwithneline'), 'setting') + assert json_eval('setting\nwithneline') == 'setting' # Allow both parentheses and square brackets. - self.assertEqual(json_eval('(8000, 8001)'), [8000, 8001]) - self.assertEqual(json_eval('[8000, 8001]'), [8000, 8001]) - self.assertEqual(json_eval('["abc", "def"]'), ['abc', 'def']) - self.assertEqual(json_eval('{"foo": "bar"}'), {'foo': 'bar'}) - self.assertEqual(json_eval('{"number": 1234}'), {'number': 1234}) + assert json_eval('(8000, 8001)') == [8000, 8001] + assert json_eval('[8000, 8001]') == [8000, 8001] + assert json_eval('["abc", "def"]') == ['abc', 'def'] + assert json_eval('{"foo": "bar"}') == {'foo': 'bar'} + assert json_eval('{"number": 1234}') == {'number': 1234} # Hex string for peer_tos. - self.assertEqual(json_eval('0x00'), '0x00') - self.assertEqual(json_eval('1000'), 1000) - self.assertEqual(json_eval('-6'), -6) - self.assertEqual(json_eval('10.5'), 10.5) - self.assertEqual(json_eval('True'), True) - self.assertEqual(json_eval('false'), False) - self.assertEqual(json_eval('none'), None) + assert json_eval('0x00') == '0x00' + assert json_eval('1000') == 1000 + assert json_eval('-6') == -6 + assert json_eval('10.5') == 10.5 + assert json_eval('True') + assert not json_eval('false') + assert json_eval('none') is None # Empty values to clear config key. - self.assertEqual(json_eval('[]'), []) - self.assertEqual(json_eval(''), '') + assert json_eval('[]') == [] + assert json_eval('') == '' diff --git a/deluge/tests/test_ui_entry.py b/deluge/tests/test_ui_entry.py index c533a0af9..0546ad7b8 100644 --- a/deluge/tests/test_ui_entry.py +++ b/deluge/tests/test_ui_entry.py @@ -12,6 +12,7 @@ from io import StringIO from unittest import mock import pytest +import pytest_twisted from twisted.internet import defer import deluge @@ -21,11 +22,11 @@ import deluge.ui.console.cmdline.commands.quit import deluge.ui.console.main import deluge.ui.web.server from deluge.common import get_localhost_auth, windows_check +from deluge.conftest import BaseTestCase from deluge.ui import ui_entry from deluge.ui.web.server import DelugeWeb from . import common -from .basetest import BaseTestCase from .daemon_base import DaemonBase DEBUG_COMMAND = False @@ -56,11 +57,7 @@ class StringFileDescriptor: class UIBaseTestCase: - def __init__(self): - self.var = {} - def set_up(self): - common.set_tmp_config_dir() common.setup_test_logger(level='info', prefix=self.id()) return component.start() @@ -76,24 +73,14 @@ class UIBaseTestCase: class UIWithDaemonBaseTestCase(UIBaseTestCase, DaemonBase): """Subclass for test that require a deluged daemon""" - def __init__(self): - UIBaseTestCase.__init__(self) - def set_up(self): d = self.common_set_up() common.setup_test_logger(level='info', prefix=self.id()) - d.addCallback(self.start_core) - return d - - def tear_down(self): - d = UIBaseTestCase.tear_down(self) - d.addCallback(self.terminate_core) return d -class DelugeEntryTestCase(BaseTestCase): +class TestDelugeEntry(BaseTestCase): def set_up(self): - common.set_tmp_config_dir() return component.start() def tear_down(self): @@ -109,10 +96,11 @@ class DelugeEntryTestCase(BaseTestCase): self.patch(argparse._sys, 'stdout', fd) with mock.patch('deluge.ui.console.main.ConsoleUI'): - self.assertRaises(SystemExit, ui_entry.start_ui) - self.assertTrue('usage: deluge' in fd.out.getvalue()) - self.assertTrue('UI Options:' in fd.out.getvalue()) - self.assertTrue('* console' in fd.out.getvalue()) + with pytest.raises(SystemExit): + ui_entry.start_ui() + assert 'usage: deluge' in fd.out.getvalue() + assert 'UI Options:' in fd.out.getvalue() + assert '* console' in fd.out.getvalue() def test_start_default(self): self.patch(sys, 'argv', ['./deluge']) @@ -147,17 +135,12 @@ class DelugeEntryTestCase(BaseTestCase): # Just test that no exception is raised ui_entry.start_ui() - self.assertEqual(_level[0], 'info') + assert _level[0] == 'info' class GtkUIBaseTestCase(UIBaseTestCase): """Implement all GtkUI tests here""" - if windows_check(): - skip = ( - 'Gtk tests on Windows have some issue with the mutex already being created' - ) - def test_start_gtk3ui(self): self.patch(sys, 'argv', self.var['sys_arg_cmd']) @@ -168,38 +151,27 @@ class GtkUIBaseTestCase(UIBaseTestCase): @pytest.mark.gtkui -class GtkUIDelugeScriptEntryTestCase(BaseTestCase, GtkUIBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - GtkUIBaseTestCase.__init__(self) - - self.var['cmd_name'] = 'deluge gtk' - self.var['start_cmd'] = ui_entry.start_ui - self.var['sys_arg_cmd'] = ['./deluge', 'gtk'] - - def set_up(self): - return GtkUIBaseTestCase.set_up(self) - - def tear_down(self): - return GtkUIBaseTestCase.tear_down(self) +class TestGtkUIDelugeScriptEntry(BaseTestCase, GtkUIBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): + request.cls.var = { + 'cmd_name': 'deluge gtk', + 'start_cmd': ui_entry.start_ui, + 'sys_arg_cmd': ['./deluge', 'gtk'], + } @pytest.mark.gtkui -class GtkUIScriptEntryTestCase(BaseTestCase, GtkUIBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - GtkUIBaseTestCase.__init__(self) +class TestGtkUIScriptEntry(BaseTestCase, GtkUIBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): from deluge.ui import gtk3 - self.var['cmd_name'] = 'deluge-gtk' - self.var['start_cmd'] = gtk3.start - self.var['sys_arg_cmd'] = ['./deluge-gtk'] - - def set_up(self): - return GtkUIBaseTestCase.set_up(self) - - def tear_down(self): - return GtkUIBaseTestCase.tear_down(self) + request.cls.var = { + 'cmd_name': 'deluge-gtk', + 'start_cmd': gtk3.start, + 'sys_arg_cmd': ['./deluge-gtk'], + } class DelugeWebMock(DelugeWeb): @@ -237,41 +209,31 @@ class WebUIBaseTestCase(UIBaseTestCase): self.patch(deluge.ui.web.server, 'DelugeWeb', DelugeWebMock) self.exec_command() - self.assertEqual(_level[0], 'info') + assert _level[0] == 'info' -class WebUIScriptEntryTestCase(BaseTestCase, WebUIBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - WebUIBaseTestCase.__init__(self) - self.var['cmd_name'] = 'deluge-web' - self.var['start_cmd'] = deluge.ui.web.start - self.var['sys_arg_cmd'] = ['./deluge-web'] +class TestWebUIScriptEntry(BaseTestCase, WebUIBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): + request.cls.var = { + 'cmd_name': 'deluge-web', + 'start_cmd': deluge.ui.web.start, + 'sys_arg_cmd': ['./deluge-web'], + } if not windows_check(): - self.var['sys_arg_cmd'].append('--do-not-daemonize') - - def set_up(self): - return WebUIBaseTestCase.set_up(self) - - def tear_down(self): - return WebUIBaseTestCase.tear_down(self) + request.cls.var['sys_arg_cmd'].append('--do-not-daemonize') -class WebUIDelugeScriptEntryTestCase(BaseTestCase, WebUIBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - WebUIBaseTestCase.__init__(self) - self.var['cmd_name'] = 'deluge web' - self.var['start_cmd'] = ui_entry.start_ui - self.var['sys_arg_cmd'] = ['./deluge', 'web'] +class TestWebUIDelugeScriptEntry(BaseTestCase, WebUIBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): + request.cls.var = { + 'cmd_name': 'deluge web', + 'start_cmd': ui_entry.start_ui, + 'sys_arg_cmd': ['./deluge', 'web'], + } if not windows_check(): - self.var['sys_arg_cmd'].append('--do-not-daemonize') - - def set_up(self): - return WebUIBaseTestCase.set_up(self) - - def tear_down(self): - return WebUIBaseTestCase.tear_down(self) + request.cls.var['sys_arg_cmd'].append('--do-not-daemonize') class ConsoleUIBaseTestCase(UIBaseTestCase): @@ -282,7 +244,7 @@ class ConsoleUIBaseTestCase(UIBaseTestCase): with mock.patch('deluge.ui.console.main.ConsoleUI'): self.exec_command() - def test_start_console_with_log_level(self): + def test_start_console_with_log_level(self, request): _level = [] def setup_logger( @@ -305,7 +267,7 @@ class ConsoleUIBaseTestCase(UIBaseTestCase): # Just test that no exception is raised self.exec_command() - self.assertEqual(_level[0], 'info') + assert _level[0] == 'info' def test_console_help(self): self.patch(sys, 'argv', self.var['sys_arg_cmd'] + ['-h']) @@ -313,18 +275,19 @@ class ConsoleUIBaseTestCase(UIBaseTestCase): self.patch(argparse._sys, 'stdout', fd) with mock.patch('deluge.ui.console.main.ConsoleUI'): - self.assertRaises(SystemExit, self.exec_command) + with pytest.raises(SystemExit): + self.exec_command() std_output = fd.out.getvalue() - self.assertTrue( - ('usage: %s' % self.var['cmd_name']) in std_output - ) # Check command name - self.assertTrue('Common Options:' in std_output) - self.assertTrue('Console Options:' in std_output) - self.assertIn( - 'Console Commands:\n The following console commands are available:', - std_output, + assert ( + 'usage: %s' % self.var['cmd_name'] + ) in std_output # Check command name + assert 'Common Options:' in std_output + assert 'Console Options:' in std_output + assert ( + 'Console Commands:\n The following console commands are available:' + in std_output ) - self.assertIn('The following console commands are available:', std_output) + assert 'The following console commands are available:' in std_output def test_console_command_info(self): self.patch(sys, 'argv', self.var['sys_arg_cmd'] + ['info']) @@ -340,10 +303,11 @@ class ConsoleUIBaseTestCase(UIBaseTestCase): self.patch(argparse._sys, 'stdout', fd) with mock.patch('deluge.ui.console.main.ConsoleUI'): - self.assertRaises(SystemExit, self.exec_command) + with pytest.raises(SystemExit): + self.exec_command() std_output = fd.out.getvalue() - self.assertIn('usage: info', std_output) - self.assertIn('Show information about the torrents', std_output) + assert 'usage: info' in std_output + assert 'Show information about the torrents' in std_output def test_console_unrecognized_arguments(self): self.patch( @@ -352,8 +316,9 @@ class ConsoleUIBaseTestCase(UIBaseTestCase): fd = StringFileDescriptor(sys.stdout) self.patch(argparse._sys, 'stderr', fd) with mock.patch('deluge.ui.console.main.ConsoleUI'): - self.assertRaises(SystemExit, self.exec_command) - self.assertIn('unrecognized arguments: --ui', fd.out.getvalue()) + with pytest.raises(SystemExit): + self.exec_command() + assert 'unrecognized arguments: --ui' in fd.out.getvalue() class ConsoleUIWithDaemonBaseTestCase(UIWithDaemonBaseTestCase): @@ -381,7 +346,7 @@ class ConsoleUIWithDaemonBaseTestCase(UIWithDaemonBaseTestCase): + command, ) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_console_command_add(self): filename = common.get_test_data_file('test.torrent') self.patch_arg_command([f'add "{filename}"']) @@ -391,11 +356,12 @@ class ConsoleUIWithDaemonBaseTestCase(UIWithDaemonBaseTestCase): yield self.exec_command() std_output = fd.out.getvalue() - self.assertEqual( - std_output, 'Attempting to add torrent: ' + filename + '\nTorrent added!\n' + assert ( + std_output + == 'Attempting to add torrent: ' + filename + '\nTorrent added!\n' ) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_console_command_add_move_completed(self): filename = common.get_test_data_file('test.torrent') tmp_path = 'c:\\tmp' if windows_check() else '/tmp' @@ -414,26 +380,23 @@ class ConsoleUIWithDaemonBaseTestCase(UIWithDaemonBaseTestCase): yield self.exec_command() std_output = fd.out.getvalue() - self.assertTrue( - std_output.endswith( - f'move_completed: True\nmove_completed_path: {tmp_path}\n' - ) - or std_output.endswith( - f'move_completed_path: {tmp_path}\nmove_completed: True\n' - ) + assert std_output.endswith( + f'move_completed: True\nmove_completed_path: {tmp_path}\n' + ) or std_output.endswith( + f'move_completed_path: {tmp_path}\nmove_completed: True\n' ) - @defer.inlineCallbacks - def test_console_command_status(self): + @pytest_twisted.ensureDeferred + async def test_console_command_status(self): fd = StringFileDescriptor(sys.stdout) self.patch_arg_command(['status']) self.patch(sys, 'stdout', fd) - yield self.exec_command() + await self.exec_command() std_output = fd.out.getvalue() - self.assertTrue(std_output.startswith('Total upload: ')) - self.assertTrue(std_output.endswith(' Moving: 0\n')) + assert std_output.startswith('Total upload: ') + assert std_output.endswith(' Moving: 0\n') @defer.inlineCallbacks def test_console_command_config_set_download_location(self): @@ -443,63 +406,36 @@ class ConsoleUIWithDaemonBaseTestCase(UIWithDaemonBaseTestCase): yield self.exec_command() std_output = fd.out.getvalue() - self.assertTrue( - std_output.startswith('Setting "download_location" to: \'/downloads\'') - ) - self.assertTrue( - std_output.endswith('Configuration value successfully updated.\n') - ) + assert std_output.startswith('Setting "download_location" to: \'/downloads\'') + assert std_output.endswith('Configuration value successfully updated.\n') -class ConsoleScriptEntryWithDaemonTestCase( - BaseTestCase, ConsoleUIWithDaemonBaseTestCase -): - def __init__(self, testname): - super().__init__(testname) - ConsoleUIWithDaemonBaseTestCase.__init__(self) - self.var['cmd_name'] = 'deluge-console' - self.var['sys_arg_cmd'] = ['./deluge-console'] - - def set_up(self): - from deluge.ui.console.console import Console - - def start_console(): - return Console().start() - - self.patch(deluge.ui.console, 'start', start_console) - self.var['start_cmd'] = deluge.ui.console.start - - return ConsoleUIWithDaemonBaseTestCase.set_up(self) - - def tear_down(self): - return ConsoleUIWithDaemonBaseTestCase.tear_down(self) +@pytest.mark.usefixtures('daemon', 'client') +class TestConsoleScriptEntryWithDaemon(BaseTestCase, ConsoleUIWithDaemonBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): + request.cls.var = { + 'cmd_name': 'deluge-console', + 'start_cmd': deluge.ui.console.start, + 'sys_arg_cmd': ['./deluge-console'], + } -class ConsoleScriptEntryTestCase(BaseTestCase, ConsoleUIBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - ConsoleUIBaseTestCase.__init__(self) - self.var['cmd_name'] = 'deluge-console' - self.var['start_cmd'] = deluge.ui.console.start - self.var['sys_arg_cmd'] = ['./deluge-console'] - - def set_up(self): - return ConsoleUIBaseTestCase.set_up(self) - - def tear_down(self): - return ConsoleUIBaseTestCase.tear_down(self) +class TestConsoleScriptEntry(BaseTestCase, ConsoleUIBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): + request.cls.var = { + 'cmd_name': 'deluge-console', + 'start_cmd': deluge.ui.console.start, + 'sys_arg_cmd': ['./deluge-console'], + } -class ConsoleDelugeScriptEntryTestCase(BaseTestCase, ConsoleUIBaseTestCase): - def __init__(self, testname): - super().__init__(testname) - ConsoleUIBaseTestCase.__init__(self) - self.var['cmd_name'] = 'deluge console' - self.var['start_cmd'] = ui_entry.start_ui - self.var['sys_arg_cmd'] = ['./deluge', 'console'] - - def set_up(self): - return ConsoleUIBaseTestCase.set_up(self) - - def tear_down(self): - return ConsoleUIBaseTestCase.tear_down(self) +class TestConsoleDelugeScriptEntry(BaseTestCase, ConsoleUIBaseTestCase): + @pytest.fixture(autouse=True) + def set_var(self, request): + request.cls.var = { + 'cmd_name': 'deluge console', + 'start_cmd': ui_entry.start_ui, + 'sys_arg_cmd': ['./deluge', 'console'], + } diff --git a/deluge/tests/test_ui_gtk3.py b/deluge/tests/test_ui_gtk3.py index 707a3ef2d..e6d025c7c 100644 --- a/deluge/tests/test_ui_gtk3.py +++ b/deluge/tests/test_ui_gtk3.py @@ -8,11 +8,10 @@ import sys from unittest import mock import pytest -from twisted.trial import unittest @pytest.mark.gtkui -class GTK3CommonTestCase(unittest.TestCase): +class TestGTK3Common: def setUp(self): sys.modules['gi.repository'] = mock.MagicMock() @@ -22,10 +21,10 @@ class GTK3CommonTestCase(unittest.TestCase): def test_cmp(self): from deluge.ui.gtk3.common import cmp - self.assertEqual(cmp(None, None), 0) - self.assertEqual(cmp(1, None), 1) - self.assertEqual(cmp(0, None), 1) - self.assertEqual(cmp(None, 7), -1) - self.assertEqual(cmp(None, 'bar'), -1) - self.assertEqual(cmp('foo', None), 1) - self.assertEqual(cmp('', None), 1) + assert cmp(None, None) == 0 + assert cmp(1, None) == 1 + assert cmp(0, None) == 1 + assert cmp(None, 7) == -1 + assert cmp(None, 'bar') == -1 + assert cmp('foo', None) == 1 + assert cmp('', None) == 1 diff --git a/deluge/tests/test_web_api.py b/deluge/tests/test_web_api.py index 8bac165e7..56f86aa56 100644 --- a/deluge/tests/test_web_api.py +++ b/deluge/tests/test_web_api.py @@ -9,14 +9,14 @@ import json from io import BytesIO +import pytest +import pytest_twisted from twisted.internet import defer, reactor -from twisted.python.failure import Failure from twisted.web.client import Agent, FileBodyProducer from twisted.web.http_headers import Headers from twisted.web.static import File import deluge.component as component -from deluge.ui.client import client from . import common from .common_web import WebServerTestBase @@ -24,20 +24,19 @@ from .common_web import WebServerTestBase common.disable_new_release_check() -class WebAPITestCase(WebServerTestBase): - def test_connect_invalid_host(self): - d = self.deluge_web.web_api.connect('id') - d.addCallback(self.fail) - d.addErrback(self.assertIsInstance, Failure) - return d +class TestWebAPI(WebServerTestBase): + @pytest.mark.xfail(reason='This just logs an error at the moment.') + @pytest_twisted.ensureDeferred + async def test_connect_invalid_host(self): + with pytest.raises(Exception): + await self.deluge_web.web_api.connect('id') - def test_connect(self): + def test_connect(self, client): d = self.deluge_web.web_api.connect(self.host_id) def on_connect(result): - self.assertEqual(type(result), tuple) - self.assertTrue(len(result) > 0) - self.addCleanup(client.disconnect) + assert type(result) == tuple + assert len(result) > 0 return result d.addCallback(on_connect) @@ -49,9 +48,9 @@ class WebAPITestCase(WebServerTestBase): @defer.inlineCallbacks def on_connect(result): - self.assertTrue(self.deluge_web.web_api.connected()) + assert self.deluge_web.web_api.connected() yield self.deluge_web.web_api.disconnect() - self.assertFalse(self.deluge_web.web_api.connected()) + assert not self.deluge_web.web_api.connected() d.addCallback(on_connect) d.addErrback(self.fail) @@ -59,7 +58,7 @@ class WebAPITestCase(WebServerTestBase): def test_get_config(self): config = self.deluge_web.web_api.get_config() - self.assertEqual(self.webserver_listen_port, config['port']) + assert self.webserver_listen_port == config['port'] def test_set_config(self): config = self.deluge_web.web_api.get_config() @@ -74,9 +73,9 @@ class WebAPITestCase(WebServerTestBase): } self.deluge_web.web_api.set_config(config) web_config = component.get('DelugeWeb').config.config - self.assertNotEqual(config['pwd_salt'], web_config['pwd_salt']) - self.assertNotEqual(config['pwd_sha1'], web_config['pwd_sha1']) - self.assertNotEqual(config['sessions'], web_config['sessions']) + assert config['pwd_salt'] != web_config['pwd_salt'] + assert config['pwd_sha1'] != web_config['pwd_sha1'] + assert config['sessions'] != web_config['sessions'] @defer.inlineCallbacks def get_host_status(self): @@ -84,49 +83,49 @@ class WebAPITestCase(WebServerTestBase): host[3] = 'Online' host[4] = '2.0.0.dev562' status = yield self.deluge_web.web_api.get_host_status(self.host_id) - self.assertEqual(status, tuple(status)) + assert status == tuple(status) def test_get_host(self): - self.assertFalse(self.deluge_web.web_api._get_host('invalid_id')) + assert not self.deluge_web.web_api._get_host('invalid_id') conn = list(self.deluge_web.web_api.hostlist.get_hosts_info()[0]) - self.assertEqual(self.deluge_web.web_api._get_host(conn[0]), conn[0:4]) + assert self.deluge_web.web_api._get_host(conn[0]) == conn[0:4] def test_add_host(self): conn = ['abcdef', '10.0.0.1', 0, 'user123', 'pass123'] - self.assertFalse(self.deluge_web.web_api._get_host(conn[0])) + assert not self.deluge_web.web_api._get_host(conn[0]) # Add valid host result, host_id = self.deluge_web.web_api.add_host( conn[1], conn[2], conn[3], conn[4] ) - self.assertEqual(result, True) + assert result conn[0] = host_id - self.assertEqual(self.deluge_web.web_api._get_host(conn[0]), conn[0:4]) + assert self.deluge_web.web_api._get_host(conn[0]) == conn[0:4] # Add already existing host ret = self.deluge_web.web_api.add_host(conn[1], conn[2], conn[3], conn[4]) - self.assertEqual(ret, (False, 'Host details already in hostlist')) + assert ret == (False, 'Host details already in hostlist') # Add invalid port conn[2] = 'bad port' ret = self.deluge_web.web_api.add_host(conn[1], conn[2], conn[3], conn[4]) - self.assertEqual(ret, (False, 'Invalid port. Must be an integer')) + assert ret == (False, 'Invalid port. Must be an integer') def test_remove_host(self): conn = ['connection_id', '', 0, '', ''] self.deluge_web.web_api.hostlist.config['hosts'].append(conn) - self.assertEqual(self.deluge_web.web_api._get_host(conn[0]), conn[0:4]) + assert self.deluge_web.web_api._get_host(conn[0]) == conn[0:4] # Remove valid host - self.assertTrue(self.deluge_web.web_api.remove_host(conn[0])) - self.assertFalse(self.deluge_web.web_api._get_host(conn[0])) + assert self.deluge_web.web_api.remove_host(conn[0]) + assert not self.deluge_web.web_api._get_host(conn[0]) # Remove non-existing host - self.assertFalse(self.deluge_web.web_api.remove_host(conn[0])) + assert not self.deluge_web.web_api.remove_host(conn[0]) def test_get_torrent_info(self): filename = common.get_test_data_file('test.torrent') ret = self.deluge_web.web_api.get_torrent_info(filename) - self.assertEqual(ret['name'], 'azcvsupdater_2.6.2.jar') - self.assertEqual(ret['info_hash'], 'ab570cdd5a17ea1b61e970bb72047de141bce173') - self.assertTrue('files_tree' in ret) + assert ret['name'] == 'azcvsupdater_2.6.2.jar' + assert ret['info_hash'] == 'ab570cdd5a17ea1b61e970bb72047de141bce173' + assert 'files_tree' in ret def test_get_torrent_info_with_md5(self): filename = common.get_test_data_file('md5sum.torrent') @@ -134,19 +133,19 @@ class WebAPITestCase(WebServerTestBase): # JSON dumping happens during response creation in normal usage # JSON serialization may fail if any of the dictionary items are byte arrays rather than strings ret = json.loads(json.dumps(ret)) - self.assertEqual(ret['name'], 'test') - self.assertEqual(ret['info_hash'], 'f6408ba9944cf9fe01b547b28f336b3ee6ec32c5') - self.assertTrue('files_tree' in ret) + assert ret['name'] == 'test' + assert ret['info_hash'] == 'f6408ba9944cf9fe01b547b28f336b3ee6ec32c5' + assert 'files_tree' in ret def test_get_magnet_info(self): ret = self.deluge_web.web_api.get_magnet_info( 'magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN' ) - self.assertEqual(ret['name'], '953bad769164e8482c7785a21d12166f94b9e14d') - self.assertEqual(ret['info_hash'], '953bad769164e8482c7785a21d12166f94b9e14d') - self.assertTrue('files_tree' in ret) + assert ret['name'] == '953bad769164e8482c7785a21d12166f94b9e14d' + assert ret['info_hash'] == '953bad769164e8482c7785a21d12166f94b9e14d' + assert 'files_tree' in ret - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_get_torrent_files(self): yield self.deluge_web.web_api.connect(self.host_id) filename = common.get_test_data_file('test.torrent') @@ -157,23 +156,20 @@ class WebAPITestCase(WebServerTestBase): ret = yield self.deluge_web.web_api.get_torrent_files( 'ab570cdd5a17ea1b61e970bb72047de141bce173' ) - self.assertEqual(ret['type'], 'dir') - self.assertEqual( - ret['contents'], - { - 'azcvsupdater_2.6.2.jar': { - 'priority': 4, - 'index': 0, - 'offset': 0, - 'progress': 0.0, - 'path': 'azcvsupdater_2.6.2.jar', - 'type': 'file', - 'size': 307949, - } - }, - ) + assert ret['type'] == 'dir' + assert ret['contents'] == { + 'azcvsupdater_2.6.2.jar': { + 'priority': 4, + 'index': 0, + 'offset': 0, + 'progress': 0.0, + 'path': 'azcvsupdater_2.6.2.jar', + 'type': 'file', + 'size': 307949, + } + } - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_download_torrent_from_url(self): filename = 'ubuntu-9.04-desktop-i386.iso.torrent' self.deluge_web.top_level.putChild( @@ -181,9 +177,9 @@ class WebAPITestCase(WebServerTestBase): ) url = 'http://localhost:%d/%s' % (self.webserver_listen_port, filename) res = yield self.deluge_web.web_api.download_torrent_from_url(url) - self.assertTrue(res.endswith(filename)) + assert res.endswith(filename) - @defer.inlineCallbacks + @pytest_twisted.inlineCallbacks def test_invalid_json(self): """ If json_api._send_response does not return server.NOT_DONE_YET diff --git a/deluge/tests/test_web_auth.py b/deluge/tests/test_web_auth.py index 9ca906108..39d66c1c1 100644 --- a/deluge/tests/test_web_auth.py +++ b/deluge/tests/test_web_auth.py @@ -3,9 +3,8 @@ # the additional special exception to link portions of this program with the OpenSSL library. # See LICENSE for more details. # -from unittest.mock import patch -from twisted.trial import unittest +from unittest.mock import patch from deluge.ui.web import auth @@ -21,7 +20,7 @@ class MockConfig: self.config[key] = value -class WebAuthTestCase(unittest.TestCase): +class TestWebAuth: @patch('deluge.ui.web.auth.JSONComponent.__init__', return_value=None) def test_change_password(self, mock_json): config = MockConfig( @@ -31,4 +30,4 @@ class WebAuthTestCase(unittest.TestCase): } ) webauth = auth.Auth(config) - self.assertTrue(webauth.change_password('deluge', 'deluge_new')) + assert webauth.change_password('deluge', 'deluge_new') diff --git a/deluge/tests/test_webserver.py b/deluge/tests/test_webserver.py index 84bd07526..e1588fdf3 100644 --- a/deluge/tests/test_webserver.py +++ b/deluge/tests/test_webserver.py @@ -9,8 +9,9 @@ import json as json_lib from io import BytesIO +import pytest_twisted import twisted.web.client -from twisted.internet import defer, reactor +from twisted.internet import reactor from twisted.web.client import Agent, FileBodyProducer from twisted.web.http_headers import Headers @@ -21,8 +22,8 @@ from .common_web import WebServerMockBase, WebServerTestBase common.disable_new_release_check() -class WebServerTestCase(WebServerTestBase, WebServerMockBase): - @defer.inlineCallbacks +class TestWebServer(WebServerTestBase, WebServerMockBase): + @pytest_twisted.inlineCallbacks def test_get_torrent_info(self): agent = Agent(reactor) @@ -49,9 +50,11 @@ class WebServerTestCase(WebServerTestBase, WebServerMockBase): Headers(headers), FileBodyProducer(BytesIO(input_file.encode('utf-8'))), ) - body = yield twisted.web.client.readBody(d) - json = json_lib.loads(body.decode()) - self.assertEqual(None, json['error']) - self.assertEqual('torrent_filehash', json['result']['name']) + try: + json = json_lib.loads(body.decode()) + except Exception: + print('aoeu') + assert json['error'] is None + assert 'torrent_filehash' == json['result']['name'] diff --git a/deluge/tests/twisted/plugins/delugereporter.py b/deluge/tests/twisted/plugins/delugereporter.py deleted file mode 100644 index 7f07edba7..000000000 --- a/deluge/tests/twisted/plugins/delugereporter.py +++ /dev/null @@ -1,47 +0,0 @@ -#! /usr/bin/env python -# -# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with -# the additional special exception to link portions of this program with the OpenSSL library. -# See LICENSE for more details. -# - -import os - -from twisted.plugin import IPlugin -from twisted.trial.itrial import IReporter -from twisted.trial.reporter import TreeReporter -from zope.interface import implements - - -class _Reporter: - implements(IPlugin, IReporter) - - def __init__( - self, name, module, description, longOpt, shortOpt, klass # noqa: N803 - ): - self.name = name - self.module = module - self.description = description - self.longOpt = longOpt - self.shortOpt = shortOpt - self.klass = klass - - -deluge = _Reporter( - 'Deluge reporter that suppresses Stacktrace from TODO tests', - 'twisted.plugins.delugereporter', - description='Deluge Reporter', - longOpt='deluge-reporter', - shortOpt=None, - klass='DelugeReporter', -) - - -class DelugeReporter(TreeReporter): - def __init__(self, *args, **kwargs): - os.environ['DELUGE_REPORTER'] = 'true' - TreeReporter.__init__(self, *args, **kwargs) - - def addExpectedFailure(self, *args): # NOQA: N802 - # super(TreeReporter, self).addExpectedFailure(*args) - self.endLine('[TODO]', self.TODO) diff --git a/deluge/ui/client.py b/deluge/ui/client.py index fc3509cf4..6b657d5ca 100644 --- a/deluge/ui/client.py +++ b/deluge/ui/client.py @@ -612,7 +612,7 @@ class Client: d.addErrback(on_authenticate_fail) return d - d.addCallback(on_connected) + d.addCallbacks(on_connected) d.addErrback(on_connect_fail) if not skip_authentication: d.addCallback(authenticate, username, password) diff --git a/deluge/ui/console/__init__.py b/deluge/ui/console/__init__.py index 5152980fc..7da04a6de 100644 --- a/deluge/ui/console/__init__.py +++ b/deluge/ui/console/__init__.py @@ -13,4 +13,4 @@ UI_PATH = __path__[0] def start(): - Console().start() + return Console().start()