mirror of
https://github.com/NewFuture/DDNS.git
synced 2026-10-19 16:15:45 +00:00
* Initial plan * feat(provider): add EdgeOne DNS provider for non-accelerated domains Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(provider): add EdgeOne DNS documentation for non-accelerated domains Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * fix(provider): update EdgeOne provider aliases per feedback - Acceleration domains: edgeone, edgeone_acc, teo_acc - DNS records: edgeone_dns, teo_dns, edgeone_noacc - Removed: teo, tencentedgeone, neo_acc, neo - Updated documentation to reflect new aliases Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * feat(provider): add extra parameter support and update documentation index - Add edgeone_dns to provider index documentation (README.md) - Add "teo" alias for backward compatibility (not documented) - Enable EdgeOneProvider to support both acceleration and DNS records via extra['dns_record'] parameter - Update provider aliases and documentation Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs: create comprehensive new-provider agent guide - Add detailed step-by-step guide for creating new DNS providers - Include API analysis, implementation, testing, and documentation steps - Provide code templates and examples for both BaseProvider and SimpleProvider - Add completion checklist and common pitfalls - Document all requirements including compatibility checks and index updates Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * refactor(provider): change extra parameter from dns_record to teoDomainType - Change EdgeOneProvider to use teoDomainType parameter instead of dns_record - Support values: "dns" or "acceleration" (default) - Parameter is case-insensitive - EdgeOneDnsProvider now uses extra parameter to control behavior - All 55 tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * refactor(provider): simplify EdgeOneDnsProvider with helper method - Extract common extra parameter preparation into _prepare_extra() method - Reduces code duplication across _query_record, _create_record, _update_record - All 55 tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * refactor(provider): make EdgeOneDnsProvider more elegant and concise - Use class attribute _default_domain_type = "dns" for clarity - Replace _prepare_extra() with inline setdefault() for more Pythonic code - setdefault() allows users to override teoDomainType if needed - All 55 tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * refactor(provider): use options instead of extra for teoDomainType - Move teoDomainType from per-call extra to instance-level options - More appropriate since provider type is fixed per instance - EdgeOneProvider reads teoDomainType from self.options at initialization - EdgeOneDnsProvider sets teoDomainType="dns" in __init__ - Simplified implementation: 28 lines vs 43 lines for EdgeOneDnsProvider - All 55 tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * refactor(provider): support both extra and options for teoDomainType with priority - Remove __init__ from EdgeOneProvider, read directly from self.options - Support teoDomainType in both extra (per-call) and options (initialization) - extra parameter has higher priority than options - Priority: extra > options > default ("acceleration") - All 55 tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(provider): add teoDomainType parameter documentation for EdgeOne - Document how to switch between acceleration domains and DNS records - Explain extra.teoDomainType parameter usage - Add configuration examples for both modes - Update parameter tables with teoDomainType and extra - Document priority: extra > initialization parameter - Add bilingual documentation (Chinese and English) Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(provider): remove initialization parameter config example from EdgeOne - Remove the example showing teoDomainType via initialization parameters - Only document usage via extra parameter - Remove priority note since only one method is documented - Keep recommendation to use EdgeOneDnsProvider for cleaner code - Update both Chinese and English documentation Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(agent): update new-provider guide with relative paths and schema notes - Update CLI compatibility note to mention checking --dns parameter choices - Change schema note to only require v4.0 (latest format) updates - Replace "multi-provider format" with "latest schema format" - Convert all absolute paths to relative paths from project root - Remove /home/runner/work/DDNS/DDNS/ prefix from all file paths Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(agent): correct latest schema version to v4.1 - Update schema compatibility section to reference v4.1 instead of v4.0 - v4.1 is the latest schema format that requires updates Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * feat(config): add edgeone_dns to CLI and schema v4.1 - Add edgeone_dns to CLI --dns parameter choices - Add edgeone_dns to schema v4.1 provider enum (both legacy and multi-provider sections) - Update provider descriptions to include EdgeOne DNS Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Refactor labels_to_prompts_mapping format * fix(provider): filter teoDomainType from extra params before API call - Remove teoDomainType from extra dict before passing to Tencent Cloud API - Fixes "UnknownParameter - The parameter `extra_teoDomainType` is not recognized" error - teoDomainType is internal parameter for routing, not for API requests - All 55 tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(provider): update schema references to v4.1.json in EdgeOne docs - Update all $schema references from v4.0.json to v4.1.json - Applied to edgeone.md, edgeone.en.md, edgeone_dns.md, edgeone_dns.en.md - Ensures documentation references the latest schema format Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * Changes before error encountered Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * fix(config): preserve nested extra dict from JSON/ENV config - Process "extra" dict before extra_ prefixed keys to avoid flattening - Fixes issue where {"extra":{"teoDomainType":"dns"}} was incorrectly transformed to {"extra_teoDomainType":"dns"} - Maintains backward compatibility with extra_ prefixed keys - Priority: explicit extra dict > extra_ prefixed keys > unknown keys Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/test_provider_edgeone_dns.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update tests/test_provider_edgeone_dns.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * style: apply ruff formatting fixes - Format 9 files with ruff - Fix 2 linting issues automatically - One complexity warning remains (C901) but doesn't affect functionality - All code now follows consistent formatting standards Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(agent): add ruff installation instructions to new-provider guide - Add pip3 install ruff command before formatting/linting steps - Ensures developers have required tools before running verification - Prevents common setup errors Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * docs(config): clarify extra dict and extra_ prefix priority within config sources - Add comments explaining that extra_ prefixed keys override nested extra dict values within the same source - Improves code documentation clarity for config flattening logic - Addresses feedback about intra-source priority ordering Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> * refactor(config): reduce complexity of _collect_extra method - Extract _process_extra_from_source helper method to reduce cyclomatic complexity - Fixes ruff C901 error (complexity was 14, now under threshold) - Maintains all existing functionality and test coverage - All 60 extra-related tests passing Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: NewFuture <6290356+NewFuture@users.noreply.github.com> Co-authored-by: New Future <NewFuture@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
205 lines
9.4 KiB
Python
205 lines
9.4 KiB
Python
# coding=utf-8
|
|
"""
|
|
Unit tests for extra field support in ddns.config.config module
|
|
@author: GitHub Copilot
|
|
"""
|
|
|
|
from __init__ import unittest
|
|
from ddns.config.config import Config # noqa: E402
|
|
|
|
|
|
class TestConfigExtra(unittest.TestCase):
|
|
"""Test extra field collection from various config sources"""
|
|
|
|
def test_extra_from_cli(self):
|
|
"""Test extra fields from CLI config with extra_ prefix"""
|
|
cli_config = {
|
|
"dns": "cloudflare",
|
|
"id": "test@example.com",
|
|
"extra_proxied": "true",
|
|
"extra_comment": "Test comment",
|
|
"extra_custom_field": "custom_value",
|
|
}
|
|
config = Config(cli_config=cli_config)
|
|
self.assertEqual(config.dns, "cloudflare")
|
|
self.assertIsInstance(config.extra, dict)
|
|
self.assertEqual(config.extra.get("proxied"), "true")
|
|
self.assertEqual(config.extra.get("comment"), "Test comment")
|
|
self.assertEqual(config.extra.get("custom_field"), "custom_value")
|
|
|
|
def test_extra_from_json(self):
|
|
"""Test extra fields from JSON config as extra object"""
|
|
json_config = {
|
|
"dns": "alidns",
|
|
"id": "test_id",
|
|
"extra": {"proxied": False, "comment": "JSON comment", "tags": ["tag1", "tag2"]},
|
|
}
|
|
config = Config(json_config=json_config)
|
|
self.assertEqual(config.dns, "alidns")
|
|
self.assertIsInstance(config.extra, dict)
|
|
self.assertFalse(config.extra.get("proxied"))
|
|
self.assertEqual(config.extra.get("comment"), "JSON comment")
|
|
self.assertEqual(config.extra.get("tags"), ["tag1", "tag2"])
|
|
|
|
def test_extra_from_json_undefined_fields(self):
|
|
"""Test undefined fields in JSON config are collected as extra"""
|
|
json_config = {"dns": "dnspod", "id": "test_id", "custom_field": "custom_value", "another_field": 123}
|
|
config = Config(json_config=json_config)
|
|
self.assertEqual(config.dns, "dnspod")
|
|
self.assertEqual(config.extra.get("custom_field"), "custom_value")
|
|
self.assertEqual(config.extra.get("another_field"), 123)
|
|
|
|
def test_extra_from_env(self):
|
|
"""Test extra fields from environment config"""
|
|
env_config = {"dns": "cloudflare", "extra_proxied": "true", "extra_ttl_override": "300"}
|
|
config = Config(env_config=env_config)
|
|
self.assertEqual(config.dns, "cloudflare")
|
|
self.assertEqual(config.extra.get("proxied"), "true")
|
|
self.assertEqual(config.extra.get("ttl_override"), "300")
|
|
|
|
def test_extra_from_env_undefined_fields(self):
|
|
"""Test undefined fields in env config are collected as extra"""
|
|
env_config = {"dns": "dnspod", "custom_env_field": "env_value", "another_env_field": "another_value"}
|
|
config = Config(env_config=env_config)
|
|
self.assertEqual(config.dns, "dnspod")
|
|
self.assertEqual(config.extra.get("custom_env_field"), "env_value")
|
|
self.assertEqual(config.extra.get("another_env_field"), "another_value")
|
|
|
|
def test_extra_priority_cli_over_json(self):
|
|
"""Test CLI extra fields have priority over JSON"""
|
|
cli_config = {"extra_comment": "CLI comment", "extra_field1": "cli_value"}
|
|
json_config = {"extra": {"comment": "JSON comment", "field1": "json_value", "field2": "json_only"}}
|
|
config = Config(cli_config=cli_config, json_config=json_config)
|
|
self.assertEqual(config.extra.get("comment"), "CLI comment")
|
|
self.assertEqual(config.extra.get("field1"), "cli_value")
|
|
self.assertEqual(config.extra.get("field2"), "json_only")
|
|
|
|
def test_extra_priority_json_over_env(self):
|
|
"""Test JSON extra fields have priority over ENV"""
|
|
json_config = {"extra": {"comment": "JSON comment", "field1": "json_value"}}
|
|
env_config = {"extra_comment": "ENV comment", "extra_field1": "env_value", "extra_field2": "env_only"}
|
|
config = Config(json_config=json_config, env_config=env_config)
|
|
self.assertEqual(config.extra.get("comment"), "JSON comment")
|
|
self.assertEqual(config.extra.get("field1"), "json_value")
|
|
self.assertEqual(config.extra.get("field2"), "env_only")
|
|
|
|
def test_extra_priority_all_sources(self):
|
|
"""Test complete priority chain: CLI > JSON > ENV"""
|
|
cli_config = {"extra_field1": "cli_value"}
|
|
json_config = {"extra": {"field1": "json_value", "field2": "json_value"}}
|
|
env_config = {"extra_field1": "env_value", "extra_field2": "env_value", "extra_field3": "env_value"}
|
|
config = Config(cli_config=cli_config, json_config=json_config, env_config=env_config)
|
|
self.assertEqual(config.extra.get("field1"), "cli_value")
|
|
self.assertEqual(config.extra.get("field2"), "json_value")
|
|
self.assertEqual(config.extra.get("field3"), "env_value")
|
|
|
|
def test_extra_empty_by_default(self):
|
|
"""Test extra is empty dict when no extra fields provided"""
|
|
config = Config()
|
|
self.assertIsInstance(config.extra, dict)
|
|
self.assertEqual(len(config.extra), 0)
|
|
|
|
def test_extra_does_not_include_known_fields(self):
|
|
"""Test that known configuration fields are not collected as extra"""
|
|
cli_config = {
|
|
"dns": "cloudflare",
|
|
"id": "test@example.com",
|
|
"token": "secret",
|
|
"ttl": "300",
|
|
"extra_custom": "custom_value",
|
|
}
|
|
config = Config(cli_config=cli_config)
|
|
# Known fields should not be in extra
|
|
self.assertNotIn("dns", config.extra)
|
|
self.assertNotIn("id", config.extra)
|
|
self.assertNotIn("token", config.extra)
|
|
self.assertNotIn("ttl", config.extra)
|
|
# Only custom field should be in extra
|
|
self.assertEqual(config.extra.get("custom"), "custom_value")
|
|
|
|
def test_extra_does_not_include_schema_field(self):
|
|
"""Test that $schema field from JSON config is not collected as extra"""
|
|
json_config = {
|
|
"$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
|
|
"dns": "tencentcloud",
|
|
"id": "test_id",
|
|
"token": "test_token",
|
|
"ipv4": ["example.com"],
|
|
"extra": {"proxied": True},
|
|
}
|
|
config = Config(json_config=json_config)
|
|
# $schema should not be in extra
|
|
self.assertNotIn("$schema", config.extra)
|
|
# Other extra fields should be collected
|
|
self.assertTrue(config.extra.get("proxied"))
|
|
# Known fields should be accessible
|
|
self.assertEqual(config.dns, "tencentcloud")
|
|
self.assertEqual(config.id, "test_id")
|
|
|
|
def test_extra_with_json_extra_object_and_undefined_fields(self):
|
|
"""Test JSON config with both extra object and undefined fields"""
|
|
json_config = {
|
|
"dns": "cloudflare",
|
|
"extra": {"proxied": True, "comment": "From extra object"},
|
|
"custom_field": "From undefined field",
|
|
"another_field": 123,
|
|
}
|
|
config = Config(json_config=json_config)
|
|
# Both should be collected
|
|
self.assertTrue(config.extra.get("proxied"))
|
|
self.assertEqual(config.extra.get("comment"), "From extra object")
|
|
self.assertEqual(config.extra.get("custom_field"), "From undefined field")
|
|
self.assertEqual(config.extra.get("another_field"), 123)
|
|
|
|
def test_extra_in_md5_hash(self):
|
|
"""Test that extra fields are included in MD5 hash"""
|
|
config1 = Config(cli_config={"dns": "cloudflare", "extra_field": "value1"})
|
|
config2 = Config(cli_config={"dns": "cloudflare", "extra_field": "value1"})
|
|
config3 = Config(cli_config={"dns": "cloudflare", "extra_field": "value2"})
|
|
|
|
# Same extra should produce same hash
|
|
self.assertEqual(config1.md5(), config2.md5())
|
|
# Different extra should produce different hash
|
|
self.assertNotEqual(config1.md5(), config3.md5())
|
|
|
|
def test_extra_with_complex_values(self):
|
|
"""Test extra fields with complex data types"""
|
|
json_config = {
|
|
"dns": "cloudflare",
|
|
"extra": {
|
|
"tags": ["tag1", "tag2", "tag3"],
|
|
"settings": {"key1": "value1", "key2": "value2"},
|
|
"enabled": True,
|
|
"priority": 10,
|
|
},
|
|
}
|
|
config = Config(json_config=json_config)
|
|
self.assertEqual(config.extra.get("tags"), ["tag1", "tag2", "tag3"])
|
|
self.assertEqual(config.extra.get("settings"), {"key1": "value1", "key2": "value2"})
|
|
self.assertTrue(config.extra.get("enabled"))
|
|
self.assertEqual(config.extra.get("priority"), 10)
|
|
|
|
def test_extra_env_with_extra_object(self):
|
|
"""Test env config with extra object (dict)"""
|
|
env_config = {"dns": "cloudflare", "extra": {"field1": "value1", "field2": "value2"}}
|
|
config = Config(env_config=env_config)
|
|
self.assertEqual(config.extra.get("field1"), "value1")
|
|
self.assertEqual(config.extra.get("field2"), "value2")
|
|
|
|
def test_extra_mixed_prefix_and_object(self):
|
|
"""Test mixing extra_ prefix and extra object in same source"""
|
|
json_config = {
|
|
"dns": "cloudflare",
|
|
"extra": {"from_object": "object_value"},
|
|
"undefined_field": "undefined_value",
|
|
}
|
|
cli_config = {"extra_from_prefix": "prefix_value"}
|
|
config = Config(cli_config=cli_config, json_config=json_config)
|
|
self.assertEqual(config.extra.get("from_object"), "object_value")
|
|
self.assertEqual(config.extra.get("undefined_field"), "undefined_value")
|
|
self.assertEqual(config.extra.get("from_prefix"), "prefix_value")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|