mirror of
https://github.com/hanzokv/go.git
synced 2026-09-24 00:31:51 +00:00
* refactor(TODO-3803): Enhance key position retrieval with CommandInfo caching ultimately solving the TODO * fix(command): Handle nil cache in Peek method to prevent panic * refactor(command): Optimize keyless command handling and improve refresh lock mechanism as requested * Check the keyless command before the switch cases * docs(command): Update Peek method documentation to clarify blocking behavior during initial population * refactor(command): Optimize command slot handling by caching CommandInfo and reducing redundant Peek calls * Update command.go --------- Co-authored-by: Krish Srivastava <[email protected]> Co-authored-by: Nedyalko Dyakov <[email protected]>
77 lines
2.3 KiB
Go
77 lines
2.3 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
// mockCmdable is a mock implementation of cmdable that records the last command.
|
|
// This is used for unit testing command construction without requiring a Redis server.
|
|
type mockCmdable struct {
|
|
lastCmd Cmder
|
|
returnErr error
|
|
}
|
|
|
|
func (m *mockCmdable) call(_ context.Context, cmd Cmder) error {
|
|
m.lastCmd = cmd
|
|
if m.returnErr != nil {
|
|
cmd.SetErr(m.returnErr)
|
|
}
|
|
return m.returnErr
|
|
}
|
|
|
|
func (m *mockCmdable) asCmdable() cmdable {
|
|
return func(ctx context.Context, cmd Cmder) error {
|
|
return m.call(ctx, cmd)
|
|
}
|
|
}
|
|
|
|
// TestCmdFirstKeyPosWithInfo_UsesCommandInfoWhenWarm checks that once the
|
|
// cmdsInfoCache has been populated, cmdFirstKeyPosWithInfo returns
|
|
// CommandInfo.FirstKeyPos rather than the hardcoded fallback of 1.
|
|
// Uses an injected cache fn so no Redis server is required.
|
|
func TestCmdFirstKeyPosWithInfo_UsesCommandInfoWhenWarm(t *testing.T) {
|
|
// "mymodule.cmd" is not in keylessCommands and has no firstKeyPos set,
|
|
// so cold-cache behaviour falls back to the default of 1.
|
|
const name = "mymodule.cmd"
|
|
ctx := context.Background()
|
|
cmd := NewCmd(ctx, name, "arg1")
|
|
|
|
if got := cmdFirstKeyPosWithInfo(cmd, nil); got != 1 {
|
|
t.Fatalf("cold cache: got %d, want 1", got)
|
|
}
|
|
|
|
// With a warm CommandInfo saying FirstKeyPos=0 (e.g. a module keyless command
|
|
// not in our hand-maintained table), the function must return 0.
|
|
info := &CommandInfo{Name: name, FirstKeyPos: 0}
|
|
if got := cmdFirstKeyPosWithInfo(cmd, info); got != 0 {
|
|
t.Fatalf("warm cache FirstKeyPos=0: got %d, want 0", got)
|
|
}
|
|
|
|
info2 := &CommandInfo{Name: name, FirstKeyPos: 2}
|
|
if got := cmdFirstKeyPosWithInfo(cmd, info2); got != 2 {
|
|
t.Fatalf("warm cache FirstKeyPos=2: got %d, want 2", got)
|
|
}
|
|
|
|
// End-to-end: Peek returns nil before Get, the real entry after.
|
|
cache := newCmdsInfoCache(func(_ context.Context) (map[string]*CommandInfo, error) {
|
|
return map[string]*CommandInfo{name: {Name: name, FirstKeyPos: 0}}, nil
|
|
})
|
|
|
|
if cache.Peek() != nil {
|
|
t.Fatal("Peek() must return nil before Get()")
|
|
}
|
|
|
|
if _, err := cache.Get(ctx); err != nil {
|
|
t.Fatalf("cache.Get: %v", err)
|
|
}
|
|
|
|
warmInfo := cache.Peek()[name]
|
|
if warmInfo == nil {
|
|
t.Fatalf("Peek()[%q] is nil after Get()", name)
|
|
}
|
|
if pos := cmdFirstKeyPosWithInfo(cmd, warmInfo); pos != 0 {
|
|
t.Fatalf("post-Get: got %d, want 0", pos)
|
|
}
|
|
}
|