From 05b1ec094c934f7fc59ba77583786e0fa487bda8 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 22 Nov 2023 18:29:22 +0200 Subject: [PATCH 01/12] first step --- src/NRedisStack/Auxiliary.cs | 41 --- .../NRedisStackConnectionMultiplexer.cs | 40 +++ src/NRedisStack/RedisUriParser.cs | 113 ++++++++ .../Core Commands/CoreTests.cs | 262 +++++++++--------- .../NRedisStackConfigurationTests.cs | 23 ++ 5 files changed, 307 insertions(+), 172 deletions(-) create mode 100644 src/NRedisStack/NRedisStackConnectionMultiplexer.cs create mode 100644 src/NRedisStack/RedisUriParser.cs create mode 100644 tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs diff --git a/src/NRedisStack/Auxiliary.cs b/src/NRedisStack/Auxiliary.cs index d5555fb7..fcb91875 100644 --- a/src/NRedisStack/Auxiliary.cs +++ b/src/NRedisStack/Auxiliary.cs @@ -1,4 +1,3 @@ -using NRedisStack.Core; using NRedisStack.RedisStackCommands; using StackExchange.Redis; @@ -6,13 +5,6 @@ namespace NRedisStack { public static class Auxiliary { - private static string? _libraryName = $"NRedisStack;.NET-{Environment.Version}"; - private static bool _setInfo = true; - public static void ResetInfoDefaults() - { - _setInfo = true; - _libraryName = $"NRedisStack;.NET-{Environment.Version}"; - } public static List MergeArgs(RedisKey key, params RedisValue[] items) { var args = new List(items.Length + 1) { key }; @@ -36,48 +28,15 @@ public static object[] AssembleNonNullArguments(params object?[] arguments) // public static IDatabase GetDatabase(this ConnectionMultiplexer redis) => redis.GetDatabase("", ""); - // TODO: add all the signatures of GetDatabase - public static IDatabase GetDatabase(this ConnectionMultiplexer redis, - string? LibraryName) - { - var _db = redis.GetDatabase(); - if (LibraryName == null) // the user wants to disable the library name and version sending - _setInfo = false; - - else // the user set his own the library name - _libraryName = $"NRedisStack({LibraryName});.NET-{Environment.Version})"; - - return _db; - } - - private static void SetInfoInPipeline(this IDatabase db) - { - if (_libraryName == null) return; - Pipeline pipeline = new Pipeline(db); - _ = pipeline.Db.ClientSetInfoAsync(SetInfoAttr.LibraryName, _libraryName!); - _ = pipeline.Db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); - pipeline.Execute(); - } public static RedisResult Execute(this IDatabase db, SerializedCommand command) { - var compareVersions = db.Multiplexer.GetServer(db.Multiplexer.GetEndPoints()[0]).Version.CompareTo(new Version(7, 1, 242)); - if (_setInfo && compareVersions >= 0) - { - _setInfo = false; - db.SetInfoInPipeline(); - } return db.Execute(command.Command, command.Args); } public async static Task ExecuteAsync(this IDatabaseAsync db, SerializedCommand command) { var compareVersions = db.Multiplexer.GetServer(db.Multiplexer.GetEndPoints()[0]).Version.CompareTo(new Version(7, 1, 242)); - if (_setInfo && compareVersions >= 0) - { - _setInfo = false; - ((IDatabase)db).SetInfoInPipeline(); - } return await db.ExecuteAsync(command.Command, command.Args); } diff --git a/src/NRedisStack/NRedisStackConnectionMultiplexer.cs b/src/NRedisStack/NRedisStackConnectionMultiplexer.cs new file mode 100644 index 00000000..86f2d9db --- /dev/null +++ b/src/NRedisStack/NRedisStackConnectionMultiplexer.cs @@ -0,0 +1,40 @@ +using StackExchange.Redis; + +namespace NRedisStack +{ + public static class NRedisStackConnectionMultiplexer // check if I can use this name to ConnectionMultiplexer + { + public static ConnectionMultiplexer Connect(string redisConnectionString) + { + var options = RedisUriParser.ParseConfigFromUri(redisConnectionString); + return Connect(options); + } + + public static Task ConnectAsync(string redisConnectionString) + { + var options = RedisUriParser.ParseConfigFromUri(redisConnectionString); + return ConnectAsync(options); + } + public static ConnectionMultiplexer Connect(ConfigurationOptions options) + { + SetLibName(options); + // TODO: set here the library version when it will be available + return ConnectionMultiplexer.Connect(options); + } + public static Task ConnectAsync(ConfigurationOptions options) + { + SetLibName(options); + // TODO: set here the library version when it will be available + return ConnectionMultiplexer.ConnectAsync(options); + } + + private static void SetLibName(ConfigurationOptions options) + { + if (options.LibraryName != null) // the user set his own the library name + options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; + else // the default library name and version sending + options.LibraryName = $"NRedisStack;.NET-{Environment.Version}"; + + } + } +} \ No newline at end of file diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs new file mode 100644 index 00000000..8bad4cf5 --- /dev/null +++ b/src/NRedisStack/RedisUriParser.cs @@ -0,0 +1,113 @@ +using System.Runtime.CompilerServices; +using System.Text.RegularExpressions; +using StackExchange.Redis; + +[assembly: InternalsVisibleTo("NRedisStack.Tests")] + +namespace NRedisStack +{ + /// + /// URI parsing utility. + /// + internal static class RedisUriParser + { + /// + /// Parses a Config options for StackExchange Redis from the URI. + /// + /// Redis Uri string + /// A configuration options result for SE.Redis. + internal static ConfigurationOptions ParseConfigFromUri(string redisUri) + { + var options = new ConfigurationOptions(); + + if (string.IsNullOrEmpty(redisUri)) + { + options.EndPoints.Add("localhost:6379"); + return options; + } + + var uri = new Uri(redisUri); + ParseHost(options, uri); + ParseUserInfo(options, uri); + ParseQueryArguments(options, uri); + ParseDefaultDatabase(options, uri); + options.Ssl = uri.Scheme == "rediss"; + options.AbortOnConnectFail = false; + return options; + } + + private static void ParseDefaultDatabase(ConfigurationOptions options, Uri uri) + { + if (string.IsNullOrEmpty(uri.AbsolutePath)) + { + return; + } + + var dbNumStr = Regex.Match(uri.AbsolutePath, "[0-9]+").Value; + int dbNum; + if (int.TryParse(dbNumStr, out dbNum)) + { + options.DefaultDatabase = dbNum; + } + } + + private static IList> ParseQuery(string query) => + query.Split('&').Select(x => + new KeyValuePair(x.Split('=').First(), x.Split('=').Last())).ToList(); + + private static void ParseUserInfo(ConfigurationOptions options, Uri uri) + { + if (!string.IsNullOrEmpty(uri.UserInfo)) + { + var userInfo = uri.UserInfo.Split(':'); + if (userInfo.Length > 1) + { + options.User = Uri.UnescapeDataString(userInfo[0]); + options.Password = Uri.UnescapeDataString(userInfo[1]); + } + else + { + throw new FormatException( + "Username and password must be in the form username:password - if there is no username use the format :password"); + } + } + } + + private static void ParseHost(ConfigurationOptions options, Uri uri) + { + var port = uri.Port >= 0 ? uri.Port : 6379; + var host = !string.IsNullOrEmpty(uri.Host) ? uri.Host : "localhost"; + options.EndPoints.Add($"{host}:{port}"); + } + + private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) + { + if (!string.IsNullOrEmpty(uri.Query)) + { + var queryArgs = ParseQuery(uri.Query.Substring(1)); + if (queryArgs.Any(x => x.Key == "timeout")) + { + var timeout = int.Parse(queryArgs.First(x => x.Key == "timeout").Value); + options.AsyncTimeout = timeout; + options.SyncTimeout = timeout; + options.ConnectTimeout = timeout; + } + + if (queryArgs.Any(x => x.Key.ToLower() == "clientname")) + { + options.ClientName = queryArgs.First(x => x.Key.ToLower() == "clientname").Value; + } + + if (queryArgs.Any(x => x.Key.ToLower() == "sentinel_primary_name")) + { + options.ServiceName = queryArgs.First(x => x.Key.ToLower() == "sentinel_primary_name").Value; + } + + foreach (var endpoint in queryArgs.Where(x => x.Key == "endpoint").Select(x => x.Value)) + { + options.EndPoints.Add(endpoint); + } + } + } + } +} diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs index d403dec2..e92daf3b 100644 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs @@ -15,135 +15,135 @@ public class CoreTests : AbstractNRedisStackTest, IDisposable public CoreTests(RedisFixture redisFixture) : base(redisFixture) { } - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public void TestSimpleSetInfo() - { - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase(); - db.Execute("FLUSHALL"); - - db.ClientSetInfo(SetInfoAttr.LibraryName, "TestLibraryName"); - db.ClientSetInfo(SetInfoAttr.LibraryVersion, "1.2.3"); - - var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=TestLibraryName lib-ver=1.2.3\n", info); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public async Task TestSimpleSetInfoAsync() - { - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase(); - db.Execute("FLUSHALL"); - - await db.ClientSetInfoAsync(SetInfoAttr.LibraryName, "TestLibraryName"); - await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, "1.2.3"); - - var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=TestLibraryName lib-ver=1.2.3\n", info); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public void TestSetInfoDefaultValue() - { - ResetInfoDefaults(); // demonstrate first connection - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase(); - db.Execute("FLUSHALL"); - - db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public async Task TestSetInfoDefaultValueAsync() - { - ResetInfoDefaults(); // demonstrate first connection - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase(); - db.Execute("FLUSHALL"); - - await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - var info = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public void TestSetInfoWithValue() - { - ResetInfoDefaults(); // demonstrate first connection - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase("MyLibraryName;v1.0.0"); - db.Execute("FLUSHALL"); - - db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"NRedisStack(MyLibraryName;v1.0.0);.NET-{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public async Task TestSetInfoWithValueAsync() - { - ResetInfoDefaults(); // demonstrate first connection - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase("MyLibraryName;v1.0.0"); - db.Execute("FLUSHALL"); - - await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - var info = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - Assert.EndsWith($"NRedisStack(MyLibraryName;v1.0.0);.NET-{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public void TestSetInfoNull() - { - ResetInfoDefaults(); // demonstrate first connection - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase(null); - - db.Execute("FLUSHALL"); - var infoBefore = db.Execute("CLIENT", "INFO").ToString(); - db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - var infoAfter = db.Execute("CLIENT", "INFO").ToString(); - // Find the indices of "lib-name=" in the strings - int infoAfterLibNameIndex = infoAfter!.IndexOf("lib-name="); - int infoBeforeLibNameIndex = infoBefore!.IndexOf("lib-name="); - - // Extract the sub-strings starting from "lib-name=" - string infoAfterLibNameToEnd = infoAfter.Substring(infoAfterLibNameIndex); - string infoBeforeLibNameToEnd = infoBefore.Substring(infoBeforeLibNameIndex); - - // Assert that the extracted sub-strings are equal - Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); - } - - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - public async Task TestSetInfoNullAsync() - { - ResetInfoDefaults(); // demonstrate first connection - var redis = ConnectionMultiplexer.Connect("localhost"); - var db = redis.GetDatabase(null); - - db.Execute("FLUSHALL"); - var infoBefore = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - var infoAfter = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - // Find the indices of "lib-name=" in the strings - int infoAfterLibNameIndex = infoAfter!.IndexOf("lib-name="); - int infoBeforeLibNameIndex = infoBefore!.IndexOf("lib-name="); - - // Extract the sub-strings starting from "lib-name=" - string infoAfterLibNameToEnd = infoAfter.Substring(infoAfterLibNameIndex); - string infoBeforeLibNameToEnd = infoBefore.Substring(infoBeforeLibNameIndex); - - // Assert that the extracted sub-strings are equal - Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); - } + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public void TestSimpleSetInfo() + // { + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase(); + // db.Execute("FLUSHALL"); + + // db.ClientSetInfo(SetInfoAttr.LibraryName, "TestLibraryName"); + // db.ClientSetInfo(SetInfoAttr.LibraryVersion, "1.2.3"); + + // var info = db.Execute("CLIENT", "INFO").ToString(); + // Assert.EndsWith($"lib-name=TestLibraryName lib-ver=1.2.3\n", info); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public async Task TestSimpleSetInfoAsync() + // { + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase(); + // db.Execute("FLUSHALL"); + + // await db.ClientSetInfoAsync(SetInfoAttr.LibraryName, "TestLibraryName"); + // await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, "1.2.3"); + + // var info = db.Execute("CLIENT", "INFO").ToString(); + // Assert.EndsWith($"lib-name=TestLibraryName lib-ver=1.2.3\n", info); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public void TestSetInfoDefaultValue() + // { + // ResetInfoDefaults(); // demonstrate first connection + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase(); + // db.Execute("FLUSHALL"); + + // db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. + + // var info = db.Execute("CLIENT", "INFO").ToString(); + // Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public async Task TestSetInfoDefaultValueAsync() + // { + // ResetInfoDefaults(); // demonstrate first connection + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase(); + // db.Execute("FLUSHALL"); + + // await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. + + // var info = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); + // Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public void TestSetInfoWithValue() + // { + // ResetInfoDefaults(); // demonstrate first connection + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase("MyLibraryName;v1.0.0"); + // db.Execute("FLUSHALL"); + + // db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. + + // var info = db.Execute("CLIENT", "INFO").ToString(); + // Assert.EndsWith($"NRedisStack(MyLibraryName;v1.0.0);.NET-{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public async Task TestSetInfoWithValueAsync() + // { + // ResetInfoDefaults(); // demonstrate first connection + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase("MyLibraryName;v1.0.0"); + // db.Execute("FLUSHALL"); + + // await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. + + // var info = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); + // Assert.EndsWith($"NRedisStack(MyLibraryName;v1.0.0);.NET-{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public void TestSetInfoNull() + // { + // ResetInfoDefaults(); // demonstrate first connection + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase(null); + + // db.Execute("FLUSHALL"); + // var infoBefore = db.Execute("CLIENT", "INFO").ToString(); + // db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. + + // var infoAfter = db.Execute("CLIENT", "INFO").ToString(); + // // Find the indices of "lib-name=" in the strings + // int infoAfterLibNameIndex = infoAfter!.IndexOf("lib-name="); + // int infoBeforeLibNameIndex = infoBefore!.IndexOf("lib-name="); + + // // Extract the sub-strings starting from "lib-name=" + // string infoAfterLibNameToEnd = infoAfter.Substring(infoAfterLibNameIndex); + // string infoBeforeLibNameToEnd = infoBefore.Substring(infoBeforeLibNameIndex); + + // // Assert that the extracted sub-strings are equal + // Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); + // } + + // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + // public async Task TestSetInfoNullAsync() + // { + // ResetInfoDefaults(); // demonstrate first connection + // var redis = ConnectionMultiplexer.Connect("localhost"); + // var db = redis.GetDatabase(null); + + // db.Execute("FLUSHALL"); + // var infoBefore = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); + // await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. + + // var infoAfter = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); + // // Find the indices of "lib-name=" in the strings + // int infoAfterLibNameIndex = infoAfter!.IndexOf("lib-name="); + // int infoBeforeLibNameIndex = infoBefore!.IndexOf("lib-name="); + + // // Extract the sub-strings starting from "lib-name=" + // string infoAfterLibNameToEnd = infoAfter.Substring(infoAfterLibNameIndex); + // string infoBeforeLibNameToEnd = infoBefore.Substring(infoBeforeLibNameIndex); + + // // Assert that the extracted sub-strings are equal + // Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); + // } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs new file mode 100644 index 00000000..0bcc7090 --- /dev/null +++ b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs @@ -0,0 +1,23 @@ +using Xunit; +using NRedisStack.Core; +using static NRedisStack.Auxiliary; + + +namespace NRedisStack.Tests.Core; + +public class NRedisStackConfigurationTests : AbstractNRedisStackTest, IDisposable +{ + public NRedisStackConfigurationTests(RedisFixture redisFixture) : base(redisFixture) { } + + // TODO: add tests + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public void TestDefaultLibName() + { + var options = RedisUriParser.ParseConfigFromUri("redis://localhost"); + var db = NRedisStackConnectionMultiplexer.Connect(options).GetDatabase(); + db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + } +} \ No newline at end of file From 468362bcd8d7769d42ca3a459bcfc0931871e131 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 26 Nov 2023 17:54:20 +0200 Subject: [PATCH 02/12] add NRedisStackConfigurationOptions --- .../NRedisStackConfigurationOptions.cs | 36 +++++++++++++ .../NRedisStackConnectionMultiplexer.cs | 25 +++------- src/NRedisStack/RedisUriParser.cs | 50 +++++++++++-------- .../NRedisStackConfigurationTests.cs | 2 +- 4 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 src/NRedisStack/NRedisStackConfigurationOptions.cs diff --git a/src/NRedisStack/NRedisStackConfigurationOptions.cs b/src/NRedisStack/NRedisStackConfigurationOptions.cs new file mode 100644 index 00000000..0abb491b --- /dev/null +++ b/src/NRedisStack/NRedisStackConfigurationOptions.cs @@ -0,0 +1,36 @@ +using NRedisStack.RedisStackCommands; +using StackExchange.Redis; + +namespace NRedisStack +{ + public class NRedisStackConfigurationOptions + { + private readonly ConfigurationOptions _configurationOptions = new ConfigurationOptions(); + + public NRedisStackConfigurationOptions(string redisConnectionString) + { + _configurationOptions = RedisUriParser.FromUri(redisConnectionString); + SetLibName(_configurationOptions); + } + + + NRedisStackConfigurationOptions() + { + SetLibName(_configurationOptions); + } + + public ConfigurationOptions GetConfigurationOptions() + { + return _configurationOptions; + } + + private static void SetLibName(ConfigurationOptions options) + { + if (options.LibraryName != null) // the user set his own the library name + options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; + else // the default library name and version sending + options.LibraryName = $"NRedisStack;.NET-{Environment.Version}"; + } + + } +} \ No newline at end of file diff --git a/src/NRedisStack/NRedisStackConnectionMultiplexer.cs b/src/NRedisStack/NRedisStackConnectionMultiplexer.cs index 86f2d9db..7e92f303 100644 --- a/src/NRedisStack/NRedisStackConnectionMultiplexer.cs +++ b/src/NRedisStack/NRedisStackConnectionMultiplexer.cs @@ -6,35 +6,22 @@ public static class NRedisStackConnectionMultiplexer // check if I can use this { public static ConnectionMultiplexer Connect(string redisConnectionString) { - var options = RedisUriParser.ParseConfigFromUri(redisConnectionString); + var options = new NRedisStackConfigurationOptions(redisConnectionString); return Connect(options); } public static Task ConnectAsync(string redisConnectionString) { - var options = RedisUriParser.ParseConfigFromUri(redisConnectionString); + var options = new NRedisStackConfigurationOptions(redisConnectionString); return ConnectAsync(options); } - public static ConnectionMultiplexer Connect(ConfigurationOptions options) + public static ConnectionMultiplexer Connect(NRedisStackConfigurationOptions options) { - SetLibName(options); - // TODO: set here the library version when it will be available - return ConnectionMultiplexer.Connect(options); + return ConnectionMultiplexer.Connect(options.GetConfigurationOptions()); } - public static Task ConnectAsync(ConfigurationOptions options) + public static Task ConnectAsync(NRedisStackConfigurationOptions options) { - SetLibName(options); - // TODO: set here the library version when it will be available - return ConnectionMultiplexer.ConnectAsync(options); - } - - private static void SetLibName(ConfigurationOptions options) - { - if (options.LibraryName != null) // the user set his own the library name - options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; - else // the default library name and version sending - options.LibraryName = $"NRedisStack;.NET-{Environment.Version}"; - + return ConnectionMultiplexer.ConnectAsync(options.GetConfigurationOptions()); } } } \ No newline at end of file diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index 8bad4cf5..d20d8e48 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -16,7 +16,7 @@ internal static class RedisUriParser /// /// Redis Uri string /// A configuration options result for SE.Redis. - internal static ConfigurationOptions ParseConfigFromUri(string redisUri) + internal static ConfigurationOptions FromUri(string redisUri) { var options = new ConfigurationOptions(); @@ -82,32 +82,38 @@ private static void ParseHost(ConfigurationOptions options, Uri uri) private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) { - if (!string.IsNullOrEmpty(uri.Query)) + if (string.IsNullOrEmpty(uri.Query)) { - var queryArgs = ParseQuery(uri.Query.Substring(1)); - if (queryArgs.Any(x => x.Key == "timeout")) - { - var timeout = int.Parse(queryArgs.First(x => x.Key == "timeout").Value); - options.AsyncTimeout = timeout; - options.SyncTimeout = timeout; - options.ConnectTimeout = timeout; - } + return; + } - if (queryArgs.Any(x => x.Key.ToLower() == "clientname")) - { - options.ClientName = queryArgs.First(x => x.Key.ToLower() == "clientname").Value; - } + var queryArgs = ParseQuery(uri.Query.Substring(1)); - if (queryArgs.Any(x => x.Key.ToLower() == "sentinel_primary_name")) - { - options.ServiceName = queryArgs.First(x => x.Key.ToLower() == "sentinel_primary_name").Value; - } + var actions = new Dictionary>(StringComparer.OrdinalIgnoreCase) + { + { "timeout", value => SetTimeoutOptions(options, value) }, + { "clientname", value => options.ClientName = value }, + { "sentinel_primary_name", value => options.ServiceName = value }, + { "endpoint", value => options.EndPoints.Add(value) }, + { "allowadmin", value => options.AllowAdmin = bool.Parse(value) }, + { "abortConnect", value => options.AbortOnConnectFail = bool.Parse(value) }, + { "asynctimeout", value => options.AsyncTimeout = int.Parse(value) }, + // TODO: add more options + }; - foreach (var endpoint in queryArgs.Where(x => x.Key == "endpoint").Select(x => x.Value)) - { - options.EndPoints.Add(endpoint); - } + foreach (var arg in queryArgs.Where(arg => actions.ContainsKey(arg.Key))) + { + actions[arg.Key](arg.Value); } } + + private static void SetTimeoutOptions(ConfigurationOptions options, string value) + { + var timeout = int.Parse(value); + options.AsyncTimeout = timeout; + options.SyncTimeout = timeout; + options.ConnectTimeout = timeout; + } + } } diff --git a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs index 0bcc7090..b84b40b2 100644 --- a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs +++ b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs @@ -14,7 +14,7 @@ public class NRedisStackConfigurationTests : AbstractNRedisStackTest, IDisposabl [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] public void TestDefaultLibName() { - var options = RedisUriParser.ParseConfigFromUri("redis://localhost"); + var options = new NRedisStackConfigurationOptions("redis://localhost"); var db = NRedisStackConnectionMultiplexer.Connect(options).GetDatabase(); db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); From 8c96fc99a15cdcc16af9c7d027c278cc2aa7b56c Mon Sep 17 00:00:00 2001 From: shacharPash Date: Mon, 27 Nov 2023 14:51:25 +0200 Subject: [PATCH 03/12] add test --- src/NRedisStack/RedisUriParser.cs | 1 + .../NRedisStackConfigurationTests.cs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index d20d8e48..138c09c8 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -98,6 +98,7 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) { "allowadmin", value => options.AllowAdmin = bool.Parse(value) }, { "abortConnect", value => options.AbortOnConnectFail = bool.Parse(value) }, { "asynctimeout", value => options.AsyncTimeout = int.Parse(value) }, + { "retry", value => options.ConnectRetry = int.Parse(value)} // TODO: add more options }; diff --git a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs index b84b40b2..82df1068 100644 --- a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs +++ b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs @@ -1,6 +1,7 @@ using Xunit; using NRedisStack.Core; using static NRedisStack.Auxiliary; +using System.Net; namespace NRedisStack.Tests.Core; @@ -20,4 +21,28 @@ public void TestDefaultLibName() var info = db.Execute("CLIENT", "INFO").ToString(); Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public async Task TestDefaultLibNameAsync() + { + var options = new NRedisStackConfigurationOptions("redis://localhost"); + var db =(await NRedisStackConnectionMultiplexer.ConnectAsync(options)).GetDatabase(); + await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public void TestNRedisStackConfigurationOptions() + { + var options = new NRedisStackConfigurationOptions("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3"); + Assert.Equal("username", options.GetConfigurationOptions().User); + Assert.Equal("password", options.GetConfigurationOptions().Password); + var endpoint = (DnsEndPoint)options.GetConfigurationOptions().EndPoints.First(); + Assert.Equal("localhost", endpoint.Host); + Assert.Equal(6379, endpoint.Port); + Assert.Equal("client", options.GetConfigurationOptions().ClientName); + Assert.Equal("sentinel", options.GetConfigurationOptions().ServiceName); + Assert.Equal(3, options.GetConfigurationOptions().ConnectRetry); + } } \ No newline at end of file From 36a58229b389a30db509713bb16945ed9afbac3f Mon Sep 17 00:00:00 2001 From: shacharPash Date: Mon, 27 Nov 2023 17:55:05 +0200 Subject: [PATCH 04/12] steve's review --- src/NRedisStack/Configuration.cs | 47 +++++++++++++++++++ src/NRedisStack/ConnectionManager.cs | 37 +++++++++++++++ .../NRedisStackConfigurationOptions.cs | 36 -------------- .../NRedisStackConnectionMultiplexer.cs | 27 ----------- .../NRedisStackConfigurationTests.cs | 38 ++++++++++----- 5 files changed, 111 insertions(+), 74 deletions(-) create mode 100644 src/NRedisStack/Configuration.cs create mode 100644 src/NRedisStack/ConnectionManager.cs delete mode 100644 src/NRedisStack/NRedisStackConfigurationOptions.cs delete mode 100644 src/NRedisStack/NRedisStackConnectionMultiplexer.cs diff --git a/src/NRedisStack/Configuration.cs b/src/NRedisStack/Configuration.cs new file mode 100644 index 00000000..93a059a7 --- /dev/null +++ b/src/NRedisStack/Configuration.cs @@ -0,0 +1,47 @@ +using NRedisStack.RedisStackCommands; +using StackExchange.Redis; + +namespace NRedisStack +{ + public class Configuration + { + private ConfigurationOptions _options = new ConfigurationOptions(); + + public static Configuration Parse(string redisConnectionString) => + new Configuration().DoParse(redisConnectionString); + + public Configuration DoParse(string redisConnectionString) + { + try // Redis URI parsing + { + _options = RedisUriParser.FromUri(redisConnectionString); + } + catch (UriFormatException) // StackExchange.Redis connection string parsing + { + _options = ConfigurationOptions.Parse(redisConnectionString); + } + SetLibName(_options); + return this; + } + + + Configuration() + { + SetLibName(_options); + } + + public ConfigurationOptions GetOptions() + { + return _options; + } + + private static void SetLibName(ConfigurationOptions options) + { + if (options.LibraryName != null) // the user set his own the library name + options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; + else // the default library name and version sending + options.LibraryName = $"NRedisStack;.NET-{Environment.Version}"; + } + + } +} \ No newline at end of file diff --git a/src/NRedisStack/ConnectionManager.cs b/src/NRedisStack/ConnectionManager.cs new file mode 100644 index 00000000..31a885bc --- /dev/null +++ b/src/NRedisStack/ConnectionManager.cs @@ -0,0 +1,37 @@ +using StackExchange.Redis; + +namespace NRedisStack +{ + public static class ConnectionManager + { + public static IConnectionMultiplexer Connect(string redisConnectionString) + { + return Connect(Configuration.Parse(redisConnectionString)); + } + + public static async Task ConnectAsync(string redisConnectionString) + { + return await ConnectAsync(Configuration.Parse(redisConnectionString)); + } + + public static IConnectionMultiplexer Connect(Configuration options) + { + return ConnectionMultiplexer.Connect(options.GetOptions()); + } + + public static async Task ConnectAsync(Configuration options) + { + return await ConnectionMultiplexer.ConnectAsync(options.GetOptions()); + } + + public static IConnectionMultiplexer Connect(ConfigurationOptions options) + { + return ConnectionMultiplexer.Connect(options); + } + + public static async Task ConnectAsync(ConfigurationOptions options) + { + return await ConnectionMultiplexer.ConnectAsync(options); + } + } +} \ No newline at end of file diff --git a/src/NRedisStack/NRedisStackConfigurationOptions.cs b/src/NRedisStack/NRedisStackConfigurationOptions.cs deleted file mode 100644 index 0abb491b..00000000 --- a/src/NRedisStack/NRedisStackConfigurationOptions.cs +++ /dev/null @@ -1,36 +0,0 @@ -using NRedisStack.RedisStackCommands; -using StackExchange.Redis; - -namespace NRedisStack -{ - public class NRedisStackConfigurationOptions - { - private readonly ConfigurationOptions _configurationOptions = new ConfigurationOptions(); - - public NRedisStackConfigurationOptions(string redisConnectionString) - { - _configurationOptions = RedisUriParser.FromUri(redisConnectionString); - SetLibName(_configurationOptions); - } - - - NRedisStackConfigurationOptions() - { - SetLibName(_configurationOptions); - } - - public ConfigurationOptions GetConfigurationOptions() - { - return _configurationOptions; - } - - private static void SetLibName(ConfigurationOptions options) - { - if (options.LibraryName != null) // the user set his own the library name - options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; - else // the default library name and version sending - options.LibraryName = $"NRedisStack;.NET-{Environment.Version}"; - } - - } -} \ No newline at end of file diff --git a/src/NRedisStack/NRedisStackConnectionMultiplexer.cs b/src/NRedisStack/NRedisStackConnectionMultiplexer.cs deleted file mode 100644 index 7e92f303..00000000 --- a/src/NRedisStack/NRedisStackConnectionMultiplexer.cs +++ /dev/null @@ -1,27 +0,0 @@ -using StackExchange.Redis; - -namespace NRedisStack -{ - public static class NRedisStackConnectionMultiplexer // check if I can use this name to ConnectionMultiplexer - { - public static ConnectionMultiplexer Connect(string redisConnectionString) - { - var options = new NRedisStackConfigurationOptions(redisConnectionString); - return Connect(options); - } - - public static Task ConnectAsync(string redisConnectionString) - { - var options = new NRedisStackConfigurationOptions(redisConnectionString); - return ConnectAsync(options); - } - public static ConnectionMultiplexer Connect(NRedisStackConfigurationOptions options) - { - return ConnectionMultiplexer.Connect(options.GetConfigurationOptions()); - } - public static Task ConnectAsync(NRedisStackConfigurationOptions options) - { - return ConnectionMultiplexer.ConnectAsync(options.GetConfigurationOptions()); - } - } -} \ No newline at end of file diff --git a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs index 82df1068..039cb6f4 100644 --- a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs +++ b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs @@ -15,8 +15,7 @@ public class NRedisStackConfigurationTests : AbstractNRedisStackTest, IDisposabl [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] public void TestDefaultLibName() { - var options = new NRedisStackConfigurationOptions("redis://localhost"); - var db = NRedisStackConnectionMultiplexer.Connect(options).GetDatabase(); + var db = ConnectionManager.Connect("redis://localhost").GetDatabase(); db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); @@ -25,8 +24,25 @@ public void TestDefaultLibName() [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] public async Task TestDefaultLibNameAsync() { - var options = new NRedisStackConfigurationOptions("redis://localhost"); - var db =(await NRedisStackConnectionMultiplexer.ConnectAsync(options)).GetDatabase(); + var db = (await ConnectionManager.ConnectAsync("redis://localhost")).GetDatabase(); + await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public void TestDefaultLibNameStackExchangeString() + { + var db = ConnectionManager.Connect("localhost").GetDatabase(); // StackExchange.Redis connection string (without the redis:// at the start) + db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public async Task TestDefaultLibNameStackExchangeStringAsync() + { + var db = (await ConnectionManager.ConnectAsync("localhost")).GetDatabase(); // StackExchange.Redis connection string (without the redis:// at the start) await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); @@ -35,14 +51,14 @@ public async Task TestDefaultLibNameAsync() [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] public void TestNRedisStackConfigurationOptions() { - var options = new NRedisStackConfigurationOptions("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3"); - Assert.Equal("username", options.GetConfigurationOptions().User); - Assert.Equal("password", options.GetConfigurationOptions().Password); - var endpoint = (DnsEndPoint)options.GetConfigurationOptions().EndPoints.First(); + var options = Configuration.Parse("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3"); + Assert.Equal("username", options.GetOptions().User); + Assert.Equal("password", options.GetOptions().Password); + var endpoint = (DnsEndPoint)options.GetOptions().EndPoints.First(); Assert.Equal("localhost", endpoint.Host); Assert.Equal(6379, endpoint.Port); - Assert.Equal("client", options.GetConfigurationOptions().ClientName); - Assert.Equal("sentinel", options.GetConfigurationOptions().ServiceName); - Assert.Equal(3, options.GetConfigurationOptions().ConnectRetry); + Assert.Equal("client", options.GetOptions().ClientName); + Assert.Equal("sentinel", options.GetOptions().ServiceName); + Assert.Equal(3, options.GetOptions().ConnectRetry); } } \ No newline at end of file From 8be3ff5a4485a2a4360301ba990bd1676051ee7e Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 28 Nov 2023 11:59:12 +0200 Subject: [PATCH 05/12] add resp --- src/NRedisStack/NRedisStack.csproj | 2 +- src/NRedisStack/RedisUriParser.cs | 16 +++++++++++++++- tests/Doc/Doc.csproj | 2 +- tests/NRedisStack.Tests/NRedisStack.Tests.csproj | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/NRedisStack/NRedisStack.csproj b/src/NRedisStack/NRedisStack.csproj index 3441d99c..f6f38a58 100644 --- a/src/NRedisStack/NRedisStack.csproj +++ b/src/NRedisStack/NRedisStack.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index 138c09c8..bbece980 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -98,7 +98,8 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) { "allowadmin", value => options.AllowAdmin = bool.Parse(value) }, { "abortConnect", value => options.AbortOnConnectFail = bool.Parse(value) }, { "asynctimeout", value => options.AsyncTimeout = int.Parse(value) }, - { "retry", value => options.ConnectRetry = int.Parse(value)} + { "retry", value => options.ConnectRetry = int.Parse(value) }, + { "protocol", value => ParseRedisProtocol(options, value) } // TODO: add more options }; @@ -108,6 +109,19 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) } } + private static RedisProtocol ParseRedisProtocol(ConfigurationOptions options, string value) + { + switch (value) + { + case "2": + return RedisProtocol.Resp2; + case "3": + return RedisProtocol.Resp3; + default: + throw new FormatException("Invalid protocol specified"); + } + } + private static void SetTimeoutOptions(ConfigurationOptions options, string value) { var timeout = int.Parse(value); diff --git a/tests/Doc/Doc.csproj b/tests/Doc/Doc.csproj index c8fef667..b5ac2836 100644 --- a/tests/Doc/Doc.csproj +++ b/tests/Doc/Doc.csproj @@ -16,7 +16,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj index e66bf0a1..dfba1b20 100644 --- a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj +++ b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj @@ -23,7 +23,7 @@ - + From 21e6a100c90d7758d2606dc6dfd3f6136732752b Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 28 Nov 2023 12:34:47 +0200 Subject: [PATCH 06/12] delete core test file --- .../Core Commands/CoreTests.cs | 149 ------------------ 1 file changed, 149 deletions(-) delete mode 100644 tests/NRedisStack.Tests/Core Commands/CoreTests.cs diff --git a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs b/tests/NRedisStack.Tests/Core Commands/CoreTests.cs deleted file mode 100644 index e92daf3b..00000000 --- a/tests/NRedisStack.Tests/Core Commands/CoreTests.cs +++ /dev/null @@ -1,149 +0,0 @@ -using Xunit; -using NRedisStack.Core; -using NRedisStack; -using static NRedisStack.Auxiliary; -using StackExchange.Redis; -using System.Xml.Linq; -using System.Reflection; -using NRedisStack.RedisStackCommands; - - -namespace NRedisStack.Tests.Core; - -public class CoreTests : AbstractNRedisStackTest, IDisposable -{ - public CoreTests(RedisFixture redisFixture) : base(redisFixture) { } - - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public void TestSimpleSetInfo() - // { - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase(); - // db.Execute("FLUSHALL"); - - // db.ClientSetInfo(SetInfoAttr.LibraryName, "TestLibraryName"); - // db.ClientSetInfo(SetInfoAttr.LibraryVersion, "1.2.3"); - - // var info = db.Execute("CLIENT", "INFO").ToString(); - // Assert.EndsWith($"lib-name=TestLibraryName lib-ver=1.2.3\n", info); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public async Task TestSimpleSetInfoAsync() - // { - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase(); - // db.Execute("FLUSHALL"); - - // await db.ClientSetInfoAsync(SetInfoAttr.LibraryName, "TestLibraryName"); - // await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, "1.2.3"); - - // var info = db.Execute("CLIENT", "INFO").ToString(); - // Assert.EndsWith($"lib-name=TestLibraryName lib-ver=1.2.3\n", info); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public void TestSetInfoDefaultValue() - // { - // ResetInfoDefaults(); // demonstrate first connection - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase(); - // db.Execute("FLUSHALL"); - - // db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - // var info = db.Execute("CLIENT", "INFO").ToString(); - // Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public async Task TestSetInfoDefaultValueAsync() - // { - // ResetInfoDefaults(); // demonstrate first connection - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase(); - // db.Execute("FLUSHALL"); - - // await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - // var info = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - // Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public void TestSetInfoWithValue() - // { - // ResetInfoDefaults(); // demonstrate first connection - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase("MyLibraryName;v1.0.0"); - // db.Execute("FLUSHALL"); - - // db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - // var info = db.Execute("CLIENT", "INFO").ToString(); - // Assert.EndsWith($"NRedisStack(MyLibraryName;v1.0.0);.NET-{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public async Task TestSetInfoWithValueAsync() - // { - // ResetInfoDefaults(); // demonstrate first connection - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase("MyLibraryName;v1.0.0"); - // db.Execute("FLUSHALL"); - - // await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - // var info = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - // Assert.EndsWith($"NRedisStack(MyLibraryName;v1.0.0);.NET-{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public void TestSetInfoNull() - // { - // ResetInfoDefaults(); // demonstrate first connection - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase(null); - - // db.Execute("FLUSHALL"); - // var infoBefore = db.Execute("CLIENT", "INFO").ToString(); - // db.Execute(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - // var infoAfter = db.Execute("CLIENT", "INFO").ToString(); - // // Find the indices of "lib-name=" in the strings - // int infoAfterLibNameIndex = infoAfter!.IndexOf("lib-name="); - // int infoBeforeLibNameIndex = infoBefore!.IndexOf("lib-name="); - - // // Extract the sub-strings starting from "lib-name=" - // string infoAfterLibNameToEnd = infoAfter.Substring(infoAfterLibNameIndex); - // string infoBeforeLibNameToEnd = infoBefore.Substring(infoBeforeLibNameIndex); - - // // Assert that the extracted sub-strings are equal - // Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); - // } - - // [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] - // public async Task TestSetInfoNullAsync() - // { - // ResetInfoDefaults(); // demonstrate first connection - // var redis = ConnectionMultiplexer.Connect("localhost"); - // var db = redis.GetDatabase(null); - - // db.Execute("FLUSHALL"); - // var infoBefore = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - // await db.ExecuteAsync(new SerializedCommand("PING")); // only the extension method of Execute (which is used for all the commands of Redis Stack) will set the library name and version. - - // var infoAfter = (await db.ExecuteAsync("CLIENT", "INFO")).ToString(); - // // Find the indices of "lib-name=" in the strings - // int infoAfterLibNameIndex = infoAfter!.IndexOf("lib-name="); - // int infoBeforeLibNameIndex = infoBefore!.IndexOf("lib-name="); - - // // Extract the sub-strings starting from "lib-name=" - // string infoAfterLibNameToEnd = infoAfter.Substring(infoAfterLibNameIndex); - // string infoBeforeLibNameToEnd = infoBefore.Substring(infoBeforeLibNameIndex); - - // // Assert that the extracted sub-strings are equal - // Assert.Equal(infoAfterLibNameToEnd, infoBeforeLibNameToEnd); - // } -} \ No newline at end of file From 7d8c85aa002bf64792551bb0f4b3ded1042e7516 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 28 Nov 2023 12:35:00 +0200 Subject: [PATCH 07/12] add ToLower --- src/NRedisStack/RedisUriParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index bbece980..98f3056b 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -105,7 +105,7 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) foreach (var arg in queryArgs.Where(arg => actions.ContainsKey(arg.Key))) { - actions[arg.Key](arg.Value); + actions[arg.Key.ToLower()](arg.Value); } } From 48ac593d135759e96903052368a701fa62626e78 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Tue, 28 Nov 2023 15:48:43 +0200 Subject: [PATCH 08/12] chayim's review --- src/NRedisStack/Configuration.cs | 2 +- src/NRedisStack/RedisUriParser.cs | 66 ++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/NRedisStack/Configuration.cs b/src/NRedisStack/Configuration.cs index 93a059a7..181929e2 100644 --- a/src/NRedisStack/Configuration.cs +++ b/src/NRedisStack/Configuration.cs @@ -10,7 +10,7 @@ public class Configuration public static Configuration Parse(string redisConnectionString) => new Configuration().DoParse(redisConnectionString); - public Configuration DoParse(string redisConnectionString) + private Configuration DoParse(string redisConnectionString) { try // Redis URI parsing { diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index 98f3056b..f86d1806 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -11,6 +11,20 @@ namespace NRedisStack /// internal static class RedisUriParser { + internal static string defaultHost = "localhost"; + internal static int defaultPort = 6379; + + internal const string + Timeout = "timeout", + ClientName = "clientname", + Sentinel_primary_name = "sentinel_primary_name", + Endpoint = "endpoint", + AllowAdmin = "allowadmin", + AbortConnect = "abortconnect", + AsyncTimeout = "asynctimeout", + Retry = "retry", + Protocol = "protocol"; + /// /// Parses a Config options for StackExchange Redis from the URI. /// @@ -22,7 +36,7 @@ internal static ConfigurationOptions FromUri(string redisUri) if (string.IsNullOrEmpty(redisUri)) { - options.EndPoints.Add("localhost:6379"); + options.EndPoints.Add($"{defaultHost}:{defaultPort}"); return options; } @@ -57,26 +71,30 @@ private static void ParseDefaultDatabase(ConfigurationOptions options, Uri uri) private static void ParseUserInfo(ConfigurationOptions options, Uri uri) { - if (!string.IsNullOrEmpty(uri.UserInfo)) + if (string.IsNullOrEmpty(uri.UserInfo)) + { + return; + } + + var userInfo = uri.UserInfo.Split(':'); + + if (userInfo.Length > 1) { - var userInfo = uri.UserInfo.Split(':'); - if (userInfo.Length > 1) - { - options.User = Uri.UnescapeDataString(userInfo[0]); - options.Password = Uri.UnescapeDataString(userInfo[1]); - } - else - { - throw new FormatException( - "Username and password must be in the form username:password - if there is no username use the format :password"); - } + options.User = Uri.UnescapeDataString(userInfo[0]); + options.Password = Uri.UnescapeDataString(userInfo[1]); + } + + else + { + throw new FormatException("Username and password must be in the form username:password - if there is no username use the format :password"); } } + private static void ParseHost(ConfigurationOptions options, Uri uri) { - var port = uri.Port >= 0 ? uri.Port : 6379; - var host = !string.IsNullOrEmpty(uri.Host) ? uri.Host : "localhost"; + var port = uri.Port >= 0 ? uri.Port : defaultPort; + var host = !string.IsNullOrEmpty(uri.Host) ? uri.Host : defaultHost; options.EndPoints.Add($"{host}:{port}"); } @@ -91,15 +109,15 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) var actions = new Dictionary>(StringComparer.OrdinalIgnoreCase) { - { "timeout", value => SetTimeoutOptions(options, value) }, - { "clientname", value => options.ClientName = value }, - { "sentinel_primary_name", value => options.ServiceName = value }, - { "endpoint", value => options.EndPoints.Add(value) }, - { "allowadmin", value => options.AllowAdmin = bool.Parse(value) }, - { "abortConnect", value => options.AbortOnConnectFail = bool.Parse(value) }, - { "asynctimeout", value => options.AsyncTimeout = int.Parse(value) }, - { "retry", value => options.ConnectRetry = int.Parse(value) }, - { "protocol", value => ParseRedisProtocol(options, value) } + { Timeout, value => SetTimeoutOptions(options, value) }, + { ClientName, value => options.ClientName = value }, + { Sentinel_primary_name, value => options.ServiceName = value }, + { Endpoint, value => options.EndPoints.Add(value) }, + { AllowAdmin, value => options.AllowAdmin = bool.Parse(value) }, + { AbortConnect, value => options.AbortOnConnectFail = bool.Parse(value) }, + { AsyncTimeout, value => options.AsyncTimeout = int.Parse(value) }, + { Retry, value => options.ConnectRetry = int.Parse(value) }, + { Protocol, value => ParseRedisProtocol(options, value) } // TODO: add more options }; From d6c0c66ae2721243412cd972ae4c4ad30bd1306d Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 29 Nov 2023 15:33:07 +0200 Subject: [PATCH 09/12] coverage --- src/NRedisStack/Configuration.cs | 11 ++-- src/NRedisStack/ConnectionManager.cs | 4 +- src/NRedisStack/RedisUriParser.cs | 9 ++- .../NRedisStackConfigurationTests.cs | 59 ++++++++++++++++++- 4 files changed, 72 insertions(+), 11 deletions(-) diff --git a/src/NRedisStack/Configuration.cs b/src/NRedisStack/Configuration.cs index 181929e2..3a6a1174 100644 --- a/src/NRedisStack/Configuration.cs +++ b/src/NRedisStack/Configuration.cs @@ -1,4 +1,3 @@ -using NRedisStack.RedisStackCommands; using StackExchange.Redis; namespace NRedisStack @@ -10,6 +9,9 @@ public class Configuration public static Configuration Parse(string redisConnectionString) => new Configuration().DoParse(redisConnectionString); + public static Configuration Parse(ConfigurationOptions options) => + new Configuration().DoParse(options); + private Configuration DoParse(string redisConnectionString) { try // Redis URI parsing @@ -24,10 +26,11 @@ private Configuration DoParse(string redisConnectionString) return this; } - - Configuration() + private Configuration DoParse(ConfigurationOptions options) { + _options = options; SetLibName(_options); + return this; } public ConfigurationOptions GetOptions() @@ -35,7 +38,7 @@ public ConfigurationOptions GetOptions() return _options; } - private static void SetLibName(ConfigurationOptions options) + internal static void SetLibName(ConfigurationOptions options) { if (options.LibraryName != null) // the user set his own the library name options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; diff --git a/src/NRedisStack/ConnectionManager.cs b/src/NRedisStack/ConnectionManager.cs index 31a885bc..f68cd596 100644 --- a/src/NRedisStack/ConnectionManager.cs +++ b/src/NRedisStack/ConnectionManager.cs @@ -26,12 +26,12 @@ public static async Task ConnectAsync(Configuration opti public static IConnectionMultiplexer Connect(ConfigurationOptions options) { - return ConnectionMultiplexer.Connect(options); + return Connect(Configuration.Parse(options)); } public static async Task ConnectAsync(ConfigurationOptions options) { - return await ConnectionMultiplexer.ConnectAsync(options); + return await ConnectAsync(Configuration.Parse(options)); } } } \ No newline at end of file diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index f86d1806..b9a698c6 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -14,6 +14,7 @@ internal static class RedisUriParser internal static string defaultHost = "localhost"; internal static int defaultPort = 6379; + // The options: internal const string Timeout = "timeout", ClientName = "clientname", @@ -127,14 +128,16 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) } } - private static RedisProtocol ParseRedisProtocol(ConfigurationOptions options, string value) + private static void ParseRedisProtocol(ConfigurationOptions options, string value) { switch (value) { case "2": - return RedisProtocol.Resp2; + options.Protocol = RedisProtocol.Resp2; + break; case "3": - return RedisProtocol.Resp3; + options.Protocol = RedisProtocol.Resp3;; + break; default: throw new FormatException("Invalid protocol specified"); } diff --git a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs index 039cb6f4..b1c12923 100644 --- a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs +++ b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs @@ -2,6 +2,8 @@ using NRedisStack.Core; using static NRedisStack.Auxiliary; using System.Net; +using StackExchange.Redis; +using System.Runtime.InteropServices; namespace NRedisStack.Tests.Core; @@ -12,6 +14,26 @@ public class NRedisStackConfigurationTests : AbstractNRedisStackTest, IDisposabl // TODO: add tests + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public void TestConnectionWithConfigurationOptions() + { + var SEconfigOptions = new ConfigurationOptions() { EndPoints = { "localhost" } }; + var db = ConnectionManager.Connect(SEconfigOptions).GetDatabase(); + db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public async Task TestConnectionWithConfigurationOptionsAsync() + { + var SEconfigOptions = new ConfigurationOptions() { EndPoints = { "localhost" } }; + var db = (await ConnectionManager.ConnectAsync(SEconfigOptions)).GetDatabase(); + await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + } + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] public void TestDefaultLibName() { @@ -48,10 +70,11 @@ public async Task TestDefaultLibNameStackExchangeStringAsync() Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); } - [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + #region Configuration parsing tests + [Fact] public void TestNRedisStackConfigurationOptions() { - var options = Configuration.Parse("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3"); + var options = Configuration.Parse("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3&timeout=1000&abortconnect=false&asynctimeout=1000&protocol=2"); Assert.Equal("username", options.GetOptions().User); Assert.Equal("password", options.GetOptions().Password); var endpoint = (DnsEndPoint)options.GetOptions().EndPoints.First(); @@ -60,5 +83,37 @@ public void TestNRedisStackConfigurationOptions() Assert.Equal("client", options.GetOptions().ClientName); Assert.Equal("sentinel", options.GetOptions().ServiceName); Assert.Equal(3, options.GetOptions().ConnectRetry); + Assert.Equal(1000, options.GetOptions().ConnectTimeout); + Assert.Equal(1000, options.GetOptions().AsyncTimeout); + Assert.True(options.GetOptions().AllowAdmin); + Assert.False(options.GetOptions().AbortOnConnectFail); + } + + [Fact] + public void TestRespConfiguration() + { + var options = Configuration.Parse("redis://localhost:6379?protocol=2"); + // options.GetOptions().Protocol = RedisProtocol.Resp2; + Assert.Equal(RedisProtocol.Resp2, options.GetOptions().Protocol); + options = Configuration.Parse("redis://localhost:6379?protocol=3"); + Assert.Equal(RedisProtocol.Resp3, options.GetOptions().Protocol); + Assert.Throws(() => Configuration.Parse("redis://localhost:6379?protocol=0")); + } + + [Fact] + public void TestWithMultipleEndpoints() + { + var options = Configuration.Parse("rediss://username:password@localhost:6379?endpoint=notSoLocalHost:6379&endpoint=reallyNotSoLocalHost:6379"); + Assert.True(options.GetOptions().EndPoints.Any(x => x is DnsEndPoint endpoint && endpoint.Host == "notSoLocalHost" && endpoint.Port == 6379)!); + Assert.True(options.GetOptions().EndPoints.Any(x => x is DnsEndPoint endpoint && endpoint.Host == "reallyNotSoLocalHost" && endpoint.Port == 6379)!); + } + + [Fact] + public void TestEmptyUri() + { + var options = Configuration.Parse(""); + Assert.Equal("localhost", ((DnsEndPoint)options.GetOptions().EndPoints.First()).Host); + Assert.Equal(6379, ((DnsEndPoint)options.GetOptions().EndPoints.First()).Port); } + #endregion } \ No newline at end of file From 46454773d6fd5ecdd91f5b1c2ab7437a6d4d51bf Mon Sep 17 00:00:00 2001 From: shacharPash Date: Wed, 29 Nov 2023 17:00:43 +0200 Subject: [PATCH 10/12] format & naming --- src/NRedisStack/Configuration.cs | 22 +++--- src/NRedisStack/ConnectionManager.cs | 8 +- src/NRedisStack/RedisUriParser.cs | 11 ++- .../NRedisStackConfigurationTests.cs | 75 ++++++++++++------- 4 files changed, 67 insertions(+), 49 deletions(-) diff --git a/src/NRedisStack/Configuration.cs b/src/NRedisStack/Configuration.cs index 3a6a1174..7ff8905e 100644 --- a/src/NRedisStack/Configuration.cs +++ b/src/NRedisStack/Configuration.cs @@ -1,10 +1,11 @@ +using System.Dynamic; using StackExchange.Redis; namespace NRedisStack { public class Configuration { - private ConfigurationOptions _options = new ConfigurationOptions(); + public ConfigurationOptions Options { get; set; } = new ConfigurationOptions(); public static Configuration Parse(string redisConnectionString) => new Configuration().DoParse(redisConnectionString); @@ -16,34 +17,29 @@ private Configuration DoParse(string redisConnectionString) { try // Redis URI parsing { - _options = RedisUriParser.FromUri(redisConnectionString); + Options = RedisUriParser.FromUri(redisConnectionString); } catch (UriFormatException) // StackExchange.Redis connection string parsing { - _options = ConfigurationOptions.Parse(redisConnectionString); + Options = ConfigurationOptions.Parse(redisConnectionString); } - SetLibName(_options); + SetLibName(Options); return this; } private Configuration DoParse(ConfigurationOptions options) { - _options = options; - SetLibName(_options); + Options = options; + SetLibName(Options); return this; } - public ConfigurationOptions GetOptions() - { - return _options; - } - internal static void SetLibName(ConfigurationOptions options) { if (options.LibraryName != null) // the user set his own the library name - options.LibraryName = $"NRedisStack({options.LibraryName});.NET-{Environment.Version})"; + options.LibraryName = $"NRedisStack({options.LibraryName};.NET_v{Environment.Version})"; else // the default library name and version sending - options.LibraryName = $"NRedisStack;.NET-{Environment.Version}"; + options.LibraryName = $"NRedisStack(.NET_v{Environment.Version})"; } } diff --git a/src/NRedisStack/ConnectionManager.cs b/src/NRedisStack/ConnectionManager.cs index f68cd596..12ea981a 100644 --- a/src/NRedisStack/ConnectionManager.cs +++ b/src/NRedisStack/ConnectionManager.cs @@ -14,14 +14,14 @@ public static async Task ConnectAsync(string redisConnec return await ConnectAsync(Configuration.Parse(redisConnectionString)); } - public static IConnectionMultiplexer Connect(Configuration options) + public static IConnectionMultiplexer Connect(Configuration configuration) { - return ConnectionMultiplexer.Connect(options.GetOptions()); + return ConnectionMultiplexer.Connect(configuration.Options); } - public static async Task ConnectAsync(Configuration options) + public static async Task ConnectAsync(Configuration configuration) { - return await ConnectionMultiplexer.ConnectAsync(options.GetOptions()); + return await ConnectionMultiplexer.ConnectAsync(configuration.Options); } public static IConnectionMultiplexer Connect(ConfigurationOptions options) diff --git a/src/NRedisStack/RedisUriParser.cs b/src/NRedisStack/RedisUriParser.cs index b9a698c6..b49ef428 100644 --- a/src/NRedisStack/RedisUriParser.cs +++ b/src/NRedisStack/RedisUriParser.cs @@ -24,7 +24,9 @@ internal const string AbortConnect = "abortconnect", AsyncTimeout = "asynctimeout", Retry = "retry", - Protocol = "protocol"; + Protocol = "protocol", + LibraryName = "lib_name"; + // TODO: add library version when it will be available /// /// Parses a Config options for StackExchange Redis from the URI. @@ -118,8 +120,9 @@ private static void ParseQueryArguments(ConfigurationOptions options, Uri uri) { AbortConnect, value => options.AbortOnConnectFail = bool.Parse(value) }, { AsyncTimeout, value => options.AsyncTimeout = int.Parse(value) }, { Retry, value => options.ConnectRetry = int.Parse(value) }, - { Protocol, value => ParseRedisProtocol(options, value) } - // TODO: add more options + { Protocol, value => ParseRedisProtocol(options, value) }, + { LibraryName, value => options.LibraryName = value } + // TODO: add more options (especially the library version when it will be available) }; foreach (var arg in queryArgs.Where(arg => actions.ContainsKey(arg.Key))) @@ -136,7 +139,7 @@ private static void ParseRedisProtocol(ConfigurationOptions options, string valu options.Protocol = RedisProtocol.Resp2; break; case "3": - options.Protocol = RedisProtocol.Resp3;; + options.Protocol = RedisProtocol.Resp3; ; break; default: throw new FormatException("Invalid protocol specified"); diff --git a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs index b1c12923..58fb9747 100644 --- a/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs +++ b/tests/NRedisStack.Tests/NRedisStackConfigurationTests.cs @@ -21,7 +21,7 @@ public void TestConnectionWithConfigurationOptions() var db = ConnectionManager.Connect(SEconfigOptions).GetDatabase(); db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + Assert.EndsWith($"lib-name=NRedisStack(.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] @@ -31,7 +31,7 @@ public async Task TestConnectionWithConfigurationOptionsAsync() var db = (await ConnectionManager.ConnectAsync(SEconfigOptions)).GetDatabase(); await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + Assert.EndsWith($"lib-name=NRedisStack(.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] @@ -40,7 +40,7 @@ public void TestDefaultLibName() var db = ConnectionManager.Connect("redis://localhost").GetDatabase(); db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + Assert.EndsWith($"lib-name=NRedisStack(.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] @@ -49,7 +49,27 @@ public async Task TestDefaultLibNameAsync() var db = (await ConnectionManager.ConnectAsync("redis://localhost")).GetDatabase(); await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + Assert.EndsWith($"lib-name=NRedisStack(.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public void TestLibNameSet() + { + var configuration = Configuration.Parse("redis://localhost?lib_name=MyLib"); + var db = ConnectionManager.Connect(configuration).GetDatabase(); + db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack(MyLib;.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); + } + + [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] + public async Task TestLibNameSetAsync() + { + var configuration = Configuration.Parse("redis://localhost?lib_name=MyLib"); + var db = (await ConnectionManager.ConnectAsync(configuration)).GetDatabase(); + await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set + var info = db.Execute("CLIENT", "INFO").ToString(); + Assert.EndsWith($"lib-name=NRedisStack(MyLib;.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] @@ -58,7 +78,7 @@ public void TestDefaultLibNameStackExchangeString() var db = ConnectionManager.Connect("localhost").GetDatabase(); // StackExchange.Redis connection string (without the redis:// at the start) db.ClientSetInfo(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + Assert.EndsWith($"lib-name=NRedisStack(.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); } [SkipIfRedis(Is.OSSCluster, Comparison.LessThan, "7.1.242")] @@ -67,53 +87,52 @@ public async Task TestDefaultLibNameStackExchangeStringAsync() var db = (await ConnectionManager.ConnectAsync("localhost")).GetDatabase(); // StackExchange.Redis connection string (without the redis:// at the start) await db.ClientSetInfoAsync(SetInfoAttr.LibraryVersion, GetNRedisStackVersion()); // delete this line after the library version will be available and auto set var info = db.Execute("CLIENT", "INFO").ToString(); - Assert.EndsWith($"lib-name=NRedisStack;.NET-{Environment.Version} lib-ver={GetNRedisStackVersion()}\n", info); + Assert.EndsWith($"lib-name=NRedisStack(.NET_v{Environment.Version}) lib-ver={GetNRedisStackVersion()}\n", info); } #region Configuration parsing tests [Fact] public void TestNRedisStackConfigurationOptions() { - var options = Configuration.Parse("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3&timeout=1000&abortconnect=false&asynctimeout=1000&protocol=2"); - Assert.Equal("username", options.GetOptions().User); - Assert.Equal("password", options.GetOptions().Password); - var endpoint = (DnsEndPoint)options.GetOptions().EndPoints.First(); + var configuration = Configuration.Parse("redis://username:password@localhost:6379?allowadmin=true&clientname=client&sentinel_primary_name=sentinel&retry=3&timeout=1000&abortconnect=false&asynctimeout=1000&protocol=2"); + Assert.Equal("username", configuration.Options.User); + Assert.Equal("password", configuration.Options.Password); + var endpoint = (DnsEndPoint)configuration.Options.EndPoints.First(); Assert.Equal("localhost", endpoint.Host); Assert.Equal(6379, endpoint.Port); - Assert.Equal("client", options.GetOptions().ClientName); - Assert.Equal("sentinel", options.GetOptions().ServiceName); - Assert.Equal(3, options.GetOptions().ConnectRetry); - Assert.Equal(1000, options.GetOptions().ConnectTimeout); - Assert.Equal(1000, options.GetOptions().AsyncTimeout); - Assert.True(options.GetOptions().AllowAdmin); - Assert.False(options.GetOptions().AbortOnConnectFail); + Assert.Equal("client", configuration.Options.ClientName); + Assert.Equal("sentinel", configuration.Options.ServiceName); + Assert.Equal(3, configuration.Options.ConnectRetry); + Assert.Equal(1000, configuration.Options.ConnectTimeout); + Assert.Equal(1000, configuration.Options.AsyncTimeout); + Assert.True(configuration.Options.AllowAdmin); + Assert.False(configuration.Options.AbortOnConnectFail); } [Fact] public void TestRespConfiguration() { - var options = Configuration.Parse("redis://localhost:6379?protocol=2"); - // options.GetOptions().Protocol = RedisProtocol.Resp2; - Assert.Equal(RedisProtocol.Resp2, options.GetOptions().Protocol); - options = Configuration.Parse("redis://localhost:6379?protocol=3"); - Assert.Equal(RedisProtocol.Resp3, options.GetOptions().Protocol); + var configuration = Configuration.Parse("redis://localhost:6379?protocol=2"); + Assert.Equal(RedisProtocol.Resp2, configuration.Options.Protocol); + configuration = Configuration.Parse("redis://localhost:6379?protocol=3"); + Assert.Equal(RedisProtocol.Resp3, configuration.Options.Protocol); Assert.Throws(() => Configuration.Parse("redis://localhost:6379?protocol=0")); } [Fact] public void TestWithMultipleEndpoints() { - var options = Configuration.Parse("rediss://username:password@localhost:6379?endpoint=notSoLocalHost:6379&endpoint=reallyNotSoLocalHost:6379"); - Assert.True(options.GetOptions().EndPoints.Any(x => x is DnsEndPoint endpoint && endpoint.Host == "notSoLocalHost" && endpoint.Port == 6379)!); - Assert.True(options.GetOptions().EndPoints.Any(x => x is DnsEndPoint endpoint && endpoint.Host == "reallyNotSoLocalHost" && endpoint.Port == 6379)!); + var configuration = Configuration.Parse("rediss://username:password@localhost:6379?endpoint=notSoLocalHost:6379&endpoint=reallyNotSoLocalHost:6379"); + Assert.True(configuration.Options.EndPoints.Any(x => x is DnsEndPoint endpoint && endpoint.Host == "notSoLocalHost" && endpoint.Port == 6379)!); + Assert.True(configuration.Options.EndPoints.Any(x => x is DnsEndPoint endpoint && endpoint.Host == "reallyNotSoLocalHost" && endpoint.Port == 6379)!); } [Fact] public void TestEmptyUri() { - var options = Configuration.Parse(""); - Assert.Equal("localhost", ((DnsEndPoint)options.GetOptions().EndPoints.First()).Host); - Assert.Equal(6379, ((DnsEndPoint)options.GetOptions().EndPoints.First()).Port); + var configuration = Configuration.Parse(""); + Assert.Equal("localhost", ((DnsEndPoint)configuration.Options.EndPoints.First()).Host); + Assert.Equal(6379, ((DnsEndPoint)configuration.Options.EndPoints.First()).Port); } #endregion } \ No newline at end of file From b666862108182678a64ca93a5b7b099d13e1b936 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 7 Jan 2024 16:24:20 +0200 Subject: [PATCH 11/12] add Directory.Packages.props --- src/NRedisStack/NRedisStack.csproj | 6 ++--- tests/Doc/Doc.csproj | 12 +++++---- .../Directory.Packages.props | 18 +++++++++++++ .../NRedisStack.Tests.csproj | 27 +++++++------------ 4 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 tests/NRedisStack.Tests/Directory.Packages.props diff --git a/src/NRedisStack/NRedisStack.csproj b/src/NRedisStack/NRedisStack.csproj index 2b7460d9..5cab183f 100644 --- a/src/NRedisStack/NRedisStack.csproj +++ b/src/NRedisStack/NRedisStack.csproj @@ -15,9 +15,9 @@ - - - + + + diff --git a/tests/Doc/Doc.csproj b/tests/Doc/Doc.csproj index b5ac2836..75b2b7a2 100644 --- a/tests/Doc/Doc.csproj +++ b/tests/Doc/Doc.csproj @@ -9,17 +9,19 @@ false Module + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + + - \ No newline at end of file + diff --git a/tests/NRedisStack.Tests/Directory.Packages.props b/tests/NRedisStack.Tests/Directory.Packages.props new file mode 100644 index 00000000..b0fed54e --- /dev/null +++ b/tests/NRedisStack.Tests/Directory.Packages.props @@ -0,0 +1,18 @@ + + + true + + + + + + + + + + + + + + + diff --git a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj index dfba1b20..a6d4452e 100644 --- a/tests/NRedisStack.Tests/NRedisStack.Tests.csproj +++ b/tests/NRedisStack.Tests/NRedisStack.Tests.csproj @@ -6,27 +6,20 @@ enable enable latest - false - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - + + + + + + + + + + From 477d9ce0fb8b3192d7d14e6d8ff440947fc767d6 Mon Sep 17 00:00:00 2001 From: shacharPash Date: Sun, 7 Jan 2024 16:34:37 +0200 Subject: [PATCH 12/12] fix location --- .../Directory.Packages.props => Directory.Packages.props | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/NRedisStack.Tests/Directory.Packages.props => Directory.Packages.props (100%) diff --git a/tests/NRedisStack.Tests/Directory.Packages.props b/Directory.Packages.props similarity index 100% rename from tests/NRedisStack.Tests/Directory.Packages.props rename to Directory.Packages.props