2019-04-22 02:59:20 +00:00

614 lines
18 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"encoding/json"
"html/template"
"io"
"os"
"sort"
"strconv"
"strings"
"time"
"go-common/app/admin/ep/melloi/conf"
"go-common/app/admin/ep/melloi/model"
"go-common/library/log"
)
// QueryDraft Query Draft
func (s *Service) QueryDraft(scene *model.Scene) (*model.QueryDraft, error) {
return s.dao.QueryDraft(scene)
}
// UpdateScene Update Scene
func (s *Service) UpdateScene(scene *model.Scene) (fusing int, err error) {
scriptIDList := make([]int, len(scene.Scripts))
for index, script := range scene.Scripts {
scriptIDList[index] = script.ID
}
fusing, err = s.dao.UpdateScene(scene, scriptIDList)
return
}
// AddScene Add Scene
func (s *Service) AddScene(scene *model.Scene) (id int, err error) {
id, err = s.dao.AddScene(scene)
return
}
// QueryAPI Query API
func (s *Service) QueryAPI(scene *model.Scene) (*model.QueryAPIs, error) {
return s.dao.QueryAPI(scene)
}
// AddConfig Add Config
func (s *Service) AddConfig(script *model.Script) error {
return s.dao.AddConfig(script)
}
// QueryTree Query Tree
func (s *Service) QueryTree(script *model.Script) (*model.ShowTree, error) {
return s.dao.QueryTree(script)
}
// QueryScenesByPage Query Scene By Page
func (s *Service) QueryScenesByPage(c context.Context, sessionID string, qsrq *model.QuerySceneRequest) (rsp *model.QuerySceneResponse, err error) {
// 获取服务树节点
var (
treeNodes []string
treeNodesd []string
)
if treeNodesd, err = s.QueryUserRoleNode(c, sessionID); err != nil {
log.Error("QueryUserRoleNode err (%v):", err)
}
treeNodes = append(treeNodesd, "")
if ExistsInSlice(qsrq.Executor, conf.Conf.Melloi.Executor) {
if rsp, err = s.dao.QueryScenesByPageWhiteName(&qsrq.Scene, qsrq.PageNum, qsrq.PageSize); err != nil {
return
}
} else {
if rsp, err = s.dao.QueryScenesByPage(&qsrq.Scene, qsrq.PageNum, qsrq.PageSize, treeNodes); err != nil {
return
}
}
return
}
//AddAndExecuScene AddSceneAuto add scene auto
func (s *Service) AddAndExecuScene(c context.Context, scene model.Scene, cookie string) (resp model.DoPtestResp, err error) {
var (
buff *template.Template
file *os.File
scrThreadGroup model.ScrThreadGroup
fileName string
testNames []string
testNameNicks []string
loadTimes []int
scripts []*model.Script
jmeterLog string
resJtl string
sceneID int
threadGroup string
)
// id 不是0 说明是输入接口创建的场景根据sceneID 查询到接口列表再根据接口列表生成jmx
// 不是前端 quick-start 页的批量选择,走如下逻辑
if scene.ID != 0 && !scene.IsBatch {
script := model.Script{SceneID: scene.ID}
if scripts, err = s.dao.QueryScripts(&script, 1, 200); err != nil {
log.Error("s.dao.QueryScripts err :(%v)", err)
return
}
scene.Scripts = scripts
}
if scene.IsDebug {
for _, script := range scene.Scripts {
script.ThreadsSum = 1
script.Loops = 5
script.TestName = script.TestName + "_perf_debug"
}
scene.SceneName = scene.SceneName + "_perf_debug"
}
// 非 quick-start 页面的批量选择,走如下逻辑,即 quick-start 页面的批量选择,不生成 scene.jmx 文件
sceneSuffix := strconv.FormatInt(time.Now().Unix(), 10)
if !scene.IsBatch {
scrThreadGroup.Scripts = scene.Scripts
if threadGroup, err = s.GetThreadGroup(scrThreadGroup); err != nil {
log.Error("s.dao.GetThreadGroup (%v)", err)
return
}
scene.ThreadGroup = unescaped(threadGroup)
if buff, err = template.ParseFiles(s.c.Jmeter.JmeterSceneTmp); err != nil {
log.Error("file is not exists (%v)", err)
return
}
scene.ScriptPath = "/data/jmeter-log/" + scene.Department + "/" + scene.Project + "/" + scene.APP + "/" + "scene" + "/" + sceneSuffix + "/"
if err = os.MkdirAll(scene.ScriptPath, 0755); err != nil {
log.Error("Create SavePath Err (%v)", err)
return
}
// 创建脚本文件 脚本路径+场景名+后缀.jmx
if file, err = os.Create(scene.ScriptPath + sceneSuffix + ".jmx"); err != nil {
log.Error("os.Create file err :(%v)", err)
return
}
defer file.Close()
buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
buff.Execute(io.Writer(file), scene)
fileName = file.Name()
jmeterLog = scene.ScriptPath + "jmg" + sceneSuffix
resJtl = scene.ScriptPath + "jtl" + sceneSuffix
}
scene.JmeterLog = jmeterLog
scene.JmeterFilePath = fileName
scene.ResJtl = resJtl
sceneID = scene.ID
// 批量选择脚本执行场景压测,则走如下逻辑,写 script 表
if scene.ID == 0 || scene.IsBatch {
//前端传入的scene 有 scripts , sceneId 没有传,走如下逻辑,写入scene 表
if !scene.IsBatch {
scene.SceneType = 1
if sceneID, err = s.AddScene(&scene); err != nil {
log.Error("s.AddScene err :(%v)", err)
return
}
scene.ID = sceneID
}
for _, script := range scene.Scripts {
script.IsSave = true
script.SceneID = sceneID
script.ID = 0
script.TestType = model.SCENE_SCRIPT_TYPE
//脚本落库
if resp, err = s.AddAndExcuScript(c, script, "", &scene, false, true); err != nil {
log.Error("s.AddAndExcuScript err :(%v)", err)
return
}
script.ID = resp.ScriptID
scripts = append(scripts, script)
}
scene.Scripts = scripts
}
// 有id需要更新数据库
if scene.ID != 0 && !scene.IsDebug {
if _, err = s.UpdateScene(&scene); err != nil {
log.Error("s.UpdateScene error :(%v)", err)
return
}
}
//获取 testNames testNameNicks loadTimes
for _, script := range scene.Scripts {
testNames = append(testNames, script.TestName)
testNameNicks = append(testNameNicks, script.TestName+sceneSuffix)
loadTimes = append(loadTimes, script.LoadTime)
}
sort.Ints(loadTimes)
//执行压测
if scene.IsExecute && len(scene.Scripts) > 0 {
ptestParam := model.DoPtestParam{
TestNames: testNames,
SceneName: scene.SceneName,
UserName: scene.UserName,
LoadTime: loadTimes[len(loadTimes)-1],
FileName: fileName,
Upload: false,
ProjectName: scene.SceneName,
JmeterLog: scene.JmeterLog,
ResJtl: scene.ResJtl,
Department: scene.Department,
Project: scene.Project,
APP: scene.APP,
ScriptID: 0,
DockerSum: 1,
TestNameNick: SliceToString(testNameNicks, ","),
TestNameNicks: testNameNicks,
Scripts: scene.Scripts,
SceneID: sceneID,
Type: model.PROTOCOL_SCENE, // 场景
IsDebug: scene.IsDebug,
Cookie: cookie,
Fusing: scene.Fusing,
}
if resp, err = s.DoPtest(c, ptestParam); err != nil {
log.Error("s.DoPtest err :(%v)", err)
return
}
//临时写法
resp.ScriptID = sceneID
}
return
}
// SaveScene Save Scene
func (s *Service) SaveScene(scene *model.Scene) error {
return s.dao.SaveScene(scene)
}
// SaveOrder Save Order
func (s *Service) SaveOrder(req model.SaveOrderReq, scene *model.Scene) error {
var (
flag = 1
length = len(req.GroupOrderList)
index = length - 1
bak int
)
if scene.SceneType == 1 {
for i := 0; i < length; i++ {
bak = req.GroupOrderList[i].GroupID
req.GroupOrderList[i].GroupID = flag
//防止越界
if i == index {
break
}
if bak != req.GroupOrderList[i+1].GroupID {
flag++
}
}
} else {
for i := 0; i < length; i++ {
bak = req.GroupOrderList[i].RunOrder
req.GroupOrderList[i].RunOrder = flag
//防止越界
if i == index {
break
}
if bak != req.GroupOrderList[i+1].RunOrder {
flag++
}
}
}
return s.dao.SaveOrder(req.GroupOrderList, scene)
}
// QueryRelation Query Relation
func (s *Service) QueryRelation(script *model.Script) (*model.QueryRelation, error) {
var (
groupId int
err error
)
if _, groupId, err = s.dao.QueryGroupId(script); err != nil {
log.Error("s.dao.QueryGroupId err :(%v)", err)
return nil, err
}
return s.dao.QueryRelation(groupId, script)
}
// DeleteAPI Delete API
func (s *Service) DeleteAPI(script *model.Script) error {
return s.dao.DeleteAPI(script)
}
// DoScenePtest Do Scene Ptest
func (s *Service) DoScenePtest(c context.Context, ptestScene model.DoPtestSceneParam, addPtest bool, cookie string) (resp model.DoPtestResp, err error) {
var (
scenes []*model.Scene
scripts []*model.Script
)
scene := model.Scene{ID: ptestScene.SceneID}
if scenes, err = s.dao.QueryScenes(&scene, 1, 1); err != nil {
log.Error("s.dao.QueryScenes err :(%v)", err)
return
}
script := model.Script{SceneID: ptestScene.SceneID}
if scripts, err = s.dao.QueryScripts(&script, 1, 300); err != nil {
log.Error("s.dao.QueryScripts err :(%v)", err)
return
}
scenes[0].Scripts = scripts
if len(scenes) > 0 {
sceneInfo := GetSceneInfo(scenes[0])
ptestParam := model.DoPtestParam{
TestNames: sceneInfo.TestNames,
SceneName: sceneInfo.SceneName,
UserName: ptestScene.UserName,
LoadTime: sceneInfo.MaxLoadTime,
FileName: scenes[0].JmeterFilePath,
Upload: false,
ProjectName: sceneInfo.SceneName,
ResJtl: sceneInfo.ResJtl,
JmeterLog: sceneInfo.JmeterLog,
Department: scenes[0].Department,
Project: scenes[0].Project,
APP: scenes[0].APP,
ScriptID: 0,
DockerSum: 1,
TestNameNick: SliceToString(sceneInfo.TestNameNicks, ","),
TestNameNicks: sceneInfo.TestNameNicks,
Scripts: sceneInfo.Scripts,
SceneID: ptestScene.SceneID,
Type: model.PROTOCOL_SCENE, // 场景
AddPtest: addPtest,
Cookie: cookie,
}
return s.DoPtest(c, ptestParam)
}
return
}
//DoScenePtestBatch dosceneptest batch
func (s *Service) DoScenePtestBatch(c context.Context, ptestScenes model.DoPtestSceneParams, cookie string) (err error) {
for _, SceneID := range ptestScenes.SceneIDs {
ptestScene := model.DoPtestSceneParam{SceneID: SceneID, UserName: ptestScenes.UserName}
go s.DoScenePtest(context.TODO(), ptestScene, false, cookie)
}
return
}
//GetSceneInfo get sceneInfo
func GetSceneInfo(scene *model.Scene) (sceneInfo model.SceneInfo) {
var (
loadTimes []int
testNames []string
testNameNicks []string
scripts []*model.Script
)
if scene == nil {
return
}
sceneSuffix := strconv.FormatInt(time.Now().Unix(), 10)
for _, script := range scene.Scripts {
loadTimes = append(loadTimes, script.LoadTime)
testNames = append(testNames, script.TestName)
testNameNicks = append(testNameNicks, script.TestName+sceneSuffix)
scripts = append(scripts, script)
}
sort.Ints(loadTimes)
sceneInfo = model.SceneInfo{
MaxLoadTime: loadTimes[len(loadTimes)-1],
JmeterLog: scene.JmeterLog + sceneSuffix,
ResJtl: scene.ResJtl + sceneSuffix,
LoadTimes: loadTimes,
TestNames: testNames,
TestNameNicks: testNameNicks,
SceneName: scene.SceneName,
Scripts: scripts,
}
return
}
// QueryExistAPI Query Exist API
func (s *Service) QueryExistAPI(c context.Context, sessionID string, req *model.APIInfoRequest) (res *model.APIInfoList, err error) {
// 获取服务树节点
var (
treeNodes []string
treeNodesd []string
)
if treeNodesd, err = s.QueryUserRoleNode(c, sessionID); err != nil {
log.Error("QueryUserRoleNode err (%v):", err)
}
treeNodes = append(treeNodesd, "")
if res, err = s.dao.QueryExistAPI(&req.Script, req.PageNum, req.PageSize, req.SceneID, treeNodes); err != nil {
return
}
for _, script := range res.ScriptList {
if script.APIHeader != "" {
if err = json.Unmarshal([]byte(script.APIHeader), &script.Headers); err != nil {
log.Error("get script header err : (%v),scriptId:(%d)", err, script.ID)
}
}
if script.ArgumentString != "" {
if err = json.Unmarshal([]byte(script.ArgumentString), &script.ArgumentsMap); err != nil {
log.Error("get script argument err: (%v), scriptId:(%d)", err, script.ID)
}
}
if script.OutputParams != "" {
if err = json.Unmarshal([]byte(script.OutputParams), &script.OutputParamsMap); err != nil {
log.Error("get script OutputParams err: (%v),scriptId:(%d)", err, script.ID)
}
}
}
return
}
// QueryPreview Query Preview
func (s *Service) QueryPreview(req *model.Script) (preRes *model.PreviewInfoList, err error) {
var (
list *model.GroupList
preList *model.PreviewList
preResd model.PreviewInfoList
)
if list, err = s.dao.QueryGroup(req.SceneID); err != nil {
return
}
for i := 0; i < len(list.GroupList); i++ {
// 或者使用var preInfo = &model.PreviewInfo{}
preInfo := new(model.PreviewInfo)
groupId := list.GroupList[i].GroupID
threadsSum := list.GroupList[i].ThreadsSum
loadTime := list.GroupList[i].LoadTime
readyTime := list.GroupList[i].ReadyTime
if preList, err = s.dao.QueryPreview(req.SceneID, groupId); err != nil {
return
}
preInfo.GroupID = groupId
preInfo.ThreadsSum = threadsSum
preInfo.LoadTime = loadTime
preInfo.ReadyTime = readyTime
preInfo.InfoList = preList.PreList
preResd.PreviewInfoList = append(preResd.PreviewInfoList, preInfo)
preRes = &preResd
}
return
}
// QueryParams Query Params
func (s *Service) QueryParams(req *model.Script) (res *model.UsefulParamsList, tempRes *model.UsefulParamsList, err error) {
//var paramList []string
var (
uParam *model.UsefulParams
)
res = &model.UsefulParamsList{}
if tempRes, err = s.dao.QueryUsefulParams(req.SceneID); err != nil {
return
}
if len(tempRes.ParamsList) > 0 {
for _, tempParam := range tempRes.ParamsList {
if strings.Contains(tempParam.OutputParams, ",") {
tempParamList := strings.Split(tempParam.OutputParams, ",")
for _, param := range tempParamList {
uParam = &model.UsefulParams{}
uParam.OutputParams = strings.Split(strings.Split(param, "\":\"")[0], "\"")[1]
res.ParamsList = append(res.ParamsList, uParam)
}
} else {
uParam = &model.UsefulParams{}
uParam.OutputParams = strings.Split(strings.Split(tempParam.OutputParams, "\":\"")[0], "\"")[1]
res.ParamsList = append(res.ParamsList, uParam)
}
}
} else {
// 赋值空数组
res.ParamsList = []*model.UsefulParams{}
}
return
}
// UpdateBindScene Update Bind Scene
func (s *Service) UpdateBindScene(bindScene *model.BindScene) (err error) {
return s.dao.UpdateBindScene(bindScene)
}
// QueryDrawRelation Query Draw Relation
func (s *Service) QueryDrawRelation(scene *model.Scene) (res model.DrawRelationList, tempRes *model.SaveOrderReq, err error) {
var (
//relationList model.DrawRelationList
edges []*model.Edge
edge *model.Edge
tempEdge *model.Edge
//nodes []*model.Node
node *model.Node
)
if tempRes, err = s.dao.QueryDrawRelation(scene); err != nil {
return
}
for k := 0; k < len(tempRes.GroupOrderList); k++ {
node = &model.Node{}
node.ID = tempRes.GroupOrderList[k].ID
node.Name = tempRes.GroupOrderList[k].TestName
res.Nodes = append(res.Nodes, node)
}
for i := 0; i < len(tempRes.GroupOrderList)-1; i++ {
edge = &model.Edge{}
tempEdge = &model.Edge{}
if tempRes.GroupOrderList[i].GroupID == tempRes.GroupOrderList[i+1].GroupID && tempRes.GroupOrderList[i].RunOrder == tempRes.GroupOrderList[i+1].RunOrder {
edge.Source = tempRes.GroupOrderList[i].TestName
edges = append(edges, edge)
if len(edges) > 0 {
//edges[i+1].Source =
tempEdge.Source = edges[i-1].Source
tempEdge.Target = tempRes.GroupOrderList[i+1].TestName
edges = append(edges, tempEdge)
}
} else if tempRes.GroupOrderList[i].GroupID == tempRes.GroupOrderList[i+1].GroupID && tempRes.GroupOrderList[i].RunOrder != tempRes.GroupOrderList[i+1].RunOrder {
edge.Source = tempRes.GroupOrderList[i].TestName
edge.Target = tempRes.GroupOrderList[i+1].TestName
edges = append(edges, edge)
} else if tempRes.GroupOrderList[i].GroupID != tempRes.GroupOrderList[i+1].GroupID {
edge.Source = tempRes.GroupOrderList[i].TestName
edges = append(edges, edge)
}
}
for j := 0; j < len(edges); j++ {
if edges[j].Target != "" {
//relationList.Edges = append(relationList.Edges, edges[j])
res.Edges = append(res.Edges, edges[j])
}
}
return
}
// DeleteDraft Delete Draft
func (s *Service) DeleteDraft(scene *model.Scene) error {
return s.dao.DeleteDraft(scene)
}
// QueryConfig Query Config
func (s *Service) QueryConfig(script *model.Script) (*model.GroupInfo, error) {
return s.dao.QueryConfig(script)
}
// DeleteScene Delete Scene
func (s *Service) DeleteScene(scene *model.Scene) error {
return s.dao.DeleteScene(scene)
}
//CopyScene copy scene
func (s *Service) CopyScene(c context.Context, scene *model.Scene, cookie string) (addScene model.AddScene, err error) {
var (
scripts []*model.Script
scenes []*model.Scene
sceneID int
resp model.DoPtestResp
)
script := model.Script{SceneID: scene.ID}
scened := model.Scene{ID: scene.ID}
//先根据 scene.ID 查询 scenes 和 scripts
if scenes, err = s.dao.QueryScenes(&scened, 1, 10); err != nil {
log.Error("s.dao.QueryScenes err :(%v)", err)
return
}
if scripts, err = s.dao.QueryScripts(&script, 1, 200); err != nil {
log.Error("s.dao.QueryScripts err :(%v)", err)
return
}
if len(scenes) != 0 {
scenes[0].ID = 0
scenes[0].UserName = scene.UserName
scenes[0].SceneName = scene.SceneName
//将新的scene 写入 数据库,并返回 sceneID
if sceneID, err = s.dao.AddScene(scenes[0]); err != nil {
log.Error("s.dao.AddScene err :(%v)", err)
return
}
// 将新的 script 写入 script 表
for _, sctd := range scripts {
sctd.SceneID = sceneID
sctd.ID = 0
if _, _, _, err = s.dao.AddScript(sctd); err != nil {
return
}
}
sce := model.Scene{
APP: scenes[0].APP,
Department: scenes[0].Department,
Project: scenes[0].Project,
ID: sceneID,
IsDebug: false,
IsExecute: false,
UserName: scene.UserName,
SceneName: scene.SceneName,
}
if resp, err = s.AddAndExecuScene(c, sce, cookie); err != nil {
log.Error("s.AddAndExecuScene err :(%v), (%v)", err, resp)
return
}
addScene.SceneID = sceneID
addScene.UserName = scene.UserName
}
return
}
// QueryFusing Query Fusing
func (s *Service) QueryFusing(script *model.Script) (res *model.FusingInfoList, err error) {
res, err = s.dao.QueryFusing(script)
for i := 0; i < len(res.FusingList)-1; i++ {
if res.FusingList[i] != res.FusingList[i+1] {
res.SetNull = true
return
}
}
return
}