2019-07-02 20:16:44 +00:00
|
|
|
import os
|
2019-05-11 22:11:44 +00:00
|
|
|
import tempfile
|
2019-05-11 17:31:18 +00:00
|
|
|
import unittest
|
2021-11-23 08:25:09 +00:00
|
|
|
from unittest.mock import Mock, patch
|
2019-05-11 17:31:18 +00:00
|
|
|
|
2019-06-03 22:44:12 +00:00
|
|
|
from tutor import config as tutor_config
|
2021-11-23 08:25:09 +00:00
|
|
|
from tutor import env, exceptions, fmt
|
2021-04-06 10:09:00 +00:00
|
|
|
from tutor.types import Config
|
2019-05-11 17:31:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
class EnvTests(unittest.TestCase):
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_walk_templates(self) -> None:
|
2020-01-16 10:52:53 +00:00
|
|
|
renderer = env.Renderer({}, [env.TEMPLATES_ROOT])
|
|
|
|
templates = list(renderer.walk_templates("local"))
|
2019-05-11 17:31:18 +00:00
|
|
|
self.assertIn("local/docker-compose.yml", templates)
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_walk_templates_partials_are_ignored(self) -> None:
|
2020-01-16 10:52:53 +00:00
|
|
|
template_name = "apps/openedx/settings/partials/common_all.py"
|
2020-01-16 21:25:57 +00:00
|
|
|
renderer = env.Renderer({}, [env.TEMPLATES_ROOT], ignore_folders=["partials"])
|
2020-01-16 10:52:53 +00:00
|
|
|
templates = list(renderer.walk_templates("apps"))
|
2021-06-02 13:16:32 +00:00
|
|
|
self.assertIn(template_name, renderer.environment.loader.list_templates())
|
2020-01-16 10:52:53 +00:00
|
|
|
self.assertNotIn(template_name, templates)
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_is_binary_file(self) -> None:
|
2020-01-16 14:40:38 +00:00
|
|
|
self.assertTrue(env.is_binary_file("/home/somefile.ico"))
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_find_os_path(self) -> None:
|
2020-01-16 14:40:38 +00:00
|
|
|
renderer = env.Renderer({}, [env.TEMPLATES_ROOT])
|
2020-11-07 15:37:43 +00:00
|
|
|
path = renderer.find_os_path("local/docker-compose.yml")
|
2020-01-16 14:40:38 +00:00
|
|
|
self.assertTrue(os.path.exists(path))
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_pathjoin(self) -> None:
|
2021-11-23 08:25:09 +00:00
|
|
|
with tempfile.TemporaryDirectory() as root:
|
|
|
|
self.assertEqual(
|
|
|
|
os.path.join(root, "env", "dummy"), env.pathjoin(root, "dummy")
|
|
|
|
)
|
2019-05-11 17:31:18 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_render_str(self) -> None:
|
2019-05-11 17:31:18 +00:00
|
|
|
self.assertEqual(
|
|
|
|
"hello world", env.render_str({"name": "world"}, "hello {{ name }}")
|
|
|
|
)
|
|
|
|
|
2021-04-13 20:14:43 +00:00
|
|
|
def test_render_unknown(self) -> None:
|
|
|
|
config: Config = {
|
|
|
|
"var1": "a",
|
|
|
|
}
|
|
|
|
self.assertEqual("ab", env.render_unknown(config, "{{ var1 }}b"))
|
|
|
|
self.assertEqual({"x": "ac"}, env.render_unknown(config, {"x": "{{ var1 }}c"}))
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_common_domain(self) -> None:
|
2019-05-21 10:34:29 +00:00
|
|
|
self.assertEqual(
|
|
|
|
"mydomain.com",
|
|
|
|
env.render_str(
|
|
|
|
{"d1": "d1.mydomain.com", "d2": "d2.mydomain.com"},
|
|
|
|
"{{ d1|common_domain(d2) }}",
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_render_str_missing_configuration(self) -> None:
|
2019-05-11 17:31:18 +00:00
|
|
|
self.assertRaises(exceptions.TutorError, env.render_str, {}, "hello {{ name }}")
|
2019-05-11 22:11:44 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_render_file(self) -> None:
|
2021-04-06 10:09:00 +00:00
|
|
|
config: Config = {}
|
2021-11-08 13:46:38 +00:00
|
|
|
tutor_config.update_with_base(config)
|
|
|
|
tutor_config.update_with_defaults(config)
|
|
|
|
tutor_config.render_full(config)
|
|
|
|
|
2019-05-11 22:11:44 +00:00
|
|
|
config["MYSQL_ROOT_PASSWORD"] = "testpassword"
|
2019-09-03 08:36:10 +00:00
|
|
|
rendered = env.render_file(config, "hooks", "mysql", "init")
|
2019-05-11 22:11:44 +00:00
|
|
|
self.assertIn("testpassword", rendered)
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
@patch.object(tutor_config.fmt, "echo")
|
|
|
|
def test_render_file_missing_configuration(self, _: Mock) -> None:
|
2019-05-11 22:11:44 +00:00
|
|
|
self.assertRaises(
|
|
|
|
exceptions.TutorError, env.render_file, {}, "local", "docker-compose.yml"
|
|
|
|
)
|
2019-05-20 17:09:58 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_save_full(self) -> None:
|
2019-05-21 10:34:29 +00:00
|
|
|
with tempfile.TemporaryDirectory() as root:
|
2021-11-08 13:46:38 +00:00
|
|
|
config = tutor_config.load_full(root)
|
2021-02-25 08:09:14 +00:00
|
|
|
with patch.object(fmt, "STDOUT"):
|
2019-12-24 16:22:12 +00:00
|
|
|
env.save(root, config)
|
2019-07-02 20:16:44 +00:00
|
|
|
self.assertTrue(
|
|
|
|
os.path.exists(os.path.join(root, "env", "local", "docker-compose.yml"))
|
|
|
|
)
|
2019-05-21 10:34:29 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_save_full_with_https(self) -> None:
|
2019-05-20 17:09:58 +00:00
|
|
|
with tempfile.TemporaryDirectory() as root:
|
2021-11-08 13:46:38 +00:00
|
|
|
config = tutor_config.load_full(root)
|
2020-09-17 10:53:14 +00:00
|
|
|
config["ENABLE_HTTPS"] = True
|
2021-02-25 08:09:14 +00:00
|
|
|
with patch.object(fmt, "STDOUT"):
|
2019-12-24 16:22:12 +00:00
|
|
|
env.save(root, config)
|
2020-09-17 10:53:14 +00:00
|
|
|
with open(os.path.join(root, "env", "apps", "caddy", "Caddyfile")) as f:
|
2021-11-09 10:42:39 +00:00
|
|
|
self.assertIn("www.myopenedx.com{$default_site_port}", f.read())
|
2019-05-29 09:14:06 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_patch(self) -> None:
|
2019-05-29 09:14:06 +00:00
|
|
|
patches = {"plugin1": "abcd", "plugin2": "efgh"}
|
2021-02-25 08:09:14 +00:00
|
|
|
with patch.object(
|
2019-05-29 09:14:06 +00:00
|
|
|
env.plugins, "iter_patches", return_value=patches.items()
|
|
|
|
) as mock_iter_patches:
|
|
|
|
rendered = env.render_str({}, '{{ patch("location") }}')
|
|
|
|
mock_iter_patches.assert_called_once_with({}, "location")
|
|
|
|
self.assertEqual("abcd\nefgh", rendered)
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_patch_separator_suffix(self) -> None:
|
2019-05-29 09:14:06 +00:00
|
|
|
patches = {"plugin1": "abcd", "plugin2": "efgh"}
|
2021-02-25 08:09:14 +00:00
|
|
|
with patch.object(env.plugins, "iter_patches", return_value=patches.items()):
|
2019-05-29 09:14:06 +00:00
|
|
|
rendered = env.render_str(
|
|
|
|
{}, '{{ patch("location", separator=",\n", suffix=",") }}'
|
|
|
|
)
|
|
|
|
self.assertEqual("abcd,\nefgh,", rendered)
|
2019-07-02 20:16:44 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_plugin_templates(self) -> None:
|
2019-07-02 20:16:44 +00:00
|
|
|
with tempfile.TemporaryDirectory() as plugin_templates:
|
2020-01-16 10:52:53 +00:00
|
|
|
# Create plugin
|
|
|
|
plugin1 = env.plugins.DictPlugin(
|
|
|
|
{"name": "plugin1", "version": "0", "templates": plugin_templates}
|
|
|
|
)
|
|
|
|
|
2019-07-02 20:16:44 +00:00
|
|
|
# Create two templates
|
|
|
|
os.makedirs(os.path.join(plugin_templates, "plugin1", "apps"))
|
|
|
|
with open(
|
|
|
|
os.path.join(plugin_templates, "plugin1", "unrendered.txt"), "w"
|
|
|
|
) as f:
|
|
|
|
f.write("This file should not be rendered")
|
|
|
|
with open(
|
|
|
|
os.path.join(plugin_templates, "plugin1", "apps", "rendered.txt"), "w"
|
|
|
|
) as f:
|
|
|
|
f.write("Hello my ID is {{ ID }}")
|
|
|
|
|
|
|
|
# Create configuration
|
2021-04-06 10:09:00 +00:00
|
|
|
config: Config = {"ID": "abcd"}
|
2019-07-02 20:16:44 +00:00
|
|
|
|
2020-01-16 10:52:53 +00:00
|
|
|
# Render templates
|
2021-02-25 08:09:14 +00:00
|
|
|
with patch.object(
|
2020-10-15 15:33:28 +00:00
|
|
|
env.plugins,
|
|
|
|
"iter_enabled",
|
|
|
|
return_value=[plugin1],
|
2019-07-02 20:16:44 +00:00
|
|
|
):
|
|
|
|
with tempfile.TemporaryDirectory() as root:
|
|
|
|
# Render plugin templates
|
2020-01-16 10:52:53 +00:00
|
|
|
env.save_plugin_templates(plugin1, root, config)
|
2019-07-02 20:16:44 +00:00
|
|
|
|
|
|
|
# Check that plugin template was rendered
|
|
|
|
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) as f:
|
|
|
|
self.assertEqual("Hello my ID is abcd", f.read())
|
2019-07-10 08:20:43 +00:00
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
def test_renderer_is_reset_on_config_change(self) -> None:
|
2019-08-20 15:46:53 +00:00
|
|
|
with tempfile.TemporaryDirectory() as plugin_templates:
|
2020-01-16 10:52:53 +00:00
|
|
|
plugin1 = env.plugins.DictPlugin(
|
|
|
|
{"name": "plugin1", "version": "0", "templates": plugin_templates}
|
|
|
|
)
|
2019-08-20 15:46:53 +00:00
|
|
|
# Create one template
|
2020-01-16 10:52:53 +00:00
|
|
|
os.makedirs(os.path.join(plugin_templates, plugin1.name))
|
|
|
|
with open(
|
|
|
|
os.path.join(plugin_templates, plugin1.name, "myplugin.txt"), "w"
|
|
|
|
) as f:
|
2019-08-20 15:46:53 +00:00
|
|
|
f.write("some content")
|
|
|
|
|
2020-01-16 10:52:53 +00:00
|
|
|
# Load env once
|
2021-04-06 10:09:00 +00:00
|
|
|
config: Config = {"PLUGINS": []}
|
2020-01-16 10:52:53 +00:00
|
|
|
env1 = env.Renderer.instance(config).environment
|
|
|
|
|
2021-02-25 08:09:14 +00:00
|
|
|
with patch.object(
|
2020-10-15 15:33:28 +00:00
|
|
|
env.plugins,
|
|
|
|
"iter_enabled",
|
|
|
|
return_value=[plugin1],
|
2020-01-16 10:52:53 +00:00
|
|
|
):
|
|
|
|
# Load env a second time
|
2021-04-06 10:09:00 +00:00
|
|
|
config["PLUGINS"] = ["myplugin"]
|
2020-01-16 10:52:53 +00:00
|
|
|
env2 = env.Renderer.instance(config).environment
|
|
|
|
|
2021-06-02 13:16:32 +00:00
|
|
|
self.assertNotIn("plugin1/myplugin.txt", env1.loader.list_templates())
|
|
|
|
self.assertIn("plugin1/myplugin.txt", env2.loader.list_templates())
|
2021-04-13 20:14:43 +00:00
|
|
|
|
|
|
|
def test_iter_values_named(self) -> None:
|
|
|
|
config: Config = {
|
|
|
|
"something0_test_app": 0,
|
|
|
|
"something1_test_not_app": 1,
|
|
|
|
"notsomething_test_app": 2,
|
|
|
|
"something3_test_app": 3,
|
|
|
|
}
|
|
|
|
renderer = env.Renderer.instance(config)
|
|
|
|
self.assertEqual([2, 3], list(renderer.iter_values_named(suffix="test_app")))
|
|
|
|
self.assertEqual([1, 3], list(renderer.iter_values_named(prefix="something")))
|
|
|
|
self.assertEqual(
|
|
|
|
[0, 3],
|
|
|
|
list(
|
|
|
|
renderer.iter_values_named(
|
|
|
|
prefix="something", suffix="test_app", allow_empty=True
|
|
|
|
)
|
|
|
|
),
|
|
|
|
)
|