Beispiel #1
0
    def test_configure(self) -> None:
        plugins_v0.DictPlugin({
            "name": "plugin1",
            "config": {
                "add": {
                    "PARAM1": "value1",
                    "PARAM2": "value2"
                },
                "set": {
                    "PARAM3": "value3"
                },
                "defaults": {
                    "PARAM4": "value4"
                },
            },
        })
        plugins.load("plugin1")

        base = tutor_config.get_base()
        defaults = tutor_config.get_defaults()

        self.assertEqual(base["PARAM3"], "value3")
        self.assertEqual(base["PLUGIN1_PARAM1"], "value1")
        self.assertEqual(base["PLUGIN1_PARAM2"], "value2")
        self.assertEqual(defaults["PLUGIN1_PARAM4"], "value4")
Beispiel #2
0
 def test_enable_twice(self) -> None:
     plugins_v0.DictPlugin({"name": "plugin1"})
     plugins.load("plugin1")
     plugins.load("plugin1")
     config: Config = {tutor_config.PLUGINS_CONFIG_KEY: []}
     tutor_config.save_enabled_plugins(config)
     self.assertEqual(["plugin1"], config[tutor_config.PLUGINS_CONFIG_KEY])
Beispiel #3
0
    def test_renderer_is_reset_on_config_change(self) -> None:
        with tempfile.TemporaryDirectory() as plugin_templates:
            plugin1 = DictPlugin({
                "name": "plugin1",
                "version": "0",
                "templates": plugin_templates
            })

            # Create one template
            os.makedirs(os.path.join(plugin_templates, plugin1.name))
            with open(
                    os.path.join(plugin_templates, plugin1.name,
                                 "myplugin.txt"),
                    "w",
                    encoding="utf-8",
            ) as f:
                f.write("some content")

            # Load env once
            config: Config = {"PLUGINS": []}
            env1 = env.Renderer(config).environment

            # Enable plugins
            plugins.load("plugin1")

            # Load env a second time
            config["PLUGINS"] = ["myplugin"]
            env2 = env.Renderer(config).environment

            self.assertNotIn("plugin1/myplugin.txt",
                             env1.loader.list_templates())
            self.assertIn("plugin1/myplugin.txt", env2.loader.list_templates())
Beispiel #4
0
def upgrade_from_lilac(config: Config) -> None:
    if not plugins.is_installed("forum"):
        fmt.echo_alert(
            "The Open edX forum feature was moved to a separate plugin in Maple. To keep using this feature, "
            "you must install and enable the tutor-forum plugin: https://github.com/overhangio/tutor-forum"
        )
    elif not plugins.is_loaded("forum"):
        fmt.echo_info(
            "The Open edX forum feature was moved to a separate plugin in Maple. To keep using this feature, "
            "we will now enable the 'forum' plugin. If you do not want to use this feature, you should disable the "
            "plugin with: `tutor plugins disable forum`.")
        plugins.load("forum")
        tutor_config.save_enabled_plugins(config)

    if not plugins.is_installed("mfe"):
        fmt.echo_alert(
            "In Maple the legacy courseware is no longer supported. You need to install and enable the 'mfe' plugin "
            "to make use of the new learning microfrontend: https://github.com/overhangio/tutor-mfe"
        )
    elif not plugins.is_loaded("mfe"):
        fmt.echo_info(
            "In Maple the legacy courseware is no longer supported. To start using the new learning microfrontend, "
            "we will now enable the 'mfe' plugin. If you do not want to use this feature, you should disable the "
            "plugin with: `tutor plugins disable mfe`.")
        plugins.load("mfe")
        tutor_config.save_enabled_plugins(config)
Beispiel #5
0
    def test_config_disable_plugin(self) -> None:
        plugins_v0.DictPlugin({
            "name": "plugin1",
            "config": {
                "set": {
                    "KEY1": "value1"
                }
            }
        })
        plugins_v0.DictPlugin({
            "name": "plugin2",
            "config": {
                "set": {
                    "KEY2": "value2"
                }
            }
        })
        plugins.load("plugin1")
        plugins.load("plugin2")

        with temporary_root() as root:
            config = tutor_config.load_minimal(root)
            config_pre = config.copy()
            with patch.object(fmt, "STDOUT"):
                hooks.Actions.PLUGIN_UNLOADED.do("plugin1", "", config)
            config_post = tutor_config.load_minimal(root)

        self.assertEqual("value1", config_pre["KEY1"])
        self.assertEqual("value2", config_pre["KEY2"])
        self.assertNotIn("KEY1", config)
        self.assertNotIn("KEY1", config_post)
        self.assertEqual("value2", config["KEY2"])
Beispiel #6
0
 def test_patches(self) -> None:
     plugins_v0.DictPlugin({
         "name": "plugin1",
         "patches": {
             "patch1": "Hello {{ ID }}"
         }
     })
     plugins.load("plugin1")
     patches = list(plugins.iter_patches("patch1"))
     self.assertEqual(["Hello {{ ID }}"], patches)
Beispiel #7
0
def enable(context: Context, plugin_names: t.List[str]) -> None:
    config = tutor_config.load_minimal(context.root)
    for plugin in plugin_names:
        plugins.load(plugin)
        fmt.echo_info(f"Plugin {plugin} enabled")
    tutor_config.save_enabled_plugins(config)
    tutor_config.save_config_file(context.root, config)
    fmt.echo_info(
        "You should now re-generate your environment with `tutor config save`."
    )
Beispiel #8
0
 def test_init_tasks(self) -> None:
     plugins_v0.DictPlugin({
         "name": "plugin1",
         "hooks": {
             "init": ["myclient"]
         }
     })
     plugins.load("plugin1")
     self.assertIn(
         ("myclient", ("plugin1", "hooks", "myclient", "init")),
         list(hooks.Filters.COMMANDS_INIT.iterate()),
     )
Beispiel #9
0
 def test_configure_default_value_with_previous_definition(self) -> None:
     config: Config = {"PARAM1": "value"}
     plugins_v0.DictPlugin({
         "name": "plugin1",
         "config": {
             "defaults": {
                 "PARAM2": "{{ PARAM1 }}"
             }
         }
     })
     plugins.load("plugin1")
     tutor_config.update_with_defaults(config)
     self.assertEqual("{{ PARAM1 }}", config["PLUGIN1_PARAM2"])
Beispiel #10
0
    def test_configure_set_random_string(self) -> None:
        plugins_v0.DictPlugin({
            "name": "plugin1",
            "config": {
                "set": {
                    "PARAM1": "{{ 128|random_string }}"
                }
            },
        })
        plugins.load("plugin1")
        config = tutor_config.get_base()
        tutor_config.render_full(config)

        self.assertEqual(128, len(get_typed(config, "PARAM1", str)))
Beispiel #11
0
    def test_plugin_templates(self) -> None:
        with tempfile.TemporaryDirectory() as plugin_templates:
            DictPlugin({
                "name": "plugin1",
                "version": "0",
                "templates": plugin_templates
            })
            # Create two templates
            os.makedirs(os.path.join(plugin_templates, "plugin1", "apps"))
            with open(
                    os.path.join(plugin_templates, "plugin1",
                                 "unrendered.txt"),
                    "w",
                    encoding="utf-8",
            ) as f:
                f.write("This file should not be rendered")
            with open(
                    os.path.join(plugin_templates, "plugin1", "apps",
                                 "rendered.txt"),
                    "w",
                    encoding="utf-8",
            ) as f:
                f.write("Hello my ID is {{ ID }}")

            # Render templates
            with temporary_root() as root:
                # Create configuration
                config: Config = tutor_config.load_full(root)
                config["ID"] = "Hector Rumblethorpe"
                plugins.load("plugin1")
                tutor_config.save_enabled_plugins(config)

                # Render environment
                with patch.object(fmt, "STDOUT"):
                    env.save(root, config)

                # Check that plugin template was rendered
                root_env = os.path.join(root, "env")
                dst_unrendered = os.path.join(root_env, "plugins", "plugin1",
                                              "unrendered.txt")
                dst_rendered = os.path.join(root_env, "plugins", "plugin1",
                                            "apps", "rendered.txt")
                self.assertFalse(os.path.exists(dst_unrendered))
                self.assertTrue(os.path.exists(dst_rendered))
                with open(dst_rendered, encoding="utf-8") as f:
                    self.assertEqual("Hello my ID is Hector Rumblethorpe",
                                     f.read())
Beispiel #12
0
def upgrade_obsolete(config: Config) -> None:
    # Openedx-specific mysql passwords
    if "MYSQL_PASSWORD" in config:
        config["MYSQL_ROOT_PASSWORD"] = config["MYSQL_PASSWORD"]
        config["OPENEDX_MYSQL_PASSWORD"] = config["MYSQL_PASSWORD"]
        config.pop("MYSQL_PASSWORD")
    if "MYSQL_DATABASE" in config:
        config["OPENEDX_MYSQL_DATABASE"] = config.pop("MYSQL_DATABASE")
    if "MYSQL_USERNAME" in config:
        config["OPENEDX_MYSQL_USERNAME"] = config.pop("MYSQL_USERNAME")
    if "RUN_NOTES" in config:
        if config["RUN_NOTES"]:
            plugins.load("notes")
            save_enabled_plugins(config)
        config.pop("RUN_NOTES")
    if "RUN_XQUEUE" in config:
        if config["RUN_XQUEUE"]:
            plugins.load("xqueue")
            save_enabled_plugins(config)
        config.pop("RUN_XQUEUE")
    if "SECRET_KEY" in config:
        config["OPENEDX_SECRET_KEY"] = config.pop("SECRET_KEY")
    # Replace WEB_PROXY by RUN_CADDY
    if "WEB_PROXY" in config:
        config["RUN_CADDY"] = not config.pop("WEB_PROXY")
    # Rename ACTIVATE_HTTPS to ENABLE_HTTPS
    if "ACTIVATE_HTTPS" in config:
        config["ENABLE_HTTPS"] = config.pop("ACTIVATE_HTTPS")
    # Replace RUN_* variables by RUN_*
    for name in [
            "ACTIVATE_LMS",
            "ACTIVATE_CMS",
            "ACTIVATE_ELASTICSEARCH",
            "ACTIVATE_MONGODB",
            "ACTIVATE_MYSQL",
            "ACTIVATE_REDIS",
            "ACTIVATE_SMTP",
    ]:
        if name in config:
            config[name.replace("ACTIVATE_", "RUN_")] = config.pop(name)
    # Replace RUN_CADDY by ENABLE_WEB_PROXY
    if "RUN_CADDY" in config:
        config["ENABLE_WEB_PROXY"] = config.pop("RUN_CADDY")
    # Replace RUN_CADDY by ENABLE_WEB_PROXY
    if "NGINX_HTTP_PORT" in config:
        config["CADDY_HTTP_PORT"] = config.pop("NGINX_HTTP_PORT")
Beispiel #13
0
 def test_images_pull_plugin(self, image_pull: Mock) -> None:
     plugins.v0.DictPlugin(
         {
             "name": "plugin1",
             "hooks": {
                 "remote-image": {
                     "service1": "service1:1.0.0",
                     "service2": "service2:2.0.0",
                 }
             },
         }
     )
     plugins.load("plugin1")
     result = self.invoke(["images", "pull", "service1"])
     self.assertIsNone(result.exception)
     self.assertEqual(0, result.exit_code)
     image_pull.assert_called_once_with("service1:1.0.0")
Beispiel #14
0
 def test_images_printtag_plugin(self) -> None:
     plugins.v0.DictPlugin(
         {
             "name": "plugin1",
             "hooks": {
                 "build-image": {
                     "service1": "service1:1.0.0",
                     "service2": "service2:2.0.0",
                 }
             },
         }
     )
     plugins.load("plugin1")
     result = self.invoke(["images", "printtag", "service1"])
     self.assertIsNone(result.exception)
     self.assertEqual(0, result.exit_code, result)
     self.assertEqual(result.output, "service1:1.0.0\n")
Beispiel #15
0
    def test_configure_set_does_not_override(self) -> None:
        config: Config = {"ID1": "oldid"}

        plugins_v0.DictPlugin({
            "name": "plugin1",
            "config": {
                "set": {
                    "ID1": "newid",
                    "ID2": "id2"
                }
            }
        })
        plugins.load("plugin1")
        tutor_config.update_with_base(config)

        self.assertEqual("oldid", config["ID1"])
        self.assertEqual("id2", config["ID2"])
Beispiel #16
0
 def test_dict_plugin(self) -> None:
     plugin = plugins_v0.DictPlugin({
         "name": "myplugin",
         "config": {
             "set": {
                 "KEY": "value"
             }
         },
         "version": "0.1"
     })
     plugins.load("myplugin")
     overriden_items: t.List[t.Tuple[
         str, t.Any]] = hooks.Filters.CONFIG_OVERRIDES.apply([])
     versions = list(plugins.iter_info())
     self.assertEqual("myplugin", plugin.name)
     self.assertEqual([("myplugin", "0.1")], versions)
     self.assertEqual([("KEY", "value")], overriden_items)
Beispiel #17
0
    def test_config_load_from_plugins(self) -> None:
        config: Config = {}

        plugins_v0.DictPlugin({
            "name": "plugin1",
            "config": {
                "add": {
                    "PARAM1": "{{ 10|random_string }}"
                }
            }
        })
        plugins.load("plugin1")

        tutor_config.update_with_base(config)
        tutor_config.update_with_defaults(config)
        tutor_config.render_full(config)
        value1 = get_typed(config, "PLUGIN1_PARAM1", str)

        self.assertEqual(10, len(value1))
Beispiel #18
0
 def test_images_build_plugin(self, mock_image_build: Mock) -> None:
     plugins.v0.DictPlugin(
         {
             "name": "plugin1",
             "hooks": {
                 "build-image": {
                     "service1": "service1:1.0.0",
                     "service2": "service2:2.0.0",
                 }
             },
         }
     )
     plugins.load("plugin1")
     with temporary_root() as root:
         self.invoke_in_root(root, ["config", "save"])
         result = self.invoke_in_root(root, ["images", "build", "service1"])
     self.assertIsNone(result.exception)
     self.assertEqual(0, result.exit_code)
     mock_image_build.assert_called()
     self.assertIn("service1:1.0.0", mock_image_build.call_args[0])
Beispiel #19
0
 def test_images_build_plugin_with_args(self, image_build: Mock) -> None:
     plugins.v0.DictPlugin(
         {
             "name": "plugin1",
             "hooks": {
                 "build-image": {
                     "service1": "service1:1.0.0",
                     "service2": "service2:2.0.0",
                 }
             },
         }
     )
     plugins.load("plugin1")
     build_args = [
         "images",
         "build",
         "--no-cache",
         "-a",
         "myarg=value",
         "--add-host",
         "host",
         "--target",
         "target",
         "-d",
         "docker_args",
         "service1",
     ]
     with temporary_root() as root:
         self.invoke_in_root(root, ["config", "save"])
         result = self.invoke_in_root(root, build_args)
     self.assertIsNone(result.exception)
     self.assertEqual(0, result.exit_code)
     image_build.assert_called()
     self.assertIn("service1:1.0.0", image_build.call_args[0])
     for arg in image_build.call_args[0][2:]:
         # The only extra args are `--build-arg`
         if arg != "--build-arg":
             self.assertIn(arg, build_args)
Beispiel #20
0
 def test_plugin_without_patches(self) -> None:
     plugins_v0.DictPlugin({"name": "plugin1"})
     plugins.load("plugin1")
     patches = list(plugins.iter_patches("patch1"))
     self.assertEqual([], patches)