veza/veza-backend-api/internal/websocket/chat/rate_limiter_test.go
senke 1ed7fe2ebb feat(chat): Redis rate limiter, persistent presence, PostgreSQL full-text search
- Rewrite chat rate limiter with Redis sliding window (sorted sets) and
  automatic in-memory fallback when Redis is unavailable
- Add ChatPresenceService with Redis-backed online/offline/heartbeat
  tracking (2min TTL), integrated into Hub register/unregister
- Add migration 113: tsvector column with GIN index and auto-update
  trigger on messages table for full-text search
- Update Search repository method to use ts_rank ordering instead of ILIKE
- Wire Redis client into chat WebSocket setup in router.go
- Add comprehensive tests: rate limiter, presence, 100-user concurrent benchmark
2026-02-22 21:17:51 +01:00

75 lines
2 KiB
Go

package chat
import (
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"go.uber.org/zap/zaptest"
)
func TestRateLimiter_InMemoryFallback_AllowsWithinLimit(t *testing.T) {
logger := zaptest.NewLogger(t)
rl := NewRateLimiter(nil, logger)
userID := uuid.New()
for i := 0; i < 10; i++ {
assert.True(t, rl.Allow(userID, "send_message"), "request %d should be allowed", i+1)
}
assert.False(t, rl.Allow(userID, "send_message"), "11th request should be denied")
}
func TestRateLimiter_InMemoryFallback_WindowReset(t *testing.T) {
logger := zaptest.NewLogger(t)
rl := NewRateLimiter(nil, logger)
rl.limits["test_action"] = rateConfig{maxRequests: 2, window: 50 * time.Millisecond}
userID := uuid.New()
assert.True(t, rl.Allow(userID, "test_action"))
assert.True(t, rl.Allow(userID, "test_action"))
assert.False(t, rl.Allow(userID, "test_action"))
time.Sleep(60 * time.Millisecond)
assert.True(t, rl.Allow(userID, "test_action"), "should allow after window reset")
}
func TestRateLimiter_UnknownAction_AlwaysAllowed(t *testing.T) {
logger := zaptest.NewLogger(t)
rl := NewRateLimiter(nil, logger)
userID := uuid.New()
for i := 0; i < 100; i++ {
assert.True(t, rl.Allow(userID, "unknown_action"))
}
}
func TestRateLimiter_DifferentUsers_IndependentLimits(t *testing.T) {
logger := zaptest.NewLogger(t)
rl := NewRateLimiter(nil, logger)
user1 := uuid.New()
user2 := uuid.New()
for i := 0; i < 10; i++ {
assert.True(t, rl.Allow(user1, "send_message"))
}
assert.False(t, rl.Allow(user1, "send_message"))
assert.True(t, rl.Allow(user2, "send_message"), "user2 should be independent of user1")
}
func TestRateLimiter_DifferentActions_IndependentLimits(t *testing.T) {
logger := zaptest.NewLogger(t)
rl := NewRateLimiter(nil, logger)
userID := uuid.New()
for i := 0; i < 10; i++ {
assert.True(t, rl.Allow(userID, "send_message"))
}
assert.False(t, rl.Allow(userID, "send_message"))
assert.True(t, rl.Allow(userID, "typing"), "typing should be independent of send_message")
}