mirror of
https://github.com/redis/go-redis.git
synced 2026-10-28 08:24:54 +08:00
* feat: add bless commands * fix: use int64 for count * fix: keylessnes, docs, tests
126 lines
3.5 KiB
Go
126 lines
3.5 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
// These tests assert the argument lists and key-position hints built by the
|
|
// BLESS commands without dispatching them to a server, since a test Redis
|
|
// instance is not guaranteed to support the BLESS command family.
|
|
|
|
func TestBlessSet_Args(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
var captured Cmder
|
|
c := captureCmdable(&captured)
|
|
c.BlessSet(ctx, "key1", BlessNoEvict)
|
|
|
|
want := []any{"bless", "set", "key1", "NO-EVICT"}
|
|
if !reflect.DeepEqual(captured.Args(), want) {
|
|
t.Errorf("args = %#v, want %#v", captured.Args(), want)
|
|
}
|
|
if pos := captured.firstKeyPos(); pos != 2 {
|
|
t.Errorf("firstKeyPos = %d, want 2", pos)
|
|
}
|
|
}
|
|
|
|
func TestBlessGet_Args(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
var captured Cmder
|
|
c := captureCmdable(&captured)
|
|
c.BlessGet(ctx, "key1")
|
|
|
|
want := []any{"bless", "get", "key1"}
|
|
if !reflect.DeepEqual(captured.Args(), want) {
|
|
t.Errorf("args = %#v, want %#v", captured.Args(), want)
|
|
}
|
|
if pos := captured.firstKeyPos(); pos != 2 {
|
|
t.Errorf("firstKeyPos = %d, want 2", pos)
|
|
}
|
|
}
|
|
|
|
func TestBlessClear_Args(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
var captured Cmder
|
|
c := captureCmdable(&captured)
|
|
c.BlessClear(ctx, "key1", BlessNoEvict)
|
|
|
|
want := []any{"bless", "clear", "key1", "NO-EVICT"}
|
|
if !reflect.DeepEqual(captured.Args(), want) {
|
|
t.Errorf("args = %#v, want %#v", captured.Args(), want)
|
|
}
|
|
if pos := captured.firstKeyPos(); pos != 2 {
|
|
t.Errorf("firstKeyPos = %d, want 2", pos)
|
|
}
|
|
}
|
|
|
|
func TestBlessScan_Args(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cursor uint64
|
|
count int64
|
|
want []any
|
|
}{
|
|
{
|
|
name: "count_omitted",
|
|
cursor: 0,
|
|
count: 0,
|
|
want: []any{"bless", "scan", uint64(0), "NO-EVICT"},
|
|
},
|
|
{
|
|
name: "with_count",
|
|
cursor: 10,
|
|
count: 100,
|
|
want: []any{"bless", "scan", uint64(10), "NO-EVICT", "count", int64(100)},
|
|
},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var captured Cmder
|
|
c := captureCmdable(&captured)
|
|
c.BlessScan(ctx, tt.cursor, BlessNoEvict, tt.count)
|
|
|
|
if !reflect.DeepEqual(captured.Args(), tt.want) {
|
|
t.Errorf("args = %#v, want %#v", captured.Args(), tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Only BLESS SCAN is keyless; BLESS SET/GET/CLEAR carry the key at position 2.
|
|
// Raw Do("bless", ...) calls have no SetFirstKeyPos hint, so the fallback in
|
|
// cmdFirstKeyPosWithInfo must distinguish the subcommand. Otherwise a Ring
|
|
// would route key-bearing BLESS calls to a random shard.
|
|
func TestBlessFirstKeyPos_RawDo(t *testing.T) {
|
|
ctx := context.Background()
|
|
tests := []struct {
|
|
name string
|
|
args []any
|
|
want int
|
|
}{
|
|
{name: "scan_keyless", args: []any{"bless", "scan", 0, "NO-EVICT"}, want: 0},
|
|
{name: "scan_uppercase", args: []any{"BLESS", "SCAN", 0, "NO-EVICT"}, want: 0},
|
|
{name: "set", args: []any{"bless", "set", "key1", "NO-EVICT"}, want: 2},
|
|
{name: "get", args: []any{"bless", "get", "key1"}, want: 2},
|
|
{name: "clear", args: []any{"bless", "clear", "key1", "NO-EVICT"}, want: 2},
|
|
{name: "set_uppercase", args: []any{"BLESS", "SET", "key1", "NO-EVICT"}, want: 2},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cmd := NewCmd(ctx, tt.args...)
|
|
if got := cmdFirstKeyPosWithInfo(cmd, nil); got != tt.want {
|
|
t.Errorf("cmdFirstKeyPosWithInfo(%v) = %d, want %d", tt.args, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
if _, ok := keylessCommands["bless"]; ok {
|
|
t.Error(`keylessCommands["bless"] present: raw BLESS SET/GET/CLEAR would route to a random shard`)
|
|
}
|
|
}
|