This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new ef820b5ef fix(list): dst-key's version is 0 in rpoplpush cmd for 
non-existent dst-key (#2985)
ef820b5ef is described below

commit ef820b5ef05b6324881d427dc9f8ade64282742c
Author: weimeng <[email protected]>
AuthorDate: Thu May 22 00:04:02 2025 +0800

    fix(list): dst-key's version is 0 in rpoplpush cmd for non-existent dst-key 
(#2985)
    
    Co-authored-by: weimeng <[email protected]>
---
 src/types/redis_list.cc                  |   2 +-
 tests/gocase/unit/type/list/list_test.go | 107 +++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/src/types/redis_list.cc b/src/types/redis_list.cc
index acef1ed9c..ceb268214 100644
--- a/src/types/redis_list.cc
+++ b/src/types/redis_list.cc
@@ -568,7 +568,7 @@ rocksdb::Status List::lmoveOnTwoLists(engine::Context &ctx, 
const rocksdb::Slice
     return s;
   }
 
-  ListMetadata dst_metadata(false);
+  ListMetadata dst_metadata(true);
   s = GetMetadata(ctx, dst_ns_key, &dst_metadata);
   if (!s.ok() && !s.IsNotFound()) {
     return s;
diff --git a/tests/gocase/unit/type/list/list_test.go 
b/tests/gocase/unit/type/list/list_test.go
index ff6a40ec6..084547883 100644
--- a/tests/gocase/unit/type/list/list_test.go
+++ b/tests/gocase/unit/type/list/list_test.go
@@ -1516,6 +1516,113 @@ func testList(t *testing.T, configs 
util.KvrocksServerConfigs) {
        }
 }
 
+type kMetadataResponse struct {
+       size    int64  `redis:"size"`
+       ktype   string `redis:"type"`
+       flags   int64  `redis:"flags"`
+       expire  int64  `redis:"expire"`
+       version int64  `redis:"version"`
+}
+
+func toInt64(val interface{}) (int64, error) {
+       switch v := val.(type) {
+       case int64:
+               return v, nil
+       case int:
+               return int64(v), nil
+       case float64:
+               return int64(v), nil
+       default:
+               return 0, fmt.Errorf("value is not a number, got %T", val)
+       }
+}
+
+func ExtractKMetadataResponse(result interface{}) (*kMetadataResponse, error) {
+       resultMap, ok := result.(map[interface{}]interface{})
+       if !ok {
+               return nil, fmt.Errorf("expected map[interface{}]interface{}, 
got %T", result)
+       }
+
+       response := &kMetadataResponse{}
+
+       // Convert numeric fields
+       for field, target := range map[string]*int64{
+               "size":    &response.size,
+               "flags":   &response.flags,
+               "expire":  &response.expire,
+               "version": &response.version,
+       } {
+               if val, ok := resultMap[field]; ok {
+                       converted, err := toInt64(val)
+                       if err != nil {
+                               return nil, fmt.Errorf("%s: %v", field, err)
+                       }
+                       *target = converted
+               }
+       }
+
+       // Extract Type field
+       if val, ok := resultMap["type"]; ok {
+               if strVal, ok := val.(string); ok {
+                       response.ktype = strVal
+               } else {
+                       return nil, fmt.Errorf("type is not a string, got %T", 
val)
+               }
+       }
+
+       return response, nil
+}
+
+func TestRPOPLPUSH(t *testing.T) {
+       configOptions := []util.ConfigOptions{
+               {
+                       Name:       "resp3-enabled",
+                       Options:    []string{"yes"},
+                       ConfigType: util.YesNo,
+               },
+       }
+
+       configsMatrix, err := util.GenerateConfigsMatrix(configOptions)
+       require.NoError(t, err)
+
+       for _, configs := range configsMatrix {
+               testRpoplpush(t, configs)
+       }
+}
+
+func testRpoplpush(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()) }()
+
+       createList := func(key string, entries ...interface{}) {
+               require.NoError(t, rdb.Del(ctx, key).Err())
+               for _, entry := range entries {
+                       require.NoError(t, rdb.RPush(ctx, key, entry).Err())
+               }
+       }
+
+       t.Run("RPOPLPUSH against non existing dst key", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "srclist", "dstlist").Err())
+               createList("srclist", []string{"a", "b", "c", "d"})
+               require.Equal(t, "d", rdb.RPopLPush(ctx, "srclist", 
"dstlist").Val())
+
+               result, err := rdb.Do(ctx, "kmetadata", "dstlist").Result()
+               if err != nil {
+                       t.Fatalf("Command failed: %v", err)
+               }
+               metaResponse, err := ExtractKMetadataResponse(result)
+               if err != nil {
+                       t.Fatalf("Failed to extract response: %v", err)
+               }
+               require.Equal(t, "list", metaResponse.ktype)
+               require.NotEqual(t, int64(0), metaResponse.version)
+       })
+
+}
+
 // TestPotentialDataRaceInBlockingCommand is to test blocking command's 
callback
 // shouldn't have data race with concurrent transaction behavior.
 //

Reply via email to