Files
go-redis/bless_commands_unit_test.go
Vladislav Kotsev e4a198a8c7 feat(cmd): bless (#4041)
* feat: add bless commands

* fix: use int64 for count

* fix: keylessnes, docs, tests
2026-10-07 12:33:09 +03:00

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`)
}
}