Files
go-redis/search_aliaslist_unit_test.go
Nedyalko Dyakovandofekshenawa 279615082b feat(search): add FT.ALIASLIST support (#3925)
* feat(search): add FT.ALIASLIST support (Redis 8.10)

- FTAliasList(ctx, index) returns the aliases of an index as an
  unordered, server-deduplicated collection; an alias-free index
  yields an empty result, not an error
- server errors (SEARCH_INDEX_NOT_FOUND, NOPERM) propagate unchanged;
  the argument must be an index name, aliases are not resolved
- wire-format unit test plus a RESP2/RESP3 integration test that gates
  on the live server supporting the command (the REDIS_VERSION float
  cannot tell 8.10 from 8.1)
- runnable example under example/ft-aliaslist

* fix(search): route FT.ALIASLIST as keyless in cluster

The static FT policy table covers aliasadd/aliasupdate/aliasdel but
not aliaslist, so the default cluster resolver returned nil and a cold
command-info cache fell back to treating the index name as a key.
Register it keyless and read-only like the other alias commands.

* test(search): version-gate FT.ALIASLIST specs

Replace the standalone probe test (unknown-command sniffing plus the
REDIS_ALIASLIST_TEST_ADDR env var) with Ginkgo specs in the main suite,
gated on SkipBeforeRedisVersion("8.10"), which compares major.minor as
integers and so distinguishes 8.10 from 8.1. The specs cover RESP2 and
RESP3 and follow the suite conventions (FlushDB per spec, :6379).

* chore(deps): bump grpc to v1.82.1 in otel examples

govulncheck fails every PR on GO-2026-6061 in google.golang.org/grpc
v1.80.0 (indirect via the OTLP exporters); v1.82.1 carries the fix.

* fix(search): route policy-table keyless commands on cold cache

ClusterClient.process computes the slot before routeAndRun consults
the policy table, and with a cold command-info cache
cmdFirstKeyPosWithInfo fell back to treating argument 1 as a key — so
FT.ALIASLIST (and the other keyless FT commands) hashed the index name
into a slot for the first calls of a process. Consult the static
policy table there: entries with default request routing and a keyless
response policy resolve to keyless. Key-carrying (ft.suglen) and
specially-routed (ft.cursor) commands keep the old fallback.

---------

Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2026-07-28 19:14:28 +03:00

45 lines
1.0 KiB
Go

package redis
import (
"context"
"reflect"
"testing"
)
// TestFTAliasListArgs pins the wire format of FT.ALIASLIST: exactly one
// argument, the index name, with no optional arguments.
func TestFTAliasListArgs(t *testing.T) {
ctx := context.Background()
tests := []struct {
name string
call func(c cmdable) Cmder
want []interface{}
}{
{
name: "index_only",
call: func(c cmdable) Cmder { return c.FTAliasList(ctx, "idx") },
want: []interface{}{"FT.ALIASLIST", "idx"},
},
{
name: "index_passed_verbatim",
call: func(c cmdable) Cmder { return c.FTAliasList(ctx, "My-Index:v2") },
want: []interface{}{"FT.ALIASLIST", "My-Index:v2"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var captured Cmder
c := captureCmdable(&captured)
cmd := tt.call(c)
if cmd == nil {
t.Fatalf("command builder returned nil")
}
if !reflect.DeepEqual(cmd.Args(), tt.want) {
t.Errorf("args mismatch\n got: %#v\nwant: %#v", cmd.Args(), tt.want)
}
})
}
}