fix: the qps feature cannot work well (#201)
This commit is contained in:
parent
3f2877e6c2
commit
69e53b6e04
|
@ -15,6 +15,9 @@ jobs:
|
||||||
- name: Unit Test
|
- name: Unit Test
|
||||||
run: |
|
run: |
|
||||||
make test-all-backend test-operator
|
make test-all-backend test-operator
|
||||||
|
- name: Long Test
|
||||||
|
run: |
|
||||||
|
make testlong
|
||||||
- name: Report
|
- name: Report
|
||||||
if: github.actor == 'linuxsuren'
|
if: github.actor == 'linuxsuren'
|
||||||
env:
|
env:
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -46,6 +46,8 @@ plugin-git:
|
||||||
test:
|
test:
|
||||||
go test ./... -cover -v -coverprofile=coverage.out
|
go test ./... -cover -v -coverprofile=coverage.out
|
||||||
go tool cover -func=coverage.out
|
go tool cover -func=coverage.out
|
||||||
|
testlong:
|
||||||
|
go test pkg/limit/limiter_long_test.go -v
|
||||||
test-ui:
|
test-ui:
|
||||||
cd console/atest-ui && npm run test:unit
|
cd console/atest-ui && npm run test:unit
|
||||||
test-e2e:
|
test-e2e:
|
||||||
|
|
|
@ -17,8 +17,8 @@ You can install in various methods:
|
||||||
|
|
||||||
* CLI via `hd i atest`
|
* CLI via `hd i atest`
|
||||||
* Web server
|
* Web server
|
||||||
* [Kubernetes](https://github.com/LinuxSuRen/api-testing/tree/master/sample/kubernetes)
|
* [Kubernetes](https://github.com/LinuxSuRen/api-testing/tree/master/docs/manifests/kubernetes)
|
||||||
* [Argo CD](https://github.com/LinuxSuRen/api-testing/blob/master/sample/argocd/simple.yaml)
|
* [Argo CD](https://github.com/LinuxSuRen/api-testing/blob/master/docs/manifests/argocd/simple.yaml)
|
||||||
|
|
||||||
If you're developing APIs locally, the best way is installing it as a container service.
|
If you're developing APIs locally, the best way is installing it as a container service.
|
||||||
Then you can access it via your browser.
|
Then you can access it via your browser.
|
||||||
|
|
|
@ -6,8 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type RateLimiter interface {
|
type RateLimiter interface {
|
||||||
TryAccept() bool
|
Accept() bool
|
||||||
Accept()
|
|
||||||
Stop()
|
Stop()
|
||||||
Burst() int32
|
Burst() int32
|
||||||
}
|
}
|
||||||
|
@ -28,43 +27,40 @@ func NewDefaultRateLimiter(qps, burst int32) RateLimiter {
|
||||||
burst = 5
|
burst = 5
|
||||||
}
|
}
|
||||||
limiter := &defaultRateLimiter{
|
limiter := &defaultRateLimiter{
|
||||||
qps: qps,
|
qps: qps,
|
||||||
burst: burst,
|
burst: burst,
|
||||||
singal: make(chan struct{}, 1),
|
singal: make(chan struct{}, 1),
|
||||||
|
lastToken: time.Now(),
|
||||||
}
|
}
|
||||||
go limiter.updateBurst()
|
go limiter.updateBurst()
|
||||||
return limiter
|
return limiter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *defaultRateLimiter) TryAccept() bool {
|
|
||||||
_, ok := r.resver()
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *defaultRateLimiter) resver() (delay time.Duration, ok bool) {
|
func (r *defaultRateLimiter) resver() (delay time.Duration, ok bool) {
|
||||||
delay = time.Now().Sub(r.lastToken) / time.Millisecond
|
delay = time.Now().Sub(r.lastToken) / time.Millisecond
|
||||||
|
delayRequire := time.Second / time.Duration(r.qps)
|
||||||
r.lastToken = time.Now()
|
r.lastToken = time.Now()
|
||||||
if delay > 0 {
|
if delay >= delayRequire {
|
||||||
ok = true
|
ok = true
|
||||||
} else if r.Burst() > 0 {
|
} else if r.Burst() > 0 {
|
||||||
r.Setburst(r.Burst() - 1)
|
r.Setburst(r.Burst() - 1)
|
||||||
ok = true
|
ok = true
|
||||||
} else {
|
} else {
|
||||||
delay = time.Second / time.Duration(r.qps)
|
delay = delayRequire - delay
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *defaultRateLimiter) Accept() {
|
func (r *defaultRateLimiter) Accept() bool {
|
||||||
delay, ok := r.resver()
|
delay, ok := r.resver()
|
||||||
if ok {
|
if ok {
|
||||||
return
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
if delay > 0 {
|
if delay > 0 {
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
}
|
}
|
||||||
return
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *defaultRateLimiter) Setburst(burst int32) {
|
func (r *defaultRateLimiter) Setburst(burst int32) {
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
//go:build longtest
|
||||||
|
// +build longtest
|
||||||
|
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 API Testing Authors.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package limit_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/linuxsuren/api-testing/pkg/limit"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLimiterWithLongTime(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
testLimiter(t, int32(8+i*2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLimiter(t *testing.T, count int32) {
|
||||||
|
t.Log("test limit with count", count)
|
||||||
|
limiter := limit.NewDefaultRateLimiter(count, 1)
|
||||||
|
num := int32(0)
|
||||||
|
|
||||||
|
loop := true
|
||||||
|
go func(l limit.RateLimiter) {
|
||||||
|
for loop {
|
||||||
|
l.Accept()
|
||||||
|
num += 1
|
||||||
|
}
|
||||||
|
}(limiter)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
loop = false
|
||||||
|
}
|
||||||
|
assert.True(t, num <= count+1, num)
|
||||||
|
}
|
|
@ -7,8 +7,9 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestXxx(t *testing.T) {
|
func TestLimiter(t *testing.T) {
|
||||||
limiter := NewDefaultRateLimiter(1, 1)
|
t.Log("run rate limit test")
|
||||||
|
limiter := NewDefaultRateLimiter(0, 0)
|
||||||
num := 0
|
num := 0
|
||||||
|
|
||||||
loop := true
|
loop := true
|
||||||
|
@ -22,6 +23,7 @@ func TestXxx(t *testing.T) {
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Second):
|
case <-time.After(time.Second):
|
||||||
loop = false
|
loop = false
|
||||||
|
limiter.Stop()
|
||||||
}
|
}
|
||||||
assert.True(t, num <= 10)
|
assert.True(t, num <= 10, num)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue