From 69e53b6e04811a7f9d4fdac6a05dfab7e5fe82f6 Mon Sep 17 00:00:00 2001 From: Rick <1450685+LinuxSuRen@users.noreply.github.com> Date: Tue, 5 Sep 2023 09:53:06 +0800 Subject: [PATCH] fix: the qps feature cannot work well (#201) --- .github/workflows/build.yaml | 3 + Makefile | 2 + docs/README.md | 4 +- {sample => docs/manifests}/argocd/simple.yaml | 0 .../kubernetes/default/kustomization.yaml | 0 .../kubernetes/default/manifest.yaml | 0 .../kubernetes/docker.io/kustomization.yaml | 0 pkg/limit/limiter.go | 26 ++++---- pkg/limit/limiter_long_test.go | 62 +++++++++++++++++++ pkg/limit/limiter_test.go | 8 ++- 10 files changed, 85 insertions(+), 20 deletions(-) rename {sample => docs/manifests}/argocd/simple.yaml (100%) rename {sample => docs/manifests}/kubernetes/default/kustomization.yaml (100%) rename {sample => docs/manifests}/kubernetes/default/manifest.yaml (100%) rename {sample => docs/manifests}/kubernetes/docker.io/kustomization.yaml (100%) create mode 100644 pkg/limit/limiter_long_test.go diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1e8b74b..bfd399b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -15,6 +15,9 @@ jobs: - name: Unit Test run: | make test-all-backend test-operator + - name: Long Test + run: | + make testlong - name: Report if: github.actor == 'linuxsuren' env: diff --git a/Makefile b/Makefile index 94d84cb..4a2330b 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,8 @@ plugin-git: test: go test ./... -cover -v -coverprofile=coverage.out go tool cover -func=coverage.out +testlong: + go test pkg/limit/limiter_long_test.go -v test-ui: cd console/atest-ui && npm run test:unit test-e2e: diff --git a/docs/README.md b/docs/README.md index e0010ca..40088d3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,8 +17,8 @@ You can install in various methods: * CLI via `hd i atest` * Web server -* [Kubernetes](https://github.com/LinuxSuRen/api-testing/tree/master/sample/kubernetes) -* [Argo CD](https://github.com/LinuxSuRen/api-testing/blob/master/sample/argocd/simple.yaml) +* [Kubernetes](https://github.com/LinuxSuRen/api-testing/tree/master/docs/manifests/kubernetes) +* [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. Then you can access it via your browser. diff --git a/sample/argocd/simple.yaml b/docs/manifests/argocd/simple.yaml similarity index 100% rename from sample/argocd/simple.yaml rename to docs/manifests/argocd/simple.yaml diff --git a/sample/kubernetes/default/kustomization.yaml b/docs/manifests/kubernetes/default/kustomization.yaml similarity index 100% rename from sample/kubernetes/default/kustomization.yaml rename to docs/manifests/kubernetes/default/kustomization.yaml diff --git a/sample/kubernetes/default/manifest.yaml b/docs/manifests/kubernetes/default/manifest.yaml similarity index 100% rename from sample/kubernetes/default/manifest.yaml rename to docs/manifests/kubernetes/default/manifest.yaml diff --git a/sample/kubernetes/docker.io/kustomization.yaml b/docs/manifests/kubernetes/docker.io/kustomization.yaml similarity index 100% rename from sample/kubernetes/docker.io/kustomization.yaml rename to docs/manifests/kubernetes/docker.io/kustomization.yaml diff --git a/pkg/limit/limiter.go b/pkg/limit/limiter.go index c71f9b1..23ae56c 100644 --- a/pkg/limit/limiter.go +++ b/pkg/limit/limiter.go @@ -6,8 +6,7 @@ import ( ) type RateLimiter interface { - TryAccept() bool - Accept() + Accept() bool Stop() Burst() int32 } @@ -28,43 +27,40 @@ func NewDefaultRateLimiter(qps, burst int32) RateLimiter { burst = 5 } limiter := &defaultRateLimiter{ - qps: qps, - burst: burst, - singal: make(chan struct{}, 1), + qps: qps, + burst: burst, + singal: make(chan struct{}, 1), + lastToken: time.Now(), } go limiter.updateBurst() return limiter } -func (r *defaultRateLimiter) TryAccept() bool { - _, ok := r.resver() - return ok -} - func (r *defaultRateLimiter) resver() (delay time.Duration, ok bool) { delay = time.Now().Sub(r.lastToken) / time.Millisecond + delayRequire := time.Second / time.Duration(r.qps) r.lastToken = time.Now() - if delay > 0 { + if delay >= delayRequire { ok = true } else if r.Burst() > 0 { r.Setburst(r.Burst() - 1) ok = true } else { - delay = time.Second / time.Duration(r.qps) + delay = delayRequire - delay } return } -func (r *defaultRateLimiter) Accept() { +func (r *defaultRateLimiter) Accept() bool { delay, ok := r.resver() if ok { - return + return ok } if delay > 0 { time.Sleep(delay) } - return + return ok } func (r *defaultRateLimiter) Setburst(burst int32) { diff --git a/pkg/limit/limiter_long_test.go b/pkg/limit/limiter_long_test.go new file mode 100644 index 0000000..a3d3e3f --- /dev/null +++ b/pkg/limit/limiter_long_test.go @@ -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) +} diff --git a/pkg/limit/limiter_test.go b/pkg/limit/limiter_test.go index a25b17a..a7e779d 100644 --- a/pkg/limit/limiter_test.go +++ b/pkg/limit/limiter_test.go @@ -7,8 +7,9 @@ import ( "github.com/stretchr/testify/assert" ) -func TestXxx(t *testing.T) { - limiter := NewDefaultRateLimiter(1, 1) +func TestLimiter(t *testing.T) { + t.Log("run rate limit test") + limiter := NewDefaultRateLimiter(0, 0) num := 0 loop := true @@ -22,6 +23,7 @@ func TestXxx(t *testing.T) { select { case <-time.After(time.Second): loop = false + limiter.Stop() } - assert.True(t, num <= 10) + assert.True(t, num <= 10, num) }