7
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-06-10 01:32:21 +00:00
tutor/tests/test_plugins.py
Régis Behmo ef189e7f67 fix: better logging during plugins disable
When disable a plugin that set config entried, such as the minio plugin, tutor was logging the following:

    Disabling plugin minio...
        Removed config entry OPENEDX_AWS_ACCESS_KEY=openedx
        Removed config entry OPENEDX_AWS_SECRET_ACCESS_KEY={{ MINIO_AWS_SECRET_ACCESS_KEY }}
        Plugin disabled

The config values were not rendered during printing, which is a shame, because
the whole point of this log line is to warn users of passwords/secrets that are
being removed. Here, we make sure that the config values are properly rendered.
The new logs are now:

    Disabling plugin minio...
        Removing config entry OPENEDX_AWS_ACCESS_KEY=openedx
        Removing config entry OPENEDX_AWS_SECRET_ACCESS_KEY=64vpCVLxhDxBuNjakSrX4CQg
        Plugin disabled
2021-06-22 12:28:58 +02:00

260 lines
8.9 KiB
Python

import unittest
from unittest.mock import Mock, patch
from tutor import config as tutor_config
from tutor import exceptions
from tutor import fmt
from tutor import plugins
from tutor.types import get_typed, Config
class PluginsTests(unittest.TestCase):
def setUp(self) -> None:
plugins.Plugins.clear()
@patch.object(plugins.DictPlugin, "iter_installed", return_value=[])
def test_iter_installed(self, _dict_plugin_iter_installed: Mock) -> None:
with patch.object(plugins.pkg_resources, "iter_entry_points", return_value=[]): # type: ignore
self.assertEqual([], list(plugins.iter_installed()))
def test_is_installed(self) -> None:
self.assertFalse(plugins.is_installed("dummy"))
@patch.object(plugins.DictPlugin, "iter_installed", return_value=[])
def test_official_plugins(self, _dict_plugin_iter_installed: Mock) -> None:
with patch.object(plugins.importlib, "import_module", return_value=42): # type: ignore
plugin1 = plugins.OfficialPlugin.load("plugin1")
with patch.object(plugins.importlib, "import_module", return_value=43): # type: ignore
plugin2 = plugins.OfficialPlugin.load("plugin2")
with patch.object(
plugins.EntrypointPlugin,
"iter_installed",
return_value=[plugin1],
):
self.assertEqual(
[plugin1, plugin2],
list(plugins.iter_installed()),
)
def test_enable(self) -> None:
config: Config = {plugins.CONFIG_KEY: []}
with patch.object(plugins, "is_installed", return_value=True):
plugins.enable(config, "plugin2")
plugins.enable(config, "plugin1")
self.assertEqual(["plugin1", "plugin2"], config[plugins.CONFIG_KEY])
def test_enable_twice(self) -> None:
config: Config = {plugins.CONFIG_KEY: []}
with patch.object(plugins, "is_installed", return_value=True):
plugins.enable(config, "plugin1")
plugins.enable(config, "plugin1")
self.assertEqual(["plugin1"], config[plugins.CONFIG_KEY])
def test_enable_not_installed_plugin(self) -> None:
config: Config = {"PLUGINS": []}
with patch.object(plugins, "is_installed", return_value=False):
self.assertRaises(exceptions.TutorError, plugins.enable, config, "plugin1")
@patch.object(
plugins.Plugins,
"iter_installed",
return_value=[
plugins.DictPlugin(
{
"name": "plugin1",
"version": "1.0.0",
"config": {"set": {"KEY": "value"}},
}
),
plugins.DictPlugin(
{
"name": "plugin2",
"version": "1.0.0",
}
),
],
)
def test_disable(self, _iter_installed_mock: Mock) -> None:
config: Config = {"PLUGINS": ["plugin1", "plugin2"]}
with patch.object(fmt, "STDOUT"):
plugin = plugins.get_enabled(config, "plugin1")
plugins.disable(config, plugin)
self.assertEqual(["plugin2"], config["PLUGINS"])
@patch.object(
plugins.Plugins,
"iter_installed",
return_value=[
plugins.DictPlugin(
{
"name": "plugin1",
"version": "1.0.0",
"config": {"set": {"KEY": "value"}},
}
),
],
)
def test_disable_removes_set_config(self, _iter_installed_mock: Mock) -> None:
config: Config = {"PLUGINS": ["plugin1"], "KEY": "value"}
plugin = plugins.get_enabled(config, "plugin1")
with patch.object(fmt, "STDOUT"):
plugins.disable(config, plugin)
self.assertEqual([], config["PLUGINS"])
self.assertNotIn("KEY", config)
def test_none_plugins(self) -> None:
config: Config = {plugins.CONFIG_KEY: None}
self.assertFalse(plugins.is_enabled(config, "myplugin"))
def test_patches(self) -> None:
class plugin1:
patches = {"patch1": "Hello {{ ID }}"}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
patches = list(plugins.iter_patches({}, "patch1"))
self.assertEqual([("plugin1", "Hello {{ ID }}")], patches)
def test_plugin_without_patches(self) -> None:
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", None)],
):
patches = list(plugins.iter_patches({}, "patch1"))
self.assertEqual([], patches)
def test_configure(self) -> None:
config: Config = {"ID": "id"}
defaults: Config = {}
class plugin1:
config: Config = {
"add": {"PARAM1": "value1", "PARAM2": "value2"},
"set": {"PARAM3": "value3"},
"defaults": {"PARAM4": "value4"},
}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
tutor_config.load_plugins(config, defaults)
self.assertEqual(
{
"ID": "id",
"PARAM3": "value3",
"PLUGIN1_PARAM1": "value1",
"PLUGIN1_PARAM2": "value2",
},
config,
)
self.assertEqual({"PLUGIN1_PARAM4": "value4"}, defaults)
def test_configure_set_does_not_override(self) -> None:
config: Config = {"ID": "oldid"}
class plugin1:
config: Config = {"set": {"ID": "newid"}}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
tutor_config.load_plugins(config, {})
self.assertEqual({"ID": "oldid"}, config)
def test_configure_set_random_string(self) -> None:
config: Config = {}
class plugin1:
config: Config = {"set": {"PARAM1": "{{ 128|random_string }}"}}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
tutor_config.load_plugins(config, {})
self.assertEqual(128, len(get_typed(config, "PARAM1", str)))
def test_configure_default_value_with_previous_definition(self) -> None:
config: Config = {}
defaults: Config = {"PARAM1": "value"}
class plugin1:
config: Config = {"defaults": {"PARAM2": "{{ PARAM1 }}"}}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
tutor_config.load_plugins(config, defaults)
self.assertEqual("{{ PARAM1 }}", defaults["PLUGIN1_PARAM2"])
def test_configure_add_twice(self) -> None:
config: Config = {}
class plugin1:
config: Config = {"add": {"PARAM1": "{{ 10|random_string }}"}}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
tutor_config.load_plugins(config, {})
value1 = get_typed(config, "PLUGIN1_PARAM1", str)
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
tutor_config.load_plugins(config, {})
value2 = get_typed(config, "PLUGIN1_PARAM1", str)
self.assertEqual(10, len(value1))
self.assertEqual(10, len(value2))
self.assertEqual(value1, value2)
def test_hooks(self) -> None:
class plugin1:
hooks = {"init": ["myclient"]}
with patch.object(
plugins.Plugins,
"iter_enabled",
return_value=[plugins.BasePlugin("plugin1", plugin1)],
):
self.assertEqual(
[("plugin1", ["myclient"])], list(plugins.iter_hooks({}, "init"))
)
def test_plugins_are_updated_on_config_change(self) -> None:
config: Config = {"PLUGINS": []}
plugins1 = plugins.Plugins(config)
self.assertEqual(0, len(list(plugins1.iter_enabled())))
config["PLUGINS"] = ["plugin1"]
with patch.object(
plugins.Plugins,
"iter_installed",
return_value=[plugins.BasePlugin("plugin1", None)],
):
plugins2 = plugins.Plugins(config)
self.assertEqual(1, len(list(plugins2.iter_enabled())))
def test_dict_plugin(self) -> None:
plugin = plugins.DictPlugin(
{"name": "myplugin", "config": {"set": {"KEY": "value"}}, "version": "0.1"}
)
self.assertEqual("myplugin", plugin.name)
self.assertEqual({"KEY": "value"}, plugin.config_set)