| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- # -*- coding:utf-8 -*-
- # type: ignore[index,operator,assignment]
- """
- Integration test for all config formats including v4.1 providers
- @author: GitHub Copilot
- """
- from __future__ import unicode_literals
- from __init__ import unittest
- import tempfile
- import shutil
- import os
- import json
- from ddns.config import load_configs
- class TestAllConfigFormatsIntegration(unittest.TestCase):
- """Integration test for all supported config formats"""
- def setUp(self):
- """Set up test fixtures"""
- self.temp_dir = tempfile.mkdtemp()
- self.addCleanup(shutil.rmtree, self.temp_dir, ignore_errors=True)
- def create_test_file(self, filename, content):
- # type: (str, dict) -> str
- """Helper method to create a test file with given content"""
- file_path = os.path.join(self.temp_dir, filename)
- with open(file_path, "w") as f:
- if isinstance(content, dict):
- f.write(json.dumps(content, indent=2))
- else:
- f.write(content)
- return file_path
- def test_all_config_formats_integration(self):
- """Test loading v4.1 config formats"""
- # Create single object config
- single_config = {
- "dns": "cloudflare",
- "id": "[email protected]",
- "token": "single_token",
- "ipv4": ["single.example.com"],
- "ssl": True,
- }
- single_file = self.create_test_file("single.json", single_config)
- # Create v4.1 providers format
- providers_config = {
- "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
- "ssl": "auto",
- "cache": True,
- "providers": [
- {"provider": "debug", "token": "provider_token1", "ipv4": ["provider1.example.com"], "ttl": 300},
- {"provider": "debug", "token": "provider_token2", "ipv4": ["provider2.example.com"], "ttl": 600},
- ],
- }
- providers_file = self.create_test_file("providers.json", providers_config)
- # Mock sys.argv to control CLI parsing
- import sys
- original_argv = sys.argv
- try:
- # Set fake argv with our config files
- sys.argv = ["ddns", "-c", single_file, "-c", providers_file]
- # Load all configs
- all_configs = load_configs("test", "1.0.0", "2025-07-17")
- # Should have 3 total configs: 1 single + 2 from providers
- self.assertEqual(len(all_configs), 3)
- # Test single config
- self.assertEqual(all_configs[0].dns, "cloudflare")
- self.assertEqual(all_configs[0].id, "[email protected]")
- self.assertEqual(all_configs[0].ssl, True)
- # Test first provider config
- self.assertEqual(all_configs[1].dns, "debug")
- self.assertEqual(all_configs[1].token, "provider_token1")
- self.assertEqual(all_configs[1].ipv4, ["provider1.example.com"])
- self.assertEqual(all_configs[1].ttl, 300)
- # Inherited from global - handle Python 2.7 unicode strings
- self.assertEqual(str(all_configs[1].ssl), "auto")
- # Inherited from global
- self.assertEqual(all_configs[1].cache, True)
- # Test second provider config
- self.assertEqual(all_configs[2].dns, "debug")
- self.assertEqual(all_configs[2].token, "provider_token2")
- self.assertEqual(all_configs[2].ipv4, ["provider2.example.com"])
- self.assertEqual(all_configs[2].ttl, 600)
- # Inherited from global - handle Python 2.7 unicode strings
- self.assertEqual(str(all_configs[2].ssl), "auto")
- # Inherited from global
- self.assertEqual(all_configs[2].cache, True)
- finally:
- # Restore original argv
- sys.argv = original_argv
- def test_v41_backward_compatibility(self):
- """Test that v4.1 format is backward compatible with existing
- single config"""
- # Create a traditional single config
- old_config = {
- "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
- "dns": "cloudflare",
- "id": "[email protected]",
- "token": "old_token",
- "ipv4": ["old.example.com"],
- "ssl": "auto",
- }
- old_file = self.create_test_file("old_format.json", old_config)
- # Mock sys.argv to control CLI parsing
- import sys
- original_argv = sys.argv
- try:
- # Set fake argv with our config file
- sys.argv = ["ddns", "-c", old_file]
- configs = load_configs("test", "1.0.0", "2025-01-01")
- # Should load exactly one config
- self.assertEqual(len(configs), 1)
- config = configs[0]
- self.assertEqual(config.dns, "cloudflare")
- self.assertEqual(config.id, "[email protected]")
- self.assertEqual(config.token, "old_token")
- self.assertEqual(str(config.ssl), "auto")
- finally:
- sys.argv = original_argv
- def test_v41_schema_reference(self):
- """Test that save_config uses v4.1 schema by default"""
- from ddns.config.file import save_config, load_config
- test_config = {"dns": "debug", "token": "test"}
- save_file = os.path.join(self.temp_dir, "new_config.json")
- # Save config
- result = save_config(save_file, test_config)
- self.assertTrue(result)
- # Load it back and check schema
- loaded = load_config(save_file)
- expected_schema = "https://ddns.newfuture.cc/schema/v4.1.json"
- self.assertEqual(loaded["$schema"], expected_schema)
- self.assertEqual(loaded["dns"], "debug")
- self.assertEqual(loaded["token"], "test")
- def test_v40_to_v41_compatibility(self):
- """Test v4.0 config is compatible with v4.1 processing"""
- from ddns.config.file import load_config
- # Create v4.0 schema config
- v40_config = {
- "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
- "dns": "cloudflare",
- "id": "[email protected]",
- "token": "v40_token",
- "ipv4": ["v40.example.com"],
- "ttl": 300,
- "ssl": True,
- "log": {"level": "DEBUG", "file": "test.log"},
- }
- v40_file = self.create_test_file("v40_config.json", v40_config)
- # Load and check it processes correctly
- loaded = load_config(v40_file)
- self.assertEqual(loaded["dns"], "cloudflare")
- self.assertEqual(loaded["id"], "[email protected]")
- self.assertEqual(loaded["token"], "v40_token")
- self.assertEqual(loaded["ipv4"], ["v40.example.com"])
- self.assertEqual(loaded["ttl"], 300)
- self.assertEqual(loaded["ssl"], True)
- # Check flattened log properties
- self.assertEqual(loaded["log_level"], "DEBUG")
- self.assertEqual(loaded["log_file"], "test.log")
- def test_v41_providers_complex_inheritance(self):
- """Test complex inheritance scenarios in v4.1 providers format"""
- from ddns.config.file import load_config
- # Create complex v4.1 config with nested objects
- complex_config = {
- "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
- "ssl": "auto",
- "ttl": 600,
- "cache": False,
- "log": {"level": "INFO", "format": "[%(levelname)s] %(message)s"},
- "providers": [
- {
- "provider": "cloudflare",
- "id": "[email protected]",
- "token": "cf_token",
- "ipv4": ["cf.example.com"],
- "ttl": 300, # Override global ttl
- "ssl": True, # Override global ssl
- },
- {
- "provider": "debug",
- "token": "debug_token",
- "ipv4": ["debug.example.com"],
- # Uses global ttl and ssl
- "log": {"level": "DEBUG"}, # Override log level
- },
- ],
- }
- complex_file = self.create_test_file("complex_v41.json", complex_config)
- # Load config
- configs = load_config(complex_file)
- self.assertEqual(len(configs), 2)
- # Test first provider inheritance and overrides
- cf_config = configs[0]
- self.assertEqual(cf_config["dns"], "cloudflare")
- self.assertEqual(cf_config["id"], "[email protected]")
- self.assertEqual(cf_config["token"], "cf_token")
- self.assertEqual(cf_config["ttl"], 300) # Overridden
- self.assertEqual(cf_config["ssl"], True) # Overridden
- self.assertEqual(cf_config["cache"], False) # Inherited
- self.assertEqual(cf_config["log_level"], "INFO") # Inherited
- self.assertEqual(cf_config["log_format"], "[%(levelname)s] %(message)s")
- # Test second provider inheritance
- debug_config = configs[1]
- self.assertEqual(debug_config["dns"], "debug")
- self.assertEqual(debug_config["token"], "debug_token")
- self.assertEqual(debug_config["ttl"], 600) # Inherited
- self.assertEqual(debug_config["ssl"], "auto") # Inherited
- self.assertEqual(debug_config["cache"], False) # Inherited
- self.assertEqual(debug_config["log_level"], "DEBUG") # Overridden
- self.assertEqual(debug_config["log_format"], "[%(levelname)s] %(message)s")
- def test_v41_providers_error_cases(self):
- """Test error handling in v4.1 providers format"""
- from ddns.config.file import load_config
- # Test providers without provider field
- invalid_config1 = {"providers": [{"id": "[email protected]", "token": "token"}]}
- invalid_file1 = self.create_test_file("invalid1.json", invalid_config1)
- with self.assertRaises(ValueError) as cm:
- load_config(invalid_file1)
- self.assertIn("provider missing provider field", str(cm.exception))
- # Test dns and providers conflict
- invalid_config2 = {"dns": "cloudflare", "providers": [{"provider": "debug", "token": "token"}]}
- invalid_file2 = self.create_test_file("invalid2.json", invalid_config2)
- with self.assertRaises(ValueError) as cm:
- load_config(invalid_file2)
- self.assertIn("providers and dns fields conflict", str(cm.exception))
- if __name__ == "__main__":
- unittest.main()
|