You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kvrocks.apache.org by ti...@apache.org on 2022/10/17 00:01:41 UTC
[incubator-kvrocks] branch unstable updated: Move TCL test unit/geo to Go case (#998)
This is an automated email from the ASF dual-hosted git repository.
tison pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/incubator-kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 8c370355 Move TCL test unit/geo to Go case (#998)
8c370355 is described below
commit 8c3703557fe842ef2f81c20d91c0ded5dfd927d4
Author: Ruixiang Tan <81...@qq.com>
AuthorDate: Mon Oct 17 08:01:35 2022 +0800
Move TCL test unit/geo to Go case (#998)
---
tests/gocase/unit/geo/geo_test.go | 315 ++++++++++++++++++++++++
tests/tcl/tests/test_helper.tcl | 1 -
tests/tcl/tests/unit/geo.tcl | 487 --------------------------------------
3 files changed, 315 insertions(+), 488 deletions(-)
diff --git a/tests/gocase/unit/geo/geo_test.go b/tests/gocase/unit/geo/geo_test.go
new file mode 100644
index 00000000..9dcfb3c8
--- /dev/null
+++ b/tests/gocase/unit/geo/geo_test.go
@@ -0,0 +1,315 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package geo
+
+import (
+ "context"
+ "math"
+ "math/rand"
+ "reflect"
+ "sort"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/apache/incubator-kvrocks/tests/gocase/util"
+ "github.com/go-redis/redis/v9"
+ "github.com/stretchr/testify/require"
+)
+
+func geoDegrad(deg float64) float64 {
+ return deg * math.Atan(1) * 8 / 360
+}
+
+func geoRandomPoint() (float64, float64) {
+ lon := (-180 + rand.Float64()*360)
+ lat := (-70 + rand.Float64()*140)
+ return lon, lat
+}
+
+func geoDistance(lon1d, lat1d, lon2d, lat2d float64) float64 {
+ lon1r := geoDegrad(lon1d)
+ lat1r := geoDegrad(lat1d)
+ lon2r := geoDegrad(lon2d)
+ lat2r := geoDegrad(lat2d)
+ v := math.Sin((lon2r - lon1r) / 2)
+ u := math.Sin((lat2r - lat1r) / 2)
+ return 2.0 * 6372797.560856 * math.Asin(math.Sqrt(u*u+math.Cos(lat1r)*math.Cos(lat2r)*v*v))
+}
+
+func compareLists(list1, list2 []string) []string {
+ vis := make(map[string]int)
+ var result []string
+ for i := 0; i < len(list1); i++ {
+ j := i
+ for j+1 < len(list1) && list1[j+1] == list1[i] {
+ j++
+ }
+ vis[list1[i]] += 1
+ i = j
+ }
+ for i := 0; i < len(list2); i++ {
+ j := i
+ for j+1 < len(list2) && list2[j+1] == list2[i] {
+ j++
+ }
+ vis[list2[i]] += 1
+ i = j
+ }
+ for _, i := range list1 {
+ if val, ok := vis[i]; ok && val == 1 {
+ result = append(result, i)
+ }
+ }
+ for _, i := range list2 {
+ if val, ok := vis[i]; ok && val == 1 {
+ result = append(result, i)
+ }
+ }
+ return result
+}
+
+func TestGeo(t *testing.T) {
+ srv := util.StartServer(t, map[string]string{})
+ defer srv.Close()
+ ctx := context.Background()
+ rdb := srv.NewClient()
+ defer func() { require.NoError(t, rdb.Close()) }()
+ t.Run("GEOADD create", func(t *testing.T) {
+ require.EqualValues(t, 1, rdb.GeoAdd(ctx, "nyc", &redis.GeoLocation{Name: "lic market", Longitude: -73.9454966, Latitude: 40.747533}).Val())
+ })
+
+ t.Run("GEOADD update", func(t *testing.T) {
+ require.EqualValues(t, 0, rdb.GeoAdd(ctx, "nyc", &redis.GeoLocation{Name: "lic market", Longitude: -73.9454966, Latitude: 40.747533}).Val())
+ })
+
+ t.Run("GEOADD invalid coordinates", func(t *testing.T) {
+ require.ErrorContains(t, rdb.Do(ctx, "geoadd", "nyc", -73.9454966, 40.747533, "lic market", "foo", "bar", "luck market").Err(), "valid")
+ })
+
+ t.Run("GEOADD multi add", func(t *testing.T) {
+ require.EqualValues(t, 6, rdb.GeoAdd(ctx, "nyc", &redis.GeoLocation{Name: "central park n/q/r", Longitude: -73.9733487, Latitude: 40.7648057},
+ &redis.GeoLocation{Name: "union square", Longitude: -73.9903085, Latitude: 40.7362513},
+ &redis.GeoLocation{Name: "wtc one", Longitude: -74.0131604, Latitude: 40.7126674},
+ &redis.GeoLocation{Name: "jfk", Longitude: -73.7858139, Latitude: 40.6428986},
+ &redis.GeoLocation{Name: "q4", Longitude: -73.9375699, Latitude: 40.7498929},
+ &redis.GeoLocation{Name: "4545", Longitude: -73.9564142, Latitude: 40.7480973}).Val())
+ })
+
+ t.Run("Check geoset values", func(t *testing.T) {
+ require.EqualValues(t, []redis.Z([]redis.Z{{Score: 1.79187397205302e+15, Member: "wtc one"}, {Score: 1.791875485187452e+15, Member: "union square"}, {Score: 1.791875761332224e+15, Member: "central park n/q/r"}, {Score: 1.791875796750882e+15, Member: "4545"}, {Score: 1.791875804419201e+15, Member: "lic market"}, {Score: 1.791875830079666e+15, Member: "q4"}, {Score: 1.791895905559723e+15, Member: "jfk"}}), rdb.ZRangeWithScores(ctx, "nyc", 0, -1).Val())
+ })
+
+ t.Run("GEORADIUS simple (sorted)", func(t *testing.T) {
+ require.EqualValues(t, []redis.GeoLocation([]redis.GeoLocation{{Name: "central park n/q/r", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "4545", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "union square", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}}), rdb.GeoRadius(ctx, "nyc", -73.9798091, 40.7598464, &redis.GeoRadiusQuery{Radius: 3, Unit: "km", Sort: "asc"}).Val())
+ })
+
+ t.Run("GEORADIUS with COUNT", func(t *testing.T) {
+ require.EqualValues(t, []redis.GeoLocation([]redis.GeoLocation{{Name: "central park n/q/r", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "4545", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "union square", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}}), rdb.GeoRadius(ctx, "nyc", -73.9798091, 40.7598464, &redis.GeoRadiusQuery{Radius: 10, Unit: "km", Sort: "asc", Count: 3}).Val())
+ })
+
+ t.Run("GEORADIUS HUGE, (redis issue #2767)", func(t *testing.T) {
+ require.NoError(t, rdb.GeoAdd(ctx, "users", &redis.GeoLocation{Name: "user_000000", Longitude: -47.271613776683807, Latitude: -54.534504198047678}).Err())
+ require.EqualValues(t, 1, len(rdb.GeoRadius(ctx, "users", 0, 0, &redis.GeoRadiusQuery{Radius: 50000, Unit: "km", WithCoord: true}).Val()))
+ })
+
+ t.Run("GEORADIUSBYMEMBER simple (sorted)", func(t *testing.T) {
+ require.EqualValues(t, []redis.GeoLocation([]redis.GeoLocation{{Name: "wtc one", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "union square", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "central park n/q/r", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "4545", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}, {Name: "lic market", Longitude: 0, Latitude: 0, Dist: 0, GeoHash: 0}}), rdb.GeoRadiusByMember(ctx, "nyc", "wtc one", &redis.GeoRadiusQuery{Radius: [...]
+ })
+
+ t.Run("GEOHASH is able to return geohash strings", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "test", Longitude: -5.6, Latitude: 42.6}).Err())
+ require.EqualValues(t, []string([]string{"ezs42e44yx0"}), rdb.GeoHash(ctx, "points", "test").Val())
+ })
+
+ t.Run("GEOPOS simple", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "a", Longitude: 10, Latitude: 20}, &redis.GeoLocation{Name: "b", Longitude: 30, Latitude: 40}).Err())
+ cmd := rdb.GeoPos(ctx, "points", "a", "b")
+ require.Less(t, math.Abs(cmd.Val()[0].Longitude-10), 0.001)
+ require.Less(t, math.Abs(cmd.Val()[0].Latitude-20), 0.001)
+ require.Less(t, math.Abs(cmd.Val()[1].Longitude-30), 0.001)
+ require.Less(t, math.Abs(cmd.Val()[1].Latitude-40), 0.001)
+ })
+
+ t.Run("GEOPOS missing element", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "a", Longitude: 10, Latitude: 20}, &redis.GeoLocation{Name: "b", Longitude: 30, Latitude: 40}).Err())
+ require.Nil(t, rdb.GeoPos(ctx, "points", "a", "x", "b").Val()[1])
+ })
+
+ t.Run("GEODIST simple & unit", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "Palermo", Longitude: 13.361389, Latitude: 38.115556}, &redis.GeoLocation{Name: "Catania", Longitude: 15.087269, Latitude: 37.502669}).Err())
+ posVal := rdb.GeoDist(ctx, "points", "Palermo", "Catania", "m").Val()
+ require.Greater(t, posVal, 166274.0)
+ require.Less(t, posVal, 166275.0)
+ distVal := rdb.GeoDist(ctx, "points", "Palermo", "Catania", "km").Val()
+ require.Greater(t, distVal, 166.2)
+ require.Less(t, distVal, 166.3)
+ })
+
+ t.Run("GEODIST missing elements", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "Palermo", Longitude: 13.361389, Latitude: 38.115556}, &redis.GeoLocation{Name: "Catania", Longitude: 15.087269, Latitude: 37.502669}).Err())
+ require.EqualValues(t, 0, rdb.GeoDist(ctx, "points", "Palermo", "Agrigento", "").Val())
+ require.EqualValues(t, 0, rdb.GeoDist(ctx, "points", "Ragusa", "Agrigento", "").Val())
+ require.EqualValues(t, 0, rdb.GeoDist(ctx, "empty_key", "Palermo", "Catania", "").Val())
+ })
+
+ t.Run("GEORADIUS STORE option: syntax error", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "Palermo", Longitude: 13.361389, Latitude: 38.115556}, &redis.GeoLocation{Name: "Catania", Longitude: 15.087269, Latitude: 37.502669}).Err())
+ require.ErrorContains(t, rdb.Do(ctx, "georadius", "points", 13.361389, 38.115556, 50, "km", "store").Err(), "syntax")
+ })
+
+ t.Run("GEORADIUS missing key", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.EqualValues(t, []redis.GeoLocation([]redis.GeoLocation{}), rdb.GeoRadius(ctx, "points", 13.361389, 38.115556, &redis.GeoRadiusQuery{Radius: 50, Unit: "km"}).Val())
+ })
+
+ t.Run("GEORANGE STORE option: plain usage", func(t *testing.T) {
+ require.NoError(t, rdb.Del(ctx, "points").Err())
+ require.NoError(t, rdb.GeoAdd(ctx, "points", &redis.GeoLocation{Name: "Palermo", Longitude: 13.361389, Latitude: 38.115556}, &redis.GeoLocation{Name: "Catania", Longitude: 15.087269, Latitude: 37.502669}).Err())
+ rdb.GeoRadiusStore(ctx, "points", 13.361389, 38.115556, &redis.GeoRadiusQuery{Radius: 500, Unit: "km", Store: "points2"})
+ require.EqualValues(t, rdb.ZRange(ctx, "points", 0, -1).Val(), rdb.ZRange(ctx, "points2", 0, -1).Val())
+ })
+
+ type item struct {
+ seed int64
+ km int64
+ lon float64
+ lat float64
+ }
+ regressionVectors := []item{
+ {1482225976969, 7083, 81.634948934258375, 30.561509253718668},
+ {1482340074151, 5416, -70.863281847379767, -46.347003465679947},
+ {1499014685896, 6064, -89.818768962202014, -40.463868561416803},
+ {1412, 156, 149.29737817929004, 15.95807862745508},
+ {441574, 143, 59.235461856813856, 66.269555127373678},
+ {160645, 187, -101.88575239939883, 49.061997951502917},
+ {750269, 154, -90.187939661642517, 66.615930412251487},
+ {342880, 145, 163.03472387745728, 64.012747720821181},
+ {729955, 143, 137.86663517256579, 63.986745399416776},
+ {939895, 151, 59.149620271823181, 65.204186651485145},
+ {1412, 156, 149.29737817929004, 15.95807862745508},
+ {564862, 149, 84.062063109158544, -65.685403922426232},
+ {1546032440391, 16751, -1.8175081637769495, 20.665668878082954},
+ }
+
+ t.Run("GEOADD + GEORANGE randomized test", func(t *testing.T) {
+ for attempt := 0; attempt < 30; attempt++ {
+ var debuginfo string
+ if attempt < len(regressionVectors) {
+ rand.Seed(regressionVectors[attempt].seed)
+ debuginfo += "rand seed is " + strconv.FormatInt(regressionVectors[attempt].seed, 10)
+ } else {
+ tmp := time.Now().UnixNano()
+ rand.Seed(tmp)
+ debuginfo += "rand seed is " + strconv.FormatInt(tmp, 10)
+ }
+ require.NoError(t, rdb.Del(ctx, "mypoints").Err())
+ var radiusKm int64
+ if util.RandomInt(10) == 0 {
+ radiusKm = util.RandomInt(50000) + 10
+ } else {
+ radiusKm = util.RandomInt(200) + 10
+ }
+ if attempt < len(regressionVectors) {
+ radiusKm = regressionVectors[attempt].km
+ }
+ radiusM := radiusKm * 1000
+ searchLon, searchLat := geoRandomPoint()
+ if attempt < len(regressionVectors) {
+ searchLon = regressionVectors[attempt].lon
+ searchLat = regressionVectors[attempt].lat
+ }
+ debuginfo += "Search area: " + strconv.FormatFloat(searchLon, 'f', 10, 64) + "," + strconv.FormatFloat(searchLat, 'f', 10, 64) + " " + strconv.FormatInt(radiusKm, 10) + " km"
+ var result []string
+ var argvs []*redis.GeoLocation
+ for j := 0; j < 20000; j++ {
+ lon, lat := geoRandomPoint()
+ argvs = append(argvs, &redis.GeoLocation{Longitude: lon, Latitude: lat, Name: "place:" + strconv.Itoa(j)})
+ distance := geoDistance(lon, lat, searchLon, searchLat)
+ if distance < float64(radiusM) {
+ result = append(result, "place:"+strconv.Itoa(j))
+ }
+ debuginfo += "place:" + strconv.FormatInt(int64(j), 10) + " " + strconv.FormatInt(int64(lon), 10) + " " + strconv.FormatInt(int64(lat), 10) + " " + strconv.FormatInt(int64(distance)/1000, 10) + " km"
+ }
+ require.NoError(t, rdb.GeoAdd(ctx, "mypoints", argvs...).Err())
+ cmd := rdb.GeoRadius(ctx, "mypoints", searchLon, searchLat, &redis.GeoRadiusQuery{Radius: float64(radiusKm), Unit: "km"})
+ sort.Strings(result)
+ var res []string
+ for _, i := range cmd.Val() {
+ res = append(res, i.Name)
+ }
+ sort.Strings(res)
+ equal := reflect.DeepEqual(res, result)
+ testResult := true
+ if !equal {
+ roundingErrors := 0
+ diff := compareLists(res, result)
+ for _, i := range diff {
+ cmd := rdb.GeoPos(ctx, "mypoints", i)
+ mydist := geoDistance(cmd.Val()[0].Longitude, cmd.Val()[0].Latitude, searchLon, searchLat) / 1000
+ if mydist/float64(radiusKm) > 0.999 {
+ roundingErrors += 1
+ continue
+ }
+ if mydist < float64(radiusM) {
+ roundingErrors += 1
+ continue
+ }
+ }
+ if len(diff) == roundingErrors {
+ equal = true
+ }
+ }
+ if !equal {
+ diff := compareLists(res, result)
+ t.Log("Redis: ", res)
+ t.Log("Gotest: ", result)
+ t.Log("Diff: ", diff)
+ t.Log("debuginfo: ", debuginfo)
+ vis := make(map[string]int)
+ for _, i := range result {
+ vis[i] += 1
+ }
+ for _, i := range diff {
+ var where string
+ if _, ok := vis[i]; ok {
+ where = "(only in Go test)"
+ } else {
+ where = "(only in Kvrocks)"
+ }
+ cmd := rdb.GeoPos(ctx, "mypoints", i)
+ require.NoError(t, cmd.Err())
+ mydis := geoDistance(cmd.Val()[0].Longitude, cmd.Val()[0].Latitude, searchLon, searchLat) / 1000
+ t.Logf("%v -> %v %v %v", i, rdb.GeoPos(ctx, "mypoints", i).Val()[0], mydis, where)
+ }
+ testResult = false
+ }
+ if !testResult {
+ require.FailNow(t, "not equal")
+ }
+ }
+ })
+}
diff --git a/tests/tcl/tests/test_helper.tcl b/tests/tcl/tests/test_helper.tcl
index f66cd9d0..3b5c87ab 100644
--- a/tests/tcl/tests/test_helper.tcl
+++ b/tests/tcl/tests/test_helper.tcl
@@ -35,7 +35,6 @@ source tests/support/util.tcl
set ::all_tests {
unit/type/list
unit/type/stream
- unit/geo
integration/slotmigrate
}
diff --git a/tests/tcl/tests/unit/geo.tcl b/tests/tcl/tests/unit/geo.tcl
deleted file mode 100644
index 3eedc0d9..00000000
--- a/tests/tcl/tests/unit/geo.tcl
+++ /dev/null
@@ -1,487 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-# Copyright (c) 2006-2020, Salvatore Sanfilippo
-# See bundled license file licenses/LICENSE.redis for details.
-
-# This file is copied and modified from the Redis project,
-# which started out as: https://github.com/redis/redis/blob/dbcc0a8/tests/unit/geo.tcl
-
-# Helper functions to simulate search-in-radius in the Tcl side in order to
-# verify the Redis implementation with a fuzzy test.
-proc geo_degrad deg {expr {$deg*atan(1)*8/360}}
-
-proc geo_distance {lon1d lat1d lon2d lat2d} {
- set lon1r [geo_degrad $lon1d]
- set lat1r [geo_degrad $lat1d]
- set lon2r [geo_degrad $lon2d]
- set lat2r [geo_degrad $lat2d]
- set v [expr {sin(($lon2r - $lon1r) / 2)}]
- set u [expr {sin(($lat2r - $lat1r) / 2)}]
- expr {2.0 * 6372797.560856 * \
- asin(sqrt($u * $u + cos($lat1r) * cos($lat2r) * $v * $v))}
-}
-
-proc geo_random_point {lonvar latvar} {
- upvar 1 $lonvar lon
- upvar 1 $latvar lat
- # Note that the actual latitude limit should be -85 to +85, we restrict
- # the test to -70 to +70 since in this range the algorithm is more precise
- # while outside this range occasionally some element may be missing.
- set lon [expr {-180 + rand()*360}]
- set lat [expr {-70 + rand()*140}]
-}
-
-# Return elements non common to both the lists.
-# This code is from http://wiki.tcl.tk/15489
-proc compare_lists {List1 List2} {
- set DiffList {}
- foreach Item $List1 {
- if {[lsearch -exact $List2 $Item] == -1} {
- lappend DiffList $Item
- }
- }
- foreach Item $List2 {
- if {[lsearch -exact $List1 $Item] == -1} {
- if {[lsearch -exact $DiffList $Item] == -1} {
- lappend DiffList $Item
- }
- }
- }
- return $DiffList
-}
-
-# The following list represents sets of random seed, search position
-# and radius that caused bugs in the past. It is used by the randomized
-# test later as a starting point. When the regression vectors are scanned
-# the code reverts to using random data.
-#
-# The format is: seed km lon lat
-set regression_vectors {
- {1482225976969 7083 81.634948934258375 30.561509253718668}
- {1482340074151 5416 -70.863281847379767 -46.347003465679947}
- {1499014685896 6064 -89.818768962202014 -40.463868561416803}
- {1412 156 149.29737817929004 15.95807862745508}
- {441574 143 59.235461856813856 66.269555127373678}
- {160645 187 -101.88575239939883 49.061997951502917}
- {750269 154 -90.187939661642517 66.615930412251487}
- {342880 145 163.03472387745728 64.012747720821181}
- {729955 143 137.86663517256579 63.986745399416776}
- {939895 151 59.149620271823181 65.204186651485145}
- {1412 156 149.29737817929004 15.95807862745508}
- {564862 149 84.062063109158544 -65.685403922426232}
- {1546032440391 16751 -1.8175081637769495 20.665668878082954}
-}
-set rv_idx 0
-
-start_server {tags {"geo"}} {
- test {GEOADD create} {
- r geoadd nyc -73.9454966 40.747533 "lic market"
- } {1}
-
- test {GEOADD update} {
- r geoadd nyc -73.9454966 40.747533 "lic market"
- } {0}
-
- # test {GEOADD update with CH option} {
- # assert_equal 1 [r geoadd nyc CH 40.747533 -73.9454966 "lic market"]
- # lassign [lindex [r geopos nyc "lic market"] 0] x1 y1
- # assert {abs($x1) - 40.747 < 0.001}
- # assert {abs($y1) - 73.945 < 0.001}
- # } {}
-
- # test {GEOADD update with NX option} {
- # assert_equal 0 [r geoadd nyc NX -73.9454966 40.747533 "lic market"]
- # lassign [lindex [r geopos nyc "lic market"] 0] x1 y1
- # assert {abs($x1) - 40.747 < 0.001}
- # assert {abs($y1) - 73.945 < 0.001}
- # } {}
-
- # test {GEOADD update with XX option} {
- # assert_equal 0 [r geoadd nyc XX -83.9454966 40.747533 "lic market"]
- # lassign [lindex [r geopos nyc "lic market"] 0] x1 y1
- # assert {abs($x1) - 83.945 < 0.001}
- # assert {abs($y1) - 40.747 < 0.001}
- # } {}
-
- # test {GEOADD update with CH NX option} {
- # r geoadd nyc CH NX -73.9454966 40.747533 "lic market"
- # } {0}
-
- # test {GEOADD update with CH XX option} {
- # r geoadd nyc CH XX -73.9454966 40.747533 "lic market"
- # } {1}
-
- # test {GEOADD update with XX NX option will return syntax error} {
- # catch {
- # r geoadd nyc xx nx -73.9454966 40.747533 "lic market"
- # } err
- # set err
- # } {ERR*syntax*}
-
- # test {GEOADD update with invalid option} {
- # catch {
- # r geoadd nyc ch xx foo -73.9454966 40.747533 "lic market"
- # } err
- # set err
- # } {ERR*syntax*}
-
- test {GEOADD invalid coordinates} {
- catch {
- r geoadd nyc -73.9454966 40.747533 "lic market" \
- foo bar "luck market"
- } err
- set err
- } {*valid*}
-
- test {GEOADD multi add} {
- r geoadd nyc -73.9733487 40.7648057 "central park n/q/r" -73.9903085 40.7362513 "union square" -74.0131604 40.7126674 "wtc one" -73.7858139 40.6428986 "jfk" -73.9375699 40.7498929 "q4" -73.9564142 40.7480973 4545
- } {6}
-
- test {Check geoset values} {
- r zrange nyc 0 -1 withscores
- } {{wtc one} 1791873972053020 {union square} 1791875485187452 {central park n/q/r} 1791875761332224 4545 1791875796750882 {lic market} 1791875804419201 q4 1791875830079666 jfk 1791895905559723}
-
- test {GEORADIUS simple (sorted)} {
- r georadius nyc -73.9798091 40.7598464 3 km asc
- } {{central park n/q/r} 4545 {union square}}
-
- # test {GEOSEARCH simple (sorted)} {
- # r geosearch nyc fromlonlat -73.9798091 40.7598464 bybox 6 6 km asc
- # } {{central park n/q/r} 4545 {union square} {lic market}}
-
- # test {GEOSEARCH FROMLONLAT and FROMMEMBER cannot exist at the same time} {
- # catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 frommember xxx bybox 6 6 km asc} e
- # set e
- # } {ERR*syntax*}
-
- # test {GEOSEARCH FROMLONLAT and FROMMEMBER one must exist} {
- # catch {r geosearch nyc bybox 3 3 km asc desc withhash withdist withcoord} e
- # set e
- # } {ERR*exactly one of FROMMEMBER or FROMLONLAT*}
-
- # test {GEOSEARCH BYRADIUS and BYBOX cannot exist at the same time} {
- # catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 byradius 3 km bybox 3 3 km asc} e
- # set e
- # } {ERR*syntax*}
-
- # test {GEOSEARCH BYRADIUS and BYBOX one must exist} {
- # catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 asc desc withhash withdist withcoord} e
- # set e
- # } {ERR*exactly one of BYRADIUS and BYBOX*}
-
- # test {GEOSEARCH with STOREDIST option} {
- # catch {r geosearch nyc fromlonlat -73.9798091 40.7598464 bybox 6 6 km asc storedist} e
- # set e
- # } {ERR*syntax*}
-
- # test {GEORADIUS withdist (sorted)} {
- # r georadius nyc -73.9798091 40.7598464 3 km withdist asc
- # } {{{central park n/q/r} 0.7750} {4545 2.3651} {{union square} 2.7697}}
-
- # test {GEOSEARCH withdist (sorted)} {
- # r geosearch nyc fromlonlat -73.9798091 40.7598464 bybox 6 6 km withdist asc
- # } {{{central park n/q/r} 0.7750} {4545 2.3651} {{union square} 2.7697} {{lic market} 3.1991}}
-
- test {GEORADIUS with COUNT} {
- r georadius nyc -73.9798091 40.7598464 10 km COUNT 3
- } {{central park n/q/r} 4545 {union square}}
-
- # test {GEORADIUS with ANY not sorted by default} {
- # r georadius nyc -73.9798091 40.7598464 10 km COUNT 3 ANY
- # } {{wtc one} {union square} {central park n/q/r}}
-
- # test {GEORADIUS with ANY sorted by ASC} {
- # r georadius nyc -73.9798091 40.7598464 10 km COUNT 3 ANY ASC
- # } {{central park n/q/r} {union square} {wtc one}}
-
- # test {GEORADIUS with ANY but no COUNT} {
- # catch {r georadius nyc -73.9798091 40.7598464 10 km ANY ASC} e
- # set e
- # } {ERR*ANY*requires*COUNT*}
-
- # test {GEORADIUS with COUNT but missing integer argument} {
- # catch {r georadius nyc -73.9798091 40.7598464 10 km COUNT} e
- # set e
- # } {ERR*syntax*}
-
- # test {GEORADIUS with COUNT DESC} {
- # r georadius nyc -73.9798091 40.7598464 10 km COUNT 2 DESC
- # } {{wtc one} q4}
-
- test {GEORADIUS HUGE, issue #2767} {
- r geoadd users -47.271613776683807 -54.534504198047678 user_000000
- llength [r GEORADIUS users 0 0 50000 km WITHCOORD]
- } {1}
-
- test {GEORADIUSBYMEMBER simple (sorted)} {
- r georadiusbymember nyc "wtc one" 7 km
- } {{wtc one} {union square} {central park n/q/r} 4545 {lic market}}
-
- # test {GEOSEARCH FROMMEMBER simple (sorted)} {
- # r geosearch nyc frommember "wtc one" bybox 14 14 km
- # } {{wtc one} {union square} {central park n/q/r} 4545 {lic market} q4}
-
- # test {GEOSEARCH vs GEORADIUS} {
- # r del Sicily
- # r geoadd Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
- # r geoadd Sicily 12.758489 38.788135 "edge1" 17.241510 38.788135 "eage2"
- # set ret1 [r georadius Sicily 15 37 200 km asc]
- # assert_equal $ret1 {Catania Palermo}
- # set ret2 [r geosearch Sicily fromlonlat 15 37 bybox 400 400 km asc]
- # assert_equal $ret2 {Catania Palermo eage2 edge1}
- # }
-
- # test {GEOSEARCH non square, long and narrow} {
- # r del Sicily
- # r geoadd Sicily 12.75 37.00 "test1"
- # r geoadd Sicily 12.75 36.50 "test2"
- # r geoadd Sicily 13.00 36.50 "test3"
- # # box height=2km width=400km
- # set ret1 [r geosearch Sicily fromlonlat 15 37 bybox 2 400 km]
- # assert_equal $ret1 {test1}
-
- # # Add a western Hemisphere point
- # r geoadd Sicily -1 37.00 "test3"
- # set ret2 [r geosearch Sicily fromlonlat 15 37 bybox 2 3000 km asc]
- # assert_equal $ret2 {test1 test3}
- # }
-
- # test {GEORADIUSBYMEMBER withdist (sorted)} {
- # r georadiusbymember nyc "wtc one" 7 km withdist
- # } {{{wtc one} 0.0000} {{union square} 3.2544} {{central park n/q/r} 6.7000} {4545 6.1975} {{lic market} 6.8969}}
-
- test {GEOHASH is able to return geohash strings} {
- # Example from Wikipedia.
- r del points
- r geoadd points -5.6 42.6 test
- lindex [r geohash points test] 0
- } {ezs42e44yx0}
-
- test {GEOPOS simple} {
- r del points
- r geoadd points 10 20 a 30 40 b
- lassign [lindex [r geopos points a b] 0] x1 y1
- lassign [lindex [r geopos points a b] 1] x2 y2
- assert {abs($x1 - 10) < 0.001}
- assert {abs($y1 - 20) < 0.001}
- assert {abs($x2 - 30) < 0.001}
- assert {abs($y2 - 40) < 0.001}
- }
-
- test {GEOPOS missing element} {
- r del points
- r geoadd points 10 20 a 30 40 b
- lindex [r geopos points a x b] 1
- } {}
-
- test {GEODIST simple & unit} {
- r del points
- r geoadd points 13.361389 38.115556 "Palermo" \
- 15.087269 37.502669 "Catania"
- set m [r geodist points Palermo Catania]
- assert {$m > 166274 && $m < 166275}
- set km [r geodist points Palermo Catania km]
- assert {$km > 166.2 && $km < 166.3}
- }
-
- test {GEODIST missing elements} {
- r del points
- r geoadd points 13.361389 38.115556 "Palermo" \
- 15.087269 37.502669 "Catania"
- set m [r geodist points Palermo Agrigento]
- assert {$m eq {}}
- set m [r geodist points Ragusa Agrigento]
- assert {$m eq {}}
- set m [r geodist empty_key Palermo Catania]
- assert {$m eq {}}
- }
-
- test {GEORADIUS STORE option: syntax error} {
- r del points
- r geoadd points 13.361389 38.115556 "Palermo" \
- 15.087269 37.502669 "Catania"
- catch {r georadius points 13.361389 38.115556 50 km store} e
- set e
- } {*syntax*}
-
- test {GEORADIUS missing key} {
- r del points
- assert_equal {} [r georadius points 13.361389 38.115556 50 km]
- }
-
- # test {GEOSEARCHSTORE STORE option: syntax error} {
- # catch {r geosearchstore abc points fromlonlat 13.361389 38.115556 byradius 50 km store abc} e
- # set e
- # } {*syntax*}
-
- # test {GEORANGE STORE option: incompatible options} {
- # r del points
- # r geoadd points 13.361389 38.115556 "Palermo" \
- # 15.087269 37.502669 "Catania"
- # catch {r georadius points 13.361389 38.115556 50 km store points2 withdist} e
- # assert_match {*ERR*} $e
- # catch {r georadius points 13.361389 38.115556 50 km store points2 withhash} e
- # assert_match {*ERR*} $e
- # catch {r georadius points 13.361389 38.115556 50 km store points2 withcoords} e
- # assert_match {*ERR*} $e
- # }
-
- test {GEORANGE STORE option: plain usage} {
- r del points
- r geoadd points 13.361389 38.115556 "Palermo" \
- 15.087269 37.502669 "Catania"
- r georadius points 13.361389 38.115556 500 km store points2
- assert_equal [r zrange points 0 -1] [r zrange points2 0 -1]
- }
-
- # test {GEOSEARCHSTORE STORE option: plain usage} {
- # r geosearchstore points2 points fromlonlat 13.361389 38.115556 byradius 500 km
- # assert_equal [r zrange points 0 -1] [r zrange points2 0 -1]
- # }
-
- # test {GEORANGE STOREDIST option: plain usage} {
- # r del points
- # r geoadd points 13.361389 38.115556 "Palermo" \
- # 15.087269 37.502669 "Catania"
- # r georadius points 13.361389 38.115556 500 km storedist points2
- # set res [r zrange points2 0 -1 withscores]
- # assert {[lindex $res 1] < 1}
- # assert {[lindex $res 3] > 166}
- # assert {[lindex $res 3] < 167}
- # }
-
- # test {GEOSEARCHSTORE STOREDIST option: plain usage} {
- # r geosearchstore points2 points fromlonlat 13.361389 38.115556 byradius 500 km storedist
- # set res [r zrange points2 0 -1 withscores]
- # assert {[lindex $res 1] < 1}
- # assert {[lindex $res 3] > 166}
- # assert {[lindex $res 3] < 167}
- # }
-
- # test {GEORANGE STOREDIST option: COUNT ASC and DESC} {
- # r del points
- # r geoadd points 13.361389 38.115556 "Palermo" \
- # 15.087269 37.502669 "Catania"
- # r georadius points 13.361389 38.115556 500 km storedist points2 asc count 1
- # assert {[r zcard points2] == 1}
- # set res [r zrange points2 0 -1 withscores]
- # assert {[lindex $res 0] eq "Palermo"}
-
- # r georadius points 13.361389 38.115556 500 km storedist points2 desc count 1
- # assert {[r zcard points2] == 1}
- # set res [r zrange points2 0 -1 withscores]
- # assert {[lindex $res 0] eq "Catania"}
- # }
-
- test {GEOADD + GEORANGE randomized test} {
- set attempt 30
- while {[incr attempt -1]} {
- set rv [lindex $regression_vectors $rv_idx]
- incr rv_idx
-
- unset -nocomplain debuginfo
- set srand_seed [clock milliseconds]
- if {$rv ne {}} {set srand_seed [lindex $rv 0]}
- lappend debuginfo "srand_seed is $srand_seed"
- expr {srand($srand_seed)} ; # If you need a reproducible run
- r del mypoints
-
- if {[randomInt 10] == 0} {
- # From time to time use very big radiuses
- set radius_km [expr {[randomInt 50000]+10}]
- } else {
- # Normally use a few - ~200km radiuses to stress
- # test the code the most in edge cases.
- set radius_km [expr {[randomInt 200]+10}]
- }
- if {$rv ne {}} {set radius_km [lindex $rv 1]}
- set radius_m [expr {$radius_km*1000}]
- geo_random_point search_lon search_lat
- if {$rv ne {}} {
- set search_lon [lindex $rv 2]
- set search_lat [lindex $rv 3]
- }
- lappend debuginfo "Search area: $search_lon,$search_lat $radius_km km"
- set tcl_result {}
- set argv {}
- for {set j 0} {$j < 20000} {incr j} {
- geo_random_point lon lat
- lappend argv $lon $lat "place:$j"
- set distance [geo_distance $lon $lat $search_lon $search_lat]
- if {$distance < $radius_m} {
- lappend tcl_result "place:$j"
- }
- lappend debuginfo "place:$j $lon $lat [expr {$distance/1000}] km"
- }
- r geoadd mypoints {*}$argv
- set res [lsort [r georadius mypoints $search_lon $search_lat $radius_km km]]
- set res2 [lsort $tcl_result]
- set test_result OK
-
- if {$res != $res2} {
- set rounding_errors 0
- set diff [compare_lists $res $res2]
- foreach place $diff {
- set mydist [geo_distance $lon $lat $search_lon $search_lat]
- set mydist [expr $mydist/1000]
- if {($mydist / $radius_km) > 0.999} {
- incr rounding_errors
- continue
- }
- if {$mydist < $radius_m} {
- # This is a false positive for redis since given the
- # same points the higher precision calculation provided
- # by TCL shows the point within range
- incr rounding_errors
- continue
- }
- }
-
- # Make sure this is a real error and not a rounidng issue.
- if {[llength $diff] == $rounding_errors} {
- set res $res2; # Error silenced
- }
- }
-
- if {$res != $res2} {
- set diff [compare_lists $res $res2]
- puts "*** Possible problem in GEO radius query ***"
- puts "Redis: $res"
- puts "Tcl : $res2"
- puts "Diff : $diff"
- puts [join $debuginfo "\n"]
- foreach place $diff {
- if {[lsearch -exact $res2 $place] != -1} {
- set where "(only in Tcl)"
- } else {
- set where "(only in Redis)"
- }
- lassign [lindex [r geopos mypoints $place] 0] lon lat
- set mydist [geo_distance $lon $lat $search_lon $search_lat]
- set mydist [expr $mydist/1000]
- puts "$place -> [r geopos mypoints $place] $mydist $where"
- if {($mydist / $radius_km) > 0.999} {incr rounding_errors}
- }
- set test_result FAIL
- }
- unset -nocomplain debuginfo
- if {$test_result ne {OK}} break
- }
- set test_result
- } {OK}
-}