mirror of
https://github.com/redis/go-redis.git
synced 2026-10-22 19:49:00 +03:00
* fix(cmd): don't modify the caller's geo queries geoLocationArgs incremented withLen on the GeoRadiusQuery that the caller passed, and GeoLocationCmd read it back to parse the reply. A second GeoRadius call with the same query parsed the reply with a doubled withLen and failed with "got 2 elements in the array, wanted 3", and sharing one query between goroutines was a data race. Count the WITH flags when the reply is read, as GeoSearchLocationCmd does, and drop the withLen field. geoSearchArgs also wrote the default "km" unit back to the GeoSearchQuery. Keep the default in a local variable instead. * fix(cmd): copy the geo query into the command GeoLocationCmd and GeoSearchLocationCmd kept the caller's query and read its WITH flags when the reply arrived. With a pipeline or autopipelining, a change to the query between queuing and reading parsed the reply with flags that weren't sent. Keep a copy of the query in the command, so the reply is parsed with the flags of the command, and make Clone a plain copy.
49 lines
1.6 KiB
Go
49 lines
1.6 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/redis/go-redis/v9/internal/proto"
|
|
)
|
|
|
|
// A pipelined or autopipelined command is built when it is queued and its
|
|
// reply is read later. Changing the caller's query in between must not change
|
|
// how the reply is parsed.
|
|
func TestGeoCmdsParseReplyWithQueuedFlags(t *testing.T) {
|
|
// Two entries, each [name, dist]: the reply to a WITHDIST query.
|
|
const withDistReply = "*2\r\n" +
|
|
"*2\r\n$7\r\nCatania\r\n$7\r\n56.4413\r\n" +
|
|
"*2\r\n$7\r\nPalermo\r\n$8\r\n190.4424\r\n"
|
|
|
|
t.Run("GeoLocationCmd", func(t *testing.T) {
|
|
q := &GeoRadiusQuery{Radius: 200, Unit: "km", WithDist: true}
|
|
cmd := NewGeoLocationCmd(context.Background(), q, "georadius", "Sicily", 15, 37)
|
|
q.WithDist, q.WithCoord = false, true
|
|
|
|
if err := cmd.readReply(proto.NewReader(strings.NewReader(withDistReply))); err != nil {
|
|
t.Fatalf("readReply: %v", err)
|
|
}
|
|
if got := cmd.Val(); len(got) != 2 || got[0].Dist != 56.4413 || got[1].Dist != 190.4424 {
|
|
t.Fatalf("got %+v", got)
|
|
}
|
|
})
|
|
|
|
t.Run("GeoSearchLocationCmd", func(t *testing.T) {
|
|
q := &GeoSearchLocationQuery{
|
|
GeoSearchQuery: GeoSearchQuery{Member: "Catania", Radius: 200},
|
|
WithDist: true,
|
|
}
|
|
cmd := NewGeoSearchLocationCmd(context.Background(), q, "geosearch", "Sicily")
|
|
q.WithDist, q.WithCoord = false, true
|
|
|
|
if err := cmd.readReply(proto.NewReader(strings.NewReader(withDistReply))); err != nil {
|
|
t.Fatalf("readReply: %v", err)
|
|
}
|
|
if got := cmd.Val(); len(got) != 2 || got[0].Dist != 56.4413 || got[1].Dist != 190.4424 {
|
|
t.Fatalf("got %+v", got)
|
|
}
|
|
})
|
|
}
|