test/framework/scripts/monkey_scenario.py

95 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
import random
from framework.core.logger import get_logger
logger = get_logger("MonkeyTester")
def run_monkey_testing(page, action_count=1000):
"""
全屏幕 Monkey 稳定性测试 (随机流操作)
利用 JS 提取网页内所有的安全交互元素(避开退出、注销、删除等敏感操作),
然后执行随机规模的乱序点击和键盘输入,最后伴随鼠标抛掷。
"""
logger.info(f"🐒 开始执行全局 Monkey 测试,计划乱序攻击交互 {action_count} 次...")
# 增加捕捉页面底层级 JS 控制台报错的能力
def log_page_error(err):
logger.error(f"💥 [Monkey 探测到前端崩溃]: {err}")
# 监听未捕获异常
page.on("pageerror", log_page_error)
# 危险词汇,避免退出登录或产生破坏性删除导致平台主干链路被污染
forbidden_keywords = ['退出', '注销', 'logout', '删除', 'delete', '清理']
# JS 提取页面上的活动区域
js_get_random_element = """
(forbidden) => {
// 大面积收割所有可能挂载事件的锚点
const interactables = Array.from(document.querySelectorAll("button, a, input, textarea, [role='button'], div.p-dropdown, li.p-menuitem"));
const visible = interactables.filter(el => {
const rect = el.getBoundingClientRect();
const style = window.getComputedStyle(el);
return rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.opacity !== '0';
});
const safeElements = visible.filter(el => {
const text = (el.innerText || el.value || el.placeholder || '').toLowerCase();
return !forbidden.some(kw => text.includes(kw));
});
if (safeElements.length > 0) {
const randomIndex = Math.floor(Math.random() * safeElements.length);
return safeElements[randomIndex];
}
return null;
}
"""
success_actions = 0
for i in range(action_count):
try:
# 高频发起,给予微小缓冲节奏
time.sleep(0.3)
# 使用 evaluate_handle 将 JS 节点句柄传回到 Python
element_handle = page.evaluate_handle(js_get_random_element, forbidden_keywords)
# null 在 Python 端 json_value 会被转换为 None但在 Handle 里需谨慎评估
is_valid = page.evaluate("(el) => el !== null && typeof el === 'object' && el.tagName", element_handle)
if is_valid:
tag_name = page.evaluate("el => el.tagName", element_handle).lower()
# 开始随机交互分发
if tag_name in ['input', 'textarea']:
# 随机混沌输入
random_txt = str(random.randint(100, 99999))
element_handle.fill(random_txt, force=True, timeout=1000)
logger.debug(f"[Monkey] ⌨️ 乱序输入框写入: {random_txt}")
else:
# 强硬暴力点击 (抛弃边界验证强制触发底层事件)
element_handle.click(force=True, timeout=1000)
logger.debug(f"[Monkey] 🖱️ 盲击了元素节点: <{tag_name}>")
success_actions += 1
else:
# 找不到靶点则强制滚屏扰动页面布局重绘
distance = random.choice([-600, -300, 300, 600])
page.mouse.wheel(0, distance)
logger.debug(f"[Monkey] 📜 随机视差滚屏了 {distance} px")
except Exception as e:
# Monkey 理念:容忍动作失败,但如果抛出的是框架级失去连接则需汇报
if "Target page, context or browser has been closed" in str(e):
logger.error("🚨 浏览器实例被截断Monkey 测试提前终止!")
break
# logger.debug(f"⚠️ Monkey 第 {i+1} 次挥拍落空: {e}")
pass
# 卸载挂载的全局异常监听,避免影响后续的常规测试
page.remove_listener("pageerror", log_page_error)
logger.info(f"✅ Monkey 测试执行完毕!成功施加了 {success_actions}/{action_count} 次有效随机压力。未探测到毁灭性 Crash。")
return True