Skip to content

Commit 27dbe23

Browse files
committed
Add tests and correct bugs
1 parent 0fa6664 commit 27dbe23

File tree

5 files changed

+84
-8
lines changed

5 files changed

+84
-8
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ require (
66
github.com/prometheus/client_golang v1.19.0
77
github.com/redis/go-redis/v9 v9.5.1
88
google.golang.org/grpc v1.63.2
9-
google.golang.org/protbuf v1.34.1
9+
google.golang.org/protobuf v1.34.1
1010
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
2+
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
3+
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
4+
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
5+
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
6+
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
7+
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
8+
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
9+
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
10+
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=

internal/algorithm/sliding_window.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ type SlidingWindow struct {
1616
window time.Duration
1717
}
1818

19-
func NewSlidingWindoe(limit int, window time.Duration) *SlidingWindow {
19+
func NewSlidingWindow(limit int, window time.Duration) *SlidingWindow {
2020
return &SlidingWindow{limit: limit, window: window}
2121
}
2222

23-
func (sw: *SlidingWindow) Allow() bool {
23+
func (sw *SlidingWindow) Allow() bool {
2424
sw.mu.Lock()
2525
defer sw.mu.Unlock()
2626

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,67 @@
1-
// internal/algorithm/sliding_window_test.go
1+
package algorithm_test
2+
3+
import (
4+
"sync"
5+
"time"
6+
"testing"
7+
8+
"github.com/Pavan-Rana/rate-limiter/internal/algorithm"
9+
)
10+
11+
func TestSlidingWindow_BasicLimit(t *testing.T) {
12+
sw := algorithm.NewSlidingWindow(5, time.Second)
13+
14+
for i := 0; i < 5; i++ {
15+
if !sw.Allow() {
16+
t.Fatalf("Expected request %d to be allowed", i+1)
17+
}
18+
}
19+
if sw.Allow() {
20+
t.Fatal("Expected 6th request to be rejected")
21+
}
22+
}
23+
24+
func TestSlidingWindow_WindowExpiry(t *testing.T) {
25+
sw := algorithm.NewSlidingWindow(3, 100*time.Millisecond)
26+
27+
for i := 0; i < 3; i++ {
28+
sw.Allow()
29+
}
30+
if sw.Allow() {
31+
t.Fatal("Expected 4th request to be rejected")
32+
}
33+
34+
time.Sleep(110 * time.Millisecond)
35+
36+
if !sw.Allow(){
37+
t.Fatal("Expected request to be allowed after window expiry")
38+
}
39+
}
40+
41+
func TestSlidingWindow_ConcurrentAccess(t *testing.T) {
42+
const limit = 100
43+
sw := algorithm.NewSlidingWindow(limit, time.Second)
44+
45+
var (
46+
wg sync.WaitGroup
47+
mu sync.Mutex
48+
allowed int
49+
)
50+
51+
for i := 0; i < limit; i++ {
52+
wg.Add(1)
53+
go func() {
54+
defer wg.Done()
55+
if sw.Allow() {
56+
mu.Lock()
57+
allowed++
58+
mu.Unlock()
59+
}
60+
}()
61+
}
62+
wg.Wait()
63+
64+
if allowed > limit {
65+
t.Fatalf("Allowed %d requests, limit is %d", allowed, limit)
66+
}
67+
}

internal/algorithm/token_bucket.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ type TokenBucket struct {
1111
tokens float64
1212
capacity float64
1313
rate float64 // tokens per second
14-
lastFillTime time.Time
14+
lastFill time.Time
1515
}
1616

17-
func NewTokenBucet(capacity float64, ratePerSec float64) *TokenBucket {
17+
func NewTokenBucket(capacity float64, ratePerSec float64) *TokenBucket {
1818
return &TokenBucket{
1919
tokens: capacity,
2020
capacity: capacity,
2121
rate: ratePerSec,
22-
lastFillTime: time.Now(),
22+
lastFill: time.Now(),
2323
}
2424
}
2525

@@ -28,7 +28,7 @@ func (tb *TokenBucket) Allow() bool {
2828
defer tb.mu.Unlock()
2929

3030
now := time.Now()
31-
elapsed := now.Sub(tb.lastFillTime).Seconds()
31+
elapsed := now.Sub(tb.lastFill).Seconds()
3232
tb.tokens = minF(tb.capacity, tb.tokens+elapsed*tb.rate)
3333
tb.lastFill = now
3434

0 commit comments

Comments
 (0)