Skip to content

Commit

Permalink
Merge pull request #21 from vearne/feat/html
Browse files Browse the repository at this point in the history
support html report
  • Loading branch information
vearne authored Oct 22, 2024
2 parents 5e67df6 + 75ae40f commit c5a1dba
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ autotest extract -x "//title" -j '[
}
]'
```
## Test Report
![report](https://github.com/vearne/autotest/raw/main/img/result_html.jpg)

## TODO
* [x] 1) support utilizing the script language Lua to ascertain the conformity of HTTP responses with expectations.
Expand Down
2 changes: 2 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ autotest extract -x "//title" -j '[
}
]'
```
## 测试报告
![report](https://github.com/vearne/autotest/raw/main/img/result_html.jpg)

## TODO
* [x] 1) 支持使用脚本语言Lua判断HTTP response是否符合预期
Expand Down
6 changes: 3 additions & 3 deletions config_files/autotest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ global:
worker_num: 5
# default: true
ignore_testcase_fail: true
debug: true
debug: false
# Timeout setting for each request
request_timeout: 5s

Expand All @@ -20,8 +20,8 @@ global:
http_rule_files:
- "./config_files/my_http_api.yml"

grpc_rule_files:
- "./config_files/my_grpc_api.yml"
#grpc_rule_files:
# - "./config_files/my_grpc_api.yml"



2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/golang/protobuf v1.5.4
github.com/jhump/protoreflect v1.16.0
github.com/lianggaoqiang/progress v0.0.1
github.com/spf13/cast v1.6.0
github.com/spf13/cast v1.7.0
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v3 v3.0.0-alpha9
github.com/vearne/executor v0.0.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand Down
Binary file added img/result_html.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 87 additions & 3 deletions internal/command/http_automate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package command

import (
"context"
"embed"
"fmt"
"github.com/lianggaoqiang/progress"
"github.com/vearne/autotest/internal/config"
"github.com/vearne/autotest/internal/model"
Expand All @@ -11,19 +13,32 @@ import (
slog "github.com/vearne/simplelog"
"github.com/vearne/zaplog"
"go.uber.org/zap"
"html/template"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"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 {
Expand Down Expand Up @@ -54,12 +69,12 @@ func HttpAutomateTest(httpTestCases map[string][]*config.TestCaseHttp) {
slog.Info("HttpTestCases, total:%v, finishCount:%v, successCount:%v, failedCount:%v",
total, finishCount, successCount, failedCount)
// generate report file
GenReportFileHttp(filePath, tcResultList)
GenReportFileHttp(filePath, tcResultList, info)
}
slog.Info("[end]HttpTestCases, total:%v, cost:%v", total, time.Since(begin))
}

func GenReportFileHttp(testCasefilePath string, tcResultList []HttpTestCaseResult) {
func GenReportFileHttp(testCasefilePath string, tcResultList []HttpTestCaseResult, info *ResultInfo) {
filename := filepath.Base(testCasefilePath)
name := strings.TrimSuffix(filename, filepath.Ext(filename))
filename = name + ".csv"
Expand All @@ -69,8 +84,9 @@ func GenReportFileHttp(testCasefilePath string, tcResultList []HttpTestCaseResul
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"})
records = append(records, []string{"id", "description", "state", "reason"})
for _, item := range tcResultList {
reasonStr := item.Reason.String()
if item.Reason == model.ReasonSuccess {
Expand All @@ -80,6 +96,74 @@ func GenReportFileHttp(testCasefilePath string, tcResultList []HttpTestCaseResul
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
}

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
}
}
}

func RenderTpl(fs embed.FS, key string, obj map[string]any, targetPath string) error {
data, err := fs.ReadFile(key)
if err != nil {
slog.Error("mytpl.ReadFile, %v", err)
return err
}
t, err := template.New("index").Parse(string(data))
if err != nil {
slog.Error("template Parse, %v", err)
return err
}
dirPath := filepath.Dir(targetPath)
if !pathExists(dirPath) {
err = os.Mkdir(dirPath, 0755)
if err != nil {
return err
}
}

file, err := os.Create(targetPath)
if err != nil {
slog.Error("Create file, %v", err)
return err
}
defer file.Close()
return t.Execute(file, obj)
}

func pathExists(path string) bool {
_, err := os.Stat(path)
// os.IsNotExist 判断错误是否为文件或目录不存在
return !os.IsNotExist(err)
}

func HandleSingleFileHttp(workerNum int, filePath string) (*ResultInfo, []HttpTestCaseResult) {
Expand Down
68 changes: 68 additions & 0 deletions internal/command/http_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package command

import (
"context"
"fmt"
"github.com/go-resty/resty/v2"
"github.com/vearne/autotest/internal/config"
"github.com/vearne/autotest/internal/model"
"github.com/vearne/autotest/internal/resource"
"github.com/vearne/executor"
"github.com/vearne/zaplog"
"go.uber.org/zap"
"net/url"
"strings"
"time"
)
Expand All @@ -22,6 +24,66 @@ type HttpTestCaseResult struct {
Request config.RequestHttp
TestCase *config.TestCaseHttp
KeyValues map[string]any
Error error
Response *resty.Response
}

/*
POST /api/order/subscribe HTTP/1.1
HOST: localhost:8080
HEADERS:
Content-Type: application/json
User-Agent: go-resty/2.12.0 (https://github.com/go-resty/resty)
BODY:
{
"title": "book3_title",
"author": "book3_author"
}
*/

func (t *HttpTestCaseResult) ReqDetail() string {
var builder strings.Builder
builder.WriteString(fmt.Sprintf("%v %v\n", strings.ToUpper(t.Request.Method), t.Request.URL))
u, _ := url.Parse(t.Request.URL)
builder.WriteString(fmt.Sprintf("HOST: %v\n", u.Host))
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()
}

/*
STATUS : 200 OK
PROTO : HTTP/1.1
RECEIVED AT : 2024-10-17T17:05:05.156315+08:00
TIME DURATION: 38.354958ms
HEADERS :
Content-Length: 17
Content-Type: application/json; charset=utf-8
Date: Thu, 17 Oct 2024 09:05:05 GMT
BODY :
{
"code": "E000"
}
*/

func (t *HttpTestCaseResult) RespDetail() string {
if t.Response == nil {
return ""
}

var builder strings.Builder
builder.WriteString(fmt.Sprintf("STATUS: %v\n", t.Response.Status()))
builder.WriteString("HEADERS:\n")
for key, values := range t.Response.Header() {
builder.WriteString(fmt.Sprintf("%v: %v\n", key, strings.Join(values, ",")))
}
builder.WriteString("BODY:\n")
builder.WriteString(fmt.Sprintf("%v\n", t.Response.String()))
return builder.String()
}

type HttpTestCallable struct {
Expand All @@ -40,6 +102,8 @@ func (m *HttpTestCallable) Call(ctx context.Context) *executor.GPResult {
Reason: model.ReasonSuccess,
TestCase: m.testcase,
KeyValues: map[string]any{},
Error: nil,
Response: nil,
}

// 1. Check other test cases of dependencies
Expand Down Expand Up @@ -75,6 +139,7 @@ func (m *HttpTestCallable) 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
Expand Down Expand Up @@ -119,11 +184,14 @@ func (m *HttpTestCallable) Call(ctx context.Context) *executor.GPResult {
)
tcResult.State = model.StateFailed
tcResult.Reason = model.ReasonRequestFailed
tcResult.Error = err
r.Value = tcResult
r.Err = err
return &r
}

tcResult.Response = out

// 6. export
if m.testcase.Export != nil {
exportConfig := m.testcase.Export
Expand Down
32 changes: 32 additions & 0 deletions internal/command/template/case.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTTP Request and Response Display</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h2 { color: #333; }
.container { margin-bottom: 20px; }
.section-title { font-weight: bold; margin-top: 20px; }
pre { background-color: #f4f4f4; padding: 10px; border: 1px solid #ddd; overflow: auto; white-space: pre-wrap; }
</style>
</head>
<body>
<h2>HTTP Request and Response Display</h2>

<div class="container">
<div class="section-title">~~~ REQUEST ~~~</div>
<pre>{{ .reqDetail }}</pre>
</div>

<div class="container">
<div class="section-title">~~~ RESPONSE ~~~</div>
{{ if .Error }}
{{ .Error }}
{{else}}
<pre>{{ .respDetail }}</pre>
{{end}}
</div>
</body>
</html>
Loading

0 comments on commit c5a1dba

Please sign in to comment.