1 什么是STF
STF(Smartphone Test Farm)是一个开源的web架构应用
- 用户可以通过浏览器远程操作操作,调试手机应用,在设备上进行测试,实现真正意义的云端使用,调试,测试,管理真机。
- 可远程调试超过160多个设备,为搭建机器提供了很好的方式
- github上1万多的star https://github.com/DeviceFarm...
<br/>
类似产品:
- AWS Device Farm
- Google Cloud Test Lab
- 百度MTC的远程真机调试
- Testin的云真机
- 腾讯WeTest的云真机
- 阿里MQC的远程真机租用
其中OpenSTF是开源项目,其他的平台大多也都是基于OpenSTF原理实现的
2 为什么需要 STF
2.1 解决测试机的高效利用
- 大家都需要设备,要互相借,还要维护借的表格
- 大家在不同地区
- android设备太多,而且一直有新的
2.2 提高测试效率
- STF提供设备机的CPU,内存,电量等性能的监测
- 对接monkey
- 查看log
- 自动化测试
2.3 测试机器的管理
- 固化测试机器的系统版本,系统设置,不被篡改
- 追踪查看测试机设置的人员
3 STF 功能介绍
3.1 OS 版本支持
- 目前只支持android系统, android 2.3.3 (SDK level 10) to android 10 (SDK level 29)
3.2 通过浏览器远程控制
- 实时屏幕操作和显示。刷新速度可以达到每秒30-40帧,可以旋转屏幕 (minicap)
- 支持从PC键盘输入到android设备
- 支持复制黏贴
- 支持多点触控 (minitouch)
- 拖拽安装,launch apk文件
- 通过minirev,可以直接从Android设备的端口转发本地服务,即便不在一个网段。
- 可以使用任意浏览器访问
- 展示和过滤设备日志。
- 当设备连接到电脑上,且打开adb模式或在一个局域网时,就可以通过adb connnect远程连接调试。
- 可以访问设备的文件系统。
3.3 在web上管理160+设备
- 查看设备状态,可以看到设备的连接状态:连接、离线、不可用(连接信号比较弱)、未授权、未连接
- 查看谁在使用设备
- 可以通过手机号码、IMEI、ICCID、Android系统版本号、运营商、手机型号或者其它属性来搜索设备。
- 检测设备电量
- 展示硬件详情
- 提供API
https://github.com/DeviceFarm...
http://youripaddress:7100/api/v1/devices/
4 STF 架构介绍
4.1 平台语言
- 查页面html使用Pug模版引擎
- 前端使用的是Angularjs
- 后端使用的是Nodejs
- 数据库使用的是对象型数据库Rethinkdb
4.2 主要模块
STF的核心功能可以理解为:“同步图像” + “点击”。前者使用minicap完成,后者依赖minitouch。 具体结构看下图
4.3 架构介绍
设备端
- STF在会在android设备上安装minicap和minitouch。使用minicap来捕获屏幕和使用minitouch来触发多点触控事件,并通过adb使用socket在服务端和设备端进行数据传输。
- STF还会在android设备上安装STFService.apk,它在设备后台运行,提供了一组socket api可以用来监控和执行不同的action。 同理,它也是通过adb和服务端通信,不过它使用的是protocal buffer数据格式。
- minirev,直接从Android设备的端口转发本地服务,即便不在一个网段
服务端
STF的服务端由多个不同的独立的,基于nodejs的微服务组成,这些服务之间是通过ZeroMQ通信。服务端可以进一步分成Provider 层和Application层
Provider 层
- Provider层(stf-provider)主要负责和设备之间进行通信。
- 通过adb来监控设备状态,当有新的设备连接,或者有设备断开则会立刻监控到
- 如果是新的connect设备,则provider会folck一个新的nodejs进程(stf-device), 这个进程主要负责与该设备的所有通信。
- 总体说,stf由两个部分组成,分别是stf-provider和adb
- 另外,需要注意的是,provider层的服务需要跑在物理机上,所有的设备需要连着这台物理机。
Application 层
- application层则是由STF -api、STF -app和STF -auth等微服务组成,这些微服务组成了一个完整的STF
- 从部署的角度来看,这些服务可以跑在任意地方,唯一的要求就是,这些服务能够通过网络和provider通信。这也就是意味着他们需要在同一个网段上
Client 层
- 使用Angular JS实现
- 通过websocket与服务进行通信
4.4 对比美团云真机架构
- Agent - 相当于stf的provider
- 消息中心 - 相当于stf的triproxy
连接手机和Server的枢纽,消息中心主要处理屏幕的操作以及手机的状态变更等消息
- 数据存储模块 - 相当于stf的RethikDB
数据存储模块用来保存整个平台的数据,例如手机的状态、用户使用记录等。 - RethikDB
- Server模块 - 服务端,websocket,nignx
Server用来集中管理和调度手机,与OpenSTF结构不同的是,我们的Server端包含Web服务器、Websocket服务器、动态代理以及消息处理服务等部分,Server将用户的访问动态代理到对应的Web服务器和Websocket服务器上,并通过消息处理模块向消息中心传递消息,实现用户与Agent端手机的交互。
4.5 STF 中的消息传递
在STF中,只要用户点击按钮,这台手机会被标记为占用状态,其他用户立刻就能看到这个最新的状态。同时其他用户也没法使用这个手机。这种即时的消息传递不能靠普通的接口的方式进行,STF中主要是通过ZeroMQ和Protobuf来实现这种即时的消息传递。
4.5.1 ZeroMQ 用到的三个模式
- push/pull是单向模式,消息只能由push端发出,由pull端进行拉取。一般来说pull端对消息进行处理,如果一个pull端不能及时处理,可以同时有多个pull端,这种情况下,一条消息只能被 一个pull端拉取,拉过之后其他pull端就不能再次拉取。如果没有pull端拉取,消息过多的时候可能会溢出。
- publish-subscribe这属于发布订阅模式。与push-pull所不同的,pub会向所有已经连接的sub发消息,如果没有sub连接,消息会被丢弃。
- dealer/router是路由模式,适用于有多个发送端和多个接收端的情况,这样可以实现负载均衡。在stf中,同时有多个用户和多台手机在线,dealer-router很适用于这种情况下的消息传递。
4.5.2 Protocol Buffer
zeromq只是负责消息流的处理,而具体如何组织消息,则是通过其他的方式,stf使用了Protocol Buffer,它是Google的数据交换的格式,与protobuf类似的东西其实是json和xml,protobuff的优势在于更小的体积,这样在大量数据传输的时候节省了带宽资源。与json和xml所不同的是,protobuff自带了一个编译器,protoc,只需要用它进行编译,可以编译成JAVA、python、C++代码,简单来说,它可以生成对应语言的数据类型,比如说生成java的一个类等等。
4.5.3 Websocket
- 启动一个websocket,负责前端页面和服务端通信
4.5.4 Processer
- 连接了设备和前端页面的所有通信
4.5.5 Dev
- 设备单元:文档没有说明,不过看源码,这部分封装了对设备操作的逻辑,譬如实际的apk安装,touch操作,实时显示图像,调用adbkit安装app等逻辑。
4.5.6 Provider
- 给每个设备启动一个work process,负责和设备的通信
4.5.7 Reaper
- reaper进程维护着一个TTLSet,主要负责对超过存活时间的设备进行收割
4.5.8 Triproxy
- triproxy其实是一个三端的消息转发器,它包含三个端口,pull、pub和dealer,分别对应zmq的三种工作模式。triproxy模块最大的用途是模块的解耦。
- 的pull端用来拉取websocket模块或者provider模块的消息,之所以用pull的模式是因为消息从websocket或者provider到triproxy的消息传递是单向的,而push-pull模式可以保证消息传递的可靠性,就是说,如果pull端断开,push端的消息仍然会被保留而不会丢失,直到pull把消息拉走,例如,provider发现一台手机的在线状态发生了改变,就是通过push的方式推给triproxy。
- 而pub端则用来广播消息,广播的特点就是一个发送端可以对应多个接收端,这些接收端可以同时接收到消息,例如设备状态的改变需要广播给所有的websocket模块,进而广播给所有的在线用户。当然广播的另外一个特点是如果广播时客户端不在线,那么这条消息就永远收不到了,因此,广播的消息也可以说是不太重要的消息,比如说如果provider的一台手机没有收到用户占用的消息,最多是用户占用失败,而不会造成太大的影响,而provider占用成功的消息如果用广播的方式就麻烦了,用户没收到占用成功的消息,会继续做占用的操作而不会成功,除非手机超时自动取消占用。
- triproxy和processor的通信是双向,因此用了dealer模式。dealer模式虽然可以一对多,但是一条消息只能唯一的传给一个接收方,就是说如果做了processor扩展,存在多个processor的情况下,同样的消息只会被一个processor处理,这点儿需要注意。
4.5.9 我们通过一个例子看下消息传递的过程。
看看stf是如何发现有新的设备连上usb的
- 设备连上usb
- Provider 发现设备状态发生变化 (监控add,change,remove)
client.trackDevices().then(function(tracker) {
log.info('Tracking devices')
...}
- Provider 通过zmq向processor发送一个protoBuf消息DeviceIntroductionMessage
- Processor 进程收到DeviceIntroductionMessage
- Processor 调用dbapi.saveDeviceInitialState()方法将消息中携带的设备信息保存到rethinkDB
- Processor 向provider发送DeviceRegisteredMessage
- Processor 将DeviceIntroductionMessage广播出去(websocket、reaper)
- Websocket进程收到DeviceIntroductionMessage
- 通过websocket(协议)向前端发送一个’device.add'消息,前端页面会根据该消息更新设备连接状态。
- Provider收到DeviceRegisteredMessage会通过flippedTracker发送一个以deviceId为消息名称的消息,参数为’register’(至此设备注册就算完成了,接下来就是启动device进程)
- Provider 启动device进程,接下来就是设备和device进程之间的监听
- device进程启动成功之后会向父进程发送一个message,内容是'ready',表示device进程启动成功了,至此整个设备连接就已经完成了。
4.6 存在的问题
- 不同android设备的兼容性问题
- 本地 STF 内网穿透公网访问
- provider启动多了,有点耗资源
- 如果对方忘记release 设备,设备会一直被占用,除非认为的把设备拔掉重新连接
- 如果是动态ip的话,会失败,所以需要申请static ip
- 不同地区如果网络弄不好的话,会延迟很厉害
- OpenSTF使用RethikDB作为数据库,RethikDB是一个NoSQL型数据库,它有非常多的缺点,比如处理大量数据时的性能很差,资料非常匮乏,排查问题和数据库维护都非常困难。
4.7 安装的坑
- node.js只支持8.x版本的 ,所以可以用nvm来管理node.js的版本,安装多个node.js
- 设备一直显示disconnect或者preparing,之后disconnect,这是他们的一个bug,当数据线很差当时候会出现。换一条数据线。
- 小米设备需要sim卡打开通过usb安装的权限才可以
- 如果在docker上安装,最好是linux系统,mac上可以装一个linux虚机来安装
参考:
由于参考的文章实在是太多了,没法一一列举出来,敬请谅解
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。