From 2c49281a3487961b69ee787517cceaf32aa5a544 Mon Sep 17 00:00:00 2001 From: rick Date: Wed, 29 Mar 2023 03:16:34 +0800 Subject: [PATCH] feat: support to set the request timeout --- cmd/run.go | 35 ++++++++++++++++++++++------------- cmd/run_test.go | 6 +++++- pkg/runner/simple.go | 12 +++++------- pkg/runner/simple_test.go | 3 ++- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 8a93803e0..1aa821969 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -17,10 +17,12 @@ import ( ) type runOption struct { - pattern string - duration time.Duration - thread int64 - context context.Context + pattern string + duration time.Duration + requestTimeout time.Duration + requestIgnoreError bool + thread int64 + context context.Context } // CreateRunCommand returns the run command @@ -40,6 +42,8 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`, flags.StringVarP(&opt.pattern, "pattern", "p", "test-suite-*.yaml", "The file pattern which try to execute the test cases") flags.DurationVarP(&opt.duration, "duration", "", 0, "Running duration") + flags.DurationVarP(&opt.requestTimeout, "request-timeout", "", time.Minute, "Timeout for per request") + flags.BoolVarP(&opt.requestIgnoreError, "request-ignore-error", "", false, "Indicate if ignore the request error") flags.Int64VarP(&opt.thread, "thread", "", 1, "Threads of the execution") return } @@ -69,7 +73,7 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) { // make sure having a valid timer timeout = time.NewTicker(time.Second) } - errChannel := make(chan error, 10) + errChannel := make(chan error, 10*o.thread) var wait sync.WaitGroup for !stop { @@ -89,13 +93,17 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) { stop = true } - go func(ch chan error) { + go func(ch chan error, sem *semaphore.Weighted) { + now := time.Now() defer sem.Release(1) defer wait.Done() + defer func() { + fmt.Println("routing end with", time.Now().Sub(now)) + }() - ctx := getDefaultContext() - ch <- runSuite(suite, ctx) - }(errChannel) + dataContext := getDefaultContext() + ch <- o.runSuite(suite, dataContext, o.context) + }(errChannel, sem) } } err = <-errChannel @@ -103,14 +111,14 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) { return } -func runSuite(suite string, ctx map[string]interface{}) (err error) { +func (o *runOption) runSuite(suite string, dataContext map[string]interface{}, ctx context.Context) (err error) { var testSuite *testing.TestSuite if testSuite, err = testing.Parse(suite); err != nil { return } var result string - if result, err = render.Render("base api", testSuite.API, ctx); err == nil { + if result, err = render.Render("base api", testSuite.API, dataContext); err == nil { testSuite.API = result testSuite.API = strings.TrimSuffix(testSuite.API, "/") } else { @@ -125,10 +133,11 @@ func runSuite(suite string, ctx map[string]interface{}) (err error) { setRelativeDir(suite, &testCase) var output interface{} - if output, err = runner.RunTestCase(&testCase, ctx); err != nil { + ctxWithTimeout, _ := context.WithTimeout(ctx, o.requestTimeout) + if output, err = runner.RunTestCase(&testCase, dataContext, ctxWithTimeout); err != nil && !o.requestIgnoreError { return } - ctx[testCase.Name] = output + dataContext[testCase.Name] = output } return } diff --git a/cmd/run_test.go b/cmd/run_test.go index 8e3d9fc06..2ae8ccbb1 100644 --- a/cmd/run_test.go +++ b/cmd/run_test.go @@ -1,8 +1,10 @@ package cmd import ( + "context" "net/http" "testing" + "time" "github.com/h2non/gock" "github.com/spf13/cobra" @@ -46,7 +48,9 @@ func TestRunSuite(t *testing.T) { tt.prepare() ctx := getDefaultContext() - err := runSuite(tt.suiteFile, ctx) + opt := &runOption{requestTimeout: 30 * time.Second} + + err := opt.runSuite(tt.suiteFile, ctx, context.TODO()) assert.Equal(t, tt.hasError, err != nil, err) }) } diff --git a/pkg/runner/simple.go b/pkg/runner/simple.go index ee0d7d9c5..0407fc4a7 100644 --- a/pkg/runner/simple.go +++ b/pkg/runner/simple.go @@ -2,6 +2,7 @@ package runner import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -11,7 +12,6 @@ import ( "os" "reflect" "strings" - "time" "github.com/andreyvit/diff" "github.com/antonmedv/expr" @@ -22,7 +22,7 @@ import ( ) // RunTestCase runs the test case -func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{}, err error) { +func RunTestCase(testcase *testing.TestCase, dataContext interface{}, ctx context.Context) (output interface{}, err error) { fmt.Printf("start to run: '%s'\n", testcase.Name) if err = doPrepare(testcase); err != nil { err = fmt.Errorf("failed to prepare, error: %v", err) @@ -37,9 +37,7 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{ } }() - client := http.Client{ - Timeout: time.Second * 30, - } + client := http.Client{} var requestBody io.Reader if testcase.Request.Body != "" { requestBody = bytes.NewBufferString(testcase.Request.Body) @@ -51,7 +49,7 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{ requestBody = bytes.NewBufferString(string(data)) } - if err = testcase.Request.Render(ctx); err != nil { + if err = testcase.Request.Render(dataContext); err != nil { return } @@ -76,7 +74,7 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{ } var request *http.Request - if request, err = http.NewRequest(testcase.Request.Method, testcase.Request.API, requestBody); err != nil { + if request, err = http.NewRequestWithContext(ctx, testcase.Request.Method, testcase.Request.API, requestBody); err != nil { return } diff --git a/pkg/runner/simple_test.go b/pkg/runner/simple_test.go index fa5f84134..1846f8c40 100644 --- a/pkg/runner/simple_test.go +++ b/pkg/runner/simple_test.go @@ -1,6 +1,7 @@ package runner import ( + "context" "errors" "net/http" "testing" @@ -365,7 +366,7 @@ func TestTestCase(t *testing.T) { if tt.prepare != nil { tt.prepare() } - output, err := RunTestCase(tt.testCase, tt.ctx) + output, err := RunTestCase(tt.testCase, tt.ctx, context.TODO()) tt.verify(t, output, err) }) }