첫 커밋: 로컬 프로젝트 업로드
This commit is contained in:
150
baron-sso/backend/internal/service/redis_service_test.go
Normal file
150
baron-sso/backend/internal/service/redis_service_test.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type redisCommandStub struct {
|
||||
scans map[string][]string
|
||||
stateValue string
|
||||
deleted []string
|
||||
}
|
||||
|
||||
func (h *redisCommandStub) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (h *redisCommandStub) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
|
||||
switch cmd.Name() {
|
||||
case "ping":
|
||||
if status, ok := cmd.(*redis.StatusCmd); ok {
|
||||
status.SetVal("PONG")
|
||||
}
|
||||
case "scan":
|
||||
if scan, ok := cmd.(*redis.ScanCmd); ok {
|
||||
scan.SetVal(h.scans[scanPattern(cmd.Args())], 0)
|
||||
}
|
||||
case "get":
|
||||
if str, ok := cmd.(*redis.StringCmd); ok {
|
||||
if h.stateValue == "" {
|
||||
str.SetErr(redis.Nil)
|
||||
return nil
|
||||
}
|
||||
str.SetVal(h.stateValue)
|
||||
}
|
||||
case "del":
|
||||
args := cmd.Args()
|
||||
keys := make([]string, 0, len(args)-1)
|
||||
for _, arg := range args[1:] {
|
||||
keys = append(keys, arg.(string))
|
||||
}
|
||||
h.deleted = append(h.deleted, keys...)
|
||||
if count, ok := cmd.(*redis.IntCmd); ok {
|
||||
count.SetVal(int64(len(keys)))
|
||||
}
|
||||
}
|
||||
cmd.SetErr(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *redisCommandStub) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (h *redisCommandStub) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanPattern(args []interface{}) string {
|
||||
for index := 0; index < len(args)-1; index++ {
|
||||
value, ok := args[index].(string)
|
||||
if ok && value == "match" {
|
||||
if pattern, ok := args[index+1].(string); ok {
|
||||
return pattern
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func newStubbedRedisService(stub *redisCommandStub) *RedisService {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: "127.0.0.1:1",
|
||||
MaxRetries: -1,
|
||||
})
|
||||
client.AddHook(stub)
|
||||
return &RedisService{Client: client}
|
||||
}
|
||||
|
||||
func TestRedisServiceGetIdentityCacheStatusReadsStateAndCountsCacheKeys(t *testing.T) {
|
||||
now := time.Date(2026, 6, 9, 3, 20, 0, 0, time.UTC)
|
||||
state, err := json.Marshal(identityMirrorStateStore{
|
||||
Status: "ready",
|
||||
LastRefreshedAt: &now,
|
||||
ObservedCount: 42,
|
||||
UpdatedAt: &now,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
stub := &redisCommandStub{
|
||||
stateValue: string(state),
|
||||
scans: map[string][]string{
|
||||
"identity:mirror:*": {"identity:mirror:state", "identity:mirror:user:1"},
|
||||
"identity:index:*": {"identity:index:email:a", "identity:mirror:user:1"},
|
||||
},
|
||||
}
|
||||
service := newStubbedRedisService(stub)
|
||||
|
||||
status, err := service.GetIdentityCacheStatus(context.Background())
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "ready", status.Status)
|
||||
require.True(t, status.RedisReady)
|
||||
require.Equal(t, int64(42), status.ObservedCount)
|
||||
require.Equal(t, int64(3), status.KeyCount)
|
||||
require.Equal(t, &now, status.LastRefreshedAt)
|
||||
require.Equal(t, &now, status.UpdatedAt)
|
||||
}
|
||||
|
||||
func TestRedisServiceFlushIdentityCacheDeletesOnlyIdentityMirrorAndIndexKeys(t *testing.T) {
|
||||
stub := &redisCommandStub{
|
||||
scans: map[string][]string{
|
||||
"identity:mirror:*": {"identity:mirror:state", "identity:mirror:user:1"},
|
||||
"identity:index:*": {"identity:index:email:a", "identity:mirror:user:1"},
|
||||
},
|
||||
}
|
||||
service := newStubbedRedisService(stub)
|
||||
|
||||
result, err := service.FlushIdentityCache(context.Background())
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "success", result.Status)
|
||||
require.Equal(t, int64(3), result.FlushedKeys)
|
||||
require.ElementsMatch(t, []string{
|
||||
"identity:mirror:state",
|
||||
"identity:mirror:user:1",
|
||||
"identity:index:email:a",
|
||||
}, stub.deleted)
|
||||
}
|
||||
|
||||
func TestRedisServiceGetIdentityCacheStatusReturnsUnavailableWithoutClient(t *testing.T) {
|
||||
status, err := (*RedisService)(nil).GetIdentityCacheStatus(context.Background())
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "unavailable", status.Status)
|
||||
require.False(t, status.RedisReady)
|
||||
require.NotEmpty(t, status.LastError)
|
||||
}
|
||||
|
||||
func TestRedisServiceFlushIdentityCacheFailsWithoutClient(t *testing.T) {
|
||||
_, err := (*RedisService)(nil).FlushIdentityCache(context.Background())
|
||||
|
||||
require.ErrorIs(t, err, os.ErrInvalid)
|
||||
}
|
||||
Reference in New Issue
Block a user