八戒你干嘛 发表于 2017-6-15 13:17:16

基于集成 jenkins 的测试平台

(一)先看测试业务的情况:
有各种各样的任务需要通过jenkins调度执行,这里包括代码构建、部署搭建、单元测试、功能自动化测试(包括许多模块的功能自动化测试,有十几个居多),性能测试、正确性验证;复杂一点的是这些任务在不同的测试阶段中都必须部署一套,一般测试至少都需要有三套环境:dailyrun环境、两套test环境用来测试不同版本。要做到持续集成,则每天晚上都需要运行所有的构建、部署、ut、ft、性能、正确性,这些任务达到五十五个,而且彼此之间存在依赖关系的,总是要先编译再部署,功能测试则由于资源有限不得不也做成前后依赖模式,占用资源比较多的分开运行。
问题有:
      (1)原本使用jenkins默认的任务依赖模式,修改任务调度次序的时候就会很悲剧,每个回归都需要从头到尾的修改一次;
(2)当前一个任务由于各种原因超时或者是执行失败的时候后面所有任务都等待,到了第二天要手工全部杀掉,否则无法运行;
(3)任务过多以后查找也很麻烦,难以找到对应任务的链接,每次翻都翻到手痛;遇到版本发布更痛苦,每个jenkins任务中git地址的版本都需要修改。
(4)测试结果用邮件发送的,没有地方可以看到全部回归的整体情况,比如某天挂了,并不能立即知道是build阶段、deploy阶段、ut阶段或者是ft的具体某个阶段的问题,还是要一层层去调查;
(二)我们的解决方案:
首先,这个系统要能够替代jenkins的任务依赖关系,在修改任务依赖的时候可以通过全局配置,这样解除掉问题1;
其次,每个任务设置超时时间去监控jenkins执行情况,当超时的时候杀死掉当前任务,同时不影响下面任务的执行,这就解决问题2;
第三,把jenkins信息和每个阶段信息存放到mysql中,其中配置修改直接通过调用jenkins api,修改git地址,修改配置相关信息,这样就解决问题3;
第四,当第一个任务做完以后,调度独立以后,可以获取到每个阶段执行是否成功的情况,测试报告同时上传到mysql数据库中,前端再用个web系统展示。
jenkins 提供了一整套api体系,可以触发任务,获取任务状态,可修改任务配置,将这些调用串起来。
      为了能有效利用回归机器资源,设置机器池子,运行jenkins任务的时候从池子中随机获取机器进行下发,这样全部配置信息都来自于数据库中,规避测试过程中各种配置不对的情况。
      一个tip对于jenkins slave机器本身,使用ssh模式启动,jenkins master会通过监控手段确保slave failover操作,当slave挂的时候master会启动,不需要人工操作。
      下面是任务依赖的配置
[
      [{"jobname":"Cupid","slave":"TEST3-JK-10"}],
      [{"jobname":"Cupid-HiveTest","slave":"TEST3-JK-1"}],
      [{"jobname":"git-console","slave":"TEST3-JK-10.1"}],
      [{"jobname":"git-console-public","slave":"TEST3-2"}],
      [{"jobname":"OpenMrLocal","slave":"TEST3-JK-10"}],
      [{"jobname":"OpenMrOnLot","slave":"TEST3-JK-10"}],
      [{"jobname":"Graph","slave":"TEST3-JK-1222"}],
      [{"jobname":"MR","slave":"TEST3-JK-101"}],
      [{"jobname":"SqlTask-Finance","slave":"TEST3-JK-1180"}],
      [{"jobname":"SqlTask-Lot","slave":"TEST3-JK-1010"}],
      [{"jobname":"Moye","slave":"TEST3-JK-10"}],
      [{"jobname":"Security","slave":"TEST3-JK-1"}],
      [{"jobname":"SqlTask-Chinese","slave":"TEST3-JK-1"}],
      [{"jobname":"SqlTask-ServiceMode","slave":"TEST3-JK-1"}],
      [{"jobname":"SqlTask-Taobao","slave":"TEST3-JK-1"}],
      [{"jobname":"XLib","slave":"TEST3-JK-1"}],
      [{"jobname":"RESTFulAPI","slave":"TEST3-JK-1"},{"jobname":"RESTFulAPI-AdminTask","slave":"TEST3-JK-1"},{"jobname":"RESTFulAPI-Event","slave":"TEST3-JK-1"}],
      [{"jobname":"CopyTask","slave":"Test-1"}],
      [{"jobname":"ReplicationTask","slave":"Test-10"}],
      [{"jobname":"MetaTest-FromFinance","slave":"TEST3-JK-1"}],
      [{"jobname":"Console-UT","slave":"TEST3-JK-1693"}],
      [{"jobname":"SDK-UT","slave":"TEST3-JK-100"}],
      [{"jobname":"PL-492","slave":"1"}],
      [{"jobname":"FT-gcc492","slave":"Test-vm-13"}],
      [{"jobname":"RESTApi-FT","slave":"Test-vm-13"}],
      [{"jobname":"FT","slave":"Test-vm-10"}],
      [{"jobname":"Api-FT-gcc492","slave":"Test-vm-1"}],
      [{"jobname":"CppSdk-FT-gcc492","slave":"Test-vm-1"}],
      [{"jobname":"OldSdk-FT-gcc492","slave":"Test-vm-1"}],
      [{"jobname":"Lot","slave":"TEST3-JK-1"}]
]
该配置文件中用逗号分隔的表示任务是并行执行的关系,放在一个中括号里面用大括号分隔表示其前后存在依赖关系,执行完毕前面的才是后面的。下面是调用这个配置的主程序入口,这里的startbuilds会去读取任务配置,API是对各种jenkins api的包装
if __name__ == "__main__":
    print "start job dependencies"
    if len(sys.argv) < 2:
      print "please input the jobName"
      exit(1)

    args = sys.argv
    print "jobName===>"+args
    api = jenkins.API()

    stime= common.getNow()
    api.startbuild(args)<code></code>python对jenkins api有专门支持的包jenkinsapi,在此基础上面进行集成是非常的方便的。
下面的函数对jenkins里面的git配置进行修改
def modify_branch(jobname,new_branch):
    print(jobname)
    if jobname=="None" or jobname is None :
      return
    jkserver=jenkins.API().get_jenkins_instance()
    job=jkserver.get_job(jobname)
    try:
      branch=job.get_scm_branch()
    except Exception,e:
      print e
      return
    print(branch)
    job.modify_scm_branch(new_branch)
    branch=job.get_scm_branch()
    print(branch)<code></code>下面这段代码可以直接获取到jenkins机器信息
def get_job_slave(groupname,jobname):
    jkserver=jenkins.API().get_jenkins_instance()
    job=jkserver.get_job(jobname)
    jobconfig = job.get_config()
    tree = Etree.fromstring(jobconfig)
    roamnode = tree.findall("./canRoam")
    if roamnode != None:
      roamnode.text="false"
    nodes = tree.findall("./assignedNode")
    print nodes
    if nodes == None or len(nodes)==0:
      tree.append(Etree.fromstring('<assignedNode>'+slave+'</assignedNode>'))
    else:
      node = nodes
      print(node.text)
    return node.text
(三)运行结果收集
      测试运行结果收集这块,测试平台提供一个restful接口,每个模块的报告最后调用一下这个接口,首先把自己的报告上传到远程的一个ftp上面,然后再把模块名称、环境名称、成功失败用例个数,这些信息上报上去,接口会存放这些信息到数据库中,在前端webserver予以展示。

悠悠小仙仙 发表于 2017-6-15 13:24:13

学习

八戒你干嘛 发表于 2017-6-15 13:24:54

悠悠小仙仙 发表于 2017-6-15 13:24
学习

:victory:
页: [1]
查看完整版本: 基于集成 jenkins 的测试平台