bilibili-backup/app/admin/ep/melloi/service/script.go

1273 lines
39 KiB
Go
Raw Normal View History

2019-04-22 10:59:20 +08:00
package service
import (
"bytes"
"context"
"encoding/json"
"html/template"
"io"
"net/url"
"os"
"regexp"
"strconv"
"strings"
"time"
"go-common/app/admin/ep/melloi/conf"
"go-common/app/admin/ep/melloi/model"
"go-common/library/ecode"
"go-common/library/log"
)
//QueryScripts query scripts
func (s *Service) QueryScripts(script *model.Script, pn, ps int) (scripts []*model.Script, err error) {
if ps <= 0 || pn <= 0 {
ps = 10
pn = 1
}
if scripts, err = s.dao.QueryScripts(script, pn, ps); err != nil {
log.Error("s.dao.QueryScripts error :(%v)", err)
return
}
for _, script := range scripts {
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
}
//CountQueryScripts count query scripts
func (s *Service) CountQueryScripts(script *model.Script) (total int) {
return s.dao.CountQueryScripts(script)
}
//QueryScriptSnap query scriptSnap
func (s *Service) QueryScriptSnap(scriptSnap *model.ScriptSnap) (snaps []*model.ScriptSnap, err error) {
return s.dao.QueryScriptSnap(scriptSnap)
}
//QueryScriptsByPage query script by page
func (s *Service) QueryScriptsByPage(c context.Context, sessionID string, qsrq *model.QueryScriptRequest) (rsp *model.QueryScriptResponse, 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) {
//rsp, err = s.dao.QueryScriptsByPageWhiteName(&qsrq.Script, qsrq.PageNum, qsrq.PageSize)
if rsp, err = s.dao.QueryScriptsByPageWhiteName(&qsrq.Script, qsrq.PageNum, qsrq.PageSize); err != nil {
return
}
} else {
if rsp, err = s.dao.QueryScriptsByPage(&qsrq.Script, qsrq.PageNum, qsrq.PageSize, treeNodes); err != nil {
return
}
}
for _, script := range rsp.Scripts {
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)
}
}
}
// 获取label
for _, script := range rsp.Scripts {
lr := model.LabelRelation{Type: model.ScriptType, TargetID: int64(script.ID)}
if script.Labels, err = s.dao.QueryLabelRelation(&lr); err != nil {
return
}
}
return
}
//AddAndExcuScript add script and excute it
func (s *Service) AddAndExcuScript(c context.Context, script *model.Script, cookie string, scene *model.Scene, fileWrite, convjson bool) (resp model.DoPtestResp, err error) {
var (
scriptID int
groupID int
runOrder int
testNameNick string
message string
scriptd model.Script
paramList *model.ParamList
isEdit = false
)
if message, scriptd, err = s.AddScript(script, fileWrite); err != nil {
log.Error("sorry, addScript fail : (%v)", err)
return
}
headerString := MapToString(scriptd.Headers)
argumentString := MapToString(scriptd.ArgumentsMap)
scriptd.ArgumentString = argumentString
scriptd.APIHeader = headerString
scriptd.OutputParams = MapToString(scriptd.OutputParamsMap)
//场景压测中选择已有接口时,去修改默认的熔断成功率的值(新增接口时不修改)
if scene.IsBatch {
scriptd.Fusing = scene.Fusing
}
if convjson {
scriptd.ArgumentString = script.ArgumentString
scriptd.APIHeader = script.APIHeader
scriptd.OutputParams = script.OutputParams
}
//场景压测独有的逻辑
if scriptd.TestType == model.SCENE_SCRIPT_TYPE {
//根据接口参数依赖,计算出接口分组与执行顺序
if paramList, err = s.dao.QueryParams(&scriptd, scene); err != nil {
log.Error("s.dao.QueryParams err :(%v)", err)
return
}
scriptd.GroupID, scriptd.RunOrder = GroupOrder(isEdit, &scriptd, scene, paramList)
}
//非debug 执行的 循环次数为-1 即永久
if scriptd.Loops == -1 {
if len(script.OutputParamsMap) == 0 || script.OutputParams == "[]" {
scriptd.OutputParams = "[{\"\":\"\"}]"
}
if scriptID, groupID, runOrder, err = s.dao.AddScript(&scriptd); err != nil {
log.Error("s.dao.AddScript err : (%v)", err)
message = "sql excute err"
return
}
}
//如果不是复制脚本操作 或者 不是保存则执行jmeter压测
if !script.IsCopy && !script.IsSave {
tim := strconv.FormatInt(time.Now().Unix(), 10)
testNameNick = scriptd.TestName + tim
log.Info("开始调用压测job-------\n")
ptestParam := model.DoPtestParam{
UserName: scriptd.UpdateBy, // 用户名
LoadTime: scriptd.LoadTime, //运行时间
TestNames: StringToSlice(scriptd.TestName), //接口名转数组
FileName: scriptd.SavePath, // jmx文件
ResJtl: scriptd.ResJtl, // jtl 文件
JmeterLog: scriptd.JmeterLog, // jmeterlog时间戳
Department: script.Department,
Project: script.Project,
APP: script.App,
ScriptID: scriptID,
IsDebug: script.IsDebug, //false
Cookie: cookie, // 用不到
URL: scriptd.URL, // 微信通知URL
LabelIDs: script.LabelIds,
Domain: scriptd.Domain,
FileSplit: script.FileSplit, // 文件切割
SplitNum: script.SplitNum, // 切割数量
Fusing: script.Fusing,
APIHeader: scriptd.APIHeader,
ExecuDockerSum: script.ExecuDockerSum,
UseBusinessStop: script.UseBusinessStop,
BusinessStopPercent: script.BusinessStopPercent,
}
if resp, err = s.DoPtestByJmeter(c, ptestParam, StringToSlice(testNameNick)); err != nil {
log.Error("DoPtestByJmeter err :(%v)", err)
message = "DoPtestByJmeter err "
return
}
resp.Message = message
}
resp.ScriptID = scriptID
resp.GroupID = groupID
resp.RunOrder = runOrder
return
}
//AddScript add script
func (s *Service) AddScript(script *model.Script, fileWrite bool) (message string, scriptd model.Script, err error) {
var (
buff *template.Template
file *os.File
scriptPath string
u *url.URL
sinfoJSON []byte
JSON []byte
JSONExtractors string
dataFileName string
Assertionsd []string
)
log.Info("threadsSum :(%d)", script.ThreadsSum)
if script.LoadTime > s.c.Jmeter.TestTimeLimit {
script.LoadTime = s.c.Jmeter.TestTimeLimit
}
//判断url
if !strings.Contains(script.URL, "http://") && !strings.Contains(script.URL, "https://") {
script.URL = "http://" + script.URL
}
if script.Delimiter == "" {
script.Delimiter = ","
}
if u, err = url.Parse(script.URL); err != nil || u == nil {
log.Error("sorry,url is not standard,error(%v)", err)
err = ecode.MelloiUrlParseError
return
}
if script.Data == "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterScUcodedTmp)
} else {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterScTmp)
}
if err != nil {
log.Error("open file failed! error %v", err)
return
}
if script.Assertion != "" {
script.UseAssertion = true
Assertions := strings.Split(script.Assertion, "|")
for _, assert := range Assertions {
Assertionsd = append(Assertionsd, model.AssertionStart+assert+model.AssertionEnd)
}
script.AssertionString = unescaped(SliceToString(Assertionsd, " "))
}
if len(script.OutputParamsMap) > 0 && script.OutputParams != "[{\"\":\"\"}]" && script.OutputParams != "[]" && script.OutputParams != "" {
if JSONExtractors, err = s.SetJSONExtractors(script); err != nil {
return
}
if JSONExtractors != "" {
script.JSONExtractor = unescaped(JSONExtractors)
}
}
// POST 请求的 binary 逻辑
if script.MultipartFile != "" && script.MultipartPath != "" {
script.UseMultipart = true
multiPartInfo := SetMultiPartInfo(script)
script.MultiPartInfo = unescaped(multiPartInfo)
}
stringHeader := SetHeaders(script.Headers, script.ID)
ArgmentStr := SetArguments(script.ArgumentsMap, script.ID)
ArgmentString := unescaped(ArgmentStr)
script.Arguments = ArgmentString
stringHeaderd := unescaped(stringHeader)
script.HeaderString = stringHeaderd
script.ProcType = u.Scheme
script.Domain = u.Hostname()
script.Port = u.Port()
if u.RawQuery == "" {
script.Path = u.Path
script.RowQuery = "appkey=" + conf.Conf.Melloi.AppkeyProd
} else {
script.Path = u.Path + "?" + u.RawQuery
script.RowQuery = u.RawQuery + "&appkey=" + conf.Conf.Melloi.AppkeyProd
}
if script.UseSign {
script.Path = u.Path + "?${params}"
}
dataFileName = script.FileName
script.FileName = script.ScriptPath + script.FileName
if script.ScriptPath != "" && script.FileName == "" && !script.Upload {
message = "dataFile is not exists"
log.Error(message)
return
}
if script.Loops == 0 {
script.Loops = -1
}
//极速模式线程NIO模式
if script.IsAsync {
script.AsyncInfo = unescaped(model.AsyncInfo)
}
//生成压测脚本
if sinfoJSON, err = json.Marshal(script); err != nil {
log.Error("script err (%v):", err)
return
}
sc := string(sinfoJSON)
log.Info("script :(%s)", sc)
//判断是否使用内置参数
if strings.Contains(sc, "${mid}") || strings.Contains(sc, "${access_key}") || script.UseSign {
script.UseBuiltinParam = true
}
//fileWrite = true ,需要创建文件,为 false ,不需要创建文件
if fileWrite {
//创建脚本保存路径
if script.ScriptPath == "" {
if scriptPath, err = s.uniqueFolderPath(script.SavePath); err != nil {
return
}
} else {
scriptPath = script.ScriptPath
}
SavePath := scriptPath + script.TestName + "/"
log.Info("SavePath****: " + SavePath)
if err = os.MkdirAll(SavePath, 0755); err != nil {
log.Error("Create SavePath Err :(%v)", err)
return
}
///创建脚本保存路径 脚本存放路径:部门/项目/应用/项目名/,须判断路径是否包含.jmx
if !strings.Contains(script.SavePath, ".jmx") {
// 创建脚本文件 部门/项目/应用/项目名/**.jmx
if file, err = os.Create(SavePath + script.TestName + ".jmx"); err != nil {
log.Error("create file error :(%v)", err)
message = "create .jmx error"
return
}
defer file.Close()
//jtl 路径
script.ResJtl = SavePath + script.TestName + ".jtl"
//jmeter-log 路径
script.JmeterLog = SavePath + script.TestName + ".log"
} else {
// 如果路径钟包含 .jmx ,则直接根据路径创建
if file, err = os.Create(script.SavePath); err != nil {
log.Error("create file error :(%v)", err)
message = "create .jmx error"
return
}
defer file.Close()
}
buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
buff.Execute(io.Writer(file), script)
script.SavePath = file.Name()
}
script.Ctime = time.Now()
script.ProjectName = script.TestName
if JSON, err = json.Marshal(script); err != nil {
return
}
if err = json.Unmarshal([]byte(JSON), &scriptd); err != nil {
log.Error("sorry,scriptd err(%v)", err)
return
}
scriptd.HeaderString = stringHeaderd
scriptd.Arguments = ArgmentString
scriptd.JSONExtractor = script.JSONExtractor
scriptd.Data = script.Data
scriptd.FileName = dataFileName
if script.FileName == "" || script.ParamsName == "" {
scriptd.UseDataFile = false
} else {
scriptd.UseDataFile = true
}
if len(Assertionsd) > 0 {
scriptd.AssertionString = unescaped(SliceToString(Assertionsd, " "))
}
return
}
//DelScript sel script
func (s *Service) DelScript(id int) error {
return s.dao.DelScript(id)
}
//UpdateScript update script info
func (s *Service) UpdateScript(script *model.Script) (updateResult string, err error) {
var (
buff *template.Template
stringHeader string
Headers []map[string]string
stringArgument string
Arguments []map[string]string
scriptd *model.Script
u *url.URL
file *os.File
sinfoJSON []byte
sinfoJSONd []byte
JSONExtractors string
Assertionsd []string
)
if scriptd, err = s.dao.QueryScriptByID(script.ID); err != nil {
log.Error("query script fail , error %v", err)
return
}
if script.Data == "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterScUcodedTmp)
} else {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterScTmp)
}
if err != nil {
log.Error("open file failed! error %v", err)
return
}
if u, err = url.Parse(script.URL); err != nil || u == nil {
log.Error("sorry,url is not standard,error(%v)", err)
err = ecode.MelloiUrlParseError
return
}
// 修改laodTime 和 threadsSum
// ThreadGroup.ramp_time">{{.ReadyTime}}</stringProp>
if file, err = os.Create(scriptd.SavePath); err != nil {
log.Error("create file failed! error %v", err)
return
}
defer file.Close()
if err = json.Unmarshal([]byte(scriptd.APIHeader), &Headers); err != nil {
updateResult = " scriptd.APIHeade json 不合法"
log.Error("scriptd.APIHeader switch map failed! error %v", err)
return
}
if err = json.Unmarshal([]byte(scriptd.ArgumentString), &Arguments); err != nil {
updateResult = "scriptd.ArgumentString json 不合法"
log.Error("scriptd.ArgumentString switch map failed! error %v", err)
return
}
if len(scriptd.OutputParamsMap) > 0 && scriptd.OutputParams != "" && scriptd.OutputParams != "[{\"\":\"\"}]" && scriptd.OutputParams != "[]" {
if err = json.Unmarshal([]byte(scriptd.OutputParams), &scriptd.OutputParamsMap); err != nil {
log.Error("scriptd.OutputParams switch map failed! error %v", err)
return
}
}
stringHeader = SetHeaders(Headers, scriptd.ID)
stringArgument = SetArguments(Arguments, scriptd.ID)
if len(scriptd.OutputParamsMap) > 0 && scriptd.OutputParams != "[{\"\":\"\"}]" && scriptd.OutputParams != "[]" && script.OutputParams != "" {
if JSONExtractors, err = s.SetJSONExtractors(scriptd); err != nil {
return
}
if JSONExtractors != "" {
script.JSONExtractor = unescaped(JSONExtractors)
}
}
scriptd.HeaderString = unescaped(stringHeader)
scriptd.Arguments = unescaped(stringArgument)
scriptd.Data = script.Data
scriptd.Assertion = script.Assertion
scriptd.ReadyTime = script.ReadyTime
scriptd.ThreadsSum = script.ThreadsSum
scriptd.LoadTime = script.LoadTime
scriptd.ProcType = u.Scheme
scriptd.Domain = u.Hostname()
scriptd.Port = u.Port()
scriptd.TestName = script.TestName
scriptd.FileName = scriptd.ScriptPath + scriptd.FileName
if scriptd.Assertion != "" {
scriptd.UseAssertion = true
Assertions := strings.Split(scriptd.Assertion, "|")
for _, assert := range Assertions {
Assertionsd = append(Assertionsd, model.AssertionStart+assert+model.AssertionEnd)
}
scriptd.AssertionString = unescaped(SliceToString(Assertionsd, " "))
}
//判断是否使用内置参数
if sinfoJSON, err = json.Marshal(script); err != nil {
log.Error("script err :(%s)", err)
return
}
if sinfoJSONd, err = json.Marshal(scriptd); err != nil {
log.Error("script err :(%s)", err)
return
}
sc := string(sinfoJSON) + string(sinfoJSONd)
if strings.Contains(sc, "${mid}") || strings.Contains(sc, "${access_key}") || script.UseSign {
scriptd.UseBuiltinParam = true
}
if u.RawQuery == "" {
scriptd.Path = u.Path
scriptd.RowQuery = "appkey=" + conf.Conf.Melloi.AppkeyProd
} else {
scriptd.Path = u.Path + "?" + u.RawQuery
scriptd.RowQuery = u.RawQuery + "&appkey=" + conf.Conf.Melloi.AppkeyProd
}
if scriptd.UseSign {
scriptd.Path = u.Path + "?${params}"
}
// POST 请求的 binary 逻辑
if scriptd.MultipartFile != "" && scriptd.MultipartPath != "" {
scriptd.UseMultipart = true
multiPartInfo := SetMultiPartInfo(scriptd)
scriptd.MultiPartInfo = unescaped(multiPartInfo)
}
if scriptd.IsAsync {
scriptd.AsyncInfo = unescaped(model.AsyncInfo)
}
buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
buff.Execute(io.Writer(file), scriptd)
script.ProjectName = script.TestName
script.KeepAlive = scriptd.KeepAlive
if err = s.dao.UpdateScriptPart(script); err != nil {
log.Error("s.dao.UpdateScript err :(%v)", err)
return
}
updateResult = "success"
return
}
//UpdateScriptAll update script all
func (s *Service) UpdateScriptAll(script *model.Script, scene *model.Scene) (updateResult string, err error) {
var (
scriptd model.Script
paramList *model.ParamList
isEdit = true
groupId int
runOrder int
fileWrite bool
)
id := script.ID
script.ID = 0
// script test_type 为1 表示 http 脚本
if script.TestType == model.HTTP_SCRIPT_TYPE {
fileWrite = true
}
if _, scriptd, err = s.AddScript(script, fileWrite); err != nil {
log.Error("sorry, addScript fail : (%v)", err)
return
}
if script.TestType == model.SCENE_SCRIPT_TYPE {
//根据接口参数依赖,计算出接口分组与执行顺序
if paramList, err = s.dao.QueryParams(&scriptd, scene); err != nil {
log.Error("s.dao.QueryParams err :(%v)", err)
return
}
groupId, runOrder = GroupOrderByEdit(isEdit, id, &scriptd, scene, paramList)
if groupId != 0 && runOrder != 0 {
scriptd.GroupID = groupId
scriptd.RunOrder = runOrder
}
}
scriptd.ID = id
scriptd.SavePath = ""
if scriptd.Loops == -1 {
headerString := MapToString(scriptd.Headers)
argumentString := MapToString(scriptd.ArgumentsMap)
scriptd.OutputParams = MapToString(scriptd.OutputParamsMap)
scriptd.ArgumentString = argumentString
scriptd.APIHeader = headerString
if err = s.dao.UpdateScript(&scriptd); err != nil {
log.Error("s.dao.UpdateScript err : (%v)", err)
return
}
}
updateResult = "success"
return
}
//AddJmeterSample add jmeter sample
func (s *Service) AddJmeterSample(script *model.Script) (result string, err error) {
var (
buff *template.Template
u *url.URL
b = bytes.NewBuffer(nil)
JSONExtractors string
Assertionsd []string
)
if script.Data == "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterSampleTmp)
} else {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterSamplePostTmp)
}
if err != nil {
log.Info("open template failed! (%v)", err)
return
}
//判断url
if !strings.Contains(script.URL, "http://") && !strings.Contains(script.URL, "https://") {
script.URL = "http://" + script.URL
}
if script.Delimiter == "" {
script.Delimiter = ","
}
if u, err = url.Parse(script.URL); err != nil || u == nil {
log.Error("sorry,url is not standard,error(%v)", err)
err = ecode.MelloiUrlParseError
return
}
stringHeader := SetHeaders(script.Headers, script.ID)
ArgmentStr := SetArguments(script.ArgumentsMap, script.ID)
ArgmentString := unescaped(ArgmentStr)
if len(script.OutputParamsMap) > 0 && script.OutputParams != "[{\"\":\"\"}]" && script.OutputParams != "[]" && script.OutputParams != "" {
if JSONExtractors, err = s.SetJSONExtractors(script); err != nil {
return
}
if JSONExtractors != "" {
script.JSONExtractor = unescaped(JSONExtractors)
}
}
script.Arguments = ArgmentString
stringHeaderd := unescaped(stringHeader)
script.HeaderString = stringHeaderd
script.ProcType = u.Scheme
script.Domain = u.Hostname()
script.Port = u.Port()
script.FileName = script.ScriptPath + script.FileName
if u.RawQuery == "" {
script.Path = u.Path
script.RowQuery = "appkey=" + conf.Conf.Melloi.AppkeyProd
} else {
script.Path = u.Path + "?" + u.RawQuery
script.RowQuery = u.RawQuery + "&appkey=" + conf.Conf.Melloi.AppkeyProd
}
if script.UseSign {
script.Path = u.Path + "?${params}"
}
if script.Assertion != "" {
script.UseAssertion = true
Assertions := strings.Split(script.Assertion, "|")
for _, assert := range Assertions {
Assertionsd = append(Assertionsd, model.AssertionStart+assert+model.AssertionEnd)
}
script.AssertionString = unescaped(SliceToString(Assertionsd, " "))
}
if script.ConstTimer > 0 && script.RandomTimer == 0 {
constTimer := strings.Replace(model.ConstTimer, "1000", strconv.Itoa(script.ConstTimer), -1)
script.ConstTimerInfo = unescaped(constTimer)
}
if script.ConstTimer > 0 && script.RandomTimer > 0 {
constTimerd := strings.Replace(model.RandomTimer, "1000", strconv.Itoa(script.ConstTimer), -1)
randomTimerd := strings.Replace(constTimerd, "500", strconv.Itoa(script.RandomTimer), -1)
script.RandomTimerInfo = unescaped(randomTimerd)
}
buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
buff.Execute(b, script)
result = b.String()
return
}
//AddThreadGroup add thread group
func (s *Service) AddThreadGroup(script *model.Script, sceneType int) (result string, err error) {
var (
buff *template.Template
scriptd model.Script
b = bytes.NewBuffer(nil)
)
if _, scriptd, err = s.AddScript(script, false); err != nil {
log.Error("s.AddScript err :(%v)", err)
return
}
//并行get
if sceneType == 1 && script.Data == "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterThGroupTmp)
}
//并行post
if sceneType == 1 && script.Data != "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterThGroupPostTmp)
}
//串行get
if sceneType == 2 && script.Data == "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterThGroupDuliTmp)
}
//串行 post
if sceneType == 2 && script.Data != "" {
buff, err = template.ParseFiles(s.c.Jmeter.JmeterThGroupPostDuliTmp)
}
if err != nil {
log.Info("open template failed! (%v)", err)
return
}
buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
scriptd.FileName = scriptd.ScriptPath + scriptd.FileName
buff.Execute(b, scriptd)
result = b.String()
return
}
//GetThreadGroup get thread group
func (s *Service) GetThreadGroup(scrThreadGroup model.ScrThreadGroup) (threadGroup string, err error) {
var (
threadGroups []string
IsSerial bool
groups []int
groupMap = make(map[int]int)
RunOrders []int
scriptsd []*model.Script
scriptsds [][]*model.Script
threadGroupd string
threadGroupds []string
threadSamples []string
threadSample string
threadSamplesd string
threadGrou string
)
for _, script := range scrThreadGroup.Scripts {
RunOrders = append(RunOrders, script.RunOrder)
groupMap[script.GroupID]++
if script.APIHeader != "" && 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 != "" && 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 != "" && script.OutputParams != "[{\"\":\"\"}]" && 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)
}
}
}
for _, order := range RunOrders {
if order > 1 {
IsSerial = true
break
}
}
for k := range groupMap {
groups = append(groups, k)
}
//并行脚本逻辑
if !IsSerial {
for _, script := range scrThreadGroup.Scripts {
if threadGrou, err = s.AddThreadGroup(script, 1); err != nil {
log.Error("d.GetThroupGroupJmeter: error(%v)", err)
return
}
threadGroups = append(threadGroups, threadGrou)
}
for _, thgroup := range threadGroups {
threadGroupd = threadGroupd + thgroup
}
threadGroup = threadGroupd
return
}
//串行脚本逻辑
for _, group := range groups {
for i := 0; i < len(scrThreadGroup.Scripts); i++ {
if scrThreadGroup.Scripts[i].GroupID == group {
scriptsd = append(scriptsd, scrThreadGroup.Scripts[i])
}
}
scriptsds = append(scriptsds, scriptsd)
scriptsd = []*model.Script{}
}
// 每个线程组内的接口,按照接口的 RunOrder 属性进行排序
for _, scriptsd := range scriptsds {
for i := 0; i < len(scriptsd)-1; i++ {
for j := i + 1; j < len(scriptsd); j++ {
if scriptsd[i].RunOrder > scriptsd[j].RunOrder {
tmp := scriptsd[i]
scriptsd[i] = scriptsd[j]
scriptsd[j] = tmp
}
}
}
}
for k := 0; k < len(scriptsds); k++ {
if len(scriptsds[k]) == 1 {
if threadGroupd, err = s.AddThreadGroup(scriptsds[k][0], 1); err != nil {
log.Error("d.GetThroupGroupJmeter: error(%v)", err)
return
}
} else {
//生成一个线程组,再往线程组插入 sample
if threadGroupd, err = s.AddThreadGroup(scriptsds[k][0], 2); err != nil {
log.Error(" s.AddScript err :(%v)", err)
return
}
for i := 0; i < len(scriptsds[k]); i++ {
//从第二个接口开始生成 sample
if i > 0 {
if threadSample, err = s.AddJmeterSample(scriptsds[k][i]); err != nil {
log.Error("s.dao.GetThroupSeriesSample err :(%v)", err)
return
}
threadSamples = append(threadSamples, threadSample)
}
}
}
for j := 0; j < len(threadSamples); j++ {
threadSamplesd = threadSamplesd + threadSamples[j]
}
//生成一个 线程组
threadGroupM := strings.Replace(threadGroupd, "+-+-+*", threadSamplesd, -1)
//多个线程组
threadGroupds = append(threadGroupds, threadGroupM)
threadSamples = []string{}
threadSamplesd = ""
}
for _, threadGrou := range threadGroupds {
threadGroup = threadGroup + threadGrou
}
return
}
//URLCheck url check
func (s *Service) URLCheck(script *model.Script) (urlEncode *model.URLEncode, err error) {
var (
tempUrl *url.URL
)
urlEncode = &model.URLEncode{}
if strings.Contains(script.URL, "?") {
if tempUrl, err = url.Parse(script.URL); err != nil {
return
}
params := tempUrl.RawQuery
paramList := strings.Split(params, "&")
for _, param := range paramList {
value := strings.Split(param, "=")[1]
var myMap map[string]interface{}
if err = json.Unmarshal([]byte(value), &myMap); err != nil {
urlEncode.ParamsType = "nojson"
urlEncode.NewUrl = script.URL
continue
}
urlEncode.ParamsType = "json"
newParams := tempUrl.Query().Encode()
urlEncode.NewUrl = strings.Split(script.URL, "?")[0] + "?" + newParams
return
}
}
return
}
//AddTimer add Timer
func (s *Service) AddTimer(script *model.Script) error {
return s.dao.AddScriptTimer(script)
}
//SetHeaders set headers
func SetHeaders(Headers []map[string]string, scriptId int) (stringHeader string) {
var (
stringHeaders []string
HeaderString string
)
// 表示直接生成的脚本,非修改
if scriptId == 0 {
for _, header := range Headers {
k := header["key"]
v := header["value"]
HeaderString = model.HeaderStart + k + model.HeaderMid + v + model.HeaderEnd
stringHeaders = append(stringHeaders, HeaderString)
}
} else {
//修改脚本header 从数据库取出的
for _, header := range Headers {
for k, v := range header {
HeaderString = model.HeaderStart + k + model.HeaderMid + v + model.HeaderEnd
stringHeaders = append(stringHeaders, HeaderString)
}
}
}
for _, str := range stringHeaders {
stringHeader = stringHeader + str + "\r\n"
}
return
}
//SetArguments set argument
func SetArguments(Arguments []map[string]string, scriptId int) (stringArgument string) {
var (
stringArguments []string
ArgumentString string
)
// 表示直接生成的脚本,非修改
if scriptId == 0 {
for _, argument := range Arguments {
k := argument["key"]
v := argument["value"]
ArgumentString = model.ElementPropName + k + model.HTTPArgument + model.HTTPArgumentEncode + model.ArgumentStart + v + model.ArgumentMid + k + model.ArgumentEnd
stringArguments = append(stringArguments, ArgumentString)
}
} else {
//修改脚本argument 从数据库取出的
for _, argument := range Arguments {
for k, v := range argument {
ArgumentString = model.ElementPropName + k + model.HTTPArgument + model.HTTPArgumentEncode + model.ArgumentStart + v + model.ArgumentMid + k + model.ArgumentEnd
stringArguments = append(stringArguments, ArgumentString)
}
}
}
for _, str := range stringArguments {
stringArgument = stringArgument + str + "\r\n"
}
return
}
//SetJSONExtractor set JSONExtractorgo
func (s *Service) SetJSONExtractor(jsonExt model.JSONExtractor) (JSONExtractor string, err error) {
var (
buff *template.Template
b = bytes.NewBuffer(nil)
)
buff, err = template.ParseFiles(s.c.Jmeter.JSONExtractorTmp)
if err != nil {
log.Info("open template failed! (%v)", err)
return
}
buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
buff.Execute(b, jsonExt)
JSONExtractor = b.String()
return
}
//SetJSONExtractors Set JSONExtractors
func (s *Service) SetJSONExtractors(script *model.Script) (JSONExtractors string, err error) {
var (
JSONExtractords []string
jsonExt model.JSONExtractor
JSONExtractord string
)
// 表示直接生成的脚本,非修改
if script.ID == 0 {
for _, OutputParam := range script.OutputParamsMap {
jsonExt.JSONName = OutputParam["key"]
jsonExt.JSONPath = OutputParam["value"]
if jsonExt.JSONName != "" && jsonExt.JSONPath != "" {
if JSONExtractord, err = s.SetJSONExtractor(jsonExt); err != nil {
log.Error("SetJSONExtractor err :(%v) ", err)
return
}
JSONExtractords = append(JSONExtractords, JSONExtractord)
}
}
} else {
//修改脚本header 从数据库取出的
for _, OutputParam := range script.OutputParamsMap {
for k, v := range OutputParam {
jsonExt.JSONName = k
jsonExt.JSONPath = v
}
if jsonExt.JSONName != "" && jsonExt.JSONPath != "" {
if JSONExtractord, err = s.SetJSONExtractor(jsonExt); err != nil {
log.Error("SetJSONExtractor err :(%v) ", err)
return
}
JSONExtractords = append(JSONExtractords, JSONExtractord)
}
}
}
JSONExtractors = SliceToString(JSONExtractords, " ")
return
}
//SetMultiPartInfo Set MultiPartInfo
func SetMultiPartInfo(script *model.Script) (multiPartInfo string) {
multiPartInfo = model.MultipartName + script.MultipartPath + script.MultipartFile + model.MultipartFilePath +
script.MultipartPath + script.MultipartFile + model.MultipartFilePathd + script.MultipartParam +
model.MultipartMimetype + script.MimeType + model.MultipartEnd
return
}
//MapToString map to string
func MapToString(strMapArr []map[string]string) (headerString string) {
for _, strMap := range strMapArr {
k, keyOk := strMap["key"]
v, valueOK := strMap["value"]
if keyOk != valueOK {
return
}
if keyOk {
delete(strMap, "key")
delete(strMap, "value")
strMap[k] = v
}
}
headers, _ := json.Marshal(strMapArr)
headerString = string(headers)
return
}
//StringToMap string to map
func StringToMap(headerString string) (mapHeaders []map[string]string) {
if headerString != "[{\"\":\"\"}]" {
if err := json.Unmarshal([]byte(headerString), &mapHeaders); err != nil {
return
}
}
return
}
func unescaped(x string) interface{} {
return template.HTML(x)
}
//HostInfo add hostinfo
func HostInfo(domain string, apiHeader string) (hostInfo string) {
mapHeaders := StringToMap(apiHeader)
reg := regexp.MustCompile(`.com|.co`)
strs := reg.FindAllString(domain, -1)
if len(strs) != 0 {
for _, str := range strs {
if (strings.Contains(str, ".com") || strings.Contains(str, ".co")) && strings.Contains(apiHeader, domain) { //绑定至用户指定的ip
for _, header := range mapHeaders {
for host := range header {
conf.Conf.Paas.HostInfo = domain + ":" + host
hostInfo = conf.Conf.Paas.HostInfo
}
}
} else if strings.Contains(str, ".com") || strings.Contains(str, ".co") { //默认绑定至172.22.22.222
conf.Conf.Paas.HostInfo = domain + ":" + conf.Conf.Melloi.DefaultHost
hostInfo = conf.Conf.Paas.HostInfo
}
}
}
return
}
//HostInfoList add hostinfo list
func HostInfoList(scripts []*model.Script) (hostInfo string) {
for _, script := range scripts {
mapHeaders := StringToMap(script.APIHeader)
reg := regexp.MustCompile(`.com|.co`)
strs := reg.FindAllString(script.Domain, -1)
if len(strs) != 0 {
for _, str := range strs {
if (strings.Contains(str, ".com") || strings.Contains(str, ".co")) && strings.Contains(script.APIHeader, script.Domain) { //绑定至用户指定的ip
for _, header := range mapHeaders {
for host := range header {
conf.Conf.Paas.HostInfo = script.Domain + ":" + host
hostInfo = conf.Conf.Paas.HostInfo
}
}
} else if strings.Contains(str, ".com") || strings.Contains(str, ".co") { //默认绑定至172.22.22.222
hostInfo = hostInfo + script.Domain + ":" + conf.Conf.Melloi.DefaultHost + ","
}
}
}
}
conf.Conf.Paas.HostInfo = hostInfo
return
}
//HostInfoByUploadSc host info By UploadSc
func HostInfoByUploadSc(domain string) (hostInfo string) {
domains := strings.Split(domain, ",")
for _, dom := range domains {
hostInfo = hostInfo + dom + ":" + conf.Conf.Melloi.DefaultHost + ","
}
conf.Conf.Paas.HostInfo = hostInfo
return
}
// GroupOrder Group Order
func GroupOrder(isEdit bool, script *model.Script, scene *model.Scene, paramList *model.ParamList) (groupId int, runOrder int) {
var (
flag = 0
//tmpIndex = 0
u *url.URL
err error
)
if u, err = url.Parse(script.URL); err != nil || u == nil {
log.Error("sorry, url is wrong, please check. error(%v)", err)
err = ecode.MelloiUrlParseError
return
}
if len(paramList.ParamList) > 0 {
for _, paramList := range paramList.ParamList {
tempList := strings.Split(u.RawQuery, "&")
tempHeaderList := strings.Split(script.APIHeader, ",")
tempArgumentList := strings.Split(script.ArgumentString, ",")
tempDataList := strings.Split(script.Data, ",")
if u.RawQuery == "" && (script.APIHeader == "[{\"\":\"\"}]" || script.APIHeader == "[]") && script.Data == "" && (script.ArgumentString == "[{\"\":\"\"}]" || script.ArgumentString == "[]") {
if scene.SceneType == 1 || scene.SceneType == 0 {
groupId = paramList.GroupID + 1
runOrder = 1
continue
} else if scene.SceneType == 2 {
groupId = paramList.GroupID
runOrder = paramList.RunOrder + 1
continue
}
}
//url params check
if u.RawQuery != "" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
//} else if flag == 2 {
// tmpIndex = index
// break
}
}
//APIHeader params check
if script.APIHeader != "[{\"\":\"\"}]" && script.APIHeader != "[]" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempHeaderList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
//ArgumentString params check
if script.ArgumentString != "[{\"\":\"\"}]" && script.ArgumentString != "[]" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempArgumentList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
//body params check
if script.Data != "" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempDataList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
}
//for i := tmpIndex; i < len(paramList.ParamList); i++ {
// if err = s.dao.UpdateRunOrder(paramList.ParamList[i].); err != nil {
// log.Error("s.dao.UpdateScript err :(%v)", err)
// return
// }
//}
} else if script.GroupID != 0 {
groupId = script.GroupID
runOrder = 1
} else {
groupId = 1
runOrder = 1
}
return
}
// GroupOrderByEdit Group Order By Edit
func GroupOrderByEdit(isEdit bool, id int, script *model.Script, scene *model.Scene, paramList *model.ParamList) (groupId int, runOrder int) {
var (
flag = 0
//tmpIndex = 0
u *url.URL
err error
)
if u, err = url.Parse(script.URL); err != nil || u == nil {
log.Error("sorry, url is wrong, please check. error(%v)", err)
err = ecode.MelloiUrlParseError
return
}
if len(paramList.ParamList) > 0 {
for _, paramList := range paramList.ParamList {
if paramList.ID != id {
tempList := strings.Split(u.RawQuery, "&")
tempHeaderList := strings.Split(script.APIHeader, ",")
tempArgumentList := strings.Split(script.ArgumentString, ",")
tempDataList := strings.Split(script.Data, ",")
//url params check
if u.RawQuery != "" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
//APIHeader params check
if script.APIHeader != "[{\"\":\"\"}]" && script.APIHeader != "[]" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempHeaderList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
//ArgumentString params check
if script.ArgumentString != "[{\"\":\"\"}]" && script.ArgumentString != "[]" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempArgumentList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
//body params check
if script.Data != "" {
if groupId, runOrder, flag, err = OrderEach(isEdit, tempDataList, paramList, scene.SceneType); err != nil || (runOrder != 1 && flag == 0) {
return
}
}
}
}
}
return
}
// OrderEach Order Each
func OrderEach(isEdit bool, strList []string, paramList *model.Params, sceneType int) (groupId int, runOrder int, flag int, err error) {
for _, paramPage := range strList {
if strings.Contains(paramPage, "$") {
tempParam := strings.Split(paramPage, "$")[1]
param := RegularTrans(tempParam)
//several params
if strings.Contains(paramList.OutputParams, ",") {
dbTempList := strings.Split(paramList.OutputParams, ",")
for _, dbParam := range dbTempList {
flag = 0
finalParam := strings.Split(strings.Split(dbParam, "\":\"")[0], "\"")[1]
if param == finalParam {
groupId = paramList.GroupID
runOrder = paramList.RunOrder + 1
return
}
if !isEdit {
if sceneType == 1 || sceneType == 0 {
groupId = paramList.GroupID + 1
runOrder = 1
} else if sceneType == 2 {
groupId = paramList.GroupID
runOrder = paramList.RunOrder + 1
flag = 1
}
}
}
} else { //single param
dbParam := paramList.OutputParams
finalParam := strings.Split(strings.Split(dbParam, "\":\"")[0], "\"")[1]
if param == finalParam {
groupId = paramList.GroupID
runOrder = paramList.RunOrder + 1
return
}
if !isEdit {
if sceneType == 1 || sceneType == 0 {
groupId = paramList.GroupID + 1
runOrder = 1
} else if sceneType == 2 {
groupId = paramList.GroupID
runOrder = paramList.RunOrder + 1
flag = 1
}
}
}
} else {
if !isEdit {
if sceneType == 1 || sceneType == 0 {
groupId = paramList.GroupID + 1
runOrder = 1
} else if sceneType == 2 {
groupId = paramList.GroupID
runOrder = paramList.RunOrder + 1
flag = 1
}
}
}
}
return
}
// RegularTrans Regular Trans
func RegularTrans(tempStr string) (targetStr string) {
reg := regexp.MustCompile(`[\w]+`)
str := reg.FindAllString(tempStr, -1)
if len(str) != 0 {
targetStr = str[0]
}
return targetStr
}