# -*- coding:utf-8 -*- """ Unit tests for ddns.scheduler._base module @author: NewFuture """ from __init__ import patch, unittest from ddns.scheduler._base import BaseScheduler class MockScheduler(BaseScheduler): """Mock scheduler for testing base functionality""" SCHEDULER_NAME = "mock" def get_status(self): return {"scheduler": "mock", "installed": False, "enabled": None, "interval": None} def is_installed(self): return False def install(self, interval, ddns_args=None): return True def uninstall(self): return True def enable(self): return True def disable(self): return True class TestBaseScheduler(unittest.TestCase): """Test BaseScheduler functionality""" def setUp(self): """Set up test fixtures""" self.scheduler = MockScheduler() def test_scheduler_name_property(self): """Test scheduler name property""" self.assertEqual(self.scheduler.SCHEDULER_NAME, "mock") def test_abstract_methods_exist(self): """Test that all abstract methods are implemented""" required_methods = ["get_status", "is_installed", "install", "uninstall", "enable", "disable"] for method_name in required_methods: self.assertTrue(hasattr(self.scheduler, method_name)) method = getattr(self.scheduler, method_name) self.assertTrue(callable(method)) def test_build_ddns_command_basic(self): """Test _build_ddns_command with basic arguments""" ddns_args = {"dns": "debug", "ipv4": ["test.example.com"]} command = self.scheduler._build_ddns_command(ddns_args) self.assertIsInstance(command, list) command_str = " ".join(command) self.assertIn("python", command_str.lower()) self.assertIn("-m", command) self.assertIn("ddns", command) self.assertIn("--dns", command) self.assertIn("debug", command) self.assertIn("--ipv4", command) self.assertIn("test.example.com", command) def test_build_ddns_command_with_config(self): """Test _build_ddns_command with config files""" ddns_args = {"dns": "cloudflare", "config": ["config1.json", "config2.json"]} command = self.scheduler._build_ddns_command(ddns_args) self.assertIn("--config", command) self.assertIn("config1.json", command) self.assertIn("config2.json", command) def test_build_ddns_command_with_lists(self): """Test _build_ddns_command with list arguments""" ddns_args = { "dns": "debug", "ipv4": ["domain1.com", "domain2.com"], "ipv6": ["ipv6domain.com"], "proxy": ["http://proxy1:8080", "http://proxy2:8080"], } command = self.scheduler._build_ddns_command(ddns_args) self.assertIn("domain1.com", command) self.assertIn("domain2.com", command) self.assertIn("ipv6domain.com", command) self.assertIn("http://proxy1:8080", command) def test_build_ddns_command_with_boolean_flags(self): """Test _build_ddns_command with boolean flags""" ddns_args = {"dns": "debug", "ipv4": ["test.com"], "debug": True, "cache": True} command = self.scheduler._build_ddns_command(ddns_args) self.assertIn("--debug", command) self.assertIn("true", command) self.assertIn("--cache", command) def test_build_ddns_command_filters_debug_false(self): """Test _build_ddns_command filters out debug=False""" ddns_args = {"dns": "debug", "ipv4": ["test.com"], "debug": False, "cache": True} # This should be filtered out command = self.scheduler._build_ddns_command(ddns_args) command_str = " ".join(command) self.assertNotIn("--debug false", command_str) self.assertIn("--cache", command) self.assertIn("true", command) def test_build_ddns_command_with_single_values(self): """Test _build_ddns_command with single value arguments""" ddns_args = {"dns": "alidns", "id": "test_id", "token": "test_token", "ttl": 600, "log_level": "INFO"} command = self.scheduler._build_ddns_command(ddns_args) self.assertIn("--id", command) self.assertIn("test_id", command) self.assertIn("--token", command) self.assertIn("test_token", command) self.assertIn("--ttl", command) self.assertIn("600", command) def test_build_ddns_command_with_cache_max_age(self): """Test _build_ddns_command emits the cache max age option.""" command = self.scheduler._build_ddns_command({"cache_max_age": 86400}) self.assertIn("--cache_max_age", command) self.assertIn("86400", command) def test_build_ddns_command_excludes_none_values(self): """Test _build_ddns_command behavior with None values""" ddns_args = {"dns": "debug", "ipv4": ["test.com"], "ttl": None, "line": None} command = self.scheduler._build_ddns_command(ddns_args) # The current implementation includes None values as strings # This test verifies the actual behavior self.assertIn("--ttl", command) self.assertIn("None", command) self.assertIn("--line", command) def test_build_ddns_command_excludes_empty_lists(self): """Test _build_ddns_command excludes empty lists""" ddns_args = {"dns": "debug", "ipv4": ["test.com"], "ipv6": [], "config": []} command = self.scheduler._build_ddns_command(ddns_args) # Should not include empty list arguments self.assertIn("--ipv4", command) self.assertNotIn("--ipv6", command) self.assertNotIn("--config", command) @patch("sys.executable", "/usr/bin/python3.9") def test_build_ddns_command_uses_current_python(self): """Test _build_ddns_command uses current Python executable""" ddns_args = {"dns": "debug", "ipv4": ["test.com"]} command = self.scheduler._build_ddns_command(ddns_args) # Should use sys.executable for Python path command_str = " ".join(command) self.assertIn("python", command_str.lower()) def test_build_ddns_command_with_special_characters(self): """Test _build_ddns_command handles special characters""" ddns_args = {"dns": "debug", "ipv4": ["test-domain.example.com"], "token": "test_token_with_special_chars!@#"} command = self.scheduler._build_ddns_command(ddns_args) self.assertIsInstance(command, list) self.assertIn("test-domain.example.com", command) self.assertIn("test_token_with_special_chars!@#", command) def test_all_scheduler_interface_methods(self): """Test that scheduler implements all interface methods correctly""" # Test get_status status = self.scheduler.get_status() self.assertIsInstance(status, dict) self.assertIn("scheduler", status) # Test is_installed installed = self.scheduler.is_installed() self.assertIsInstance(installed, bool) # Test install result = self.scheduler.install(5, {"dns": "debug"}) self.assertIsInstance(result, bool) # Test uninstall result = self.scheduler.uninstall() self.assertIsInstance(result, bool) # Test enable result = self.scheduler.enable() self.assertIsInstance(result, bool) # Test disable result = self.scheduler.disable() self.assertIsInstance(result, bool) def test_quote_command_array(self): """Test _quote_command_array method""" # Test basic functionality cmd_array = ["python", "script.py"] result = self.scheduler._quote_command_array(cmd_array) self.assertEqual(result, "python script.py") # Test with spaces cmd_array = ["python", "script with spaces.py", "normal_arg"] result = self.scheduler._quote_command_array(cmd_array) self.assertEqual(result, 'python "script with spaces.py" normal_arg') # Test with multiple spaced arguments cmd_array = ["python", "-m", "ddns", "--config", "config file.json"] result = self.scheduler._quote_command_array(cmd_array) self.assertEqual(result, 'python -m ddns --config "config file.json"') # Test empty array result = self.scheduler._quote_command_array([]) self.assertEqual(result, "") if __name__ == "__main__": unittest.main()