redis_ttl_fix_test.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Redis TTL不同步Bug修复验证测试
  5. 验证修复后的store_file_info函数能够同步更新meta和content的TTL
  6. """
  7. import asyncio
  8. import json
  9. import time
  10. import sys
  11. from pathlib import Path
  12. root_dir = Path(__file__).parent.parent
  13. sys.path.append(str(root_dir))
  14. from foundation.utils.redis_utils import store_file_info, get_file_info
  15. from foundation.base.redis_connection import RedisConnectionFactory
  16. async def test_ttl_sync_fix():
  17. """测试TTL同步修复效果"""
  18. print("[TEST] 开始验证TTL同步修复效果")
  19. try:
  20. redis_store = await RedisConnectionFactory.get_redis_store()
  21. file_id = "test_ttl_fix_file_456"
  22. file_info = {
  23. "file_name": "修复测试文档.pdf",
  24. "file_size": 2048,
  25. "file_content": "这是用于验证修复效果的测试文件内容。" * 100,
  26. "callback_task_id": "original_task",
  27. "upload_time": int(time.time())
  28. }
  29. print("\n=== 步骤1: 存储完整文件信息 ===")
  30. # 存储文件信息,TTL=8秒
  31. success = await store_file_info(file_id, file_info, expire_seconds=8)
  32. assert success, "存储文件信息失败"
  33. # 验证初始TTL同步
  34. meta_ttl = await redis_store.ttl(f"meta:{file_id}")
  35. content_ttl = await redis_store.ttl(f"content:{file_id}")
  36. print(f"初始TTL - meta: {meta_ttl}s, content: {content_ttl}s")
  37. assert abs(meta_ttl - content_ttl) <= 1, "初始TTL应该同步"
  38. print("\n=== 步骤2: 等待2秒后更新callback_task_id ===")
  39. # 等待2秒,让TTL减少
  40. await asyncio.sleep(2)
  41. # 更新callback_task_id,触发TTL同步修复逻辑
  42. update_success = await store_file_info(
  43. file_id,
  44. {'callback_task_id': 'updated_task'},
  45. expire_seconds=15 # 设置更长的TTL
  46. )
  47. assert update_success, "更新callback_task_id失败"
  48. print("\n=== 步骤3: 验证TTL同步修复效果 ===")
  49. # 检查TTL是否同步更新
  50. new_meta_ttl = await redis_store.ttl(f"meta:{file_id}")
  51. new_content_ttl = await redis_store.ttl(f"content:{file_id}")
  52. print(f"更新后TTL - meta: {new_meta_ttl}s, content: {new_content_ttl}s")
  53. # 验证修复效果:两个TTL都应该被重置为15秒左右
  54. assert new_meta_ttl > 12, f"meta的TTL应该被重置为约15秒,实际为{new_meta_ttl}"
  55. assert new_content_ttl > 12, f"content的TTL也应该被重置为约15秒,实际为{new_content_ttl}"
  56. assert abs(new_meta_ttl - new_content_ttl) <= 2, "修复后TTL应该保持同步"
  57. print("[PASS] TTL同步修复验证成功!")
  58. print("\n=== 步骤4: 验证文件内容获取正常 ===")
  59. # 等待一段时间后验证文件内容仍然可以获取
  60. await asyncio.sleep(3)
  61. retrieved_info = await get_file_info(file_id, include_content=True)
  62. assert retrieved_info is not None, "修复后应该能正常获取文件信息"
  63. assert retrieved_info['file_content'] is not None, "修复后文件内容应该存在"
  64. assert retrieved_info['callback_task_id'] == 'updated_task', "callback_task_id应该被正确更新"
  65. print(f"[PASS] 文件信息获取正常,内容长度: {len(retrieved_info['file_content'])}")
  66. print("\n=== 步骤5: 验证长期稳定性 ===")
  67. # 再等待一段时间,验证TTL继续同步
  68. await asyncio.sleep(3)
  69. final_meta_ttl = await redis_store.ttl(f"meta:{file_id}")
  70. final_content_ttl = await redis_store.ttl(f"content:{file_id}")
  71. print(f"最终TTL - meta: {final_meta_ttl}s, content: {final_content_ttl}s")
  72. # TTL差值应该仍然很小
  73. assert abs(final_meta_ttl - final_content_ttl) <= 2, "TTL应该保持同步"
  74. # 文件内容应该仍然可以获取
  75. final_info = await get_file_info(file_id, include_content=True)
  76. assert final_info is not None, "最终应该能获取文件信息"
  77. assert final_info['file_content'] is not None, "最终文件内容应该存在"
  78. print("[PASS] 长期稳定性验证成功!")
  79. print("\n=== 步骤6: 对比修复前后行为 ===")
  80. # 清理测试文件
  81. await redis_store.delete(f"meta:{file_id}", f"content:{file_id}")
  82. # 模拟修复前的错误行为(如果需要对比)
  83. print("修复前行为: meta和content TTL不同步,导致间歇性获取失败")
  84. print("修复后行为: meta和content TTL保持同步,确保稳定获取")
  85. print("[PASS] 修复效果验证完成!")
  86. except Exception as e:
  87. print(f"[FAIL] 测试失败: {e}")
  88. import traceback
  89. traceback.print_exc()
  90. finally:
  91. await RedisConnectionFactory.close_all()
  92. async def test_edge_cases():
  93. """测试边界情况"""
  94. print("\n[TEST] 开始测试边界情况")
  95. try:
  96. redis_store = await RedisConnectionFactory.get_redis_store()
  97. # 测试1: 只有meta没有content的情况
  98. file_id_1 = "test_edge_meta_only"
  99. await redis_store.setex(f"meta:{file_id_1}", 10, json.dumps({"test": "meta_only"}))
  100. success = await store_file_info(file_id_1, {'callback_task_id': 'edge_test'}, expire_seconds=15)
  101. assert success, "只有meta的情况下更新应该成功"
  102. meta_ttl = await redis_store.ttl(f"meta:{file_id_1}")
  103. assert meta_ttl > 12, "meta的TTL应该被更新"
  104. print("[PASS] 只有meta的边界情况测试通过")
  105. await redis_store.delete(f"meta:{file_id_1}")
  106. # 测试2: 新文件存储的正常行为
  107. file_id_2 = "test_edge_new_file"
  108. new_file_info = {
  109. "file_name": "新文件.pdf",
  110. "file_content": "新文件内容",
  111. "callback_task_id": "new_task"
  112. }
  113. success = await store_file_info(file_id_2, new_file_info, expire_seconds=10)
  114. assert success, "新文件存储应该成功"
  115. meta_ttl = await redis_store.ttl(f"meta:{file_id_2}")
  116. content_ttl = await redis_store.ttl(f"content:{file_id_2}")
  117. assert abs(meta_ttl - content_ttl) <= 1, "新文件的TTL应该同步"
  118. print("[PASS] 新文件存储的边界情况测试通过")
  119. await redis_store.delete(f"meta:{file_id_2}", f"content:{file_id_2}")
  120. print("[PASS] 所有边界情况测试通过!")
  121. except Exception as e:
  122. print(f"[FAIL] 边界情况测试失败: {e}")
  123. import traceback
  124. traceback.print_exc()
  125. finally:
  126. await RedisConnectionFactory.close_all()
  127. async def run_fix_validation_tests():
  128. """运行修复验证测试"""
  129. print("=" * 60)
  130. print("Redis TTL不同步Bug修复验证测试")
  131. print("=" * 60)
  132. await test_ttl_sync_fix()
  133. await test_edge_cases()
  134. print("\n" + "=" * 60)
  135. print("[SUCCESS] 所有修复验证测试通过!")
  136. print("=" * 60)
  137. if __name__ == "__main__":
  138. asyncio.run(run_fix_validation_tests())