3

1 什么是STF

STF(Smartphone Test Farm)是一个开源的web架构应用

  • 用户可以通过浏览器远程操作操作,调试手机应用,在设备上进行测试,实现真正意义的云端使用,调试,测试,管理真机。
  • 可远程调试超过160多个设备,为搭建机器提供了很好的方式
  • github上1万多的star https://github.com/DeviceFarm...

image.png
image.png

<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 架构介绍

image.png

设备端
  • 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 对比美团云真机架构

image.png

  • Agent - 相当于stf的provider
  • 消息中心 - 相当于stf的triproxy
连接手机和Server的枢纽,消息中心主要处理屏幕的操作以及手机的状态变更等消息
  • 数据存储模块 - 相当于stf的RethikDB
数据存储模块用来保存整个平台的数据,例如手机的状态、用户使用记录等。 - RethikDB
  • Server模块 - 服务端,websocket,nignx
Server用来集中管理和调度手机,与OpenSTF结构不同的是,我们的Server端包含Web服务器、Websocket服务器、动态代理以及消息处理服务等部分,Server将用户的访问动态代理到对应的Web服务器和Websocket服务器上,并通过消息处理模块向消息中心传递消息,实现用户与Agent端手机的交互。

4.5 STF 中的消息传递

image.png

在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虚机来安装
参考:
由于参考的文章实在是太多了,没法一一列举出来,敬请谅解

lucy
18 声望7 粉丝