mirror of https://github.com/q191201771/naza
- 新增 package ratelimit:限速器,令牌桶
- 新增 package bitrate:计算带宽 - 新增 package fake - 删除 package mockwriter - 删除 package mockserver - demo/add_blog_license:行尾增加两个空格,便于部分 markdown 解析器解析为为换行pull/2/head
parent
b1349bbc76
commit
7722ee012a
@ -0,0 +1,29 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package bitrate_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/q191201771/naza/pkg/assert"
|
||||
"github.com/q191201771/naza/pkg/bitrate"
|
||||
)
|
||||
|
||||
func TestBitrate(t *testing.T) {
|
||||
var b *bitrate.Bitrate
|
||||
b = bitrate.NewBitrate(func(option *bitrate.Option) {
|
||||
option.WindowMS = 10
|
||||
})
|
||||
b.Add(1000)
|
||||
r := b.Rate()
|
||||
assert.Equal(t, 800, r)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
b.Rate()
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package fake_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/q191201771/naza/pkg/fake"
|
||||
|
||||
"github.com/q191201771/naza/pkg/assert"
|
||||
)
|
||||
|
||||
func TestNewWriter(t *testing.T) {
|
||||
_ = fake.NewWriter(fake.WriterTypeDoNothing)
|
||||
}
|
||||
|
||||
func TestWriter_Write(t *testing.T) {
|
||||
var (
|
||||
w *fake.Writer
|
||||
n int
|
||||
err error
|
||||
b = []byte("hello")
|
||||
)
|
||||
|
||||
w = fake.NewWriter(fake.WriterTypeDoNothing)
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, 5, n)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
w = fake.NewWriter(fake.WriterTypeReturnError)
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, 0, n)
|
||||
assert.Equal(t, fake.ErrFakeWriter, err)
|
||||
|
||||
w = fake.NewWriter(fake.WriterTypeIntoBuffer)
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, 5, n)
|
||||
assert.Equal(t, nil, err)
|
||||
}
|
||||
|
||||
func TestWriter_SetSpecificType(t *testing.T) {
|
||||
var (
|
||||
w *fake.Writer
|
||||
n int
|
||||
err error
|
||||
b = []byte("hello")
|
||||
)
|
||||
w = fake.NewWriter(fake.WriterTypeDoNothing)
|
||||
w.SetSpecificType(map[uint32]fake.WriterType{
|
||||
0: fake.WriterTypeReturnError,
|
||||
2: fake.WriterTypeReturnError,
|
||||
4: fake.WriterTypeDoNothing,
|
||||
})
|
||||
|
||||
expectedLen := map[int]int{
|
||||
0: 0,
|
||||
1: 5,
|
||||
2: 0,
|
||||
3: 5,
|
||||
4: 5,
|
||||
5: 5,
|
||||
}
|
||||
expectedErr := map[int]error{
|
||||
0: fake.ErrFakeWriter,
|
||||
1: nil,
|
||||
2: fake.ErrFakeWriter,
|
||||
3: nil,
|
||||
4: nil,
|
||||
5: nil,
|
||||
}
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, expectedLen[i], n)
|
||||
assert.Equal(t, expectedErr[i], err)
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package mockserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type MockAcceptServer struct {
|
||||
l net.Listener
|
||||
conns []net.Conn
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
func (s *MockAcceptServer) Run(addr string) (err error) {
|
||||
s.m.Lock()
|
||||
s.l, err = net.Listen("tcp", addr)
|
||||
s.m.Unlock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c, err := s.l.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.conns = append(s.conns, c)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *MockAcceptServer) Dispose() {
|
||||
s.m.Lock()
|
||||
if s.l != nil {
|
||||
s.l.Close()
|
||||
|
||||
}
|
||||
s.m.Unlock()
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package mockserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/q191201771/naza/pkg/assert"
|
||||
)
|
||||
|
||||
var addr = ":10027"
|
||||
|
||||
func TestMockListenServer(t *testing.T) {
|
||||
//var s MockListenServer
|
||||
//err := s.Run(addr)
|
||||
//assert.Equal(t, nil, err)
|
||||
//defer s.Dispose()
|
||||
//_, err = net.DialTimeout("tcp", addr, time.Duration(1000) * time.Millisecond)
|
||||
//assert.IsNotNil(t, err)
|
||||
}
|
||||
|
||||
func TestMockAcceptServer(t *testing.T) {
|
||||
var s MockAcceptServer
|
||||
var conns []net.Conn
|
||||
go s.Run(addr)
|
||||
for i := 0; i < 16; i++ {
|
||||
c, err := net.DialTimeout("tcp", addr, time.Duration(1000)*time.Millisecond)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
//assert.Equal(t, nil, err)
|
||||
conns = append(conns, c)
|
||||
}
|
||||
s.Dispose()
|
||||
}
|
||||
|
||||
func TestCorner(t *testing.T) {
|
||||
var s MockListenServer
|
||||
err := s.Run("wrong addr")
|
||||
assert.IsNotNil(t, err)
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package mockwriter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/q191201771/naza/pkg/assert"
|
||||
)
|
||||
|
||||
func TestNewMockWriter(t *testing.T) {
|
||||
_ = NewMockWriter(WriterTypeDoNothing)
|
||||
}
|
||||
|
||||
func TestMockWriter_Write(t *testing.T) {
|
||||
var (
|
||||
w *MockWriter
|
||||
n int
|
||||
err error
|
||||
b = []byte("hello")
|
||||
)
|
||||
|
||||
w = NewMockWriter(WriterTypeDoNothing)
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, 5, n)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
w = NewMockWriter(WriterTypeReturnError)
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, 0, n)
|
||||
assert.Equal(t, ErrMockWriter, err)
|
||||
|
||||
w = NewMockWriter(WriterTypeIntoBuffer)
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, 5, n)
|
||||
assert.Equal(t, nil, err)
|
||||
}
|
||||
|
||||
func TestMockWriter_SetSpecificType(t *testing.T) {
|
||||
var (
|
||||
w *MockWriter
|
||||
n int
|
||||
err error
|
||||
b = []byte("hello")
|
||||
)
|
||||
w = NewMockWriter(WriterTypeDoNothing)
|
||||
w.SetSpecificType(map[uint32]WriterType{
|
||||
0: WriterTypeReturnError,
|
||||
2: WriterTypeReturnError,
|
||||
4: WriterTypeDoNothing,
|
||||
})
|
||||
|
||||
expectedLen := map[int]int{
|
||||
0: 0,
|
||||
1: 5,
|
||||
2: 0,
|
||||
3: 5,
|
||||
4: 5,
|
||||
5: 5,
|
||||
}
|
||||
expectedErr := map[int]error{
|
||||
0: ErrMockWriter,
|
||||
1: nil,
|
||||
2: ErrMockWriter,
|
||||
3: nil,
|
||||
4: nil,
|
||||
5: nil,
|
||||
}
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
n, err = w.Write(b)
|
||||
assert.Equal(t, expectedLen[i], n)
|
||||
assert.Equal(t, expectedErr[i], err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewMockWriter(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
var tmp uint32
|
||||
for i := 0; i < b.N; i++ {
|
||||
mw := NewMockWriter(WriterTypeDoNothing)
|
||||
tmp = tmp + mw.count
|
||||
}
|
||||
}
|
||||
|
||||
func newMockWriter2(t WriterType) MockWriter {
|
||||
return MockWriter{
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNewMockWriter2(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
var tmp uint32
|
||||
for i := 0; i < b.N; i++ {
|
||||
mw := newMockWriter2(WriterTypeDoNothing)
|
||||
tmp = tmp + mw.count
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RateLimit struct {
|
||||
num int
|
||||
option Option
|
||||
|
||||
neededWait time.Duration
|
||||
mu sync.Mutex
|
||||
last time.Time
|
||||
}
|
||||
|
||||
type Option struct {
|
||||
Duration time.Duration
|
||||
}
|
||||
|
||||
var defaultOption = Option{
|
||||
Duration: 1 * time.Second,
|
||||
}
|
||||
|
||||
type ModOption func(option *Option)
|
||||
|
||||
func New(num int, modOptions ...ModOption) *RateLimit {
|
||||
option := defaultOption
|
||||
for _, fn := range modOptions {
|
||||
fn(&option)
|
||||
}
|
||||
return &RateLimit{
|
||||
num: num,
|
||||
option: option,
|
||||
neededWait: option.Duration / time.Duration(num),
|
||||
}
|
||||
}
|
||||
|
||||
func (rl *RateLimit) Wait() {
|
||||
rl.mu.Lock()
|
||||
now := time.Now()
|
||||
if rl.last.IsZero() {
|
||||
rl.last = now
|
||||
rl.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
diff := now.Sub(rl.last)
|
||||
if diff > rl.neededWait {
|
||||
rl.last = now
|
||||
rl.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
rl.last = rl.last.Add(rl.neededWait)
|
||||
rl.mu.Unlock()
|
||||
|
||||
t := time.NewTimer(rl.neededWait - diff)
|
||||
<-t.C
|
||||
t.Stop()
|
||||
return
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package ratelimit_test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/q191201771/naza/pkg/nazalog"
|
||||
"github.com/q191201771/naza/pkg/ratelimit"
|
||||
)
|
||||
|
||||
var (
|
||||
duration = 100 * time.Millisecond
|
||||
num = 50
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
rl := ratelimit.New(num)
|
||||
rl = ratelimit.New(num, func(option *ratelimit.Option) {
|
||||
option.Duration = duration
|
||||
})
|
||||
rl.Wait()
|
||||
}
|
||||
|
||||
func TestRateLimit_Wait(t *testing.T) {
|
||||
rl := ratelimit.New(num, func(option *ratelimit.Option) {
|
||||
option.Duration = duration
|
||||
})
|
||||
b := time.Now()
|
||||
for i := 0; i < num; i++ {
|
||||
rl.Wait()
|
||||
}
|
||||
nazalog.Debugf("cost:%v", time.Now().Sub(b))
|
||||
}
|
||||
|
||||
func TestRateLimit_Wait2(t *testing.T) {
|
||||
rl := ratelimit.New(num, func(option *ratelimit.Option) {
|
||||
option.Duration = duration
|
||||
})
|
||||
b := time.Now()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(num)
|
||||
for i := 0; i < num; i++ {
|
||||
go func(ii int) {
|
||||
rl.Wait()
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
nazalog.Debugf("cost:%v", time.Now().Sub(b))
|
||||
}
|
||||
|
||||
func TestRateLimit_Wait3(t *testing.T) {
|
||||
rand.Seed(time.Now().Unix())
|
||||
rl := ratelimit.New(num, func(option *ratelimit.Option) {
|
||||
option.Duration = duration
|
||||
})
|
||||
b := time.Now()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(num)
|
||||
for i := 0; i < num; i++ {
|
||||
go func(ii int) {
|
||||
time.Sleep(time.Duration(rand.Int63n(int64(duration) / 2)))
|
||||
rl.Wait()
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
nazalog.Debugf("cost:%v", time.Now().Sub(b))
|
||||
}
|
||||
|
||||
func TestRateLimit_Wait4(t *testing.T) {
|
||||
rl := ratelimit.New(num, func(option *ratelimit.Option) {
|
||||
option.Duration = duration
|
||||
})
|
||||
b := time.Now()
|
||||
for i := 0; i < num; i++ {
|
||||
time.Sleep(time.Duration(int64(duration) * 2 / int64(num)))
|
||||
rl.Wait()
|
||||
}
|
||||
nazalog.Debugf("cost:%v", time.Now().Sub(b))
|
||||
}
|
||||
|
||||
func BenchmarkRateLimit_Wait(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
rl := ratelimit.New(num)
|
||||
for i := 0; i < num; i++ {
|
||||
rl.Wait()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue