6
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-11-19 19:45:25 +00:00
tutor/tests/test_env.py

252 lines
9.8 KiB
Python
Raw Normal View History

import os
import tempfile
import unittest
from unittest.mock import Mock, patch
2022-01-08 11:19:46 +00:00
from tutor.__about__ import __version__
from tutor import config as tutor_config
from tutor import env, exceptions, fmt
from tutor.types import Config
2022-01-08 11:19:46 +00:00
from tests.helpers import temporary_root
class EnvTests(unittest.TestCase):
def test_walk_templates(self) -> None:
renderer = env.Renderer({}, [env.TEMPLATES_ROOT])
templates = list(renderer.walk_templates("local"))
self.assertIn("local/docker-compose.yml", templates)
def test_walk_templates_partials_are_ignored(self) -> None:
template_name = "apps/openedx/settings/partials/common_all.py"
renderer = env.Renderer({}, [env.TEMPLATES_ROOT], ignore_folders=["partials"])
templates = list(renderer.walk_templates("apps"))
self.assertIn(template_name, renderer.environment.loader.list_templates())
self.assertNotIn(template_name, templates)
def test_is_binary_file(self) -> None:
self.assertTrue(env.is_binary_file("/home/somefile.ico"))
def test_find_os_path(self) -> None:
renderer = env.Renderer({}, [env.TEMPLATES_ROOT])
path = renderer.find_os_path("local/docker-compose.yml")
self.assertTrue(os.path.exists(path))
def test_pathjoin(self) -> None:
2022-01-08 11:19:46 +00:00
with temporary_root() as root:
self.assertEqual(
2022-01-08 11:19:46 +00:00
os.path.join(env.base_dir(root), "dummy"), env.pathjoin(root, "dummy")
)
def test_render_str(self) -> None:
self.assertEqual(
"hello world", env.render_str({"name": "world"}, "hello {{ name }}")
)
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"}))
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) }}",
),
)
def test_render_str_missing_configuration(self) -> None:
self.assertRaises(exceptions.TutorError, env.render_str, {}, "hello {{ name }}")
def test_render_file(self) -> None:
config: Config = {}
tutor_config.update_with_base(config)
tutor_config.update_with_defaults(config)
tutor_config.render_full(config)
config["MYSQL_ROOT_PASSWORD"] = "testpassword"
rendered = env.render_file(config, "hooks", "mysql", "init")
self.assertIn("testpassword", rendered)
@patch.object(tutor_config.fmt, "echo")
def test_render_file_missing_configuration(self, _: Mock) -> None:
self.assertRaises(
exceptions.TutorError, env.render_file, {}, "local", "docker-compose.yml"
)
def test_save_full(self) -> None:
2022-01-08 11:19:46 +00:00
with temporary_root() as root:
config = tutor_config.load_full(root)
with patch.object(fmt, "STDOUT"):
env.save(root, config)
self.assertTrue(
2022-01-08 11:19:46 +00:00
os.path.exists(
os.path.join(env.base_dir(root), "local", "docker-compose.yml")
)
)
2019-05-21 10:34:29 +00:00
def test_save_full_with_https(self) -> None:
2022-01-08 11:19:46 +00:00
with temporary_root() as root:
config = tutor_config.load_full(root)
v11.0.0 (2020-12-09) - 💥[Improvement] Upgrade Open edX to Koa - 💥 Setting changes: - The ``ACTIVATE_HTTPS`` setting was renamed to ``ENABLE_HTTPS``. - Other ``ACTIVATE_*`` variables were all renamed to ``RUN_*``. - The ``WEB_PROXY`` setting was removed and ``RUN_CADDY`` was added. - The ``NGINX_HTTPS_PORT`` setting is deprecated. - Architectural changes: - Use Caddy as a web proxy for automated SSL/TLS certificate generation: - Nginx no longer listens to port 443 for https traffic - The Caddy configuration file comes with a new ``caddyfile`` patch for much simpler SSL/TLS management. - Configuration files for web proxies are no longer provided. - Kubernetes deployment no longer requires setting up a custom Ingress resource or custom manager. - Gunicorn and Whitenoise are replaced by uwsgi: this increases boostrap performance and makes it no longer necessary to mount media folders in the Nginx container. - Replace memcached and rabbitmq by redis. - Additional features: - Make it possible to disable all plugins at once with ``plugins disable all``. - Add ``tutor k8s wait`` command to wait for a pod to become ready - Faster, more reliable static assets with local memory caching - Deprecation: proxy files for Apache and Nginx are no longer provided out of the box. - Removed plugin `{{ patch (...) }}` statements: - "https-create", "k8s-ingress-rules", "k8s-ingress-tls-hosts": these are no longer necessary. Instead, declare your app in the "caddyfile" patch. - "local-docker-compose-nginx-volumes": this patch was primarily used to serve media assets. The recommended is now to serve assets with uwsgi.
2020-09-17 10:53:14 +00:00
config["ENABLE_HTTPS"] = True
with patch.object(fmt, "STDOUT"):
env.save(root, config)
2022-01-08 11:19:46 +00:00
with open(
os.path.join(env.base_dir(root), "apps", "caddy", "Caddyfile"),
encoding="utf-8",
) as f:
2021-11-09 10:42:39 +00:00
self.assertIn("www.myopenedx.com{$default_site_port}", f.read())
def test_patch(self) -> None:
patches = {"plugin1": "abcd", "plugin2": "efgh"}
with patch.object(
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)
def test_patch_separator_suffix(self) -> None:
patches = {"plugin1": "abcd", "plugin2": "efgh"}
with patch.object(env.plugins, "iter_patches", return_value=patches.items()):
rendered = env.render_str(
{}, '{{ patch("location", separator=",\n", suffix=",") }}'
)
self.assertEqual("abcd,\nefgh,", rendered)
def test_plugin_templates(self) -> None:
with tempfile.TemporaryDirectory() as plugin_templates:
# Create plugin
plugin1 = env.plugins.DictPlugin(
{"name": "plugin1", "version": "0", "templates": plugin_templates}
)
# Create two templates
os.makedirs(os.path.join(plugin_templates, "plugin1", "apps"))
with open(
2022-01-08 11:19:46 +00:00
os.path.join(plugin_templates, "plugin1", "unrendered.txt"),
"w",
encoding="utf-8",
) as f:
f.write("This file should not be rendered")
with open(
2022-01-08 11:19:46 +00:00
os.path.join(plugin_templates, "plugin1", "apps", "rendered.txt"),
"w",
encoding="utf-8",
) as f:
f.write("Hello my ID is {{ ID }}")
# Create configuration
config: Config = {"ID": "abcd"}
# Render templates
with patch.object(
env.plugins,
"iter_enabled",
return_value=[plugin1],
):
2022-01-08 11:19:46 +00:00
with temporary_root() as root:
# Render plugin templates
env.save_plugin_templates(plugin1, root, config)
# 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))
2022-01-08 11:19:46 +00:00
with open(dst_rendered, encoding="utf-8") as f:
self.assertEqual("Hello my ID is abcd", f.read())
2019-07-10 08:20:43 +00:00
def test_renderer_is_reset_on_config_change(self) -> None:
with tempfile.TemporaryDirectory() as plugin_templates:
plugin1 = env.plugins.DictPlugin(
{"name": "plugin1", "version": "0", "templates": plugin_templates}
)
# Create one template
os.makedirs(os.path.join(plugin_templates, plugin1.name))
with open(
2022-01-08 11:19:46 +00:00
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.instance(config).environment
with patch.object(
env.plugins,
"iter_enabled",
return_value=[plugin1],
):
# Load env a second time
config["PLUGINS"] = ["myplugin"]
env2 = env.Renderer.instance(config).environment
self.assertNotIn("plugin1/myplugin.txt", env1.loader.list_templates())
self.assertIn("plugin1/myplugin.txt", env2.loader.list_templates())
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
)
),
)
2022-01-08 11:19:46 +00:00
class CurrentVersionTests(unittest.TestCase):
2022-01-08 11:19:46 +00:00
def test_current_version_in_empty_env(self) -> None:
with temporary_root() as root:
self.assertIsNone(env.current_version(root))
self.assertIsNone(env.get_env_release(root))
self.assertIsNone(env.should_upgrade_from_release(root))
2022-01-08 11:19:46 +00:00
self.assertTrue(env.is_up_to_date(root))
def test_current_version_in_lilac_env(self) -> None:
with temporary_root() as root:
os.makedirs(env.base_dir(root))
with open(
os.path.join(env.base_dir(root), env.VERSION_FILENAME),
"w",
encoding="utf-8",
) as f:
f.write("12.0.46")
self.assertEqual("12.0.46", env.current_version(root))
self.assertEqual("lilac", env.get_env_release(root))
self.assertEqual("lilac", env.should_upgrade_from_release(root))
2022-01-08 11:19:46 +00:00
self.assertFalse(env.is_up_to_date(root))
def test_current_version_in_latest_env(self) -> None:
with temporary_root() as root:
os.makedirs(env.base_dir(root))
with open(
os.path.join(env.base_dir(root), env.VERSION_FILENAME),
"w",
encoding="utf-8",
) as f:
f.write(__version__)
self.assertEqual(__version__, env.current_version(root))
self.assertEqual("maple", env.get_env_release(root))
self.assertIsNone(env.should_upgrade_from_release(root))
2022-01-08 11:19:46 +00:00
self.assertTrue(env.is_up_to_date(root))