303 lines
7.2 KiB
Go
303 lines
7.2 KiB
Go
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 setupServiceTestRedis(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 TestNewService(t *testing.T) {
|
|
rds, cleanup := setupServiceTestRedis(t)
|
|
defer cleanup()
|
|
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: rds,
|
|
})
|
|
|
|
assert.NotNil(t, svc)
|
|
assert.NotNil(t, svc.Client())
|
|
assert.NotNil(t, svc.Token())
|
|
assert.NotNil(t, svc.Blacklist())
|
|
assert.NotNil(t, svc.Online())
|
|
}
|
|
|
|
func TestNewService_WithoutRedis(t *testing.T) {
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: nil, // 沒有 Redis
|
|
})
|
|
|
|
assert.NotNil(t, svc)
|
|
assert.NotNil(t, svc.Client())
|
|
assert.NotNil(t, svc.Token())
|
|
assert.Nil(t, svc.Blacklist()) // 應該為 nil
|
|
assert.Nil(t, svc.Online()) // 應該為 nil
|
|
}
|
|
|
|
func TestNewService_DefaultValues(t *testing.T) {
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
})
|
|
|
|
assert.NotNil(t, svc)
|
|
// 檢查預設值已被應用(通過生成 Token 間接驗證)
|
|
token, err := svc.GenerateToken("user-123")
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, token)
|
|
}
|
|
|
|
func TestNewService_WithCustomConfig(t *testing.T) {
|
|
rds, cleanup := setupServiceTestRedis(t)
|
|
defer cleanup()
|
|
|
|
customExpire := 24 * time.Hour
|
|
customTTL := 10 * time.Minute
|
|
customPrefix := "custom:"
|
|
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
TokenExpire: customExpire,
|
|
Redis: rds,
|
|
OnlineTTL: customTTL,
|
|
KeyPrefix: customPrefix,
|
|
})
|
|
|
|
assert.NotNil(t, svc)
|
|
}
|
|
|
|
func TestService_GenerateToken(t *testing.T) {
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
})
|
|
|
|
token, err := svc.GenerateToken("user-123")
|
|
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, token)
|
|
}
|
|
|
|
func TestService_GenerateTokenWithInfo(t *testing.T) {
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
})
|
|
|
|
info := map[string]interface{}{
|
|
"name": "Daniel",
|
|
"avatar": "https://example.com/avatar.jpg",
|
|
}
|
|
|
|
token, err := svc.GenerateTokenWithInfo("user-123", info)
|
|
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, token)
|
|
}
|
|
|
|
func TestService_IsUserOnline_WithoutRedis(t *testing.T) {
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: nil,
|
|
})
|
|
|
|
_, err := svc.IsUserOnline(context.Background(), "user-123")
|
|
|
|
assert.Error(t, err)
|
|
assert.ErrorIs(t, err, ErrOnlineStoreNotConfigured)
|
|
}
|
|
|
|
func TestService_GetUsersOnlineStatus_WithoutRedis(t *testing.T) {
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: nil,
|
|
})
|
|
|
|
_, err := svc.GetUsersOnlineStatus(context.Background(), []string{"user-1", "user-2"})
|
|
|
|
assert.Error(t, err)
|
|
assert.ErrorIs(t, err, ErrOnlineStoreNotConfigured)
|
|
}
|
|
|
|
func TestService_IsUserOnline_WithRedis(t *testing.T) {
|
|
rds, cleanup := setupServiceTestRedis(t)
|
|
defer cleanup()
|
|
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: rds,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
userID := "user-123"
|
|
|
|
// 初始狀態應該是離線
|
|
online, err := svc.IsUserOnline(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.False(t, online)
|
|
|
|
// 處理連線事件
|
|
err = svc.Online().HandleConnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
|
|
// 現在應該在線
|
|
online, err = svc.IsUserOnline(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.True(t, online)
|
|
|
|
// 處理斷線事件
|
|
err = svc.Online().HandleDisconnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
|
|
// 現在應該離線
|
|
online, err = svc.IsUserOnline(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.False(t, online)
|
|
}
|
|
|
|
func TestService_GetUsersOnlineStatus_WithRedis(t *testing.T) {
|
|
rds, cleanup := setupServiceTestRedis(t)
|
|
defer cleanup()
|
|
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: rds,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
|
|
// 設置一些用戶在線
|
|
err := svc.Online().HandleConnect(ctx, "user-1")
|
|
require.NoError(t, err)
|
|
err = svc.Online().HandleConnect(ctx, "user-3")
|
|
require.NoError(t, err)
|
|
|
|
// 批量獲取在線狀態
|
|
status, err := svc.GetUsersOnlineStatus(ctx, []string{"user-1", "user-2", "user-3"})
|
|
require.NoError(t, err)
|
|
|
|
assert.True(t, status["user-1"])
|
|
assert.False(t, status["user-2"])
|
|
assert.True(t, status["user-3"])
|
|
}
|
|
|
|
func TestService_Blacklist_Integration(t *testing.T) {
|
|
rds, cleanup := setupServiceTestRedis(t)
|
|
defer cleanup()
|
|
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: rds,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
userID := "user-123"
|
|
|
|
// 撤銷用戶所有 Token
|
|
err := svc.Blacklist().RevokeUserTokens(ctx, userID)
|
|
require.NoError(t, err)
|
|
|
|
// 獲取版本
|
|
version, err := svc.Blacklist().GetUserTokenVersion(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.Greater(t, version, int64(0))
|
|
|
|
// 檢查舊版本無效
|
|
valid, err := svc.Blacklist().IsTokenVersionValid(ctx, userID, version-1)
|
|
require.NoError(t, err)
|
|
assert.False(t, valid)
|
|
|
|
// 檢查當前版本有效
|
|
valid, err = svc.Blacklist().IsTokenVersionValid(ctx, userID, version)
|
|
require.NoError(t, err)
|
|
assert.True(t, valid)
|
|
}
|
|
|
|
func TestService_MultipleConnections(t *testing.T) {
|
|
rds, cleanup := setupServiceTestRedis(t)
|
|
defer cleanup()
|
|
|
|
svc := NewService(ServiceConfig{
|
|
APIURL: "http://localhost:8000",
|
|
APIKey: "test-api-key",
|
|
TokenSecret: "test-secret",
|
|
Redis: rds,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
userID := "user-123"
|
|
|
|
// 模擬多個設備連線
|
|
err := svc.Online().HandleConnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
err = svc.Online().HandleConnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
err = svc.Online().HandleConnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
|
|
// 用戶應該在線
|
|
online, err := svc.IsUserOnline(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.True(t, online)
|
|
|
|
// 斷開一個設備
|
|
err = svc.Online().HandleDisconnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
|
|
// 用戶仍然在線(還有 2 個連線)
|
|
online, err = svc.IsUserOnline(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.True(t, online)
|
|
|
|
// 斷開剩餘設備
|
|
err = svc.Online().HandleDisconnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
err = svc.Online().HandleDisconnect(ctx, userID)
|
|
require.NoError(t, err)
|
|
|
|
// 用戶現在離線
|
|
online, err = svc.IsUserOnline(ctx, userID)
|
|
require.NoError(t, err)
|
|
assert.False(t, online)
|
|
}
|