1. 背景
最近负责CTS测试工作,但是经常需要手动去测,且由于系统,网络等原因,测试过程中偶会发生异常,然后需要进行重测。于是想到Jenkins可以代替完成这一系列的自动化工作。
2. Jenkins
Jenkins的Demo在官网Jenkins可以很方便查阅到,较低Ubuntu版本的可以选择使用Apache+jenkins.war的方式进行配置,高版本或者Mac上可以直接通过apt install或brew install的方式安装了。由于在运行时遇到一些异常,所以抛弃了使用Docker方式的配置。
与以往直接跑脚本的配置方式不一样,发现Jenkins支持了一种Groovy形式的pipeline语法,例子如下:
1
2
3
4
5
6
7
8
9
10
pipeline {
agent { docker 'python:3.5.1' }
stages {
stage('build') {
steps {
sh 'python --version'
}
}
}
}
我决定使用了这种形式进行自动化测试搭建。
3. 环境搭建
CTS的测试需要有adb和aapt支持,以及Java版本是11以上,所以配置方面需要先配置环境变量,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
pipeline {
agent any
environment {
// SDK路径,如果安装了Android Studio,可以在SDKManager中查阅
ANDROID_HOME = '...'
// 特别指定了adb,aapt的路径
PATH = "${env.ANDROID_HOME}/platform-tools:${env.ANDROID_HOME}/build-tools/30.0.3:${env.PATH}"
// CTS套件路径,可以在官网下载
CTS_HOME = "..."
}
....
}
如果需要执行脚本获取变量,可以在这样实现:
1
2
3
4
5
6
7
8
9
stages {
stage('Clearing') {
steps {
script {
//获取当前编译时间
env.CTS_BUILD_TIME = sh(script:'date +%Y-%m-%d-%H-%M-%S', returnStdout: true).trim()
}
}
}
4. 测试脚本示例
为了检查之前设置的环境变量是否有设置成功,可以通过printenv方式进行查看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
stages {
stage('Build') {
steps {
sh 'printenv'
}
}
stage('Test') {
steps {
echo 'Testing Stage'
// 运行具体的CTS测试脚本
sh 'xxxx'
}
}
stage('Retry-1') {
steps {
echo 'Retry 1'
// 运行具体的CTS重测脚本
sh 'xxxx'
}
}
}
主要的测试逻辑方式在Test的阶段执行,目的是将CTS测试通过命令行方式跑起来。这里给出具体的测试命令,脚本可以参考实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/python2.7
# -*- coding: UTF-8 -*-
import sys
import os
CTS_HOME=os.environ['HOME'] + '/Workspace/cts/android-cts'
if sys.argv[1] == 'CtsXXXXCaseATestCases':
TEST=sys.argv[1]
TEST_HOME=CTS_HOME
TEST_TYPE='cts'
TEST_TRADEFED='cts-tradefed'
elif sys.argv[1] == 'CtsXXXXCaseBTestCases':
TEST=sys.argv[1]
TEST_HOME=CTS_HOME
TEST_TYPE='cts'
TEST_TRADEFED='cts-tradefed'
# 这里的判断为的是支持扩展,如GTS,VTS等测试项目,使用不同套件
# 默认指定了一台设备,实际可以通过获取当前adb devices设备进行多设备测试
os.system(TEST_HOME + "/tools/" + TEST_TRADEFED + " run " + TEST_TYPE + " -m " + TEST + " --logcat-on-failure --skip-preconditions")
重测流程主要是对照着Session号进行重测,所以必须先得直到Result文件夹中有多少个结果,只要获取到zip包数量,就可以知道上次结果对应的session号,从而主动进行重测操作了,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/python2.7
# -*- coding: UTF-8 -*-
import sys
import os
import time
CTS_HOME=os.environ['HOME'] + '/Workspace/cts/android-cts'
TEST_HOME=CTS_HOME
TEST_TRADEFED='cts-tradefed'
RESULT_COUNTS=0
RESULT_LISTS = []
for item in os.listdir(TEST_HOME + "/results"):
if os.path.isdir(TEST_HOME + "/results/" + item) and item != 'latest':
if os.path.isfile(TEST_HOME + "/results/" + item + '/test_result.xml'):
RESULT_COUNTS += 1
RESULT_LISTS.append(item)
# 获取上次结果的Session号
LAST_SESSION = RESULT_COUNTS - 1
# 当多个测试同时进行时,无法保证最新一次的result对应的session号就是需要重测的session。
# 但是latest对应的session一定是需要重测的session, 所以可以通过排序最新的,然后对比latest软连接的名字
# 得出重测对应的session号
REAL_RESULT_PATH=os.path.basename(os.path.realpath(TEST_HOME + "/results/latest"))
for index, item in enumerate(sorted(RESULT_LISTS)):
if item == REAL_RESULT_PATH:
#LAST_SESSION = LAST_SESSION - 1
LAST_SESSION = index
break
# 根据session执行重测
os.system(TEST_HOME + "/tools/" + TEST_TRADEFED + " run retry --retry " + str(LAST_SESSION) + " --logcat-on-failure " + " -s " + DEVICE_SERIAL)
5. 邮件通知
测试结束后可以通过mailext插件将日志和结果进行发送,具体示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
post {
always {
// 将日志放到result文件夹一起进行压缩
sh "cd ${env.RESULT_HOME}/latest && cp -rf ../../logs/latest/inv* logs && zip -r ${env.WORKSPACE}/${env.EMAIL_ATTACHMENT}-${env.CTS_BUILD_TIME}.zip . && cd -"
emailext(
body: "${env.TEST_CASE} test finished",
subject: "${env.JOB_NAME} - Build # ${env.BUILD_NUMBER}-JENKINS-${env.TEST_CASE}-TEST-REPORT",
// 发送目标可以通过环境变量设置,可以发送给多个收件人,使用逗号分割
to: "${env.EMAIL_TARGET}",
// 作为附件进行发送
attachmentsPattern: "**/${env.EMAIL_ATTACHMENT}-${env.CTS_BUILD_TIME}.zip"
)
// 清理本次附件
sh "rm ${env.WORKSPACE}/${env.EMAIL_ATTACHMENT}-${env.CTS_BUILD_TIME}.zip"
}
}