From 5aca8205e3d984bb2ccc4ce3683a3c6359273845 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Mon, 29 May 2023 18:38:56 +0300 Subject: [PATCH 01/18] strart working on RG commands --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 27 +++++++++++++++++++ src/NRedisStack/Gears/GearsCommands.cs | 19 +++++++++++++ src/NRedisStack/Gears/GearsCommandsAsync.cs | 19 +++++++++++++ src/NRedisStack/Gears/IGearsCommands.cs | 22 +++++++++++++++ src/NRedisStack/Gears/IGearsCommandsAsync.cs | 22 +++++++++++++++ src/NRedisStack/Gears/Literals/CommandArgs.cs | 8 ++++++ src/NRedisStack/Gears/Literals/Commands.cs | 7 +++++ 7 files changed, 124 insertions(+) create mode 100644 src/NRedisStack/Gears/GearsCommandBuilder.cs create mode 100644 src/NRedisStack/Gears/GearsCommands.cs create mode 100644 src/NRedisStack/Gears/GearsCommandsAsync.cs create mode 100644 src/NRedisStack/Gears/IGearsCommands.cs create mode 100644 src/NRedisStack/Gears/IGearsCommandsAsync.cs create mode 100644 src/NRedisStack/Gears/Literals/CommandArgs.cs create mode 100644 src/NRedisStack/Gears/Literals/Commands.cs diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs new file mode 100644 index 00000000..920b1084 --- /dev/null +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -0,0 +1,27 @@ +using NRedisStack.RedisStackCommands; +using StackExchange.Redis; +using NRedisStack.Gears.Literals; +namespace NRedisStack +{ + + public static class GearsCommandBuilder + { + public static SerializedCommand TFunctionLoad(string libraryCode, string? config = null, bool replace = false) + { + var args = new List(); + + if (replace) + { + args.Add(GearsArgs.REPLACE); + } + + if (config != null) + { + args.Add(GearsArgs.CONFIG); + args.Add(config); + } + args.Add(libraryCode); + return new SerializedCommand("TFUNCTION LOAD", args); // TODO: check if its supposed to be "TFUNCTION", "LOAD" + } + } +} diff --git a/src/NRedisStack/Gears/GearsCommands.cs b/src/NRedisStack/Gears/GearsCommands.cs new file mode 100644 index 00000000..fbd280a6 --- /dev/null +++ b/src/NRedisStack/Gears/GearsCommands.cs @@ -0,0 +1,19 @@ +using StackExchange.Redis; +namespace NRedisStack +{ + + public class GearsCommands : GearsCommandsAsync, IGearsCommands + { + IDatabase _db; + public GearsCommands(IDatabase db) : base(db) + { + _db = db; + } + + /// + public bool TFunctionLoad(string libraryCode, string? config = null, bool replace = false) + { + return _db.Execute(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace)).OKtoBoolean(); + } + } +} diff --git a/src/NRedisStack/Gears/GearsCommandsAsync.cs b/src/NRedisStack/Gears/GearsCommandsAsync.cs new file mode 100644 index 00000000..b51b0fa8 --- /dev/null +++ b/src/NRedisStack/Gears/GearsCommandsAsync.cs @@ -0,0 +1,19 @@ +using StackExchange.Redis; +namespace NRedisStack +{ + + public class GearsCommandsAsync : IGearsCommandsAsync + { + IDatabaseAsync _db; + public GearsCommandsAsync(IDatabaseAsync db) + { + _db = db; + } + + /// + public async Task TFunctionLoadAsync(string libraryCode, string? config = null, bool replace = false) + { + return (await _db.ExecuteAsync(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace))).OKtoBoolean(); + } + } +} diff --git a/src/NRedisStack/Gears/IGearsCommands.cs b/src/NRedisStack/Gears/IGearsCommands.cs new file mode 100644 index 00000000..49aa8eb8 --- /dev/null +++ b/src/NRedisStack/Gears/IGearsCommands.cs @@ -0,0 +1,22 @@ +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface IGearsCommands + { + /// + /// Load a new library to RedisGears. + /// + /// the library code. + /// a string representation of a JSON object + /// that will be provided to the library on load time, + /// for more information refer to + /// + /// library configuration + /// an optional argument, instructs RedisGears to replace the function if its already exists. + /// if everything was done correctly, Error otherwise. + /// //TODO: add link to the command when it's available + bool TFunctionLoad(string libraryCode, string? config = null, bool replace = false); + + } +} diff --git a/src/NRedisStack/Gears/IGearsCommandsAsync.cs b/src/NRedisStack/Gears/IGearsCommandsAsync.cs new file mode 100644 index 00000000..faff0950 --- /dev/null +++ b/src/NRedisStack/Gears/IGearsCommandsAsync.cs @@ -0,0 +1,22 @@ +using StackExchange.Redis; + +namespace NRedisStack +{ + public interface IGearsCommandsAsync + { + /// + /// Load a new library to RedisGears. + /// + /// the library code. + /// a string representation of a JSON object + /// that will be provided to the library on load time, + /// for more information refer to + /// + /// library configuration + /// an optional argument, instructs RedisGears to replace the function if its already exists. + /// if everything was done correctly, Error otherwise. + /// //TODO: add link to the command when it's available + Task TFunctionLoadAsync(string libraryCode, string? config = null, bool replace = false); + + } +} diff --git a/src/NRedisStack/Gears/Literals/CommandArgs.cs b/src/NRedisStack/Gears/Literals/CommandArgs.cs new file mode 100644 index 00000000..a2cfeed1 --- /dev/null +++ b/src/NRedisStack/Gears/Literals/CommandArgs.cs @@ -0,0 +1,8 @@ +namespace NRedisStack.Gears.Literals +{ + internal class GearsArgs + { + public const string CONFIG = "CONFIG"; + public const string REPLACE = "REPLACE"; + } +} diff --git a/src/NRedisStack/Gears/Literals/Commands.cs b/src/NRedisStack/Gears/Literals/Commands.cs new file mode 100644 index 00000000..379a0844 --- /dev/null +++ b/src/NRedisStack/Gears/Literals/Commands.cs @@ -0,0 +1,7 @@ +namespace NRedisStack.Gears.Literals +{ + internal class RG + { + // TODO: decide if needed + } +} From 60b0375067e2bce7fa779f8e5e56c749f256de36 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 30 May 2023 16:37:48 +0300 Subject: [PATCH 02/18] delete interfaces --- src/NRedisStack/Gears/GearsCommands.cs | 24 +++++++++++------- src/NRedisStack/Gears/GearsCommandsAsync.cs | 25 +++++++++++-------- src/NRedisStack/Gears/IGearsCommands.cs | 22 ----------------- src/NRedisStack/Gears/IGearsCommandsAsync.cs | 22 ----------------- tests/NRedisStack.Tests/Gears/GearsTests.cs | 26 ++++++++++++++++++++ 5 files changed, 56 insertions(+), 63 deletions(-) delete mode 100644 src/NRedisStack/Gears/IGearsCommands.cs delete mode 100644 src/NRedisStack/Gears/IGearsCommandsAsync.cs create mode 100644 tests/NRedisStack.Tests/Gears/GearsTests.cs diff --git a/src/NRedisStack/Gears/GearsCommands.cs b/src/NRedisStack/Gears/GearsCommands.cs index fbd280a6..cc7b1bc0 100644 --- a/src/NRedisStack/Gears/GearsCommands.cs +++ b/src/NRedisStack/Gears/GearsCommands.cs @@ -2,18 +2,24 @@ namespace NRedisStack { - public class GearsCommands : GearsCommandsAsync, IGearsCommands + public static class GearsCommands //: GearsCommandsAsync, IGearsCommands { - IDatabase _db; - public GearsCommands(IDatabase db) : base(db) - { - _db = db; - } - /// - public bool TFunctionLoad(string libraryCode, string? config = null, bool replace = false) + /// + /// Load a new library to RedisGears. + /// + /// the library code. + /// a string representation of a JSON object + /// that will be provided to the library on load time, + /// for more information refer to + /// + /// library configuration + /// an optional argument, instructs RedisGears to replace the function if its already exists. + /// if everything was done correctly, Error otherwise. + /// //TODO: add link to the command when it's available + public static bool TFunctionLoad(this IDatabase db, string libraryCode, string? config = null, bool replace = false) { - return _db.Execute(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace)).OKtoBoolean(); + return db.Execute(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace)).OKtoBoolean(); } } } diff --git a/src/NRedisStack/Gears/GearsCommandsAsync.cs b/src/NRedisStack/Gears/GearsCommandsAsync.cs index b51b0fa8..b900f057 100644 --- a/src/NRedisStack/Gears/GearsCommandsAsync.cs +++ b/src/NRedisStack/Gears/GearsCommandsAsync.cs @@ -2,18 +2,23 @@ namespace NRedisStack { - public class GearsCommandsAsync : IGearsCommandsAsync + public static class GearsCommandsAsync //: IGearsCommandsAsync { - IDatabaseAsync _db; - public GearsCommandsAsync(IDatabaseAsync db) + /// + /// Load a new library to RedisGears. + /// + /// the library code. + /// a string representation of a JSON object + /// that will be provided to the library on load time, + /// for more information refer to + /// + /// library configuration + /// an optional argument, instructs RedisGears to replace the function if its already exists. + /// if everything was done correctly, Error otherwise. + /// //TODO: add link to the command when it's available + public static async Task TFunctionLoadAsync(this IDatabase db, string libraryCode, string? config = null, bool replace = false) { - _db = db; - } - - /// - public async Task TFunctionLoadAsync(string libraryCode, string? config = null, bool replace = false) - { - return (await _db.ExecuteAsync(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace))).OKtoBoolean(); + return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace))).OKtoBoolean(); } } } diff --git a/src/NRedisStack/Gears/IGearsCommands.cs b/src/NRedisStack/Gears/IGearsCommands.cs deleted file mode 100644 index 49aa8eb8..00000000 --- a/src/NRedisStack/Gears/IGearsCommands.cs +++ /dev/null @@ -1,22 +0,0 @@ -using StackExchange.Redis; - -namespace NRedisStack -{ - public interface IGearsCommands - { - /// - /// Load a new library to RedisGears. - /// - /// the library code. - /// a string representation of a JSON object - /// that will be provided to the library on load time, - /// for more information refer to - /// - /// library configuration - /// an optional argument, instructs RedisGears to replace the function if its already exists. - /// if everything was done correctly, Error otherwise. - /// //TODO: add link to the command when it's available - bool TFunctionLoad(string libraryCode, string? config = null, bool replace = false); - - } -} diff --git a/src/NRedisStack/Gears/IGearsCommandsAsync.cs b/src/NRedisStack/Gears/IGearsCommandsAsync.cs deleted file mode 100644 index faff0950..00000000 --- a/src/NRedisStack/Gears/IGearsCommandsAsync.cs +++ /dev/null @@ -1,22 +0,0 @@ -using StackExchange.Redis; - -namespace NRedisStack -{ - public interface IGearsCommandsAsync - { - /// - /// Load a new library to RedisGears. - /// - /// the library code. - /// a string representation of a JSON object - /// that will be provided to the library on load time, - /// for more information refer to - /// - /// library configuration - /// an optional argument, instructs RedisGears to replace the function if its already exists. - /// if everything was done correctly, Error otherwise. - /// //TODO: add link to the command when it's available - Task TFunctionLoadAsync(string libraryCode, string? config = null, bool replace = false); - - } -} diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs new file mode 100644 index 00000000..08d3554d --- /dev/null +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -0,0 +1,26 @@ +using Xunit; +using StackExchange.Redis; +using NRedisStack.RedisStackCommands; +using Moq; + +namespace NRedisStack.Tests.Gears; + +public class GearsTests : AbstractNRedisStackTest, IDisposable +{ + Mock _mock = new Mock(); + private readonly string key = "BLOOM_TESTS"; + public GearsTests(RedisFixture redisFixture) : base(redisFixture) { } + + public void Dispose() + { + redisFixture.Redis.GetDatabase().KeyDelete(key); + } + + [Fact] + public void TestReserveBasic() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + // TODO: write a test + } +} \ No newline at end of file From 6f10c7b5297be90c35879444c88e48e286928728 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 30 May 2023 16:59:44 +0300 Subject: [PATCH 03/18] test --- tests/NRedisStack.Tests/Gears/GearsTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 08d3554d..e39e4fa2 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -21,6 +21,7 @@ public void TestReserveBasic() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - // TODO: write a test + // TODO: finish the test when the docker will support this command + // Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); } } \ No newline at end of file From bf1aef600a3bde178398bb67a570f9a6afa6dbc2 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 30 May 2023 17:22:06 +0300 Subject: [PATCH 04/18] Support TFunction Delete --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 5 +++++ src/NRedisStack/Gears/GearsCommands.cs | 11 +++++++++++ src/NRedisStack/Gears/GearsCommandsAsync.cs | 11 +++++++++++ tests/NRedisStack.Tests/Gears/GearsTests.cs | 13 ++++++++++++- 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index 920b1084..201260ed 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -23,5 +23,10 @@ public static SerializedCommand TFunctionLoad(string libraryCode, string? config args.Add(libraryCode); return new SerializedCommand("TFUNCTION LOAD", args); // TODO: check if its supposed to be "TFUNCTION", "LOAD" } + + public static SerializedCommand TFunctionDelete(string libraryName) + { + return new SerializedCommand("TFUNCTION DELETE", libraryName); // TODO: check if its supposed to be "TFUNCTION", "DELETE" + } } } diff --git a/src/NRedisStack/Gears/GearsCommands.cs b/src/NRedisStack/Gears/GearsCommands.cs index cc7b1bc0..b301508d 100644 --- a/src/NRedisStack/Gears/GearsCommands.cs +++ b/src/NRedisStack/Gears/GearsCommands.cs @@ -21,5 +21,16 @@ public static bool TFunctionLoad(this IDatabase db, string libraryCode, string? { return db.Execute(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace)).OKtoBoolean(); } + + /// + /// Delete a library from RedisGears. + /// + /// the name of the library to delete. + /// if the library was deleted successfully, Error otherwise. + /// //TODO: add link to the command when it's available + public static bool TFunctionDelete(this IDatabase db, string libraryName) + { + return db.Execute(GearsCommandBuilder.TFunctionDelete(libraryName)).OKtoBoolean(); + } } } diff --git a/src/NRedisStack/Gears/GearsCommandsAsync.cs b/src/NRedisStack/Gears/GearsCommandsAsync.cs index b900f057..57ab61ee 100644 --- a/src/NRedisStack/Gears/GearsCommandsAsync.cs +++ b/src/NRedisStack/Gears/GearsCommandsAsync.cs @@ -20,5 +20,16 @@ public static async Task TFunctionLoadAsync(this IDatabase db, string libr { return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace))).OKtoBoolean(); } + + /// + /// Delete a library from RedisGears. + /// + /// the name of the library to delete. + /// if the library was deleted successfully, Error otherwise. + /// //TODO: add link to the command when it's available + public static async Task TFunctionDeleteAsync(this IDatabase db, string libraryName) + { + return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionDelete(libraryName))).OKtoBoolean(); + } } } diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index e39e4fa2..8c184e87 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -16,12 +16,23 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(key); } + // TODO: add async tests [Fact] - public void TestReserveBasic() + public void TestTFunctionLoad() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); // TODO: finish the test when the docker will support this command // Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); } + + [Fact] + public void TestTFunctionDelete() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + // TODO: finish the test when the docker will support this command + // Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + // Assert.True(db.TFunctionDelete("lib")); + } } \ No newline at end of file From de2b95e3609dfe440175a2e3625d6f6c28365804 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 31 May 2023 11:49:23 +0300 Subject: [PATCH 05/18] uncomment tests --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 6 +++--- tests/NRedisStack.Tests/Gears/GearsTests.cs | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index 201260ed..b14e051c 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -8,7 +8,7 @@ public static class GearsCommandBuilder { public static SerializedCommand TFunctionLoad(string libraryCode, string? config = null, bool replace = false) { - var args = new List(); + var args = new List() { "TFUNCTION" }; if (replace) { @@ -21,12 +21,12 @@ public static SerializedCommand TFunctionLoad(string libraryCode, string? config args.Add(config); } args.Add(libraryCode); - return new SerializedCommand("TFUNCTION LOAD", args); // TODO: check if its supposed to be "TFUNCTION", "LOAD" + return new SerializedCommand("LOAD", args); } public static SerializedCommand TFunctionDelete(string libraryName) { - return new SerializedCommand("TFUNCTION DELETE", libraryName); // TODO: check if its supposed to be "TFUNCTION", "DELETE" + return new SerializedCommand("TFUNCTION", "DELETE", libraryName); } } } diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 8c184e87..1cfbac89 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -22,8 +22,7 @@ public void TestTFunctionLoad() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - // TODO: finish the test when the docker will support this command - // Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); } [Fact] @@ -31,8 +30,7 @@ public void TestTFunctionDelete() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - // TODO: finish the test when the docker will support this command - // Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); - // Assert.True(db.TFunctionDelete("lib")); + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionDelete("lib")); } } \ No newline at end of file From 018684bc71745140eefadca00aa6b374f25700ae Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 31 May 2023 11:59:10 +0300 Subject: [PATCH 06/18] fix test --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index b14e051c..2a8a08c1 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -8,7 +8,7 @@ public static class GearsCommandBuilder { public static SerializedCommand TFunctionLoad(string libraryCode, string? config = null, bool replace = false) { - var args = new List() { "TFUNCTION" }; + var args = new List() { "LOAD" }; if (replace) { @@ -21,7 +21,7 @@ public static SerializedCommand TFunctionLoad(string libraryCode, string? config args.Add(config); } args.Add(libraryCode); - return new SerializedCommand("LOAD", args); + return new SerializedCommand("TFUNCTION", args); } public static SerializedCommand TFunctionDelete(string libraryName) From 1284fe7d236ed0027e7431df7e897eec4dd0f4bf Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 1 Jun 2023 16:50:17 +0300 Subject: [PATCH 07/18] fix tests --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 2 +- tests/NRedisStack.Tests/Gears/GearsTests.cs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index 2a8a08c1..fd6b93f5 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -8,7 +8,7 @@ public static class GearsCommandBuilder { public static SerializedCommand TFunctionLoad(string libraryCode, string? config = null, bool replace = false) { - var args = new List() { "LOAD" }; + var args = new List() { "LOAD" }; if (replace) { diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 1cfbac89..d18d8a3e 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -1,6 +1,5 @@ using Xunit; using StackExchange.Redis; -using NRedisStack.RedisStackCommands; using Moq; namespace NRedisStack.Tests.Gears; @@ -16,21 +15,24 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(key); } - // TODO: add async tests + [Fact] - public void TestTFunctionLoad() + public void TestTFunctionLoadDelete() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionDelete("lib")); } [Fact] - public void TestTFunctionDelete() + public async Task TestTFunctionLoadDeleteAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.True(db.TFunctionDelete("lib")); + + Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(await db.TFunctionDeleteAsync("lib")); } } \ No newline at end of file From 6da2318b21af1d776c62823d522a183fdbfbe4a4 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 4 Jun 2023 12:06:05 +0300 Subject: [PATCH 08/18] Support TFunctionList --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 23 ++++++++++ src/NRedisStack/Gears/GearsCommands.cs | 16 ++++++- src/NRedisStack/Gears/GearsCommandsAsync.cs | 14 ++++++ src/NRedisStack/ResponseParser.cs | 12 +++++ tests/NRedisStack.Tests/Gears/GearsTests.cs | 46 ++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index fd6b93f5..db5e240a 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -28,5 +28,28 @@ public static SerializedCommand TFunctionDelete(string libraryName) { return new SerializedCommand("TFUNCTION", "DELETE", libraryName); } + + public static SerializedCommand TFunctionList(bool withCode = false, int verbose = 0, string? libraryName = null) + { + var args = new List() { "LIST" }; + + if (withCode) + { + args.Add("WITHCODE"); + } + + if (verbose > 0) + { + args.Add(new string('v', Math.Min(3, verbose))); + } + + if (libraryName != null) + { + args.Add("LIBRARY"); + args.Add(libraryName); + } + + return new SerializedCommand("TFUNCTION", args); + } } } diff --git a/src/NRedisStack/Gears/GearsCommands.cs b/src/NRedisStack/Gears/GearsCommands.cs index b301508d..842ca37d 100644 --- a/src/NRedisStack/Gears/GearsCommands.cs +++ b/src/NRedisStack/Gears/GearsCommands.cs @@ -28,9 +28,23 @@ public static bool TFunctionLoad(this IDatabase db, string libraryCode, string? /// the name of the library to delete. /// if the library was deleted successfully, Error otherwise. /// //TODO: add link to the command when it's available - public static bool TFunctionDelete(this IDatabase db, string libraryName) + public static bool TFunctionDelete(this IDatabase db, string libraryName) { return db.Execute(GearsCommandBuilder.TFunctionDelete(libraryName)).OKtoBoolean(); } + + /// + /// List the functions with additional information about each function. + /// + /// Show libraries code. + /// output verbosity level, higher number will increase verbosity level + /// specifying a library name (can be used + /// multiple times to show multiple libraries in a single command) + /// Information about the requested libraries. + /// //TODO: add link to the command when it's available + public static Dictionary[] TFunctionList(this IDatabase db, bool withCode = false, int verbose = 0, string? libraryName = null) + { + return db.Execute(GearsCommandBuilder.TFunctionList(withCode, verbose, libraryName)).ToDictionarys(); + } } } diff --git a/src/NRedisStack/Gears/GearsCommandsAsync.cs b/src/NRedisStack/Gears/GearsCommandsAsync.cs index 57ab61ee..7add3fc4 100644 --- a/src/NRedisStack/Gears/GearsCommandsAsync.cs +++ b/src/NRedisStack/Gears/GearsCommandsAsync.cs @@ -31,5 +31,19 @@ public static async Task TFunctionDeleteAsync(this IDatabase db, string li { return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionDelete(libraryName))).OKtoBoolean(); } + + /// + /// List the functions with additional information about each function. + /// + /// Show libraries code. + /// output verbosity level, higher number will increase verbosity level + /// specifying a library name (can be used + /// multiple times to show multiple libraries in a single command) + /// Information about the requested libraries. + /// //TODO: add link to the command when it's available + public static async Task[]> TFunctionListAsync(this IDatabase db, bool withCode = false, int verbose = 0, string? libraryName = null) + { + return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionList(withCode, verbose, libraryName))).ToDictionarys(); + } } } diff --git a/src/NRedisStack/ResponseParser.cs b/src/NRedisStack/ResponseParser.cs index a8b0fd85..7071476b 100644 --- a/src/NRedisStack/ResponseParser.cs +++ b/src/NRedisStack/ResponseParser.cs @@ -613,5 +613,17 @@ public static IEnumerable> ToHashSets(this RedisResult result) return sets; } + + public static Dictionary[] ToDictionarys(this RedisResult result) + { + var resArr = (RedisResult[])result!; + var dicts = new Dictionary[resArr.Length]; + for (int i = 0; i < resArr.Length; i++) + { + dicts[i] = resArr[i].ToDictionary(); + } + + return dicts; + } } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index d18d8a3e..372832e4 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -35,4 +35,50 @@ public async Task TestTFunctionLoadDeleteAsync() Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(await db.TFunctionDeleteAsync("lib")); } + + [Fact] + public void TestTFunctionList() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); + + var functions = db.TFunctionList(verbose : 1); + Assert.Equal(3, functions.Length); + + Assert.Equal("lib1", functions[0]["name"].ToString()); + Assert.Equal("lib2", functions[1]["name"].ToString()); + Assert.Equal("lib3", functions[2]["name"].ToString()); + + + Assert.True(db.TFunctionDelete("lib1")); + Assert.True(db.TFunctionDelete("lib2")); + Assert.True(db.TFunctionDelete("lib3")); + } + + [Fact] + public async Task TestTFunctionListAsync() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + + Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); + + var functions = await db.TFunctionListAsync(verbose : 1); + Assert.Equal(3, functions.Length); + + Assert.Equal("lib1", functions[0]["name"].ToString()); + Assert.Equal("lib2", functions[1]["name"].ToString()); + Assert.Equal("lib3", functions[2]["name"].ToString()); + + + Assert.True(await db.TFunctionDeleteAsync("lib1")); + Assert.True(await db.TFunctionDeleteAsync("lib2")); + Assert.True(await db.TFunctionDeleteAsync("lib3")); + } } \ No newline at end of file From 33c74e4cacda1d8b80731bc11714854ea955a6a2 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 4 Jun 2023 12:58:51 +0300 Subject: [PATCH 09/18] TestCommandBuilder --- tests/NRedisStack.Tests/Gears/GearsTests.cs | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 372832e4..580498ad 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -81,4 +81,43 @@ public async Task TestTFunctionListAsync() Assert.True(await db.TFunctionDeleteAsync("lib2")); Assert.True(await db.TFunctionDeleteAsync("lib3")); } + + [Fact] + public void TestCommandBuilder() + { + var buildCommand = GearsCommandBuilder + .TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})", + "config", true); + var expected = new List + { + "LOAD", + "REPLACE", + "CONFIG", + "config", + "#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})" + }; + Assert.Equal("TFUNCTION", buildCommand.Command); + Assert.Equal(expected, buildCommand.Args); + + buildCommand = GearsCommandBuilder.TFunctionDelete("lib"); + expected = new List + { + "DELETE", + "lib" + }; + Assert.Equal("TFUNCTION", buildCommand.Command); + Assert.Equal(expected, buildCommand.Args); + + buildCommand = GearsCommandBuilder.TFunctionList(true, 2, "lib"); + expected = new List + { + "LIST", + "WITHCODE", + "vv", + "LIBRARY", + "lib", + }; + Assert.Equal("TFUNCTION", buildCommand.Command); + Assert.Equal(expected, buildCommand.Args); + } } \ No newline at end of file From 4c0d9ddebe4c8c912d652f2adce3531ce021bd89 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 4 Jun 2023 14:24:43 +0300 Subject: [PATCH 10/18] Support FTCall Sync --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 23 +++++++++++ src/NRedisStack/Gears/GearsCommands.cs | 15 +++++++ tests/NRedisStack.Tests/Gears/GearsTests.cs | 41 +++++++++++++++++++- 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index db5e240a..bd5b5644 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -51,5 +51,28 @@ public static SerializedCommand TFunctionList(bool withCode = false, int verbose return new SerializedCommand("TFUNCTION", args); } + + public static SerializedCommand TFCall(string libraryName, string functionName, string[]? keys = null, string[]? args = null, bool async = false) + { + string command = async ? "TFCALLASYNC" : "TFCALL"; + var commandArgs = new List() {libraryName, functionName}; + + if (keys != null) + { + commandArgs.Add(keys.Length); + commandArgs.AddRange(keys); + } + else + { + commandArgs.Add(0); + } + + if (args != null) + { + commandArgs.AddRange(args); + } + + return new SerializedCommand(command, commandArgs); + } } } diff --git a/src/NRedisStack/Gears/GearsCommands.cs b/src/NRedisStack/Gears/GearsCommands.cs index 842ca37d..d8363122 100644 --- a/src/NRedisStack/Gears/GearsCommands.cs +++ b/src/NRedisStack/Gears/GearsCommands.cs @@ -46,5 +46,20 @@ public static Dictionary[] TFunctionList(this IDatabase db, { return db.Execute(GearsCommandBuilder.TFunctionList(withCode, verbose, libraryName)).ToDictionarys(); } + + /// + /// Invoke a sync or async (Coroutine) function. + /// + /// The library name contains the function. + /// The function name to run. + /// keys that will be touched by the function. + /// Additional argument to pass to the function. + /// If true, Invoke an async function (Coroutine). + /// The return value from the sync & async function on error in case of failure. + /// //TODO: add link to the command when it's available + public static RedisResult TFCall(this IDatabase db, string libraryName, string functionName, string[]? keys = null, string[]? args = null, bool async = false) + { + return db.Execute(GearsCommandBuilder.TFCall(libraryName, functionName, keys, args, async)); + } } } diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 580498ad..03df29af 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -83,8 +83,22 @@ public async Task TestTFunctionListAsync() } [Fact] - public void TestCommandBuilder() + public void TestTFCall() { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + + Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.Equal("bar", db.TFCall("lib", "foo", async : false).ToString()); + Assert.Equal("bar", db.TFCall("lib", "foo", async : true).ToString()); + + Assert.True(db.TFunctionDelete("lib")); + } + + [Fact] + public void TestGearsCommandBuilder() + { + // TFunctionLoad: var buildCommand = GearsCommandBuilder .TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})", "config", true); @@ -99,6 +113,7 @@ public void TestCommandBuilder() Assert.Equal("TFUNCTION", buildCommand.Command); Assert.Equal(expected, buildCommand.Args); + // TFunctionDelete: buildCommand = GearsCommandBuilder.TFunctionDelete("lib"); expected = new List { @@ -108,6 +123,7 @@ public void TestCommandBuilder() Assert.Equal("TFUNCTION", buildCommand.Command); Assert.Equal(expected, buildCommand.Args); + // TFunctionList: buildCommand = GearsCommandBuilder.TFunctionList(true, 2, "lib"); expected = new List { @@ -119,5 +135,26 @@ public void TestCommandBuilder() }; Assert.Equal("TFUNCTION", buildCommand.Command); Assert.Equal(expected, buildCommand.Args); + + // TFCall: + var buildSync = GearsCommandBuilder.TFCall("libName", "funcName", new string[] { "key1", "key2" }, new string[] { "arg1", "arg2" }, false); + var buildAsync = GearsCommandBuilder.TFCall("libName", "funcName", new string[] { "key1", "key2" }, new string[] { "arg1", "arg2" }, true); + + expected = new List + { + "libName", + "funcName", + 2, + "key1", + "key2", + "arg1", + "arg2" + }; + + Assert.Equal("TFCALL", buildSync.Command); + Assert.Equal(expected, buildSync.Args); + + Assert.Equal("TFCALLASYNC", buildAsync.Command); + Assert.Equal(expected, buildAsync.Args); } -} \ No newline at end of file +} From 54bd84b8779f17701243662393379f03dfbae563 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 4 Jun 2023 14:31:41 +0300 Subject: [PATCH 11/18] async FTCALL --- src/NRedisStack/Gears/GearsCommandsAsync.cs | 15 +++++++++++++++ tests/NRedisStack.Tests/Gears/GearsTests.cs | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/NRedisStack/Gears/GearsCommandsAsync.cs b/src/NRedisStack/Gears/GearsCommandsAsync.cs index 7add3fc4..e7d7fa87 100644 --- a/src/NRedisStack/Gears/GearsCommandsAsync.cs +++ b/src/NRedisStack/Gears/GearsCommandsAsync.cs @@ -45,5 +45,20 @@ public static async Task[]> TFunctionListAsync(t { return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionList(withCode, verbose, libraryName))).ToDictionarys(); } + + /// + /// Invoke a sync or async (Coroutine) function. + /// + /// The library name contains the function. + /// The function name to run. + /// keys that will be touched by the function. + /// Additional argument to pass to the function. + /// If true, Invoke an async function (Coroutine). + /// The return value from the sync & async function on error in case of failure. + /// //TODO: add link to the command when it's available + public static async Task TFCallAsync(this IDatabase db, string libraryName, string functionName, string[]? keys = null, string[]? args = null, bool async = false) + { + return await db.ExecuteAsync(GearsCommandBuilder.TFCall(libraryName, functionName, keys, args, async)); + } } } diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 03df29af..737f6d77 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -95,6 +95,19 @@ public void TestTFCall() Assert.True(db.TFunctionDelete("lib")); } + [Fact] + public async Task TestTFCallAsync() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + + Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async : false)).ToString()); + Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async : true)).ToString()); + + Assert.True(await db.TFunctionDeleteAsync("lib")); + } + [Fact] public void TestGearsCommandBuilder() { From 9179584e222e1e17bba4cc802ecea06492fc75ef Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 4 Jun 2023 14:35:14 +0300 Subject: [PATCH 12/18] Cleaning --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 1 - src/NRedisStack/Gears/Literals/Commands.cs | 7 ------- 2 files changed, 8 deletions(-) delete mode 100644 src/NRedisStack/Gears/Literals/Commands.cs diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index bd5b5644..6fa03da1 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -1,5 +1,4 @@ using NRedisStack.RedisStackCommands; -using StackExchange.Redis; using NRedisStack.Gears.Literals; namespace NRedisStack { diff --git a/src/NRedisStack/Gears/Literals/Commands.cs b/src/NRedisStack/Gears/Literals/Commands.cs deleted file mode 100644 index 379a0844..00000000 --- a/src/NRedisStack/Gears/Literals/Commands.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace NRedisStack.Gears.Literals -{ - internal class RG - { - // TODO: decide if needed - } -} From 71c9c3cb7d56be5c490d8844440646e655a63ec6 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 7 Jun 2023 14:26:07 +0300 Subject: [PATCH 13/18] review fixes --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 10 +++++++--- src/NRedisStack/Gears/GearsCommands.cs | 15 ++++++++------- tests/NRedisStack.Tests/Gears/GearsTests.cs | 11 ++++++++++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index 6fa03da1..f3826a88 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -5,7 +5,7 @@ namespace NRedisStack public static class GearsCommandBuilder { - public static SerializedCommand TFunctionLoad(string libraryCode, string? config = null, bool replace = false) + public static SerializedCommand TFunctionLoad(string libraryCode, bool replace = false, string? config = null) { var args = new List() { "LOAD" }; @@ -37,9 +37,13 @@ public static SerializedCommand TFunctionList(bool withCode = false, int verbose args.Add("WITHCODE"); } - if (verbose > 0) + if (verbose > 0 && verbose < 4) { - args.Add(new string('v', Math.Min(3, verbose))); + args.Add(new string('v', verbose)); + } + else if (verbose != 0) // verbose == 0 is the default so we don't need to throw an error + { + throw new ArgumentOutOfRangeException(nameof(verbose), "verbose must be between 1 and 3"); } if (libraryName != null) diff --git a/src/NRedisStack/Gears/GearsCommands.cs b/src/NRedisStack/Gears/GearsCommands.cs index d8363122..9c0b890e 100644 --- a/src/NRedisStack/Gears/GearsCommands.cs +++ b/src/NRedisStack/Gears/GearsCommands.cs @@ -16,10 +16,10 @@ public static class GearsCommands //: GearsCommandsAsync, IGearsCommands /// library configuration /// an optional argument, instructs RedisGears to replace the function if its already exists. /// if everything was done correctly, Error otherwise. - /// //TODO: add link to the command when it's available - public static bool TFunctionLoad(this IDatabase db, string libraryCode, string? config = null, bool replace = false) + /// //TODO: check this link when it's available + public static bool TFunctionLoad(this IDatabase db, string libraryCode, bool replace = false, string? config = null) { - return db.Execute(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace)).OKtoBoolean(); + return db.Execute(GearsCommandBuilder.TFunctionLoad(libraryCode, replace, config)).OKtoBoolean(); } /// @@ -27,7 +27,7 @@ public static bool TFunctionLoad(this IDatabase db, string libraryCode, string? /// /// the name of the library to delete. /// if the library was deleted successfully, Error otherwise. - /// //TODO: add link to the command when it's available + /// //TODO: check this link when it's available public static bool TFunctionDelete(this IDatabase db, string libraryName) { return db.Execute(GearsCommandBuilder.TFunctionDelete(libraryName)).OKtoBoolean(); @@ -41,14 +41,14 @@ public static bool TFunctionDelete(this IDatabase db, string libraryName) /// specifying a library name (can be used /// multiple times to show multiple libraries in a single command) /// Information about the requested libraries. - /// //TODO: add link to the command when it's available + /// //TODO: check this link when it's available public static Dictionary[] TFunctionList(this IDatabase db, bool withCode = false, int verbose = 0, string? libraryName = null) { return db.Execute(GearsCommandBuilder.TFunctionList(withCode, verbose, libraryName)).ToDictionarys(); } /// - /// Invoke a sync or async (Coroutine) function. + /// Trigger a sync or async (Coroutine) function. /// /// The library name contains the function. /// The function name to run. @@ -56,7 +56,8 @@ public static Dictionary[] TFunctionList(this IDatabase db, /// Additional argument to pass to the function. /// If true, Invoke an async function (Coroutine). /// The return value from the sync & async function on error in case of failure. - /// //TODO: add link to the command when it's available + /// //TODO: check this link when it's available + /// //TODO: check this link when it's available public static RedisResult TFCall(this IDatabase db, string libraryName, string functionName, string[]? keys = null, string[]? args = null, bool async = false) { return db.Execute(GearsCommandBuilder.TFCall(libraryName, functionName, keys, args, async)); diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 737f6d77..7ffe3b84 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -17,6 +17,7 @@ public void Dispose() [Fact] + [Trait("Category", "edge")] public void TestTFunctionLoadDelete() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -27,6 +28,7 @@ public void TestTFunctionLoadDelete() } [Fact] + [Trait("Category", "edge")] public async Task TestTFunctionLoadDeleteAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -37,6 +39,7 @@ public async Task TestTFunctionLoadDeleteAsync() } [Fact] + [Trait("Category", "edge")] public void TestTFunctionList() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -46,6 +49,8 @@ public void TestTFunctionList() Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); + // test error throwing: + Assert.Throws(() => db.TFunctionList(verbose : 8)); var functions = db.TFunctionList(verbose : 1); Assert.Equal(3, functions.Length); @@ -60,6 +65,7 @@ public void TestTFunctionList() } [Fact] + [Trait("Category", "edge")] public async Task TestTFunctionListAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -83,6 +89,7 @@ public async Task TestTFunctionListAsync() } [Fact] + [Trait("Category", "edge")] public void TestTFCall() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -96,6 +103,7 @@ public void TestTFCall() } [Fact] + [Trait("Category", "edge")] public async Task TestTFCallAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -109,12 +117,13 @@ public async Task TestTFCallAsync() } [Fact] + [Trait("Category", "edge")] public void TestGearsCommandBuilder() { // TFunctionLoad: var buildCommand = GearsCommandBuilder .TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})", - "config", true); + true, "config"); var expected = new List { "LOAD", From b929cb4f7781cf14539b0f23b6895ad5e6b89c7f Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 7 Jun 2023 14:53:49 +0300 Subject: [PATCH 14/18] wip --- src/NRedisStack/Gears/GearsCommandsAsync.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NRedisStack/Gears/GearsCommandsAsync.cs b/src/NRedisStack/Gears/GearsCommandsAsync.cs index e7d7fa87..c0b65912 100644 --- a/src/NRedisStack/Gears/GearsCommandsAsync.cs +++ b/src/NRedisStack/Gears/GearsCommandsAsync.cs @@ -18,7 +18,7 @@ public static class GearsCommandsAsync //: IGearsCommandsAsync /// //TODO: add link to the command when it's available public static async Task TFunctionLoadAsync(this IDatabase db, string libraryCode, string? config = null, bool replace = false) { - return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionLoad(libraryCode, config, replace))).OKtoBoolean(); + return (await db.ExecuteAsync(GearsCommandBuilder.TFunctionLoad(libraryCode, replace, config))).OKtoBoolean(); } /// From 042e3f2e92ad6e9b4b2ce3fc38b315c53e0b2d9c Mon Sep 17 00:00:00 2001 From: shacharPash Date: Mon, 26 Jun 2023 17:24:35 +0300 Subject: [PATCH 15/18] TryDeleteLib --- tests/NRedisStack.Tests/Gears/GearsTests.cs | 31 +++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 7ffe3b84..e9029a41 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -22,17 +22,18 @@ public void TestTFunctionLoadDelete() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(db.TFunctionDelete("lib")); } + [Fact] [Trait("Category", "edge")] public async Task TestTFunctionLoadDeleteAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); + TryDeleteLib(db, "lib"); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(await db.TFunctionDeleteAsync("lib")); @@ -44,14 +45,15 @@ public void TestTFunctionList() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); + TryDeleteLib(db, "lib1", "lib2", "lib3"); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); // test error throwing: - Assert.Throws(() => db.TFunctionList(verbose : 8)); - var functions = db.TFunctionList(verbose : 1); + Assert.Throws(() => db.TFunctionList(verbose: 8)); + var functions = db.TFunctionList(verbose: 1); Assert.Equal(3, functions.Length); Assert.Equal("lib1", functions[0]["name"].ToString()); @@ -70,12 +72,13 @@ public async Task TestTFunctionListAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); + TryDeleteLib(db, "lib1", "lib2", "lib3"); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); - var functions = await db.TFunctionListAsync(verbose : 1); + var functions = await db.TFunctionListAsync(verbose: 1); Assert.Equal(3, functions.Length); Assert.Equal("lib1", functions[0]["name"].ToString()); @@ -94,10 +97,11 @@ public void TestTFCall() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); + TryDeleteLib(db, "lib"); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.Equal("bar", db.TFCall("lib", "foo", async : false).ToString()); - Assert.Equal("bar", db.TFCall("lib", "foo", async : true).ToString()); + Assert.Equal("bar", db.TFCall("lib", "foo", async: false).ToString()); + Assert.Equal("bar", db.TFCall("lib", "foo", async: true).ToString()); Assert.True(db.TFunctionDelete("lib")); } @@ -108,10 +112,11 @@ public async Task TestTFCallAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); + TryDeleteLib(db, "lib"); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async : false)).ToString()); - Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async : true)).ToString()); + Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async: false)).ToString()); + Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async: true)).ToString()); Assert.True(await db.TFunctionDeleteAsync("lib")); } @@ -179,4 +184,14 @@ public void TestGearsCommandBuilder() Assert.Equal("TFCALLASYNC", buildAsync.Command); Assert.Equal(expected, buildAsync.Args); } + + private static void TryDeleteLib(IDatabase db, params string[] libNames) + { + try + { + foreach(var libName in libNames) + db.TFunctionDelete(libName); + } + catch (RedisServerException) { } + } } From 8f1fbbc44c54bf8e42276b785c64ba93815e3999 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 27 Jun 2023 11:21:36 +0300 Subject: [PATCH 16/18] Try to delete all optional libs before test and more fixes --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 2 +- tests/NRedisStack.Tests/Gears/GearsTests.cs | 32 +++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index f3826a88..65b50a07 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -58,7 +58,7 @@ public static SerializedCommand TFunctionList(bool withCode = false, int verbose public static SerializedCommand TFCall(string libraryName, string functionName, string[]? keys = null, string[]? args = null, bool async = false) { string command = async ? "TFCALLASYNC" : "TFCALL"; - var commandArgs = new List() {libraryName, functionName}; + var commandArgs = new List() {$"{libraryName}.{functionName}"}; if (keys != null) { diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index e9029a41..f9a88511 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -33,7 +33,7 @@ public async Task TestTFunctionLoadDeleteAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - TryDeleteLib(db, "lib"); + TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(await db.TFunctionDeleteAsync("lib")); @@ -45,7 +45,7 @@ public void TestTFunctionList() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - TryDeleteLib(db, "lib1", "lib2", "lib3"); + TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); @@ -56,9 +56,14 @@ public void TestTFunctionList() var functions = db.TFunctionList(verbose: 1); Assert.Equal(3, functions.Length); - Assert.Equal("lib1", functions[0]["name"].ToString()); - Assert.Equal("lib2", functions[1]["name"].ToString()); - Assert.Equal("lib3", functions[2]["name"].ToString()); + HashSet expectedNames = new HashSet { "lib1", "lib2", "lib3" }; + HashSet actualNames = new HashSet{ + functions[0]["name"].ToString()!, + functions[1]["name"].ToString()!, + functions[2]["name"].ToString()! + }; + + Assert.Equal(expectedNames, actualNames); Assert.True(db.TFunctionDelete("lib1")); @@ -72,7 +77,7 @@ public async Task TestTFunctionListAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - TryDeleteLib(db, "lib1", "lib2", "lib3"); + TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); @@ -81,9 +86,14 @@ public async Task TestTFunctionListAsync() var functions = await db.TFunctionListAsync(verbose: 1); Assert.Equal(3, functions.Length); - Assert.Equal("lib1", functions[0]["name"].ToString()); - Assert.Equal("lib2", functions[1]["name"].ToString()); - Assert.Equal("lib3", functions[2]["name"].ToString()); + HashSet expectedNames = new HashSet { "lib1", "lib2", "lib3" }; + HashSet actualNames = new HashSet{ + functions[0]["name"].ToString()!, + functions[1]["name"].ToString()!, + functions[2]["name"].ToString()! + }; + + Assert.Equal(expectedNames, actualNames); Assert.True(await db.TFunctionDeleteAsync("lib1")); @@ -97,7 +107,7 @@ public void TestTFCall() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - TryDeleteLib(db, "lib"); + TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.Equal("bar", db.TFCall("lib", "foo", async: false).ToString()); @@ -112,7 +122,7 @@ public async Task TestTFCallAsync() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - TryDeleteLib(db, "lib"); + TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async: false)).ToString()); From 6c84e0992d150885b4685cdc51e5038bcb25268f Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 27 Jun 2023 12:45:48 +0300 Subject: [PATCH 17/18] fix test --- tests/NRedisStack.Tests/Gears/GearsTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index f9a88511..5f6c4831 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -179,8 +179,7 @@ public void TestGearsCommandBuilder() expected = new List { - "libName", - "funcName", + "libName.funcName", 2, "key1", "key2", From 704aa6d6e8b76f22acd9ab481b811b4250695dff Mon Sep 17 00:00:00 2001 From: shacharPash Date: Thu, 29 Jun 2023 14:23:22 +0300 Subject: [PATCH 18/18] use saved strings --- src/NRedisStack/Gears/GearsCommandBuilder.cs | 16 +++++----- src/NRedisStack/Gears/Literals/CommandArgs.cs | 5 ++++ src/NRedisStack/Gears/Literals/Commands.cs | 12 ++++++++ tests/NRedisStack.Tests/Gears/GearsTests.cs | 29 +++++++++++-------- 4 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 src/NRedisStack/Gears/Literals/Commands.cs diff --git a/src/NRedisStack/Gears/GearsCommandBuilder.cs b/src/NRedisStack/Gears/GearsCommandBuilder.cs index 65b50a07..31d8c73c 100644 --- a/src/NRedisStack/Gears/GearsCommandBuilder.cs +++ b/src/NRedisStack/Gears/GearsCommandBuilder.cs @@ -7,7 +7,7 @@ public static class GearsCommandBuilder { public static SerializedCommand TFunctionLoad(string libraryCode, bool replace = false, string? config = null) { - var args = new List() { "LOAD" }; + var args = new List() { GearsArgs.LOAD }; if (replace) { @@ -20,21 +20,21 @@ public static SerializedCommand TFunctionLoad(string libraryCode, bool replace = args.Add(config); } args.Add(libraryCode); - return new SerializedCommand("TFUNCTION", args); + return new SerializedCommand(RG.TFUNCTION, args); } public static SerializedCommand TFunctionDelete(string libraryName) { - return new SerializedCommand("TFUNCTION", "DELETE", libraryName); + return new SerializedCommand(RG.TFUNCTION, GearsArgs.DELETE, libraryName); } public static SerializedCommand TFunctionList(bool withCode = false, int verbose = 0, string? libraryName = null) { - var args = new List() { "LIST" }; + var args = new List() { GearsArgs.LIST }; if (withCode) { - args.Add("WITHCODE"); + args.Add(GearsArgs.WITHCODE); } if (verbose > 0 && verbose < 4) @@ -48,16 +48,16 @@ public static SerializedCommand TFunctionList(bool withCode = false, int verbose if (libraryName != null) { - args.Add("LIBRARY"); + args.Add(GearsArgs.LIBRARY); args.Add(libraryName); } - return new SerializedCommand("TFUNCTION", args); + return new SerializedCommand(RG.TFUNCTION, args); } public static SerializedCommand TFCall(string libraryName, string functionName, string[]? keys = null, string[]? args = null, bool async = false) { - string command = async ? "TFCALLASYNC" : "TFCALL"; + string command = async ? RG.TFCALLASYNC : RG.TFCALL; var commandArgs = new List() {$"{libraryName}.{functionName}"}; if (keys != null) diff --git a/src/NRedisStack/Gears/Literals/CommandArgs.cs b/src/NRedisStack/Gears/Literals/CommandArgs.cs index a2cfeed1..4c9a44a9 100644 --- a/src/NRedisStack/Gears/Literals/CommandArgs.cs +++ b/src/NRedisStack/Gears/Literals/CommandArgs.cs @@ -4,5 +4,10 @@ internal class GearsArgs { public const string CONFIG = "CONFIG"; public const string REPLACE = "REPLACE"; + public const string LOAD = "LOAD"; + public const string DELETE = "DELETE"; + public const string LIST = "LIST"; + public const string WITHCODE = "WITHCODE"; + public const string LIBRARY = "LIBRARY"; } } diff --git a/src/NRedisStack/Gears/Literals/Commands.cs b/src/NRedisStack/Gears/Literals/Commands.cs new file mode 100644 index 00000000..7a34dd7e --- /dev/null +++ b/src/NRedisStack/Gears/Literals/Commands.cs @@ -0,0 +1,12 @@ +namespace NRedisStack.Gears.Literals +{ + /// + /// RedisGears command literals + /// + internal class RG + { + public const string TFUNCTION = "TFUNCTION"; + public const string TFCALL = "TFCALL"; + public const string TFCALLASYNC = "TFCALLASYNC"; + } +} diff --git a/tests/NRedisStack.Tests/Gears/GearsTests.cs b/tests/NRedisStack.Tests/Gears/GearsTests.cs index 5f6c4831..79d7f7ae 100644 --- a/tests/NRedisStack.Tests/Gears/GearsTests.cs +++ b/tests/NRedisStack.Tests/Gears/GearsTests.cs @@ -22,7 +22,7 @@ public void TestTFunctionLoadDelete() { IDatabase db = redisFixture.Redis.GetDatabase(); db.Execute("FLUSHALL"); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionLoad(GenerateLibCode("lib"))); Assert.True(db.TFunctionDelete("lib")); } @@ -35,7 +35,7 @@ public async Task TestTFunctionLoadDeleteAsync() db.Execute("FLUSHALL"); TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); - Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(await db.TFunctionLoadAsync(GenerateLibCode("lib"))); Assert.True(await db.TFunctionDeleteAsync("lib")); } @@ -47,9 +47,9 @@ public void TestTFunctionList() db.Execute("FLUSHALL"); TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionLoad(GenerateLibCode("lib1"))); + Assert.True(db.TFunctionLoad(GenerateLibCode("lib2"))); + Assert.True(db.TFunctionLoad(GenerateLibCode("lib3"))); // test error throwing: Assert.Throws(() => db.TFunctionList(verbose: 8)); @@ -79,9 +79,9 @@ public async Task TestTFunctionListAsync() db.Execute("FLUSHALL"); TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); - Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib1\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib2\n redis.registerFunction('foo', ()=>{return 'bar'})")); - Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib3\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(await db.TFunctionLoadAsync(GenerateLibCode("lib1"))); + Assert.True(await db.TFunctionLoadAsync(GenerateLibCode("lib2"))); + Assert.True(await db.TFunctionLoadAsync(GenerateLibCode("lib3"))); var functions = await db.TFunctionListAsync(verbose: 1); Assert.Equal(3, functions.Length); @@ -109,7 +109,7 @@ public void TestTFCall() db.Execute("FLUSHALL"); TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); - Assert.True(db.TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(db.TFunctionLoad(GenerateLibCode("lib"))); Assert.Equal("bar", db.TFCall("lib", "foo", async: false).ToString()); Assert.Equal("bar", db.TFCall("lib", "foo", async: true).ToString()); @@ -124,7 +124,7 @@ public async Task TestTFCallAsync() db.Execute("FLUSHALL"); TryDeleteLib(db, "lib", "lib1", "lib2", "lib3"); - Assert.True(await db.TFunctionLoadAsync("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})")); + Assert.True(await db.TFunctionLoadAsync(GenerateLibCode("lib"))); Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async: false)).ToString()); Assert.Equal("bar", (await db.TFCallAsync("lib", "foo", async: true)).ToString()); @@ -137,7 +137,7 @@ public void TestGearsCommandBuilder() { // TFunctionLoad: var buildCommand = GearsCommandBuilder - .TFunctionLoad("#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})", + .TFunctionLoad(GenerateLibCode("lib"), true, "config"); var expected = new List { @@ -145,7 +145,7 @@ public void TestGearsCommandBuilder() "REPLACE", "CONFIG", "config", - "#!js api_version=1.0 name=lib\n redis.registerFunction('foo', ()=>{return 'bar'})" + GenerateLibCode("lib") }; Assert.Equal("TFUNCTION", buildCommand.Command); Assert.Equal(expected, buildCommand.Args); @@ -203,4 +203,9 @@ private static void TryDeleteLib(IDatabase db, params string[] libNames) } catch (RedisServerException) { } } + + private static string GenerateLibCode(string libName) + { + return $"#!js api_version=1.0 name={libName}\n redis.registerFunction('foo', ()=>{{return 'bar'}})"; + } }