更新测试报告

This commit is contained in:
wh_zcy 2022-12-13 16:57:14 +08:00
parent cd408bfb7d
commit ba3c8963ce
5 changed files with 246 additions and 68 deletions

117
lib/ai.go
View File

@ -3,6 +3,9 @@ package lib
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"os"
"path/filepath"
"strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -17,19 +20,22 @@ type myAI struct {
iscenes []IScene iscenes []IScene
tickets Tickets //票池 tickets Tickets //票池
useCount uint32 //计数(压入的用户数) useCount uint32 //计数(压入的用户数)
lock sync.Mutex // useCountTotal uint32 //总数
lock sync.Mutex //合并数据锁
config *storage.Config //配置 config *storage.Config //配置
ReportMap map[string]map[string]*Statistics //测试报告 key1:场景 key2:协议
} }
func NewAI(aip AIParam) (*myAI, error) { func NewAI(aip AIParam) (*myAI, error) {
if err := aip.Check(); err != nil { // if err := aip.Check(); err != nil {
return nil, err // return nil, err
} // }
ai := &myAI{ ai := &myAI{
scenes: make([]*scene, 0), scenes: make([]*scene, 0),
config: aip.Config, config: aip.Config,
iscenes: aip.Scenes, iscenes: aip.Scenes,
ReportMap: make(map[string]map[string]*Statistics),
} }
if err := ai.init(); err != nil { if err := ai.init(); err != nil {
@ -56,7 +62,7 @@ func (m *myAI) init() error {
return nil return nil
} }
func (m *myAI) appendRobot(robot *Robot) { func (m *myAI) AppendRobot(robot *Robot) {
defer m.lock.Unlock() defer m.lock.Unlock()
m.lock.Lock() m.lock.Lock()
m.robots = append(m.robots, robot) m.robots = append(m.robots, robot)
@ -79,12 +85,28 @@ func (m *myAI) Start() bool {
atomic.AddUint32(&m.useCount, 1) atomic.AddUint32(&m.useCount, 1)
robot := NewRobot(m.config) robot := NewRobot(m.config)
robot.SetScenes(m.iscenes) robot.SetScenes(m.iscenes)
m.appendRobot(robot) m.AppendRobot(robot)
robot.Start() robot.Start()
atomic.AddUint32(&m.useCountTotal, 1)
// m.genReport(robot)
}() }()
} }
}() }()
go func() {
for {
total := atomic.LoadUint32(&m.useCountTotal)
if total == m.config.Global.UserCountTotal {
logrus.Debug("开始合并报告")
m.MergeResult()
logrus.Debug("结束合并报告")
//打印报告
m.genReport()
break
}
}
}()
return true return true
} }
@ -92,6 +114,87 @@ func (m *myAI) Stop() {
} }
func (m *myAI) ShowResult() { func (m *myAI) MergeResult() {
m.lock.Lock()
defer m.lock.Unlock()
n := make(map[string]map[string]*Statistics)
for _, r := range m.robots {
if len(m.ReportMap) == 0 {
m.ReportMap = r.ReportMap
} else {
x := m.ReportMap //已存在的
y := r.ReportMap //将要合并的
for i, v := range x {
for j, w := range y {
//场景相同
if i == j {
for k, a := range v {
for l, b := range w {
//判断协议是否相同
if k == l {
statis := &Statistics{}
statis.ElapseTotal = (a.ElapseTotal + b.ElapseTotal) / 2
statis.AvgElapse = (a.AvgElapse + b.AvgElapse) / 2
statis.CallCount = a.CallCount + b.CallCount
statis.MaxElapse = (a.MaxElapse + b.MaxElapse) / 2
statis.MinElapse = (a.MinElapse + b.MinElapse) / 2
statis.Route = a.Route
statis.SceneName = i
if n[i][k] == nil {
n[i] = make(map[string]*Statistics)
}
n[i][k] = statis
} else {
if _, ok := n[i][k]; !ok {
n[i][k] = a
}
if _, ok := n[i][l]; !ok {
n[i][l] = b
}
}
}
}
} else {
if _, ok := n[i]; !ok {
n[i] = v
}
if _, ok := n[j]; !ok {
n[j] = w
}
}
}
}
}
}
m.ReportMap = n
}
func (m *myAI) genReport() {
var buf bytes.Buffer
buf.WriteString("测试报告\n")
buf.WriteString(fmt.Sprintf("用户总数:%d \n",
m.config.Global.UserCountTotal))
var msgs []string
for k, routes := range m.ReportMap {
for r, d := range routes {
msgs = append(msgs, fmt.Sprintf("【%s】协议:%s 调用次数:%d 总耗时:%v 平均耗时:%v 最大耗时:%v 最小耗时:%v",
k, r, d.CallCount, d.ElapseTotal.String(), d.AvgElapse.String(), d.MaxElapse.String(), d.MinElapse.String()))
}
}
record := strings.Join(msgs, "\n")
buf.WriteString(record)
buf.WriteString("\n------------------------------------------------------------------------------------------------------\n")
// logrus.WithField("res", buf.String()).Debug("报告内容")
file, err := os.OpenFile(filepath.Join("./", "report.log"), os.O_APPEND|os.O_CREATE, os.ModePerm)
if err != nil {
logrus.Error(err)
}
defer file.Close()
if _, err := file.WriteString(buf.String()); err != nil {
logrus.Error(err)
}
} }

View File

@ -26,7 +26,8 @@ type SceneInfo struct {
} }
type CallResult struct { type CallResult struct {
ID int64 // ID。 ID int64 // ID
SceneName string
MainType string MainType string
SubType string SubType string
Elapse time.Duration // 耗时。 Elapse time.Duration // 耗时。
@ -39,6 +40,7 @@ type Statistics struct {
AvgElapse time.Duration //平均耗时 AvgElapse time.Duration //平均耗时
CallCount int64 //调用次数 CallCount int64 //调用次数
Route string //协议名称 Route string //协议名称
SceneName string //场景名称
} }
const ( const (

View File

@ -32,16 +32,19 @@ type IRobot interface {
type Robot struct { type Robot struct {
IStore IStore
scene IScene //场景
account string account string
sid string sid string
conn *websocket.Conn conn *websocket.Conn
data map[string]interface{} //机器人缓存数据 data map[string]interface{} //机器人缓存数据
status uint32 //状态 status uint32 //状态
lock sync.Mutex // lock sync.Mutex //数据缓存锁
sceneQueue *Queue[IScene] //场景队列 sceneQueue *Queue[IScene] //场景队列
config *storage.Config //配置 config *storage.Config //配置
resultCh chan *CallResult //请求结果通道 resultCh chan *CallResult //请求结果通道
sceneResultCh chan *CallResult //场景结果通道 sceneResultCh chan *CallResult //场景结果通道
ReportMap map[string]map[string]*Statistics //测试报告 key1:场景 key2:协议
elipseTotal time.Duration
} }
func NewRobot(config *storage.Config) *Robot { func NewRobot(config *storage.Config) *Robot {
@ -51,6 +54,7 @@ func NewRobot(config *storage.Config) *Robot {
config: config, config: config,
resultCh: make(chan *CallResult, 100), resultCh: make(chan *CallResult, 100),
sceneResultCh: make(chan *CallResult, 50), sceneResultCh: make(chan *CallResult, 50),
ReportMap: make(map[string]map[string]*Statistics),
} }
robot.Store("sid", config.Global.SId) robot.Store("sid", config.Global.SId)
return robot return robot
@ -76,8 +80,13 @@ func (r *Robot) SendMsg(mainType, subType string, req proto.Message, rsp proto.M
defer func() { defer func() {
t := time.Since(start) t := time.Since(start)
logrus.WithFields(logrus.Fields{"MainType": mainType, "SubType": subType, "rsp": rsp, "since": t.String()}).Debug("接收消息") logrus.WithFields(logrus.Fields{"MainType": mainType, "SubType": subType, "rsp": rsp, "since": t.String()}).Debug("接收消息")
var name string
if r.scene != nil {
name = r.scene.Info().Name
}
// 发送请求结果 // 发送请求结果
r.SendResult(&CallResult{ r.SendResult(&CallResult{
SceneName: name,
MainType: mainType, MainType: mainType,
SubType: subType, SubType: subType,
Elapse: t, Elapse: t,
@ -182,13 +191,17 @@ func (m *Robot) Stop() bool {
} }
func (m *Robot) syncCall() { func (m *Robot) syncCall() {
// var sceneElipseTotal time.Duration // 场景总耗时
for { for {
scene, err := m.sceneQueue.Pop() scene, err := m.sceneQueue.Pop()
if err != nil { if err != nil {
logrus.WithField("err", err).Warn("所有场景执行结束") logrus.WithField("err", err).Warn("所有场景执行结束")
m.prepareToStop() // m.prepareToStop()
// m.genReport(sceneElipseTotal)
return return
} }
m.scene = scene
info := m.scene.Info()
start := time.Now() start := time.Now()
//这里执行会花很长时间 //这里执行会花很长时间
@ -197,12 +210,11 @@ func (m *Robot) syncCall() {
break break
} }
elapsedTime := time.Since(start) elapsedTime := time.Since(start)
info := scene.Info()
m.elipseTotal += elapsedTime
logrus.WithField("t", elapsedTime.String()).Debug("场景【" + info.Name + "】执行完毕耗时统计") logrus.WithField("t", elapsedTime.String()).Debug("场景【" + info.Name + "】执行完毕耗时统计")
//结束
// m.prepareToStop()
//显示场景结果 //显示场景结果
m.ShowResult() m.processResult()
} }
} }
@ -228,27 +240,14 @@ func (m *Robot) SendResult(result *CallResult) bool {
} }
} }
func (m *Robot) ShowResult() { func (m *Robot) processResult() {
go func() { go func() {
logrus.Debug("开始生成测试报告") defer m.lock.Unlock()
defer logrus.Debug("测试报告生成完成") m.lock.Lock()
routes := make(map[string]*Statistics)
for r := range m.resultCh { for r := range m.resultCh {
head := fmt.Sprintf("%s.%s", r.MainType, r.SubType) head := fmt.Sprintf("%s.%s", r.MainType, r.SubType)
logrus.WithField("head", head).Debug("读结果") if routes, ok := m.ReportMap[r.SceneName]; ok {
if len(routes) == 0 { if route, y := routes[head]; y {
statis := &Statistics{
Route: head,
ElapseTotal: r.Elapse,
MaxElapse: r.Elapse,
MinElapse: r.Elapse,
CallCount: 1,
}
avg := (statis.MaxElapse + statis.MinElapse) / 2
statis.AvgElapse = avg
routes[head] = statis
} else {
if route, ok := routes[head]; ok {
max := route.MaxElapse max := route.MaxElapse
min := route.MinElapse min := route.MinElapse
if r.Elapse > max { if r.Elapse > max {
@ -260,6 +259,7 @@ func (m *Robot) ShowResult() {
} }
statis := &Statistics{ statis := &Statistics{
Route: head, Route: head,
SceneName: r.SceneName,
ElapseTotal: route.ElapseTotal + r.Elapse, ElapseTotal: route.ElapseTotal + r.Elapse,
MaxElapse: max, MaxElapse: max,
MinElapse: min, MinElapse: min,
@ -271,6 +271,7 @@ func (m *Robot) ShowResult() {
} else { } else {
statis := &Statistics{ statis := &Statistics{
Route: head, Route: head,
SceneName: r.SceneName,
ElapseTotal: r.Elapse, ElapseTotal: r.Elapse,
MaxElapse: r.Elapse, MaxElapse: r.Elapse,
MinElapse: r.Elapse, MinElapse: r.Elapse,
@ -280,24 +281,50 @@ func (m *Robot) ShowResult() {
statis.AvgElapse = avg statis.AvgElapse = avg
routes[head] = statis routes[head] = statis
} }
m.ReportMap[r.SceneName] = routes
} else {
route := make(map[string]*Statistics)
statis := &Statistics{
Route: head,
SceneName: r.SceneName,
ElapseTotal: r.Elapse,
MaxElapse: r.Elapse,
MinElapse: r.Elapse,
CallCount: 1,
}
avg := (statis.MaxElapse + statis.MinElapse) / 2
statis.AvgElapse = avg
route[head] = statis
m.ReportMap[r.SceneName] = route
} }
} }
// 将统计结果写入文件 }()
var msgs []string
for k, v := range routes {
msgs = append(msgs, fmt.Sprintf("协议:%s 调用次数:%d 总耗时:%v 平均耗时:%v 最大耗时:%v 最小耗时:%v",
k, v.CallCount, v.ElapseTotal.String(), v.AvgElapse.String(), v.MaxElapse.String(), v.MinElapse.String()))
} }
record := strings.Join(msgs, "\n")
// 将统计结果写入文件
// Deprecated
func (m *Robot) genReport(e time.Duration) {
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString("测试报告\n") buf.WriteString("测试报告\n")
buf.WriteString(fmt.Sprintf("用户总数:%d 场景总耗时:%s\n",
m.config.Global.UserCountTotal, e.String()))
var msgs []string
for k, routes := range m.ReportMap {
// buf.WriteString(fmt.Sprintf("【%s】\n", k))
for r, d := range routes {
msgs = append(msgs, fmt.Sprintf("【%s】协议:%s 调用次数:%d 总耗时:%v 平均耗时:%v 最大耗时:%v 最小耗时:%v",
k, r, d.CallCount, d.ElapseTotal.String(), d.AvgElapse.String(), d.MaxElapse.String(), d.MinElapse.String()))
}
}
record := strings.Join(msgs, "\n")
buf.WriteString(record) buf.WriteString(record)
logrus.WithField("res", buf.String()).Debug("报告内容") buf.WriteString("\n------------------------------------------------------------------------------\n")
// logrus.WithField("res", buf.String()).Debug("报告内容")
if err := ioutil.WriteFile(filepath.Join("./", "report.log"), buf.Bytes(), fs.ModePerm); err != nil { if err := ioutil.WriteFile(filepath.Join("./", "report.log"), buf.Bytes(), fs.ModePerm); err != nil {
logrus.WithField("err", err).Error("测试报告") logrus.WithField("err", err).Error("测试报告")
} }
}()
} }
func (m *Robot) printIgnoredResult(result *CallResult, cause string) { func (m *Robot) printIgnoredResult(result *CallResult, cause string) {

View File

@ -6,6 +6,7 @@ import (
"legu.airobot/busi/friend" "legu.airobot/busi/friend"
"legu.airobot/lib" "legu.airobot/lib"
"legu.airobot/storage"
) )
func TestAction(t *testing.T) { func TestAction(t *testing.T) {
@ -47,3 +48,48 @@ func TestA(t *testing.T) {
fmt.Println(i) fmt.Println(i)
} }
} }
func TestMerge(t *testing.T) {
config := &storage.Config{
Global: &storage.Global{UserCountTotal: 2, SId: "dfz"},
}
ma, _ := lib.NewAI(lib.AIParam{Config: config})
robot1 := lib.NewRobot(config)
robot1.ReportMap = make(map[string]map[string]*lib.Statistics)
robot1.ReportMap["登录"] = make(map[string]*lib.Statistics)
robot1.ReportMap["登录"]["user.login"] = &lib.Statistics{
ElapseTotal: 5,
CallCount: 1,
AvgElapse: 1,
MaxElapse: 4,
MinElapse: 1,
Route: "user.login",
SceneName: "登录",
}
ma.AppendRobot(robot1)
///////////////
robot2 := lib.NewRobot(config)
robot2.ReportMap = make(map[string]map[string]*lib.Statistics)
robot2.ReportMap["登录"] = make(map[string]*lib.Statistics)
robot2.ReportMap["登录"]["user.login"] = &lib.Statistics{
ElapseTotal: 7,
CallCount: 1,
AvgElapse: 1,
MaxElapse: 5,
MinElapse: 2,
Route: "user.login",
SceneName: "登录",
}
ma.AppendRobot(robot2)
ma.MergeResult()
fmt.Println(ma.ReportMap)
for i, v := range ma.ReportMap {
fmt.Println(i)
for j, m := range v {
fmt.Printf("【%s】 调用次数:%v 总耗时:%v 平均:%v 最大:%v 最小:%v\n", j, m.CallCount, m.ElapseTotal, m.AvgElapse, m.MaxElapse, m.MinElapse)
}
}
}

View File

@ -650,7 +650,7 @@ func (mw *MainWindow) newSceneContainer() {
container.NewBorder( container.NewBorder(
container.NewBorder(nil, nil, container.NewHBox(addSceneBtn), nil, searchEntry), nil, nil, nil, container.NewBorder(nil, nil, container.NewHBox(addSceneBtn), nil, searchEntry), nil, nil, nil,
registerSceneList.ListWidget), dynamic) registerSceneList.ListWidget), dynamic)
split.Offset = 0.4 split.Offset = 0.5
mw.changeContent(split) mw.changeContent(split)
} }
contentRender() contentRender()