99 "sync"
1010 "time"
1111
12+ "github.com/linuxsuren/api-testing/pkg/limit"
1213 "github.com/linuxsuren/api-testing/pkg/render"
1314 "github.com/linuxsuren/api-testing/pkg/runner"
1415 "github.com/linuxsuren/api-testing/pkg/testing"
@@ -23,6 +24,10 @@ type runOption struct {
2324 requestIgnoreError bool
2425 thread int64
2526 context context.Context
27+ qps int32
28+ burst int32
29+ limiter limit.RateLimiter
30+ startTime time.Time
2631}
2732
2833// CreateRunCommand returns the run command
@@ -45,12 +50,20 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
4550 flags .DurationVarP (& opt .requestTimeout , "request-timeout" , "" , time .Minute , "Timeout for per request" )
4651 flags .BoolVarP (& opt .requestIgnoreError , "request-ignore-error" , "" , false , "Indicate if ignore the request error" )
4752 flags .Int64VarP (& opt .thread , "thread" , "" , 1 , "Threads of the execution" )
53+ flags .Int32VarP (& opt .qps , "qps" , "" , 5 , "QPS" )
54+ flags .Int32VarP (& opt .burst , "burst" , "" , 5 , "burst" )
4855 return
4956}
5057
5158func (o * runOption ) runE (cmd * cobra.Command , args []string ) (err error ) {
5259 var files []string
60+ o .startTime = time .Now ()
5361 o .context = cmd .Context ()
62+ o .limiter = limit .NewDefaultRateLimiter (o .qps , o .burst )
63+ defer func () {
64+ cmd .Printf ("consume: %s\n " , time .Now ().Sub (o .startTime ).String ())
65+ o .limiter .Stop ()
66+ }()
5467
5568 if files , err = filepath .Glob (o .pattern ); err == nil {
5669 for i := range files {
@@ -74,12 +87,14 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) {
7487 timeout = time .NewTicker (time .Second )
7588 }
7689 errChannel := make (chan error , 10 * o .thread )
90+ stopSingal := make (chan struct {}, 1 )
7791 var wait sync.WaitGroup
7892
7993 for ! stop {
8094 select {
8195 case <- timeout .C :
8296 stop = true
97+ stopSingal <- struct {}{}
8398 case err = <- errChannel :
8499 if err != nil {
85100 stop = true
@@ -89,9 +104,6 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) {
89104 continue
90105 }
91106 wait .Add (1 )
92- if o .duration <= 0 {
93- stop = true
94- }
95107
96108 go func (ch chan error , sem * semaphore.Weighted ) {
97109 now := time .Now ()
@@ -102,16 +114,24 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) {
102114 }()
103115
104116 dataContext := getDefaultContext ()
105- ch <- o .runSuite (suite , dataContext , o .context )
117+ ch <- o .runSuite (suite , dataContext , o .context , stopSingal )
106118 }(errChannel , sem )
119+ if o .duration <= 0 {
120+ stop = true
121+ }
107122 }
108123 }
109- err = <- errChannel
124+
125+ select {
126+ case err = <- errChannel :
127+ case <- stopSingal :
128+ }
129+
110130 wait .Wait ()
111131 return
112132}
113133
114- func (o * runOption ) runSuite (suite string , dataContext map [string ]interface {}, ctx context.Context ) (err error ) {
134+ func (o * runOption ) runSuite (suite string , dataContext map [string ]interface {}, ctx context.Context , stopSingal chan struct {} ) (err error ) {
115135 var testSuite * testing.TestSuite
116136 if testSuite , err = testing .Parse (suite ); err != nil {
117137 return
@@ -131,11 +151,23 @@ func (o *runOption) runSuite(suite string, dataContext map[string]interface{}, c
131151 testCase .Request .API = fmt .Sprintf ("%s%s" , testSuite .API , testCase .Request .API )
132152 }
133153
134- setRelativeDir (suite , & testCase )
135154 var output interface {}
136- ctxWithTimeout , _ := context . WithTimeout ( ctx , o . requestTimeout )
137- if output , err = runner . RunTestCase ( & testCase , dataContext , ctxWithTimeout ); err != nil && ! o . requestIgnoreError {
155+ select {
156+ case <- stopSingal :
138157 return
158+ default :
159+ // reuse the API prefix
160+ if strings .HasPrefix (testCase .Request .API , "/" ) {
161+ testCase .Request .API = fmt .Sprintf ("%s%s" , testSuite .API , testCase .Request .API )
162+ }
163+
164+ setRelativeDir (suite , & testCase )
165+ o .limiter .Accept ()
166+
167+ ctxWithTimeout , _ := context .WithTimeout (ctx , o .requestTimeout )
168+ if output , err = runner .RunTestCase (& testCase , dataContext , ctxWithTimeout ); err != nil && ! o .requestIgnoreError {
169+ return
170+ }
139171 }
140172 dataContext [testCase .Name ] = output
141173 }
0 commit comments