From a20aa56c93d3604f794b752394a318746bfed197 Mon Sep 17 00:00:00 2001 From: ktsivkov Date: Sat, 18 Mar 2023 16:16:14 +0100 Subject: [PATCH 1/6] Added support for MODULE LOADEX command --- commands.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/commands.go b/commands.go index ac93f39c93..1c4828b397 100644 --- a/commands.go +++ b/commands.go @@ -3684,3 +3684,32 @@ func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *Geo _ = c(ctx, cmd) return cmd } + +// LoadexConfig struct is used to specify the arguments for the MODULE LOADEX command of redis. +// `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` +type LoadexConfig struct { + Path string + Conf map[string]interface{} + Args []interface{} +} + +func (c *LoadexConfig) ToArgs() []interface{} { + var args = make([]interface{}, 3, len(c.Conf)*2+len(c.Args)+3) + args[0] = "MODULE" + args[1] = "LOADEX" + args[2] = c.Path + for k, v := range c.Conf { + args = append(args, "CONFIG", k, v) + } + for _, arg := range c.Args { + args = append(args, "ARGS", arg) + } + return args +} + +// Loadex Redis `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` command. +func (c cmdable) Loadex(ctx context.Context, conf *LoadexConfig) *Cmd { + cmd := NewCmd(ctx, conf.ToArgs()...) + _ = c(ctx, cmd) + return cmd +} From efb34255ac8f07d229965ec32f542183743e2c31 Mon Sep 17 00:00:00 2001 From: ktsivkov Date: Mon, 3 Apr 2023 19:36:35 +0200 Subject: [PATCH 2/6] Export the Loadex command through the available interface --- commands.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commands.go b/commands.go index 94a2ffe20f..06867eb790 100644 --- a/commands.go +++ b/commands.go @@ -495,6 +495,8 @@ type Cmdable interface { GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd + + Loadex(ctx context.Context, conf *LoadexConfig) *Cmd } type StatefulCmdable interface { From ba59a1159f87c624ec4979865741e97f64c08f5a Mon Sep 17 00:00:00 2001 From: ktsivkov Date: Fri, 7 Apr 2023 15:33:43 +0200 Subject: [PATCH 3/6] Add tests for redis module loadex, and enable `--enable-module-command` to check that the loadex command fails as expected --- commands.go | 30 ++++--------------------- commands_test.go | 16 ++++++++++++- main_test.go | 2 +- module_loadex.go | 23 +++++++++++++++++++ module_loadex_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 28 deletions(-) create mode 100644 module_loadex.go create mode 100644 module_loadex_test.go diff --git a/commands.go b/commands.go index 06867eb790..5db01f4da5 100644 --- a/commands.go +++ b/commands.go @@ -496,7 +496,7 @@ type Cmdable interface { ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd - Loadex(ctx context.Context, conf *LoadexConfig) *Cmd + ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd } type StatefulCmdable interface { @@ -3876,31 +3876,9 @@ func (c cmdable) ACLDryRun(ctx context.Context, username string, command ...inte return cmd } -// LoadexConfig struct is used to specify the arguments for the MODULE LOADEX command of redis. -// `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` -type LoadexConfig struct { - Path string - Conf map[string]interface{} - Args []interface{} -} - -func (c *LoadexConfig) ToArgs() []interface{} { - var args = make([]interface{}, 3, len(c.Conf)*2+len(c.Args)+3) - args[0] = "MODULE" - args[1] = "LOADEX" - args[2] = c.Path - for k, v := range c.Conf { - args = append(args, "CONFIG", k, v) - } - for _, arg := range c.Args { - args = append(args, "ARGS", arg) - } - return args -} - -// Loadex Redis `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` command. -func (c cmdable) Loadex(ctx context.Context, conf *LoadexConfig) *Cmd { - cmd := NewCmd(ctx, conf.ToArgs()...) +// ModuleLoadex Redis `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` command. +func (c cmdable) ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd { + cmd := NewStringCmd(ctx, conf.ToArgs()...) _ = c(ctx, cmd) return cmd } diff --git a/commands_test.go b/commands_test.go index 72b2bb23de..f03a25ebf9 100644 --- a/commands_test.go +++ b/commands_test.go @@ -1926,11 +1926,25 @@ var _ = Describe("Commands", func() { Expect(replace.Val()).To(Equal(int64(1))) }) - It("should acl dryryn", func() { + It("should acl dryrun", func() { dryRun := client.ACLDryRun(ctx, "default", "get", "randomKey") Expect(dryRun.Err()).NotTo(HaveOccurred()) Expect(dryRun.Val()).To(Equal("OK")) }) + + It("should fail module loadex", func() { + dryRun := client.ModuleLoadex(ctx, &redis.ModuleLoadexConfig{ + Path: "/path/to/non-existent-library.so", + Conf: map[string]interface{}{ + "param1": "value1", + }, + Args: []interface{}{ + "arg1", + }, + }) + Expect(dryRun.Err()).To(HaveOccurred()) + Expect(dryRun.Err().Error()).To(Equal("ERR Error loading the extension. Please check the server logs.")) + }) }) Describe("hashes", func() { diff --git a/main_test.go b/main_test.go index b1a1f3950a..8e87d76f86 100644 --- a/main_test.go +++ b/main_test.go @@ -314,7 +314,7 @@ func startRedis(port string, args ...string) (*redisProcess, error) { return nil, err } - baseArgs := []string{filepath.Join(dir, "redis.conf"), "--port", port, "--dir", dir} + baseArgs := []string{filepath.Join(dir, "redis.conf"), "--port", port, "--dir", dir, "--enable-module-command", "yes"} process, err := execCmd(redisServerBin, append(baseArgs, args...)...) if err != nil { return nil, err diff --git a/module_loadex.go b/module_loadex.go new file mode 100644 index 0000000000..c27641db6b --- /dev/null +++ b/module_loadex.go @@ -0,0 +1,23 @@ +package redis + +// ModuleLoadexConfig struct is used to specify the arguments for the MODULE LOADEX command of redis. +// `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` +type ModuleLoadexConfig struct { + Path string + Conf map[string]interface{} + Args []interface{} +} + +func (c *ModuleLoadexConfig) ToArgs() []interface{} { + var args = make([]interface{}, 3, len(c.Conf)*2+len(c.Args)+3) + args[0] = "MODULE" + args[1] = "LOADEX" + args[2] = c.Path + for k, v := range c.Conf { + args = append(args, "CONFIG", k, v) + } + for _, arg := range c.Args { + args = append(args, "ARGS", arg) + } + return args +} diff --git a/module_loadex_test.go b/module_loadex_test.go new file mode 100644 index 0000000000..9fc565fc72 --- /dev/null +++ b/module_loadex_test.go @@ -0,0 +1,52 @@ +package redis_test + +import ( + . "github.com/bsm/ginkgo/v2" + . "github.com/bsm/gomega" + + "github.com/redis/go-redis/v9" +) + +var _ = Describe("Loadex Config", func() { + It("converts the configuration to a slice of arguments correctly", func() { + conf := &redis.ModuleLoadexConfig{ + Path: "/path/to/your/module.so", + Conf: map[string]interface{}{ + "param1": "value1", + "param2": "value2", + "param3": 3, + }, + Args: []interface{}{ + "arg1", + "arg2", + 3, + }, + } + + args := conf.ToArgs() + + // Test if the arguments are in the correct order + expectedArgs := []interface{}{ + "MODULE", + "LOADEX", + "/path/to/your/module.so", + "CONFIG", + "param1", + "value1", + "CONFIG", + "param2", + "value2", + "CONFIG", + "param3", + 3, + "ARGS", + "arg1", + "ARGS", + "arg2", + "ARGS", + 3, + } + + Expect(args).To(Equal(expectedArgs)) + }) +}) From 973f0fe7d04dccefd065efa7dde5d68aa2bee48a Mon Sep 17 00:00:00 2001 From: ktsivkov Date: Fri, 7 Apr 2023 15:56:40 +0200 Subject: [PATCH 4/6] Removed module_loadex files, and moved their code inside commands' --- commands.go | 22 ++++++++++++++++++ commands_test.go | 34 ++++++++++++++++++++++++++++ module_loadex.go | 23 ------------------- module_loadex_test.go | 52 ------------------------------------------- 4 files changed, 56 insertions(+), 75 deletions(-) delete mode 100644 module_loadex.go delete mode 100644 module_loadex_test.go diff --git a/commands.go b/commands.go index 5db01f4da5..b59a602db6 100644 --- a/commands.go +++ b/commands.go @@ -3876,6 +3876,28 @@ func (c cmdable) ACLDryRun(ctx context.Context, username string, command ...inte return cmd } +// ModuleLoadexConfig struct is used to specify the arguments for the MODULE LOADEX command of redis. +// `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` +type ModuleLoadexConfig struct { + Path string + Conf map[string]interface{} + Args []interface{} +} + +func (c *ModuleLoadexConfig) ToArgs() []interface{} { + var args = make([]interface{}, 3, len(c.Conf)*2+len(c.Args)+3) + args[0] = "MODULE" + args[1] = "LOADEX" + args[2] = c.Path + for k, v := range c.Conf { + args = append(args, "CONFIG", k, v) + } + for _, arg := range c.Args { + args = append(args, "ARGS", arg) + } + return args +} + // ModuleLoadex Redis `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` command. func (c cmdable) ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd { cmd := NewStringCmd(ctx, conf.ToArgs()...) diff --git a/commands_test.go b/commands_test.go index f03a25ebf9..f66db88f05 100644 --- a/commands_test.go +++ b/commands_test.go @@ -1945,6 +1945,40 @@ var _ = Describe("Commands", func() { Expect(dryRun.Err()).To(HaveOccurred()) Expect(dryRun.Err().Error()).To(Equal("ERR Error loading the extension. Please check the server logs.")) }) + + It("converts the module loadex configuration to a slice of arguments correctly", func() { + conf := &redis.ModuleLoadexConfig{ + Path: "/path/to/your/module.so", + Conf: map[string]interface{}{ + "param1": "value1", + }, + Args: []interface{}{ + "arg1", + "arg2", + 3, + }, + } + + args := conf.ToArgs() + + // Test if the arguments are in the correct order + expectedArgs := []interface{}{ + "MODULE", + "LOADEX", + "/path/to/your/module.so", + "CONFIG", + "param1", + "value1", + "ARGS", + "arg1", + "ARGS", + "arg2", + "ARGS", + 3, + } + + Expect(args).To(Equal(expectedArgs)) + }) }) Describe("hashes", func() { diff --git a/module_loadex.go b/module_loadex.go deleted file mode 100644 index c27641db6b..0000000000 --- a/module_loadex.go +++ /dev/null @@ -1,23 +0,0 @@ -package redis - -// ModuleLoadexConfig struct is used to specify the arguments for the MODULE LOADEX command of redis. -// `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` -type ModuleLoadexConfig struct { - Path string - Conf map[string]interface{} - Args []interface{} -} - -func (c *ModuleLoadexConfig) ToArgs() []interface{} { - var args = make([]interface{}, 3, len(c.Conf)*2+len(c.Args)+3) - args[0] = "MODULE" - args[1] = "LOADEX" - args[2] = c.Path - for k, v := range c.Conf { - args = append(args, "CONFIG", k, v) - } - for _, arg := range c.Args { - args = append(args, "ARGS", arg) - } - return args -} diff --git a/module_loadex_test.go b/module_loadex_test.go deleted file mode 100644 index 9fc565fc72..0000000000 --- a/module_loadex_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package redis_test - -import ( - . "github.com/bsm/ginkgo/v2" - . "github.com/bsm/gomega" - - "github.com/redis/go-redis/v9" -) - -var _ = Describe("Loadex Config", func() { - It("converts the configuration to a slice of arguments correctly", func() { - conf := &redis.ModuleLoadexConfig{ - Path: "/path/to/your/module.so", - Conf: map[string]interface{}{ - "param1": "value1", - "param2": "value2", - "param3": 3, - }, - Args: []interface{}{ - "arg1", - "arg2", - 3, - }, - } - - args := conf.ToArgs() - - // Test if the arguments are in the correct order - expectedArgs := []interface{}{ - "MODULE", - "LOADEX", - "/path/to/your/module.so", - "CONFIG", - "param1", - "value1", - "CONFIG", - "param2", - "value2", - "CONFIG", - "param3", - 3, - "ARGS", - "arg1", - "ARGS", - "arg2", - "ARGS", - 3, - } - - Expect(args).To(Equal(expectedArgs)) - }) -}) From 2da69f2349c06ed6b74a2d2beeb60fce14e04ad6 Mon Sep 17 00:00:00 2001 From: ktsivkov Date: Fri, 7 Apr 2023 17:36:50 +0200 Subject: [PATCH 5/6] Allocate the correct amount of memory Co-authored-by: Anurag Bandyopadhyay --- commands.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands.go b/commands.go index b59a602db6..4711c2a963 100644 --- a/commands.go +++ b/commands.go @@ -3885,7 +3885,7 @@ type ModuleLoadexConfig struct { } func (c *ModuleLoadexConfig) ToArgs() []interface{} { - var args = make([]interface{}, 3, len(c.Conf)*2+len(c.Args)+3) + args := make([]interface{}, 3, 3+len(c.Conf)*3+len(c.Args)*2) args[0] = "MODULE" args[1] = "LOADEX" args[2] = c.Path From 9b60cc85149087377cf4cd327a60f02a70d57a26 Mon Sep 17 00:00:00 2001 From: ktsivkov Date: Tue, 18 Apr 2023 14:45:13 +0200 Subject: [PATCH 6/6] Renamed ModuleLoadexConfig ToArgs to toArgs and export it for tests only --- commands.go | 4 ++-- export_test.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/commands.go b/commands.go index 0b79b54cbf..3721df4e1d 100644 --- a/commands.go +++ b/commands.go @@ -3899,7 +3899,7 @@ type ModuleLoadexConfig struct { Args []interface{} } -func (c *ModuleLoadexConfig) ToArgs() []interface{} { +func (c *ModuleLoadexConfig) toArgs() []interface{} { args := make([]interface{}, 3, 3+len(c.Conf)*3+len(c.Args)*2) args[0] = "MODULE" args[1] = "LOADEX" @@ -3915,7 +3915,7 @@ func (c *ModuleLoadexConfig) ToArgs() []interface{} { // ModuleLoadex Redis `MODULE LOADEX path [CONFIG name value [CONFIG name value ...]] [ARGS args [args ...]]` command. func (c cmdable) ModuleLoadex(ctx context.Context, conf *ModuleLoadexConfig) *StringCmd { - cmd := NewStringCmd(ctx, conf.ToArgs()...) + cmd := NewStringCmd(ctx, conf.toArgs()...) _ = c(ctx, cmd) return cmd } diff --git a/export_test.go b/export_test.go index 19a9dddcf2..3f92983dd3 100644 --- a/export_test.go +++ b/export_test.go @@ -98,3 +98,7 @@ func (c *Ring) ShardByName(name string) *ringShard { shard, _ := c.sharding.GetByName(name) return shard } + +func (c *ModuleLoadexConfig) ToArgs() []interface{} { + return c.toArgs() +}