123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- package service
- import (
- "context"
- "fmt"
- "html/template"
- "io"
- "os"
- "os/exec"
- "path"
- "strconv"
- "strings"
- "time"
- "go-common/app/admin/ep/melloi/model"
- "go-common/app/admin/ep/melloi/service/proto"
- "go-common/library/ecode"
- "go-common/library/log"
- )
- const (
- _upCase = 1
- _downCase = 0
- )
- // capitalize 首字母大小写处理
- func (s *Service) capitalize(str string, tp int) string {
- b := []rune(str)
- if tp == _upCase {
- if b[0] >= 97 && b[1] <= 122 {
- b[0] -= 32
- }
- } else {
- if b[0] >= 64 && b[0] <= 90 {
- b[0] += 32
- }
- }
- return string(b)
- }
- // ProtoParsing analyze proto file
- func (s *Service) ProtoParsing(protoPath, protoName string) (res map[string]interface{}, err error) {
- var pkgRetMap []string
- res = make(map[string]interface{})
- reader, err := os.Open(path.Join(protoPath, protoName))
- if err != nil {
- log.Error("open proto file error(%v)", err)
- return nil, err
- }
- defer reader.Close()
- parser := proto.NewParser(reader)
- var proto *proto.Proto
- proto, err = parser.Parse()
- if err != nil {
- log.Error("parse proto file error(%v)", err)
- return nil, err
- }
- res["fileName"] = protoName
- proto.Filename = strings.TrimSuffix(protoName, ".proto")
- res["protoClass"] = s.capitalize(proto.Filename, _upCase)
- if len(proto.Imports) > 0 {
- var retImportMap []string
- for _, impt := range proto.Imports {
- retImportMap = append(retImportMap, impt.Filename)
- }
- res["import"] = retImportMap
- }
- if len(proto.Package) > 0 {
- for _, pkg := range proto.Package {
- pkgRetMap = append(pkgRetMap, pkg.Name)
- }
- res["package"] = pkgRetMap
- }
- if len(proto.Options) > 0 {
- var retOptionsList []string
- for _, opt := range proto.Options {
- retOptionsList = append(retOptionsList, opt.Name)
- // java_package proto
- if opt.Name == "java_package" && len(proto.Package) <= 0 {
- pkgRetMap = append(pkgRetMap, opt.Constant.Source)
- }
- }
- res["package"] = pkgRetMap
- res["options"] = retOptionsList
- }
- if len(proto.Services) > 0 {
- var retImportMap []map[string]interface{}
- for _, srv := range proto.Services {
- firstTmp := make(map[string]interface{})
- firstTmp["name"] = srv.Name
- var secondMapTmp []map[string]interface{}
- for _, rpc := range srv.RPCElements {
- secondTmp := make(map[string]interface{})
- method := s.capitalize(rpc.Name, _downCase)
- // transfer get_by_uid to getByUid
- if strings.ContainsAny(method, "_") {
- var nmethod string
- methodStrs := strings.Split(method, "_")
- for i, item := range methodStrs {
- if i != 0 {
- item = s.capitalize(item, _upCase)
- }
- nmethod += item
- }
- method = nmethod
- }
- secondTmp["method"] = method
- secondTmp["requestType"] = rpc.RequestType
- secondTmp["returnType"] = rpc.ReturnsType
- secondMapTmp = append(secondMapTmp, secondTmp)
- }
- firstTmp["rpc"] = secondMapTmp
- retImportMap = append(retImportMap, firstTmp)
- }
- res["service"] = retImportMap
- }
- return
- }
- // CreateProtoImportDir create import dir
- func (s *Service) CreateProtoImportDir(pathModel *model.ProtoPathModel) (err error) {
- cMakeDir := fmt.Sprintf("mkdir -p %s ", path.Join(pathModel.RootPath, pathModel.ExtraPath))
- if err = exec.Command("/bin/bash", "-c", cMakeDir).Run(); err != nil {
- log.Error("create proto import dir error(%v)", err)
- }
- return
- }
- //GRPCQuickStart grpc quickstart
- func (s *Service) GRPCQuickStart(c context.Context, request *model.GRPCQuickStartRequest, runUser string, cookies string) (ret map[string]string, err error) {
- var (
- g *model.GRPC
- reportID int
- )
- addScriptReq := request.GRPCAddScriptRequest
- ret = make(map[string]string)
- if g, err = s.GRPCAddScript(c, &addScriptReq); err != nil {
- log.Error("Save grpc script failed, (%v)", err)
- return
- }
- if reportID, err = s.GRPCRunByModel(c, g, runUser, cookies); err != nil {
- log.Error("performance test execution failed, (%v)", err)
- return
- }
- ret["report_id"] = strconv.Itoa(reportID)
- return
- }
- // SaveGRPCQuickStart save gRPC script of quick start
- func (s *Service) SaveGRPCQuickStart(c context.Context, request *model.GRPCQuickStartRequest) (err error) {
- addScriptReq := request.GRPCAddScriptRequest
- _, err = s.GRPCAddScript(c, &addScriptReq)
- return err
- }
- //GRPCAddScript create grpc script
- func (s *Service) GRPCAddScript(c context.Context, request *model.GRPCAddScriptRequest) (g *model.GRPC, err error) {
- // 若是debug ,则执行固定次数
- if request.IsDebug == 1 {
- request.Loops = 4
- request.ThreadsSum = 1
- request.TaskName += "_perf_debug" // debug tag
- }
- if g, err = s.CreateJmx(c, request); err != nil {
- log.Error("create jmeter file error (%v)", err)
- return
- }
- g.IsDebug = request.IsDebug
- return s.dao.CreateGRPC(g)
- }
- // CreateJmx create jmx
- func (s *Service) CreateJmx(c context.Context, request *model.GRPCAddScriptRequest) (g *model.GRPC, err error) {
- if g, err = s.createJmeterFile(request); err != nil {
- log.Error("create jmeter file error (%v)", err)
- return
- }
- return
- }
- //GRPCRunByScriptID grpc execution by id
- func (s *Service) GRPCRunByScriptID(c context.Context, request *model.GRPCExecuteScriptRequest, runUser string, cookie string) (reportId int, err error) {
- var grpc *model.GRPC
- if grpc, err = s.dao.QueryGRPCByID(request.ScriptID); err != nil {
- return
- }
- return s.GRPCRunByModel(c, grpc, runUser, cookie)
- }
- //GRPCRunByModel execute grpc by model data
- func (s *Service) GRPCRunByModel(c context.Context, grpc *model.GRPC, runUser string, cookie string) (reportId int, err error) {
- var resp model.DoPtestResp
- tim := strconv.FormatInt(time.Now().Unix(), 10)
- testNameNick := grpc.TaskName + tim
- log.Info("开始调用压测grpc job-------\n")
- ptestParam := model.DoPtestParam{
- UserName: runUser, // 用户名
- LoadTime: grpc.LoadTime, //运行时间
- TestNames: StringToSlice(grpc.TaskName), //接口名转数组
- FileName: grpc.JmxPath, // jmx文件
- ResJtl: grpc.JtlLog, // jtl时间戳
- JmeterLog: grpc.JmxLog, // jmeterlog时间戳
- Department: grpc.Department,
- Project: grpc.Project,
- IsDebug: false,
- APP: grpc.APP,
- ScriptID: grpc.ID,
- Cookie: cookie, // 用不到
- URL: grpc.ServiceName, // 用于微信通知
- LabelIDs: nil,
- Domain: grpc.HostName, // 微信通知Domain
- FileSplit: false, // 文件切割
- SplitNum: 0, // 切割数量
- JarPath: grpc.JarPath,
- Type: model.PROTOCOL_GRPC, //grpc
- }
- if grpc.IsDebug == 1 {
- ptestParam.IsDebug = true
- }
- if resp, err = s.DoPtestByJmeter(c, ptestParam, StringToSlice(testNameNick)); err != nil {
- log.Error("s.DoPtestByJmeter err :(%v)", err)
- return
- }
- reportId = resp.ReportSuID
- return
- }
- //QueryGrpc query grpc list
- func (s *Service) QueryGrpc(c context.Context, sessionID string, qgr *model.QueryGRPCRequest) (res *model.QueryGRPCResponse, err error) {
- // 获取服务树节点
- var (
- treeNodes []string
- treeNodesd []string
- )
- if treeNodesd, err = s.QueryUserRoleNode(c, sessionID); err != nil {
- log.Error("QueryUserRoleNode err (%v):", err)
- return
- }
- treeNodes = append(treeNodesd, "")
- if ExistsInSlice(qgr.Executor, s.c.Melloi.Executor) {
- return s.dao.QueryGRPCByWhiteName(&qgr.GRPC, qgr.PageNum, qgr.PageSize)
- }
- return s.dao.QueryGRPC(&qgr.GRPC, qgr.PageNum, qgr.PageSize, treeNodes)
- }
- //QueryGrpcById query grpc by id
- func (s *Service) QueryGrpcById(id int) (*model.GRPC, error) {
- return s.dao.QueryGRPCByID(id)
- }
- // UpdateGrpc update grpc
- func (s *Service) UpdateGrpc(grpc *model.GRPC) error {
- return s.dao.UpdateGRPC(grpc)
- }
- // DeleteGrpc delete grpc by id
- func (s *Service) DeleteGrpc(id int) error {
- return s.dao.DeleteGRPC(id)
- }
- //createJmx create jmx file, jtl file, jmx_log file
- func (s *Service) createJmeterFile(grpcReq *model.GRPCAddScriptRequest) (g *model.GRPC, err error) {
- var (
- buff *template.Template
- file *os.File
- )
- if buff, err = template.ParseFiles(s.c.Jmeter.GRPCTemplatePath); err != nil {
- log.Error("open grpc.jmx failed! (%v)", err)
- return nil, ecode.MelloiJmeterGenerateErr
- }
- g = model.GRPCReqToGRPC(grpcReq)
- // 脚本执行限制
- if g.LoadTime > s.c.Jmeter.TestTimeLimit {
- g.LoadTime = s.c.Jmeter.TestTimeLimit
- }
- if g.Loops <= 0 {
- g.Loops = -1
- }
- if g.IsAsync {
- g.AsyncInfo = unescaped(model.AsyncInfo)
- }
- // 生成jmx文件
- if grpcReq.ScriptPath == "" {
- log.Error("proto file is not uploaded.")
- return nil, ecode.MelloiProtoFileNotUploaded
- }
- g.JmxPath = path.Join(grpcReq.ScriptPath, grpcReq.TaskName+".jmx")
- g.JmxLog = path.Join(grpcReq.ScriptPath, grpcReq.TaskName+".log") // 定义好即可,运行时生成
- g.JtlLog = path.Join(grpcReq.ScriptPath, grpcReq.TaskName+".jtl") // 定义好即可,运行时生成
- if g.ParamFilePath != "" {
- g.ParamEnable = "true"
- }
- if file, err = os.Create(g.JmxPath); err != nil {
- log.Error("create jmx file error :(%v)", err)
- return nil, ecode.MelloiJmeterGenerateErr
- }
- defer file.Close()
- // 写入模板数据
- buff = buff.Funcs(template.FuncMap{"unescaped": unescaped})
- if err = buff.Execute(io.Writer(file), g); err != nil {
- log.Error("write jmeter file failed, (%v)", err)
- return nil, ecode.MelloiJmeterGenerateErr
- }
- return
- }
|