From a7c19a65ff88a7c28b73d0bd94f545096c9da3bf Mon Sep 17 00:00:00 2001 From: vearne Date: Wed, 23 Oct 2024 20:29:04 +0800 Subject: [PATCH 1/2] support grpc html report --- internal/command/common.go | 18 +++++++++++++ internal/command/grpc_automate.go | 40 +++++++++++++++++++++++++++-- internal/command/grpc_call.go | 42 ++++++++++++++++++++++++++++--- internal/command/http_automate.go | 18 +------------ 4 files changed, 95 insertions(+), 23 deletions(-) diff --git a/internal/command/common.go b/internal/command/common.go index c41fdf8..91402f0 100644 --- a/internal/command/common.go +++ b/internal/command/common.go @@ -1,6 +1,7 @@ package command import ( + "embed" "fmt" "github.com/antchfx/jsonquery" "github.com/flosch/pongo2/v6" @@ -10,6 +11,23 @@ import ( "strings" ) +//go:embed template/*.tpl +var mytpl embed.FS + +type ResultInfo struct { + Total int + SuccessCount int + FailedCount int +} + +type CaseShow struct { + ID uint64 + Description string + State string + Reason string + Link string +} + func templateRender(tplStr string) (string, error) { // Compile the template first (i. e. creating the AST) tpl, err := pongo2.FromString(tplStr) diff --git a/internal/command/grpc_automate.go b/internal/command/grpc_automate.go index 5546859..0727c0f 100644 --- a/internal/command/grpc_automate.go +++ b/internal/command/grpc_automate.go @@ -2,6 +2,7 @@ package command import ( "context" + "fmt" "github.com/lianggaoqiang/progress" "github.com/vearne/autotest/internal/config" "github.com/vearne/autotest/internal/model" @@ -48,7 +49,7 @@ func GrpcAutomateTest(grpcTestCases map[string][]*config.TestCaseGrpc) { slog.Info("GrpcTestCases, total:%v, finishCount:%v, successCount:%v, failedCount:%v", total, finishCount, successCount, failedCount) // generate report file - GenReportFileGrpc(filePath, tcResultList) + GenReportFileGrpc(filePath, tcResultList, info) } slog.Info("[end]GrpcTestCases, total:%v, cost:%v", total, time.Since(begin)) } @@ -146,7 +147,7 @@ func HandleSingleFileGrpc(workerNum int, filePath string) (*ResultInfo, []GrpcTe FailedCount: failedCount}, tcResultList } -func GenReportFileGrpc(testCasefilePath string, tcResultList []GrpcTestCaseResult) { +func GenReportFileGrpc(testCasefilePath string, tcResultList []GrpcTestCaseResult, info *ResultInfo) { filename := filepath.Base(testCasefilePath) name := strings.TrimSuffix(filename, filepath.Ext(filename)) filename = name + ".csv" @@ -156,6 +157,7 @@ func GenReportFileGrpc(testCasefilePath string, tcResultList []GrpcTestCaseResul sort.Slice(tcResultList, func(i, j int) bool { return tcResultList[i].ID < tcResultList[j].ID }) + // 1. csv file var records [][]string records = append(records, []string{"id", "desc", "state", "reason"}) for _, item := range tcResultList { @@ -167,4 +169,38 @@ func GenReportFileGrpc(testCasefilePath string, tcResultList []GrpcTestCaseResul item.Desc, item.State.String(), reasonStr}) } util.WriterCSV(reportPath, records) + // 2. html file + dirName := util.MD5(reportDirPath + name) + + var caseResults []CaseShow + for _, item := range tcResultList { + caseResults = append(caseResults, CaseShow{ID: item.ID, Description: item.Desc, + State: item.State.String(), Reason: item.Reason.String(), + Link: fmt.Sprintf("./%v/%v.html", dirName, item.ID)}) + } + obj := map[string]any{ + "info": info, + "tcResultList": caseResults, + } + // index file + err := RenderTpl(mytpl, "template/index.tpl", obj, filepath.Join(reportDirPath, name+".html")) + if err != nil { + slog.Error("RenderTpl, %v", err) + return + } + + // case file + for _, item := range tcResultList { + data := map[string]any{ + "Error": item.Error, + "reqDetail": item.ReqDetail(), + "respDetail": item.RespDetail(), + } + err := RenderTpl(mytpl, "template/case.tpl", data, + filepath.Join(reportDirPath, dirName, strconv.Itoa(int(item.ID))+".html")) + if err != nil { + slog.Error("RenderTpl, %v", err) + return + } + } } diff --git a/internal/command/grpc_call.go b/internal/command/grpc_call.go index 5376b2a..c5d9ff7 100644 --- a/internal/command/grpc_call.go +++ b/internal/command/grpc_call.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "github.com/fullstorydev/grpcurl" + // ignore SA1019 we have to import this because it appears in exported API "github.com/golang/protobuf/proto" //nolint:staticcheck "github.com/jhump/protoreflect/desc" @@ -31,6 +32,38 @@ type GrpcTestCaseResult struct { Request config.RequestGrpc TestCase *config.TestCaseGrpc KeyValues map[string]any + Error error + Response *model.GrpcResp +} + +func (t *GrpcTestCaseResult) ReqDetail() string { + var builder strings.Builder + builder.WriteString(fmt.Sprintf("ADDRESS: %v\n", t.Request.Address)) + builder.WriteString(fmt.Sprintf("SYMBOL: %v\n", t.Request.Symbol)) + builder.WriteString("HEADERS:\n") + for _, item := range t.Request.Headers { + builder.WriteString(fmt.Sprintf("%v\n", item)) + } + builder.WriteString("BODY:\n") + builder.WriteString(fmt.Sprintf("%v\n", t.Request.Body)) + return builder.String() +} + +func (t *GrpcTestCaseResult) RespDetail() string { + if t.Response == nil { + return "" + } + + var builder strings.Builder + builder.WriteString(fmt.Sprintf("GRPC.CODE: %v\n", t.Response.Code)) + builder.WriteString(fmt.Sprintf("GRPC.MESSAGE %v\n", t.Response.Message)) + builder.WriteString("HEADERS:\n") + for _, item := range t.Response.Headers { + builder.WriteString(fmt.Sprintf("%v\n", item)) + } + builder.WriteString("BODY:\n") + builder.WriteString(fmt.Sprintf("%v\n", t.Response.Body)) + return builder.String() } type GrpcTestCallable struct { @@ -40,7 +73,6 @@ type GrpcTestCallable struct { func (m *GrpcTestCallable) Call(ctx context.Context) *executor.GPResult { r := executor.GPResult{} - var dialErr error var cc *grpc.ClientConn var rf grpcurl.RequestParser var formatter grpcurl.Formatter @@ -94,6 +126,7 @@ func (m *GrpcTestCallable) Call(ctx context.Context) *executor.GPResult { if err != nil { tcResult.State = model.StateFailed tcResult.Reason = model.ReasonTemplateRenderError + tcResult.Error = err r.Value = tcResult r.Err = err return &r @@ -117,12 +150,12 @@ func (m *GrpcTestCallable) Call(ctx context.Context) *executor.GPResult { goto ERROR } - cc, dialErr = dial(reqInfo.Address) - if dialErr != nil { + cc, err = dial(reqInfo.Address) + if err != nil { zaplog.Error("GrpcTestCallable-dial", zap.Uint64("testCaseId", m.testcase.ID), zap.String("address", reqInfo.Address), - zap.Error(dialErr), + zap.Error(err), ) goto ERROR } @@ -187,6 +220,7 @@ func (m *GrpcTestCallable) Call(ctx context.Context) *executor.GPResult { ERROR: tcResult.State = model.StateFailed tcResult.Reason = model.ReasonRequestFailed + tcResult.Error = err r.Value = tcResult r.Err = err return &r diff --git a/internal/command/http_automate.go b/internal/command/http_automate.go index 52a3d18..60af6bd 100644 --- a/internal/command/http_automate.go +++ b/internal/command/http_automate.go @@ -22,23 +22,6 @@ import ( "time" ) -//go:embed template/*.tpl -var mytpl embed.FS - -type ResultInfo struct { - Total int - SuccessCount int - FailedCount int -} - -type CaseShow struct { - ID uint64 - Description string - State string - Reason string - Link string -} - func HttpAutomateTest(httpTestCases map[string][]*config.TestCaseHttp) { total := 0 for _, testcases := range httpTestCases { @@ -117,6 +100,7 @@ func GenReportFileHttp(testCasefilePath string, tcResultList []HttpTestCaseResul return } + // case file for _, item := range tcResultList { data := map[string]any{ "Error": item.Error, From 3b6eaa05dbaf1602304d7f89f79786329a21931c Mon Sep 17 00:00:00 2001 From: vearne Date: Thu, 24 Oct 2024 11:58:08 +0800 Subject: [PATCH 2/2] support grpc html report --- config_files/autotest.yml | 2 +- internal/command/grpc_call.go | 3 +++ main.go | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config_files/autotest.yml b/config_files/autotest.yml index c1793a0..d24e0b8 100644 --- a/config_files/autotest.yml +++ b/config_files/autotest.yml @@ -20,7 +20,7 @@ global: http_rule_files: - "./config_files/my_http_api.yml" -#grpc_rule_files: +grpc_rule_files: # - "./config_files/my_grpc_api.yml" diff --git a/internal/command/grpc_call.go b/internal/command/grpc_call.go index c5d9ff7..18a1cf9 100644 --- a/internal/command/grpc_call.go +++ b/internal/command/grpc_call.go @@ -187,6 +187,8 @@ func (m *GrpcTestCallable) Call(ctx context.Context) *executor.GPResult { goto ERROR } + tcResult.Response = &handler.resp + if resource.GlobalConfig.Global.Debug { debugPrint(reqInfo, handler.resp) } @@ -271,6 +273,7 @@ func getDescSourceWitchCache(ctx context.Context, address string) (grpcurl.Descr }) if err != nil { zaplog.Error("getDescSourceWitchCache", zap.Error(err)) + return nil, err } s = v.(grpcurl.DescriptorSource) diff --git a/main.go b/main.go index 2f3fc19..3fe18d2 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( ) const ( - version = "v0.1.5" + version = "v0.1.6" ) func main() {