Skip to content

Commit

Permalink
PluginResourceManager: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Lord-Kamina committed Jul 17, 2024
1 parent 62584c1 commit 2d2546f
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 0 deletions.
71 changes: 71 additions & 0 deletions deluge/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,22 @@
import os
import sys
import traceback
from pathlib import Path
from unittest import mock

import pytest
import pytest_twisted
from twisted.internet import defer, protocol, reactor
from twisted.internet.defer import Deferred
from twisted.internet.error import CannotListenError

import deluge.component as component
import deluge.configmanager
import deluge.core.preferencesmanager
import deluge.log
from deluge.common import get_localhost_auth
from deluge.error import DelugeError
from deluge.pluginmanagerbase import PluginManagerBase
from deluge.ui.client import Client

# This sets log level to critical, so use log.critical() to debug while running unit tests
Expand All @@ -39,6 +43,14 @@ def get_test_data_file(filename):
return os.path.join(os.path.join(os.path.dirname(__file__), 'data'), filename)


def plugin_search_dir(self):
basedir = get_test_data_file('')
test_plugin_wheels = list(Path(basedir).glob('*.whl'))
plugin_dir = [basedir] + [str(i) for i in test_plugin_wheels]
print(f'plugin_search_dir(): plugin_dir is: {plugin_dir}')
return plugin_dir


def todo_test(caller):
# If we are using the delugereporter we can set todo mark on the test
# Without the delugereporter the todo would print a stack trace, so in
Expand Down Expand Up @@ -66,6 +78,65 @@ def callback(value):
return watchdog


@pytest.mark.usefixtures('config_dir')
@mock.patch.object(PluginManagerBase, 'get_plugin_dirs', new=plugin_search_dir, create=True)
class TestPluginManager(
deluge.pluginmanagerbase.PluginManagerBase, component.Component
):
"""For testing the PluginManager and PluginResourceManager."""

def __init__(self, core):
component.Component.__init__(self, 'TestPluginManager')

self.status_fields = {}

# Call the PluginManagerBase constructor
deluge.pluginmanagerbase.PluginManagerBase.__init__(
self, 'core.conf', 'deluge.plugin.core'
)

def start(self):
# Enable plugins that are enabled in the config
self.enable_plugins()

def stop(self):
# Disable all enabled plugins
self.disable_plugins()

def shutdown(self):
self.stop()

def update_plugins(self):
for plugin in self.plugins:
if hasattr(self.plugins[plugin], 'update'):
try:
self.plugins[plugin].update()
except Exception as ex:
deluge.log.critical(ex)

def enable_plugin(self, name):
d = defer.succeed(True)
if name not in self.plugins:
d = deluge.pluginmanagerbase.PluginManagerBase.enable_plugin(self, name)

def on_enable_plugin(result):
return result

d.addBoth(on_enable_plugin)
return d

def disable_plugin(self, name):
d = defer.succeed(True)
if name in self.plugins:
d = deluge.pluginmanagerbase.PluginManagerBase.disable_plugin(self, name)

def on_disable_plugin(result):
return result

d.addBoth(on_disable_plugin)
return d


class ReactorOverride:
"""Class used to patch reactor while running unit tests
to avoid starting and stopping the twisted reactor
Expand Down
8 changes: 8 additions & 0 deletions deluge/tests/test_plugin_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
# See LICENSE for more details.
#

from unittest import mock

from deluge.pluginmanagerbase import PluginManagerBase

from . import common

@mock.patch.object(PluginManagerBase, 'get_plugin_dirs', new=common.plugin_search_dir, create=True)
class TestPluginManagerBase:
def test_scan_for_plugins(self):
pm = PluginManagerBase('core.conf', 'deluge.plugin.core')
assert 'plugin_resources_test' in pm.available_plugins

def test_get_plugin_info(self):
pm = PluginManagerBase('core.conf', 'deluge.plugin.core')
for p in pm.get_available_plugins():
Expand Down
123 changes: 123 additions & 0 deletions deluge/tests/test_plugin_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#
# Copyright (C) 2024 Gregorio Litenstein <[email protected]>
#
# 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 unittest import mock

import deluge.component as component
from deluge.conftest import BaseTestCase
from deluge.core import pluginmanager
from deluge.core.core import Core
from deluge.core.rpcserver import RPCServer
from deluge.plugin_resource_manager import PluginResourceManager
from deluge.pluginmanagerbase import PluginManagerBase

from . import common

common.disable_new_release_check()


@mock.patch.object(pluginmanager, 'PluginManager', new=common.TestPluginManager, create=True)
class TestPluginResourceManager(BaseTestCase):
test_plugin_js = b'''/**
* Script: plugin_resources_test.js
* The client-side javascript code for the plugin_resources_test plugin.
*
* Copyright:
* (C) Gregorio Litenstein 2024 <[email protected]>
*
* This file is part of plugin_resources_test and is licensed under GNU GPL 3.0, or
* later, with the additional special exception to link portions of this
* program with the OpenSSL library. See LICENSE for more details.
*/
plugin_resources_testPlugin = Ext.extend(Deluge.Plugin, {
constructor: function(config) {
config = Ext.apply({
name: 'plugin_resources_test'
}, config);
plugin_resources_testPlugin.superclass.constructor.call(this, config);
},
onDisable: function() {
deluge.preferences.removePage(this.prefsPage);
},
onEnable: function() {
this.prefsPage = deluge.preferences.addPage(
new Deluge.ux.preferences.plugin_resources_testPage());
}
});
new plugin_resources_testPlugin();
'''

def set_up(self):
self.rpcserver = RPCServer(listen=False)
self.core: Core = Core()
self.core.config.config['lsd'] = False
self.core.config.config['enabled_plugins'] = []
self.listen_port = 51242
return component.start()

def tear_down(self):
def on_shutdown(result):
del self.rpcserver
del self.core

return component.shutdown().addCallback(on_shutdown)

async def test_resource_filename(self):
self.core.pluginmanager.scan_for_plugins()
await self.core.pluginmanager.enable_plugin('plugin_resources_test')
js_file_path = PluginResourceManager.resource_filename(
'deluge_plugin_resources_test', 'data/plugin_resources_test.js'
)
assert os.path.isfile(js_file_path)
with open(js_file_path, 'rb') as readfile:
contents = readfile.read()
assert contents == self.test_plugin_js

async def test_reuse_previously_extracted_file(self):
def get_js_file():
js_file = PluginResourceManager.resource_filename(
'deluge_plugin_resources_test', 'data/plugin_resources_test.js'
)
yield js_file

self.core.pluginmanager.scan_for_plugins()
await self.core.pluginmanager.enable_plugin('plugin_resources_test')
js_file_path = ''
for i in range(5):
del i
if not js_file_path:
js_file_path = next(get_js_file())
assert next(get_js_file()) == js_file_path and os.path.isfile(js_file_path)

async def test_update_path_if_file_deleted(self):
self.core.pluginmanager.scan_for_plugins()
await self.core.pluginmanager.enable_plugin('plugin_resources_test')
js_file_path = PluginResourceManager.resource_filename(
'deluge_plugin_resources_test', 'data/plugin_resources_test.js'
)
assert os.path.isfile(js_file_path)
os.remove(js_file_path)
assert not os.path.isfile(js_file_path)
js_file_path_new = PluginResourceManager.resource_filename(
'deluge_plugin_resources_test', 'data/plugin_resources_test.js'
)
assert js_file_path != js_file_path_new and os.path.isfile(js_file_path_new)

async def test_clean_files_on_disable_plugin(self):
self.core.pluginmanager.scan_for_plugins()
await self.core.pluginmanager.enable_plugin('plugin_resources_test')
js_file_path = PluginResourceManager.resource_filename(
'deluge_plugin_resources_test', 'data/plugin_resources_test.js'
)
assert os.path.isfile(js_file_path)
await self.core.pluginmanager.disable_plugin('plugin_resources_test')
assert not os.path.isfile(js_file_path)
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ per-file-ignores =
deluge/**/gtkui/*.py: E402
deluge/plugins/Stats/deluge_stats/graph.py: E402
deluge/plugin_resource_manager.py: N813
deluge/tests/test_plugin_resources.py: F401, E501
deluge/tests/test_plugin_metadata.py: E501
deluge/tests/common.py: E501
setup.py : E402
# loop variable shares name with imported function
deluge/common.py : F402
Expand Down

0 comments on commit 2d2546f

Please sign in to comment.