11package cmd
22
33import (
4+ "context"
45 "fmt"
56 "path"
67 "path/filepath"
78 "strings"
9+ "sync"
10+ "time"
811
12+ "github.com/linuxsuren/api-testing/pkg/render"
913 "github.com/linuxsuren/api-testing/pkg/runner"
1014 "github.com/linuxsuren/api-testing/pkg/testing"
1115 "github.com/spf13/cobra"
16+ "golang.org/x/sync/semaphore"
1217)
1318
1419type runOption struct {
15- pattern string
20+ pattern string
21+ duration time.Duration
22+ thread int64
23+ context context.Context
1624}
1725
1826// CreateRunCommand returns the run command
@@ -31,31 +39,84 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
3139 flags := cmd .Flags ()
3240 flags .StringVarP (& opt .pattern , "pattern" , "p" , "test-suite-*.yaml" ,
3341 "The file pattern which try to execute the test cases" )
42+ flags .DurationVarP (& opt .duration , "duration" , "" , 0 , "Running duration" )
43+ flags .Int64VarP (& opt .thread , "thread" , "" , 1 , "Threads of the execution" )
3444 return
3545}
3646
3747func (o * runOption ) runE (cmd * cobra.Command , args []string ) (err error ) {
3848 var files []string
39- ctx := getDefaultContext ()
49+ o . context = cmd . Context ()
4050
4151 if files , err = filepath .Glob (o .pattern ); err == nil {
4252 for i := range files {
4353 item := files [i ]
44- if err = runSuite (item , ctx ); err != nil {
54+ if err = o . runSuiteWithDuration (item ); err != nil {
4555 return
4656 }
4757 }
4858 }
4959 return
5060}
5161
62+ func (o * runOption ) runSuiteWithDuration (suite string ) (err error ) {
63+ sem := semaphore .NewWeighted (o .thread )
64+ stop := false
65+ var timeout * time.Ticker
66+ if o .duration > 0 {
67+ timeout = time .NewTicker (o .duration )
68+ } else {
69+ // make sure having a valid timer
70+ timeout = time .NewTicker (time .Second )
71+ }
72+ errChannel := make (chan error , 10 )
73+ var wait sync.WaitGroup
74+
75+ for ! stop {
76+ select {
77+ case <- timeout .C :
78+ stop = true
79+ case err = <- errChannel :
80+ if err != nil {
81+ stop = true
82+ }
83+ default :
84+ if err := sem .Acquire (o .context , 1 ); err != nil {
85+ continue
86+ }
87+ wait .Add (1 )
88+ if o .duration <= 0 {
89+ stop = true
90+ }
91+
92+ go func (ch chan error ) {
93+ defer sem .Release (1 )
94+ defer wait .Done ()
95+
96+ ctx := getDefaultContext ()
97+ ch <- runSuite (suite , ctx )
98+ }(errChannel )
99+ }
100+ }
101+ err = <- errChannel
102+ wait .Wait ()
103+ return
104+ }
105+
52106func runSuite (suite string , ctx map [string ]interface {}) (err error ) {
53107 var testSuite * testing.TestSuite
54108 if testSuite , err = testing .Parse (suite ); err != nil {
55109 return
56110 }
57111
58- testSuite .API = strings .TrimSuffix (testSuite .API , "/" )
112+ var result string
113+ if result , err = render .Render ("base api" , testSuite .API , ctx ); err == nil {
114+ testSuite .API = result
115+ testSuite .API = strings .TrimSuffix (testSuite .API , "/" )
116+ } else {
117+ return
118+ }
119+
59120 for _ , testCase := range testSuite .Items {
60121 // reuse the API prefix
61122 if strings .HasPrefix (testCase .Request .API , "/" ) {
0 commit comments