最终项目夭折了,原因在于选型会议选择了另外一个工具基础上二次开发,另外一个原因是其实本身没有那么多自动化用例的日志可供分析。我们不是平台部门,是个小业务部门
计划与交付件
聚焦核心诉求,降低界面可视化等优先级。
【用例优化建议:kw、参数等提取抽象】
时间 |
进度 |
交付件 |
4.09 |
方案、技术选型、元数据 |
总体设计方案.pptx |
5.25 |
采集、传输、存储 |
Only Code |
6.01 |
统计、可视化 |
RF、Cloud Test执行结果统计展示 |
7.20 |
整合被测应用日志、时间同步 |
关联展示日志片段 |
8.10 |
人工打Tag |
聚类展示 |
9.07 |
智能诊断用例失败原因 |
推测失败原因、提示历史解决方案 |
10.19 |
频繁项集挖掘与聚类算法 |
相近用例步骤、demo用例提示 |
11.09 |
铺开测试、高斯异常检测 |
最终展示 |
11.16 |
提供error日志对应用例 |
辅助精准化测试接口 |
11.23 |
提供精益看板数据 |
执行(历史)结果数据接口 |
方案与计划
采集使用flume,传输协议就avro,同时存储在hdfs和kafka中
flume简单笔记
source有两类:
- 驱动型source:是外部主动发送数据给Flume,驱动Flume接受数据。
- 轮询source:是Flume周期性主动去获取数据。
日志类型
- linux系统日志
- web
- was
- tomcat
- jetty
测试工具日志
RobotFramework
原生单进程pybot
在所有用例执行完后,会生成output.xml,解析xml能获取各用例的执行。非实时。
jobsubmit用例级并行
在各自进程中系统调用pybot执行用例,解析output.xml生成执行结果,准实时。
推送方式
数据清洗放在最早的此处
【TODO】未定
- flume配置源为http,解析json
- flume配置源为avro,解析用例结果的代码推avro请求
- flume配置元为exec,调用解析代码,output存chanel
- 解析代码推二进制到kafka,然后转储到hdfs
CloudTest
协议自动化
avro结构定义
表结构
项目表project
field |
type |
comment |
id |
int |
自增id |
name |
varchar(256) |
项目名 |
responsible |
varchar(128) |
责任人 |
create_date |
datetime |
创建时间 |
|
|
|
任务表task
field |
type |
comment |
id |
int |
自增id |
name |
varchar(256) |
任务名/taskId |
responsible |
varchar(128) |
责任人 |
create_date |
datetime |
创建时间 |
project_id |
int |
项目表的id |
|
|
|
测试套表test_suite
field |
type |
comment |
id |
int |
自增id |
name |
varchar(256) |
测试套名 |
long_name |
varchar(2048) |
从顶往下的长测试套名 |
project_id |
int |
项目表的id |
|
|
|
|
|
|
测试用例表test_case
field |
type |
comment |
id |
int |
自增id |
name |
varchar(256) |
测试套名 |
long_name |
varchar(2048) |
从顶往下的长测试套名 |
project_id |
int |
项目表的id |
|
|
|
|
|
|
测试步骤
kw,参数、报错信息
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| package com.huawei.unistar.ailog.domain; import javax.persistence.*; @Entity public class Suite { public Suite() { } public Suite(Integer id, Integer projectId, String name, String doc) { this.id = id; this.projectId = projectId; this.name = name; this.doc = doc; } @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private Integer projectId; @Column(nullable = false) private String name; @Column(length = 4096) private String doc = ""; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getProjectId() { return projectId; } public void setProjectId(Integer projectId) { this.projectId = projectId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDoc() { return doc; } public void setDoc(String doc) { this.doc = doc; } }
public class SuiteTreePath { @EmbeddedId private TreePathPK id; private Integer distance; public Integer getDistance() { return distance; } public void setDistance(Integer distance) { this.distance = distance; } }
public class TreePathPK implements Serializable { private Integer ancestor; private Integer descendant; public TreePathPK(Integer ancestor, Integer descendant) { this.ancestor = ancestor; this.descendant = descendant; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TreePathPK that = (TreePathPK) o; if (ancestor != null ? !ancestor.equals(that.ancestor) : that.ancestor != null) return false; return descendant != null ? descendant.equals(that.descendant) : that.descendant == null; } @Override public int hashCode() { int result = ancestor != null ? ancestor.hashCode() : 0; result = 31 * result + (descendant != null ? descendant.hashCode() : 0); return result; } }
|