refactor: run step with runner

This commit is contained in:
debugtalk
2021-09-22 18:23:18 +08:00
parent e0d1c5d959
commit aee9b0c0b5
8 changed files with 266 additions and 228 deletions
+13 -12
View File
@@ -1,25 +1,26 @@
package httpboomer package httpboomer
// implements IStep interface // implements IStep interface
type StepRequestExtraction struct { type stepRequestExtraction struct {
*TStep runner *Runner
step *TStep
} }
func (step *StepRequestExtraction) WithJmesPath(jmesPath string, varName string) *StepRequestExtraction { func (s *stepRequestExtraction) WithJmesPath(jmesPath string, varName string) *stepRequestExtraction {
step.TStep.Extract[varName] = jmesPath s.step.Extract[varName] = jmesPath
return step return s
} }
func (step *StepRequestExtraction) Validate() *StepRequestValidation { func (s *stepRequestExtraction) Validate() *stepRequestValidation {
return &StepRequestValidation{ return &stepRequestValidation{
TStep: step.TStep, TStep: s.step,
} }
} }
func (step *StepRequestExtraction) ToStruct() *TStep { func (s *stepRequestExtraction) ToStruct() *TStep {
return step.TStep return s.step
} }
func (step *StepRequestExtraction) Run() error { func (s *stepRequestExtraction) Run() error {
return step.TStep.Run() return s.runner.runStep(s.step)
} }
-145
View File
@@ -1,145 +0,0 @@
package httpboomer
func RunRequest(name string) *Request {
return &Request{
TStep: &TStep{
Name: name,
Request: &TRequest{},
Variables: make(Variables),
},
}
}
type Request struct {
*TStep
}
func (r *Request) WithVariables(variables Variables) *Request {
r.TStep.Variables = variables
return r
}
func (r *Request) GET(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = GET
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
func (r *Request) HEAD(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = HEAD
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
func (r *Request) POST(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = POST
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
func (r *Request) PUT(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = PUT
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
func (r *Request) DELETE(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = DELETE
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
func (r *Request) OPTIONS(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = OPTIONS
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
func (r *Request) PATCH(url string) *RequestWithOptionalArgs {
r.TStep.Request.Method = PATCH
r.TStep.Request.URL = url
return &RequestWithOptionalArgs{
TStep: r.TStep,
}
}
// implements IStep interface
type RequestWithOptionalArgs struct {
*TStep
}
func (r *RequestWithOptionalArgs) SetVerify(verify bool) *RequestWithOptionalArgs {
r.TStep.Request.Verify = verify
return r
}
func (r *RequestWithOptionalArgs) SetTimeout(timeout float32) *RequestWithOptionalArgs {
r.TStep.Request.Timeout = timeout
return r
}
func (r *RequestWithOptionalArgs) SetProxies(proxies map[string]string) *RequestWithOptionalArgs {
// TODO
return r
}
func (r *RequestWithOptionalArgs) SetAllowRedirects(allowRedirects bool) *RequestWithOptionalArgs {
r.TStep.Request.AllowRedirects = allowRedirects
return r
}
func (r *RequestWithOptionalArgs) SetAuth(auth map[string]string) *RequestWithOptionalArgs {
// TODO
return r
}
func (r *RequestWithOptionalArgs) WithParams(params Params) *RequestWithOptionalArgs {
r.TStep.Request.Params = params
return r
}
func (r *RequestWithOptionalArgs) WithHeaders(headers Headers) *RequestWithOptionalArgs {
r.TStep.Request.Headers = headers
return r
}
func (r *RequestWithOptionalArgs) WithCookies(cookies Cookies) *RequestWithOptionalArgs {
r.TStep.Request.Cookies = cookies
return r
}
func (r *RequestWithOptionalArgs) WithData(data interface{}) *RequestWithOptionalArgs {
r.TStep.Request.Data = data
return r
}
func (r *RequestWithOptionalArgs) WithJSON(json interface{}) *RequestWithOptionalArgs {
r.TStep.Request.JSON = json
return r
}
func (r *RequestWithOptionalArgs) Validate() *StepRequestValidation {
return &StepRequestValidation{
TStep: r.TStep,
}
}
func (r *RequestWithOptionalArgs) ToStruct() *TStep {
return r.TStep
}
func (r *RequestWithOptionalArgs) Run() error {
return r.TStep.Run()
}
+13 -14
View File
@@ -6,11 +6,16 @@ import (
"github.com/imroc/req" "github.com/imroc/req"
) )
var defaultRunner = HttpRunner()
func HttpRunner() *Runner { func HttpRunner() *Runner {
return &Runner{} return &Runner{
Client: req.New(),
}
} }
type Runner struct { type Runner struct {
Client *req.Req
} }
func (r *Runner) Run(testcases ...*TestCase) error { func (r *Runner) Run(testcases ...*TestCase) error {
@@ -25,23 +30,14 @@ func (r *Runner) Run(testcases ...*TestCase) error {
func (r *Runner) runCase(testcase *TestCase) error { func (r *Runner) runCase(testcase *TestCase) error {
// config := testcase.Config // config := testcase.Config
for _, step := range testcase.TestSteps { for _, step := range testcase.TestSteps {
if err := r.runStep(step); err != nil { if err := step.Run(); err != nil {
return err return err
} }
} }
return nil return nil
} }
func (r *Runner) runStep(req IStep) error { func (r *Runner) runStep(step *TStep) error {
return req.Run()
}
func (r *Runner) GetSummary() *TestCaseSummary {
return &TestCaseSummary{}
}
func (step *TStep) Run() error {
var v []interface{} var v []interface{}
v = append(v, req.Header(step.Request.Headers)) v = append(v, req.Header(step.Request.Headers))
v = append(v, req.Param(step.Request.Params)) v = append(v, req.Param(step.Request.Params))
@@ -53,11 +49,14 @@ func (step *TStep) Run() error {
}) })
} }
req.Debug = true resp, err := r.Client.Do(string(step.Request.Method), step.Request.URL, v...)
resp, err := req.Do(string(step.Request.Method), step.Request.URL, v...)
if err != nil { if err != nil {
return err return err
} }
resp.Response().Body.Close() resp.Response().Body.Close()
return nil return nil
} }
func (r *Runner) GetSummary() *TestCaseSummary {
return &TestCaseSummary{}
}
+3 -3
View File
@@ -11,17 +11,17 @@ func TestHttpRunner(t *testing.T) {
BaseURL: "http://httpbin.org", BaseURL: "http://httpbin.org",
}, },
TestSteps: []IStep{ TestSteps: []IStep{
RunRequest("headers"). Step("headers").
GET("/headers"). GET("/headers").
Validate(). Validate().
AssertEqual("status_code", 200, "check status code"). AssertEqual("status_code", 200, "check status code").
AssertEqual("headers.Host", "httpbin.org", "check http response host"), AssertEqual("headers.Host", "httpbin.org", "check http response host"),
RunRequest("user-agent"). Step("user-agent").
GET("/user-agent"). GET("/user-agent").
Validate(). Validate().
AssertEqual("status_code", 200, "check status code"). AssertEqual("status_code", 200, "check status code").
AssertEqual("body.\"user-agent\"", "python-requests", "check User-Agent"), AssertEqual("body.\"user-agent\"", "python-requests", "check User-Agent"),
RunTestCase("TestCase3").WithVariables(Variables{"var1": "value1"}), Step("TestCase3").CallRefCase(&TestCase{}),
}, },
} }
testcase2 := &TestCase{ testcase2 := &TestCase{
+211
View File
@@ -0,0 +1,211 @@
package httpboomer
func Step(name string) *step {
return &step{
runner: defaultRunner,
TStep: &TStep{
Name: name,
Request: &TRequest{},
Variables: make(Variables),
},
}
}
type step struct {
runner *Runner
*TStep
}
func (s *step) WithRunner(runner *Runner) *step {
s.runner = runner
return s
}
func (s *step) WithVariables(variables Variables) *step {
s.TStep.Variables = variables
return s
}
func (s *step) SetupHook(hook string) *step {
s.TStep.SetupHooks = append(s.TStep.SetupHooks, hook)
return s
}
func (s *step) GET(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = GET
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
func (s *step) HEAD(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = HEAD
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
func (s *step) POST(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = POST
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
func (s *step) PUT(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = PUT
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
func (s *step) DELETE(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = DELETE
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
func (s *step) OPTIONS(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = OPTIONS
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
func (s *step) PATCH(url string) *requestWithOptionalArgs {
s.TStep.Request.Method = PATCH
s.TStep.Request.URL = url
return &requestWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
// call referenced testcase
func (s *step) CallRefCase(tc *TestCase) *testcaseWithOptionalArgs {
s.TStep.TestCase = tc
return &testcaseWithOptionalArgs{
runner: s.runner,
step: s.TStep,
}
}
// implements IStep interface
type requestWithOptionalArgs struct {
runner *Runner
step *TStep
}
func (s *requestWithOptionalArgs) SetVerify(verify bool) *requestWithOptionalArgs {
s.step.Request.Verify = verify
return s
}
func (s *requestWithOptionalArgs) SetTimeout(timeout float32) *requestWithOptionalArgs {
s.step.Request.Timeout = timeout
return s
}
func (s *requestWithOptionalArgs) SetProxies(proxies map[string]string) *requestWithOptionalArgs {
// TODO
return s
}
func (s *requestWithOptionalArgs) SetAllowRedirects(allowRedirects bool) *requestWithOptionalArgs {
s.step.Request.AllowRedirects = allowRedirects
return s
}
func (s *requestWithOptionalArgs) SetAuth(auth map[string]string) *requestWithOptionalArgs {
// TODO
return s
}
func (s *requestWithOptionalArgs) WithParams(params Params) *requestWithOptionalArgs {
s.step.Request.Params = params
return s
}
func (s *requestWithOptionalArgs) WithHeaders(headers Headers) *requestWithOptionalArgs {
s.step.Request.Headers = headers
return s
}
func (s *requestWithOptionalArgs) WithCookies(cookies Cookies) *requestWithOptionalArgs {
s.step.Request.Cookies = cookies
return s
}
func (s *requestWithOptionalArgs) WithData(data interface{}) *requestWithOptionalArgs {
s.step.Request.Data = data
return s
}
func (s *requestWithOptionalArgs) WithJSON(json interface{}) *requestWithOptionalArgs {
s.step.Request.JSON = json
return s
}
func (s *requestWithOptionalArgs) TeardownHook(hook string) *requestWithOptionalArgs {
s.step.TeardownHooks = append(s.step.TeardownHooks, hook)
return s
}
func (s *requestWithOptionalArgs) Validate() *stepRequestValidation {
return &stepRequestValidation{
runner: s.runner,
TStep: s.step,
}
}
func (s *requestWithOptionalArgs) Extract() *stepRequestExtraction {
return &stepRequestExtraction{
runner: s.runner,
step: s.step,
}
}
func (s *requestWithOptionalArgs) ToStruct() *TStep {
return s.step
}
func (s *requestWithOptionalArgs) Run() error {
return s.runner.runStep(s.step)
}
// implements IStep interface
type testcaseWithOptionalArgs struct {
runner *Runner
step *TStep
}
func (s *testcaseWithOptionalArgs) TeardownHook(hook string) *testcaseWithOptionalArgs {
s.step.TeardownHooks = append(s.step.TeardownHooks, hook)
return s
}
func (s *testcaseWithOptionalArgs) Export(names ...string) *testcaseWithOptionalArgs {
s.step.Export = append(s.step.Export, names...)
return s
}
func (s *testcaseWithOptionalArgs) ToStruct() *TStep {
return s.step
}
func (s *testcaseWithOptionalArgs) Run() error {
return s.runner.runCase(s.step.TestCase)
}
+10 -10
View File
@@ -5,14 +5,14 @@ import (
) )
var ( var (
tStepGET = RunRequest("get with params"). stepGET = Step("get with params").
GET("https://postman-echo.com/get"). GET("https://postman-echo.com/get").
WithParams(Params{"foo1": "bar1", "foo2": "bar2"}). WithParams(Params{"foo1": "bar1", "foo2": "bar2"}).
WithHeaders(Headers{"User-Agent": "HttpBoomer"}). WithHeaders(Headers{"User-Agent": "HttpBoomer"}).
WithCookies(Cookies{"user": "debugtalk"}). WithCookies(Cookies{"user": "debugtalk"}).
Validate(). Validate().
AssertEqual("status_code", 200, "check status code") AssertEqual("status_code", 200, "check status code")
tStepPOSTData = RunRequest("post form data"). stepPOSTData = Step("post form data").
POST("https://postman-echo.com/post"). POST("https://postman-echo.com/post").
WithParams(Params{"foo1": "bar1", "foo2": "bar2"}). WithParams(Params{"foo1": "bar1", "foo2": "bar2"}).
WithHeaders(Headers{"User-Agent": "HttpBoomer", "Content-Type": "application/x-www-form-urlencoded"}). WithHeaders(Headers{"User-Agent": "HttpBoomer", "Content-Type": "application/x-www-form-urlencoded"}).
@@ -23,12 +23,12 @@ var (
) )
func TestRunRequestGetToStruct(t *testing.T) { func TestRunRequestGetToStruct(t *testing.T) {
tStep := tStepGET.ToStruct() tStep := stepGET.ToStruct()
if tStep.Request.Method != GET { if tStep.Request.Method != GET {
t.Fatalf("tStep.Request.Method != GET") t.Fatalf("tStep.Request.Method != GET")
} }
if tStep.Request.URL != "/get" { if tStep.Request.URL != "https://postman-echo.com/get" {
t.Fatalf("tStep.Request.URL != '/get'") t.Fatalf("tStep.Request.URL != 'https://postman-echo.com/get'")
} }
if tStep.Request.Params["foo1"] != "bar1" || tStep.Request.Params["foo2"] != "bar2" { if tStep.Request.Params["foo1"] != "bar1" || tStep.Request.Params["foo2"] != "bar2" {
t.Fatalf("tStep.Request.Params mismatch") t.Fatalf("tStep.Request.Params mismatch")
@@ -45,12 +45,12 @@ func TestRunRequestGetToStruct(t *testing.T) {
} }
func TestRunRequestPostDataToStruct(t *testing.T) { func TestRunRequestPostDataToStruct(t *testing.T) {
tStep := tStepPOSTData.ToStruct() tStep := stepPOSTData.ToStruct()
if tStep.Request.Method != POST { if tStep.Request.Method != POST {
t.Fatalf("tStep.Request.Method != POST") t.Fatalf("tStep.Request.Method != POST")
} }
if tStep.Request.URL != "/post" { if tStep.Request.URL != "https://postman-echo.com/post" {
t.Fatalf("tStep.Request.URL != '/post'") t.Fatalf("tStep.Request.URL != 'https://postman-echo.com/post'")
} }
if tStep.Request.Params["foo1"] != "bar1" || tStep.Request.Params["foo2"] != "bar2" { if tStep.Request.Params["foo1"] != "bar1" || tStep.Request.Params["foo2"] != "bar2" {
t.Fatalf("tStep.Request.Params mismatch") t.Fatalf("tStep.Request.Params mismatch")
@@ -70,10 +70,10 @@ func TestRunRequestPostDataToStruct(t *testing.T) {
} }
func TestRunRequestRun(t *testing.T) { func TestRunRequestRun(t *testing.T) {
if err := tStepGET.Run(); err != nil { if err := stepGET.Run(); err != nil {
t.Fatalf("tStep.Run() error: %s", err) t.Fatalf("tStep.Run() error: %s", err)
} }
if err := tStepPOSTData.Run(); err != nil { if err := stepPOSTData.Run(); err != nil {
t.Fatalf("tStepPOSTData.Run() error: %s", err) t.Fatalf("tStepPOSTData.Run() error: %s", err)
} }
} }
-29
View File
@@ -1,29 +0,0 @@
package httpboomer
func RunTestCase(name string) *TestCase {
return &TestCase{
Config: TConfig{
Name: name,
},
}
}
func (tc *TestCase) WithVariables(variables Variables) *TestCase {
tc.Config.Variables = variables
return tc
}
func (tc *TestCase) ToStruct() *TStep {
return &TStep{
TestCase: tc,
}
}
func (tc *TestCase) Run() error {
for _, step := range tc.TestSteps {
if err := step.Run(); err != nil {
return err
}
}
return nil
}
+10 -9
View File
@@ -1,25 +1,26 @@
package httpboomer package httpboomer
// implements IStep interface // implements IStep interface
type StepRequestValidation struct { type stepRequestValidation struct {
*TStep runner *Runner
TStep *TStep
} }
func (step *StepRequestValidation) AssertEqual(jmesPath string, expected interface{}, msg string) *StepRequestValidation { func (s *stepRequestValidation) AssertEqual(jmesPath string, expected interface{}, msg string) *stepRequestValidation {
validator := TValidator{ validator := TValidator{
Check: jmesPath, Check: jmesPath,
Comparator: "equals", Comparator: "equals",
Expect: expected, Expect: expected,
Message: msg, Message: msg,
} }
step.TStep.Validators = append(step.TStep.Validators, validator) s.TStep.Validators = append(s.TStep.Validators, validator)
return step return s
} }
func (step *StepRequestValidation) ToStruct() *TStep { func (s *stepRequestValidation) ToStruct() *TStep {
return step.TStep return s.TStep
} }
func (step *StepRequestValidation) Run() error { func (s *stepRequestValidation) Run() error {
return step.TStep.Run() return s.runner.runStep(s.TStep)
} }