mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 10:42:25 +08:00
395 lines
12 KiB
Python
395 lines
12 KiB
Python
![]() |
"""
|
|||
|
資源管理器測試模組
|
|||
|
|
|||
|
測試 ResourceManager 類的各項功能,包括:
|
|||
|
- 臨時文件和目錄管理
|
|||
|
- 進程註冊和清理
|
|||
|
- 自動清理機制
|
|||
|
- 資源統計和監控
|
|||
|
"""
|
|||
|
|
|||
|
import pytest
|
|||
|
import os
|
|||
|
import sys
|
|||
|
import time
|
|||
|
import tempfile
|
|||
|
import subprocess
|
|||
|
import threading
|
|||
|
from pathlib import Path
|
|||
|
from unittest.mock import patch, MagicMock
|
|||
|
|
|||
|
# 添加 src 目錄到 Python 路徑
|
|||
|
sys.path.insert(0, 'src')
|
|||
|
|
|||
|
from mcp_feedback_enhanced.utils.resource_manager import (
|
|||
|
ResourceManager,
|
|||
|
get_resource_manager,
|
|||
|
create_temp_file,
|
|||
|
create_temp_dir,
|
|||
|
register_process,
|
|||
|
cleanup_all_resources
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
class TestResourceManager:
|
|||
|
"""資源管理器測試類"""
|
|||
|
|
|||
|
def setup_method(self):
|
|||
|
"""每個測試方法前的設置"""
|
|||
|
# 重置單例實例
|
|||
|
ResourceManager._instance = None
|
|||
|
|
|||
|
def test_singleton_pattern(self):
|
|||
|
"""測試單例模式"""
|
|||
|
rm1 = ResourceManager()
|
|||
|
rm2 = ResourceManager()
|
|||
|
rm3 = get_resource_manager()
|
|||
|
|
|||
|
assert rm1 is rm2
|
|||
|
assert rm2 is rm3
|
|||
|
assert id(rm1) == id(rm2) == id(rm3)
|
|||
|
|
|||
|
def test_create_temp_file(self):
|
|||
|
"""測試創建臨時文件"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 測試基本創建
|
|||
|
temp_file = rm.create_temp_file(suffix=".txt", prefix="test_")
|
|||
|
|
|||
|
assert isinstance(temp_file, str)
|
|||
|
assert os.path.exists(temp_file)
|
|||
|
assert temp_file.endswith(".txt")
|
|||
|
assert "test_" in os.path.basename(temp_file)
|
|||
|
assert temp_file in rm.temp_files
|
|||
|
|
|||
|
# 清理
|
|||
|
os.remove(temp_file)
|
|||
|
|
|||
|
def test_create_temp_dir(self):
|
|||
|
"""測試創建臨時目錄"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 測試基本創建
|
|||
|
temp_dir = rm.create_temp_dir(suffix="_test", prefix="test_")
|
|||
|
|
|||
|
assert isinstance(temp_dir, str)
|
|||
|
assert os.path.exists(temp_dir)
|
|||
|
assert os.path.isdir(temp_dir)
|
|||
|
assert temp_dir.endswith("_test")
|
|||
|
assert "test_" in os.path.basename(temp_dir)
|
|||
|
assert temp_dir in rm.temp_dirs
|
|||
|
|
|||
|
# 清理
|
|||
|
os.rmdir(temp_dir)
|
|||
|
|
|||
|
def test_convenience_functions(self):
|
|||
|
"""測試便捷函數"""
|
|||
|
# 測試 create_temp_file 便捷函數
|
|||
|
temp_file = create_temp_file(suffix=".log", prefix="conv_")
|
|||
|
assert isinstance(temp_file, str)
|
|||
|
assert os.path.exists(temp_file)
|
|||
|
assert temp_file.endswith(".log")
|
|||
|
|
|||
|
# 測試 create_temp_dir 便捷函數
|
|||
|
temp_dir = create_temp_dir(suffix="_conv", prefix="conv_")
|
|||
|
assert isinstance(temp_dir, str)
|
|||
|
assert os.path.exists(temp_dir)
|
|||
|
assert os.path.isdir(temp_dir)
|
|||
|
|
|||
|
# 清理
|
|||
|
os.remove(temp_file)
|
|||
|
os.rmdir(temp_dir)
|
|||
|
|
|||
|
def test_register_process_with_popen(self):
|
|||
|
"""測試註冊 Popen 進程"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建一個簡單的進程
|
|||
|
process = subprocess.Popen(
|
|||
|
["python", "-c", "import time; time.sleep(0.1)"],
|
|||
|
stdout=subprocess.PIPE,
|
|||
|
stderr=subprocess.PIPE
|
|||
|
)
|
|||
|
|
|||
|
# 註冊進程
|
|||
|
pid = rm.register_process(process, description="測試進程")
|
|||
|
|
|||
|
assert pid == process.pid
|
|||
|
assert pid in rm.processes
|
|||
|
assert rm.processes[pid]["description"] == "測試進程"
|
|||
|
assert rm.processes[pid]["process"] is process
|
|||
|
|
|||
|
# 等待進程結束
|
|||
|
process.wait()
|
|||
|
|
|||
|
def test_register_process_with_pid(self):
|
|||
|
"""測試註冊 PID"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 使用當前進程的 PID
|
|||
|
current_pid = os.getpid()
|
|||
|
|
|||
|
# 註冊 PID
|
|||
|
registered_pid = rm.register_process(current_pid, description="當前進程")
|
|||
|
|
|||
|
assert registered_pid == current_pid
|
|||
|
assert current_pid in rm.processes
|
|||
|
assert rm.processes[current_pid]["description"] == "當前進程"
|
|||
|
assert rm.processes[current_pid]["process"] is None
|
|||
|
|
|||
|
def test_unregister_temp_file(self):
|
|||
|
"""測試取消臨時文件追蹤"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建臨時文件
|
|||
|
temp_file = rm.create_temp_file()
|
|||
|
assert temp_file in rm.temp_files
|
|||
|
|
|||
|
# 取消追蹤
|
|||
|
result = rm.unregister_temp_file(temp_file)
|
|||
|
assert result is True
|
|||
|
assert temp_file not in rm.temp_files
|
|||
|
|
|||
|
# 再次取消追蹤(應該返回 False)
|
|||
|
result = rm.unregister_temp_file(temp_file)
|
|||
|
assert result is False
|
|||
|
|
|||
|
# 清理
|
|||
|
if os.path.exists(temp_file):
|
|||
|
os.remove(temp_file)
|
|||
|
|
|||
|
def test_unregister_process(self):
|
|||
|
"""測試取消進程追蹤"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 註冊進程
|
|||
|
current_pid = os.getpid()
|
|||
|
rm.register_process(current_pid, description="測試進程")
|
|||
|
assert current_pid in rm.processes
|
|||
|
|
|||
|
# 取消追蹤
|
|||
|
result = rm.unregister_process(current_pid)
|
|||
|
assert result is True
|
|||
|
assert current_pid not in rm.processes
|
|||
|
|
|||
|
# 再次取消追蹤(應該返回 False)
|
|||
|
result = rm.unregister_process(current_pid)
|
|||
|
assert result is False
|
|||
|
|
|||
|
def test_cleanup_temp_files(self):
|
|||
|
"""測試清理臨時文件"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建多個臨時文件
|
|||
|
temp_files = []
|
|||
|
for i in range(3):
|
|||
|
temp_file = rm.create_temp_file(prefix=f"cleanup_test_{i}_")
|
|||
|
temp_files.append(temp_file)
|
|||
|
|
|||
|
# 確認文件都存在
|
|||
|
for temp_file in temp_files:
|
|||
|
assert os.path.exists(temp_file)
|
|||
|
assert temp_file in rm.temp_files
|
|||
|
|
|||
|
# 執行清理(max_age=0 清理所有文件)
|
|||
|
cleaned_count = rm.cleanup_temp_files(max_age=0)
|
|||
|
|
|||
|
assert cleaned_count == 3
|
|||
|
for temp_file in temp_files:
|
|||
|
assert not os.path.exists(temp_file)
|
|||
|
assert temp_file not in rm.temp_files
|
|||
|
|
|||
|
def test_cleanup_temp_dirs(self):
|
|||
|
"""測試清理臨時目錄"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建多個臨時目錄
|
|||
|
temp_dirs = []
|
|||
|
for i in range(2):
|
|||
|
temp_dir = rm.create_temp_dir(prefix=f"cleanup_test_{i}_")
|
|||
|
temp_dirs.append(temp_dir)
|
|||
|
|
|||
|
# 確認目錄都存在
|
|||
|
for temp_dir in temp_dirs:
|
|||
|
assert os.path.exists(temp_dir)
|
|||
|
assert temp_dir in rm.temp_dirs
|
|||
|
|
|||
|
# 執行清理
|
|||
|
cleaned_count = rm.cleanup_temp_dirs()
|
|||
|
|
|||
|
assert cleaned_count == 2
|
|||
|
for temp_dir in temp_dirs:
|
|||
|
assert not os.path.exists(temp_dir)
|
|||
|
assert temp_dir not in rm.temp_dirs
|
|||
|
|
|||
|
def test_cleanup_all(self):
|
|||
|
"""測試全面清理"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建各種資源
|
|||
|
temp_file = rm.create_temp_file(prefix="cleanup_all_")
|
|||
|
temp_dir = rm.create_temp_dir(prefix="cleanup_all_")
|
|||
|
|
|||
|
# 註冊進程
|
|||
|
current_pid = os.getpid()
|
|||
|
rm.register_process(current_pid, description="測試進程", auto_cleanup=False)
|
|||
|
|
|||
|
# 執行全面清理
|
|||
|
results = rm.cleanup_all()
|
|||
|
|
|||
|
assert isinstance(results, dict)
|
|||
|
assert "temp_files" in results
|
|||
|
assert "temp_dirs" in results
|
|||
|
assert "processes" in results
|
|||
|
assert "file_handles" in results
|
|||
|
|
|||
|
# 檢查文件和目錄是否被清理
|
|||
|
assert not os.path.exists(temp_file)
|
|||
|
assert not os.path.exists(temp_dir)
|
|||
|
assert temp_file not in rm.temp_files
|
|||
|
assert temp_dir not in rm.temp_dirs
|
|||
|
|
|||
|
# 進程不應該被清理(auto_cleanup=False)
|
|||
|
assert current_pid in rm.processes
|
|||
|
|
|||
|
def test_get_resource_stats(self):
|
|||
|
"""測試獲取資源統計"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建一些資源
|
|||
|
temp_file = rm.create_temp_file()
|
|||
|
temp_dir = rm.create_temp_dir()
|
|||
|
rm.register_process(os.getpid(), description="統計測試")
|
|||
|
|
|||
|
# 獲取統計
|
|||
|
stats = rm.get_resource_stats()
|
|||
|
|
|||
|
assert isinstance(stats, dict)
|
|||
|
assert "current_temp_files" in stats
|
|||
|
assert "current_temp_dirs" in stats
|
|||
|
assert "current_processes" in stats
|
|||
|
assert "temp_files_created" in stats
|
|||
|
assert "temp_dirs_created" in stats
|
|||
|
assert "auto_cleanup_enabled" in stats
|
|||
|
|
|||
|
assert stats["current_temp_files"] >= 1
|
|||
|
assert stats["current_temp_dirs"] >= 1
|
|||
|
assert stats["current_processes"] >= 1
|
|||
|
|
|||
|
# 清理
|
|||
|
os.remove(temp_file)
|
|||
|
os.rmdir(temp_dir)
|
|||
|
|
|||
|
def test_get_detailed_info(self):
|
|||
|
"""測試獲取詳細信息"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建一些資源
|
|||
|
temp_file = rm.create_temp_file(prefix="detail_test_")
|
|||
|
rm.register_process(os.getpid(), description="詳細信息測試")
|
|||
|
|
|||
|
# 獲取詳細信息
|
|||
|
info = rm.get_detailed_info()
|
|||
|
|
|||
|
assert isinstance(info, dict)
|
|||
|
assert "temp_files" in info
|
|||
|
assert "temp_dirs" in info
|
|||
|
assert "processes" in info
|
|||
|
assert "stats" in info
|
|||
|
|
|||
|
assert temp_file in info["temp_files"]
|
|||
|
assert os.getpid() in info["processes"]
|
|||
|
assert info["processes"][os.getpid()]["description"] == "詳細信息測試"
|
|||
|
|
|||
|
# 清理
|
|||
|
os.remove(temp_file)
|
|||
|
|
|||
|
def test_configure(self):
|
|||
|
"""測試配置功能"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 測試配置更新
|
|||
|
rm.configure(
|
|||
|
auto_cleanup_enabled=False,
|
|||
|
cleanup_interval=120,
|
|||
|
temp_file_max_age=1800
|
|||
|
)
|
|||
|
|
|||
|
assert rm.auto_cleanup_enabled is False
|
|||
|
assert rm.cleanup_interval == 120
|
|||
|
assert rm.temp_file_max_age == 1800
|
|||
|
|
|||
|
# 測試最小值限制
|
|||
|
rm.configure(
|
|||
|
cleanup_interval=30, # 小於最小值 60
|
|||
|
temp_file_max_age=100 # 小於最小值 300
|
|||
|
)
|
|||
|
|
|||
|
assert rm.cleanup_interval == 60 # 應該被限制為最小值
|
|||
|
assert rm.temp_file_max_age == 300 # 應該被限制為最小值
|
|||
|
|
|||
|
def test_cleanup_all_convenience_function(self):
|
|||
|
"""測試全面清理便捷函數"""
|
|||
|
# 創建一些資源
|
|||
|
temp_file = create_temp_file(prefix="conv_cleanup_")
|
|||
|
temp_dir = create_temp_dir(prefix="conv_cleanup_")
|
|||
|
|
|||
|
# 執行清理
|
|||
|
results = cleanup_all_resources()
|
|||
|
|
|||
|
assert isinstance(results, dict)
|
|||
|
assert not os.path.exists(temp_file)
|
|||
|
assert not os.path.exists(temp_dir)
|
|||
|
|
|||
|
def test_error_handling(self):
|
|||
|
"""測試錯誤處理"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 測試創建臨時文件時的錯誤處理
|
|||
|
with patch('tempfile.mkstemp', side_effect=OSError("Mock error")):
|
|||
|
with pytest.raises(OSError):
|
|||
|
rm.create_temp_file()
|
|||
|
|
|||
|
# 測試創建臨時目錄時的錯誤處理
|
|||
|
with patch('tempfile.mkdtemp', side_effect=OSError("Mock error")):
|
|||
|
with pytest.raises(OSError):
|
|||
|
rm.create_temp_dir()
|
|||
|
|
|||
|
def test_file_handle_registration(self):
|
|||
|
"""測試文件句柄註冊"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 創建一個文件句柄
|
|||
|
temp_file = rm.create_temp_file()
|
|||
|
with open(temp_file, 'w') as f:
|
|||
|
f.write("test")
|
|||
|
rm.register_file_handle(f)
|
|||
|
|
|||
|
# 檢查是否註冊成功
|
|||
|
assert len(rm.file_handles) > 0
|
|||
|
|
|||
|
# 清理
|
|||
|
os.remove(temp_file)
|
|||
|
|
|||
|
def test_auto_cleanup_thread(self):
|
|||
|
"""測試自動清理線程"""
|
|||
|
rm = get_resource_manager()
|
|||
|
|
|||
|
# 確保自動清理已啟動
|
|||
|
assert rm.auto_cleanup_enabled is True
|
|||
|
assert rm._cleanup_thread is not None
|
|||
|
assert rm._cleanup_thread.is_alive()
|
|||
|
|
|||
|
# 測試停止自動清理
|
|||
|
rm.stop_auto_cleanup()
|
|||
|
assert rm._cleanup_thread is None
|
|||
|
|
|||
|
# 重新啟動
|
|||
|
rm.configure(auto_cleanup_enabled=True)
|
|||
|
assert rm._cleanup_thread is not None
|
|||
|
|
|||
|
|
|||
|
if __name__ == '__main__':
|
|||
|
# 運行測試
|
|||
|
pytest.main([__file__, '-v'])
|