- Hook通道全量实现: frida_manager(三模式usb/gadget/remote)、hook_executor(30动作)、event_reporter - 微信Hook脚本 v2.1: wechat_hook_v2.js 消息/联系人/好友/群管理/朋友圈 完整RPC - 真机联调验证: ADB通道启动微信/截图/UI树/点击/发消息 全链路通过 - 54项单元测试全绿: test_frida_manager(14) + test_hook_executor(20) + test_hook_module_api(20) - SDK服务端 116 个API端点全部在线 - 开发文档/进度表更新: Phase 2 进度 90%, 整体 88% Made-with: Cursor
129 lines
5.3 KiB
Python
129 lines
5.3 KiB
Python
"""
|
||
HookExecutor 单元测试 (H31)
|
||
测试 HookExecutor 在 Frida 未连接/已连接 两种状态下的行为。
|
||
使用 Mock 模拟 FridaManager,不需要真机。
|
||
"""
|
||
|
||
import sys
|
||
import os
|
||
import unittest
|
||
from unittest.mock import MagicMock, patch
|
||
|
||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "agent"))
|
||
|
||
from hook.hook_executor import HookExecutor, ACTION_TO_RPC
|
||
from hook.frida_manager import FridaManager
|
||
|
||
|
||
class TestHookExecutorOffline(unittest.TestCase):
|
||
"""FridaManager 未连接时 HookExecutor 应安全返回错误"""
|
||
|
||
def setUp(self):
|
||
self.mgr = MagicMock(spec=FridaManager)
|
||
self.mgr.connected = False
|
||
self.executor = HookExecutor(self.mgr)
|
||
|
||
def test_available_false_when_disconnected(self):
|
||
self.assertFalse(self.executor.available)
|
||
|
||
def test_execute_returns_error_when_disconnected(self):
|
||
result = self.executor.execute("send_message", {"to_id": "test", "content": "hello"})
|
||
self.assertFalse(result["success"])
|
||
self.assertIn("不可用", result["error"])
|
||
self.assertEqual(result["channel"], "hook")
|
||
|
||
def test_supports_known_actions(self):
|
||
for action in ACTION_TO_RPC:
|
||
self.assertTrue(self.executor.supports(action), f"{action} should be supported")
|
||
|
||
def test_supports_returns_false_for_unknown(self):
|
||
self.assertFalse(self.executor.supports("fly_to_moon"))
|
||
|
||
def test_get_status(self):
|
||
self.mgr.get_status.return_value = {"connected": False, "device": None}
|
||
status = self.executor.get_status()
|
||
self.assertFalse(status["available"])
|
||
self.assertIsInstance(status["supported_actions"], list)
|
||
self.assertGreater(len(status["supported_actions"]), 10)
|
||
|
||
|
||
class TestHookExecutorOnline(unittest.TestCase):
|
||
"""FridaManager 已连接时 HookExecutor 应正确路由 RPC 调用"""
|
||
|
||
def setUp(self):
|
||
self.mgr = MagicMock(spec=FridaManager)
|
||
self.mgr.connected = True
|
||
self.mgr.call_rpc.return_value = {"success": True, "message_id": "msg_123"}
|
||
self.executor = HookExecutor(self.mgr)
|
||
|
||
def test_available_true_when_connected(self):
|
||
self.assertTrue(self.executor.available)
|
||
|
||
def test_send_message_routes_to_rpc(self):
|
||
params = {"to_id": "wxid_abc", "content": "hello"}
|
||
result = self.executor.execute("send_message", params)
|
||
self.mgr.call_rpc.assert_called_once_with("sendMessage", params)
|
||
self.assertTrue(result["success"])
|
||
self.assertEqual(result["channel"], "hook")
|
||
|
||
def test_get_contacts_routes_to_rpc(self):
|
||
self.mgr.call_rpc.return_value = {"success": True, "contacts": [], "count": 0}
|
||
result = self.executor.execute("get_contacts", {"limit": 100})
|
||
self.mgr.call_rpc.assert_called_once_with("getContacts", {"limit": 100})
|
||
self.assertTrue(result["success"])
|
||
|
||
def test_unknown_action_returns_error(self):
|
||
result = self.executor.execute("nonexistent_action", {})
|
||
self.assertFalse(result["success"])
|
||
self.assertIn("不支持", result["error"])
|
||
|
||
def test_all_actions_map_to_rpc(self):
|
||
for action, rpc_method in ACTION_TO_RPC.items():
|
||
self.mgr.call_rpc.reset_mock()
|
||
self.mgr.call_rpc.return_value = {"success": True}
|
||
self.executor.execute(action, {"test": True})
|
||
self.mgr.call_rpc.assert_called_once_with(rpc_method, {"test": True})
|
||
|
||
def test_rpc_failure_propagates(self):
|
||
self.mgr.call_rpc.return_value = {"success": False, "error": "微信未运行"}
|
||
result = self.executor.execute("send_message", {"to_id": "x", "content": "y"})
|
||
self.assertFalse(result["success"])
|
||
self.assertEqual(result["error"], "微信未运行")
|
||
|
||
# H19 好友管理动作
|
||
def test_add_friend(self):
|
||
self.mgr.call_rpc.return_value = {"success": True, "user_id": "test_user"}
|
||
result = self.executor.execute("add_friend", {"user_id": "test_user", "message": "hi"})
|
||
self.mgr.call_rpc.assert_called_once_with("addFriend", {"user_id": "test_user", "message": "hi"})
|
||
|
||
def test_accept_friend(self):
|
||
self.mgr.call_rpc.return_value = {"success": True}
|
||
result = self.executor.execute("accept_friend", {"encrypt_username": "v3_xxx", "ticket": "t_xxx"})
|
||
self.assertTrue(result["success"])
|
||
|
||
# H22 群管理动作
|
||
def test_create_group(self):
|
||
self.mgr.call_rpc.return_value = {"success": True}
|
||
result = self.executor.execute("create_group", {"member_ids": ["a", "b"], "topic": "测试群"})
|
||
self.mgr.call_rpc.assert_called_once()
|
||
|
||
def test_invite_to_group(self):
|
||
self.mgr.call_rpc.return_value = {"success": True}
|
||
result = self.executor.execute("invite_to_group", {"group_id": "xxx@chatroom", "member_ids": ["a"]})
|
||
self.assertTrue(result["success"])
|
||
|
||
# H20/H21 朋友圈动作
|
||
def test_post_moments(self):
|
||
self.mgr.call_rpc.return_value = {"success": True, "sns_id": "sns_123"}
|
||
result = self.executor.execute("post_moments", {"content": "今天天气真好"})
|
||
self.assertTrue(result["success"])
|
||
|
||
def test_like_moments(self):
|
||
self.mgr.call_rpc.return_value = {"success": True}
|
||
result = self.executor.execute("like_moments", {"sns_id": "12345"})
|
||
self.assertTrue(result["success"])
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|