第6.2节 Android Agent开发<一>
Android Agent介绍
·
Android Agent为完成Android端覆盖率报告的生成,关联用例等功能的服务,本来可以做成微服务的形式,早期由于和iOS端放在了一起,而iOS相关功能无法布置到容器上,就直接使用django开发了一个服务,通过Http接口完成相应的操作。后来功能越来越强大,就将Android和iOS拆分出来,Android agent为Flask框架开发的服务,django无法部署到公司的容器上。
6.2.1 整体架构
目前Android agent的整体架构如下,随着精准测试平台功能的越来越多,Agent的功能也会不断地增加的。
功能介绍:
1,文件模块
为Flask的一个接口模块,主要用来处理Agent对于文件的操作。比如下载项目代码,上传覆盖率文件,下载覆盖率报告,下载构建后的class文件,以及拷贝覆盖率文件等操作。用于精准测试平台与Agent交互的所有文件操作,其中的小技巧:如果文件在同一文件存储服务上,就采用拷贝的方法来代码上传操作,以提高执行速度。
(1)clone文件代码:
class CloneProFromGit(object):
"""
从Git上下载代码
"""
def cloneprofiles(self,gitadr,gitbran,propath):
"""下载或更新指定分支的代码"""
utiloper=Utils()
curpath = os.getcwd()
print("开始Clone项目:"+gitadr)
if not os.path.exists(propath+"XXXXXX"):
os.makedirs(propath)
# clone代码,需要优化一下
if gitbran.find("master")!=-1:
os.system("git clone "+gitadr+" "+propath)
print("Clone代码库,master分支......")
else:
# 切换分支,可能超时
os.system("git clone "+gitadr+" "+propath)
os.chdir(propath)
os.system("git checkout -b "+gitbran+" remotes/origin/"+gitbran)
os.system("git pull")
print("Clone代码库,并更新分支......")
else:
#更新代码库
os.chdir(propath)
os.system("git checkout -b "+gitbran+" remotes/origin/"+gitbran)
os.system("git pull")
print("Clone代码库,代码库已经存在,切换分支:"+gitbran)
return propath
2,覆盖率模块
通过上传构建后的class文件,使用jacococli工具来生成指定的需求的全量覆盖率报告,这样可以防止通过项目构建生成Class文件来生成报告。同时对于增量覆盖率报告有两种处理情况:
(1)对比分支的增量报告,利用开源工具diff-cover来生成增量报告,而后再生成一个汇总页面;核心代码:
# coding=utf-8
import logging
from pathlib import Path
import asyncio, os
import time, sys, shutil
logger=logging.getLogger("AndroidDiffCoverReportOper")
class AndroidDiffCoverReportOper(object):
"""
多线程执行生成diff-cover覆盖率报告,以提高执行速度
@author SXF
@date 2022-05-27
"""
def getReportHeader(self, branch):
"""生成增量覆盖率报告"""
headcontent = '''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="stylesheet" href="resources/report.css" type="text/css"/>
<title>Diff Coverage</title>
</head>
<body>
<h1>Diff Coverage</h1>
'''
headcontent = headcontent + "<p>Diff: " + branch + "...HEAD, staged and unstaged changes</p>\r\n"
return headcontent
def createTotalReport(self, propath, branch, srcfold):
"""
生成最终的汇总报告
"""
reportcontent = "<table class=\"coverage\" cellspacing=\"0\" id=\"coveragetable\">\r\n<thead><tr><th>Pagckages</th><th>Diff Coverage (%) </th><th width=\"100\">Total Lines </th><th width=\"100\">Missing Lines </th></tr></thead>\r\n"
totallines = 0
mislines = 0
index = 0
for sfold in srcfold:
reportcontent = reportcontent + "<tr><td><a href=\"diffreport" + str(
index) + ".html\" class=\"el_package\">" + sfold[
sfold.find("packages"):sfold.find("src") - 1] + "</a> </td>"
diffreport = propath + "diffreport/diffreport" + str(index) + ".html"
dfile = open(diffreport, "r")
lines = dfile.readlines()
if len(lines) < 94:
# diff-cover生成的报告中无数据
reportcontent = reportcontent + "<td colspan='3' class=\"ctr1\">No lines with coverage information in this diff.</td>"
else:
cktotal = ""
ckmisline = ""
ckcovrate = 0
flag = 0
for line in lines:
if line.find("<b>Total</b>") > -1:
cktotal = line[line.find(":") + 1:line.find("line")]
totallines = totallines + int(cktotal.strip())
flag = flag + 1
if line.find("<b>Missing</b>") > -1:
ckmisline = line[line.find(":") + 1:line.find("line")]
mislines = mislines + int(ckmisline.strip())
flag = flag + 1
if line.find("<b>Coverage</b>") > -1:
ckcovrate = int(line[line.find(":") + 1:line.find("%")].strip())
flag = flag + 1
# 统一添加相关数据
if flag == 3:
# 1,覆盖率
miscov = 100 - ckcovrate
reportcontent = reportcontent + "<td class=\"bar\">" + "<img src=\"resources/redbar.gif\" width=\"" + str(
miscov) + "\" height=\"10\">"
reportcontent = reportcontent + "<img src=\"resources/greenbar.gif\" width=\"" + str(
ckcovrate) + "\" height=\"10\"> " + str(ckcovrate) + "%</td>"
# 2,总行数
reportcontent = reportcontent + "<td class=\"ctr1\">" + cktotal + "</td>"
# 3,没有覆盖的行数
reportcontent = reportcontent + "<td class=\"ctr1\">" + ckmisline + "</td>"
reportcontent = reportcontent + "</tr>\r\n"
index = index + 1
reportcontent = reportcontent + "</table>"
# 添加头部信息及汇总信息
covlines = totallines - mislines
if totallines == 0:
covrate=0
else:
covrate = float(covlines) / float(totallines) * 100
headcontent = self.getReportHeader(branch)
headcontent = headcontent + "<ul>\r\n<li><b>Total</b>: " + str(totallines) + " lines</li>\r\n"
headcontent = headcontent + "<li><b>Missing</b>: " + str(mislines) + " lines</li>\r\n"
headcontent = headcontent + "<li><b>Coverage</b>: " + str(round(covrate, 2)) + " %</li>\r\n</ul>\r\n"
reportcontent = headcontent + reportcontent + "\r\n</body>\r\n</html>"
# 汇总报告写入文件
difffolder=propath + "diffreport"
if not os.path.exists(difffolder):
os.makedirs(difffolder)
findreport = difffolder+"/index.html"
rf = open(findreport, "w")
rf.write(reportcontent)
rf.close
logger.info("生成汇总报告:" + findreport)
def getDiffFile(self, propath,branch):
"""获取Diff文件"""
curpath = os.getcwd()
logger.info("getDiffFile中的当前路径:"+curpath)
os.chdir(propath)
gitcmd = "git diff " + branch + "|grep 'diff --git'"
runcmd = os.popen(gitcmd)
fileinfo = runcmd.readlines()
pclist = []
for line in fileinfo:
if (line.find(".kt") > -1 or line.find(".java") > -1):
if (line.find(".kt") > -1):
getfile = line[line.find("a/") + 2:line.find(".kt") + 3]
else:
getfile = line[line.find("a/") + 2:line.find(".java") + 5]
packagepath = getfile[9:getfile.find("/src")]
if not (packagepath in pclist):
pclist.append(packagepath)
# print(pclist)
os.chdir(curpath)
return pclist
def getAllSourcePath(self, propath, branch):
"""
获取项目中的所有源码路径
:param propath:
:return:
"""
sroucepath = []
diffpclist = self.getDiffFile(propath,branch)
folder = Path(propath)
result = list(folder.rglob("src/main/java"))
for ckfile in result:
ckpath = str(ckfile.resolve())
for packinfo in diffpclist:
if ckpath.find(packinfo) > -1:
sroucepath.append(ckpath)
break
# print (sroucepath)
return sroucepath
async def creatDiffReport(self, propath, combran, srcpath, index):
"""
生成增量覆盖率报告
"""
logger.info("开始生成" + srcpath + "的增量报告.........")
jacocoxml = propath + "jacocoTestReport.xml"
diffrepfold = propath + "diffreport"
if not os.path.exists(diffrepfold):
os.makedirs(diffrepfold)
os.chdir(propath)
diffcmd = "diff-cover " + jacocoxml + " --html-report " + diffrepfold + "/diffreport" + str(
index) + ".html --compare-branch " + combran + " --src-roots " + srcpath
proc = await asyncio.create_subprocess_shell(diffcmd)
stdout, stderr = await proc.communicate()
return srcpath + "的增量报告生成完成!"
async def runDiffCreateTask(self, propath, combran, srclist, start):
"""
批量生成报告任务
"""
task_list = []
index = start
loop=asyncio.get_event_loop()
for srcpath in srclist:
task = loop.create_task(self.creatDiffReport(propath, combran, srcpath, index))
task_list.append(task)
index = index + 1
done, pending = await asyncio.wait(task_list, timeout=None)
for done_task in done:
print(done_task.result())
def createDiffCoverReportOfAndroid(self, propath, branch):
"""
生成Android的增量报告
"""
logger.info("*******************开始生成增量报告*********************")
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
srcfold = self.getAllSourcePath(propath, branch)
curpath = os.getcwd()
index = 0
for i in range(len(srcfold)):
# 取子列表,一次并发10个
if index >= len(srcfold):
break
sublist = srcfold[index:index + 10]
loop = asyncio.get_event_loop()
loop.run_until_complete(self.runDiffCreateTask(propath, branch, sublist, index))
index = index + 10
logger.info("所有增量报告生成完成.....")
# 生成汇总报告
self.createTotalReport(propath, branch, srcfold)
logger.info("*******************结束生成增量报告*********************")
#将diffreport打包
os.chdir(propath)
shutil.make_archive("diffreport","zip",'./diffreport')
logger.info("将diffreport打包!")
os.chdir(curpath)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
if __name__ == '__main__':
propath = sys.argv[1]
combranch = sys.argv[2]
crfk = AndroidDiffCoverReportOper()
crfk.createDiffCoverReportOfAndroid(propath, combranch)
(2)对比版本的增量报告,由于diff-cover不支持版本对比,就单独开发了版本对比的功能。通过git diff来获取变更的文件列表,再去过滤全量覆盖率报告,最终生成增量覆盖率报告。核心代码:
# coding=utf-8
import os
import shutil
from datetime import time
from pathlib import Path
from flask import current_app
from AndroidCovAgent.CovRelateOperation.JacocoReportSelectOper import JacocoReportSelectOper
class AndroidComPareCommitsReport(object):
"""
生成Android版本对比覆盖率报告
"""
def selectReportByDiffFiles(self,filelist,jacocorpath,diffreport):
"""
根据diff文件列表,生成相应的增量覆盖率报告文件
:param filelist:
:param jacocorpath:
:return:
"""
for ckfile in filelist:
#解析文件名
ckfname=ckfile[ckfile.rindex("/")+1:ckfile.rindex(".")]
changepath=ckfile[ckfile.index("com"):ckfile.rindex("/")].replace("/",".")
folder=Path(jacocorpath)
result=list(folder.rglob(changepath+"/"+ckfname+"*"))
for ckfile in result:
ckpath=str(ckfile.resolve())
newpath=diffreport+ckpath[ckpath.index("jacoco")+7:ckpath.rindex("/")]
newfilename=ckpath[ckpath.rindex("/")+1:]
if not os.path.exists(newpath):
os.makedirs(newpath)
#拷贝index.html文件
shutil.copy(ckpath[0:ckpath.rindex("/")+1]+"index.html",newpath+"/index.html")
shutil.copy(ckpath,newpath+"/"+newfilename)
# print(ckpath)
def getDiffFile(self, propath,comparecommit):
"""获取Diff文件"""
curpath = os.getcwd()
os.chdir(propath)
gitcmd = "git diff " + comparecommit + "|grep 'diff --git'"
runcmd = os.popen(gitcmd)
fileinfo = runcmd.readlines()
# print(fileinfo)
difffiles = []
for line in fileinfo:
if (line.find(".kt") > -1 or line.find(".java") > -1):
if (line.find(".kt") > -1):
getfile = line[line.find("a/") + 2:line.find(".kt") + 3]
else:
getfile = line[line.find("a/") + 2:line.find(".java") + 5]
if not (getfile in difffiles):
difffiles.append(getfile)
# print(pclist)
os.chdir(curpath)
return difffiles
def createDiffReportByCompareCommits(self,propath,comparecomit):
"""
对比分支,生成增量覆盖率报告
:param propath:
:param comparecomit:
:return:
"""
#获取diff文件列表
difffilelist=self.getDiffFile(propath,comparecomit)
#print(difffilelist)
jacocopath=propath+"jacoco/"
diffrppath=propath+"diffreport/"
if not os.path.exists(diffrppath):
os.makedirs(diffrppath)
#拷贝资源文件到diffreport文件夹中
shutil.copytree(jacocopath+"/jacoco-resources",diffrppath+"/jacoco-resources")
print("创建增量覆盖率文件夹,拷贝资源文件!")
#拷贝增量覆盖率文件相关报告
self.selectReportByDiffFiles(difffilelist,jacocopath,diffrppath)
#修改各个package下的index文件,去掉不是diff中的文件信息
jrsoper=JacocoReportSelectOper()
for i,j,k in os.walk(diffrppath):
for folder in j:
# print("package="+folder)
if folder.find("jacoco-resources")==-1:
packagepath=diffrppath+folder+"/"
jrsoper.correctIndexFile(packagepath)
#生成最终的覆盖率报告
jrsoper.createDiffReport(diffrppath,comparecomit)
print("对比版本:"+comparecomit+"的增量报告生成完成!")
#将全量覆盖率报告打包
curpath=os.getcwd()
os.chdir(propath)
shutil.make_archive("jacoco","zip",'./jacoco')
#将增量报告打包
shutil.make_archive("diffreport","zip",'./diffreport')
os.chdir(curpath)
if __name__=='__main__':
acpcr=AndroidComPareCommitsReport()
propath="/Users/*******/"
acpcr.createDiffReportByCompareCommits(propath,"321ce030db507b72f04da3fa09b9e90e3be7313e")
更多推荐
所有评论(0)