1
0

test_provider_base.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. """
  4. BaseProvider 单元测试
  5. 支持 Python 2.7 和 Python 3
  6. """
  7. from base_test import BaseProviderTestCase, unittest
  8. from ddns.provider._base import BaseProvider, encode_params
  9. class _TestProvider(BaseProvider):
  10. """测试用的具体Provider实现"""
  11. endpoint = "https://api.example.com"
  12. def __init__(self, id="test_id", token="test_token_123456789", **options):
  13. super(_TestProvider, self).__init__(id, token, **options)
  14. self._test_zone_data = {"example.com": "zone123", "test.com": "zone456"}
  15. self._test_records = {}
  16. def _query_zone_id(self, domain):
  17. return self._test_zone_data.get(domain)
  18. def _query_record(self, zone_id, subdomain, main_domain, record_type, line=None, extra=None):
  19. key = "{}-{}-{}".format(zone_id, subdomain, record_type)
  20. return self._test_records.get(key)
  21. def _create_record(self, zone_id, subdomain, main_domain, value, record_type, ttl=None, line=None, extra=None):
  22. key = "{}-{}-{}".format(zone_id, subdomain, record_type)
  23. self._test_records[key] = {"id": "rec123", "name": subdomain, "value": value, "type": record_type}
  24. return True
  25. def _update_record(self, zone_id, old_record, value, record_type, ttl=None, line=None, extra=None):
  26. old_record["value"] = value
  27. return True
  28. class TestBaseProvider(BaseProviderTestCase):
  29. """BaseProvider 测试类"""
  30. def setUp(self):
  31. """测试初始化"""
  32. super(TestBaseProvider, self).setUp()
  33. self.provider = _TestProvider()
  34. def test_init_success(self):
  35. """测试正常初始化"""
  36. provider = _TestProvider("test_id", "test_token")
  37. self.assertEqual(provider.id, "test_id")
  38. self.assertEqual(provider.token, "test_token")
  39. self.assertIsNotNone(provider.logger)
  40. self.assertEqual(provider._proxy, None) # proxy 初始化为 None
  41. self.assertEqual(provider._zone_map, {})
  42. def test_validate_missing_id(self):
  43. """测试缺少id的验证"""
  44. with self.assertRaises(ValueError) as cm:
  45. _TestProvider("", "token")
  46. self.assertIn("id must be configured", str(cm.exception))
  47. def test_validate_missing_token(self):
  48. """测试缺少token的验证"""
  49. with self.assertRaises(ValueError) as cm:
  50. _TestProvider("id", "")
  51. self.assertIn("token must be configured", str(cm.exception))
  52. def test_init_with_endpoint_override(self):
  53. """测试使用endpoint参数覆盖默认API"""
  54. custom_endpoint = "https://custom.api.com"
  55. provider = _TestProvider("test_id", "test_token", endpoint=custom_endpoint)
  56. self.assertEqual(provider.endpoint, custom_endpoint)
  57. self.assertEqual(provider.id, "test_id")
  58. self.assertEqual(provider.token, "test_token")
  59. def test_init_without_endpoint_uses_default(self):
  60. """测试不提供endpoint时使用默认API"""
  61. provider = _TestProvider("test_id", "test_token")
  62. self.assertEqual(provider.endpoint, "https://api.example.com") # 使用类级别的默认值
  63. self.assertEqual(provider.id, "test_id")
  64. self.assertEqual(provider.token, "test_token")
  65. def test_init_with_empty_endpoint_ignored(self):
  66. """测试空endpoint参数被忽略"""
  67. provider = _TestProvider("test_id", "test_token", endpoint="")
  68. self.assertEqual(provider.endpoint, "https://api.example.com") # 使用类级别的默认值
  69. provider = _TestProvider("test_id", "test_token", endpoint=None)
  70. self.assertEqual(provider.endpoint, "https://api.example.com") # 使用类级别的默认值
  71. def test_remark_exists_and_format(self):
  72. """测试remark存在且格式正确"""
  73. provider = _TestProvider("test_id", "test_token")
  74. self.assertTrue(hasattr(provider, "remark"))
  75. self.assertIsInstance(provider.remark, str)
  76. self.assertGreater(len(provider.remark), 0)
  77. # 检查是否包含基本的说明信息
  78. self.assertIn("DDNS", provider.remark)
  79. def test_endpoint_priority_over_class_api(self):
  80. """测试endpoint参数优先级高于类级别API"""
  81. # 创建一个有不同默认API的测试类
  82. class _CustomAPIProvider(_TestProvider):
  83. endpoint = "https://different.api.com"
  84. # 不使用endpoint - 应该使用类级别的API
  85. provider1 = _CustomAPIProvider("id", "token")
  86. self.assertEqual(provider1.endpoint, "https://different.api.com")
  87. # 使用endpoint - 应该覆盖类级别的API
  88. custom_endpoint = "https://override.api.com"
  89. provider2 = _CustomAPIProvider("id", "token", endpoint=custom_endpoint)
  90. self.assertEqual(provider2.endpoint, custom_endpoint)
  91. def test_get_zone_id_from_cache(self):
  92. """测试从缓存获取zone_id"""
  93. self.provider._zone_map["cached.com"] = "cached_zone"
  94. zone_id = self.provider.get_zone_id("cached.com")
  95. self.assertEqual(zone_id, "cached_zone")
  96. def test_get_zone_id_query_and_cache(self):
  97. """测试查询并缓存zone_id"""
  98. zone_id = self.provider.get_zone_id("example.com")
  99. self.assertEqual(zone_id, "zone123")
  100. self.assertEqual(self.provider._zone_map["example.com"], "zone123")
  101. def test_split_custom_domain_with_tilde(self):
  102. """测试用~分隔的自定义域名"""
  103. from ddns.provider._base import _split_custom_domain
  104. sub, main = _split_custom_domain("www~example.com")
  105. self.assertEqual(sub, "www")
  106. self.assertEqual(main, "example.com")
  107. def test_split_custom_domain_with_plus(self):
  108. """测试用+分隔的自定义域名"""
  109. from ddns.provider._base import _split_custom_domain
  110. sub, main = _split_custom_domain("api+test.com")
  111. self.assertEqual(sub, "api")
  112. self.assertEqual(main, "test.com")
  113. def test_split_custom_domain_no_separator(self):
  114. """测试没有分隔符的域名"""
  115. from ddns.provider._base import _split_custom_domain
  116. sub, main = _split_custom_domain("example.com")
  117. self.assertIsNone(sub)
  118. self.assertEqual(main, "example.com")
  119. def test_join_domain_normal(self):
  120. """测试正常合并域名"""
  121. from ddns.provider._base import join_domain
  122. domain = join_domain("www", "example.com")
  123. self.assertEqual(domain, "www.example.com")
  124. def test_join_domain_empty_sub(self):
  125. """测试空子域名合并"""
  126. from ddns.provider._base import join_domain
  127. domain = join_domain("", "example.com")
  128. self.assertEqual(domain, "example.com")
  129. domain = join_domain("@", "example.com")
  130. self.assertEqual(domain, "example.com")
  131. def test_encode_dict(self):
  132. """测试编码字典参数"""
  133. params = {"key1": "value1", "key2": "value2"}
  134. result = encode_params(params)
  135. # 由于字典顺序可能不同,我们检查包含关系
  136. self.assertIn("key1=value1", result)
  137. self.assertIn("key2=value2", result)
  138. def test_encode_none(self):
  139. """测试编码None参数"""
  140. result = encode_params(None)
  141. self.assertEqual(result, "")
  142. def test_mask_sensitive_data_empty(self):
  143. """测试空数据打码"""
  144. result = self.provider._mask_sensitive_data("")
  145. self.assertEqual(result, "")
  146. result = self.provider._mask_sensitive_data(None)
  147. self.assertEqual(result, None)
  148. def test_mask_sensitive_data_long_token(self):
  149. """测试长token的打码"""
  150. data = "token=test_token_123456789&other=value"
  151. result = self.provider._mask_sensitive_data(data)
  152. expected = "token=te***89&other=value"
  153. self.assertEqual(result, expected)
  154. def test_set_record_create(self):
  155. """测试创建记录"""
  156. result = self.provider.set_record("www~example.com", "1.2.3.4", "A")
  157. self.assertTrue(result)
  158. # 验证记录是否被创建
  159. record = self.provider._query_record("zone123", "www", "example.com", "A", None, {})
  160. self.assertIsNotNone(record)
  161. if record: # Type narrowing for mypy
  162. self.assertEqual(record["value"], "1.2.3.4")
  163. def test_set_record_update_existing(self):
  164. """测试更新现有记录"""
  165. # 先创建一个记录
  166. self.provider.set_record("www~example.com", "1.2.3.4", "A")
  167. # 再更新它
  168. result = self.provider.set_record("www~example.com", "9.8.7.6", "A")
  169. self.assertTrue(result)
  170. record = self.provider._query_record("zone123", "www", "example.com", "A", None, {})
  171. if record: # Type narrowing for mypy
  172. self.assertEqual(record["value"], "9.8.7.6")
  173. def test_set_record_invalid_domain(self):
  174. """测试无效域名"""
  175. result = self.provider.set_record("invalid.notfound", "1.2.3.4", "A")
  176. self.assertFalse(result)
  177. if __name__ == "__main__":
  178. # 运行测试
  179. unittest.main(verbosity=2)