Monkey测试常用与GUI压测,用来发现应用程序存在的bug。在Linux平台下,如果我们想用GUI压测的方式评估一个桌面环境的稳定性,也可以借鉴Monkey测试的思路,不过Linux平台下并没有一个开箱可用的方案,因此我做了一些探索尝试,总结如下,如有帮助,点个赞吧。(hhhh)
方案设计
父子进程分离
引入多进程的考量
- 增强健壮性,GUI压测进程异常退出时,父进程可以重启子进程。 (执行桌面环境级别的GUI压测的过程中,往往需要打开不限数量的应用程序,容易出现系统内存资源吃满的情况,这种情况下会触发Linux的OOM-Kill机制,OOM-Kill机制会基于OOM-Score指标,终止一些进程,来保证操作系统的可响应性。当OOM-Kill机制导致X11 Server实例重置时,GUI操作将无法执行,进程会因此退出。多进程架构可以通过父进程监控子进程的执行状态,把子进程重启,从而保证GUI压测能够持续进行。)
键鼠控制方案对比
xdotool: GitHub - jordansissel/xdotool: fake keyboard/mouse input, window management, and more
pyautogui: Welcome to PyAutoGUI’s documentation! — PyAutoGUI documentation
xdotool | pyautogui | |
---|---|---|
是否支持Wayland | × | × |
支持键盘输入模拟 | √ | √ |
支持鼠标模拟 | √ | √ |
支持图像识别 | × | √ |
接口实现的方式 | 基于C, X11 API | python(Xlib) |
Github Stars(2023/8/29) | 2.7k | 8.5k |
从扩展性、社区繁荣度、功能完善度和开发成本几个维度考量,选择pyautogui作为键鼠控制方案。
Wayland兼容方案
Wayland协议相比X11更重视安全性,所以协议设计上突出强隔离性,事件的分发由compositor决定,每个client只能收到自己的事件,并且只有获得焦点的窗口才能接收键鼠事件。所以通用的GUI测试方案在Wayland上往往行不通。目前Linux社区里对Wayland下自动化GUI测试的支持,做的比较好的是KDE. KDE的KWayland设计实现了一个extension — FakeInput, 用于扩展支持模拟的键鼠输入。
代码仓库:https://github.com/KDE/kwayland
KDE那一层的关键源码参看src/client/fakeinput.cpp:
|
其中关键的是 org_kde_kwin_fake_input_button
.
org_kde_kwin_fake_input_button 并不是直接定义在项目源码中的接口,而是wayland-scanner基于xml文件生成的。
假设项目构建目录为./build, 则org_kde_kwin_fake_input_button
的源码在 build/src/client/wayland-fake-input-client-protocol.h
.
|
录制回放方案设计
用一个数据结构描述GUI操作,将该对象序列化后存储在本地磁盘,实现录制;回放时,将数据反序列化为事件对象并执行,实现回放。
录制文件的存储处理
Action数据的写入采用 “”即时写 “策略,即每一个数据做一次写入操作,这样做的好处:
- 避免action数据在内存中积压,导致内存资源过度占用;
- 避免测试过程中,进程异常导致数据丢失
保活机制
Monkey GUI压测过程中会出现桌面环境崩溃的异常,导致测试中断,针对这类异常,设计双重保活机制:
机制一:守护进程+负载控制
基本思路:
检查系统负载情况,适时释放系统资源。子进程退出后父进程能重启唤起。
机制二:lightdm自启动
将monkey测试嵌入到lightdm的启动流程中,修改/etc/lightdm/lightdm.conf配置文件。
应用级别的Monkey Test机制
核心点
- 应用启动
- GUI事件过滤
- 窗口管理
实现思路
应用进程的启动采用子进程唤起的方式。
GUI事件基于应用窗口的范围进行过滤。
实现应用级别的monkey测试,需要具备窗口管理的能力,核心接口:
基于窗口管理的接口,我们能做到:
- 获取目标应用窗口的信息,进而实现事件过滤
- 窗口管理(用于窗口位置、大小恢复)
窗口管理用到了一个开源库,参考:GitHub - Kalmat/PyWinCtl: Cross-Platform module to get info on and control windows on screen
如果觉得有用 ,请点个赞吧。Thanks♪(・ω・)ノ