test_config_env.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. # -*- coding:utf-8 -*-
  2. """
  3. Configuration loader tests for environment variables.
  4. """
  5. import os
  6. import unittest
  7. from ddns.config.env import load_config
  8. class TestConfigEnv(unittest.TestCase):
  9. """Test configuration loading from environment variables"""
  10. def setUp(self):
  11. """Set up test environment"""
  12. self._clear_env_prefix("DDNS_TEST_")
  13. self._clear_env_prefix("DDNS_")
  14. self._clear_standard_env()
  15. def tearDown(self):
  16. """Clean up after tests"""
  17. self._clear_env_prefix("DDNS_TEST_")
  18. self._clear_env_prefix("DDNS_")
  19. self._clear_standard_env()
  20. def _clear_env_prefix(self, prefix):
  21. # type: (str) -> None
  22. """Clear environment variables with a specific prefix"""
  23. test_prefixes = [prefix.lower(), prefix.upper()]
  24. for key in list(os.environ.keys()):
  25. if any(key.startswith(prefix) for prefix in test_prefixes):
  26. del os.environ[key]
  27. def _clear_standard_env(self):
  28. # type: () -> None
  29. """Clear standard environment variables used in tests"""
  30. keys = ["PYTHONHTTPSVERIFY"]
  31. for key in keys:
  32. if key in os.environ:
  33. del os.environ[key]
  34. def test_basic_string_values(self):
  35. """Test that basic string values are preserved"""
  36. os.environ["DDNS_DNS"] = "cloudflare"
  37. os.environ["DDNS_ID"] = "[email protected]"
  38. os.environ["DDNS_TOKEN"] = "secret123"
  39. config = load_config()
  40. self.assertEqual(config.get("dns"), "cloudflare")
  41. self.assertEqual(config.get("id"), "[email protected]")
  42. self.assertEqual(config.get("token"), "secret123")
  43. def test_json_array_conversion(self):
  44. """Test JSON array format conversion"""
  45. os.environ["DDNS_IPV4"] = '["domain1.com", "domain2.com"]'
  46. os.environ["DDNS_INDEX4"] = '["public", 0]'
  47. config = load_config()
  48. self.assertEqual(config.get("ipv4"), ["domain1.com", "domain2.com"])
  49. self.assertEqual(config.get("index4"), ["public", 0])
  50. def test_key_normalization(self):
  51. """Test key normalization (uppercase to lowercase)"""
  52. os.environ["DDNS_DNS"] = "cloudflare"
  53. os.environ["ddns_id"] = "[email protected]"
  54. config = load_config()
  55. self.assertEqual(config.get("dns"), "cloudflare")
  56. self.assertEqual(config.get("id"), "[email protected]")
  57. def test_dot_to_underscore_conversion(self):
  58. """Test conversion of dots to underscores in keys"""
  59. os.environ["DDNS_LOG.LEVEL"] = "DEBUG"
  60. os.environ["DDNS_LOG.FILE"] = "/var/log/ddns.log"
  61. config = load_config()
  62. self.assertEqual(config.get("log_level"), "DEBUG")
  63. self.assertEqual(config.get("log_file"), "/var/log/ddns.log")
  64. def test_pythonhttpsverify_values(self):
  65. """Test PYTHONHTTPSVERIFY with different values"""
  66. test_cases = [("0", "0"), ("1", "1"), ("false", "false"), ("true", "true"), ("anything", "anything")]
  67. for env_value, expected in test_cases:
  68. os.environ["PYTHONHTTPSVERIFY"] = env_value
  69. config = load_config()
  70. self.assertEqual(config.get("ssl"), expected)
  71. del os.environ["PYTHONHTTPSVERIFY"]
  72. def test_ddns_proxy_basic(self):
  73. """Test basic DDNS_PROXY functionality"""
  74. os.environ["DDNS_PROXY"] = "http://ddns.proxy.com:9090"
  75. config = load_config()
  76. self.assertEqual(config.get("proxy"), "http://ddns.proxy.com:9090")
  77. del os.environ["DDNS_PROXY"]
  78. def test_ddns_variables_override_standard_vars(self):
  79. """Test that DDNS variables take precedence over standard environment variables"""
  80. self._clear_standard_env()
  81. # Set standard environment variables
  82. os.environ["PYTHONHTTPSVERIFY"] = "0"
  83. # Set conflicting DDNS variables
  84. os.environ["DDNS_SSL"] = "auto"
  85. config = load_config()
  86. # DDNS should take precedence
  87. self.assertEqual(config.get("ssl"), "auto")
  88. # Clean up
  89. del os.environ["DDNS_SSL"]
  90. self._clear_standard_env()
  91. def test_custom_prefix(self):
  92. """Test custom prefix functionality"""
  93. os.environ["CUSTOM_DNS"] = "cloudflare"
  94. os.environ["CUSTOM_ID"] = "[email protected]"
  95. config = load_config(prefix="CUSTOM_")
  96. self.assertEqual(config.get("dns"), "cloudflare")
  97. self.assertEqual(config.get("id"), "[email protected]")
  98. # Clean up
  99. del os.environ["CUSTOM_DNS"]
  100. del os.environ["CUSTOM_ID"]
  101. def test_empty_prefix(self):
  102. """Test empty prefix (loads all environment variables)"""
  103. os.environ["TEST_DNS"] = "cloudflare"
  104. config = load_config(prefix="")
  105. self.assertEqual(config.get("test_dns"), "cloudflare")
  106. del os.environ["TEST_DNS"]
  107. def test_no_matching_environment_variables(self):
  108. """Test behavior when no matching environment variables exist"""
  109. config = load_config()
  110. self.assertEqual(config, {})
  111. def test_whitespace_stripping(self):
  112. """Test that leading and trailing whitespace is stripped from values"""
  113. test_cases = [
  114. (" value ", "value"),
  115. ("\tvalue\t", "value"),
  116. ("\nvalue\n", "value"),
  117. (" value with spaces ", "value with spaces"),
  118. ]
  119. for env_value, expected in test_cases:
  120. os.environ["DDNS_TEST_STRIP"] = env_value
  121. config = load_config(prefix="DDNS_TEST_")
  122. self.assertEqual(config.get("strip"), expected, "Failed for value with whitespace: %r" % env_value)
  123. def test_case_insensitive_prefix_matching(self):
  124. """Test case-insensitive prefix matching"""
  125. os.environ["ddns_dns"] = "cloudflare"
  126. os.environ["DDNS_ID"] = "[email protected]"
  127. config = load_config()
  128. self.assertEqual(config.get("dns"), "cloudflare")
  129. self.assertEqual(config.get("id"), "[email protected]")
  130. def test_invalid_json_array(self):
  131. """Test handling of invalid JSON array format"""
  132. os.environ["DDNS_TEST_INVALID"] = "[invalid"
  133. config = load_config(prefix="DDNS_TEST_")
  134. self.assertEqual(config.get("invalid"), "[invalid") # Should remain as string
  135. def test_malformed_json_arrays(self):
  136. """Test handling of malformed JSON arrays"""
  137. test_cases = [
  138. ("[,]", "[,]"), # Empty elements
  139. ("[unclosed", "[unclosed"), # Unclosed bracket
  140. ("[1,2,3", "[1,2,3"), # Missing closing bracket
  141. ]
  142. for malformed, expected in test_cases:
  143. os.environ["DDNS_TEST_MALFORMED"] = malformed
  144. config = load_config(prefix="DDNS_TEST_")
  145. self.assertEqual(config.get("malformed"), expected)
  146. def test_json_array_edge_cases(self):
  147. """Test JSON array edge cases"""
  148. test_cases = [
  149. ("[]", []), # Empty array
  150. ("[1]", [1]), # Single element
  151. ('["string"]', ["string"]), # Single string
  152. ('[1, "two", 3]', [1, "two", 3]), # Mixed types
  153. ]
  154. for json_array, expected in test_cases:
  155. os.environ["DDNS_TEST_ARRAY"] = json_array
  156. config = load_config(prefix="DDNS_TEST_")
  157. self.assertEqual(config.get("array"), expected)
  158. def test_empty_values_remain_as_strings(self):
  159. """Test that empty values remain as strings"""
  160. os.environ["DDNS_TEST_EMPTY"] = ""
  161. config = load_config(prefix="DDNS_TEST_")
  162. self.assertEqual(config.get("empty"), "")
  163. def test_numeric_and_boolean_strings(self):
  164. """Test that numeric and boolean strings are preserved"""
  165. test_cases = [("123", "123"), ("true", "true"), ("false", "false"), ("3.14", "3.14")]
  166. for value, expected in test_cases:
  167. os.environ["DDNS_TEST_VALUE"] = value
  168. config = load_config(prefix="DDNS_TEST_")
  169. self.assertEqual(config.get("value"), expected)
  170. def test_special_characters_in_values(self):
  171. """Test handling of special characters in values"""
  172. test_cases = [
  173. ("value with spaces", "value with spaces"),
  174. ("value@with#special$chars%", "value@with#special$chars%"),
  175. ("http://example.com:8080", "http://example.com:8080"),
  176. ]
  177. for value, expected in test_cases:
  178. os.environ["DDNS_TEST_SPECIAL"] = value
  179. config = load_config(prefix="DDNS_TEST_")
  180. self.assertEqual(config.get("special"), expected)
  181. def test_regular_comma_values_kept_as_string(self):
  182. """Test that regular comma-separated values are kept as strings"""
  183. os.environ["DDNS_TEST_COMMA"] = "value1,value2,value3"
  184. config = load_config(prefix="DDNS_TEST_")
  185. self.assertEqual(config.get("comma"), "value1,value2,value3")
  186. def test_edge_cases(self):
  187. """Test edge cases"""
  188. # Test with only prefix (should be ignored)
  189. os.environ["DDNS_"] = "ignored"
  190. config = load_config()
  191. self.assertNotIn("", config)
  192. # Clean up
  193. del os.environ["DDNS_"]
  194. def test_mixed_params_config(self):
  195. """Test mixed configuration with different parameter types"""
  196. os.environ["DDNS_DNS"] = "cloudflare"
  197. os.environ["DDNS_IPV4"] = '["domain1.com", "domain2.com"]'
  198. os.environ["DDNS_TTL"] = "300"
  199. os.environ["DDNS_SSL"] = "auto"
  200. config = load_config()
  201. self.assertEqual(config.get("dns"), "cloudflare")
  202. self.assertEqual(config.get("ipv4"), ["domain1.com", "domain2.com"])
  203. self.assertEqual(config.get("ttl"), "300")
  204. self.assertEqual(config.get("ssl"), "auto")
  205. def test_configuration_consistency(self):
  206. """Test that configuration parsing is consistent across different input formats"""
  207. # Test array consistency
  208. os.environ["DDNS_TEST1"] = '["item1", "item2"]'
  209. os.environ["DDNS_TEST2"] = "single_item"
  210. config = load_config(prefix="DDNS_")
  211. self.assertEqual(config.get("test1"), ["item1", "item2"])
  212. self.assertEqual(config.get("test2"), "single_item")
  213. if __name__ == "__main__":
  214. unittest.main()