feat: dump2YAML

This commit is contained in:
debugtalk
2021-10-09 16:39:25 +08:00
parent d8a1a6ef24
commit bbe33e0dd0
4 changed files with 115 additions and 75 deletions

View File

@@ -1,10 +1,13 @@
package httpboomer
import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"path/filepath"
"gopkg.in/yaml.v3"
)
func (tc *TestCase) toStruct() *TCase {
@@ -33,3 +36,31 @@ func (tc *TestCase) dump2JSON(path string) error {
}
return nil
}
func (tc *TestCase) dump2YAML(path string) error {
path, err := filepath.Abs(path)
if err != nil {
log.Printf("convert absolute path error: %v, path: %v", err, path)
return err
}
log.Printf("dump testcase to yaml path: %s", path)
// init yaml encoder
buffer := new(bytes.Buffer)
encoder := yaml.NewEncoder(buffer)
encoder.SetIndent(4)
// encode
tcStruct := tc.toStruct()
err = encoder.Encode(tcStruct)
if err != nil {
return err
}
err = ioutil.WriteFile(path, buffer.Bytes(), 0644)
if err != nil {
log.Printf("dump yaml path error: %v", err)
return err
}
return nil
}

View File

@@ -6,50 +6,58 @@ import (
"github.com/stretchr/testify/assert"
)
var demoTestCase = &TestCase{
Config: TConfig{
Name: "demo with complex mechanisms",
BaseURL: "https://postman-echo.com",
Variables: map[string]interface{}{ // global level variables
"n": 5,
"a": 12.3,
"b": 3.45,
"varFoo1": "${gen_random_string($n)}",
"varFoo2": "${max($a, $b)}", // 12.3; eval with built-in function
},
},
TestSteps: []IStep{
Step("get with params").
WithVariables(map[string]interface{}{ // step level variables
"n": 3, // inherit config level variables if not set in step level, a/varFoo1
"b": 34.5, // override config level variable if existed, n/b/varFoo2
"varFoo2": "${max($a, $b)}", // 34.5; override variable b and eval again
}).
GET("/get").
WithParams(map[string]interface{}{"foo1": "$varFoo1", "foo2": "$varFoo2"}). // request with params
WithHeaders(map[string]string{"User-Agent": "HttpBoomer"}). // request with headers
Extract().
WithJmesPath("body.args.foo1", "varFoo1"). // extract variable with jmespath
Validate().
AssertEqual("status_code", 200, "check response status code"). // validate response status code
AssertStartsWith("headers.\"Content-Type\"", "application/json", ""). // validate response header
AssertLengthEqual("body.args.foo1", 5, "check args foo1"). // validate response body with jmespath
AssertLengthEqual("$varFoo1", 5, "check args foo1"). // assert with extracted variable from current step
AssertEqual("body.args.foo2", "34.5", "check args foo2"), // notice: request params value will be converted to string
Step("post json data").
POST("/post").
WithJSON(map[string]interface{}{
"foo1": "$varFoo1", // reference former extracted variable
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
}).
Validate().
AssertEqual("status_code", 200, "check status code").
AssertLengthEqual("body.json.foo1", 5, "check args foo1").
AssertEqual("body.json.foo2", 12.3, "check args foo2"),
},
}
func TestDump2JSON(t *testing.T) {
testcase := &TestCase{
Config: TConfig{
Name: "demo with complex mechanisms",
BaseURL: "https://postman-echo.com",
Variables: map[string]interface{}{ // global level variables
"n": 5,
"a": 12.3,
"b": 3.45,
"varFoo1": "${gen_random_string($n)}",
"varFoo2": "${max($a, $b)}", // 12.3; eval with built-in function
},
},
TestSteps: []IStep{
Step("get with params").
WithVariables(map[string]interface{}{ // step level variables
"n": 3, // inherit config level variables if not set in step level, a/varFoo1
"b": 34.5, // override config level variable if existed, n/b/varFoo2
"varFoo2": "${max($a, $b)}", // 34.5; override variable b and eval again
}).
GET("/get").
WithParams(map[string]interface{}{"foo1": "$varFoo1", "foo2": "$varFoo2"}). // request with params
WithHeaders(map[string]string{"User-Agent": "HttpBoomer"}). // request with headers
Extract().
WithJmesPath("body.args.foo1", "varFoo1"). // extract variable with jmespath
Validate().
AssertEqual("status_code", 200, "check response status code"). // validate response status code
AssertStartsWith("headers.\"Content-Type\"", "application/json", ""). // validate response header
AssertLengthEqual("body.args.foo1", 5, "check args foo1"). // validate response body with jmespath
AssertLengthEqual("$varFoo1", 5, "check args foo1"). // assert with extracted variable from current step
AssertEqual("body.args.foo2", "34.5", "check args foo2"), // notice: request params value will be converted to string
Step("post json data").
POST("/post").
WithJSON(map[string]interface{}{
"foo1": "$varFoo1", // reference former extracted variable
"foo2": "${max($a, $b)}", // 12.3; step level variables are independent, variable b is 3.45 here
}).
Validate().
AssertEqual("status_code", 200, "check status code").
AssertLengthEqual("body.json.foo1", 5, "check args foo1").
AssertEqual("body.json.foo2", 12.3, "check args foo2"),
},
}
err := testcase.dump2JSON("test.json")
err := demoTestCase.dump2JSON("demo.json")
if !assert.NoError(t, err) {
t.Fail()
}
}
func TestDump2YAML(t *testing.T) {
err := demoTestCase.dump2YAML("demo.yml")
if !assert.NoError(t, err) {
t.Fail()
}

1
go.mod
View File

@@ -20,4 +20,5 @@ require (
github.com/zeromq/gomq v0.0.0-20201031135124-cef4e507bb8e // indirect
github.com/zeromq/gomq/zmtp v0.0.0-20201031135124-cef4e507bb8e // indirect
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)

View File

@@ -13,51 +13,51 @@ const (
)
type TConfig struct {
Name string `json:"name"`
Verify bool `json:"verify,omitempty"`
BaseURL string `json:"base_url,omitempty"`
Variables map[string]interface{} `json:"variables,omitempty"`
Parameters map[string]interface{} `json:"parameters,omitempty"`
Export []string `json:"export,omitempty"`
Weight int `json:"weight,omitempty"`
Name string `json:"name" yaml:"name"`
Verify bool `json:"verify,omitempty" yaml:"verify,omitempty"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
Weight int `json:"weight,omitempty" yaml:"weight,omitempty"`
}
type TRequest struct {
Method enumHTTPMethod `json:"method"`
URL string `json:"url"`
Params map[string]interface{} `json:"params,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Cookies map[string]string `json:"cookies,omitempty"`
Data interface{} `json:"data,omitempty"`
JSON interface{} `json:"json,omitempty"`
Timeout float32 `json:"timeout,omitempty"`
AllowRedirects bool `json:"allow_redirects,omitempty"`
Verify bool `json:"verify,omitempty"`
Method enumHTTPMethod `json:"method" yaml:"method"`
URL string `json:"url" yaml:"url"`
Params map[string]interface{} `json:"params,omitempty" yaml:"params,omitempty"`
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
Cookies map[string]string `json:"cookies,omitempty" yaml:"cookies,omitempty"`
Data interface{} `json:"data,omitempty" yaml:"data,omitempty"`
JSON interface{} `json:"json,omitempty" yaml:"json,omitempty"`
Timeout float32 `json:"timeout,omitempty" yaml:"timeout,omitempty"`
AllowRedirects bool `json:"allow_redirects,omitempty" yaml:"allow_redirects,omitempty"`
Verify bool `json:"verify,omitempty" yaml:"verify,omitempty"`
}
type TValidator struct {
Check string `json:"check,omitempty"` // get value with jmespath
Assert string `json:"assert,omitempty"`
Expect interface{} `json:"expect,omitempty"`
Message string `json:"msg,omitempty"`
Check string `json:"check,omitempty" yaml:"check,omitempty"` // get value with jmespath
Assert string `json:"assert,omitempty" yaml:"assert,omitempty"`
Expect interface{} `json:"expect,omitempty" yaml:"expect,omitempty"`
Message string `json:"msg,omitempty" yaml:"msg,omitempty"`
}
type TStep struct {
Name string `json:"name"`
Request *TRequest `json:"request,omitempty"`
TestCase *TestCase `json:"testcase,omitempty"`
Variables map[string]interface{} `json:"variables,omitempty"`
SetupHooks []string `json:"setup_hooks,omitempty"`
TeardownHooks []string `json:"teardown_hooks,omitempty"`
Extract map[string]string `json:"extract,omitempty"`
Validators []TValidator `json:"validate,omitempty"`
Export []string `json:"export,omitempty"`
Name string `json:"name" yaml:"name"`
Request *TRequest `json:"request,omitempty" yaml:"request,omitempty"`
TestCase *TestCase `json:"testcase,omitempty" yaml:"testcase,omitempty"`
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
SetupHooks []string `json:"setup_hooks,omitempty" yaml:"setup_hooks,omitempty"`
TeardownHooks []string `json:"teardown_hooks,omitempty" yaml:"teardown_hooks,omitempty"`
Extract map[string]string `json:"extract,omitempty" yaml:"extract,omitempty"`
Validators []TValidator `json:"validate,omitempty" yaml:"validate,omitempty"`
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
}
// used for testcase json loading and dumping
type TCase struct {
Config TConfig `json:"config"`
TestSteps []*TStep `json:"teststeps"`
Config TConfig `json:"config" yaml:"config"`
TestSteps []*TStep `json:"teststeps" yaml:"teststeps"`
}
// interface for all types of steps