Files
votianng/tests/test_backend_config.py

92 lines
4.9 KiB
Python

import contextlib
import importlib.util
import io
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
MODULE_PATH = Path(__file__).resolve().parents[1] / "scripts/run-backend.py"
SPEC = importlib.util.spec_from_file_location("backend_config", MODULE_PATH)
CONFIG = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(CONFIG)
class BackendConfigurationTest(unittest.TestCase):
def test_env_file_works_without_php_or_connection_json(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / ".env").write_text("DB_URL=jdbc:mariadb://test.invalid/db\nDB_USER=fixture\nDB_PASSWORD=literal$#=secret\\end\n")
result = CONFIG.database_environment(root, {})
self.assertEqual(result["DB_PASSWORD"], "literal$#=secret\\end")
self.assertEqual(result["DB_USER"], "fixture")
def test_process_environment_overrides_env_file(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / ".env").write_text("DB_URL=jdbc:mariadb://test.invalid/db\nDB_USER=fixture\nDB_PASSWORD=local\n")
result = CONFIG.database_environment(root, {"DB_USER": "override", "DB_PASSWORD": ""})
self.assertEqual(result["DB_USER"], "override")
self.assertEqual(result["DB_PASSWORD"], "")
def test_explicit_environment_needs_no_file(self):
expected = {"DB_URL": "jdbc:mariadb://test.invalid/db", "DB_USER": "fixture", "DB_PASSWORD": "secret"}
with tempfile.TemporaryDirectory() as directory:
self.assertEqual(CONFIG.database_environment(Path(directory), expected), expected)
def test_missing_credentials_do_not_fall_back_to_legacy_files(self):
with tempfile.TemporaryDirectory() as directory:
with self.assertRaises(ValueError):
CONFIG.database_environment(Path(directory), {"DB_URL": "jdbc:mariadb://test.invalid/db"})
def test_jar_version_is_not_hardcoded_and_original_is_ignored(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
target = root / "backend/target"
target.mkdir(parents=True)
jar = target / "votian-backend-0.1.jar"
jar.touch()
(target / "votian-backend-0.1.jar.original").touch()
self.assertEqual(CONFIG.backend_jar(root), jar)
(target / "votian-backend-1.0.0-SNAPSHOT.jar").touch()
with self.assertRaises(FileNotFoundError):
CONFIG.backend_jar(root)
def test_check_config_does_not_find_jar_or_launch_java(self):
environment = {"DB_URL": "jdbc:mariadb://test.invalid/db", "DB_USER": "fixture", "DB_PASSWORD": "secret"}
with patch.object(CONFIG.sys, "argv", ["run-backend.py", "--check-config"]), \
patch.object(CONFIG, "database_environment", return_value=environment), \
patch.object(CONFIG, "backend_jar") as jar, \
patch.object(CONFIG.os, "execvpe") as execute, contextlib.redirect_stdout(io.StringIO()):
self.assertEqual(CONFIG.main(), 0)
jar.assert_not_called()
execute.assert_not_called()
def test_launch_uses_env_port_and_keeps_secrets_out_of_arguments(self):
for arguments, expected_port in (([], "18081"), (["--port", "18082"], "18082")):
environment = {"DB_URL": "jdbc:mariadb://test.invalid/db", "DB_USER": "fixture", "DB_PASSWORD": "secret", "PORT": "18081"}
with self.subTest(arguments=arguments), \
patch.object(CONFIG.sys, "argv", ["run-backend.py", *arguments]), \
patch.object(CONFIG, "database_environment", return_value=environment), \
patch.object(CONFIG, "backend_jar", return_value=Path("/fixture/backend.jar")), \
patch.object(CONFIG.os, "chdir"), patch.object(CONFIG.os, "execvpe") as execute:
self.assertEqual(CONFIG.main(), 0)
command, actual_arguments, actual_environment = execute.call_args.args
self.assertEqual(command, "java")
self.assertEqual(actual_arguments, ["java", "-jar", "/fixture/backend.jar"])
self.assertEqual(actual_environment["PORT"], expected_port)
self.assertEqual(actual_environment["DB_PASSWORD"], "secret")
def test_configuration_error_never_prints_secret(self):
output = io.StringIO()
with patch.object(CONFIG.sys, "argv", ["run-backend.py", "--check-config"]), \
patch.object(CONFIG, "database_environment", side_effect=ValueError("secret=do-not-expose")), \
patch.object(CONFIG.os, "execvpe") as execute, contextlib.redirect_stderr(output):
self.assertEqual(CONFIG.main(), 2)
execute.assert_not_called()
self.assertNotIn("do-not-expose", output.getvalue())
if __name__ == "__main__":
unittest.main()