mapleFU commented on code in PR #2524:
URL: https://github.com/apache/kvrocks/pull/2524#discussion_r1770520260


##########
tests/gocase/unit/cms/cms_test.go:
##########
@@ -0,0 +1,245 @@
+/*
+ * 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 cms
+
+import (
+       "context"
+       "fmt"
+       "strconv"
+       "testing"
+
+       "github.com/apache/kvrocks/tests/gocase/util"
+       "github.com/stretchr/testify/require"
+)
+
+func TestCountMinSketch(t *testing.T) {
+       // Define configuration options if needed.
+       // Adjust or add more configurations as per your CMS requirements.
+       configOptions := []util.ConfigOptions{
+               {
+                       Name:       "txn-context-enabled",
+                       Options:    []string{"yes", "no"},
+                       ConfigType: util.YesNo,
+               },
+               // Add more configuration options here if necessary
+       }
+
+       // Generate all combinations of configurations
+       configsMatrix, err := util.GenerateConfigsMatrix(configOptions)
+       require.NoError(t, err)
+
+       // Iterate over each configuration and run CMS tests
+       for _, configs := range configsMatrix {
+               testCMS(t, configs)
+       }
+}
+
+// testCMS sets up the server with the given configurations and runs CMS tests
+func testCMS(t *testing.T, configs util.KvrocksServerConfigs) {
+       srv := util.StartServer(t, configs)
+       defer srv.Close()
+
+       ctx := context.Background()
+       rdb := srv.NewClient()
+       defer func() { require.NoError(t, rdb.Close()) }()
+
+       // Run individual CMS test cases
+       t.Run("basic add", func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsA").Err())
+
+               res := rdb.Do(ctx, "cms.initbydim", "cmsA", 100, 10)
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               require.Equal(t, []interface{}{"width", int64(100), "depth", 
int64(10), "count", int64(0)}, rdb.Do(ctx, "cms.info", "cmsA").Val())
+
+               res = rdb.Do(ctx, "cms.incrby", "cmsA", "foo", 1)
+               require.NoError(t, res.Err())
+               addCnt, err := res.Result()
+
+               require.NoError(t, err)
+               require.Equal(t, string("OK"), addCnt)
+
+               card, err := rdb.Do(ctx, "cms.query", "cmsA", "foo").Result()
+               require.NoError(t, err)
+               require.Equal(t, []interface{}([]interface{}{"1"}), card, "The 
queried count for 'foo' should be 1")
+       })
+
+       t.Run("cms.initbyprob - Initialization with Probability Parameters", 
func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsB").Err())
+
+               res := rdb.Do(ctx, "cms.initbyprob", "cmsB", "0.001", "0.1")
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               infoRes := rdb.Do(ctx, "cms.info", "cmsB")
+               require.NoError(t, infoRes.Err())
+               infoSlice, ok := infoRes.Val().([]interface{})
+               require.True(t, ok, "Expected cms.info to return a slice")
+
+               infoMap := make(map[string]interface{})
+               for i := 0; i < len(infoSlice); i += 2 {
+                       key, ok1 := infoSlice[i].(string)
+                       value, ok2 := infoSlice[i+1].(int64)
+                       require.True(t, ok1 && ok2, "Expected cms.info keys to 
be strings and values to be int64")
+                       infoMap[key] = value
+               }
+
+               require.Equal(t, int64(2000), infoMap["width"])
+               require.Equal(t, int64(4), infoMap["depth"])
+               require.Equal(t, int64(0), infoMap["count"])
+       })
+
+       t.Run("cms.incrby - Basic Increment Operations", func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsA").Err())
+               res := rdb.Do(ctx, "cms.initbydim", "cmsA", "100", "10")
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               elements := map[string]string{"apple": "7", "orange": "15", 
"mango": "3"}
+               for key, count := range elements {
+                       res = rdb.Do(ctx, "cms.incrby", "cmsA", key, count)
+                       require.NoError(t, res.Err())
+                       require.Equal(t, "OK", res.Val())
+               }
+
+               for key, expected := range elements {
+                       res = rdb.Do(ctx, "cms.query", "cmsA", key)
+                       require.NoError(t, res.Err())
+                       countSlice, ok := res.Val().([]interface{})
+                       require.True(t, ok, "Expected cms.query to return a 
slice")
+                       require.Len(t, countSlice, 1, "Expected cms.query to 
return a single count")
+                       count, ok := countSlice[0].(string)
+                       require.True(t, ok, "Expected count to be a string")
+                       require.Equal(t, expected, count, fmt.Sprintf("Count 
for key '%s' mismatch", key))
+               }
+
+               // Verify total count
+               infoRes := rdb.Do(ctx, "cms.info", "cmsA")
+               require.NoError(t, infoRes.Err())
+               infoSlice, ok := infoRes.Val().([]interface{})
+               require.True(t, ok, "Expected cms.info to return a slice")
+
+               // Convert the slice to a map for easier access
+               infoMap := make(map[string]interface{})
+               for i := 0; i < len(infoSlice); i += 2 {
+                       key, ok1 := infoSlice[i].(string)
+                       value, ok2 := infoSlice[i+1].(int64)
+                       require.True(t, ok1 && ok2, "Expected cms.info keys to 
be strings and values to be int64")
+                       infoMap[key] = value
+               }
+
+               total := int64(0)
+               for _, cntStr := range elements {
+                       cnt, err := strconv.ParseInt(cntStr, 10, 64)
+                       require.NoError(t, err, "Failed to parse count string 
to int64")
+                       total += cnt
+               }
+               require.Equal(t, total, infoMap["count"], "Total count 
mismatch")
+       })
+
+       // Increment operation on a non-existent CMS
+       t.Run("cms.incrby - Increment Non-Existent CMS", func(t *testing.T) {
+               res := rdb.Do(ctx, "cms.incrby", "nonexistent_cms", "apple", 
"5")
+               require.Error(t, res.Err())
+       })
+
+       // Query for non-existent element
+       t.Run("cms.query - Query Non-Existent Element", func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsA").Err())
+               res := rdb.Do(ctx, "cms.initbydim", "cmsA", "100", "10")
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               // Query a non-existent element
+               res = rdb.Do(ctx, "cms.query", "cmsA", "nonexistent")
+               require.NoError(t, res.Err())
+               countSlice, ok := res.Val().([]interface{})
+               require.True(t, ok, "Expected cms.query to return a slice")
+               require.Len(t, countSlice, 1, "Expected cms.query to return a 
single count")
+               count, ok := countSlice[0].(string)
+               require.True(t, ok, "Expected count to be a string")
+               require.Equal(t, "0", count, "Non-existent element should 
return count '0'")
+       })
+
+       // Merging CMS structures

Review Comment:
   Can we also merge on unexists key? Includling uninitialized dest or sources



##########
tests/gocase/unit/cms/cms_test.go:
##########
@@ -0,0 +1,245 @@
+/*
+ * 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 cms
+
+import (
+       "context"
+       "fmt"
+       "strconv"
+       "testing"
+
+       "github.com/apache/kvrocks/tests/gocase/util"
+       "github.com/stretchr/testify/require"
+)
+
+func TestCountMinSketch(t *testing.T) {
+       // Define configuration options if needed.
+       // Adjust or add more configurations as per your CMS requirements.
+       configOptions := []util.ConfigOptions{
+               {
+                       Name:       "txn-context-enabled",
+                       Options:    []string{"yes", "no"},
+                       ConfigType: util.YesNo,
+               },
+               // Add more configuration options here if necessary
+       }
+
+       // Generate all combinations of configurations
+       configsMatrix, err := util.GenerateConfigsMatrix(configOptions)
+       require.NoError(t, err)
+
+       // Iterate over each configuration and run CMS tests
+       for _, configs := range configsMatrix {
+               testCMS(t, configs)
+       }
+}
+
+// testCMS sets up the server with the given configurations and runs CMS tests
+func testCMS(t *testing.T, configs util.KvrocksServerConfigs) {
+       srv := util.StartServer(t, configs)
+       defer srv.Close()
+
+       ctx := context.Background()
+       rdb := srv.NewClient()
+       defer func() { require.NoError(t, rdb.Close()) }()
+
+       // Run individual CMS test cases
+       t.Run("basic add", func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsA").Err())
+
+               res := rdb.Do(ctx, "cms.initbydim", "cmsA", 100, 10)
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               require.Equal(t, []interface{}{"width", int64(100), "depth", 
int64(10), "count", int64(0)}, rdb.Do(ctx, "cms.info", "cmsA").Val())
+
+               res = rdb.Do(ctx, "cms.incrby", "cmsA", "foo", 1)
+               require.NoError(t, res.Err())
+               addCnt, err := res.Result()
+
+               require.NoError(t, err)
+               require.Equal(t, string("OK"), addCnt)
+
+               card, err := rdb.Do(ctx, "cms.query", "cmsA", "foo").Result()
+               require.NoError(t, err)
+               require.Equal(t, []interface{}([]interface{}{"1"}), card, "The 
queried count for 'foo' should be 1")
+       })
+
+       t.Run("cms.initbyprob - Initialization with Probability Parameters", 
func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsB").Err())
+
+               res := rdb.Do(ctx, "cms.initbyprob", "cmsB", "0.001", "0.1")
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               infoRes := rdb.Do(ctx, "cms.info", "cmsB")
+               require.NoError(t, infoRes.Err())
+               infoSlice, ok := infoRes.Val().([]interface{})
+               require.True(t, ok, "Expected cms.info to return a slice")
+
+               infoMap := make(map[string]interface{})
+               for i := 0; i < len(infoSlice); i += 2 {
+                       key, ok1 := infoSlice[i].(string)
+                       value, ok2 := infoSlice[i+1].(int64)
+                       require.True(t, ok1 && ok2, "Expected cms.info keys to 
be strings and values to be int64")
+                       infoMap[key] = value
+               }
+
+               require.Equal(t, int64(2000), infoMap["width"])
+               require.Equal(t, int64(4), infoMap["depth"])
+               require.Equal(t, int64(0), infoMap["count"])
+       })
+
+       t.Run("cms.incrby - Basic Increment Operations", func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsA").Err())
+               res := rdb.Do(ctx, "cms.initbydim", "cmsA", "100", "10")
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())
+
+               elements := map[string]string{"apple": "7", "orange": "15", 
"mango": "3"}
+               for key, count := range elements {
+                       res = rdb.Do(ctx, "cms.incrby", "cmsA", key, count)
+                       require.NoError(t, res.Err())
+                       require.Equal(t, "OK", res.Val())
+               }
+
+               for key, expected := range elements {
+                       res = rdb.Do(ctx, "cms.query", "cmsA", key)
+                       require.NoError(t, res.Err())
+                       countSlice, ok := res.Val().([]interface{})
+                       require.True(t, ok, "Expected cms.query to return a 
slice")
+                       require.Len(t, countSlice, 1, "Expected cms.query to 
return a single count")
+                       count, ok := countSlice[0].(string)
+                       require.True(t, ok, "Expected count to be a string")
+                       require.Equal(t, expected, count, fmt.Sprintf("Count 
for key '%s' mismatch", key))
+               }
+
+               // Verify total count
+               infoRes := rdb.Do(ctx, "cms.info", "cmsA")
+               require.NoError(t, infoRes.Err())
+               infoSlice, ok := infoRes.Val().([]interface{})
+               require.True(t, ok, "Expected cms.info to return a slice")
+
+               // Convert the slice to a map for easier access
+               infoMap := make(map[string]interface{})
+               for i := 0; i < len(infoSlice); i += 2 {
+                       key, ok1 := infoSlice[i].(string)
+                       value, ok2 := infoSlice[i+1].(int64)
+                       require.True(t, ok1 && ok2, "Expected cms.info keys to 
be strings and values to be int64")
+                       infoMap[key] = value
+               }
+
+               total := int64(0)
+               for _, cntStr := range elements {
+                       cnt, err := strconv.ParseInt(cntStr, 10, 64)
+                       require.NoError(t, err, "Failed to parse count string 
to int64")
+                       total += cnt
+               }
+               require.Equal(t, total, infoMap["count"], "Total count 
mismatch")
+       })
+
+       // Increment operation on a non-existent CMS
+       t.Run("cms.incrby - Increment Non-Existent CMS", func(t *testing.T) {
+               res := rdb.Do(ctx, "cms.incrby", "nonexistent_cms", "apple", 
"5")
+               require.Error(t, res.Err())
+       })
+
+       // Query for non-existent element
+       t.Run("cms.query - Query Non-Existent Element", func(t *testing.T) {
+               require.NoError(t, rdb.Do(ctx, "DEL", "cmsA").Err())
+               res := rdb.Do(ctx, "cms.initbydim", "cmsA", "100", "10")
+               require.NoError(t, res.Err())
+               require.Equal(t, "OK", res.Val())

Review Comment:
   Can we also query a non-exists key like "cms.incrby - Increment Non-Existent 
CMS"



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to