9
9
"sync"
10
10
"time"
11
11
12
+ "github.com/linuxsuren/api-testing/pkg/limit"
12
13
"github.com/linuxsuren/api-testing/pkg/render"
13
14
"github.com/linuxsuren/api-testing/pkg/runner"
14
15
"github.com/linuxsuren/api-testing/pkg/testing"
@@ -23,6 +24,10 @@ type runOption struct {
23
24
requestIgnoreError bool
24
25
thread int64
25
26
context context.Context
27
+ qps int32
28
+ burst int32
29
+ limiter limit.RateLimiter
30
+ startTime time.Time
26
31
}
27
32
28
33
// CreateRunCommand returns the run command
@@ -45,12 +50,20 @@ See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
45
50
flags .DurationVarP (& opt .requestTimeout , "request-timeout" , "" , time .Minute , "Timeout for per request" )
46
51
flags .BoolVarP (& opt .requestIgnoreError , "request-ignore-error" , "" , false , "Indicate if ignore the request error" )
47
52
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" )
48
55
return
49
56
}
50
57
51
58
func (o * runOption ) runE (cmd * cobra.Command , args []string ) (err error ) {
52
59
var files []string
60
+ o .startTime = time .Now ()
53
61
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
+ }()
54
67
55
68
if files , err = filepath .Glob (o .pattern ); err == nil {
56
69
for i := range files {
@@ -74,12 +87,14 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) {
74
87
timeout = time .NewTicker (time .Second )
75
88
}
76
89
errChannel := make (chan error , 10 * o .thread )
90
+ stopSingal := make (chan struct {}, 1 )
77
91
var wait sync.WaitGroup
78
92
79
93
for ! stop {
80
94
select {
81
95
case <- timeout .C :
82
96
stop = true
97
+ stopSingal <- struct {}{}
83
98
case err = <- errChannel :
84
99
if err != nil {
85
100
stop = true
@@ -89,9 +104,6 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) {
89
104
continue
90
105
}
91
106
wait .Add (1 )
92
- if o .duration <= 0 {
93
- stop = true
94
- }
95
107
96
108
go func (ch chan error , sem * semaphore.Weighted ) {
97
109
now := time .Now ()
@@ -102,16 +114,24 @@ func (o *runOption) runSuiteWithDuration(suite string) (err error) {
102
114
}()
103
115
104
116
dataContext := getDefaultContext ()
105
- ch <- o .runSuite (suite , dataContext , o .context )
117
+ ch <- o .runSuite (suite , dataContext , o .context , stopSingal )
106
118
}(errChannel , sem )
119
+ if o .duration <= 0 {
120
+ stop = true
121
+ }
107
122
}
108
123
}
109
- err = <- errChannel
124
+
125
+ select {
126
+ case err = <- errChannel :
127
+ case <- stopSingal :
128
+ }
129
+
110
130
wait .Wait ()
111
131
return
112
132
}
113
133
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 ) {
115
135
var testSuite * testing.TestSuite
116
136
if testSuite , err = testing .Parse (suite ); err != nil {
117
137
return
@@ -131,11 +151,23 @@ func (o *runOption) runSuite(suite string, dataContext map[string]interface{}, c
131
151
testCase .Request .API = fmt .Sprintf ("%s%s" , testSuite .API , testCase .Request .API )
132
152
}
133
153
134
- setRelativeDir (suite , & testCase )
135
154
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 :
138
157
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
+ }
139
171
}
140
172
dataContext [testCase .Name ] = output
141
173
}
0 commit comments