backend/pkg/library/centrifugo/online_redis_test.go

272 lines
6.2 KiB
Go
Raw Normal View History

2026-01-06 07:15:18 +00:00
package centrifugo
import (
"context"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zeromicro/go-zero/core/stores/redis"
)
func setupOnlineTestRedis(t *testing.T) (*redis.Redis, func()) {
mr, err := miniredis.Run()
require.NoError(t, err)
rds, err := redis.NewRedis(redis.RedisConf{
Host: mr.Addr(),
Type: "node",
})
require.NoError(t, err)
return rds, func() {
mr.Close()
}
}
func TestNewRedisOnlineStore(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
assert.NotNil(t, store)
assert.Equal(t, "online:", store.keyPrefix)
}
func TestNewRedisOnlineStoreWithPrefix(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStoreWithPrefix(rds, "custom:online:")
assert.NotNil(t, store)
assert.Equal(t, "custom:online:", store.keyPrefix)
}
func TestSetOnline(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
userID := "user-123"
ttl := 5 * time.Minute
// 設置在線
err := store.SetOnline(ctx, userID, ttl)
require.NoError(t, err)
// 檢查是否在線
online, err := store.IsOnline(ctx, userID)
require.NoError(t, err)
assert.True(t, online)
}
func TestSetOffline(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
userID := "user-123"
// 先設置在線
err := store.SetOnline(ctx, userID, 5*time.Minute)
require.NoError(t, err)
// 設置離線
err = store.SetOffline(ctx, userID)
require.NoError(t, err)
// 檢查是否離線
online, err := store.IsOnline(ctx, userID)
require.NoError(t, err)
assert.False(t, online)
}
func TestIsOnline_NotOnline(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
// 未設置在線的用戶應該返回 false
online, err := store.IsOnline(ctx, "non-existent-user")
require.NoError(t, err)
assert.False(t, online)
}
func TestGetOnlineUsers(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
// 設置一些用戶在線
err := store.SetOnline(ctx, "user-1", 5*time.Minute)
require.NoError(t, err)
err = store.SetOnline(ctx, "user-3", 5*time.Minute)
require.NoError(t, err)
// 批量獲取在線狀態
userIDs := []string{"user-1", "user-2", "user-3"}
status, err := store.GetOnlineUsers(ctx, userIDs)
require.NoError(t, err)
assert.True(t, status["user-1"])
assert.False(t, status["user-2"])
assert.True(t, status["user-3"])
}
func TestGetOnlineUsers_Empty(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
// 空列表應該返回空 map
status, err := store.GetOnlineUsers(ctx, []string{})
require.NoError(t, err)
assert.Empty(t, status)
}
func TestIncrClient(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
userID := "user-123"
// 第一次增加
count, err := store.IncrClient(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(1), count)
// 第二次增加
count, err = store.IncrClient(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
// 獲取連線數
count, err = store.GetClientCount(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
}
func TestDecrClient(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
userID := "user-123"
// 先增加到 2
_, err := store.IncrClient(ctx, userID)
require.NoError(t, err)
_, err = store.IncrClient(ctx, userID)
require.NoError(t, err)
// 減少一次
count, err := store.DecrClient(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(1), count)
// 再減少一次
count, err = store.DecrClient(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(0), count)
}
func TestDecrClient_NegativeProtection(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
userID := "user-123"
// 直接減少(沒有先增加)
count, err := store.DecrClient(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(0), count) // 應該被保護為 0
// 再次減少
count, err = store.DecrClient(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(0), count) // 仍然是 0
}
func TestGetClientCount_NoClient(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
// 未設置連線數的用戶應該返回 0
count, err := store.GetClientCount(ctx, "non-existent-user")
require.NoError(t, err)
assert.Equal(t, int64(0), count)
}
func TestSetOffline_ClearsClientCount(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
ctx := context.Background()
userID := "user-123"
// 設置在線和連線數
err := store.SetOnline(ctx, userID, 5*time.Minute)
require.NoError(t, err)
_, err = store.IncrClient(ctx, userID)
require.NoError(t, err)
_, err = store.IncrClient(ctx, userID)
require.NoError(t, err)
// 設置離線
err = store.SetOffline(ctx, userID)
require.NoError(t, err)
// 連線數也應該被清除
count, err := store.GetClientCount(ctx, userID)
require.NoError(t, err)
assert.Equal(t, int64(0), count)
}
func TestKeyGeneration_OnlineStore(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStoreWithPrefix(rds, "test:")
// 測試 key 生成
assert.Equal(t, "test:user-123", store.key("user-123"))
assert.Equal(t, "test:clients:user-456", store.clientCountKey("user-456"))
}
func TestOnlineStore_ImplementsInterface(t *testing.T) {
rds, cleanup := setupOnlineTestRedis(t)
defer cleanup()
store := NewRedisOnlineStore(rds)
// 確保 RedisOnlineStore 實現了 OnlineStore 介面
var _ OnlineStore = store
}