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,21 @@ 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 )
107
119
}
108
120
}
109
- err = <- errChannel
121
+
122
+ select {
123
+ case err = <- errChannel :
124
+ case <- stopSingal :
125
+ }
126
+
110
127
wait .Wait ()
111
128
return
112
129
}
113
130
114
- func (o * runOption ) runSuite (suite string , dataContext map [string ]interface {}, ctx context.Context ) (err error ) {
131
+ func (o * runOption ) runSuite (suite string , dataContext map [string ]interface {}, ctx context.Context , stopSingal chan struct {} ) (err error ) {
115
132
var testSuite * testing.TestSuite
116
133
if testSuite , err = testing .Parse (suite ); err != nil {
117
134
return
@@ -131,11 +148,23 @@ func (o *runOption) runSuite(suite string, dataContext map[string]interface{}, c
131
148
testCase .Request .API = fmt .Sprintf ("%s%s" , testSuite .API , testCase .Request .API )
132
149
}
133
150
134
- setRelativeDir (suite , & testCase )
135
151
var output interface {}
136
- ctxWithTimeout , _ := context . WithTimeout ( ctx , o . requestTimeout )
137
- if output , err = runner . RunTestCase ( & testCase , dataContext , ctxWithTimeout ); err != nil && ! o . requestIgnoreError {
152
+ select {
153
+ case <- stopSingal :
138
154
return
155
+ default :
156
+ // reuse the API prefix
157
+ if strings .HasPrefix (testCase .Request .API , "/" ) {
158
+ testCase .Request .API = fmt .Sprintf ("%s%s" , testSuite .API , testCase .Request .API )
159
+ }
160
+
161
+ setRelativeDir (suite , & testCase )
162
+ o .limiter .Accept ()
163
+
164
+ ctxWithTimeout , _ := context .WithTimeout (ctx , o .requestTimeout )
165
+ if output , err = runner .RunTestCase (& testCase , dataContext , ctxWithTimeout ); err != nil && ! o .requestIgnoreError {
166
+ return
167
+ }
139
168
}
140
169
dataContext [testCase .Name ] = output
141
170
}
0 commit comments