From 8cce0181017bd4c6462851c9f8818640edb5fed7 Mon Sep 17 00:00:00 2001 From: vearne Date: Tue, 7 May 2024 11:05:20 +0800 Subject: [PATCH] add subcommand extract --- Makefile | 2 +- README.md | 26 ++++++++++++++++++-- README_zh.md | 26 ++++++++++++++++++-- internal/command/command.go | 48 ++++++++++++++++++++++++++++++++++++- internal/rule/http_rule.go | 2 -- main.go | 11 ++++++++- 6 files changed, 106 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 2c58dc8..089e800 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,6 @@ LDFLAGS = -ldflags "-s -w" .PHONY: build build: - env go build ${LDFLAGS} -o autotest ./ + env CGO_ENABLED=0 go build ${LDFLAGS} -o autotest ./ xgo: xgo -out=./autotest . diff --git a/README.md b/README.md index f3685cf..6f0533e 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,18 @@ Automated testing framework for api services, http, gRPC (may support in the fut ## Usage ### 1) check configuration file ``` -autotest --config-file=${CONFIG_FILE} +autotest test --config-file=${CONFIG_FILE} ``` ### 2) execute automated tests ``` -autotest --config-file=${CONFIG_FILE} --env-file=${ENV_FILE} +autotest run --config-file=${CONFIG_FILE} --env-file=${ENV_FILE} ``` +### 3) extract the value corresponding to xpath +``` +autotest extract --xpath=${XPATH} --json=${JSON} +``` + ## Example ### 1) start a fake http api service ``` @@ -56,3 +61,20 @@ curl 'http://localhost:8080/api/books' make build ./autotest run -c=./config_files/autotest.yml -e=./config_files/.env.dev ``` + +### 3) extract the value corresponding to xpath +get the title of each book in the book list +``` +./autotest extract -x "//title" -j '[ + { + "id": 2, + "title": "Effective Go", + "author": "The Go Authors" + }, + { + "id": 3, + "title": "book3_title", + "author": "book3_author-2" + } +]' +``` diff --git a/README_zh.md b/README_zh.md index 1a88b51..57f49f4 100644 --- a/README_zh.md +++ b/README_zh.md @@ -12,12 +12,17 @@ ## 用法 ### 1) 检查配置文件 ``` -autotest --config-file=${CONFIG_FILE} +autotest test --config-file=${CONFIG_FILE} ``` ### 2) 执行自动化测试 ``` -autotest --config-file=${CONFIG_FILE} --env-file=${ENV_FILE} +autotest run --config-file=${CONFIG_FILE} --env-file=${ENV_FILE} +``` + +### 3) 提取xpath对应的值 +``` +autotest extract --xpath=${XPATH} --json=${JSON} ``` ## 示例 @@ -55,3 +60,20 @@ make build ./autotest run -c=./config_files/autotest.yml -e=./config_files/.env.dev ``` +### 3) 提取xpath对应的值 +获取书本列表中,书的title +``` +./autotest extract -x "//title" -j '[ + { + "id": 2, + "title": "Effective Go", + "author": "The Go Authors" + }, + { + "id": 3, + "title": "book3_title", + "author": "book3_author-2" + } +]' +``` + diff --git a/internal/command/command.go b/internal/command/command.go index 1212941..1729508 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -2,12 +2,14 @@ package command import ( "context" + "github.com/antchfx/jsonquery" "github.com/antchfx/xpath" "github.com/urfave/cli/v3" "github.com/vearne/autotest/internal/resource" "github.com/vearne/autotest/internal/rule" slog "github.com/vearne/simplelog" "github.com/vearne/zaplog" + "strings" ) func RunTestCases(ctx context.Context, cmd *cli.Command) error { @@ -57,6 +59,7 @@ func ValidateConfig(ctx context.Context, cmd *cli.Command) error { } slog.Info("=== validate config file ===") + slog.Info("1. check xpath") for filePath, testcases := range resource.HttpTestCases { slog.Info("filePath:%v, len(testcases):%v", filePath, len(testcases)) for _, tc := range testcases { @@ -70,7 +73,7 @@ func ValidateConfig(ctx context.Context, cmd *cli.Command) error { return err } case "HttpBodyAtLeastOneRule": - rule := r.(*rule.HttpBodyEqualRule) + rule := r.(*rule.HttpBodyAtLeastOneRule) _, err := xpath.Compile(rule.Xpath) if err != nil { slog.Error("rule error, testCaseId:%v, xpath:%v", tc.ID, rule.Xpath) @@ -82,5 +85,48 @@ func ValidateConfig(ctx context.Context, cmd *cli.Command) error { } } } + + slog.Info("2. check if ID is duplicate") + for filePath, testcases := range resource.HttpTestCases { + slog.Info("filePath:%v, len(testcases):%v", filePath, len(testcases)) + exist := make(map[uint64]struct{}) + for _, tc := range testcases { + _, ok := exist[tc.ID] + if ok { + slog.Error("filePath:%v, ID [%v] is duplicate", filePath, tc.ID) + break + } + exist[tc.ID] = struct{}{} + } + } + return nil +} + +func ExtractXpath(ctx context.Context, cmd *cli.Command) error { + // 检查testcase的xpath语法是否正确 + + xpathStr := cmd.String("xpath") + slog.Info("xpathStr:%v", xpathStr) + + jsonStr := cmd.String("json") + slog.Info("jsonStr:%v", jsonStr) + + _, err := xpath.Compile(xpathStr) + if err != nil { + slog.Error("xpath syntax error") + return nil + } + + doc, err := jsonquery.Parse(strings.NewReader(jsonStr)) + if err != nil { + slog.Error("jsonStr format error") + return nil + } + nodes := jsonquery.Find(doc, xpathStr) + for idx, node := range nodes { + if node != nil { + slog.Info("[%v] = %v", idx, node.Value()) + } + } return nil } diff --git a/internal/rule/http_rule.go b/internal/rule/http_rule.go index 8a1e7e1..b8a6594 100644 --- a/internal/rule/http_rule.go +++ b/internal/rule/http_rule.go @@ -1,7 +1,6 @@ package rule import ( - "fmt" "github.com/antchfx/jsonquery" "github.com/go-resty/resty/v2" "strings" @@ -58,7 +57,6 @@ func (r *HttpBodyAtLeastOneRule) Verify(resp *resty.Response) bool { nodes := jsonquery.Find(doc, r.Xpath) for _, node := range nodes { if node != nil && convStr(r.Expected) == convStr(node.Value()) { - fmt.Printf("xpath:%v, value:%v\n", r.Xpath, node.Value()) return true } } diff --git a/main.go b/main.go index 48ee072..9b0cc00 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( ) const ( - version = "v0.0.1" + version = "v0.0.2" ) func main() { @@ -45,6 +45,15 @@ func main() { Usage: "run all test cases", Action: command.RunTestCases, }, + { + Name: "extract", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "xpath", Aliases: []string{"x"}}, + &cli.StringFlag{Name: "json", Aliases: []string{"j"}}, + }, + Usage: "try to extract data corresponding to xpath from json string", + Action: command.ExtractXpath, + }, }, }