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"])
def test_update_twice_should_return_same_config(self, _: Mock) -> None: with temporary_root() as root: config1 = tutor_config.load_minimal(root) tutor_config.save_config_file(root, config1) config2 = tutor_config.load_minimal(root) self.assertEqual(config1, config2)
def test_config_printvalue(self) -> None: with temporary_root() as root: self.invoke_in_root(root, ["config", "save"]) result = self.invoke_in_root( root, ["config", "printvalue", "MYSQL_ROOT_PASSWORD"]) self.assertFalse(result.exception) self.assertEqual(0, result.exit_code) self.assertTrue(result.output)
def test_config_render(self) -> None: with tempfile.TemporaryDirectory() as dest: with temporary_root() as root: self.invoke_in_root(root, ["config", "save"]) result = self.invoke_in_root(root, ["config", "render", root, dest]) self.assertEqual(0, result.exit_code) self.assertFalse(result.exception)
def test_save_full(self) -> None: with temporary_root() as root: config = tutor_config.load_full(root) with patch.object(fmt, "STDOUT"): env.save(root, config) self.assertTrue( os.path.exists( os.path.join(env.base_dir(root), "local", "docker-compose.yml")))
def test_config_save_unset_value(self) -> None: with temporary_root() as root: result1 = self.invoke_in_root(root, ["config", "save", "-U", "key"]) result2 = self.invoke_in_root(root, ["config", "printvalue", "key"]) self.assertFalse(result1.exception) self.assertEqual(0, result1.exit_code) self.assertEqual(1, result2.exit_code)
def test_initialise(self, mock_stdout: StringIO) -> None: with temporary_root() as root: context = TestContext(root) config = tutor_config.load_full(root) runner = context.job_runner(config) jobs.initialise(runner) output = mock_stdout.getvalue().strip() self.assertTrue(output.startswith("Initialising all services...")) self.assertTrue(output.endswith("All services initialised."))
def test_create_testcontext(self) -> None: with temporary_root() as root: context = TestContext(root) config = tutor_config.load_full(root) runner = context.job_runner(config) self.assertTrue(os.path.exists(context.root)) self.assertFalse( os.path.exists(os.path.join(context.root, tutor_config.CONFIG_FILENAME)) ) self.assertTrue(isinstance(runner, TestJobRunner))
def test_save_full_with_https(self) -> None: with temporary_root() as root: config = tutor_config.load_full(root) config["ENABLE_HTTPS"] = True with patch.object(fmt, "STDOUT"): env.save(root, config) with open( os.path.join(env.base_dir(root), "apps", "caddy", "Caddyfile"), encoding="utf-8", ) as f: self.assertIn("www.myopenedx.com{$default_site_port}", f.read())
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("nutmeg", env.get_env_release(root)) self.assertIsNone(env.should_upgrade_from_release(root)) self.assertTrue(env.is_up_to_date(root))
def test_interactive(self) -> None: def mock_prompt(*_args: None, **kwargs: str) -> str: return kwargs["default"] with temporary_root() as rootdir: with patch.object(click, "prompt", new=mock_prompt): with patch.object(click, "confirm", new=mock_prompt): config = tutor_config.load_minimal(rootdir) interactive.ask_questions(config) self.assertIn("MYSQL_ROOT_PASSWORD", config) self.assertEqual(8, len(get_typed(config, "MYSQL_ROOT_PASSWORD", str))) self.assertEqual("www.myopenedx.com", config["LMS_HOST"]) self.assertEqual("studio.www.myopenedx.com", config["CMS_HOST"])
def test_set_theme(self, mock_stdout: StringIO) -> None: with temporary_root() as root: context = TestContext(root) config = tutor_config.load_full(root) runner = context.job_runner(config) jobs.set_theme("sample_theme", ["domain1", "domain2"], runner) output = mock_stdout.getvalue() service = re.search(r"Service: (\w*)", output) commands = re.search(r"(-----)([\S\s]+)(-----)", output) assert service is not None assert commands is not None self.assertEqual(service.group(1), "lms") self.assertTrue( commands.group(2).strip().startswith( 'echo "Loading settings $DJANGO_SETTINGS_MODULE"'))
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())
def test_config_render_with_extra_configs(self) -> None: with tempfile.TemporaryDirectory() as dest: with temporary_root() as root: self.invoke_in_root(root, ["config", "save"]) result = self.invoke_in_root( root, [ "config", "render", "-x", os.path.join(root, tutor_config.CONFIG_FILENAME), root, dest, ], ) self.assertEqual(0, result.exit_code) self.assertFalse(result.exception)
def test_removed_entry_is_added_on_save(self, _: Mock) -> None: with temporary_root() as root: mock_random_string = Mock() hooks.Filters.ENV_TEMPLATE_FILTERS.add_item( ("random_string", mock_random_string), ) mock_random_string.return_value = "abcd" config1 = tutor_config.load_full(root) password1 = config1.pop("MYSQL_ROOT_PASSWORD") tutor_config.save_config_file(root, config1) mock_random_string.return_value = "efgh" config2 = tutor_config.load_full(root) password2 = config2["MYSQL_ROOT_PASSWORD"] self.assertEqual("abcd", password1) self.assertEqual("efgh", password2)
def test_copyfrom(self) -> None: with temporary_root() as root: with tempfile.TemporaryDirectory() as directory: with patch( "tutor.utils.docker_compose") as mock_docker_compose: self.invoke_in_root(root, ["config", "save"]) # Copy to existing directory result = self.invoke_in_root(root, [ "local", "copyfrom", "lms", "/openedx/venv", directory ]) self.assertIsNone(result.exception) self.assertEqual(0, result.exit_code) self.assertIn( f"--volume={directory}:/tmp/mount", mock_docker_compose.call_args[0], ) self.assertIn( "cp --recursive --preserve /openedx/venv /tmp/mount", mock_docker_compose.call_args[0], ) # Copy to non-existing directory result = self.invoke_in_root( root, [ "local", "copyfrom", "lms", "/openedx/venv", os.path.join(directory, "venv2"), ], ) self.assertIsNone(result.exception) self.assertEqual(0, result.exit_code) self.assertIn( f"--volume={directory}:/tmp/mount", mock_docker_compose.call_args[0], ) self.assertIn( "cp --recursive --preserve /openedx/venv /tmp/mount/venv2", mock_docker_compose.call_args[0], )
def test_json_config_is_overwritten_by_yaml(self, _: Mock) -> None: with temporary_root() as root: # Create config from scratch config_yml_path = os.path.join(root, tutor_config.CONFIG_FILENAME) config_json_path = os.path.join( root, tutor_config.CONFIG_FILENAME.replace("yml", "json")) config = tutor_config.load_full(root) # Save config to json with open(config_json_path, "w", encoding="utf-8") as f: json.dump(config, f, ensure_ascii=False, indent=4) self.assertFalse(os.path.exists(config_yml_path)) self.assertTrue(os.path.exists(config_json_path)) # Reload and compare current = tutor_config.load_full(root) self.assertTrue(os.path.exists(config_yml_path)) self.assertFalse(os.path.exists(config_json_path)) self.assertEqual(config, current)
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])
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)
def test_config_printroot(self) -> None: with temporary_root() as root: result = self.invoke_in_root(root, ["config", "printroot"]) self.assertFalse(result.exception) self.assertEqual(0, result.exit_code) self.assertIn(root, result.output)
def test_get_all_openedx_domains(self) -> None: with temporary_root() as root: config = tutor_config.load_full(root) domains = jobs.get_all_openedx_domains(config) self.assertTrue(domains) self.assertEqual(6, len(domains))
def invoke(args: t.List[str]) -> click.testing.Result: with temporary_root() as root: return TestCommandMixin.invoke_in_root(root, args)
def test_pathjoin(self) -> None: with temporary_root() as root: self.assertEqual(os.path.join(env.base_dir(root), "dummy"), env.pathjoin(root, "dummy"))
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)) self.assertTrue(env.is_up_to_date(root))