51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 1861|回复: 0
打印 上一主题 下一主题

基于 Docker 集群的分布式测试系统 DDT (DockerDistributedTest) 【中】

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2017-8-9 13:27:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 八戒你干嘛 于 2017-8-9 14:46 编辑

2-2.分布式任务调度工具选型TestNG

早在2006年2月,TestNG 4.5版本中就新增了Distributed TestNG特性,遗憾的是,作者Cedric Beust已经不维护,将Distributed classes移出, 现在的TestNG已不支持Distributed Test。国内有人研究过,有兴趣的可以了解下:http://markshao.github.io/blog/2014/03/01/new-testng/,由于是非官方的,并且也不是很完善,我们没采用他们的方式。

Gearman

入门简单,由worker、client和Job server组成,client发送任务给Job Server,Job Server将任务传送给worker执行并将结果返回给client(http://gearman.org/getting-started/);尝试过,但是不稳定,外网机器调度内网机器或内网机器调度内网机器,会发生无法执行任务的情况,猜测可能是Gearman Protocol被公司网络限制。

bistro

facebook开源的一款分布式任务调度工具, Bistro needs a 64-bit Linux, Folly, FBThrift, boost, and libsqlite3. Caveats: You need about 2GB of RAM to build, as well as GCC 4.8 or above. 安装时,依赖的一些资源,国内无法下载,故没安装上; 项目也没怎么维护。

celery

Python开发的一款分布式任务队列(https://github.com/celery/celery),用的人还是蛮多的,github上5k+个star,因为我们的工程是java编写,最好使用有java api的工具,故没使用该工具。

LTS

Java开发的一款分布式任务调度工具(https://github.com/ltsopensource/light-task-scheduler),提供了完整的文档、使用示例和前端控制台,并且有丰富的java api,可以将调度方有效的结合到测试工程中;故我们使用LTS作为我们分布式测试调度工具; LTS主要由JobClient(负责提交任务,并接受结果)、JobTracker(接收并分配任务)、TaskTracker(执行任务,结果反馈给JobTrack)组成,同时需要配置zookeeper和mysql, 详见github主页LTS用户文档。

3.实现

完整的流程图:




DockerDistributedTest系统由自动化测试工程、用例子集发送器(将测试集自动拆成N个子集)、JobTrack中转站、执行用例Docker集群、测试结果解析器组件构成。

3-1.自动化测试工程

自动化测试工程FastTest, 用例使用TestNG编写,支持http接口测试、rpc服务测试等。

3-2.用例子集发送器

用例子集发送器由JobClient和测试类探测器(https://github.com/neven7/TestClassFinder)组成;

测试类探测器可以根据全限包正则表达匹配出该包下所有的测试类名(JUnit或TestNG测试类):

  1. // 正则匹配
  2. String[] filterPatterns = { "com.weibo.qa.testclassfinder.test.*Test" };
  3. TestClassFinder tcn = new TestClassFinder(filterPatterns);

  4. System.out.println(tcn.find());
  5. System.out.println(tcn.classNameList(tcn.find()));

  6. 输出:
  7. [class com.weibo.qa.testclassfinder.test.JUnitTest]
  8. [JUnitTest]
复制代码

根据测试类探测器得出的测试类集合,拆分成N个子集(N为执行docker实例的数量):

  1. /**
  2. * 将testClassName list拆分成TASK_TRACKER_NUM个子list
  3. *
  4. * @param testClassName
  5. * @return
  6. * @author hugang
  7. */
  8. public static List<String> convertClassStr(
  9.         List<String> testClassNameList) {
  10.     if (testClassNameList == null) {
  11.         throw new NullPointerException("the testClassName list is null .");
  12.     }

  13.     if (TASK_TRACKER_NUM <= 0) {
  14.         throw new IllegalArgumentException(
  15.                 "TASK_TRACKER_NUM must be more than 0");
  16.     }


  17.     List<List<String>> subListResult = new ArrayList<List<String>>(
  18.             TASK_TRACKER_NUM);

  19.     for (int i = 0; i < TASK_TRACKER_NUM; i++) {
  20.         subListResult.add(new ArrayList<String>());
  21.     }

  22.     int index = 0;
  23.     for (String testClassName : testClassNameList) {
  24.         subListResult.get(index).add(testClassName);
  25.         index = (index + 1) % TASK_TRACKER_NUM;
  26.     }

  27.     List<String> TestClssName = new ArrayList();

  28.     TestClssName = convertFormat(subListResult);

  29.     return TestClssName;
  30. }

  31. public static List<String> convertFormat(List<List<String>> subListResult) {
  32.     if (subListResult == null) {
  33.         throw new NullPointerException("the subListResult list is null. ");
  34.     }

  35.     List<String> FromatTestClass = new ArrayList<String>();

  36.     // 将子数组拆分成字符串,数组元素间以逗号分隔 e.g.
  37.     // {["test1","test2"],["test3","test4","test5"]} -> ["test1,test2",
  38.     // "test3,test4,test5"]
  39.     for (int j = subListResult.size() - 1; j != -1; j--) {
  40.         FromatTestClass.add(convertListToString(subListResult.get(j)));
  41.     }

  42.     return FromatTestClass;
  43. }

  44. /**
  45. *  将一个list转成字符串形式, ["test1","test2"] -> "test1,test2"
  46. * @param testNameList
  47. * @return
  48. * @author hugang
  49. */
  50. public static String convertListToString(List<String> testNameList){
  51.     if(testNameList == null){
  52.         throw new NullPointerException("the testNameList list is null. ");
  53.     }

  54.     String arrayStr = "";
  55.     String subStr;
  56.     for(int i = 0; i < testNameList.size(); i++){
  57.         subStr = testNameList.get(i);
  58.         if(i != testNameList.size() -1){
  59.             arrayStr += (subStr + ",");
  60.         }else{
  61.             arrayStr += subStr;
  62.         }
  63.     }

  64.     return arrayStr;
  65. }
复制代码
得到一个list,list每个元素就是每个docker实例需要执行的测试类, 比如有10个测试类"class1,class2,class3,class4,class5,class6,class7,class8,class9,class10",有5个docker实例,则list形如:["class1,class2", "class3,class4", "class5,class6", "class7,class8", "class9,class10"];foreach这个list,将每个元素提交给JobTracker:
  1. for (String jobTestClass : runTestClassList) {
  2.         submitClassRealtimeJob(jobClient, jobTestClass);
  3.     }


  4. // 新增测试类参数, 将测试类子集className提交给一个job任务
  5. private static Response submitClassRealtimeJob(JobClient jobClient,
  6.         String className) {
  7.     Job job = new Job();
  8.     job.setTaskId("run_test_case_realtime_001 " + Math.random());
  9.     job.setParam("className", className);
  10.     job.setTaskTrackerNodeGroup("test_trade_TaskTracker");
  11.     job.setNeedFeedback(true);
  12.     job.setReplaceOnExist(true); // 当任务队列中存在这个任务的时候,是否替换更新
  13.     // 提交任务的状态
  14.     Response response = jobClient.submitJob(job);
  15.     System.out.println(response);
  16.     return response;
  17. }   
复制代码
请跳转至基于 Docker 集群的分布式测试系统 DDT (DockerDistributedTest) 【下】
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-4-25 14:43 , Processed in 0.065478 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表