test_cloud_config.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import os
  2. import json
  3. import time
  4. import tempfile
  5. import threading
  6. import unittest
  7. from http.server import HTTPServer, BaseHTTPRequestHandler
  8. from utils.cloud_config import (
  9. compute_config_hash,
  10. fetch_remote_config,
  11. save_local_cache,
  12. load_local_config,
  13. load_remote_or_cache,
  14. )
  15. class MockConfigHTTPHandler(BaseHTTPRequestHandler):
  16. config_payload = [{"identifier": "test_group", "enable": True}]
  17. status_code = 200
  18. def do_GET(self):
  19. self.send_response(self.status_code)
  20. self.send_header("Content-Type", "application/json")
  21. self.end_headers()
  22. response_data = json.dumps(self.config_payload).encode("utf-8")
  23. self.wfile.write(response_data)
  24. def log_message(self, format, *args):
  25. pass # 禁用标准输出日志,保持测试输出简洁
  26. class TestCloudConfig(unittest.TestCase):
  27. @classmethod
  28. def setUpClass(cls):
  29. # 启动本地 Mock HTTP 服务器
  30. cls.server = HTTPServer(("127.0.0.1", 0), MockConfigHTTPHandler)
  31. cls.port = cls.server.server_address[1]
  32. cls.server_thread = threading.Thread(target=cls.server.serve_forever)
  33. cls.server_thread.daemon = True
  34. cls.server_thread.start()
  35. cls.url = f"http://127.0.0.1:{cls.port}/config.json"
  36. @classmethod
  37. def tearDownClass(cls):
  38. cls.server.shutdown()
  39. cls.server.server_close()
  40. def test_compute_config_hash(self):
  41. data1 = {"b": 2, "a": 1}
  42. data2 = {"a": 1, "b": 2}
  43. data3 = {"a": 1, "b": 3}
  44. self.assertEqual(compute_config_hash(data1), compute_config_hash(data2))
  45. self.assertNotEqual(compute_config_hash(data1), compute_config_hash(data3))
  46. def test_fetch_remote_config_success(self):
  47. MockConfigHTTPHandler.config_payload = [{"identifier": "group_a", "enable": True}]
  48. MockConfigHTTPHandler.status_code = 200
  49. data = fetch_remote_config(self.url)
  50. self.assertEqual(data, [{"identifier": "group_a", "enable": True}])
  51. def test_fetch_remote_config_http_error(self):
  52. MockConfigHTTPHandler.status_code = 500
  53. with self.assertRaises(RuntimeError):
  54. fetch_remote_config(self.url)
  55. def test_load_remote_or_cache_success_and_save(self):
  56. MockConfigHTTPHandler.config_payload = [{"identifier": "group_remote", "enable": True}]
  57. MockConfigHTTPHandler.status_code = 200
  58. with tempfile.TemporaryDirectory() as tmp_dir:
  59. cache_path = os.path.join(tmp_dir, "cache.json")
  60. data, hash_val, loaded_remote = load_remote_or_cache(
  61. remote_url=self.url,
  62. local_cache_path=cache_path
  63. )
  64. self.assertTrue(loaded_remote)
  65. self.assertEqual(data, [{"identifier": "group_remote", "enable": True}])
  66. self.assertTrue(os.path.exists(cache_path))
  67. # 验证本地缓存是否被写入
  68. cached_data = load_local_config(cache_path)
  69. self.assertEqual(cached_data, [{"identifier": "group_remote", "enable": True}])
  70. def test_load_remote_or_cache_fallback_to_local(self):
  71. MockConfigHTTPHandler.status_code = 500 # 模拟云端 API 失败
  72. with tempfile.TemporaryDirectory() as tmp_dir:
  73. cache_path = os.path.join(tmp_dir, "cache.json")
  74. # 预先存入本地缓存
  75. save_local_cache(cache_path, [{"identifier": "group_cached", "enable": True}])
  76. data, hash_val, loaded_remote = load_remote_or_cache(
  77. remote_url=self.url,
  78. local_cache_path=cache_path
  79. )
  80. self.assertFalse(loaded_remote)
  81. self.assertEqual(data, [{"identifier": "group_cached", "enable": True}])
  82. if __name__ == "__main__":
  83. unittest.main()