本帖最后由 八戒你干嘛 于 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被公司网络限制。 bistrofacebook开源的一款分布式任务调度工具, 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. 安装时,依赖的一些资源,国内无法下载,故没安装上; 项目也没怎么维护。 celeryPython开发的一款分布式任务队列(https://github.com/celery/celery),用的人还是蛮多的,github上5k+个star,因为我们的工程是java编写,最好使用有java api的工具,故没使用该工具。 LTSJava开发的一款分布式任务调度工具(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测试类): - // 正则匹配
- String[] filterPatterns = { "com.weibo.qa.testclassfinder.test.*Test" };
- TestClassFinder tcn = new TestClassFinder(filterPatterns);
- System.out.println(tcn.find());
- System.out.println(tcn.classNameList(tcn.find()));
- 输出:
- [class com.weibo.qa.testclassfinder.test.JUnitTest]
- [JUnitTest]
复制代码根据测试类探测器得出的测试类集合,拆分成N个子集(N为执行docker实例的数量): - /**
- * 将testClassName list拆分成TASK_TRACKER_NUM个子list
- *
- * @param testClassName
- * @return
- * @author hugang
- */
- public static List<String> convertClassStr(
- List<String> testClassNameList) {
- if (testClassNameList == null) {
- throw new NullPointerException("the testClassName list is null .");
- }
- if (TASK_TRACKER_NUM <= 0) {
- throw new IllegalArgumentException(
- "TASK_TRACKER_NUM must be more than 0");
- }
- List<List<String>> subListResult = new ArrayList<List<String>>(
- TASK_TRACKER_NUM);
- for (int i = 0; i < TASK_TRACKER_NUM; i++) {
- subListResult.add(new ArrayList<String>());
- }
- int index = 0;
- for (String testClassName : testClassNameList) {
- subListResult.get(index).add(testClassName);
- index = (index + 1) % TASK_TRACKER_NUM;
- }
- List<String> TestClssName = new ArrayList();
- TestClssName = convertFormat(subListResult);
- return TestClssName;
- }
- public static List<String> convertFormat(List<List<String>> subListResult) {
- if (subListResult == null) {
- throw new NullPointerException("the subListResult list is null. ");
- }
- List<String> FromatTestClass = new ArrayList<String>();
- // 将子数组拆分成字符串,数组元素间以逗号分隔 e.g.
- // {["test1","test2"],["test3","test4","test5"]} -> ["test1,test2",
- // "test3,test4,test5"]
- for (int j = subListResult.size() - 1; j != -1; j--) {
- FromatTestClass.add(convertListToString(subListResult.get(j)));
- }
- return FromatTestClass;
- }
- /**
- * 将一个list转成字符串形式, ["test1","test2"] -> "test1,test2"
- * @param testNameList
- * @return
- * @author hugang
- */
- public static String convertListToString(List<String> testNameList){
- if(testNameList == null){
- throw new NullPointerException("the testNameList list is null. ");
- }
- String arrayStr = "";
- String subStr;
- for(int i = 0; i < testNameList.size(); i++){
- subStr = testNameList.get(i);
- if(i != testNameList.size() -1){
- arrayStr += (subStr + ",");
- }else{
- arrayStr += subStr;
- }
- }
- return arrayStr;
- }
复制代码 得到一个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:
- for (String jobTestClass : runTestClassList) {
- submitClassRealtimeJob(jobClient, jobTestClass);
- }
- // 新增测试类参数, 将测试类子集className提交给一个job任务
- private static Response submitClassRealtimeJob(JobClient jobClient,
- String className) {
- Job job = new Job();
- job.setTaskId("run_test_case_realtime_001 " + Math.random());
- job.setParam("className", className);
- job.setTaskTrackerNodeGroup("test_trade_TaskTracker");
- job.setNeedFeedback(true);
- job.setReplaceOnExist(true); // 当任务队列中存在这个任务的时候,是否替换更新
- // 提交任务的状态
- Response response = jobClient.submitJob(job);
- System.out.println(response);
- return response;
- }
复制代码 请跳转至基于 Docker 集群的分布式测试系统 DDT (DockerDistributedTest) 【下】
|