diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1d560447c..53f5701f2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,13 +29,18 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.0.x' + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -45,18 +50,11 @@ jobs: # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). - # If this step fails, then you should remove it and run the build manually (see below) - - if: matrix.language != 'csharp' - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - if: matrix.language == 'csharp' name: .NET Build run: dotnet build Build.csproj -c Release /p:CI=true - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index ff720e26a..9f512d5e9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,7 +15,7 @@ https://stackexchange.github.io/StackExchange.Redis/ MIT - 11 + 13 git https://github.com/StackExchange/StackExchange.Redis/ diff --git a/Directory.Packages.props b/Directory.Packages.props index 6d15ad199..79c404dc2 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,6 +15,7 @@ + @@ -25,7 +26,8 @@ - - + + + \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index b180c6544..678032414 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,10 +6,6 @@ init: install: - cmd: >- - choco install dotnet-6.0-sdk - - choco install dotnet-7.0-sdk - choco install dotnet-9.0-sdk cd tests\RedisConfigs\3.0.503 @@ -71,7 +67,7 @@ nuget: disable_publish_on_pr: true build_script: -- ps: .\build.ps1 -PullRequestNumber "$env:APPVEYOR_PULL_REQUEST_NUMBER" -CreatePackages ($env:OS -eq "Windows_NT") +- ps: .\build.ps1 -PullRequestNumber "$env:APPVEYOR_PULL_REQUEST_NUMBER" -CreatePackages ($env:OS -eq "Windows_NT") -NetCoreOnlyTests test: off artifacts: diff --git a/build.ps1 b/build.ps1 index 24152baab..3ace75a06 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,7 +3,8 @@ param( [bool] $CreatePackages, [switch] $StartServers, [bool] $RunTests = $true, - [string] $PullRequestNumber + [string] $PullRequestNumber, + [switch] $NetCoreOnlyTests ) Write-Host "Run Parameters:" -ForegroundColor Cyan @@ -29,7 +30,11 @@ if ($RunTests) { Write-Host "Servers Started." -ForegroundColor "Green" } Write-Host "Running tests: Build.csproj traversal (all frameworks)" -ForegroundColor "Magenta" - dotnet test ".\Build.csproj" -c Release --no-build --logger trx + if ($NetCoreOnlyTests) { + dotnet test ".\Build.csproj" -c Release -f net8.0 --no-build --logger trx + } else { + dotnet test ".\Build.csproj" -c Release --no-build --logger trx + } if ($LastExitCode -ne 0) { Write-Host "Error with tests, aborting build." -Foreground "Red" Exit 1 diff --git a/src/StackExchange.Redis/ConnectionMultiplexer.cs b/src/StackExchange.Redis/ConnectionMultiplexer.cs index e17a9503b..7ac25e42b 100644 --- a/src/StackExchange.Redis/ConnectionMultiplexer.cs +++ b/src/StackExchange.Redis/ConnectionMultiplexer.cs @@ -535,7 +535,7 @@ static void LogWithThreadPoolStats(ILogger? log, string message, out int busyWor } try { - await Task.WhenAny(task, Task.Delay(remaining)).ObserveErrors().ForAwait(); + await task.TimeoutAfter(remaining).ObserveErrors().ForAwait(); } catch { } diff --git a/src/StackExchange.Redis/TaskExtensions.cs b/src/StackExchange.Redis/TaskExtensions.cs index 081a691ec..ad4b41113 100644 --- a/src/StackExchange.Redis/TaskExtensions.cs +++ b/src/StackExchange.Redis/TaskExtensions.cs @@ -34,7 +34,7 @@ internal static Task ObserveErrors(this Task task) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ConfiguredValueTaskAwaitable ForAwait(this in ValueTask task) => task.ConfigureAwait(false); - internal static void RedisFireAndForget(this Task task) => task?.ContinueWith(t => GC.KeepAlive(t.Exception), TaskContinuationOptions.OnlyOnFaulted); + internal static void RedisFireAndForget(this Task task) => task?.ContinueWith(static t => GC.KeepAlive(t.Exception), TaskContinuationOptions.OnlyOnFaulted); /// /// Licensed to the .NET Foundation under one or more agreements. diff --git a/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs b/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs index 2920a51d3..b68e57c9e 100644 --- a/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs +++ b/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs @@ -2,18 +2,15 @@ using System.Threading.Tasks; using StackExchange.Redis.Tests.Helpers; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class AbortOnConnectFailTests : TestBase +public class AbortOnConnectFailTests(ITestOutputHelper output) : TestBase(output) { - public AbortOnConnectFailTests(ITestOutputHelper output) : base(output) { } - [Fact] - public void NeverEverConnectedNoBacklogThrowsConnectionNotAvailableSync() + public async Task NeverEverConnectedNoBacklogThrowsConnectionNotAvailableSync() { - using var conn = GetFailFastConn(); + await using var conn = GetFailFastConn(); var db = conn.GetDatabase(); var key = Me(); @@ -26,7 +23,7 @@ public void NeverEverConnectedNoBacklogThrowsConnectionNotAvailableSync() [Fact] public async Task NeverEverConnectedNoBacklogThrowsConnectionNotAvailableAsync() { - using var conn = GetFailFastConn(); + await using var conn = GetFailFastConn(); var db = conn.GetDatabase(); var key = Me(); @@ -37,13 +34,13 @@ public async Task NeverEverConnectedNoBacklogThrowsConnectionNotAvailableAsync() } [Fact] - public void DisconnectAndReconnectThrowsConnectionExceptionSync() + public async Task DisconnectAndReconnectThrowsConnectionExceptionSync() { - using var conn = GetWorkingBacklogConn(); + await using var conn = GetWorkingBacklogConn(); var db = conn.GetDatabase(); var key = Me(); - _ = db.Ping(); // Doesn't throw - we're connected + await db.PingAsync(); // Doesn't throw - we're connected // Disconnect and don't allow re-connection conn.AllowConnect = false; @@ -54,7 +51,7 @@ public void DisconnectAndReconnectThrowsConnectionExceptionSync() var ex = Assert.ThrowsAny(() => db.Ping()); Log("Exception: " + ex.Message); Assert.True(ex is RedisConnectionException or RedisTimeoutException); - Assert.StartsWith("The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: ", ex.Message); + Assert.StartsWith("The message timed out in the backlog attempting to send because no connection became available (1000ms) - Last Connection Exception: ", ex.Message); Assert.NotNull(ex.InnerException); var iex = Assert.IsType(ex.InnerException); Assert.Contains(iex.Message, ex.Message); @@ -63,11 +60,11 @@ public void DisconnectAndReconnectThrowsConnectionExceptionSync() [Fact] public async Task DisconnectAndNoReconnectThrowsConnectionExceptionAsync() { - using var conn = GetWorkingBacklogConn(); + await using var conn = GetWorkingBacklogConn(); var db = conn.GetDatabase(); var key = Me(); - _ = db.Ping(); // Doesn't throw - we're connected + await db.PingAsync(); // Doesn't throw - we're connected // Disconnect and don't allow re-connection conn.AllowConnect = false; @@ -77,25 +74,25 @@ public async Task DisconnectAndNoReconnectThrowsConnectionExceptionAsync() // Exception: The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: SocketFailure (InputReaderCompleted, last-recv: 7) on 127.0.0.1:6379/Interactive, Idle/ReadAsync, last: PING, origin: SimulateConnectionFailure, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 100s, state: ConnectedEstablished, mgr: 8 of 10 available, in: 0, in-pipe: 0, out-pipe: 0, last-heartbeat: never, last-mbeat: 0s ago, global: 0s ago, v: 2.6.120.51136, command=PING, timeout: 100, inst: 0, qu: 0, qs: 0, aw: False, bw: CheckingForTimeout, last-in: 0, cur-in: 0, sync-ops: 1, async-ops: 1, serverEndpoint: 127.0.0.1:6379, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 8 of 10 available, clientName: CRAVERTOP7(SE.Redis-v2.6.120.51136), IOCP: (Busy=0,Free=1000,Min=16,Max=1000), WORKER: (Busy=6,Free=32761,Min=16,Max=32767), POOL: (Threads=33,QueuedItems=0,CompletedItems=5547,Timers=60), v: 2.6.120.51136 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts) var ex = await Assert.ThrowsAsync(() => db.PingAsync()); Log("Exception: " + ex.Message); - Assert.StartsWith("The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: ", ex.Message); + Assert.StartsWith("The message timed out in the backlog attempting to send because no connection became available (1000ms) - Last Connection Exception: ", ex.Message); Assert.NotNull(ex.InnerException); var iex = Assert.IsType(ex.InnerException); Assert.Contains(iex.Message, ex.Message); } private ConnectionMultiplexer GetFailFastConn() => - ConnectionMultiplexer.Connect(GetOptions(BacklogPolicy.FailFast).Apply(o => o.EndPoints.Add($"doesnot.exist.{Guid.NewGuid():N}:6379")), Writer); + ConnectionMultiplexer.Connect(GetOptions(BacklogPolicy.FailFast, 400).Apply(o => o.EndPoints.Add($"doesnot.exist.{Guid.NewGuid():N}:6379")), Writer); private ConnectionMultiplexer GetWorkingBacklogConn() => - ConnectionMultiplexer.Connect(GetOptions(BacklogPolicy.Default).Apply(o => o.EndPoints.Add(GetConfiguration())), Writer); + ConnectionMultiplexer.Connect(GetOptions(BacklogPolicy.Default, 1000).Apply(o => o.EndPoints.Add(GetConfiguration())), Writer); - private ConfigurationOptions GetOptions(BacklogPolicy policy) => new ConfigurationOptions() + private static ConfigurationOptions GetOptions(BacklogPolicy policy, int duration) => new ConfigurationOptions() { AbortOnConnectFail = false, BacklogPolicy = policy, ConnectTimeout = 500, - SyncTimeout = 400, - KeepAlive = 400, + SyncTimeout = duration, + KeepAlive = duration, AllowAdmin = true, }.WithoutSubscriptions(); } diff --git a/tests/StackExchange.Redis.Tests/AdhocTests.cs b/tests/StackExchange.Redis.Tests/AdhocTests.cs index 38ae5639a..42a5ebb23 100644 --- a/tests/StackExchange.Redis.Tests/AdhocTests.cs +++ b/tests/StackExchange.Redis.Tests/AdhocTests.cs @@ -1,17 +1,14 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class AdhocTests : TestBase +public class AdhocTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public AdhocTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void TestAdhocCommandsAPI() + public async Task TestAdhocCommandsAPI() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); // needs explicit RedisKey type for key-based diff --git a/tests/StackExchange.Redis.Tests/AggressiveTests.cs b/tests/StackExchange.Redis.Tests/AggressiveTests.cs index 73d06c4c7..f0ba91f16 100644 --- a/tests/StackExchange.Redis.Tests/AggressiveTests.cs +++ b/tests/StackExchange.Redis.Tests/AggressiveTests.cs @@ -1,18 +1,16 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class AggressiveTests : TestBase +public class AggressiveTests(ITestOutputHelper output) : TestBase(output) { - public AggressiveTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task ParallelTransactionsWithConditions() { + Skip.UnlessLongRunning(); const int Muxers = 4, Workers = 20, PerThread = 250; var muxers = new IConnectionMultiplexer[Muxers]; @@ -24,7 +22,7 @@ public async Task ParallelTransactionsWithConditions() RedisKey hits = Me(), trigger = Me() + "3"; int expectedSuccess = 0; - await muxers[0].GetDatabase().KeyDeleteAsync(new[] { hits, trigger }).ForAwait(); + await muxers[0].GetDatabase().KeyDeleteAsync([hits, trigger]).ForAwait(); Task[] tasks = new Task[Workers]; for (int i = 0; i < tasks.Length; i++) @@ -73,10 +71,11 @@ public async Task ParallelTransactionsWithConditions() private const int IterationCount = 5000, InnerCount = 20; - [FactLongRunning] - public void RunCompetingBatchesOnSameMuxer() + [Fact] + public async Task RunCompetingBatchesOnSameMuxer() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var db = conn.GetDatabase(); Thread x = new Thread(state => BatchRunPings((IDatabase)state!)) @@ -132,10 +131,11 @@ private static void BatchRunPings(IDatabase db) } } - [FactLongRunning] + [Fact] public async Task RunCompetingBatchesOnSameMuxerAsync() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var db = conn.GetDatabase(); var x = Task.Run(() => BatchRunPingsAsync(db)); @@ -189,10 +189,11 @@ private static async Task BatchRunPingsAsync(IDatabase db) } } - [FactLongRunning] - public void RunCompetingTransactionsOnSameMuxer() + [Fact] + public async Task RunCompetingTransactionsOnSameMuxer() { - using var conn = Create(logTransactionData: false); + Skip.UnlessLongRunning(); + await using var conn = Create(logTransactionData: false); var db = conn.GetDatabase(); Thread x = new Thread(state => TranRunPings((IDatabase)state!)) @@ -252,10 +253,11 @@ private void TranRunPings(IDatabase db) } } - [FactLongRunning] + [Fact] public async Task RunCompetingTransactionsOnSameMuxerAsync() { - using var conn = Create(logTransactionData: false); + Skip.UnlessLongRunning(); + await using var conn = Create(logTransactionData: false); var db = conn.GetDatabase(); var x = Task.Run(() => TranRunPingsAsync(db)); diff --git a/tests/StackExchange.Redis.Tests/AsyncTests.cs b/tests/StackExchange.Redis.Tests/AsyncTests.cs index e42e2f07d..cba1b1145 100644 --- a/tests/StackExchange.Redis.Tests/AsyncTests.cs +++ b/tests/StackExchange.Redis.Tests/AsyncTests.cs @@ -3,23 +3,18 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class AsyncTests : TestBase +public class AsyncTests(ITestOutputHelper output) : TestBase(output) { - public AsyncTests(ITestOutputHelper output) : base(output) { } - - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - [Fact] - public void AsyncTasksReportFailureIfServerUnavailable() + public async Task AsyncTasksReportFailureIfServerUnavailable() { SetExpectedAmbientFailureCount(-1); // this will get messy - using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); var server = conn.GetServer(TestConfig.Current.PrimaryServer, TestConfig.Current.PrimaryPort); RedisKey key = Me(); @@ -45,8 +40,8 @@ public void AsyncTasksReportFailureIfServerUnavailable() [Fact] public async Task AsyncTimeoutIsNoticed() { - using var conn = Create(syncTimeout: 1000, asyncTimeout: 1000); - using var pauseConn = Create(); + await using var conn = Create(syncTimeout: 1000, asyncTimeout: 1000); + await using var pauseConn = Create(); var opt = ConfigurationOptions.Parse(conn.Configuration); if (!Debugger.IsAttached) { // we max the timeouts if a debugger is detected diff --git a/tests/StackExchange.Redis.Tests/AzureMaintenanceEventTests.cs b/tests/StackExchange.Redis.Tests/AzureMaintenanceEventTests.cs index 852ab9af7..b43731efc 100644 --- a/tests/StackExchange.Redis.Tests/AzureMaintenanceEventTests.cs +++ b/tests/StackExchange.Redis.Tests/AzureMaintenanceEventTests.cs @@ -3,14 +3,11 @@ using System.Net; using StackExchange.Redis.Maintenance; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class AzureMaintenanceEventTests : TestBase +public class AzureMaintenanceEventTests(ITestOutputHelper output) : TestBase(output) { - public AzureMaintenanceEventTests(ITestOutputHelper output) : base(output) { } - [Theory] [InlineData("NotificationType|NodeMaintenanceStarting|StartTimeInUTC|2021-03-02T23:26:57|IsReplica|False|IPAddress||SSLPort|15001|NonSSLPort|13001", AzureNotificationType.NodeMaintenanceStarting, "2021-03-02T23:26:57", false, null, 15001, 13001)] [InlineData("NotificationType|NodeMaintenanceFailover|StartTimeInUTC||IsReplica|False|IPAddress||SSLPort|15001|NonSSLPort|13001", AzureNotificationType.NodeMaintenanceFailoverComplete, null, false, null, 15001, 13001)] diff --git a/tests/StackExchange.Redis.Tests/BacklogTests.cs b/tests/StackExchange.Redis.Tests/BacklogTests.cs index b81c86b8a..f0c0d3d0c 100644 --- a/tests/StackExchange.Redis.Tests/BacklogTests.cs +++ b/tests/StackExchange.Redis.Tests/BacklogTests.cs @@ -1,14 +1,11 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class BacklogTests : TestBase +public class BacklogTests(ITestOutputHelper output) : TestBase(output) { - public BacklogTests(ITestOutputHelper output) : base(output) { } - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; [Fact] @@ -49,7 +46,7 @@ void PrintSnapshot(ConnectionMultiplexer muxer) }; options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); var db = conn.GetDatabase(); Log("Test: Initial (connected) ping"); @@ -122,7 +119,7 @@ public async Task QueuesAndFlushesAfterReconnectingAsync() }; options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); conn.ErrorMessage += (s, e) => Log($"Error Message {e.EndPoint}: {e.Message}"); conn.InternalError += (s, e) => Log($"Internal Error {e.EndPoint}: {e.Exception.Message}"); conn.ConnectionFailed += (s, a) => Log("Disconnected: " + EndPointCollection.ToString(a.EndPoint)); @@ -213,7 +210,7 @@ public async Task QueuesAndFlushesAfterReconnecting() }; options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); conn.ErrorMessage += (s, e) => Log($"Error Message {e.EndPoint}: {e.Message}"); conn.InternalError += (s, e) => Log($"Internal Error {e.EndPoint}: {e.Exception.Message}"); conn.ConnectionFailed += (s, a) => Log("Disconnected: " + EndPointCollection.ToString(a.EndPoint)); @@ -236,10 +233,12 @@ public async Task QueuesAndFlushesAfterReconnecting() // Queue up some commands Log("Test: Disconnected pings"); - Task[] pings = new Task[3]; - pings[0] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(1)); - pings[1] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(2)); - pings[2] = RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(3)); + Task[] pings = + [ + RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(1)), + RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(2)), + RunBlockingSynchronousWithExtraThreadAsync(() => DisconnectedPings(3)), + ]; void DisconnectedPings(int id) { // No need to delay, we're going to try a disconnected connection immediately so it'll fail... @@ -311,7 +310,7 @@ public async Task QueuesAndFlushesAfterReconnectingClusterAsync() options.AllowAdmin = true; options.SocketManager = SocketManager.ThreadPool; - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); conn.ErrorMessage += (s, e) => Log($"Error Message {e.EndPoint}: {e.Message}"); conn.InternalError += (s, e) => Log($"Internal Error {e.EndPoint}: {e.Exception.Message}"); conn.ConnectionFailed += (s, a) => Log("Disconnected: " + EndPointCollection.ToString(a.EndPoint)); diff --git a/tests/StackExchange.Redis.Tests/BasicOpTests.cs b/tests/StackExchange.Redis.Tests/BasicOpTests.cs index 58c82dda6..ad85f5a88 100644 --- a/tests/StackExchange.Redis.Tests/BasicOpTests.cs +++ b/tests/StackExchange.Redis.Tests/BasicOpTests.cs @@ -3,27 +3,15 @@ using System.Threading.Tasks; using StackExchange.Redis.KeyspaceIsolation; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class HighIntegrityBasicOpsTests : BasicOpsTests +public class BasicOpsTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public HighIntegrityBasicOpsTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - - internal override bool HighIntegrity => true; -} - -[Collection(SharedConnectionFixture.Key)] -public class BasicOpsTests : TestBase -{ - public BasicOpsTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task PingOnce() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var duration = await db.PingAsync().ForAwait(); @@ -34,14 +22,14 @@ public async Task PingOnce() [Fact(Skip = "This needs some CI love, it's not a scenario we care about too much but noisy atm.")] public async Task RapidDispose() { - using var primary = Create(); + await using var primary = Create(); var db = primary.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); for (int i = 0; i < 10; i++) { - using var secondary = Create(fail: true, shared: false); + await using var secondary = Create(fail: true, shared: false); secondary.GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget); } // Give it a moment to get through the pipe...they were fire and forget @@ -52,7 +40,7 @@ public async Task RapidDispose() [Fact] public async Task PingMany() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var tasks = new Task[100]; for (int i = 0; i < tasks.Length; i++) @@ -65,9 +53,9 @@ public async Task PingMany() } [Fact] - public void GetWithNullKey() + public async Task GetWithNullKey() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); const string? key = null; var ex = Assert.Throws(() => db.StringGet(key)); @@ -75,9 +63,9 @@ public void GetWithNullKey() } [Fact] - public void SetWithNullKey() + public async Task SetWithNullKey() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); const string? key = null, value = "abc"; var ex = Assert.Throws(() => db.StringSet(key!, value)); @@ -85,9 +73,9 @@ public void SetWithNullKey() } [Fact] - public void SetWithNullValue() + public async Task SetWithNullValue() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); string key = Me(); const string? value = null; @@ -103,9 +91,9 @@ public void SetWithNullValue() } [Fact] - public void SetWithDefaultValue() + public async Task SetWithDefaultValue() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); string key = Me(); var value = default(RedisValue); // this is kinda 0... ish @@ -121,9 +109,9 @@ public void SetWithDefaultValue() } [Fact] - public void SetWithZeroValue() + public async Task SetWithZeroValue() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); string key = Me(); const long value = 0; @@ -141,7 +129,7 @@ public void SetWithZeroValue() [Fact] public async Task GetSetAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -164,9 +152,9 @@ public async Task GetSetAsync() } [Fact] - public void GetSetSync() + public async Task GetSetSync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -193,7 +181,7 @@ public void GetSetSync() [InlineData(true, false)] public async Task GetWithExpiry(bool exists, bool hasExpiry) { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); @@ -229,7 +217,7 @@ public async Task GetWithExpiry(bool exists, bool hasExpiry) [Fact] public async Task GetWithExpiryWrongTypeAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); _ = db.KeyDeleteAsync(key); @@ -250,12 +238,12 @@ public async Task GetWithExpiryWrongTypeAsync() } [Fact] - public void GetWithExpiryWrongTypeSync() + public async Task GetWithExpiryWrongTypeSync() { RedisKey key = Me(); - var ex = Assert.Throws(() => + var ex = await Assert.ThrowsAsync(async () => { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SetAdd(key, "abc", CommandFlags.FireAndForget); @@ -269,7 +257,7 @@ public void GetWithExpiryWrongTypeSync() public async Task TestSevered() { SetExpectedAmbientFailureCount(2); - using var conn = Create(allowAdmin: true, shared: false); + await using var conn = Create(allowAdmin: true, shared: false); var db = conn.GetDatabase(); string key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); @@ -289,7 +277,7 @@ public async Task TestSevered() [Fact] public async Task IncrAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); @@ -315,11 +303,12 @@ public async Task IncrAsync() } [Fact] - public void IncrSync() + public async Task IncrSync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); + Log(key); db.KeyDelete(key, CommandFlags.FireAndForget); var nix = db.KeyExists(key); var a = db.StringGet(key); @@ -343,9 +332,9 @@ public void IncrSync() } [Fact] - public void IncrDifferentSizes() + public async Task IncrDifferentSizes() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); @@ -376,21 +365,21 @@ private static void Incr(IDatabase database, RedisKey key, int delta, ref int to } [Fact] - public void ShouldUseSharedMuxer() + public async Task ShouldUseSharedMuxer() { Log($"Shared: {SharedFixtureAvailable}"); if (SharedFixtureAvailable) { - using var a = Create(); + await using var a = Create(); Assert.IsNotType(a); - using var b = Create(); + await using var b = Create(); Assert.Same(a, b); } else { - using var a = Create(); + await using var a = Create(); Assert.IsType(a); - using var b = Create(); + await using var b = Create(); Assert.NotSame(a, b); } } @@ -398,7 +387,7 @@ public void ShouldUseSharedMuxer() [Fact] public async Task Delete() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); _ = db.StringSetAsync(key, "Heyyyyy"); @@ -413,7 +402,7 @@ public async Task Delete() [Fact] public async Task DeleteAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); _ = db.StringSetAsync(key, "Heyyyyy"); @@ -428,7 +417,7 @@ public async Task DeleteAsync() [Fact] public async Task DeleteMany() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key1 = Me(); var key2 = Me() + "2"; @@ -436,7 +425,7 @@ public async Task DeleteMany() _ = db.StringSetAsync(key1, "Heyyyyy"); _ = db.StringSetAsync(key2, "Heyyyyy"); // key 3 not set - var ku1 = db.KeyDelete(new RedisKey[] { key1, key2, key3 }); + var ku1 = db.KeyDelete([key1, key2, key3]); var ke1 = db.KeyExistsAsync(key1).ForAwait(); var ke2 = db.KeyExistsAsync(key2).ForAwait(); Assert.Equal(2, ku1); @@ -447,7 +436,7 @@ public async Task DeleteMany() [Fact] public async Task DeleteManyAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key1 = Me(); var key2 = Me() + "2"; @@ -455,7 +444,7 @@ public async Task DeleteManyAsync() _ = db.StringSetAsync(key1, "Heyyyyy"); _ = db.StringSetAsync(key2, "Heyyyyy"); // key 3 not set - var ku1 = db.KeyDeleteAsync(new RedisKey[] { key1, key2, key3 }).ForAwait(); + var ku1 = db.KeyDeleteAsync([key1, key2, key3]).ForAwait(); var ke1 = db.KeyExistsAsync(key1).ForAwait(); var ke2 = db.KeyExistsAsync(key2).ForAwait(); Assert.Equal(2, await ku1); @@ -464,10 +453,10 @@ public async Task DeleteManyAsync() } [Fact] - public void WrappedDatabasePrefixIntegration() + public async Task WrappedDatabasePrefixIntegration() { var key = Me(); - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase().WithKeyPrefix("abc"); db.KeyDelete(key, CommandFlags.FireAndForget); db.StringIncrement(key, flags: CommandFlags.FireAndForget); @@ -479,9 +468,9 @@ public void WrappedDatabasePrefixIntegration() } [Fact] - public void TransactionSync() + public async Task TransactionSync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); diff --git a/tests/StackExchange.Redis.Tests/BatchTests.cs b/tests/StackExchange.Redis.Tests/BatchTests.cs index 6783360e5..2605b172d 100644 --- a/tests/StackExchange.Redis.Tests/BatchTests.cs +++ b/tests/StackExchange.Redis.Tests/BatchTests.cs @@ -2,41 +2,37 @@ using System.Collections.Generic; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class BatchTests : TestBase +public class BatchTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public BatchTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void TestBatchNotSent() + public async Task TestBatchNotSent() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); - db.KeyDeleteAsync(key); - db.StringSetAsync(key, "batch-not-sent"); + _ = db.KeyDeleteAsync(key); + _ = db.StringSetAsync(key, "batch-not-sent"); var batch = db.CreateBatch(); - batch.KeyDeleteAsync(key); - batch.SetAddAsync(key, "a"); - batch.SetAddAsync(key, "b"); - batch.SetAddAsync(key, "c"); + _ = batch.KeyDeleteAsync(key); + _ = batch.SetAddAsync(key, "a"); + _ = batch.SetAddAsync(key, "b"); + _ = batch.SetAddAsync(key, "c"); Assert.Equal("batch-not-sent", db.StringGet(key)); } [Fact] - public void TestBatchSent() + public async Task TestBatchSent() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); - db.KeyDeleteAsync(key); - db.StringSetAsync(key, "batch-sent"); + _ = db.KeyDeleteAsync(key); + _ = db.StringSetAsync(key, "batch-sent"); var tasks = new List(); var batch = db.CreateBatch(); tasks.Add(batch.KeyDeleteAsync(key)); @@ -47,7 +43,7 @@ public void TestBatchSent() var result = db.SetMembersAsync(key); tasks.Add(result); - Task.WhenAll(tasks.ToArray()); + await Task.WhenAll(tasks.ToArray()); var arr = result.Result; Array.Sort(arr, (x, y) => string.Compare(x, y)); diff --git a/tests/StackExchange.Redis.Tests/BitTests.cs b/tests/StackExchange.Redis.Tests/BitTests.cs index c6b12c02b..b4c032366 100644 --- a/tests/StackExchange.Redis.Tests/BitTests.cs +++ b/tests/StackExchange.Redis.Tests/BitTests.cs @@ -1,18 +1,15 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class BitTests : TestBase +public class BitTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public BitTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void BasicOps() + public async Task BasicOps() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); diff --git a/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs b/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs index 1ffb972a2..033a24839 100644 --- a/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs +++ b/tests/StackExchange.Redis.Tests/BoxUnboxTests.cs @@ -55,82 +55,82 @@ public static IEnumerable RoundTripValues => new[] { new object[] { RedisValue.Null }, - new object[] { RedisValue.EmptyString }, - new object[] { (RedisValue)0L }, - new object[] { (RedisValue)1L }, - new object[] { (RedisValue)18L }, - new object[] { (RedisValue)19L }, - new object[] { (RedisValue)20L }, - new object[] { (RedisValue)21L }, - new object[] { (RedisValue)22L }, - new object[] { (RedisValue)(-1L) }, - new object[] { (RedisValue)0 }, - new object[] { (RedisValue)1 }, - new object[] { (RedisValue)18 }, - new object[] { (RedisValue)19 }, - new object[] { (RedisValue)20 }, - new object[] { (RedisValue)21 }, - new object[] { (RedisValue)22 }, - new object[] { (RedisValue)(-1) }, - new object[] { (RedisValue)0F }, - new object[] { (RedisValue)1F }, - new object[] { (RedisValue)(-1F) }, - new object[] { (RedisValue)0D }, - new object[] { (RedisValue)1D }, - new object[] { (RedisValue)(-1D) }, - new object[] { (RedisValue)float.PositiveInfinity }, - new object[] { (RedisValue)float.NegativeInfinity }, - new object[] { (RedisValue)float.NaN }, - new object[] { (RedisValue)double.PositiveInfinity }, - new object[] { (RedisValue)double.NegativeInfinity }, - new object[] { (RedisValue)double.NaN }, - new object[] { (RedisValue)true }, - new object[] { (RedisValue)false }, - new object[] { (RedisValue)(string?)null }, - new object[] { (RedisValue)"abc" }, - new object[] { (RedisValue)s_abc }, - new object[] { (RedisValue)new Memory(s_abc) }, - new object[] { (RedisValue)new ReadOnlyMemory(s_abc) }, + [RedisValue.EmptyString], + [(RedisValue)0L], + [(RedisValue)1L], + [(RedisValue)18L], + [(RedisValue)19L], + [(RedisValue)20L], + [(RedisValue)21L], + [(RedisValue)22L], + [(RedisValue)(-1L)], + [(RedisValue)0], + [(RedisValue)1], + [(RedisValue)18], + [(RedisValue)19], + [(RedisValue)20], + [(RedisValue)21], + [(RedisValue)22], + [(RedisValue)(-1)], + [(RedisValue)0F], + [(RedisValue)1F], + [(RedisValue)(-1F)], + [(RedisValue)0D], + [(RedisValue)1D], + [(RedisValue)(-1D)], + [(RedisValue)float.PositiveInfinity], + [(RedisValue)float.NegativeInfinity], + [(RedisValue)float.NaN], + [(RedisValue)double.PositiveInfinity], + [(RedisValue)double.NegativeInfinity], + [(RedisValue)double.NaN], + [(RedisValue)true], + [(RedisValue)false], + [(RedisValue)(string?)null], + [(RedisValue)"abc"], + [(RedisValue)s_abc], + [(RedisValue)new Memory(s_abc)], + [(RedisValue)new ReadOnlyMemory(s_abc)], }; public static IEnumerable UnboxValues => new[] { new object?[] { null, RedisValue.Null }, - new object[] { "", RedisValue.EmptyString }, - new object[] { 0, (RedisValue)0 }, - new object[] { 1, (RedisValue)1 }, - new object[] { 18, (RedisValue)18 }, - new object[] { 19, (RedisValue)19 }, - new object[] { 20, (RedisValue)20 }, - new object[] { 21, (RedisValue)21 }, - new object[] { 22, (RedisValue)22 }, - new object[] { -1, (RedisValue)(-1) }, - new object[] { 18L, (RedisValue)18 }, - new object[] { 19L, (RedisValue)19 }, - new object[] { 20L, (RedisValue)20 }, - new object[] { 21L, (RedisValue)21 }, - new object[] { 22L, (RedisValue)22 }, - new object[] { -1L, (RedisValue)(-1) }, - new object[] { 0F, (RedisValue)0 }, - new object[] { 1F, (RedisValue)1 }, - new object[] { -1F, (RedisValue)(-1) }, - new object[] { 0D, (RedisValue)0 }, - new object[] { 1D, (RedisValue)1 }, - new object[] { -1D, (RedisValue)(-1) }, - new object[] { float.PositiveInfinity, (RedisValue)double.PositiveInfinity }, - new object[] { float.NegativeInfinity, (RedisValue)double.NegativeInfinity }, - new object[] { float.NaN, (RedisValue)double.NaN }, - new object[] { double.PositiveInfinity, (RedisValue)double.PositiveInfinity }, - new object[] { double.NegativeInfinity, (RedisValue)double.NegativeInfinity }, - new object[] { double.NaN, (RedisValue)double.NaN }, - new object[] { true, (RedisValue)true }, - new object[] { false, (RedisValue)false }, - new object[] { "abc", (RedisValue)"abc" }, - new object[] { s_abc, (RedisValue)s_abc }, - new object[] { new Memory(s_abc), (RedisValue)s_abc }, - new object[] { new ReadOnlyMemory(s_abc), (RedisValue)s_abc }, - new object[] { (RedisValue)1234, (RedisValue)1234 }, + ["", RedisValue.EmptyString], + [0, (RedisValue)0], + [1, (RedisValue)1], + [18, (RedisValue)18], + [19, (RedisValue)19], + [20, (RedisValue)20], + [21, (RedisValue)21], + [22, (RedisValue)22], + [-1, (RedisValue)(-1)], + [18L, (RedisValue)18], + [19L, (RedisValue)19], + [20L, (RedisValue)20], + [21L, (RedisValue)21], + [22L, (RedisValue)22], + [-1L, (RedisValue)(-1)], + [0F, (RedisValue)0], + [1F, (RedisValue)1], + [-1F, (RedisValue)(-1)], + [0D, (RedisValue)0], + [1D, (RedisValue)1], + [-1D, (RedisValue)(-1)], + [float.PositiveInfinity, (RedisValue)double.PositiveInfinity], + [float.NegativeInfinity, (RedisValue)double.NegativeInfinity], + [float.NaN, (RedisValue)double.NaN], + [double.PositiveInfinity, (RedisValue)double.PositiveInfinity], + [double.NegativeInfinity, (RedisValue)double.NegativeInfinity], + [double.NaN, (RedisValue)double.NaN], + [true, (RedisValue)true], + [false, (RedisValue)false], + ["abc", (RedisValue)"abc"], + [s_abc, (RedisValue)s_abc], + [new Memory(s_abc), (RedisValue)s_abc], + [new ReadOnlyMemory(s_abc), (RedisValue)s_abc], + [(RedisValue)1234, (RedisValue)1234], }; public static IEnumerable InternedValues() diff --git a/tests/StackExchange.Redis.Tests/CancellationTests.cs b/tests/StackExchange.Redis.Tests/CancellationTests.cs index 58e33e3de..ba23fb6ed 100644 --- a/tests/StackExchange.Redis.Tests/CancellationTests.cs +++ b/tests/StackExchange.Redis.Tests/CancellationTests.cs @@ -3,71 +3,22 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -#if !NET6_0_OR_GREATER -internal static class TaskExtensions +[Collection(NonParallelCollection.Name)] +public class CancellationTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - // suboptimal polyfill version of the .NET 6+ API; I'm not recommending this for production use, - // but it's good enough for tests - public static Task WaitAsync(this Task task, CancellationToken cancellationToken) - { - if (task.IsCompleted || !cancellationToken.CanBeCanceled) return task; - return Wrap(task, cancellationToken); - - static async Task Wrap(Task task, CancellationToken cancellationToken) - { - var tcs = new TaskCompletionSource(); - using var reg = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken)); - _ = task.ContinueWith(t => - { - if (t.IsCanceled) tcs.TrySetCanceled(); - else if (t.IsFaulted) tcs.TrySetException(t.Exception!); - else tcs.TrySetResult(t.Result); - }); - return await tcs.Task; - } - } - - public static Task WaitAsync(this Task task, TimeSpan timeout) - { - if (task.IsCompleted) return task; - return Wrap(task, timeout); - - static async Task Wrap(Task task, TimeSpan timeout) - { - Task other = Task.Delay(timeout); - var first = await Task.WhenAny(task, other); - if (ReferenceEquals(first, other)) - { - throw new TimeoutException(); - } - return await task; - } - } -} -#endif - -[Collection(SharedConnectionFixture.Key)] -public class CancellationTests : TestBase -{ - public CancellationTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task WithCancellation_CancelledToken_ThrowsOperationCanceledException() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); using var cts = new CancellationTokenSource(); cts.Cancel(); // Cancel immediately - await Assert.ThrowsAnyAsync(async () => - { - await db.StringSetAsync(Me(), "value").WaitAsync(cts.Token); - }); + await Assert.ThrowsAnyAsync(async () => await db.StringSetAsync(Me(), "value").WaitAsync(cts.Token)); } private IInternalConnectionMultiplexer Create() => Create(syncTimeout: 10_000); @@ -75,7 +26,7 @@ await Assert.ThrowsAnyAsync(async () => [Fact] public async Task WithCancellation_ValidToken_OperationSucceeds() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); using var cts = new CancellationTokenSource(); @@ -87,15 +38,12 @@ public async Task WithCancellation_ValidToken_OperationSucceeds() Assert.Equal("value", result); } - private void Pause(IDatabase db) - { - db.Execute("client", new object[] { "pause", ConnectionPauseMilliseconds }, CommandFlags.FireAndForget); - } + private static void Pause(IDatabase db) => db.Execute("client", ["pause", ConnectionPauseMilliseconds], CommandFlags.FireAndForget); [Fact] public async Task WithTimeout_ShortTimeout_Async_ThrowsOperationCanceledException() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var watch = Stopwatch.StartNew(); @@ -122,7 +70,7 @@ public async Task WithTimeout_ShortTimeout_Async_ThrowsOperationCanceledExceptio [Fact] public async Task WithoutCancellation_OperationsWorkNormally() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); // No cancellation - should work normally @@ -171,7 +119,7 @@ private static CancellationTokenSource CreateCts(CancelStrategy strategy) [InlineData(CancelStrategy.Manual)] public async Task CancellationDuringOperation_Async_CancelsGracefully(CancelStrategy strategy) { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var watch = Stopwatch.StartNew(); diff --git a/tests/StackExchange.Redis.Tests/Certificates/CertValidationTests.cs b/tests/StackExchange.Redis.Tests/Certificates/CertValidationTests.cs index 528944429..529b29a02 100644 --- a/tests/StackExchange.Redis.Tests/Certificates/CertValidationTests.cs +++ b/tests/StackExchange.Redis.Tests/Certificates/CertValidationTests.cs @@ -3,14 +3,11 @@ using System.Net.Security; using System.Security.Cryptography.X509Certificates; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class CertValidationTests : TestBase +public class CertValidationTests(ITestOutputHelper output) : TestBase(output) { - public CertValidationTests(ITestOutputHelper output) : base(output) { } - [Fact] public void CheckIssuerValidity() { diff --git a/tests/StackExchange.Redis.Tests/ClientKillTests.cs b/tests/StackExchange.Redis.Tests/ClientKillTests.cs index eaf91e073..f10f69ef6 100644 --- a/tests/StackExchange.Redis.Tests/ClientKillTests.cs +++ b/tests/StackExchange.Redis.Tests/ClientKillTests.cs @@ -1,44 +1,37 @@ using System.Collections.Generic; using System.Net; using System.Threading; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -public class ClientKillTests : TestBase +public class ClientKillTests(ITestOutputHelper output) : TestBase(output) { - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public ClientKillTests(ITestOutputHelper output) : base(output) { } - [Fact] - public void ClientKill() + public async Task ClientKill() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); - SetExpectedAmbientFailureCount(-1); - using var otherConnection = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var otherConnection = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast, require: RedisFeatures.v7_4_0_rc1); var id = otherConnection.GetDatabase().Execute(RedisCommand.CLIENT.ToString(), RedisLiterals.ID); - using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); var server = conn.GetServer(conn.GetEndPoints()[0]); long result = server.ClientKill(id.AsInt64(), ClientType.Normal, null, true); Assert.Equal(1, result); } [Fact] - public void ClientKillWithMaxAge() + public async Task ClientKillWithMaxAge() { - var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); - SetExpectedAmbientFailureCount(-1); - using var otherConnection = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var otherConnection = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast, require: RedisFeatures.v7_4_0_rc1); var id = otherConnection.GetDatabase().Execute(RedisCommand.CLIENT.ToString(), RedisLiterals.ID); - Thread.Sleep(1000); + await Task.Delay(1000); - using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); var server = conn.GetServer(conn.GetEndPoints()[0]); var filter = new ClientKillFilter().WithId(id.AsInt64()).WithMaxAgeInSeconds(1).WithSkipMe(true); long result = server.ClientKill(filter, CommandFlags.DemandMaster); @@ -57,10 +50,10 @@ public void TestClientKillMessageWithAllArguments() long maxAge = 102; var filter = new ClientKillFilter().WithId(id).WithClientType(type).WithUsername(userName).WithEndpoint(endpoint).WithServerEndpoint(serverEndpoint).WithSkipMe(skipMe).WithMaxAgeInSeconds(maxAge); - List expected = new List() - { + List expected = + [ "KILL", "ID", "101", "TYPE", "normal", "USERNAME", "user1", "ADDR", "127.0.0.1:1234", "LADDR", "198.0.0.1:6379", "SKIPME", "yes", "MAXAGE", "102", - }; + ]; Assert.Equal(expected, filter.ToList(true)); } } diff --git a/tests/StackExchange.Redis.Tests/ClusterShardedTests.cs b/tests/StackExchange.Redis.Tests/ClusterShardedTests.cs new file mode 100644 index 000000000..dd57483b9 --- /dev/null +++ b/tests/StackExchange.Redis.Tests/ClusterShardedTests.cs @@ -0,0 +1,177 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace StackExchange.Redis.Tests; + +[RunPerProtocol] +[Collection(NonParallelCollection.Name)] +public class ClusterShardedTests(ITestOutputHelper output) : TestBase(output) +{ + protected override string GetConfiguration() => TestConfig.Current.ClusterServersAndPorts + ",connectTimeout=10000"; + + [Fact] + public async Task TestShardedPubsubSubscriberAgainstReconnects() + { + Skip.UnlessLongRunning(); + var channel = RedisChannel.Sharded(Me()); + await using var conn = Create(allowAdmin: true, keepAlive: 1, connectTimeout: 3000, shared: false, require: RedisFeatures.v7_0_0_rc1); + Assert.True(conn.IsConnected); + var db = conn.GetDatabase(); + Assert.Equal(0, await db.PublishAsync(channel, "noClientReceivesThis")); + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + + var pubsub = conn.GetSubscriber(); + List<(RedisChannel, RedisValue)> received = []; + var queue = await pubsub.SubscribeAsync(channel); + _ = Task.Run(async () => + { + // use queue API to have control over order + await foreach (var item in queue) + { + lock (received) + { + if (item.Channel.IsSharded && item.Channel == channel) received.Add((item.Channel, item.Message)); + } + } + }); + Assert.Equal(1, conn.GetSubscriptionsCount()); + + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + await db.PingAsync(); + + for (int i = 0; i < 5; i++) + { + // check we get a hit + Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); + } + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + + // this is endpoint at index 1 which has the hashslot for "testShardChannel" + var server = conn.GetServer(conn.GetEndPoints()[1]); + server.SimulateConnectionFailure(SimulatedFailureType.All); + SetExpectedAmbientFailureCount(2); + + await Task.Delay(4000); + for (int i = 0; i < 5; i++) + { + // check we get a hit + Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); + } + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + + Assert.Equal(1, conn.GetSubscriptionsCount()); + Assert.Equal(10, received.Count); + ClearAmbientFailures(); + } + + [Fact] + public async Task TestShardedPubsubSubscriberAgainsHashSlotMigration() + { + Skip.UnlessLongRunning(); + var channel = RedisChannel.Sharded(Me()); + await using var conn = Create(allowAdmin: true, keepAlive: 1, connectTimeout: 3000, shared: false, require: RedisFeatures.v7_0_0_rc1); + Assert.True(conn.IsConnected); + var db = conn.GetDatabase(); + Assert.Equal(0, await db.PublishAsync(channel, "noClientReceivesThis")); + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + + var pubsub = conn.GetSubscriber(); + List<(RedisChannel, RedisValue)> received = []; + var queue = await pubsub.SubscribeAsync(channel); + _ = Task.Run(async () => + { + // use queue API to have control over order + await foreach (var item in queue) + { + lock (received) + { + if (item.Channel.IsSharded && item.Channel == channel) received.Add((item.Channel, item.Message)); + } + } + }); + Assert.Equal(1, conn.GetSubscriptionsCount()); + + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + await db.PingAsync(); + + for (int i = 0; i < 5; i++) + { + // check we get a hit + Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); + } + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + + // lets migrate the slot for "testShardChannel" to another node + await DoHashSlotMigrationAsync(); + + await Task.Delay(4000); + for (int i = 0; i < 5; i++) + { + // check we get a hit + Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); + } + await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) + + Assert.Equal(1, conn.GetSubscriptionsCount()); + Assert.Equal(10, received.Count); + await RollbackHashSlotMigrationAsync(); + ClearAmbientFailures(); + } + + private Task DoHashSlotMigrationAsync() => MigrateSlotForTestShardChannelAsync(false); + private Task RollbackHashSlotMigrationAsync() => MigrateSlotForTestShardChannelAsync(true); + + private async Task MigrateSlotForTestShardChannelAsync(bool rollback) + { + int hashSlotForTestShardChannel = 7177; + await using var conn = Create(allowAdmin: true, keepAlive: 1, connectTimeout: 5000, shared: false); + var servers = conn.GetServers(); + IServer? serverWithPort7000 = null; + IServer? serverWithPort7001 = null; + + string nodeIdForPort7000 = "780813af558af81518e58e495d63b6e248e80adf"; + string nodeIdForPort7001 = "ea828c6074663c8bd4e705d3e3024d9d1721ef3b"; + foreach (var server in servers) + { + string id = server.Execute("CLUSTER", "MYID").ToString(); + if (id == nodeIdForPort7000) + { + serverWithPort7000 = server; + } + if (id == nodeIdForPort7001) + { + serverWithPort7001 = server; + } + } + + IServer fromServer, toServer; + string fromNode, toNode; + if (rollback) + { + fromServer = serverWithPort7000!; + fromNode = nodeIdForPort7000; + toServer = serverWithPort7001!; + toNode = nodeIdForPort7001; + } + else + { + fromServer = serverWithPort7001!; + fromNode = nodeIdForPort7001; + toServer = serverWithPort7000!; + toNode = nodeIdForPort7000; + } + + try + { + Assert.Equal("OK", toServer.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "IMPORTING", fromNode).ToString()); + Assert.Equal("OK", fromServer.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "MIGRATING", toNode).ToString()); + Assert.Equal("OK", toServer.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "NODE", toNode).ToString()); + Assert.Equal("OK", fromServer!.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "NODE", toNode).ToString()); + } + catch (RedisServerException ex) when (ex.Message == "ERR I'm already the owner of hash slot 7177") + { + Log("Slot already migrated."); + } + } +} diff --git a/tests/StackExchange.Redis.Tests/ClusterTests.cs b/tests/StackExchange.Redis.Tests/ClusterTests.cs index b1f9d01cd..6fa963b8a 100644 --- a/tests/StackExchange.Redis.Tests/ClusterTests.cs +++ b/tests/StackExchange.Redis.Tests/ClusterTests.cs @@ -7,26 +7,20 @@ using System.Threading.Tasks; using StackExchange.Redis.Profiling; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class ClusterTests : TestBase +public class ClusterTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ClusterTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) - { - } - protected override string GetConfiguration() => TestConfig.Current.ClusterServersAndPorts + ",connectTimeout=10000"; [Fact] - public void ExportConfiguration() + public async Task ExportConfiguration() { if (File.Exists("cluster.zip")) File.Delete("cluster.zip"); Assert.False(File.Exists("cluster.zip")); - using (var conn = Create(allowAdmin: true)) + await using (var conn = Create(allowAdmin: true)) using (var file = File.Create("cluster.zip")) { conn.ExportConfiguration(file); @@ -35,11 +29,11 @@ public void ExportConfiguration() } [Fact] - public void ConnectUsesSingleSocket() + public async Task ConnectUsesSingleSocket() { for (int i = 0; i < 5; i++) { - using var conn = Create(failMessage: i + ": ", log: Writer); + await using var conn = Create(failMessage: i + ": ", log: Writer); foreach (var ep in conn.GetEndPoints()) { @@ -53,15 +47,15 @@ public void ConnectUsesSingleSocket() var srv = conn.GetServer(ep); var counters = srv.GetCounters(); Assert.Equal(1, counters.Interactive.SocketCount); - Assert.Equal(Context.IsResp3 ? 0 : 1, counters.Subscription.SocketCount); + Assert.Equal(TestContext.Current.IsResp3() ? 0 : 1, counters.Subscription.SocketCount); } } } [Fact] - public void CanGetTotalStats() + public async Task CanGetTotalStats() { - using var conn = Create(); + await using var conn = Create(); var counters = conn.GetCounters(); Log(counters.ToString()); @@ -78,9 +72,9 @@ private void PrintEndpoints(EndPoint[] endpoints) } [Fact] - public void Connect() + public async Task Connect() { - using var conn = Create(log: Writer); + await using var conn = Create(log: Writer); var expectedPorts = new HashSet(Enumerable.Range(TestConfig.Current.ClusterStartPort, TestConfig.Current.ClusterServerCount)); var endpoints = conn.GetEndPoints(); @@ -129,9 +123,9 @@ public void Connect() } [Fact] - public void TestIdentity() + public async Task TestIdentity() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Guid.NewGuid().ToByteArray(); var ep = conn.GetDatabase().IdentifyEndpoint(key); @@ -140,12 +134,12 @@ public void TestIdentity() } [Fact] - public void IntentionalWrongServer() + public async Task IntentionalWrongServer() { static string? StringGet(IServer server, RedisKey key, CommandFlags flags = CommandFlags.None) - => (string?)server.Execute("GET", new object[] { key }, flags); + => (string?)server.Execute("GET", [key], flags); - using var conn = Create(); + await using var conn = Create(); var endpoints = conn.GetEndPoints(); var servers = endpoints.Select(e => conn.GetServer(e)).ToList(); @@ -155,13 +149,13 @@ public void IntentionalWrongServer() var db = conn.GetDatabase(); db.KeyDelete(key, CommandFlags.FireAndForget); db.StringSet(key, value, flags: CommandFlags.FireAndForget); - servers[0].Ping(); + await servers[0].PingAsync(); var config = servers[0].ClusterConfiguration; Assert.NotNull(config); int slot = conn.HashSlot(key); var rightPrimaryNode = config.GetBySlot(key); Assert.NotNull(rightPrimaryNode); - Log("Right Primary: {0} {1}", rightPrimaryNode.EndPoint, rightPrimaryNode.NodeId); + Log($"Right Primary: {rightPrimaryNode.EndPoint} {rightPrimaryNode.NodeId}"); Assert.NotNull(rightPrimaryNode.EndPoint); string? a = StringGet(conn.GetServer(rightPrimaryNode.EndPoint), key); @@ -169,7 +163,7 @@ public void IntentionalWrongServer() var node = config.Nodes.FirstOrDefault(x => !x.IsReplica && x.NodeId != rightPrimaryNode.NodeId); Assert.NotNull(node); - Log("Using Primary: {0}", node.EndPoint, node.NodeId); + Log($"Using Primary: {node.EndPoint} {node.NodeId}"); { Assert.NotNull(node.EndPoint); string? b = StringGet(conn.GetServer(node.EndPoint), key); @@ -200,15 +194,15 @@ public void IntentionalWrongServer() } [Fact] - public void TransactionWithMultiServerKeys() + public async Task TransactionWithMultiServerKeys() { - using var conn = Create(); - var ex = Assert.Throws(() => + await using var conn = Create(); + var ex = await Assert.ThrowsAsync(async () => { // connect var cluster = conn.GetDatabase(); var anyServer = conn.GetServer(conn.GetEndPoints()[0]); - anyServer.Ping(); + await anyServer.PingAsync(); Assert.Equal(ServerType.Cluster, anyServer.ServerType); var config = anyServer.ClusterConfiguration; Assert.NotNull(config); @@ -223,7 +217,7 @@ public void TransactionWithMultiServerKeys() y = Guid.NewGuid().ToString(); } while (--abort > 0 && config.GetBySlot(y) == xNode); - if (abort == 0) Skip.Inconclusive("failed to find a different node to use"); + if (abort == 0) Assert.Skip("failed to find a different node to use"); var yNode = config.GetBySlot(y); Assert.NotNull(yNode); Log("x={0}, served by {1}", x, xNode.NodeId); @@ -258,15 +252,15 @@ public void TransactionWithMultiServerKeys() } [Fact] - public void TransactionWithSameServerKeys() + public async Task TransactionWithSameServerKeys() { - using var conn = Create(); - var ex = Assert.Throws(() => + await using var conn = Create(); + var ex = await Assert.ThrowsAsync(async () => { // connect var cluster = conn.GetDatabase(); var anyServer = conn.GetServer(conn.GetEndPoints()[0]); - anyServer.Ping(); + await anyServer.PingAsync(); var config = anyServer.ClusterConfiguration; Assert.NotNull(config); @@ -279,7 +273,7 @@ public void TransactionWithSameServerKeys() y = Guid.NewGuid().ToString(); } while (--abort > 0 && config.GetBySlot(y) != xNode); - if (abort == 0) Skip.Inconclusive("failed to find a key with the same node to use"); + Assert.SkipWhen(abort == 0, "failed to find a key with the same node to use"); var yNode = config.GetBySlot(y); Assert.NotNull(xNode); Log("x={0}, served by {1}", x, xNode.NodeId); @@ -315,14 +309,14 @@ public void TransactionWithSameServerKeys() } [Fact] - public void TransactionWithSameSlotKeys() + public async Task TransactionWithSameSlotKeys() { - using var conn = Create(); + await using var conn = Create(); // connect var cluster = conn.GetDatabase(); var anyServer = conn.GetServer(conn.GetEndPoints()[0]); - anyServer.Ping(); + await anyServer.PingAsync(); var config = anyServer.ClusterConfiguration; Assert.NotNull(config); @@ -361,27 +355,26 @@ public void TransactionWithSameSlotKeys() Assert.True(cluster.Wait(existsY), "y exists"); } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "Because.")] - [Theory(Skip = "FlushAllDatabases")] + [Theory] [InlineData(null, 10)] [InlineData(null, 100)] [InlineData("abc", 10)] [InlineData("abc", 100)] - public void Keys(string? pattern, int pageSize) + public async Task Keys(string? pattern, int pageSize) { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); - _ = conn.GetDatabase(); + var dbId = TestConfig.GetDedicatedDB(conn); var server = conn.GetEndPoints().Select(x => conn.GetServer(x)).First(x => !x.IsReplica); - server.FlushAllDatabases(); + await server.FlushDatabaseAsync(dbId); try { - Assert.False(server.Keys(pattern: pattern, pageSize: pageSize).Any()); - Log("Complete: '{0}' / {1}", pattern, pageSize); + Assert.False(server.Keys(dbId, pattern: pattern, pageSize: pageSize).Any()); + Log($"Complete: '{pattern}' / {pageSize}"); } catch { - Log("Failed: '{0}' / {1}", pattern, pageSize); + Log($"Failed: '{pattern}' / {pageSize}"); throw; } } @@ -411,17 +404,17 @@ public void Keys(string? pattern, int pageSize) [InlineData("foo{bar}{zap}", 5061)] [InlineData("bar", 5061)] - public void HashSlots(string key, int slot) + public async Task HashSlots(string key, int slot) { - using var conn = Create(connectTimeout: 5000); + await using var conn = Create(connectTimeout: 5000); Assert.Equal(slot, conn.HashSlot(key)); } [Fact] - public void SScan() + public async Task SScan() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = "a"; var db = conn.GetDatabase(); @@ -441,9 +434,9 @@ public void SScan() } [Fact] - public void GetConfig() + public async Task GetConfig() { - using var conn = Create(allowAdmin: true, log: Writer); + await using var conn = Create(allowAdmin: true, log: Writer); var endpoints = conn.GetEndPoints(); var server = conn.GetServer(endpoints[0]); @@ -467,9 +460,9 @@ public void GetConfig() [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped", Justification = "Because.")] [Fact(Skip = "FlushAllDatabases")] - public void AccessRandomKeys() + public async Task AccessRandomKeys() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var cluster = conn.GetDatabase(); int slotMovedCount = 0; @@ -488,8 +481,8 @@ public void AccessRandomKeys() { if (!server.IsReplica) { - server.Ping(); - server.FlushAllDatabases(); + await server.PingAsync(); + await server.FlushAllDatabasesAsync(); } } @@ -542,12 +535,12 @@ public void AccessRandomKeys() [InlineData(CommandFlags.DemandReplica, true)] [InlineData(CommandFlags.PreferMaster, false)] [InlineData(CommandFlags.PreferReplica, true)] - public void GetFromRightNodeBasedOnFlags(CommandFlags flags, bool isReplica) + public async Task GetFromRightNodeBasedOnFlags(CommandFlags flags, bool isReplica) { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var db = conn.GetDatabase(); - for (int i = 0; i < 1000; i++) + for (int i = 0; i < 500; i++) { var key = Guid.NewGuid().ToString(); var endpoint = db.IdentifyEndpoint(key, flags); @@ -560,9 +553,9 @@ public void GetFromRightNodeBasedOnFlags(CommandFlags flags, bool isReplica) private static string Describe(EndPoint endpoint) => endpoint?.ToString() ?? "(unknown)"; [Fact] - public void SimpleProfiling() + public async Task SimpleProfiling() { - using var conn = Create(log: Writer); + await using var conn = Create(log: Writer); var profiler = new ProfilingSession(); var key = Me(); @@ -591,11 +584,11 @@ public void SimpleProfiling() } [Fact] - public void MultiKeyQueryFails() + public async Task MultiKeyQueryFails() { var keys = InventKeys(); // note the rules expected of this data are enforced in GroupedQueriesWork - using var conn = Create(); + await using var conn = Create(); var ex = Assert.Throws(() => conn.GetDatabase(0).StringGet(keys)); Assert.Contains("Multi-key operations must involve a single slot", ex.Message); @@ -623,13 +616,13 @@ string InventString() } [Fact] - public void GroupedQueriesWork() + public async Task GroupedQueriesWork() { // note it doesn't matter that the data doesn't exist for this; // the point here is that the entire thing *won't work* otherwise, // as per above test var keys = InventKeys(); - using var conn = Create(); + await using var conn = Create(); var grouped = keys.GroupBy(key => conn.GetHashSlot(key)).ToList(); Assert.True(grouped.Count > 1); // check not all a super-group @@ -651,14 +644,14 @@ public void GroupedQueriesWork() } [Fact] - public void MovedProfiling() + public async Task MovedProfiling() { var key = Me(); const string Value = "redirected-value"; var profiler = new ProfilingTests.PerThreadProfiler(); - using var conn = Create(); + await using var conn = Create(); conn.RegisterProfiler(profiler.GetSession); @@ -734,12 +727,12 @@ public void MovedProfiling() } [Fact] - public void ConnectIncludesSubscriber() + public async Task ConnectIncludesSubscriber() { - using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(conn.IsConnected); foreach (var server in conn.GetServerSnapshot()) @@ -749,168 +742,6 @@ public void ConnectIncludesSubscriber() } } - [Fact] - public async Task TestShardedPubsubSubscriberAgainstReconnects() - { - var channel = RedisChannel.Sharded(Me()); - using var conn = Create(allowAdmin: true, keepAlive: 1, connectTimeout: 3000, shared: false, require: RedisFeatures.v7_0_0_rc1); - Assert.True(conn.IsConnected); - var db = conn.GetDatabase(); - Assert.Equal(0, await db.PublishAsync(channel, "noClientReceivesThis")); - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - - var pubsub = conn.GetSubscriber(); - List<(RedisChannel, RedisValue)> received = new(); - var queue = await pubsub.SubscribeAsync(channel); - _ = Task.Run(async () => - { - // use queue API to have control over order - await foreach (var item in queue) - { - lock (received) - { - if (item.Channel.IsSharded && item.Channel == channel) received.Add((item.Channel, item.Message)); - } - } - }); - Assert.Equal(1, conn.GetSubscriptionsCount()); - - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - await db.PingAsync(); - - for (int i = 0; i < 5; i++) - { - // check we get a hit - Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); - } - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - - // this is endpoint at index 1 which has the hashslot for "testShardChannel" - var server = conn.GetServer(conn.GetEndPoints()[1]); - server.SimulateConnectionFailure(SimulatedFailureType.All); - SetExpectedAmbientFailureCount(2); - - await Task.Delay(4000); - for (int i = 0; i < 5; i++) - { - // check we get a hit - Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); - } - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - - Assert.Equal(1, conn.GetSubscriptionsCount()); - Assert.Equal(10, received.Count); - ClearAmbientFailures(); - } - - [Fact] - public async Task TestShardedPubsubSubscriberAgainsHashSlotMigration() - { - var channel = RedisChannel.Sharded(Me()); - using var conn = Create(allowAdmin: true, keepAlive: 1, connectTimeout: 3000, shared: false, require: RedisFeatures.v7_0_0_rc1); - Assert.True(conn.IsConnected); - var db = conn.GetDatabase(); - Assert.Equal(0, await db.PublishAsync(channel, "noClientReceivesThis")); - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - - var pubsub = conn.GetSubscriber(); - List<(RedisChannel, RedisValue)> received = new(); - var queue = await pubsub.SubscribeAsync(channel); - _ = Task.Run(async () => - { - // use queue API to have control over order - await foreach (var item in queue) - { - lock (received) - { - if (item.Channel.IsSharded && item.Channel == channel) received.Add((item.Channel, item.Message)); - } - } - }); - Assert.Equal(1, conn.GetSubscriptionsCount()); - - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - await db.PingAsync(); - - for (int i = 0; i < 5; i++) - { - // check we get a hit - Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); - } - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - - // lets migrate the slot for "testShardChannel" to another node - DoHashSlotMigration(); - - await Task.Delay(4000); - for (int i = 0; i < 5; i++) - { - // check we get a hit - Assert.Equal(1, await db.PublishAsync(channel, i.ToString())); - } - await Task.Delay(50); // let the sub settle (this isn't needed on RESP3, note) - - Assert.Equal(1, conn.GetSubscriptionsCount()); - Assert.Equal(10, received.Count); - RollbackHashSlotMigration(); - ClearAmbientFailures(); - } - - private void DoHashSlotMigration() - { - MigrateSlotForTestShardChannel(false); - } - private void RollbackHashSlotMigration() - { - MigrateSlotForTestShardChannel(true); - } - - private void MigrateSlotForTestShardChannel(bool rollback) - { - int hashSlotForTestShardChannel = 7177; - using var conn = Create(allowAdmin: true, keepAlive: 1, connectTimeout: 5000, shared: false); - var servers = conn.GetServers(); - IServer? serverWithPort7000 = null; - IServer? serverWithPort7001 = null; - - string nodeIdForPort7000 = "780813af558af81518e58e495d63b6e248e80adf"; - string nodeIdForPort7001 = "ea828c6074663c8bd4e705d3e3024d9d1721ef3b"; - foreach (var server in servers) - { - string id = server.Execute("CLUSTER", "MYID").ToString(); - if (id == nodeIdForPort7000) - { - serverWithPort7000 = server; - } - if (id == nodeIdForPort7001) - { - serverWithPort7001 = server; - } - } - - IServer fromServer, toServer; - string fromNode, toNode; - if (rollback) - { - fromServer = serverWithPort7000!; - fromNode = nodeIdForPort7000; - toServer = serverWithPort7001!; - toNode = nodeIdForPort7001; - } - else - { - fromServer = serverWithPort7001!; - fromNode = nodeIdForPort7001; - toServer = serverWithPort7000!; - toNode = nodeIdForPort7000; - } - - Assert.Equal("OK", toServer.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "IMPORTING", fromNode).ToString()); - Assert.Equal("OK", fromServer.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "MIGRATING", toNode).ToString()); - Assert.Equal("OK", toServer.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "NODE", toNode).ToString()); - Assert.Equal("OK", fromServer!.Execute("CLUSTER", "SETSLOT", hashSlotForTestShardChannel, "NODE", toNode).ToString()); - } - [Theory] [InlineData(true)] [InlineData(false)] @@ -918,11 +749,11 @@ public async Task ClusterPubSub(bool sharded) { var guid = Guid.NewGuid().ToString(); var channel = sharded ? RedisChannel.Sharded(guid) : RedisChannel.Literal(guid); - using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false, require: sharded ? RedisFeatures.v7_0_0_rc1 : RedisFeatures.v2_0_0); + await using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false, require: sharded ? RedisFeatures.v7_0_0_rc1 : RedisFeatures.v2_0_0); Assert.True(conn.IsConnected); var pubsub = conn.GetSubscriber(); - List<(RedisChannel, RedisValue)> received = new(); + List<(RedisChannel, RedisValue)> received = []; var queue = await pubsub.SubscribeAsync(channel); _ = Task.Run(async () => { diff --git a/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs b/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs index 13125d722..04e1ca624 100644 --- a/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs +++ b/tests/StackExchange.Redis.Tests/CommandTimeoutTests.cs @@ -1,24 +1,22 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class CommandTimeoutTests : TestBase +public class CommandTimeoutTests(ITestOutputHelper output) : TestBase(output) { - public CommandTimeoutTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task DefaultHeartbeatTimeout() { + Skip.UnlessLongRunning(); var options = ConfigurationOptions.Parse(TestConfig.Current.PrimaryServerAndPort); options.AllowAdmin = true; options.AsyncTimeout = 1000; - using var pauseConn = ConnectionMultiplexer.Connect(options); - using var conn = ConnectionMultiplexer.Connect(options); + await using var pauseConn = ConnectionMultiplexer.Connect(options); + await using var conn = ConnectionMultiplexer.Connect(options); var pauseServer = GetServer(pauseConn); var pauseTask = pauseServer.ExecuteAsync("CLIENT", "PAUSE", 5000); @@ -44,8 +42,8 @@ public async Task DefaultHeartbeatLowTimeout() options.AsyncTimeout = 50; options.HeartbeatInterval = TimeSpan.FromMilliseconds(100); - using var pauseConn = ConnectionMultiplexer.Connect(options); - using var conn = ConnectionMultiplexer.Connect(options); + await using var pauseConn = await ConnectionMultiplexer.ConnectAsync(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); var pauseServer = GetServer(pauseConn); var pauseTask = pauseServer.ExecuteAsync("CLIENT", "PAUSE", 2000); diff --git a/tests/StackExchange.Redis.Tests/ConfigTests.cs b/tests/StackExchange.Redis.Tests/ConfigTests.cs index 7c8e917b7..995b66a5a 100644 --- a/tests/StackExchange.Redis.Tests/ConfigTests.cs +++ b/tests/StackExchange.Redis.Tests/ConfigTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Globalization; using System.IO; using System.IO.Pipelines; @@ -15,16 +14,12 @@ using Microsoft.Extensions.Logging.Abstractions; using StackExchange.Redis.Configuration; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class ConfigTests : TestBase +public class ConfigTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ConfigTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - public Version DefaultVersion = new(3, 0, 0); [Fact] @@ -216,7 +211,7 @@ public void CanParseAndFormatUnixDomainSocket() } [Fact] - public void TalkToNonsenseServer() + public async Task TalkToNonsenseServer() { var config = new ConfigurationOptions { @@ -228,7 +223,7 @@ public void TalkToNonsenseServer() ConnectTimeout = 200, }; var log = new StringWriter(); - using (var conn = ConnectionMultiplexer.Connect(config, log)) + await using (var conn = ConnectionMultiplexer.Connect(config, log)) { Log(log.ToString()); Assert.False(conn.IsConnected); @@ -240,7 +235,7 @@ public async Task TestManualHeartbeat() { var options = ConfigurationOptions.Parse(GetConfiguration()); options.HeartbeatInterval = TimeSpan.FromMilliseconds(100); - using var conn = await ConnectionMultiplexer.ConnectAsync(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); foreach (var ep in conn.GetServerSnapshot().ToArray()) { @@ -248,7 +243,7 @@ public async Task TestManualHeartbeat() } var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); var before = conn.OperationCount; @@ -264,40 +259,40 @@ public async Task TestManualHeartbeat() [InlineData(10)] [InlineData(100)] [InlineData(200)] - public void GetSlowlog(int count) + public async Task GetSlowlog(int count) { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var rows = GetAnyPrimary(conn).SlowlogGet(count); Assert.NotNull(rows); } [Fact] - public void ClearSlowlog() + public async Task ClearSlowlog() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); GetAnyPrimary(conn).SlowlogReset(); } [Fact] - public void ClientName() + public async Task ClientName() { - using var conn = Create(clientName: "Test Rig", allowAdmin: true, shared: false); + await using var conn = Create(clientName: "Test Rig", allowAdmin: true, shared: false); Assert.Equal("Test Rig", conn.ClientName); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); - var name = (string?)GetAnyPrimary(conn).Execute("CLIENT", "GETNAME"); + var name = (string?)(await GetAnyPrimary(conn).ExecuteAsync("CLIENT", "GETNAME")); Assert.Equal("TestRig", name); } [Fact] public async Task ClientLibraryName() { - using var conn = Create(allowAdmin: true, shared: false); + await using var conn = Create(allowAdmin: true, shared: false); var server = GetAnyPrimary(conn); await server.PingAsync(); @@ -320,7 +315,7 @@ public async Task ClientLibraryName() conn.AddLibraryNameSuffix("foo"); libName = (await server.ClientListAsync()).Single(x => x.Id == id).LibraryName; - Log("library name: {0}", libName); + Log($"library name: {libName}"); Assert.Equal("SE.Redis-bar-foo", libName); } else @@ -330,22 +325,22 @@ public async Task ClientLibraryName() } [Fact] - public void DefaultClientName() + public async Task DefaultClientName() { - using var conn = Create(allowAdmin: true, caller: "", shared: false); // force default naming to kick in + await using var conn = Create(allowAdmin: true, caller: "", shared: false); // force default naming to kick in Assert.Equal($"{Environment.MachineName}(SE.Redis-v{Utils.GetLibVersion()})", conn.ClientName); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); var name = (string?)GetAnyPrimary(conn).Execute("CLIENT", "GETNAME"); Assert.Equal($"{Environment.MachineName}(SE.Redis-v{Utils.GetLibVersion()})", name); } [Fact] - public void ReadConfigWithConfigDisabled() + public async Task ReadConfigWithConfigDisabled() { - using var conn = Create(allowAdmin: true, disabledCommands: new[] { "config", "info" }); + await using var conn = Create(allowAdmin: true, disabledCommands: ["config", "info"]); var server = GetAnyPrimary(conn); var ex = Assert.Throws(() => server.ConfigGet()); @@ -353,14 +348,14 @@ public void ReadConfigWithConfigDisabled() } [Fact] - public void ConnectWithSubscribeDisabled() + public async Task ConnectWithSubscribeDisabled() { - using var conn = Create(allowAdmin: true, disabledCommands: new[] { "subscribe" }); + await using var conn = Create(allowAdmin: true, disabledCommands: ["subscribe"]); Assert.True(conn.IsConnected); var servers = conn.GetServerSnapshot(); Assert.True(servers[0].IsConnected); - if (!Context.IsResp3) + if (!TestContext.Current.IsResp3()) { Assert.False(servers[0].IsSubscriberConnected); } @@ -370,9 +365,9 @@ public void ConnectWithSubscribeDisabled() } [Fact] - public void ReadConfig() + public async Task ReadConfig() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); Log("about to get config"); var server = GetAnyPrimary(conn); @@ -391,9 +386,9 @@ public void ReadConfig() } [Fact] - public void GetTime() + public async Task GetTime() { - using var conn = Create(); + await using var conn = Create(); var server = GetAnyPrimary(conn); var serverTime = server.Time(); @@ -404,9 +399,9 @@ public void GetTime() } [Fact] - public void DebugObject() + public async Task DebugObject() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -418,9 +413,9 @@ public void DebugObject() } [Fact] - public void GetInfo() + public async Task GetInfo() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var server = GetAnyPrimary(conn); var info1 = server.Info(); @@ -434,12 +429,17 @@ public void GetInfo() Log("Full info for: " + first.Key); foreach (var setting in first) { - Log("{0} ==> {1}", setting.Key, setting.Value); + Log(" {0} ==> {1}", setting.Key, setting.Value); } var info2 = server.Info("cpu"); Assert.Single(info2); var cpu = info2.Single(); + Log("Full info for: " + cpu.Key); + foreach (var setting in cpu) + { + Log(" {0} ==> {1}", setting.Key, setting.Value); + } var cpuCount = cpu.Count(); Assert.True(cpuCount > 2); Assert.Equal("CPU", cpu.Key); @@ -448,9 +448,9 @@ public void GetInfo() } [Fact] - public void GetInfoRaw() + public async Task GetInfoRaw() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var server = GetAnyPrimary(conn); var info = server.InfoRaw(); @@ -459,10 +459,10 @@ public void GetInfoRaw() } [Fact] - public void GetClients() + public async Task GetClients() { var name = Guid.NewGuid().ToString(); - using var conn = Create(clientName: name, allowAdmin: true, shared: false); + await using var conn = Create(clientName: name, allowAdmin: true, shared: false); var server = GetAnyPrimary(conn); var clients = server.ClientList(); @@ -482,7 +482,7 @@ public void GetClients() var self = clients.First(x => x.Id == id); if (server.Version.Major >= 7) { - Assert.Equal(Context.Test.Protocol, self.Protocol); + Assert.Equal(TestContext.Current.GetProtocol(), self.Protocol); } else { @@ -492,50 +492,15 @@ public void GetClients() } [Fact] - public void SlowLog() + public async Task SlowLog() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var server = GetAnyPrimary(conn); server.SlowlogGet(); server.SlowlogReset(); } - [Fact] - public async Task TestAutomaticHeartbeat() - { - RedisValue oldTimeout = RedisValue.Null; - using var configConn = Create(allowAdmin: true); - - try - { - configConn.GetDatabase(); - var srv = GetAnyPrimary(configConn); - oldTimeout = srv.ConfigGet("timeout")[0].Value; - srv.ConfigSet("timeout", 5); - - using var innerConn = Create(); - var innerDb = innerConn.GetDatabase(); - innerDb.Ping(); // need to wait to pick up configuration etc - - var before = innerConn.OperationCount; - - Log("sleeping to test heartbeat..."); - await Task.Delay(8000).ForAwait(); - - var after = innerConn.OperationCount; - Assert.True(after >= before + 1, $"after: {after}, before: {before}"); - } - finally - { - if (!oldTimeout.IsNull) - { - var srv = GetAnyPrimary(configConn); - srv.ConfigSet("timeout", oldTimeout); - } - } - } - [Fact] public void EndpointIteratorIsReliableOverChanges() { @@ -555,7 +520,7 @@ public void EndpointIteratorIsReliableOverChanges() } [Fact] - public void ThreadPoolManagerIsDetected() + public async Task ThreadPoolManagerIsDetected() { var config = new ConfigurationOptions { @@ -563,20 +528,20 @@ public void ThreadPoolManagerIsDetected() SocketManager = SocketManager.ThreadPool, }; - using var conn = ConnectionMultiplexer.Connect(config); + await using var conn = ConnectionMultiplexer.Connect(config); Assert.Same(PipeScheduler.ThreadPool, conn.SocketManager?.Scheduler); } [Fact] - public void DefaultThreadPoolManagerIsDetected() + public async Task DefaultThreadPoolManagerIsDetected() { var config = new ConfigurationOptions { EndPoints = { { IPAddress.Loopback, 6379 } }, }; - using var conn = ConnectionMultiplexer.Connect(config); + await using var conn = ConnectionMultiplexer.Connect(config); Assert.Same(SocketManager.Shared.Scheduler, conn.SocketManager?.Scheduler); } @@ -643,7 +608,7 @@ public void Apply() } [Fact] - public void BeforeSocketConnect() + public async Task BeforeSocketConnect() { var options = ConfigurationOptions.Parse(TestConfig.Current.PrimaryServerAndPort); int count = 0; @@ -654,7 +619,7 @@ public void BeforeSocketConnect() socket.DontFragment = true; socket.Ttl = (short)(connType == ConnectionType.Interactive ? 12 : 123); }; - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = ConnectionMultiplexer.Connect(options); Assert.True(conn.IsConnected); Assert.Equal(2, count); @@ -684,7 +649,7 @@ public async Task MutableOptions() var originalUser = options.User = "originalUser"; var originalPassword = options.Password = "originalPassword"; Assert.Equal("Details", options.ClientName); - using var conn = await ConnectionMultiplexer.ConnectAsync(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); // Same instance Assert.Same(options, conn.RawConfig); diff --git a/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs b/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs index 24fc8d44d..3b6fc4d49 100644 --- a/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectByIPTests.cs @@ -2,15 +2,13 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectByIPTests : TestBase +public class ConnectByIPTests(ITestOutputHelper output) : TestBase(output) { - public ConnectByIPTests(ITestOutputHelper output) : base(output) { } - [Fact] public void ParseEndpoints() { @@ -31,36 +29,36 @@ public void ParseEndpoints() } [Fact] - public void IPv4Connection() + public async Task IPv4Connection() { var config = new ConfigurationOptions { EndPoints = { { TestConfig.Current.IPv4Server, TestConfig.Current.IPv4Port } }, }; - using var conn = ConnectionMultiplexer.Connect(config); + await using var conn = ConnectionMultiplexer.Connect(config); var server = conn.GetServer(config.EndPoints[0]); Assert.Equal(AddressFamily.InterNetwork, server.EndPoint.AddressFamily); - server.Ping(); + await server.PingAsync(); } [Fact] - public void IPv6Connection() + public async Task IPv6Connection() { var config = new ConfigurationOptions { EndPoints = { { TestConfig.Current.IPv6Server, TestConfig.Current.IPv6Port } }, }; - using var conn = ConnectionMultiplexer.Connect(config); + await using var conn = ConnectionMultiplexer.Connect(config); var server = conn.GetServer(config.EndPoints[0]); Assert.Equal(AddressFamily.InterNetworkV6, server.EndPoint.AddressFamily); - server.Ping(); + await server.PingAsync(); } [Theory] [MemberData(nameof(ConnectByVariousEndpointsData))] - public void ConnectByVariousEndpoints(EndPoint ep, AddressFamily expectedFamily) + public async Task ConnectByVariousEndpoints(EndPoint ep, AddressFamily expectedFamily) { Assert.Equal(expectedFamily, ep.AddressFamily); var config = new ConfigurationOptions @@ -69,11 +67,11 @@ public void ConnectByVariousEndpoints(EndPoint ep, AddressFamily expectedFamily) }; if (ep.AddressFamily != AddressFamily.InterNetworkV6) // I don't have IPv6 servers { - using (var conn = ConnectionMultiplexer.Connect(config)) + await using (var conn = ConnectionMultiplexer.Connect(config)) { var actual = conn.GetEndPoints().Single(); var server = conn.GetServer(actual); - server.Ping(); + await server.PingAsync(); } } } diff --git a/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs b/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs index 460f6f6b6..d0e67f35f 100644 --- a/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectCustomConfigTests.cs @@ -1,14 +1,11 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectCustomConfigTests : TestBase +public class ConnectCustomConfigTests(ITestOutputHelper output) : TestBase(output) { - public ConnectCustomConfigTests(ITestOutputHelper output) : base(output) { } - // So we're triggering tiebreakers here protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; @@ -19,12 +16,12 @@ public ConnectCustomConfigTests(ITestOutputHelper output) : base(output) { } [InlineData("config,get")] [InlineData("info,get")] [InlineData("config,info,get")] - public void DisabledCommandsStillConnect(string disabledCommands) + public async Task DisabledCommandsStillConnect(string disabledCommands) { - using var conn = Create(allowAdmin: true, disabledCommands: disabledCommands.Split(','), log: Writer); + await using var conn = Create(allowAdmin: true, disabledCommands: disabledCommands.Split(','), log: Writer); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(db.IsConnected(default(RedisKey))); } @@ -37,19 +34,19 @@ public void DisabledCommandsStillConnect(string disabledCommands) [InlineData("info,get")] [InlineData("config,info,get")] [InlineData("config,info,get,cluster")] - public void DisabledCommandsStillConnectCluster(string disabledCommands) + public async Task DisabledCommandsStillConnectCluster(string disabledCommands) { - using var conn = Create(allowAdmin: true, configuration: TestConfig.Current.ClusterServersAndPorts, disabledCommands: disabledCommands.Split(','), log: Writer); + await using var conn = Create(allowAdmin: true, configuration: TestConfig.Current.ClusterServersAndPorts, disabledCommands: disabledCommands.Split(','), log: Writer); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(db.IsConnected(default(RedisKey))); } [Fact] - public void TieBreakerIntact() + public async Task TieBreakerIntact() { - using var conn = Create(allowAdmin: true, log: Writer); + await using var conn = Create(allowAdmin: true, log: Writer); var tiebreaker = conn.GetDatabase().StringGet(conn.RawConfig.TieBreaker); Log($"Tiebreaker: {tiebreaker}"); @@ -61,9 +58,9 @@ public void TieBreakerIntact() } [Fact] - public void TieBreakerSkips() + public async Task TieBreakerSkips() { - using var conn = Create(allowAdmin: true, disabledCommands: new[] { "get" }, log: Writer); + await using var conn = Create(allowAdmin: true, disabledCommands: ["get"], log: Writer); Assert.Throws(() => conn.GetDatabase().StringGet(conn.RawConfig.TieBreaker)); foreach (var server in conn.GetServerSnapshot()) @@ -74,18 +71,18 @@ public void TieBreakerSkips() } [Fact] - public void TiebreakerIncorrectType() + public async Task TiebreakerIncorrectType() { var tiebreakerKey = Me(); - using var fubarConn = Create(allowAdmin: true, log: Writer); + await using var fubarConn = Create(allowAdmin: true, log: Writer); // Store something nonsensical in the tiebreaker key: fubarConn.GetDatabase().HashSet(tiebreakerKey, "foo", "bar"); // Ensure the next connection getting an invalid type still connects - using var conn = Create(allowAdmin: true, tieBreaker: tiebreakerKey, log: Writer); + await using var conn = Create(allowAdmin: true, tieBreaker: tiebreakerKey, log: Writer); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(db.IsConnected(default(RedisKey))); var ex = Assert.Throws(() => db.StringGet(tiebreakerKey)); @@ -93,7 +90,7 @@ public void TiebreakerIncorrectType() } [Theory] - [InlineData(true, 4, 15)] + [InlineData(true, 2, 15)] [InlineData(false, 0, 0)] public async Task HeartbeatConsistencyCheckPingsAsync(bool enableConsistencyChecks, int minExpected, int maxExpected) { @@ -104,10 +101,10 @@ public async Task HeartbeatConsistencyCheckPingsAsync(bool enableConsistencyChec }; options.EndPoints.Add(TestConfig.Current.PrimaryServerAndPort); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(db.IsConnected(default)); var preCount = conn.OperationCount; diff --git a/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs b/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs index 58d9795bb..6a7e253d7 100644 --- a/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectFailTimeoutTests.cs @@ -1,19 +1,16 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectFailTimeoutTests : TestBase +public class ConnectFailTimeoutTests(ITestOutputHelper output) : TestBase(output) { - public ConnectFailTimeoutTests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task NoticesConnectFail() { SetExpectedAmbientFailureCount(-1); - using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var conn = Create(allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); var server = conn.GetServer(conn.GetEndPoints()[0]); @@ -41,7 +38,7 @@ void InnerScenario() await UntilConditionAsync(TimeSpan.FromSeconds(10), () => server.IsConnected); Log("pinging - expect success"); - var time = server.Ping(); + var time = await server.PingAsync(); Log("pinged"); Log(time.ToString()); } diff --git a/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs b/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs index d8a942a28..cc015c711 100644 --- a/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectToUnexistingHostTests.cs @@ -3,14 +3,11 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectToUnexistingHostTests : TestBase +public class ConnectToUnexistingHostTests(ITestOutputHelper output) : TestBase(output) { - public ConnectToUnexistingHostTests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task FailsWithinTimeout() { @@ -24,7 +21,7 @@ public async Task FailsWithinTimeout() ConnectTimeout = timeout, }; - using (ConnectionMultiplexer.Connect(config, Writer)) + await using (ConnectionMultiplexer.Connect(config, Writer)) { await Task.Delay(10000).ForAwait(); } diff --git a/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs b/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs index bc0fa9d0c..a905c613a 100644 --- a/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectingFailDetectionTests.cs @@ -2,14 +2,11 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectingFailDetectionTests : TestBase +public class ConnectingFailDetectionTests(ITestOutputHelper output) : TestBase(output) { - public ConnectingFailDetectionTests(ITestOutputHelper output) : base(output) { } - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; [Fact] @@ -17,11 +14,11 @@ public async Task FastNoticesFailOnConnectingSyncCompletion() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); conn.RawConfig.ReconnectRetryPolicy = new LinearRetry(200); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); var server = conn.GetServer(conn.GetEndPoints()[0]); var server2 = conn.GetServer(conn.GetEndPoints()[1]); @@ -57,11 +54,11 @@ public async Task FastNoticesFailOnConnectingAsyncCompletion() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); conn.RawConfig.ReconnectRetryPolicy = new LinearRetry(200); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); var server = conn.GetServer(conn.GetEndPoints()[0]); var server2 = conn.GetServer(conn.GetEndPoints()[1]); @@ -106,7 +103,7 @@ public async Task Issue922_ReconnectRaised() int failCount = 0, restoreCount = 0; - using var conn = ConnectionMultiplexer.Connect(config); + await using var conn = await ConnectionMultiplexer.ConnectAsync(config); conn.ConnectionFailed += (s, e) => { @@ -137,14 +134,14 @@ public async Task Issue922_ReconnectRaised() } [Fact] - public void ConnectsWhenBeginConnectCompletesSynchronously() + public async Task ConnectsWhenBeginConnectCompletesSynchronously() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 3000); + await using var conn = Create(keepAlive: 1, connectTimeout: 3000); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(conn.IsConnected); } @@ -155,12 +152,12 @@ public void ConnectsWhenBeginConnectCompletesSynchronously() } [Fact] - public void ConnectIncludesSubscriber() + public async Task ConnectIncludesSubscriber() { - using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 3000, shared: false); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.True(conn.IsConnected); foreach (var server in conn.GetServerSnapshot()) diff --git a/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs b/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs index d359bd4b4..ce1a31980 100644 --- a/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectionFailedErrorsTests.cs @@ -4,14 +4,11 @@ using System.Threading.Tasks; using StackExchange.Redis.Configuration; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectionFailedErrorsTests : TestBase +public class ConnectionFailedErrorsTests(ITestOutputHelper output) : TestBase(output) { - public ConnectionFailedErrorsTests(ITestOutputHelper output) : base(output) { } - [Theory] [InlineData(true)] [InlineData(false)] @@ -27,7 +24,7 @@ public async Task SSLCertificateValidationError(bool isCertValidationSucceeded) options.CertificateValidation += (sender, cert, chain, errors) => isCertValidationSucceeded; options.AbortOnConnectFail = false; - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); @@ -71,14 +68,14 @@ public async Task AuthenticationFailureError() options.AbortOnConnectFail = false; options.CertificateValidation += SSLTests.ShowCertFailures(Writer); - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); void InnerScenario() { conn.ConnectionFailed += (sender, e) => { - if (e.FailureType == ConnectionFailureType.SocketFailure) Skip.Inconclusive("socket fail"); // this is OK too + if (e.FailureType == ConnectionFailureType.SocketFailure) Assert.Skip("socket fail"); // this is OK too Assert.Equal(ConnectionFailureType.AuthenticationFailure, e.FailureType); }; var ex = Assert.Throws(() => conn.GetDatabase().Ping()); @@ -176,7 +173,7 @@ public async Task CheckFailureRecovered() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, log: Writer, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, log: Writer, shared: false); await RunBlockingSynchronousWithExtraThreadAsync(InnerScenario).ForAwait(); void InnerScenario() diff --git a/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs b/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs index 07e90dabc..db5f541b3 100644 --- a/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectionReconnectRetryPolicyTests.cs @@ -1,13 +1,10 @@ using System; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class TransientErrorTests : TestBase +public class TransientErrorTests(ITestOutputHelper output) : TestBase(output) { - public TransientErrorTests(ITestOutputHelper output) : base(output) { } - [Fact] public void TestExponentialRetry() { diff --git a/tests/StackExchange.Redis.Tests/ConnectionShutdownTests.cs b/tests/StackExchange.Redis.Tests/ConnectionShutdownTests.cs index c39bc4a76..279d8bd23 100644 --- a/tests/StackExchange.Redis.Tests/ConnectionShutdownTests.cs +++ b/tests/StackExchange.Redis.Tests/ConnectionShutdownTests.cs @@ -2,19 +2,15 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ConnectionShutdownTests : TestBase +public class ConnectionShutdownTests(ITestOutputHelper output) : TestBase(output) { - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public ConnectionShutdownTests(ITestOutputHelper output) : base(output) { } - [Fact(Skip = "Unfriendly")] public async Task ShutdownRaisesConnectionFailedAndRestore() { - using var conn = Create(allowAdmin: true, shared: false); + await using var conn = Create(allowAdmin: true, shared: false); int failed = 0, restored = 0; Stopwatch watch = Stopwatch.StartNew(); @@ -29,7 +25,7 @@ public async Task ShutdownRaisesConnectionFailedAndRestore() Interlocked.Increment(ref restored); }; var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); Assert.Equal(0, Interlocked.CompareExchange(ref failed, 0, 0)); Assert.Equal(0, Interlocked.CompareExchange(ref restored, 0, 0)); await Task.Delay(1).ForAwait(); // To make compiler happy in Release diff --git a/tests/StackExchange.Redis.Tests/ConstraintsTests.cs b/tests/StackExchange.Redis.Tests/ConstraintsTests.cs index d5d58cbef..6740fe2b3 100644 --- a/tests/StackExchange.Redis.Tests/ConstraintsTests.cs +++ b/tests/StackExchange.Redis.Tests/ConstraintsTests.cs @@ -1,14 +1,10 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class ConstraintsTests : TestBase +public class ConstraintsTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ConstraintsTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public void ValueEquals() { @@ -20,7 +16,7 @@ public void ValueEquals() [Fact] public async Task TestManualIncr() { - using var conn = Create(syncTimeout: 120000); // big timeout while debugging + await using var conn = Create(syncTimeout: 120000); // big timeout while debugging var key = Me(); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/CopyTests.cs b/tests/StackExchange.Redis.Tests/CopyTests.cs index b40f00c02..e0003136c 100644 --- a/tests/StackExchange.Redis.Tests/CopyTests.cs +++ b/tests/StackExchange.Redis.Tests/CopyTests.cs @@ -1,19 +1,15 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class CopyTests : TestBase +public class CopyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public CopyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task Basic() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var src = Me(); @@ -30,7 +26,7 @@ public async Task Basic() [Fact] public async Task CrossDB() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var dbDestId = TestConfig.GetDedicatedDB(conn); @@ -52,7 +48,7 @@ public async Task CrossDB() [Fact] public async Task WithReplace() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var src = Me(); diff --git a/tests/StackExchange.Redis.Tests/DatabaseTests.cs b/tests/StackExchange.Redis.Tests/DatabaseTests.cs index aed1dbf00..bb134c4fd 100644 --- a/tests/StackExchange.Redis.Tests/DatabaseTests.cs +++ b/tests/StackExchange.Redis.Tests/DatabaseTests.cs @@ -1,19 +1,15 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class DatabaseTests : TestBase +public class DatabaseTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public DatabaseTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task CommandCount() { - using var conn = Create(); + await using var conn = Create(); var server = GetAnyPrimary(conn); var count = server.CommandCount(); Assert.True(count > 100); @@ -25,13 +21,13 @@ public async Task CommandCount() [Fact] public async Task CommandGetKeys() { - using var conn = Create(); + await using var conn = Create(); var server = GetAnyPrimary(conn); - RedisValue[] command = { "MSET", "a", "b", "c", "d", "e", "f" }; + RedisValue[] command = ["MSET", "a", "b", "c", "d", "e", "f"]; RedisKey[] keys = server.CommandGetKeys(command); - RedisKey[] expected = { "a", "c", "e" }; + RedisKey[] expected = ["a", "c", "e"]; Assert.Equal(keys, expected); keys = await server.CommandGetKeysAsync(command); @@ -41,7 +37,7 @@ public async Task CommandGetKeys() [Fact] public async Task CommandList() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var server = GetAnyPrimary(conn); var commands = server.CommandList(); @@ -73,7 +69,7 @@ public async Task CountKeys() { var db1Id = TestConfig.GetDedicatedDB(); var db2Id = TestConfig.GetDedicatedDB(); - using (var conn = Create(allowAdmin: true)) + await using (var conn = Create(allowAdmin: true)) { Skip.IfMissingDatabase(conn, db1Id); Skip.IfMissingDatabase(conn, db2Id); @@ -81,7 +77,7 @@ public async Task CountKeys() server.FlushDatabase(db1Id, CommandFlags.FireAndForget); server.FlushDatabase(db2Id, CommandFlags.FireAndForget); } - using (var conn = Create(defaultDatabase: db2Id)) + await using (var conn = Create(defaultDatabase: db2Id)) { Skip.IfMissingDatabase(conn, db1Id); Skip.IfMissingDatabase(conn, db2Id); @@ -104,9 +100,9 @@ public async Task CountKeys() } [Fact] - public void DatabaseCount() + public async Task DatabaseCount() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var server = GetAnyPrimary(conn); var count = server.DatabaseCount; @@ -119,7 +115,7 @@ public void DatabaseCount() [Fact] public async Task MultiDatabases() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db0 = conn.GetDatabase(TestConfig.GetDedicatedDB(conn)); @@ -146,7 +142,7 @@ public async Task MultiDatabases() [Fact] public async Task SwapDatabases() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v4_0_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v4_0_0); RedisKey key = Me(); var db0id = TestConfig.GetDedicatedDB(conn); @@ -179,7 +175,7 @@ public async Task SwapDatabases() [Fact] public async Task SwapDatabasesAsync() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v4_0_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v4_0_0); RedisKey key = Me(); var db0id = TestConfig.GetDedicatedDB(conn); diff --git a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs index 8c35ab3e1..be80fd9c5 100644 --- a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs +++ b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Configuration; using System.Linq; using System.Net; using System.Threading; @@ -9,18 +8,14 @@ using Microsoft.Extensions.Logging.Abstractions; using StackExchange.Redis.Configuration; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class DefaultOptionsTests : TestBase +public class DefaultOptionsTests(ITestOutputHelper output) : TestBase(output) { - public DefaultOptionsTests(ITestOutputHelper output) : base(output) { } - - public class TestOptionsProvider : DefaultOptionsProvider + public class TestOptionsProvider(string domainSuffix) : DefaultOptionsProvider { - private readonly string _domainSuffix; - public TestOptionsProvider(string domainSuffix) => _domainSuffix = domainSuffix; + private readonly string _domainSuffix = domainSuffix; public override bool AbortOnConnectFail => true; public override TimeSpan? ConnectTimeout => TimeSpan.FromSeconds(123); @@ -150,7 +145,7 @@ public async Task AfterConnectAsyncHandler() var provider = new TestAfterConnectOptionsProvider(); options.Defaults = provider; - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); Assert.True(conn.IsConnected); Assert.Equal(1, provider.Calls); @@ -167,7 +162,7 @@ public async Task ClientNameOverride() var options = ConfigurationOptions.Parse(GetConfiguration()); options.Defaults = new TestClientNameOptionsProvider(); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); Assert.True(conn.IsConnected); Assert.Equal("Hey there", conn.ClientName); @@ -179,7 +174,7 @@ public async Task ClientNameExplicitWins() var options = ConfigurationOptions.Parse(GetConfiguration() + ",name=FooBar"); options.Defaults = new TestClientNameOptionsProvider(); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); Assert.True(conn.IsConnected); Assert.Equal("FooBar", conn.ClientName); @@ -199,9 +194,9 @@ public async Task LibraryNameOverride() options.AllowAdmin = true; options.Defaults = defaults; - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); // CLIENT SETINFO is in 7.2.0+ - ThrowIfBelowMinVersion(conn, RedisFeatures.v7_2_0_rc1); + TestBase.ThrowIfBelowMinVersion(conn, RedisFeatures.v7_2_0_rc1); var clients = await GetServer(conn).ClientListAsync(); foreach (var client in clients) diff --git a/tests/StackExchange.Redis.Tests/DeprecatedTests.cs b/tests/StackExchange.Redis.Tests/DeprecatedTests.cs index 3e0971d6c..ab909ea16 100644 --- a/tests/StackExchange.Redis.Tests/DeprecatedTests.cs +++ b/tests/StackExchange.Redis.Tests/DeprecatedTests.cs @@ -1,16 +1,13 @@ using System; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; /// /// Testing that things we deprecate still parse, but are otherwise defaults. /// -public class DeprecatedTests : TestBase +public class DeprecatedTests(ITestOutputHelper output) : TestBase(output) { - public DeprecatedTests(ITestOutputHelper output) : base(output) { } - #pragma warning disable CS0618 // Type or member is obsolete [Fact] public void HighPrioritySocketThreads() diff --git a/tests/StackExchange.Redis.Tests/EnvoyTests.cs b/tests/StackExchange.Redis.Tests/EnvoyTests.cs index 6d669a6db..d9d22c801 100644 --- a/tests/StackExchange.Redis.Tests/EnvoyTests.cs +++ b/tests/StackExchange.Redis.Tests/EnvoyTests.cs @@ -1,27 +1,25 @@ using System; using System.Text; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class EnvoyTests : TestBase +public class EnvoyTests(ITestOutputHelper output) : TestBase(output) { - public EnvoyTests(ITestOutputHelper output) : base(output) { } - protected override string GetConfiguration() => TestConfig.Current.ProxyServerAndPort; /// /// Tests basic envoy connection with the ability to set and get a key. /// [Fact] - public void TestBasicEnvoyConnection() + public async Task TestBasicEnvoyConnection() { var sb = new StringBuilder(); Writer.EchoTo(sb); try { - using var conn = Create(configuration: GetConfiguration(), keepAlive: 1, connectTimeout: 2000, allowAdmin: true, shared: false, proxy: Proxy.Envoyproxy, log: Writer); + await using var conn = Create(configuration: GetConfiguration(), keepAlive: 1, connectTimeout: 2000, allowAdmin: true, shared: false, proxy: Proxy.Envoyproxy, log: Writer); var db = conn.GetDatabase(); @@ -35,15 +33,15 @@ public void TestBasicEnvoyConnection() } catch (TimeoutException ex) when (ex.Message == "Connect timeout" || sb.ToString().Contains("Returned, but incorrectly")) { - Skip.Inconclusive($"Envoy server not found: {ex}."); + Assert.Skip($"Envoy server not found: {ex}."); } catch (AggregateException ex) { - Skip.Inconclusive($"Envoy server not found: {ex}."); + Assert.Skip($"Envoy server not found: {ex}."); } catch (RedisConnectionException ex) when (sb.ToString().Contains("It was not possible to connect to the redis server(s)")) { - Skip.Inconclusive($"Envoy server not found: {ex}."); + Assert.Skip($"Envoy server not found: {ex}."); } } } diff --git a/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs b/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs index 2edee05c6..53f28f163 100644 --- a/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs +++ b/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs @@ -1,17 +1,15 @@ using System; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ExceptionFactoryTests : TestBase +public class ExceptionFactoryTests(ITestOutputHelper output) : TestBase(output) { - public ExceptionFactoryTests(ITestOutputHelper output) : base(output) { } - [Fact] - public void NullLastException() + public async Task NullLastException() { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true); conn.GetDatabase(); Assert.Null(conn.GetServerSnapshot()[0].LastException); @@ -28,11 +26,11 @@ public void CanGetVersion() #if DEBUG [Fact] - public void MultipleEndpointsThrowConnectionException() + public async Task MultipleEndpointsThrowConnectionException() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); conn.GetDatabase(); conn.AllowConnect = false; @@ -57,11 +55,11 @@ public void MultipleEndpointsThrowConnectionException() #endif [Fact] - public void ServerTakesPrecendenceOverSnapshot() + public async Task ServerTakesPrecendenceOverSnapshot() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false, backlogPolicy: BacklogPolicy.FailFast); conn.GetDatabase(); conn.AllowConnect = false; @@ -80,11 +78,11 @@ public void ServerTakesPrecendenceOverSnapshot() } [Fact] - public void NullInnerExceptionForMultipleEndpointsWithNoLastException() + public async Task NullInnerExceptionForMultipleEndpointsWithNoLastException() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true); conn.GetDatabase(); conn.AllowConnect = false; @@ -99,11 +97,11 @@ public void NullInnerExceptionForMultipleEndpointsWithNoLastException() } [Fact] - public void TimeoutException() + public async Task TimeoutException() { try { - using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); + await using var conn = Create(keepAlive: 1, connectTimeout: 10000, allowAdmin: true, shared: false); var server = GetServer(conn); conn.AllowConnect = false; @@ -153,7 +151,7 @@ public void TimeoutException() [InlineData(true, 0, 0, true, "No connection is active/available to service this operation: PING")] [InlineData(true, 1, 0, true, "No connection is active/available to service this operation: PING")] [InlineData(true, 12, 0, true, "No connection is active/available to service this operation: PING")] - public void NoConnectionException(bool abortOnConnect, int connCount, int completeCount, bool hasDetail, string messageStart) + public async Task NoConnectionException(bool abortOnConnect, int connCount, int completeCount, bool hasDetail, string messageStart) { try { @@ -178,7 +176,7 @@ public void NoConnectionException(bool abortOnConnect, int connCount, int comple conn = ConnectionMultiplexer.Connect(options, Writer); } - using (conn) + await using (conn) { var server = conn.GetServer(conn.GetEndPoints()[0]); conn.AllowConnect = false; @@ -218,9 +216,9 @@ public void NoConnectionException(bool abortOnConnect, int connCount, int comple } [Fact] - public void NoConnectionPrimaryOnlyException() + public async Task NoConnectionPrimaryOnlyException() { - using var conn = ConnectionMultiplexer.Connect(TestConfig.Current.ReplicaServerAndPort, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(TestConfig.Current.ReplicaServerAndPort, Writer); var msg = Message.Create(0, CommandFlags.None, RedisCommand.SET, (RedisKey)Me(), (RedisValue)"test"); Assert.True(msg.IsPrimaryOnly()); @@ -237,9 +235,9 @@ public void NoConnectionPrimaryOnlyException() [InlineData(true, ConnectionFailureType.ConnectionDisposed, "ConnectionDisposed on [0]:GET myKey (StringProcessor), my annotation")] [InlineData(false, ConnectionFailureType.ProtocolFailure, "ProtocolFailure on [0]:GET (StringProcessor), my annotation")] [InlineData(false, ConnectionFailureType.ConnectionDisposed, "ConnectionDisposed on [0]:GET (StringProcessor), my annotation")] - public void MessageFail(bool includeDetail, ConnectionFailureType failType, string messageStart) + public async Task MessageFail(bool includeDetail, ConnectionFailureType failType, string messageStart) { - using var conn = Create(shared: false); + await using var conn = Create(shared: false); conn.RawConfig.IncludeDetailInExceptions = includeDetail; diff --git a/tests/StackExchange.Redis.Tests/ExecuteTests.cs b/tests/StackExchange.Redis.Tests/ExecuteTests.cs index 30012001a..1e1f10bd4 100644 --- a/tests/StackExchange.Redis.Tests/ExecuteTests.cs +++ b/tests/StackExchange.Redis.Tests/ExecuteTests.cs @@ -1,19 +1,15 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class ExecuteTests : TestBase +public class ExecuteTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ExecuteTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task DBExecute() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(4); RedisKey key = Me(); @@ -29,7 +25,7 @@ public async Task DBExecute() [Fact] public async Task ServerExecute() { - using var conn = Create(); + await using var conn = Create(); var server = conn.GetServer(conn.GetEndPoints().First()); var actual = (string?)server.Execute("echo", "some value"); diff --git a/tests/StackExchange.Redis.Tests/ExpiryTests.cs b/tests/StackExchange.Redis.Tests/ExpiryTests.cs index 3d11442e6..fab26586f 100644 --- a/tests/StackExchange.Redis.Tests/ExpiryTests.cs +++ b/tests/StackExchange.Redis.Tests/ExpiryTests.cs @@ -1,23 +1,19 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class ExpiryTests : TestBase +public class ExpiryTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ExpiryTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - - private static string[]? GetMap(bool disablePTimes) => disablePTimes ? new[] { "pexpire", "pexpireat", "pttl" } : null; + private static string[]? GetMap(bool disablePTimes) => disablePTimes ? ["pexpire", "pexpireat", "pttl"] : null; [Theory] [InlineData(true)] [InlineData(false)] public async Task TestBasicExpiryTimeSpan(bool disablePTimes) { - using var conn = Create(disabledCommands: GetMap(disablePTimes)); + await using var conn = Create(disabledCommands: GetMap(disablePTimes)); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -53,7 +49,7 @@ public async Task TestBasicExpiryTimeSpan(bool disablePTimes) [InlineData(false)] public async Task TestExpiryOptions(bool disablePTimes) { - using var conn = Create(disabledCommands: GetMap(disablePTimes), require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(disabledCommands: GetMap(disablePTimes), require: RedisFeatures.v7_0_0_rc1); var key = Me(); var db = conn.GetDatabase(); @@ -84,7 +80,7 @@ public async Task TestExpiryOptions(bool disablePTimes) [InlineData(false, false)] public async Task TestBasicExpiryDateTime(bool disablePTimes, bool utc) { - using var conn = Create(disabledCommands: GetMap(disablePTimes)); + await using var conn = Create(disabledCommands: GetMap(disablePTimes)); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -135,9 +131,9 @@ public async Task TestBasicExpiryDateTime(bool disablePTimes, bool utc) [Theory] [InlineData(true)] [InlineData(false)] - public void KeyExpiryTime(bool disablePTimes) + public async Task KeyExpiryTime(bool disablePTimes) { - using var conn = Create(disabledCommands: GetMap(disablePTimes), require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(disabledCommands: GetMap(disablePTimes), require: RedisFeatures.v7_0_0_rc1); var key = Me(); var db = conn.GetDatabase(); @@ -168,7 +164,7 @@ public void KeyExpiryTime(bool disablePTimes) [InlineData(false)] public async Task KeyExpiryTimeAsync(bool disablePTimes) { - using var conn = Create(disabledCommands: GetMap(disablePTimes), require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(disabledCommands: GetMap(disablePTimes), require: RedisFeatures.v7_0_0_rc1); var key = Me(); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs b/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs index 7b39d36b9..192234f2d 100644 --- a/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs +++ b/tests/StackExchange.Redis.Tests/FSharpCompatTests.cs @@ -1,12 +1,9 @@ using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class FSharpCompatTests : TestBase +public class FSharpCompatTests(ITestOutputHelper output) : TestBase(output) { - public FSharpCompatTests(ITestOutputHelper output) : base(output) { } - #pragma warning disable SA1129 // Do not use default value type constructor [Fact] public void RedisKeyConstructor() diff --git a/tests/StackExchange.Redis.Tests/FailoverTests.cs b/tests/StackExchange.Redis.Tests/FailoverTests.cs index fdbd23a94..68f8f2266 100644 --- a/tests/StackExchange.Redis.Tests/FailoverTests.cs +++ b/tests/StackExchange.Redis.Tests/FailoverTests.cs @@ -4,22 +4,19 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class FailoverTests : TestBase, IAsyncLifetime +public class FailoverTests(ITestOutputHelper output) : TestBase(output), IAsyncLifetime { protected override string GetConfiguration() => GetPrimaryReplicaConfig().ToString(); - public FailoverTests(ITestOutputHelper output) : base(output) { } + public ValueTask DisposeAsync() => ValueTask.CompletedTask; - public Task DisposeAsync() => Task.CompletedTask; - - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { - using var conn = Create(); + await using var conn = Create(); var shouldBePrimary = conn.GetServer(TestConfig.Current.FailoverPrimaryServerAndPort); if (shouldBePrimary.IsReplica) @@ -54,7 +51,7 @@ private static ConfigurationOptions GetPrimaryReplicaConfig() [Fact] public async Task ConfigureAsync() { - using var conn = Create(); + await using var conn = Create(); await Task.Delay(1000).ForAwait(); Log("About to reconfigure....."); @@ -65,7 +62,7 @@ public async Task ConfigureAsync() [Fact] public async Task ConfigureSync() { - using var conn = Create(); + await using var conn = Create(); await Task.Delay(1000).ForAwait(); Log("About to reconfigure....."); @@ -77,8 +74,8 @@ public async Task ConfigureSync() public async Task ConfigVerifyReceiveConfigChangeBroadcast() { _ = GetConfiguration(); - using var senderConn = Create(allowAdmin: true); - using var receiverConn = Create(syncTimeout: 2000); + await using var senderConn = Create(allowAdmin: true); + await using var receiverConn = Create(syncTimeout: 2000); int total = 0; receiverConn.ConfigurationChangedBroadcast += (s, a) => @@ -88,8 +85,8 @@ public async Task ConfigVerifyReceiveConfigChangeBroadcast() }; // send a reconfigure/reconnect message long count = senderConn.PublishReconfigure(); - GetServer(receiverConn).Ping(); - GetServer(receiverConn).Ping(); + await GetServer(receiverConn).PingAsync(); + await GetServer(receiverConn).PingAsync(); await Task.Delay(1000).ConfigureAwait(false); Assert.True(count == -1 || count >= 2, "subscribers"); Assert.True(Interlocked.CompareExchange(ref total, 0, 0) >= 1, "total (1st)"); @@ -98,11 +95,11 @@ public async Task ConfigVerifyReceiveConfigChangeBroadcast() // and send a second time via a re-primary operation var server = GetServer(senderConn); - if (server.IsReplica) Skip.Inconclusive("didn't expect a replica"); + if (server.IsReplica) Assert.Skip("didn't expect a replica"); await server.MakePrimaryAsync(ReplicationChangeOptions.Broadcast); await Task.Delay(1000).ConfigureAwait(false); - GetServer(receiverConn).Ping(); - GetServer(receiverConn).Ping(); + await GetServer(receiverConn).PingAsync(); + await GetServer(receiverConn).PingAsync(); Assert.True(Interlocked.CompareExchange(ref total, 0, 0) >= 1, "total (2nd)"); } @@ -112,21 +109,21 @@ public async Task DereplicateGoesToPrimary() ConfigurationOptions config = GetPrimaryReplicaConfig(); config.ConfigCheckSeconds = 5; - using var conn = ConnectionMultiplexer.Connect(config); + await using var conn = await ConnectionMultiplexer.ConnectAsync(config); var primary = conn.GetServer(TestConfig.Current.FailoverPrimaryServerAndPort); var secondary = conn.GetServer(TestConfig.Current.FailoverReplicaServerAndPort); - primary.Ping(); - secondary.Ping(); + await primary.PingAsync(); + await secondary.PingAsync(); await primary.MakePrimaryAsync(ReplicationChangeOptions.SetTiebreaker); await secondary.MakePrimaryAsync(ReplicationChangeOptions.None); await Task.Delay(100).ConfigureAwait(false); - primary.Ping(); - secondary.Ping(); + await primary.PingAsync(); + await secondary.PingAsync(); using (var writer = new StringWriter()) { @@ -134,7 +131,7 @@ public async Task DereplicateGoesToPrimary() string log = writer.ToString(); Log(log); bool isUnanimous = log.Contains("tie-break is unanimous at " + TestConfig.Current.FailoverPrimaryServerAndPort); - if (!isUnanimous) Skip.Inconclusive("this is timing sensitive; unable to verify this time"); + if (!isUnanimous) Assert.Skip("this is timing sensitive; unable to verify this time"); } // k, so we know everyone loves 6379; is that what we get? @@ -154,8 +151,8 @@ public async Task DereplicateGoesToPrimary() await Task.Delay(100).ConfigureAwait(false); Log("Invoking Ping() (post-primary)"); - primary.Ping(); - secondary.Ping(); + await primary.PingAsync(); + await secondary.PingAsync(); Log("Finished Ping() (post-primary)"); Assert.True(primary.IsConnected, $"{primary.EndPoint} is not connected."); @@ -201,7 +198,7 @@ public async Task DereplicateGoesToPrimary() [Fact] public async Task SubscriptionsSurviveConnectionFailureAsync() { - using var conn = Create(allowAdmin: true, shared: false, log: Writer, syncTimeout: 1000); + await using var conn = Create(allowAdmin: true, shared: false, log: Writer, syncTimeout: 1000); var profiler = conn.AddProfiler(); RedisChannel channel = RedisChannel.Literal(Me()); @@ -217,7 +214,7 @@ public async Task SubscriptionsSurviveConnectionFailureAsync() await Task.Delay(200).ConfigureAwait(false); await sub.PublishAsync(channel, "abc").ConfigureAwait(false); - sub.Ping(); + await sub.PingAsync(); await Task.Delay(200).ConfigureAwait(false); var counter1 = Thread.VolatileRead(ref counter); @@ -256,7 +253,7 @@ public async Task SubscriptionsSurviveConnectionFailureAsync() var profile2 = Log(profiler); // Assert.Equal(1, profile2.Count(p => p.Command == nameof(RedisCommand.SUBSCRIBE))); Log("Issuing ping after reconnected"); - sub.Ping(); + await sub.PingAsync(); var muxerSubCount = conn.GetSubscriptionsCount(); Log($"Muxer thinks we have {muxerSubCount} subscriber(s)."); @@ -295,15 +292,10 @@ public async Task SubscriptionsSurviveConnectionFailureAsync() [Fact] public async Task SubscriptionsSurvivePrimarySwitchAsync() { - static void TopologyFail() => Skip.Inconclusive("Replication topology change failed...and that's both inconsistent and not what we're testing."); - - if (RunningInCI) - { - Skip.Inconclusive("TODO: Fix race in broadcast reconfig a zero latency."); - } + static void TopologyFail() => Assert.Skip("Replication topology change failed...and that's both inconsistent and not what we're testing."); - using var aConn = Create(allowAdmin: true, shared: false); - using var bConn = Create(allowAdmin: true, shared: false); + await using var aConn = Create(allowAdmin: true, shared: false); + await using var bConn = Create(allowAdmin: true, shared: false); RedisChannel channel = RedisChannel.Literal(Me()); Log("Using Channel: " + channel); @@ -362,8 +354,8 @@ public async Task SubscriptionsSurvivePrimarySwitchAsync() } Log("Waiting for connection B to detect..."); await UntilConditionAsync(TimeSpan.FromSeconds(10), () => bConn.GetServer(TestConfig.Current.FailoverPrimaryServerAndPort).IsReplica).ForAwait(); - subA.Ping(); - subB.Ping(); + await subA.PingAsync(); + await subB.PingAsync(); Log("Failover 2 Attempted. Pausing..."); Log(" A " + TestConfig.Current.FailoverPrimaryServerAndPort + " status: " + (aConn.GetServer(TestConfig.Current.FailoverPrimaryServerAndPort).IsReplica ? "Replica" : "Primary")); Log(" A " + TestConfig.Current.FailoverReplicaServerAndPort + " status: " + (aConn.GetServer(TestConfig.Current.FailoverReplicaServerAndPort).IsReplica ? "Replica" : "Primary")); @@ -391,7 +383,7 @@ public async Task SubscriptionsSurvivePrimarySwitchAsync() Log(" IsReplica: " + !server.IsReplica); Log(" Type: " + server.ServerType); } - // Skip.Inconclusive("Not enough latency."); + // Assert.Skip("Not enough latency."); } Assert.True(sanityCheck, $"B Connection: {TestConfig.Current.FailoverPrimaryServerAndPort} should be a replica"); Assert.False(bConn.GetServer(TestConfig.Current.FailoverReplicaServerAndPort).IsReplica, $"B Connection: {TestConfig.Current.FailoverReplicaServerAndPort} should be a primary"); @@ -399,8 +391,8 @@ public async Task SubscriptionsSurvivePrimarySwitchAsync() Log("Pause complete"); Log(" A outstanding: " + aConn.GetCounters().TotalOutstanding); Log(" B outstanding: " + bConn.GetCounters().TotalOutstanding); - subA.Ping(); - subB.Ping(); + await subA.PingAsync(); + await subB.PingAsync(); await Task.Delay(5000).ForAwait(); epA = subA.SubscribedEndpoint(channel); epB = subB.SubscribedEndpoint(channel); @@ -411,8 +403,8 @@ public async Task SubscriptionsSurvivePrimarySwitchAsync() var bSentTo = subB.Publish(channel, "B2"); Log(" A2 sent to: " + aSentTo); Log(" B2 sent to: " + bSentTo); - subA.Ping(); - subB.Ping(); + await subA.PingAsync(); + await subB.PingAsync(); Log("Ping Complete. Checking..."); await UntilConditionAsync(TimeSpan.FromSeconds(10), () => Interlocked.Read(ref aCount) == 2 && Interlocked.Read(ref bCount) == 2).ForAwait(); diff --git a/tests/StackExchange.Redis.Tests/FloatingPointTests.cs b/tests/StackExchange.Redis.Tests/FloatingPointTests.cs index 71bab0386..9b4b2bd7e 100644 --- a/tests/StackExchange.Redis.Tests/FloatingPointTests.cs +++ b/tests/StackExchange.Redis.Tests/FloatingPointTests.cs @@ -1,38 +1,34 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class FloatingPointTests : TestBase +public class FloatingPointTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public FloatingPointTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - private static bool Within(double x, double y, double delta) => Math.Abs(x - y) <= delta; [Fact] - public void IncrDecrFloatingPoint() + public async Task IncrDecrFloatingPoint() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = - { + [ 12.134, -14561.0000002, 125.3421, -2.49892498, - }, + ], decr = - { + [ 99.312, 12, -35, - }; + ]; double sum = 0; foreach (var value in incr) { @@ -52,24 +48,24 @@ public void IncrDecrFloatingPoint() [Fact] public async Task IncrDecrFloatingPointAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = - { + [ 12.134, -14561.0000002, 125.3421, -2.49892498, - }, + ], decr = - { + [ 99.312, 12, -35, - }; + ]; double sum = 0; foreach (var value in incr) { @@ -87,27 +83,27 @@ public async Task IncrDecrFloatingPointAsync() } [Fact] - public void HashIncrDecrFloatingPoint() + public async Task HashIncrDecrFloatingPoint() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); RedisValue field = "foo"; db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = - { + [ 12.134, -14561.0000002, 125.3421, -2.49892498, - }, + ], decr = - { + [ 99.312, 12, -35, - }; + ]; double sum = 0; foreach (var value in incr) { @@ -127,25 +123,25 @@ public void HashIncrDecrFloatingPoint() [Fact] public async Task HashIncrDecrFloatingPointAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); RedisValue field = "bar"; db.KeyDelete(key, CommandFlags.FireAndForget); double[] incr = - { + [ 12.134, -14561.0000002, 125.3421, -2.49892498, - }, + ], decr = - { + [ 99.312, 12, -35, - }; + ]; double sum = 0; foreach (var value in incr) { diff --git a/tests/StackExchange.Redis.Tests/FormatTests.cs b/tests/StackExchange.Redis.Tests/FormatTests.cs index 9356c2e31..451db8c20 100644 --- a/tests/StackExchange.Redis.Tests/FormatTests.cs +++ b/tests/StackExchange.Redis.Tests/FormatTests.cs @@ -3,14 +3,11 @@ using System.Net; using System.Text; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class FormatTests : TestBase +public class FormatTests(ITestOutputHelper output) : TestBase(output) { - public FormatTests(ITestOutputHelper output) : base(output) { } - public static IEnumerable EndpointData() { // note: the 3rd arg is for formatting; null means "expect the original string" diff --git a/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs b/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs index 8a263c553..ef28ed6e9 100644 --- a/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs +++ b/tests/StackExchange.Redis.Tests/GarbageCollectionTests.cs @@ -2,15 +2,12 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] // because I need to measure some things that could get confused -public class GarbageCollectionTests : TestBase +public class GarbageCollectionTests(ITestOutputHelper helper) : TestBase(helper) { - public GarbageCollectionTests(ITestOutputHelper helper) : base(helper) { } - private static void ForceGC() { for (int i = 0; i < 3; i++) @@ -24,14 +21,14 @@ private static void ForceGC() public async Task MuxerIsCollected() { #if DEBUG - Skip.Inconclusive("Only predictable in release builds"); + Assert.Skip("Only predictable in release builds"); #endif // this is more nuanced than it looks; multiple sockets with // async callbacks, plus a heartbeat on a timer // deliberately not "using" - we *want* to leak this var conn = Create(); - conn.GetDatabase().Ping(); // smoke-test + await conn.GetDatabase().PingAsync(); // smoke-test ForceGC(); @@ -57,6 +54,7 @@ public async Task MuxerIsCollected() [Fact] public async Task UnrootedBackloggedAsyncTaskIsCompletedOnTimeout() { + Skip.UnlessLongRunning(); // Run the test on a separate thread without keeping a reference to the task to ensure // that there are no references to the variables in test task from the main thread. // WithTimeout must not be used within Task.Run because timers are rooted and would keep everything alive. @@ -64,7 +62,7 @@ public async Task UnrootedBackloggedAsyncTaskIsCompletedOnTimeout() Task? completedTestTask = null; _ = Task.Run(async () => { - using var conn = await ConnectionMultiplexer.ConnectAsync( + await using var conn = await ConnectionMultiplexer.ConnectAsync( new ConfigurationOptions() { BacklogPolicy = BacklogPolicy.Default, diff --git a/tests/StackExchange.Redis.Tests/GeoTests.cs b/tests/StackExchange.Redis.Tests/GeoTests.cs index 84fa30386..c46f65be7 100644 --- a/tests/StackExchange.Redis.Tests/GeoTests.cs +++ b/tests/StackExchange.Redis.Tests/GeoTests.cs @@ -1,28 +1,24 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class GeoTests : TestBase +public class GeoTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public GeoTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - private static readonly GeoEntry Palermo = new GeoEntry(13.361389, 38.115556, "Palermo"), Catania = new GeoEntry(15.087269, 37.502669, "Catania"), Agrigento = new GeoEntry(13.5765, 37.311, "Agrigento"), Cefalù = new GeoEntry(14.0188, 38.0084, "Cefalù"); - private static readonly GeoEntry[] All = { Palermo, Catania, Agrigento, Cefalù }; + private static readonly GeoEntry[] All = [Palermo, Catania, Agrigento, Cefalù]; [Fact] - public void GeoAdd() + public async Task GeoAdd() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -30,12 +26,12 @@ public void GeoAdd() // add while not there Assert.True(db.GeoAdd(key, Cefalù.Longitude, Cefalù.Latitude, Cefalù.Member)); - Assert.Equal(2, db.GeoAdd(key, new[] { Palermo, Catania })); + Assert.Equal(2, db.GeoAdd(key, [Palermo, Catania])); Assert.True(db.GeoAdd(key, Agrigento)); // now add again Assert.False(db.GeoAdd(key, Cefalù.Longitude, Cefalù.Latitude, Cefalù.Member)); - Assert.Equal(0, db.GeoAdd(key, new[] { Palermo, Catania })); + Assert.Equal(0, db.GeoAdd(key, [Palermo, Catania])); Assert.False(db.GeoAdd(key, Agrigento)); // Validate @@ -46,9 +42,9 @@ public void GeoAdd() } [Fact] - public void GetDistance() + public async Task GetDistance() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -63,16 +59,16 @@ public void GetDistance() } [Fact] - public void GeoHash() + public async Task GeoHash() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.GeoAdd(key, All, CommandFlags.FireAndForget); - var hashes = db.GeoHash(key, new RedisValue[] { Palermo.Member, "Nowhere", Agrigento.Member }); + var hashes = db.GeoHash(key, [Palermo.Member, "Nowhere", Agrigento.Member]); Assert.NotNull(hashes); Assert.Equal(3, hashes.Length); Assert.Equal("sqc8b49rny0", hashes[0]); @@ -87,9 +83,9 @@ public void GeoHash() } [Fact] - public void GeoGetPosition() + public async Task GeoGetPosition() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -106,9 +102,9 @@ public void GeoGetPosition() } [Fact] - public void GeoRemove() + public async Task GeoRemove() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -127,9 +123,9 @@ public void GeoRemove() } [Fact] - public void GeoRadius() + public async Task GeoRadius() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -173,7 +169,7 @@ public void GeoRadius() [Fact] public async Task GeoRadiusOverloads() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -222,7 +218,7 @@ private void GeoSearchSetup(RedisKey key, IDatabase db) [Fact] public async Task GeoSearchCircleMemberAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -243,7 +239,7 @@ public async Task GeoSearchCircleMemberAsync() [Fact] public async Task GeoSearchCircleMemberAsyncOnlyHash() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -264,7 +260,7 @@ public async Task GeoSearchCircleMemberAsyncOnlyHash() [Fact] public async Task GeoSearchCircleMemberAsyncHashAndDistance() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -285,7 +281,7 @@ public async Task GeoSearchCircleMemberAsyncHashAndDistance() [Fact] public async Task GeoSearchCircleLonLatAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -301,9 +297,9 @@ public async Task GeoSearchCircleLonLatAsync() } [Fact] - public void GeoSearchCircleMember() + public async Task GeoSearchCircleMember() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -319,9 +315,9 @@ public void GeoSearchCircleMember() } [Fact] - public void GeoSearchCircleLonLat() + public async Task GeoSearchCircleLonLat() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -339,7 +335,7 @@ public void GeoSearchCircleLonLat() [Fact] public async Task GeoSearchBoxMemberAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -356,7 +352,7 @@ public async Task GeoSearchBoxMemberAsync() [Fact] public async Task GeoSearchBoxLonLatAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -371,9 +367,9 @@ public async Task GeoSearchBoxLonLatAsync() } [Fact] - public void GeoSearchBoxMember() + public async Task GeoSearchBoxMember() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -388,9 +384,9 @@ public void GeoSearchBoxMember() } [Fact] - public void GeoSearchBoxLonLat() + public async Task GeoSearchBoxLonLat() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -405,9 +401,9 @@ public void GeoSearchBoxLonLat() } [Fact] - public void GeoSearchLimitCount() + public async Task GeoSearchLimitCount() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -421,9 +417,9 @@ public void GeoSearchLimitCount() } [Fact] - public void GeoSearchLimitCountMakeNoDemands() + public async Task GeoSearchLimitCountMakeNoDemands() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -439,7 +435,7 @@ public void GeoSearchLimitCountMakeNoDemands() [Fact] public async Task GeoSearchBoxLonLatDescending() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -457,7 +453,7 @@ public async Task GeoSearchBoxLonLatDescending() [Fact] public async Task GeoSearchBoxMemberAndStoreAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -479,7 +475,7 @@ public async Task GeoSearchBoxMemberAndStoreAsync() [Fact] public async Task GeoSearchBoxLonLatAndStoreAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -501,7 +497,7 @@ public async Task GeoSearchBoxLonLatAndStoreAsync() [Fact] public async Task GeoSearchCircleMemberAndStoreAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -523,7 +519,7 @@ public async Task GeoSearchCircleMemberAndStoreAsync() [Fact] public async Task GeoSearchCircleLonLatAndStoreAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -543,9 +539,9 @@ public async Task GeoSearchCircleLonLatAndStoreAsync() } [Fact] - public void GeoSearchCircleMemberAndStore() + public async Task GeoSearchCircleMemberAndStore() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -565,9 +561,9 @@ public void GeoSearchCircleMemberAndStore() } [Fact] - public void GeoSearchCircleLonLatAndStore() + public async Task GeoSearchCircleLonLatAndStore() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -587,9 +583,9 @@ public void GeoSearchCircleLonLatAndStore() } [Fact] - public void GeoSearchCircleAndStoreDistOnly() + public async Task GeoSearchCircleAndStoreDistOnly() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var me = Me(); var db = conn.GetDatabase(); @@ -612,9 +608,9 @@ public void GeoSearchCircleAndStoreDistOnly() } [Fact] - public void GeoSearchBadArgs() + public async Task GeoSearchBadArgs() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/HashFieldTests.cs b/tests/StackExchange.Redis.Tests/HashFieldTests.cs index e50cd0546..3d1cb0c6e 100644 --- a/tests/StackExchange.Redis.Tests/HashFieldTests.cs +++ b/tests/StackExchange.Redis.Tests/HashFieldTests.cs @@ -1,7 +1,7 @@ using System; using System.Linq; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -9,19 +9,14 @@ namespace StackExchange.Redis.Tests; /// Tests for . /// [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class HashFieldTests : TestBase +public class HashFieldTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { private readonly DateTime nextCentury = new DateTime(2101, 1, 1, 0, 0, 0, DateTimeKind.Utc); private readonly TimeSpan oneYearInMs = TimeSpan.FromMilliseconds(31536000000); - private readonly HashEntry[] entries = new HashEntry[] { new("f1", 1), new("f2", 2) }; + private readonly HashEntry[] entries = [new("f1", 1), new("f2", 2)]; - private readonly RedisValue[] fields = new RedisValue[] { "f1", "f2" }; - - public HashFieldTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) - { - } + private readonly RedisValue[] fields = ["f1", "f2"]; [Fact] public void HashFieldExpire() @@ -31,10 +26,10 @@ public void HashFieldExpire() db.HashSet(hashKey, entries); var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); - Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); + Assert.Equal([ExpireResult.Success, ExpireResult.Success], fieldsResult); fieldsResult = db.HashFieldExpire(hashKey, fields, nextCentury); - Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, }, fieldsResult); + Assert.Equal([ExpireResult.Success, ExpireResult.Success,], fieldsResult); } [Fact] @@ -44,37 +39,37 @@ public void HashFieldExpireNoKey() var hashKey = Me(); var fieldsResult = db.HashFieldExpire(hashKey, fields, oneYearInMs); - Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); + Assert.Equal([ExpireResult.NoSuchField, ExpireResult.NoSuchField], fieldsResult); fieldsResult = db.HashFieldExpire(hashKey, fields, nextCentury); - Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); + Assert.Equal([ExpireResult.NoSuchField, ExpireResult.NoSuchField], fieldsResult); } [Fact] - public async void HashFieldExpireAsync() + public async Task HashFieldExpireAsync() { var db = Create(require: RedisFeatures.v7_4_0_rc1).GetDatabase(); var hashKey = Me(); db.HashSet(hashKey, entries); var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); - Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); + Assert.Equal([ExpireResult.Success, ExpireResult.Success], fieldsResult); fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, nextCentury); - Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success }, fieldsResult); + Assert.Equal([ExpireResult.Success, ExpireResult.Success], fieldsResult); } [Fact] - public async void HashFieldExpireAsyncNoKey() + public async Task HashFieldExpireAsyncNoKey() { var db = Create(require: RedisFeatures.v7_4_0_rc2).GetDatabase(); var hashKey = Me(); var fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, oneYearInMs); - Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); + Assert.Equal([ExpireResult.NoSuchField, ExpireResult.NoSuchField], fieldsResult); fieldsResult = await db.HashFieldExpireAsync(hashKey, fields, nextCentury); - Assert.Equal(new[] { ExpireResult.NoSuchField, ExpireResult.NoSuchField }, fieldsResult); + Assert.Equal([ExpireResult.NoSuchField, ExpireResult.NoSuchField], fieldsResult); } [Fact] @@ -84,8 +79,8 @@ public void HashFieldGetExpireDateTimeIsDue() var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldExpire(hashKey, new RedisValue[] { "f1" }, new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)); - Assert.Equal(new[] { ExpireResult.Due }, result); + var result = db.HashFieldExpire(hashKey, ["f1"], new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal([ExpireResult.Due], result); } [Fact] @@ -95,8 +90,8 @@ public void HashFieldExpireNoField() var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldExpire(hashKey, new RedisValue[] { "nonExistingField" }, oneYearInMs); - Assert.Equal(new[] { ExpireResult.NoSuchField }, result); + var result = db.HashFieldExpire(hashKey, ["nonExistingField"], oneYearInMs); + Assert.Equal([ExpireResult.NoSuchField], result); } [Fact] @@ -106,21 +101,21 @@ public void HashFieldExpireConditionsSatisfied() var hashKey = Me(); db.KeyDelete(hashKey); db.HashSet(hashKey, entries); - db.HashSet(hashKey, new HashEntry[] { new("f3", 3), new("f4", 4) }); - var initialExpire = db.HashFieldExpire(hashKey, new RedisValue[] { "f2", "f3", "f4" }, new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); - Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, ExpireResult.Success }, initialExpire); + db.HashSet(hashKey, [new("f3", 3), new("f4", 4)]); + var initialExpire = db.HashFieldExpire(hashKey, ["f2", "f3", "f4"], new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal([ExpireResult.Success, ExpireResult.Success, ExpireResult.Success], initialExpire); - var result = db.HashFieldExpire(hashKey, new RedisValue[] { "f1" }, oneYearInMs, ExpireWhen.HasNoExpiry); - Assert.Equal(new[] { ExpireResult.Success }, result); + var result = db.HashFieldExpire(hashKey, ["f1"], oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal([ExpireResult.Success], result); - result = db.HashFieldExpire(hashKey, new RedisValue[] { "f2" }, oneYearInMs, ExpireWhen.HasExpiry); - Assert.Equal(new[] { ExpireResult.Success }, result); + result = db.HashFieldExpire(hashKey, ["f2"], oneYearInMs, ExpireWhen.HasExpiry); + Assert.Equal([ExpireResult.Success], result); - result = db.HashFieldExpire(hashKey, new RedisValue[] { "f3" }, nextCentury, ExpireWhen.GreaterThanCurrentExpiry); - Assert.Equal(new[] { ExpireResult.Success }, result); + result = db.HashFieldExpire(hashKey, ["f3"], nextCentury, ExpireWhen.GreaterThanCurrentExpiry); + Assert.Equal([ExpireResult.Success], result); - result = db.HashFieldExpire(hashKey, new RedisValue[] { "f4" }, oneYearInMs, ExpireWhen.LessThanCurrentExpiry); - Assert.Equal(new[] { ExpireResult.Success }, result); + result = db.HashFieldExpire(hashKey, ["f4"], oneYearInMs, ExpireWhen.LessThanCurrentExpiry); + Assert.Equal([ExpireResult.Success], result); } [Fact] @@ -130,21 +125,21 @@ public void HashFieldExpireConditionsNotSatisfied() var hashKey = Me(); db.KeyDelete(hashKey); db.HashSet(hashKey, entries); - db.HashSet(hashKey, new HashEntry[] { new("f3", 3), new("f4", 4) }); - var initialExpire = db.HashFieldExpire(hashKey, new RedisValue[] { "f2", "f3", "f4" }, new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); - Assert.Equal(new[] { ExpireResult.Success, ExpireResult.Success, ExpireResult.Success }, initialExpire); + db.HashSet(hashKey, [new("f3", 3), new("f4", 4)]); + var initialExpire = db.HashFieldExpire(hashKey, ["f2", "f3", "f4"], new DateTime(2050, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal([ExpireResult.Success, ExpireResult.Success, ExpireResult.Success], initialExpire); - var result = db.HashFieldExpire(hashKey, new RedisValue[] { "f1" }, oneYearInMs, ExpireWhen.HasExpiry); - Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); + var result = db.HashFieldExpire(hashKey, ["f1"], oneYearInMs, ExpireWhen.HasExpiry); + Assert.Equal([ExpireResult.ConditionNotMet], result); - result = db.HashFieldExpire(hashKey, new RedisValue[] { "f2" }, oneYearInMs, ExpireWhen.HasNoExpiry); - Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); + result = db.HashFieldExpire(hashKey, ["f2"], oneYearInMs, ExpireWhen.HasNoExpiry); + Assert.Equal([ExpireResult.ConditionNotMet], result); - result = db.HashFieldExpire(hashKey, new RedisValue[] { "f3" }, nextCentury, ExpireWhen.LessThanCurrentExpiry); - Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); + result = db.HashFieldExpire(hashKey, ["f3"], nextCentury, ExpireWhen.LessThanCurrentExpiry); + Assert.Equal([ExpireResult.ConditionNotMet], result); - result = db.HashFieldExpire(hashKey, new RedisValue[] { "f4" }, oneYearInMs, ExpireWhen.GreaterThanCurrentExpiry); - Assert.Equal(new[] { ExpireResult.ConditionNotMet }, result); + result = db.HashFieldExpire(hashKey, ["f4"], oneYearInMs, ExpireWhen.GreaterThanCurrentExpiry); + Assert.Equal([ExpireResult.ConditionNotMet], result); } [Fact] @@ -156,11 +151,11 @@ public void HashFieldGetExpireDateTime() db.HashFieldExpire(hashKey, fields, nextCentury); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "f1" }); - Assert.Equal(new[] { ms }, result); + var result = db.HashFieldGetExpireDateTime(hashKey, ["f1"]); + Assert.Equal([ms], result); var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new[] { ms, ms }, fieldsResult); + Assert.Equal([ms, ms], fieldsResult); } [Fact] @@ -170,11 +165,11 @@ public void HashFieldExpireFieldNoExpireTime() var hashKey = Me(); db.HashSet(hashKey, entries); - var result = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "f1" }); - Assert.Equal(new[] { -1L }, result); + var result = db.HashFieldGetExpireDateTime(hashKey, ["f1"]); + Assert.Equal([-1L], result); var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -1, -1, }, fieldsResult); + Assert.Equal([-1, -1,], fieldsResult); } [Fact] @@ -184,7 +179,7 @@ public void HashFieldGetExpireDateTimeNoKey() var hashKey = Me(); var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, fields); - Assert.Equal(new long[] { -2, -2, }, fieldsResult); + Assert.Equal([-2, -2,], fieldsResult); } [Fact] @@ -195,8 +190,8 @@ public void HashFieldGetExpireDateTimeNoField() db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); - Assert.Equal(new long[] { -2, -2, }, fieldsResult); + var fieldsResult = db.HashFieldGetExpireDateTime(hashKey, ["notExistingField1", "notExistingField2"]); + Assert.Equal([-2, -2,], fieldsResult); } [Fact] @@ -208,7 +203,7 @@ public void HashFieldGetTimeToLive() db.HashFieldExpire(hashKey, fields, oneYearInMs); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" }); + var result = db.HashFieldGetTimeToLive(hashKey, ["f1"]); Assert.NotNull(result); Assert.True(result.Length == 1); Assert.True(result[0] > 0); @@ -227,7 +222,7 @@ public void HashFieldGetTimeToLiveNoExpireTime() db.HashSet(hashKey, entries); var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.Equal(new long[] { -1, -1, }, fieldsResult); + Assert.Equal([-1, -1,], fieldsResult); } [Fact] @@ -237,7 +232,7 @@ public void HashFieldGetTimeToLiveNoKey() var hashKey = Me(); var fieldsResult = db.HashFieldGetTimeToLive(hashKey, fields); - Assert.Equal(new long[] { -2, -2, }, fieldsResult); + Assert.Equal([-2, -2,], fieldsResult); } [Fact] @@ -248,8 +243,8 @@ public void HashFieldGetTimeToLiveNoField() db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var fieldsResult = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); - Assert.Equal(new long[] { -2, -2, }, fieldsResult); + var fieldsResult = db.HashFieldGetTimeToLive(hashKey, ["notExistingField1", "notExistingField2"]); + Assert.Equal([-2, -2,], fieldsResult); } [Fact] @@ -261,13 +256,13 @@ public void HashFieldPersist() db.HashFieldExpire(hashKey, fields, oneYearInMs); long ms = new DateTimeOffset(nextCentury).ToUnixTimeMilliseconds(); - var result = db.HashFieldPersist(hashKey, new RedisValue[] { "f1" }); - Assert.Equal(new[] { PersistResult.Success }, result); + var result = db.HashFieldPersist(hashKey, ["f1"]); + Assert.Equal([PersistResult.Success], result); db.HashFieldExpire(hashKey, fields, oneYearInMs); var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Equal(new[] { PersistResult.Success, PersistResult.Success }, fieldsResult); + Assert.Equal([PersistResult.Success, PersistResult.Success], fieldsResult); } [Fact] @@ -278,7 +273,7 @@ public void HashFieldPersistNoExpireTime() db.HashSet(hashKey, entries); var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Equal(new[] { PersistResult.ConditionNotMet, PersistResult.ConditionNotMet }, fieldsResult); + Assert.Equal([PersistResult.ConditionNotMet, PersistResult.ConditionNotMet], fieldsResult); } [Fact] @@ -288,7 +283,7 @@ public void HashFieldPersistNoKey() var hashKey = Me(); var fieldsResult = db.HashFieldPersist(hashKey, fields); - Assert.Equal(new[] { PersistResult.NoSuchField, PersistResult.NoSuchField }, fieldsResult); + Assert.Equal([PersistResult.NoSuchField, PersistResult.NoSuchField], fieldsResult); } [Fact] @@ -299,7 +294,7 @@ public void HashFieldPersistNoField() db.HashSet(hashKey, entries); db.HashFieldExpire(hashKey, fields, oneYearInMs); - var fieldsResult = db.HashFieldPersist(hashKey, new RedisValue[] { "notExistingField1", "notExistingField2" }); - Assert.Equal(new[] { PersistResult.NoSuchField, PersistResult.NoSuchField }, fieldsResult); + var fieldsResult = db.HashFieldPersist(hashKey, ["notExistingField1", "notExistingField2"]); + Assert.Equal([PersistResult.NoSuchField, PersistResult.NoSuchField], fieldsResult); } } diff --git a/tests/StackExchange.Redis.Tests/HashTests.cs b/tests/StackExchange.Redis.Tests/HashTests.cs index b949f5911..af2fa11c8 100644 --- a/tests/StackExchange.Redis.Tests/HashTests.cs +++ b/tests/StackExchange.Redis.Tests/HashTests.cs @@ -4,7 +4,6 @@ using System.Text; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -12,15 +11,12 @@ namespace StackExchange.Redis.Tests; /// Tests for . /// [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class HashTests : TestBase +public class HashTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public HashTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task TestIncrBy() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -45,7 +41,7 @@ public async Task TestIncrBy() [Fact] public async Task ScanAsync() { - using var conn = Create(require: RedisFeatures.v2_8_0); + await using var conn = Create(require: RedisFeatures.v2_8_0); var db = conn.GetDatabase(); var key = Me(); @@ -89,17 +85,17 @@ public async Task ScanAsync() } [Fact] - public void Scan() + public async Task Scan() { - using var conn = Create(require: RedisFeatures.v2_8_0); + await using var conn = Create(require: RedisFeatures.v2_8_0); var db = conn.GetDatabase(); var key = Me(); - db.KeyDeleteAsync(key); - db.HashSetAsync(key, "abc", "def"); - db.HashSetAsync(key, "ghi", "jkl"); - db.HashSetAsync(key, "mno", "pqr"); + _ = db.KeyDeleteAsync(key); + _ = db.HashSetAsync(key, "abc", "def"); + _ = db.HashSetAsync(key, "ghi", "jkl"); + _ = db.HashSetAsync(key, "mno", "pqr"); var t1 = db.HashScan(key); var t2 = db.HashScan(key, "*h*"); @@ -129,7 +125,7 @@ public void Scan() [Fact] public async Task ScanNoValuesAsync() { - using var conn = Create(require: RedisFeatures.v7_4_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_4_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -173,17 +169,17 @@ public async Task ScanNoValuesAsync() } [Fact] - public void ScanNoValues() + public async Task ScanNoValues() { - using var conn = Create(require: RedisFeatures.v7_4_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_4_0_rc1); var db = conn.GetDatabase(); var key = Me(); - db.KeyDeleteAsync(key); - db.HashSetAsync(key, "abc", "def"); - db.HashSetAsync(key, "ghi", "jkl"); - db.HashSetAsync(key, "mno", "pqr"); + _ = db.KeyDeleteAsync(key); + _ = db.HashSetAsync(key, "abc", "def"); + _ = db.HashSetAsync(key, "ghi", "jkl"); + _ = db.HashSetAsync(key, "mno", "pqr"); var t1 = db.HashScanNoValues(key); var t2 = db.HashScanNoValues(key, "*h*"); @@ -212,12 +208,12 @@ public void ScanNoValues() } [Fact] - public void TestIncrementOnHashThatDoesntExist() + public async Task TestIncrementOnHashThatDoesntExist() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); - db.KeyDeleteAsync("keynotexist"); + _ = db.KeyDeleteAsync("keynotexist"); var result1 = db.Wait(db.HashIncrementAsync("keynotexist", "fieldnotexist", 1)); var result2 = db.Wait(db.HashIncrementAsync("keynotexist", "anotherfieldnotexist", 1)); Assert.Equal(1, result1); @@ -227,7 +223,7 @@ public void TestIncrementOnHashThatDoesntExist() [Fact] public async Task TestIncrByFloat() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var key = Me(); @@ -250,7 +246,7 @@ public async Task TestIncrByFloat() [Fact] public async Task TestGetAll() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -282,7 +278,7 @@ public async Task TestGetAll() [Fact] public async Task TestGet() { - using var conn = Create(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); @@ -314,7 +310,7 @@ public async Task TestGet() [Fact] public async Task TestSet() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -356,7 +352,7 @@ public async Task TestSet() [Fact] public async Task TestSetNotExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -390,7 +386,7 @@ public async Task TestSetNotExists() [Fact] public async Task TestDelSingle() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -413,7 +409,7 @@ public async Task TestDelSingle() [Fact] public async Task TestDelMulti() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -425,7 +421,7 @@ public async Task TestDelMulti() var s2 = db.HashExistsAsync(hashkey, "key2"); var s3 = db.HashExistsAsync(hashkey, "key3"); - var removed = db.HashDeleteAsync(hashkey, new RedisValue[] { "key1", "key3" }); + var removed = db.HashDeleteAsync(hashkey, ["key1", "key3"]); var d1 = db.HashExistsAsync(hashkey, "key1"); var d2 = db.HashExistsAsync(hashkey, "key2"); @@ -441,7 +437,7 @@ public async Task TestDelMulti() Assert.True(await d2); Assert.False(await d3); - var removeFinal = db.HashDeleteAsync(hashkey, new RedisValue[] { "key2" }); + var removeFinal = db.HashDeleteAsync(hashkey, ["key2"]); Assert.Equal(0, await db.HashLengthAsync(hashkey).ForAwait()); Assert.Equal(1, await removeFinal); @@ -453,7 +449,7 @@ public async Task TestDelMulti() [Fact] public async Task TestDelMultiInsideTransaction() { - using var conn = Create(); + await using var conn = Create(); var tran = conn.GetDatabase().CreateTransaction(); { @@ -466,7 +462,7 @@ public async Task TestDelMultiInsideTransaction() var s2 = tran.HashExistsAsync(hashkey, "key2"); var s3 = tran.HashExistsAsync(hashkey, "key3"); - var removed = tran.HashDeleteAsync(hashkey, new RedisValue[] { "key1", "key3" }); + var removed = tran.HashDeleteAsync(hashkey, ["key1", "key3"]); var d1 = tran.HashExistsAsync(hashkey, "key1"); var d2 = tran.HashExistsAsync(hashkey, "key2"); @@ -492,7 +488,7 @@ public async Task TestDelMultiInsideTransaction() [Fact] public async Task TestExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -514,7 +510,7 @@ public async Task TestExists() [Fact] public async Task TestHashKeys() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashKey = Me(); @@ -540,7 +536,7 @@ public async Task TestHashKeys() [Fact] public async Task TestHashValues() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -567,7 +563,7 @@ public async Task TestHashValues() [Fact] public async Task TestHashLength() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -590,13 +586,13 @@ public async Task TestHashLength() [Fact] public async Task TestGetMulti() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); db.KeyDelete(hashkey, CommandFlags.FireAndForget); - RedisValue[] fields = { "foo", "bar", "blop" }; + RedisValue[] fields = ["foo", "bar", "blop"]; var arr0 = await db.HashGetAsync(hashkey, fields).ForAwait(); db.HashSet(hashkey, "foo", "abc", flags: CommandFlags.FireAndForget); @@ -625,18 +621,18 @@ public async Task TestGetMulti() /// Tests for . /// [Fact] - public void TestGetPairs() + public async Task TestGetPairs() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); - db.KeyDeleteAsync(hashkey); + _ = db.KeyDeleteAsync(hashkey); var result0 = db.HashGetAllAsync(hashkey); - db.HashSetAsync(hashkey, "foo", "abc"); - db.HashSetAsync(hashkey, "bar", "def"); + _ = db.HashSetAsync(hashkey, "foo", "abc"); + _ = db.HashSetAsync(hashkey, "bar", "def"); var result1 = db.HashGetAllAsync(hashkey); @@ -651,13 +647,13 @@ public void TestGetPairs() /// Tests for . /// [Fact] - public void TestSetPairs() + public async Task TestSetPairs() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); - db.KeyDeleteAsync(hashkey).ForAwait(); + _ = db.KeyDeleteAsync(hashkey).ForAwait(); var result0 = db.HashGetAllAsync(hashkey); @@ -666,7 +662,7 @@ public void TestSetPairs() new HashEntry("foo", Encoding.UTF8.GetBytes("abc")), new HashEntry("bar", Encoding.UTF8.GetBytes("def")), }; - db.HashSetAsync(hashkey, data).ForAwait(); + _ = db.HashSetAsync(hashkey, data).ForAwait(); var result1 = db.Wait(db.HashGetAllAsync(hashkey)); @@ -680,7 +676,7 @@ public void TestSetPairs() [Fact] public async Task TestWhenAlwaysAsync() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var hashkey = Me(); @@ -701,7 +697,7 @@ public async Task TestWhenAlwaysAsync() [Fact] public async Task HashRandomFieldAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var hashKey = Me(); @@ -727,9 +723,9 @@ public async Task HashRandomFieldAsync() } [Fact] - public void HashRandomField() + public async Task HashRandomField() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var hashKey = Me(); @@ -755,9 +751,9 @@ public void HashRandomField() } [Fact] - public void HashRandomFieldEmptyHash() + public async Task HashRandomFieldEmptyHash() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var hashKey = Me(); diff --git a/tests/StackExchange.Redis.Tests/HeartbeatTests.cs b/tests/StackExchange.Redis.Tests/HeartbeatTests.cs new file mode 100644 index 000000000..4de271f9a --- /dev/null +++ b/tests/StackExchange.Redis.Tests/HeartbeatTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace StackExchange.Redis.Tests; + +[RunPerProtocol] +public class HeartbeatTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) +{ + [Fact] + public async Task TestAutomaticHeartbeat() + { + RedisValue oldTimeout = RedisValue.Null; + await using var configConn = Create(allowAdmin: true); + + try + { + configConn.GetDatabase(); + var srv = GetAnyPrimary(configConn); + oldTimeout = srv.ConfigGet("timeout")[0].Value; + Log("Old Timeout: " + oldTimeout); + srv.ConfigSet("timeout", 3); + + await using var innerConn = Create(); + var innerDb = innerConn.GetDatabase(); + await innerDb.PingAsync(); // need to wait to pick up configuration etc + + var before = innerConn.OperationCount; + + Log("sleeping to test heartbeat..."); + await Task.Delay(TimeSpan.FromSeconds(5)).ForAwait(); + + var after = innerConn.OperationCount; + Assert.True(after >= before + 1, $"after: {after}, before: {before}"); + } + finally + { + if (!oldTimeout.IsNull) + { + Log("Resetting old timeout: " + oldTimeout); + var srv = GetAnyPrimary(configConn); + srv.ConfigSet("timeout", oldTimeout); + } + } + } +} diff --git a/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs b/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs index ab0583764..a3386e80c 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/Attributes.cs @@ -3,11 +3,18 @@ using System.Globalization; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Xunit.Abstractions; +using Xunit; +using Xunit.Internal; using Xunit.Sdk; +using Xunit.v3; +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1502 // Element should not be on a single line +#pragma warning disable SA1649 // File name should match first type name +#pragma warning disable IDE0130 // Namespace does not match folder structure namespace StackExchange.Redis.Tests; /// @@ -19,18 +26,8 @@ namespace StackExchange.Redis.Tests; /// /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -[XunitTestCaseDiscoverer("StackExchange.Redis.Tests.FactDiscoverer", "StackExchange.Redis.Tests")] -public class FactAttribute : Xunit.FactAttribute { } - -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -public class FactLongRunningAttribute : FactAttribute -{ - public override string Skip - { - get => TestConfig.Current.RunLongRunning ? base.Skip : "Config.RunLongRunning is false - skipping long test."; - set => base.Skip = value; - } -} +[XunitTestCaseDiscoverer(typeof(FactDiscoverer))] +public class FactAttribute([CallerFilePath] string? sourceFilePath = null, [CallerLineNumber] int sourceLineNumber = -1) : Xunit.FactAttribute(sourceFilePath, sourceLineNumber) { } /// /// Override for that truncates our DisplayName down. @@ -43,223 +40,134 @@ public override string Skip /// /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -[XunitTestCaseDiscoverer("StackExchange.Redis.Tests.TheoryDiscoverer", "StackExchange.Redis.Tests")] -public class TheoryAttribute : Xunit.TheoryAttribute { } +[XunitTestCaseDiscoverer(typeof(TheoryDiscoverer))] +public class TheoryAttribute([CallerFilePath] string? sourceFilePath = null, [CallerLineNumber] int sourceLineNumber = -1) : Xunit.TheoryAttribute(sourceFilePath, sourceLineNumber) { } -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -public class TheoryLongRunningAttribute : Xunit.TheoryAttribute +public class FactDiscoverer : Xunit.v3.FactDiscoverer { - public override string Skip - { - get => TestConfig.Current.RunLongRunning ? base.Skip : "Config.RunLongRunning is false - skipping long test."; - set => base.Skip = value; - } + public override ValueTask> Discover(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, IFactAttribute factAttribute) + => base.Discover(discoveryOptions, testMethod, factAttribute).ExpandAsync(); } -public class FactDiscoverer : Xunit.Sdk.FactDiscoverer +public class TheoryDiscoverer : Xunit.v3.TheoryDiscoverer { - public FactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { } + protected override ValueTask> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute, ITheoryDataRow dataRow, object?[] testMethodArguments) + => base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, testMethodArguments).ExpandAsync(); - public override IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) - { - if (testMethod.Method.GetParameters().Any()) - { - return new[] { new ExecutionErrorTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "[Fact] methods are not allowed to have parameters. Did you mean to use [Theory]?") }; - } - else if (testMethod.Method.IsGenericMethodDefinition) - { - return new[] { new ExecutionErrorTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "[Fact] methods are not allowed to be generic.") }; - } - else - { - return testMethod.Expand(protocol => new SkippableTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, protocol: protocol)); - } - } + protected override ValueTask> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute) + => base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute).ExpandAsync(); } -public class TheoryDiscoverer : Xunit.Sdk.TheoryDiscoverer -{ - public TheoryDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { } - - protected override IEnumerable CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow) - => testMethod.Expand(protocol => new SkippableTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, dataRow, protocol: protocol)); - - protected override IEnumerable CreateTestCasesForSkip(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, string skipReason) - => testMethod.Expand(protocol => new SkippableTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, protocol: protocol)); - - protected override IEnumerable CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute) - => testMethod.Expand(protocol => new SkippableTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, protocol: protocol)); +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] +public class RunPerProtocol() : Attribute { } - protected override IEnumerable CreateTestCasesForSkippedDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow, string skipReason) - => new[] { new NamedSkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow) }; +public interface IProtocolTestCase +{ + RedisProtocol Protocol { get; } } -public class SkippableTestCase : XunitTestCase, IRedisTest +public class ProtocolTestCase : XunitTestCase, IProtocolTestCase { - public RedisProtocol Protocol { get; set; } - public string ProtocolString => Protocol switch - { - RedisProtocol.Resp2 => "RESP2", - RedisProtocol.Resp3 => "RESP3", - _ => "UnknownProtocolFixMeeeeee", - }; - - protected override string GetUniqueID() => base.GetUniqueID() + ProtocolString; - - protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName) => - base.GetDisplayName(factAttribute, displayName).StripName() + "(" + ProtocolString + ")"; + public RedisProtocol Protocol { get; private set; } [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public SkippableTestCase() { } - - public SkippableTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[]? testMethodArguments = null, RedisProtocol? protocol = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) - { - // TODO: Default RESP2 somewhere cleaner - Protocol = protocol ?? RedisProtocol.Resp2; - } - - public override void Serialize(IXunitSerializationInfo data) + public ProtocolTestCase() { } + + public ProtocolTestCase(XunitTestCase testCase, RedisProtocol protocol) : base( + testMethod: testCase.TestMethod, + testCaseDisplayName: $"{testCase.TestCaseDisplayName.Replace("StackExchange.Redis.Tests.", "")} ({protocol.GetString()})", + uniqueID: testCase.UniqueID + protocol.GetString(), + @explicit: testCase.Explicit, + skipExceptions: testCase.SkipExceptions, + skipReason: testCase.SkipReason, + skipType: testCase.SkipType, + skipUnless: testCase.SkipUnless, + skipWhen: testCase.SkipWhen, + traits: testCase.TestMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase), + testMethodArguments: testCase.TestMethodArguments, + sourceFilePath: testCase.SourceFilePath, + sourceLineNumber: testCase.SourceLineNumber, + timeout: testCase.Timeout) + => Protocol = protocol; + + protected override void Serialize(IXunitSerializationInfo data) { - data.AddValue(nameof(Protocol), (int)Protocol); base.Serialize(data); + data.AddValue("resp", (int)Protocol); } - public override void Deserialize(IXunitSerializationInfo data) + protected override void Deserialize(IXunitSerializationInfo data) { - Protocol = (RedisProtocol)data.GetValue(nameof(Protocol)); base.Deserialize(data); - } - - public override async Task RunAsync( - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - { - var skipMessageBus = new SkippableMessageBus(messageBus); - TestBase.SetContext(new TestContext(this)); - var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource).ForAwait(); - return result.Update(skipMessageBus); + Protocol = (RedisProtocol)data.GetValue("resp"); } } -public class SkippableTheoryTestCase : XunitTheoryTestCase, IRedisTest +public class ProtocolDelayEnumeratedTestCase : XunitDelayEnumeratedTheoryTestCase, IProtocolTestCase { - public RedisProtocol Protocol { get; set; } - - protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName) => - base.GetDisplayName(factAttribute, displayName).StripName(); + public RedisProtocol Protocol { get; private set; } [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public SkippableTheoryTestCase() { } - - public SkippableTheoryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, RedisProtocol? protocol = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod) + public ProtocolDelayEnumeratedTestCase() { } + + public ProtocolDelayEnumeratedTestCase(XunitDelayEnumeratedTheoryTestCase testCase, RedisProtocol protocol) : base( + testMethod: testCase.TestMethod, + testCaseDisplayName: $"{testCase.TestCaseDisplayName.Replace("StackExchange.Redis.Tests.", "")} ({protocol.GetString()})", + uniqueID: testCase.UniqueID + protocol.GetString(), + @explicit: testCase.Explicit, + skipTestWithoutData: testCase.SkipTestWithoutData, + skipExceptions: testCase.SkipExceptions, + skipReason: testCase.SkipReason, + skipType: testCase.SkipType, + skipUnless: testCase.SkipUnless, + skipWhen: testCase.SkipWhen, + traits: testCase.TestMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase), + sourceFilePath: testCase.SourceFilePath, + sourceLineNumber: testCase.SourceLineNumber, + timeout: testCase.Timeout) + => Protocol = protocol; + + protected override void Serialize(IXunitSerializationInfo data) { - // TODO: Default RESP2 somewhere cleaner - Protocol = protocol ?? RedisProtocol.Resp2; - } - - public override async Task RunAsync( - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - { - var skipMessageBus = new SkippableMessageBus(messageBus); - TestBase.SetContext(new TestContext(this)); - var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource).ForAwait(); - return result.Update(skipMessageBus); - } -} - -[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] -public class RunPerProtocol : Attribute -{ - public static RedisProtocol[] AllProtocols { get; } = new[] { RedisProtocol.Resp2, RedisProtocol.Resp3 }; - - public RedisProtocol[] Protocols { get; } - public RunPerProtocol(params RedisProtocol[] procotols) => Protocols = procotols ?? AllProtocols; -} - -public class NamedSkippedDataRowTestCase : XunitSkippedDataRowTestCase -{ - protected override string GetDisplayName(IAttributeInfo factAttribute, string displayName) => - base.GetDisplayName(factAttribute, displayName).StripName(); - - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public NamedSkippedDataRowTestCase() { } - - public NamedSkippedDataRowTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, string skipReason, object[]? testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, skipReason, testMethodArguments) { } -} - -public class SkippableMessageBus : IMessageBus -{ - private readonly IMessageBus InnerBus; - public SkippableMessageBus(IMessageBus innerBus) => InnerBus = innerBus; - - public int DynamicallySkippedTestCount { get; private set; } - - public void Dispose() - { - InnerBus.Dispose(); - GC.SuppressFinalize(this); + base.Serialize(data); + data.AddValue("resp", (int)Protocol); } - public bool QueueMessage(IMessageSinkMessage message) + protected override void Deserialize(IXunitSerializationInfo data) { - if (message is ITestFailed testFailed) - { - var exceptionType = testFailed.ExceptionTypes.FirstOrDefault(); - if (exceptionType == typeof(SkipTestException).FullName) - { - DynamicallySkippedTestCount++; - return InnerBus.QueueMessage(new TestSkipped(testFailed.Test, testFailed.Messages.FirstOrDefault())); - } - } - return InnerBus.QueueMessage(message); + base.Deserialize(data); + Protocol = (RedisProtocol)data.GetValue("resp"); } } internal static class XUnitExtensions { - internal static string StripName(this string name) => - name.Replace("StackExchange.Redis.Tests.", ""); - - public static RunSummary Update(this RunSummary summary, SkippableMessageBus bus) + public static async ValueTask> ExpandAsync(this ValueTask> discovery) { - if (bus.DynamicallySkippedTestCount > 0) + static IXunitTestCase CreateTestCase(XunitTestCase tc, RedisProtocol protocol) => tc switch { - summary.Failed -= bus.DynamicallySkippedTestCount; - summary.Skipped += bus.DynamicallySkippedTestCount; - } - return summary; - } - - public static IEnumerable Expand(this ITestMethod testMethod, Func generator) - { - if ((testMethod.Method.GetCustomAttributes(typeof(RunPerProtocol)).FirstOrDefault() - ?? testMethod.TestClass.Class.GetCustomAttributes(typeof(RunPerProtocol)).FirstOrDefault()) is IAttributeInfo attr) + XunitDelayEnumeratedTheoryTestCase delayed => new ProtocolDelayEnumeratedTestCase(delayed, protocol), + _ => new ProtocolTestCase(tc, protocol), + }; + var testCases = await discovery; + List result = []; + foreach (var testCase in testCases.OfType()) { - // params means not null but default empty - var protocols = attr.GetNamedArgument(nameof(RunPerProtocol.Protocols)); - if (protocols.Length == 0) + var testMethod = testCase.TestMethod; + + if ((testMethod.Method.GetCustomAttributes(typeof(RunPerProtocol)).FirstOrDefault() + ?? testMethod.TestClass.Class.GetCustomAttributes(typeof(RunPerProtocol)).FirstOrDefault()) is RunPerProtocol) { - protocols = RunPerProtocol.AllProtocols; + result.Add(CreateTestCase(testCase, RedisProtocol.Resp2)); + result.Add(CreateTestCase(testCase, RedisProtocol.Resp3)); } - foreach (var protocol in protocols) + else { - yield return generator(protocol); + // Default to RESP2 everywhere else + result.Add(CreateTestCase(testCase, RedisProtocol.Resp2)); } } - else - { - yield return generator(RedisProtocol.Resp2); - } + return result; } } @@ -269,25 +177,22 @@ public static IEnumerable Expand(this ITestMethod testMethod, Fu /// /// /// Based on: https://bartwullems.blogspot.com/2022/03/xunit-change-culture-during-your-test.html. +/// Replaces the culture and UI culture of the current thread with . /// +/// The name of the culture. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] -public class TestCultureAttribute : BeforeAfterTestAttribute +public class TestCultureAttribute(string culture) : BeforeAfterTestAttribute { - private readonly CultureInfo culture; + private readonly CultureInfo culture = new CultureInfo(culture, false); private CultureInfo? originalCulture; - /// - /// Replaces the culture and UI culture of the current thread with . - /// - /// The name of the culture. - public TestCultureAttribute(string culture) => this.culture = new CultureInfo(culture, false); - /// /// Stores the current and /// and replaces them with the new cultures defined in the constructor. /// /// The method under test. - public override void Before(MethodInfo methodUnderTest) + /// The current . + public override void Before(MethodInfo methodUnderTest, IXunitTest test) { originalCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; @@ -298,7 +203,8 @@ public override void Before(MethodInfo methodUnderTest) /// Restores the original to . /// /// The method under test. - public override void After(MethodInfo methodUnderTest) + /// The current . + public override void After(MethodInfo methodUnderTest, IXunitTest test) { if (originalCulture is not null) { diff --git a/tests/StackExchange.Redis.Tests/Helpers/Extensions.cs b/tests/StackExchange.Redis.Tests/Helpers/Extensions.cs index 052129a9a..6f776d268 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/Extensions.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/Extensions.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using Xunit.Abstractions; +using Xunit; namespace StackExchange.Redis.Tests.Helpers; @@ -11,19 +11,7 @@ public static class Extensions static Extensions() { -#if NET462 - VersionInfo = "Compiled under .NET 4.6.2"; -#else VersionInfo = $"Running under {RuntimeInformation.FrameworkDescription} ({Environment.Version})"; -#endif - try - { - VersionInfo += "\n Running on: " + RuntimeInformation.OSDescription; - } - catch (Exception) - { - VersionInfo += "\n Failed to get OS version"; - } } public static void WriteFrameworkVersion(this ITestOutputHelper output) => output.WriteLine(VersionInfo); diff --git a/tests/StackExchange.Redis.Tests/Helpers/IRedisTest.cs b/tests/StackExchange.Redis.Tests/Helpers/IRedisTest.cs deleted file mode 100644 index 76ea5bc1b..000000000 --- a/tests/StackExchange.Redis.Tests/Helpers/IRedisTest.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Xunit.Sdk; - -namespace StackExchange.Redis.Tests; - -public interface IRedisTest : IXunitTestCase -{ - public RedisProtocol Protocol { get; set; } -} diff --git a/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs b/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs index ae48ff676..cf6c7d326 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/SharedConnectionFixture.cs @@ -11,13 +11,14 @@ using StackExchange.Redis.Profiling; using Xunit; +[assembly: AssemblyFixture(typeof(StackExchange.Redis.Tests.SharedConnectionFixture))] + namespace StackExchange.Redis.Tests; public class SharedConnectionFixture : IDisposable { public bool IsEnabled { get; } - public const string Key = "Shared Muxer"; private readonly ConnectionMultiplexer _actualConnection; public string Configuration { get; } @@ -68,7 +69,7 @@ static NonDisposingConnection VerifyAndWrap(IInternalConnectionMultiplexer muxer } } - internal sealed class NonDisposingConnection : IInternalConnectionMultiplexer + internal sealed class NonDisposingConnection(IInternalConnectionMultiplexer inner) : IInternalConnectionMultiplexer { public IInternalConnectionMultiplexer UnderlyingConnection => _inner; @@ -92,8 +93,7 @@ public bool IgnoreConnect public ConnectionMultiplexer UnderlyingMultiplexer => _inner.UnderlyingMultiplexer; - private readonly IInternalConnectionMultiplexer _inner; - public NonDisposingConnection(IInternalConnectionMultiplexer inner) => _inner = inner; + private readonly IInternalConnectionMultiplexer _inner = inner; public int GetSubscriptionsCount() => _inner.GetSubscriptionsCount(); public ConcurrentDictionary GetSubscriptions() => _inner.GetSubscriptions(); @@ -255,7 +255,7 @@ protected void OnConnectionFailed(object? sender, ConnectionFailedEventArgs e) privateExceptions.Add($"{TestBase.Time()}: Connection failed ({e.FailureType}): {EndPointCollection.ToString(e.EndPoint)}/{e.ConnectionType}: {e.Exception}"); } } - private readonly List privateExceptions = new List(); + private readonly List privateExceptions = []; private int privateFailCount; public void Teardown(TextWriter output) @@ -288,14 +288,3 @@ public void Teardown(TextWriter output) } } } - -/// -/// See . -/// -[CollectionDefinition(SharedConnectionFixture.Key)] -public class ConnectionCollection : ICollectionFixture -{ - // This class has no code, and is never created. Its purpose is simply - // to be the place to apply [CollectionDefinition] and all the - // ICollectionFixture<> interfaces. -} diff --git a/tests/StackExchange.Redis.Tests/Helpers/Skip.cs b/tests/StackExchange.Redis.Tests/Helpers/Skip.cs index 8627dbda2..72d62a3dc 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/Skip.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/Skip.cs @@ -1,30 +1,29 @@ using System; using System.Diagnostics.CodeAnalysis; +using Xunit; namespace StackExchange.Redis.Tests; public static class Skip { - public static void Inconclusive(string message) => throw new SkipTestException(message); + public static void UnlessLongRunning() + { + Assert.SkipUnless(TestConfig.Current.RunLongRunning, "Skipping long-running test"); + } public static void IfNoConfig(string prop, [NotNull] string? value) { - if (value.IsNullOrEmpty()) - { - throw new SkipTestException($"Config.{prop} is not set, skipping test."); - } + Assert.SkipWhen(value.IsNullOrEmpty(), $"Config.{prop} is not set, skipping test."); } internal static void IfMissingDatabase(IConnectionMultiplexer conn, int dbId) { var dbCount = conn.GetServer(conn.GetEndPoints()[0]).DatabaseCount; - if (dbId >= dbCount) throw new SkipTestException($"Database '{dbId}' is not supported on this server."); + Assert.SkipWhen(dbId >= dbCount, $"Database '{dbId}' is not supported on this server."); } } -public class SkipTestException : Exception +public class SkipTestException(string reason) : Exception(reason) { public string? MissingFeatures { get; set; } - - public SkipTestException(string reason) : base(reason) { } } diff --git a/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs b/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs index fafb30543..c0194d5a6 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/TestConfig.cs @@ -9,11 +9,15 @@ namespace StackExchange.Redis.Tests; public static class TestConfig { - private const string FileName = "TestConfig.json"; + private const string FileName = "RedisTestConfig.json"; public static Config Current { get; } +#if NET private static int _db = 17; +#else + private static int _db = 77; +#endif public static int GetDedicatedDB(IConnectionMultiplexer? conn = null) { int db = Interlocked.Increment(ref _db); @@ -65,7 +69,6 @@ public class Config { public bool UseSharedConnection { get; set; } = true; public bool RunLongRunning { get; set; } - public bool LogToConsole { get; set; } public string PrimaryServer { get; set; } = "127.0.0.1"; public int PrimaryPort { get; set; } = 6379; diff --git a/tests/StackExchange.Redis.Tests/Helpers/TestContext.cs b/tests/StackExchange.Redis.Tests/Helpers/TestContext.cs deleted file mode 100644 index 799f753b4..000000000 --- a/tests/StackExchange.Redis.Tests/Helpers/TestContext.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace StackExchange.Redis.Tests; - -public class TestContext -{ - public IRedisTest Test { get; set; } - - public bool IsResp2 => Test.Protocol == RedisProtocol.Resp2; - public bool IsResp3 => Test.Protocol == RedisProtocol.Resp3; - - public string KeySuffix => Test.Protocol switch - { - RedisProtocol.Resp2 => "R2", - RedisProtocol.Resp3 => "R3", - _ => "", - }; - - public TestContext(IRedisTest test) => Test = test; - - public override string ToString() => $"Protocol: {Test.Protocol}"; -} diff --git a/tests/StackExchange.Redis.Tests/Helpers/TestExtensions.cs b/tests/StackExchange.Redis.Tests/Helpers/TestExtensions.cs index 504f260a4..aab965f98 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/TestExtensions.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/TestExtensions.cs @@ -1,4 +1,5 @@ using StackExchange.Redis.Profiling; +using Xunit; namespace StackExchange.Redis.Tests; @@ -10,4 +11,25 @@ public static ProfilingSession AddProfiler(this IConnectionMultiplexer mutex) mutex.RegisterProfiler(() => session); return session; } + + public static RedisProtocol GetProtocol(this ITestContext context) => + context.Test?.TestCase is IProtocolTestCase protocolTestCase + ? protocolTestCase.Protocol : RedisProtocol.Resp2; + + public static bool IsResp2(this ITestContext context) => GetProtocol(context) == RedisProtocol.Resp2; + public static bool IsResp3(this ITestContext context) => GetProtocol(context) == RedisProtocol.Resp3; + + public static string KeySuffix(this ITestContext context) => GetProtocol(context) switch + { + RedisProtocol.Resp2 => "R2", + RedisProtocol.Resp3 => "R3", + _ => "", + }; + + public static string GetString(this RedisProtocol protocol) => protocol switch + { + RedisProtocol.Resp2 => "RESP2", + RedisProtocol.Resp3 => "RESP3", + _ => "UnknownProtocolFixMeeeeee", + }; } diff --git a/tests/StackExchange.Redis.Tests/Helpers/TextWriterOutputHelper.cs b/tests/StackExchange.Redis.Tests/Helpers/TextWriterOutputHelper.cs index fe54c472c..e41a46670 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/TextWriterOutputHelper.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/TextWriterOutputHelper.cs @@ -1,22 +1,16 @@ using System; using System.IO; using System.Text; -using Xunit.Abstractions; +using Xunit; namespace StackExchange.Redis.Tests.Helpers; -public class TextWriterOutputHelper : TextWriter +public class TextWriterOutputHelper(ITestOutputHelper outputHelper) : TextWriter { private StringBuilder Buffer { get; } = new StringBuilder(2048); private StringBuilder? Echo { get; set; } public override Encoding Encoding => Encoding.UTF8; - private readonly ITestOutputHelper Output; - private readonly bool ToConsole; - public TextWriterOutputHelper(ITestOutputHelper outputHelper, bool echoToConsole) - { - Output = outputHelper; - ToConsole = echoToConsole; - } + private readonly ITestOutputHelper Output = outputHelper; public void EchoTo(StringBuilder sb) => Echo = sb; @@ -90,10 +84,6 @@ private void FlushBuffer() // Thrown when writing from a handler after a test has ended - just bail in this case } Echo?.AppendLine(text); - if (ToConsole) - { - Console.WriteLine(text); - } Buffer.Clear(); } } diff --git a/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs b/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs index fd614fa93..557562b71 100644 --- a/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs +++ b/tests/StackExchange.Redis.Tests/Helpers/redis-sharp.cs @@ -23,7 +23,7 @@ namespace RedisSharp { - public class Redis : IDisposable + public class Redis(string host, int port) : IDisposable { private Socket socket; private BufferedStream bstream; @@ -36,27 +36,19 @@ public enum KeyType Set, } - public class ResponseException : Exception + public class ResponseException(string code) : Exception("Response error") { - public string Code { get; } - public ResponseException(string code) : base("Response error") => Code = code; - } - - public Redis(string host, int port) - { - Host = host ?? throw new ArgumentNullException(nameof(host)); - Port = port; - SendTimeout = -1; + public string Code { get; } = code; } public Redis(string host) : this(host, 6379) { } public Redis() : this("localhost", 6379) { } - public string Host { get; } - public int Port { get; } + public string Host { get; } = host ?? throw new ArgumentNullException(nameof(host)); + public int Port { get; } = port; public int RetryTimeout { get; set; } public int RetryCount { get; set; } - public int SendTimeout { get; set; } + public int SendTimeout { get; set; } = -1; public string Password { get; set; } private int db; @@ -235,7 +227,7 @@ private void Connect() SendExpectSuccess("AUTH {0}\r\n", Password); } - private readonly byte[] endData = new byte[] { (byte)'\r', (byte)'\n' }; + private readonly byte[] endData = [(byte)'\r', (byte)'\n']; private bool SendDataCommand(byte[] data, string cmd, params object[] args) { diff --git a/tests/StackExchange.Redis.Tests/HighIntegrityBasicOpsTests.cs b/tests/StackExchange.Redis.Tests/HighIntegrityBasicOpsTests.cs new file mode 100644 index 000000000..d7b85cd62 --- /dev/null +++ b/tests/StackExchange.Redis.Tests/HighIntegrityBasicOpsTests.cs @@ -0,0 +1,8 @@ +using Xunit; + +namespace StackExchange.Redis.Tests; + +public class HighIntegrityBasicOpsTests(ITestOutputHelper output, SharedConnectionFixture fixture) : BasicOpsTests(output, fixture) +{ + internal override bool HighIntegrity => true; +} diff --git a/tests/StackExchange.Redis.Tests/HttpTunnelConnectTests.cs b/tests/StackExchange.Redis.Tests/HttpTunnelConnectTests.cs index 2c1dc1ec6..4099c7b94 100644 --- a/tests/StackExchange.Redis.Tests/HttpTunnelConnectTests.cs +++ b/tests/StackExchange.Redis.Tests/HttpTunnelConnectTests.cs @@ -2,14 +2,12 @@ using System.Diagnostics; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests { - public class HttpTunnelConnectTests + public class HttpTunnelConnectTests(ITestOutputHelper log) { - private ITestOutputHelper Log { get; } - public HttpTunnelConnectTests(ITestOutputHelper log) => Log = log; + private ITestOutputHelper Log { get; } = log; [Theory] [InlineData("")] @@ -19,7 +17,7 @@ public async Task Connect(string suffix) var cs = Environment.GetEnvironmentVariable("HACK_TUNNEL_ENDPOINT"); if (string.IsNullOrWhiteSpace(cs)) { - Skip.Inconclusive("Need HACK_TUNNEL_ENDPOINT environment variable"); + Assert.Skip("Need HACK_TUNNEL_ENDPOINT environment variable"); } var config = ConfigurationOptions.Parse(cs + suffix); if (!string.IsNullOrWhiteSpace(suffix)) diff --git a/tests/StackExchange.Redis.Tests/HyperLogLogTests.cs b/tests/StackExchange.Redis.Tests/HyperLogLogTests.cs index e0451e9c5..f4c259854 100644 --- a/tests/StackExchange.Redis.Tests/HyperLogLogTests.cs +++ b/tests/StackExchange.Redis.Tests/HyperLogLogTests.cs @@ -1,18 +1,15 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class HyperLogLogTests : TestBase +public class HyperLogLogTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public HyperLogLogTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void SingleKeyLength() + public async Task SingleKeyLength() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = "hll1"; @@ -25,12 +22,12 @@ public void SingleKeyLength() } [Fact] - public void MultiKeyLength() + public async Task MultiKeyLength() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); - RedisKey[] keys = { "hll1", "hll2", "hll3" }; + RedisKey[] keys = ["hll1", "hll2", "hll3"]; db.HyperLogLogAdd(keys[0], "a"); db.HyperLogLogAdd(keys[1], "b"); diff --git a/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs b/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs index 547d3cc88..03b9f5b7f 100644 --- a/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs +++ b/tests/StackExchange.Redis.Tests/InfoReplicationCheckTests.cs @@ -1,20 +1,18 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class InfoReplicationCheckTests : TestBase +public class InfoReplicationCheckTests(ITestOutputHelper output) : TestBase(output) { protected override string GetConfiguration() => base.GetConfiguration() + ",configCheckSeconds=2"; - public InfoReplicationCheckTests(ITestOutputHelper output) : base(output) { } [Fact] public async Task Exec() { - Skip.Inconclusive("need to think about CompletedSynchronously"); + Assert.Skip("need to think about CompletedSynchronously"); - using var conn = Create(); + await using var conn = Create(); var parsed = ConfigurationOptions.Parse(conn.Configuration); Assert.Equal(2, parsed.ConfigCheckSeconds); diff --git a/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs b/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs index 2b4a8797e..15e4c6ef3 100644 --- a/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/BgSaveResponseTests.cs @@ -1,19 +1,16 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class BgSaveResponseTests : TestBase +public class BgSaveResponseTests(ITestOutputHelper output) : TestBase(output) { - public BgSaveResponseTests(ITestOutputHelper output) : base(output) { } - [Theory(Skip = "We don't need to test this, and it really screws local testing hard.")] [InlineData(SaveType.BackgroundSave)] [InlineData(SaveType.BackgroundRewriteAppendOnlyFile)] public async Task ShouldntThrowException(SaveType saveType) { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var server = GetServer(conn); server.Save(saveType); diff --git a/tests/StackExchange.Redis.Tests/Issues/DefaultDatabaseTests.cs b/tests/StackExchange.Redis.Tests/Issues/DefaultDatabaseTests.cs index 5514bc5c4..9666c91a2 100644 --- a/tests/StackExchange.Redis.Tests/Issues/DefaultDatabaseTests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/DefaultDatabaseTests.cs @@ -1,13 +1,11 @@ using System.IO; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class DefaultDatabaseTests : TestBase +public class DefaultDatabaseTests(ITestOutputHelper output) : TestBase(output) { - public DefaultDatabaseTests(ITestOutputHelper output) : base(output) { } - [Fact] public void UnspecifiedDbId_ReturnsNull() { @@ -23,12 +21,12 @@ public void SpecifiedDbId_ReturnsExpected() } [Fact] - public void ConfigurationOptions_UnspecifiedDefaultDb() + public async Task ConfigurationOptions_UnspecifiedDefaultDb() { var log = new StringWriter(); try { - using var conn = ConnectionMultiplexer.Connect(TestConfig.Current.PrimaryServerAndPort, log); + await using var conn = await ConnectionMultiplexer.ConnectAsync(TestConfig.Current.PrimaryServerAndPort, log); var db = conn.GetDatabase(); Assert.Equal(0, db.Database); } @@ -39,12 +37,12 @@ public void ConfigurationOptions_UnspecifiedDefaultDb() } [Fact] - public void ConfigurationOptions_SpecifiedDefaultDb() + public async Task ConfigurationOptions_SpecifiedDefaultDb() { var log = new StringWriter(); try { - using var conn = ConnectionMultiplexer.Connect($"{TestConfig.Current.PrimaryServerAndPort},defaultDatabase=3", log); + await using var conn = await ConnectionMultiplexer.ConnectAsync($"{TestConfig.Current.PrimaryServerAndPort},defaultDatabase=3", log); var db = conn.GetDatabase(); Assert.Equal(3, db.Database); } diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue10Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue10Tests.cs index af95cd71e..0a2f3fa8f 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue10Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue10Tests.cs @@ -1,26 +1,24 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests.Issues; -public class Issue10Tests : TestBase +public class Issue10Tests(ITestOutputHelper output) : TestBase(output) { - public Issue10Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void Execute() + public async Task Execute() { - using var conn = Create(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); - db.KeyDeleteAsync(key); // contents: nil - db.ListLeftPushAsync(key, "abc"); // "abc" - db.ListLeftPushAsync(key, "def"); // "def", "abc" - db.ListLeftPushAsync(key, "ghi"); // "ghi", "def", "abc", - db.ListSetByIndexAsync(key, 1, "jkl"); // "ghi", "jkl", "abc" + _ = db.KeyDeleteAsync(key); // contents: nil + _ = db.ListLeftPushAsync(key, "abc"); // "abc" + _ = db.ListLeftPushAsync(key, "def"); // "def", "abc" + _ = db.ListLeftPushAsync(key, "ghi"); // "ghi", "def", "abc", + _ = db.ListSetByIndexAsync(key, 1, "jkl"); // "ghi", "jkl", "abc" - var contents = db.Wait(db.ListRangeAsync(key, 0, -1)); + var contents = await db.ListRangeAsync(key, 0, -1); Assert.Equal(3, contents.Length); Assert.Equal("ghi", contents[0]); Assert.Equal("jkl", contents[1]); diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue1101Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue1101Tests.cs index 3f248b480..b0d9b9027 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue1101Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue1101Tests.cs @@ -4,14 +4,11 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class Issue1101Tests : TestBase +public class Issue1101Tests(ITestOutputHelper output) : TestBase(output) { - public Issue1101Tests(ITestOutputHelper output) : base(output) { } - private static void AssertCounts(ISubscriber pubsub, in RedisChannel channel, bool has, int handlers, int queues) { if (pubsub.Multiplexer is ConnectionMultiplexer muxer) @@ -26,7 +23,7 @@ private static void AssertCounts(ISubscriber pubsub, in RedisChannel channel, bo [Fact] public async Task ExecuteWithUnsubscribeViaChannel() { - using var conn = Create(log: Writer); + await using var conn = Create(log: Writer); RedisChannel name = RedisChannel.Literal(Me()); var pubsub = conn.GetSubscriber(); @@ -91,7 +88,7 @@ public async Task ExecuteWithUnsubscribeViaChannel() [Fact] public async Task ExecuteWithUnsubscribeViaSubscriber() { - using var conn = Create(shared: false, log: Writer); + await using var conn = Create(shared: false, log: Writer); RedisChannel name = RedisChannel.Literal(Me()); var pubsub = conn.GetSubscriber(); @@ -142,7 +139,7 @@ public async Task ExecuteWithUnsubscribeViaSubscriber() [Fact] public async Task ExecuteWithUnsubscribeViaClearAll() { - using var conn = Create(log: Writer); + await using var conn = Create(log: Writer); RedisChannel name = RedisChannel.Literal(Me()); var pubsub = conn.GetSubscriber(); diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue1103Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue1103Tests.cs index 4d9ff3731..ab4042042 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue1103Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue1103Tests.cs @@ -1,14 +1,12 @@ using System.Globalization; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; using static StackExchange.Redis.RedisValue; namespace StackExchange.Redis.Tests.Issues; -public class Issue1103Tests : TestBase +public class Issue1103Tests(ITestOutputHelper output) : TestBase(output) { - public Issue1103Tests(ITestOutputHelper output) : base(output) { } - [Theory] [InlineData(142205255210238005UL, (int)StorageType.Int64)] [InlineData(ulong.MaxValue, (int)StorageType.UInt64)] @@ -16,9 +14,9 @@ public Issue1103Tests(ITestOutputHelper output) : base(output) { } [InlineData(0x8000000000000000UL, (int)StorageType.UInt64)] [InlineData(0x8000000000000001UL, (int)StorageType.UInt64)] [InlineData(0x7FFFFFFFFFFFFFFFUL, (int)StorageType.Int64)] - public void LargeUInt64StoredCorrectly(ulong value, int storageType) + public async Task LargeUInt64StoredCorrectly(ulong value, int storageType) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs index 396b40b5f..e60332603 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue182Tests.cs @@ -2,20 +2,18 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class Issue182Tests : TestBase +public class Issue182Tests(ITestOutputHelper output) : TestBase(output) { protected override string GetConfiguration() => $"{TestConfig.Current.PrimaryServerAndPort},responseTimeout=10000"; - public Issue182Tests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task SetMembers() { - using var conn = Create(syncTimeout: 20000); + Skip.UnlessLongRunning(); + await using var conn = Create(syncTimeout: 20000); conn.ConnectionFailed += (s, a) => { @@ -41,10 +39,11 @@ public async Task SetMembers() Assert.Equal(count, result.Length); // SMEMBERS result length } - [FactLongRunning] + [Fact] public async Task SetUnion() { - using var conn = Create(syncTimeout: 10000); + Skip.UnlessLongRunning(); + await using var conn = Create(syncTimeout: 10000); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs index 6ec0b86f5..39edd91d1 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2176Tests.cs @@ -2,18 +2,15 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues { - public class Issue2176Tests : TestBase + public class Issue2176Tests(ITestOutputHelper output) : TestBase(output) { - public Issue2176Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void Execute_Batch() + public async Task Execute_Batch() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var me = Me(); @@ -29,12 +26,12 @@ public void Execute_Batch() var tasks = new List(); var batch = db.CreateBatch(); tasks.Add(batch.SortedSetAddAsync(key2, "a", 4567)); - tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, keyIntersect, new RedisKey[] { key, key2 })); + tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, keyIntersect, [key, key2])); var rangeByRankTask = batch.SortedSetRangeByRankAsync(keyIntersect); tasks.Add(rangeByRankTask); batch.Execute(); - Task.WhenAll(tasks.ToArray()); + await Task.WhenAll(tasks.ToArray()); var rangeByRankSortedSetValues = rangeByRankTask.Result; @@ -45,9 +42,9 @@ public void Execute_Batch() } [Fact] - public void Execute_Transaction() + public async Task Execute_Transaction() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var me = Me(); @@ -63,12 +60,12 @@ public void Execute_Transaction() var tasks = new List(); var batch = db.CreateTransaction(); tasks.Add(batch.SortedSetAddAsync(key2, "a", 4567)); - tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, keyIntersect, new RedisKey[] { key, key2 })); + tasks.Add(batch.SortedSetCombineAndStoreAsync(SetOperation.Intersect, keyIntersect, [key, key2])); var rangeByRankTask = batch.SortedSetRangeByRankAsync(keyIntersect); tasks.Add(rangeByRankTask); batch.Execute(); - Task.WhenAll(tasks.ToArray()); + await Task.WhenAll(tasks.ToArray()); var rangeByRankSortedSetValues = rangeByRankTask.Result; diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2392Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2392Tests.cs index fe3e9673d..39df94021 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2392Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2392Tests.cs @@ -1,14 +1,11 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues { - public class Issue2392Tests : TestBase + public class Issue2392Tests(ITestOutputHelper output) : TestBase(output) { - public Issue2392Tests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task Execute() { @@ -28,7 +25,7 @@ public async Task Execute() }; options.EndPoints.Add("127.0.0.1:1234"); - using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options, Writer); var key = Me(); var db = conn.GetDatabase(); var server = conn.GetServerSnapshot()[0]; diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs index a22bbbcbd..db38b1325 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2418.cs @@ -1,30 +1,22 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class Issue2418 : TestBase +public class Issue2418(ITestOutputHelper output, SharedConnectionFixture? fixture = null) : TestBase(output, fixture) { - public Issue2418(ITestOutputHelper output, SharedConnectionFixture? fixture = null) - : base(output, fixture) { } - [Fact] public async Task Execute() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); RedisValue someInt = 12; Assert.False(someInt.IsNullOrEmpty, nameof(someInt.IsNullOrEmpty) + " before"); Assert.True(someInt.IsInteger, nameof(someInt.IsInteger) + " before"); - await db.HashSetAsync(key, new[] - { - new HashEntry("some_int", someInt), - // ... - }); + await db.HashSetAsync(key, [new HashEntry("some_int", someInt)]); // check we can fetch it var entry = await db.HashGetAllAsync(key); diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2507.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2507.cs index 7d2a9b19a..b548d7031 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2507.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2507.cs @@ -1,46 +1,40 @@ -using System.Collections.Generic; -using System.Linq; +using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; -namespace StackExchange.Redis.Tests.Issues +namespace StackExchange.Redis.Tests.Issues; + +[Collection(NonParallelCollection.Name)] +public class Issue2507(ITestOutputHelper output, SharedConnectionFixture? fixture = null) : TestBase(output, fixture) { - [Collection(NonParallelCollection.Name)] - public class Issue2507 : TestBase + [Fact(Explicit = true)] + public async Task Execute() { - public Issue2507(ITestOutputHelper output, SharedConnectionFixture? fixture = null) - : base(output, fixture) { } - - [Fact] - public async Task Execute() - { - using var conn = Create(shared: false); - var db = conn.GetDatabase(); - var pubsub = conn.GetSubscriber(); - var queue = await pubsub.SubscribeAsync(RedisChannel.Literal("__redis__:invalidate")); - await Task.Delay(100); - var connectionId = conn.GetConnectionId(conn.GetEndPoints().Single(), ConnectionType.Subscription); - if (connectionId is null) Skip.Inconclusive("Connection id not available"); + await using var conn = Create(shared: false); + var db = conn.GetDatabase(); + var pubsub = conn.GetSubscriber(); + var queue = await pubsub.SubscribeAsync(RedisChannel.Literal("__redis__:invalidate")); + await Task.Delay(100); + var connectionId = conn.GetConnectionId(conn.GetEndPoints().Single(), ConnectionType.Subscription); + if (connectionId is null) Assert.Skip("Connection id not available"); - string baseKey = Me(); - RedisKey key1 = baseKey + "abc", - key2 = baseKey + "ghi", - key3 = baseKey + "mno"; + string baseKey = Me(); + RedisKey key1 = baseKey + "abc", + key2 = baseKey + "ghi", + key3 = baseKey + "mno"; - await db.StringSetAsync(new KeyValuePair[] { new(key1, "def"), new(key2, "jkl"), new(key3, "pqr") }); - // this is not supported, but: we want it to at least not fail - await db.ExecuteAsync("CLIENT", "TRACKING", "on", "REDIRECT", connectionId!.Value, "BCAST"); - await db.KeyDeleteAsync(new RedisKey[] { key1, key2, key3 }); - await Task.Delay(100); - queue.Unsubscribe(); - Assert.True(queue.TryRead(out var message)); - Assert.Equal(key1, message.Message); - Assert.True(queue.TryRead(out message)); - Assert.Equal(key2, message.Message); - Assert.True(queue.TryRead(out message)); - Assert.Equal(key3, message.Message); - Assert.False(queue.TryRead(out message)); - } + await db.StringSetAsync([new(key1, "def"), new(key2, "jkl"), new(key3, "pqr")]); + // this is not supported, but: we want it to at least not fail + await db.ExecuteAsync("CLIENT", "TRACKING", "on", "REDIRECT", connectionId!.Value, "BCAST"); + await db.KeyDeleteAsync([key1, key2, key3]); + await Task.Delay(100); + queue.Unsubscribe(); + Assert.True(queue.TryRead(out var message), "Queue 1 Read failed"); + Assert.Equal(key1, message.Message); + Assert.True(queue.TryRead(out message), "Queue 2 Read failed"); + Assert.Equal(key2, message.Message); + Assert.True(queue.TryRead(out message), "Queue 3 Read failed"); + Assert.Equal(key3, message.Message); + Assert.False(queue.TryRead(out message), "Queue 4 Read succeeded"); } } diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs index 8841d81d3..05dc4d57c 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue25Tests.cs @@ -1,13 +1,10 @@ using System; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class Issue25Tests : TestBase +public class Issue25Tests(ITestOutputHelper output) : TestBase(output) { - public Issue25Tests(ITestOutputHelper output) : base(output) { } - [Fact] public void CaseInsensitive() { diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue2763Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue2763Tests.cs index 4da997e7d..699076118 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue2763Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue2763Tests.cs @@ -2,18 +2,15 @@ using System.Collections.Generic; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues { - public class Issue2763Tests : TestBase + public class Issue2763Tests(ITestOutputHelper output) : TestBase(output) { - public Issue2763Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void Execute() + public async Task Execute() { - using var conn = Create(); + await using var conn = Create(); var subscriber = conn.GetSubscriber(); static void Handler(RedisChannel c, RedisValue v) { } diff --git a/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs b/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs index 3b6d4f8fc..c7c6385c0 100644 --- a/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/Issue6Tests.cs @@ -1,19 +1,18 @@ -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests.Issues; -public class Issue6Tests : TestBase +public class Issue6Tests(ITestOutputHelper output) : TestBase(output) { - public Issue6Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void ShouldWorkWithoutEchoOrPing() + public async Task ShouldWorkWithoutEchoOrPing() { - using var conn = Create(proxy: Proxy.Twemproxy); + await using var conn = Create(proxy: Proxy.Twemproxy); Log("config: " + conn.Configuration); var db = conn.GetDatabase(); - var time = db.Ping(); + var time = await db.PingAsync(); Log("ping time: " + time); } } diff --git a/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs b/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs index bbd9171ea..94590a186 100644 --- a/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/MassiveDeleteTests.cs @@ -2,17 +2,15 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Xunit.Abstractions; +using Xunit; namespace StackExchange.Redis.Tests.Issues; -public class MassiveDeleteTests : TestBase +public class MassiveDeleteTests(ITestOutputHelper output) : TestBase(output) { - public MassiveDeleteTests(ITestOutputHelper output) : base(output) { } - - private void Prep(int dbId, string key) + private async Task Prep(int dbId, string key) { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var prefix = Me(); Skip.IfMissingDatabase(conn, dbId); @@ -22,20 +20,21 @@ private void Prep(int dbId, string key) for (int i = 0; i < 10000; i++) { string iKey = prefix + i; - db.StringSetAsync(iKey, iKey); + _ = db.StringSetAsync(iKey, iKey); last = db.SetAddAsync(key, iKey); } - db.Wait(last!); + await last!; } - [FactLongRunning] + [Fact] public async Task ExecuteMassiveDelete() { + Skip.UnlessLongRunning(); var dbId = TestConfig.GetDedicatedDB(); var key = Me(); - Prep(dbId, key); + await Prep(dbId, key); var watch = Stopwatch.StartNew(); - using var conn = Create(); + await using var conn = Create(); using var throttle = new SemaphoreSlim(1); var db = conn.GetDatabase(dbId); var originally = await db.SetLengthAsync(key).ForAwait(); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO10504853Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO10504853Tests.cs index ee2fd9bbc..7d4276e9d 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO10504853Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO10504853Tests.cs @@ -1,20 +1,18 @@ using System; using System.Diagnostics; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class SO10504853Tests : TestBase +public class SO10504853Tests(ITestOutputHelper output) : TestBase(output) { - public SO10504853Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void LoopLotsOfTrivialStuff() + public async Task LoopLotsOfTrivialStuff() { var key = Me(); Trace.WriteLine("### init"); - using (var conn = Create()) + await using (var conn = Create()) { var db = conn.GetDatabase(); db.KeyDelete(key, CommandFlags.FireAndForget); @@ -23,12 +21,12 @@ public void LoopLotsOfTrivialStuff() for (int i = 0; i < COUNT; i++) { Trace.WriteLine("### incr:" + i); - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); Assert.Equal(i + 1, db.StringIncrement(key)); } Trace.WriteLine("### close"); - using (var conn = Create()) + await using (var conn = Create()) { var db = conn.GetDatabase(); Assert.Equal(COUNT, (long)db.StringGet(key)); @@ -36,20 +34,20 @@ public void LoopLotsOfTrivialStuff() } [Fact] - public void ExecuteWithEmptyStartingPoint() + public async Task ExecuteWithEmptyStartingPoint() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); var task = new { priority = 3 }; - db.KeyDeleteAsync(key); - db.HashSetAsync(key, "something else", "abc"); - db.HashSetAsync(key, "priority", task.priority.ToString()); + _ = db.KeyDeleteAsync(key); + _ = db.HashSetAsync(key, "something else", "abc"); + _ = db.HashSetAsync(key, "priority", task.priority.ToString()); var taskResult = db.HashGetAsync(key, "priority"); - db.Wait(taskResult); + await taskResult; var priority = int.Parse(taskResult.Result!); @@ -57,18 +55,18 @@ public void ExecuteWithEmptyStartingPoint() } [Fact] - public void ExecuteWithNonHashStartingPoint() + public async Task ExecuteWithNonHashStartingPoint() { var key = Me(); - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var task = new { priority = 3 }; - db.KeyDeleteAsync(key); - db.StringSetAsync(key, "not a hash"); - db.HashSetAsync(key, "priority", task.priority.ToString()); + _ = db.KeyDeleteAsync(key); + _ = db.StringSetAsync(key, "not a hash"); + _ = db.HashSetAsync(key, "priority", task.priority.ToString()); var taskResult = db.HashGetAsync(key, "priority"); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO10825542Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO10825542Tests.cs index b19386f6b..493f4ec1b 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO10825542Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO10825542Tests.cs @@ -2,18 +2,15 @@ using System.Text; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class SO10825542Tests : TestBase +public class SO10825542Tests(ITestOutputHelper output) : TestBase(output) { - public SO10825542Tests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task Execute() { - using var conn = Create(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO11766033Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO11766033Tests.cs index d350bcff3..65cef55a7 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO11766033Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO11766033Tests.cs @@ -1,36 +1,34 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests.Issues; -public class SO11766033Tests : TestBase +public class SO11766033Tests(ITestOutputHelper output) : TestBase(output) { - public SO11766033Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void TestNullString() + public async Task TestNullString() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); const string? expectedTestValue = null; var uid = Me(); - db.StringSetAsync(uid, "abc"); - db.StringSetAsync(uid, expectedTestValue); + _ = db.StringSetAsync(uid, "abc"); + _ = db.StringSetAsync(uid, expectedTestValue); string? testValue = db.StringGet(uid); Assert.Null(testValue); } [Fact] - public void TestEmptyString() + public async Task TestEmptyString() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); const string expectedTestValue = ""; var uid = Me(); - db.StringSetAsync(uid, expectedTestValue); + _ = db.StringSetAsync(uid, expectedTestValue); string? testValue = db.StringGet(uid); Assert.Equal(expectedTestValue, testValue); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs index 562eef8c5..0fc653991 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO22786599Tests.cs @@ -1,16 +1,14 @@ using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class SO22786599Tests : TestBase +public class SO22786599Tests(ITestOutputHelper output) : TestBase(output) { - public SO22786599Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void Execute() + public async Task Execute() { string currentIdsSetDbKey = Me() + ".x"; string currentDetailsSetDbKey = Me() + ".y"; @@ -18,13 +16,13 @@ public void Execute() RedisValue[] stringIds = Enumerable.Range(1, 750).Select(i => (RedisValue)(i + " id")).ToArray(); RedisValue[] stringDetails = Enumerable.Range(1, 750).Select(i => (RedisValue)(i + " detail")).ToArray(); - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var tran = db.CreateTransaction(); - tran.SetAddAsync(currentIdsSetDbKey, stringIds); - tran.SetAddAsync(currentDetailsSetDbKey, stringDetails); + _ = tran.SetAddAsync(currentIdsSetDbKey, stringIds); + _ = tran.SetAddAsync(currentDetailsSetDbKey, stringDetails); var watch = Stopwatch.StartNew(); var isOperationSuccessful = tran.Execute(); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs index aa545a3cb..92277289a 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO23949477Tests.cs @@ -1,16 +1,14 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests.Issues; -public class SO23949477Tests : TestBase +public class SO23949477Tests(ITestOutputHelper output) : TestBase(output) { - public SO23949477Tests(ITestOutputHelper output) : base(output) { } - [Fact] - public void Execute() + public async Task Execute() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -18,13 +16,12 @@ public void Execute() db.SortedSetAdd(key, "c", 3, When.Always, CommandFlags.FireAndForget); db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("a", 1), new SortedSetEntry("b", 2), new SortedSetEntry("d", 4), new SortedSetEntry("e", 5), - }, + ], When.Always, CommandFlags.FireAndForget); var pairs = db.SortedSetRangeByScoreWithScores( diff --git a/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs index d4b449dd3..ddff810c0 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO24807536Tests.cs @@ -1,18 +1,15 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class SO24807536Tests : TestBase +public class SO24807536Tests(ITestOutputHelper output) : TestBase(output) { - public SO24807536Tests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task Exec() { - using var conn = Create(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); @@ -20,7 +17,7 @@ public async Task Exec() // setup some data db.KeyDelete(key, CommandFlags.FireAndForget); db.HashSet(key, "full", "some value", flags: CommandFlags.FireAndForget); - db.KeyExpire(key, TimeSpan.FromSeconds(4), CommandFlags.FireAndForget); + db.KeyExpire(key, TimeSpan.FromSeconds(2), CommandFlags.FireAndForget); // test while exists var keyExists = db.KeyExists(key); @@ -28,7 +25,7 @@ public async Task Exec() var fullWait = db.HashGetAsync(key, "full", flags: CommandFlags.None); Assert.True(keyExists, "key exists"); Assert.NotNull(ttl); - Assert.Equal("some value", fullWait.Result); + Assert.Equal("some value", await fullWait); // wait for expiry await UntilConditionAsync(TimeSpan.FromSeconds(10), () => !db.KeyExists(key)).ForAwait(); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs index 8de318e2a..00bc9836b 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO25113323Tests.cs @@ -1,17 +1,14 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class SO25113323Tests : TestBase +public class SO25113323Tests(ITestOutputHelper output) : TestBase(output) { - public SO25113323Tests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task SetExpirationToPassed() { - using var conn = Create(); + await using var conn = Create(); // Given var key = Me(); diff --git a/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs b/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs index b71b2a1f9..6d00a705e 100644 --- a/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs +++ b/tests/StackExchange.Redis.Tests/Issues/SO25567566Tests.cs @@ -1,19 +1,16 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests.Issues; -public class SO25567566Tests : TestBase +public class SO25567566Tests(ITestOutputHelper output) : TestBase(output) { - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public SO25567566Tests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task Execute() { - using var conn = ConnectionMultiplexer.Connect(GetConfiguration()); + Skip.UnlessLongRunning(); + await using var conn = await ConnectionMultiplexer.ConnectAsync(GetConfiguration()); for (int i = 0; i < 100; i++) { diff --git a/tests/StackExchange.Redis.Tests/KeyIdleAsyncTests.cs b/tests/StackExchange.Redis.Tests/KeyIdleAsyncTests.cs new file mode 100644 index 000000000..598e84d93 --- /dev/null +++ b/tests/StackExchange.Redis.Tests/KeyIdleAsyncTests.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace StackExchange.Redis.Tests; + +[RunPerProtocol] +public class KeyIdleAsyncTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) +{ + [Fact] + public async Task IdleTimeAsync() + { + await using var conn = Create(); + + RedisKey key = Me(); + var db = conn.GetDatabase(); + db.KeyDelete(key, CommandFlags.FireAndForget); + db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); + await Task.Delay(2000).ForAwait(); + var idleTime = await db.KeyIdleTimeAsync(key).ForAwait(); + Assert.True(idleTime > TimeSpan.Zero, "First check"); + + db.StringSet(key, "new value2", flags: CommandFlags.FireAndForget); + var idleTime2 = await db.KeyIdleTimeAsync(key).ForAwait(); + Assert.True(idleTime2 < idleTime, "Second check"); + + db.KeyDelete(key); + var idleTime3 = await db.KeyIdleTimeAsync(key).ForAwait(); + Assert.Null(idleTime3); + } + + [Fact] + public async Task TouchIdleTimeAsync() + { + await using var conn = Create(require: RedisFeatures.v3_2_1); + + RedisKey key = Me(); + var db = conn.GetDatabase(); + db.KeyDelete(key, CommandFlags.FireAndForget); + db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); + await Task.Delay(2000).ForAwait(); + var idleTime = await db.KeyIdleTimeAsync(key).ForAwait(); + Assert.True(idleTime > TimeSpan.Zero, "First check"); + + Assert.True(await db.KeyTouchAsync(key).ForAwait(), "Second check"); + var idleTime1 = await db.KeyIdleTimeAsync(key).ForAwait(); + Assert.True(idleTime1 < idleTime, "Third check"); + } +} diff --git a/tests/StackExchange.Redis.Tests/KeyIdleTests.cs b/tests/StackExchange.Redis.Tests/KeyIdleTests.cs new file mode 100644 index 000000000..deec1efb4 --- /dev/null +++ b/tests/StackExchange.Redis.Tests/KeyIdleTests.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace StackExchange.Redis.Tests; + +[RunPerProtocol] +public class KeyIdleTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) +{ + [Fact] + public async Task IdleTime() + { + await using var conn = Create(); + + RedisKey key = Me(); + var db = conn.GetDatabase(); + db.KeyDelete(key, CommandFlags.FireAndForget); + db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); + await Task.Delay(2000).ForAwait(); + var idleTime = db.KeyIdleTime(key); + Assert.True(idleTime > TimeSpan.Zero); + + db.StringSet(key, "new value2", flags: CommandFlags.FireAndForget); + var idleTime2 = db.KeyIdleTime(key); + Assert.True(idleTime2 < idleTime); + + db.KeyDelete(key); + var idleTime3 = db.KeyIdleTime(key); + Assert.Null(idleTime3); + } + + [Fact] + public async Task TouchIdleTime() + { + await using var conn = Create(require: RedisFeatures.v3_2_1); + + RedisKey key = Me(); + var db = conn.GetDatabase(); + db.KeyDelete(key, CommandFlags.FireAndForget); + db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); + await Task.Delay(2000).ForAwait(); + var idleTime = db.KeyIdleTime(key); + Assert.True(idleTime > TimeSpan.Zero, "First check"); + + Assert.True(db.KeyTouch(key), "Second check"); + var idleTime1 = db.KeyIdleTime(key); + Assert.True(idleTime1 < idleTime, "Third check"); + } +} diff --git a/tests/StackExchange.Redis.Tests/KeyPrefixedDatabaseTests.cs b/tests/StackExchange.Redis.Tests/KeyPrefixedDatabaseTests.cs index 2552ac7aa..3c56f7605 100644 --- a/tests/StackExchange.Redis.Tests/KeyPrefixedDatabaseTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyPrefixedDatabaseTests.cs @@ -237,7 +237,7 @@ public void HyperLogLogMerge_1() [Fact] public void HyperLogLogMerge_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.HyperLogLogMerge("destination", keys, CommandFlags.None); mock.Received().HyperLogLogMerge("prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -267,7 +267,7 @@ public void KeyDelete_1() [Fact] public void KeyDelete_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.KeyDelete(keys, CommandFlags.None); mock.Received().KeyDelete(Arg.Is(valid), CommandFlags.None); @@ -458,7 +458,7 @@ public void ListLeftPush_2() [Fact] public void ListLeftPush_3() { - RedisValue[] values = new RedisValue[] { "value1", "value2" }; + RedisValue[] values = ["value1", "value2"]; prefixed.ListLeftPush("key", values, When.Exists, CommandFlags.None); mock.Received().ListLeftPush("prefix:key", values, When.Exists, CommandFlags.None); } @@ -530,7 +530,7 @@ public void ListRightPush_2() [Fact] public void ListRightPush_3() { - RedisValue[] values = new RedisValue[] { "value1", "value2" }; + RedisValue[] values = ["value1", "value2"]; prefixed.ListRightPush("key", values, When.Exists, CommandFlags.None); mock.Received().ListRightPush("prefix:key", values, When.Exists, CommandFlags.None); } @@ -593,7 +593,7 @@ public void ScriptEvaluate_1() { byte[] hash = Array.Empty(); RedisValue[] values = Array.Empty(); - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.ScriptEvaluate(hash, keys, values, CommandFlags.None); mock.Received().ScriptEvaluate(hash, Arg.Is(valid), values, CommandFlags.None); @@ -603,7 +603,7 @@ public void ScriptEvaluate_1() public void ScriptEvaluate_2() { RedisValue[] values = Array.Empty(); - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.ScriptEvaluate(script: "script", keys: keys, values: values, flags: CommandFlags.None); mock.Received().ScriptEvaluate(script: "script", keys: Arg.Is(valid), values: values, flags: CommandFlags.None); @@ -634,7 +634,7 @@ public void SetCombine_1() [Fact] public void SetCombine_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.SetCombine(SetOperation.Intersect, keys, CommandFlags.None); mock.Received().SetCombine(SetOperation.Intersect, Arg.Is(valid), CommandFlags.None); @@ -650,7 +650,7 @@ public void SetCombineAndStore_1() [Fact] public void SetCombineAndStore_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.SetCombineAndStore(SetOperation.Intersect, "destination", keys, CommandFlags.None); mock.Received().SetCombineAndStore(SetOperation.Intersect, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -666,7 +666,7 @@ public void SetContains() [Fact] public void SetContains_2() { - RedisValue[] values = new RedisValue[] { "value1", "value2" }; + RedisValue[] values = ["value1", "value2"]; prefixed.SetContains("key", values, CommandFlags.None); mock.Received().SetContains("prefix:key", values, CommandFlags.None); } @@ -763,7 +763,7 @@ public void SetScan_Full() [Fact] public void Sort() { - RedisValue[] get = new RedisValue[] { "a", "#" }; + RedisValue[] get = ["a", "#"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "#"; prefixed.Sort("key", 123, 456, Order.Descending, SortType.Alphabetic, "nosort", get, CommandFlags.None); @@ -776,7 +776,7 @@ public void Sort() [Fact] public void SortAndStore() { - RedisValue[] get = new RedisValue[] { "a", "#" }; + RedisValue[] get = ["a", "#"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "#"; prefixed.SortAndStore("destination", "key", 123, 456, Order.Descending, SortType.Alphabetic, "nosort", get, CommandFlags.None); @@ -812,7 +812,7 @@ public void SortedSetAdd_3() [Fact] public void SortedSetCombine() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; prefixed.SortedSetCombine(SetOperation.Intersect, keys); mock.Received().SortedSetCombine(SetOperation.Intersect, keys, null, Aggregate.Sum, CommandFlags.None); } @@ -820,7 +820,7 @@ public void SortedSetCombine() [Fact] public void SortedSetCombineWithScores() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; prefixed.SortedSetCombineWithScores(SetOperation.Intersect, keys); mock.Received().SortedSetCombineWithScores(SetOperation.Intersect, keys, null, Aggregate.Sum, CommandFlags.None); } @@ -835,7 +835,7 @@ public void SortedSetCombineAndStore_1() [Fact] public void SortedSetCombineAndStore_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.SetCombineAndStore(SetOperation.Intersect, "destination", keys, CommandFlags.None); mock.Received().SetCombineAndStore(SetOperation.Intersect, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -858,7 +858,7 @@ public void SortedSetIncrement() [Fact] public void SortedSetIntersectionLength() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; prefixed.SortedSetIntersectionLength(keys, 1, CommandFlags.None); mock.Received().SortedSetIntersectionLength(keys, 1, CommandFlags.None); } @@ -1233,7 +1233,7 @@ public void StringBitOperation_1() [Fact] public void StringBitOperation_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.StringBitOperation(Bitwise.Xor, "destination", keys, CommandFlags.None); mock.Received().StringBitOperation(Bitwise.Xor, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1242,7 +1242,7 @@ public void StringBitOperation_2() [Fact] public void StringBitOperation_Diff() { - RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" }; + RedisKey[] keys = ["x", "y1", "y2"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2"; prefixed.StringBitOperation(Bitwise.Diff, "destination", keys, CommandFlags.None); mock.Received().StringBitOperation(Bitwise.Diff, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1251,7 +1251,7 @@ public void StringBitOperation_Diff() [Fact] public void StringBitOperation_Diff1() { - RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" }; + RedisKey[] keys = ["x", "y1", "y2"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2"; prefixed.StringBitOperation(Bitwise.Diff1, "destination", keys, CommandFlags.None); mock.Received().StringBitOperation(Bitwise.Diff1, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1260,7 +1260,7 @@ public void StringBitOperation_Diff1() [Fact] public void StringBitOperation_AndOr() { - RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" }; + RedisKey[] keys = ["x", "y1", "y2"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2"; prefixed.StringBitOperation(Bitwise.AndOr, "destination", keys, CommandFlags.None); mock.Received().StringBitOperation(Bitwise.AndOr, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1269,7 +1269,7 @@ public void StringBitOperation_AndOr() [Fact] public void StringBitOperation_One() { - RedisKey[] keys = new RedisKey[] { "a", "b", "c" }; + RedisKey[] keys = ["a", "b", "c"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:a" && _[1] == "prefix:b" && _[2] == "prefix:c"; prefixed.StringBitOperation(Bitwise.One, "destination", keys, CommandFlags.None); mock.Received().StringBitOperation(Bitwise.One, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1313,7 +1313,7 @@ public void StringGet_1() [Fact] public void StringGet_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; prefixed.StringGet(keys, CommandFlags.None); mock.Received().StringGet(Arg.Is(valid), CommandFlags.None); @@ -1394,7 +1394,7 @@ public void StringSet_2() [Fact] public void StringSet_3() { - KeyValuePair[] values = new KeyValuePair[] { new KeyValuePair("a", "x"), new KeyValuePair("b", "y") }; + KeyValuePair[] values = [new KeyValuePair("a", "x"), new KeyValuePair("b", "y")]; Expression[]>> valid = _ => _.Length == 2 && _[0].Key == "prefix:a" && _[0].Value == "x" && _[1].Key == "prefix:b" && _[1].Value == "y"; prefixed.StringSet(values, When.Exists, CommandFlags.None); mock.Received().StringSet(Arg.Is(valid), When.Exists, CommandFlags.None); diff --git a/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs b/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs index e768b9ec5..70893e510 100644 --- a/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyPrefixedTests.cs @@ -176,7 +176,7 @@ public async Task HyperLogLogMergeAsync_1() [Fact] public async Task HyperLogLogMergeAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.HyperLogLogMergeAsync("destination", keys, CommandFlags.None); await mock.Received().HyperLogLogMergeAsync("prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -213,7 +213,7 @@ public async Task KeyDeleteAsync_1() [Fact] public async Task KeyDeleteAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.KeyDeleteAsync(keys, CommandFlags.None); await mock.Received().KeyDeleteAsync(Arg.Is(valid), CommandFlags.None); @@ -404,7 +404,7 @@ public async Task ListLeftPushAsync_2() [Fact] public async Task ListLeftPushAsync_3() { - RedisValue[] values = new RedisValue[] { "value1", "value2" }; + RedisValue[] values = ["value1", "value2"]; await prefixed.ListLeftPushAsync("key", values, When.Exists, CommandFlags.None); await mock.Received().ListLeftPushAsync("prefix:key", values, When.Exists, CommandFlags.None); } @@ -476,7 +476,7 @@ public async Task ListRightPushAsync_2() [Fact] public async Task ListRightPushAsync_3() { - RedisValue[] values = new RedisValue[] { "value1", "value2" }; + RedisValue[] values = ["value1", "value2"]; await prefixed.ListRightPushAsync("key", values, When.Exists, CommandFlags.None); await mock.Received().ListRightPushAsync("prefix:key", values, When.Exists, CommandFlags.None); } @@ -537,7 +537,7 @@ public async Task ScriptEvaluateAsync_1() { byte[] hash = Array.Empty(); RedisValue[] values = Array.Empty(); - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.ScriptEvaluateAsync(hash, keys, values, CommandFlags.None); await mock.Received().ScriptEvaluateAsync(hash, Arg.Is(valid), values, CommandFlags.None); @@ -547,7 +547,7 @@ public async Task ScriptEvaluateAsync_1() public async Task ScriptEvaluateAsync_2() { RedisValue[] values = Array.Empty(); - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.ScriptEvaluateAsync("script", keys, values, CommandFlags.None); await mock.Received().ScriptEvaluateAsync(script: "script", keys: Arg.Is(valid), values: values, flags: CommandFlags.None); @@ -578,7 +578,7 @@ public async Task SetCombineAndStoreAsync_1() [Fact] public async Task SetCombineAndStoreAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.SetCombineAndStoreAsync(SetOperation.Intersect, "destination", keys, CommandFlags.None); await mock.Received().SetCombineAndStoreAsync(SetOperation.Intersect, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -594,7 +594,7 @@ public async Task SetCombineAsync_1() [Fact] public async Task SetCombineAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.SetCombineAsync(SetOperation.Intersect, keys, CommandFlags.None); await mock.Received().SetCombineAsync(SetOperation.Intersect, Arg.Is(valid), CommandFlags.None); @@ -610,7 +610,7 @@ public async Task SetContainsAsync() [Fact] public async Task SetContainsAsync_2() { - RedisValue[] values = new RedisValue[] { "value1", "value2" }; + RedisValue[] values = ["value1", "value2"]; await prefixed.SetContainsAsync("key", values, CommandFlags.None); await mock.Received().SetContainsAsync("prefix:key", values, CommandFlags.None); } @@ -693,7 +693,7 @@ public async Task SetRemoveAsync_2() [Fact] public async Task SortAndStoreAsync() { - RedisValue[] get = new RedisValue[] { "a", "#" }; + RedisValue[] get = ["a", "#"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "#"; await prefixed.SortAndStoreAsync("destination", "key", 123, 456, Order.Descending, SortType.Alphabetic, "nosort", get, CommandFlags.None); @@ -706,7 +706,7 @@ public async Task SortAndStoreAsync() [Fact] public async Task SortAsync() { - RedisValue[] get = new RedisValue[] { "a", "#" }; + RedisValue[] get = ["a", "#"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "#"; await prefixed.SortAsync("key", 123, 456, Order.Descending, SortType.Alphabetic, "nosort", get, CommandFlags.None); @@ -742,7 +742,7 @@ public async Task SortedSetAddAsync_3() [Fact] public async Task SortedSetCombineAsync() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; await prefixed.SortedSetCombineAsync(SetOperation.Intersect, keys); await mock.Received().SortedSetCombineAsync(SetOperation.Intersect, keys, null, Aggregate.Sum, CommandFlags.None); } @@ -750,7 +750,7 @@ public async Task SortedSetCombineAsync() [Fact] public async Task SortedSetCombineWithScoresAsync() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; await prefixed.SortedSetCombineWithScoresAsync(SetOperation.Intersect, keys); await mock.Received().SortedSetCombineWithScoresAsync(SetOperation.Intersect, keys, null, Aggregate.Sum, CommandFlags.None); } @@ -765,7 +765,7 @@ public async Task SortedSetCombineAndStoreAsync_1() [Fact] public async Task SortedSetCombineAndStoreAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.SetCombineAndStoreAsync(SetOperation.Intersect, "destination", keys, CommandFlags.None); await mock.Received().SetCombineAndStoreAsync(SetOperation.Intersect, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -788,7 +788,7 @@ public async Task SortedSetIncrementAsync() [Fact] public async Task SortedSetIntersectionLengthAsync() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; await prefixed.SortedSetIntersectionLengthAsync(keys, 1, CommandFlags.None); await mock.Received().SortedSetIntersectionLengthAsync(keys, 1, CommandFlags.None); } @@ -1149,7 +1149,7 @@ public async Task StringBitOperationAsync_1() [Fact] public async Task StringBitOperationAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.StringBitOperationAsync(Bitwise.Xor, "destination", keys, CommandFlags.None); await mock.Received().StringBitOperationAsync(Bitwise.Xor, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1158,7 +1158,7 @@ public async Task StringBitOperationAsync_2() [Fact] public async Task StringBitOperationAsync_Diff() { - RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" }; + RedisKey[] keys = ["x", "y1", "y2"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2"; await prefixed.StringBitOperationAsync(Bitwise.Diff, "destination", keys, CommandFlags.None); await mock.Received().StringBitOperationAsync(Bitwise.Diff, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1167,7 +1167,7 @@ public async Task StringBitOperationAsync_Diff() [Fact] public async Task StringBitOperationAsync_Diff1() { - RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" }; + RedisKey[] keys = ["x", "y1", "y2"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2"; await prefixed.StringBitOperationAsync(Bitwise.Diff1, "destination", keys, CommandFlags.None); await mock.Received().StringBitOperationAsync(Bitwise.Diff1, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1176,7 +1176,7 @@ public async Task StringBitOperationAsync_Diff1() [Fact] public async Task StringBitOperationAsync_AndOr() { - RedisKey[] keys = new RedisKey[] { "x", "y1", "y2" }; + RedisKey[] keys = ["x", "y1", "y2"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:x" && _[1] == "prefix:y1" && _[2] == "prefix:y2"; await prefixed.StringBitOperationAsync(Bitwise.AndOr, "destination", keys, CommandFlags.None); await mock.Received().StringBitOperationAsync(Bitwise.AndOr, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1185,7 +1185,7 @@ public async Task StringBitOperationAsync_AndOr() [Fact] public async Task StringBitOperationAsync_One() { - RedisKey[] keys = new RedisKey[] { "a", "b", "c" }; + RedisKey[] keys = ["a", "b", "c"]; Expression> valid = _ => _.Length == 3 && _[0] == "prefix:a" && _[1] == "prefix:b" && _[2] == "prefix:c"; await prefixed.StringBitOperationAsync(Bitwise.One, "destination", keys, CommandFlags.None); await mock.Received().StringBitOperationAsync(Bitwise.One, "prefix:destination", Arg.Is(valid), CommandFlags.None); @@ -1229,7 +1229,7 @@ public async Task StringGetAsync_1() [Fact] public async Task StringGetAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.StringGetAsync(keys, CommandFlags.None); await mock.Received().StringGetAsync(Arg.Is(valid), CommandFlags.None); @@ -1310,7 +1310,7 @@ public async Task StringSetAsync_2() [Fact] public async Task StringSetAsync_3() { - KeyValuePair[] values = new KeyValuePair[] { new KeyValuePair("a", "x"), new KeyValuePair("b", "y") }; + KeyValuePair[] values = [new KeyValuePair("a", "x"), new KeyValuePair("b", "y")]; Expression[]>> valid = _ => _.Length == 2 && _[0].Key == "prefix:a" && _[0].Value == "x" && _[1].Key == "prefix:b" && _[1].Value == "y"; await prefixed.StringSetAsync(values, When.Exists, CommandFlags.None); await mock.Received().StringSetAsync(Arg.Is(valid), When.Exists, CommandFlags.None); @@ -1348,7 +1348,7 @@ public async Task KeyTouchAsync_1() [Fact] public async Task KeyTouchAsync_2() { - RedisKey[] keys = new RedisKey[] { "a", "b" }; + RedisKey[] keys = ["a", "b"]; Expression> valid = _ => _.Length == 2 && _[0] == "prefix:a" && _[1] == "prefix:b"; await prefixed.KeyTouchAsync(keys, CommandFlags.None); await mock.Received().KeyTouchAsync(Arg.Is(valid), CommandFlags.None); diff --git a/tests/StackExchange.Redis.Tests/KeyTests.cs b/tests/StackExchange.Redis.Tests/KeyTests.cs index bfb57a425..31cd87d79 100644 --- a/tests/StackExchange.Redis.Tests/KeyTests.cs +++ b/tests/StackExchange.Redis.Tests/KeyTests.cs @@ -5,20 +5,16 @@ using System.Text; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class KeyTests : TestBase +public class KeyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public KeyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void TestScan() + public async Task TestScan() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var dbId = TestConfig.GetDedicatedDB(conn); var db = conn.GetDatabase(dbId); @@ -35,9 +31,9 @@ public void TestScan() } [Fact] - public void FlushFetchRandomKey() + public async Task FlushFetchRandomKey() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var dbId = TestConfig.GetDedicatedDB(conn); Skip.IfMissingDatabase(conn, dbId); @@ -55,9 +51,9 @@ public void FlushFetchRandomKey() } [Fact] - public void Zeros() + public async Task Zeros() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -111,9 +107,9 @@ public void PrependAppend() } [Fact] - public void Exists() + public async Task Exists() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); RedisKey key2 = Me() + "2"; @@ -123,23 +119,23 @@ public void Exists() Assert.False(db.KeyExists(key)); Assert.False(db.KeyExists(key2)); - Assert.Equal(0, db.KeyExists(new[] { key, key2 })); + Assert.Equal(0, db.KeyExists([key, key2])); db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); Assert.True(db.KeyExists(key)); Assert.False(db.KeyExists(key2)); - Assert.Equal(1, db.KeyExists(new[] { key, key2 })); + Assert.Equal(1, db.KeyExists([key, key2])); db.StringSet(key2, "new value", flags: CommandFlags.FireAndForget); Assert.True(db.KeyExists(key)); Assert.True(db.KeyExists(key2)); - Assert.Equal(2, db.KeyExists(new[] { key, key2 })); + Assert.Equal(2, db.KeyExists([key, key2])); } [Fact] public async Task ExistsAsync() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); RedisKey key2 = Me() + "2"; @@ -148,19 +144,19 @@ public async Task ExistsAsync() db.KeyDelete(key2, CommandFlags.FireAndForget); var a1 = db.KeyExistsAsync(key).ForAwait(); var a2 = db.KeyExistsAsync(key2).ForAwait(); - var a3 = db.KeyExistsAsync(new[] { key, key2 }).ForAwait(); + var a3 = db.KeyExistsAsync([key, key2]).ForAwait(); db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); var b1 = db.KeyExistsAsync(key).ForAwait(); var b2 = db.KeyExistsAsync(key2).ForAwait(); - var b3 = db.KeyExistsAsync(new[] { key, key2 }).ForAwait(); + var b3 = db.KeyExistsAsync([key, key2]).ForAwait(); db.StringSet(key2, "new value", flags: CommandFlags.FireAndForget); var c1 = db.KeyExistsAsync(key).ForAwait(); var c2 = db.KeyExistsAsync(key2).ForAwait(); - var c3 = db.KeyExistsAsync(new[] { key, key2 }).ForAwait(); + var c3 = db.KeyExistsAsync([key, key2]).ForAwait(); Assert.False(await a1); Assert.False(await a2); @@ -175,90 +171,10 @@ public async Task ExistsAsync() Assert.Equal(2, await c3); } - [Fact] - public async Task IdleTime() - { - using var conn = Create(); - - RedisKey key = Me(); - var db = conn.GetDatabase(); - db.KeyDelete(key, CommandFlags.FireAndForget); - db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); - await Task.Delay(2000).ForAwait(); - var idleTime = db.KeyIdleTime(key); - Assert.True(idleTime > TimeSpan.Zero); - - db.StringSet(key, "new value2", flags: CommandFlags.FireAndForget); - var idleTime2 = db.KeyIdleTime(key); - Assert.True(idleTime2 < idleTime); - - db.KeyDelete(key); - var idleTime3 = db.KeyIdleTime(key); - Assert.Null(idleTime3); - } - - [Fact] - public async Task TouchIdleTime() - { - using var conn = Create(require: RedisFeatures.v3_2_1); - - RedisKey key = Me(); - var db = conn.GetDatabase(); - db.KeyDelete(key, CommandFlags.FireAndForget); - db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); - await Task.Delay(2000).ForAwait(); - var idleTime = db.KeyIdleTime(key); - Assert.True(idleTime > TimeSpan.Zero); - - Assert.True(db.KeyTouch(key)); - var idleTime1 = db.KeyIdleTime(key); - Assert.True(idleTime1 < idleTime); - } - - [Fact] - public async Task IdleTimeAsync() - { - using var conn = Create(); - - RedisKey key = Me(); - var db = conn.GetDatabase(); - db.KeyDelete(key, CommandFlags.FireAndForget); - db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); - await Task.Delay(2000).ForAwait(); - var idleTime = await db.KeyIdleTimeAsync(key).ForAwait(); - Assert.True(idleTime > TimeSpan.Zero); - - db.StringSet(key, "new value2", flags: CommandFlags.FireAndForget); - var idleTime2 = await db.KeyIdleTimeAsync(key).ForAwait(); - Assert.True(idleTime2 < idleTime); - - db.KeyDelete(key); - var idleTime3 = await db.KeyIdleTimeAsync(key).ForAwait(); - Assert.Null(idleTime3); - } - - [Fact] - public async Task TouchIdleTimeAsync() - { - using var conn = Create(require: RedisFeatures.v3_2_1); - - RedisKey key = Me(); - var db = conn.GetDatabase(); - db.KeyDelete(key, CommandFlags.FireAndForget); - db.StringSet(key, "new value", flags: CommandFlags.FireAndForget); - await Task.Delay(2000).ForAwait(); - var idleTime = await db.KeyIdleTimeAsync(key).ForAwait(); - Assert.True(idleTime > TimeSpan.Zero); - - Assert.True(await db.KeyTouchAsync(key).ForAwait()); - var idleTime1 = await db.KeyIdleTimeAsync(key).ForAwait(); - Assert.True(idleTime1 < idleTime); - } - [Fact] public async Task KeyEncoding() { - using var conn = Create(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); @@ -285,7 +201,7 @@ public async Task KeyEncoding() [Fact] public async Task KeyRefCount() { - using var conn = Create(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); @@ -303,7 +219,7 @@ public async Task KeyRefCount() [Fact] public async Task KeyFrequency() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v4_0_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v4_0_0); var key = Me(); var db = conn.GetDatabase(); @@ -492,49 +408,50 @@ public void KeyEquality(RedisKey x, RedisKey y, bool equal) } } - public static IEnumerable KeyEqualityData() + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "xUnit1046:Avoid using TheoryDataRow arguments that are not serializable", Justification = "No options at the moment.")] + public static IEnumerable> KeyEqualityData() { RedisKey abcString = "abc", abcBytes = Encoding.UTF8.GetBytes("abc"); RedisKey abcdefString = "abcdef", abcdefBytes = Encoding.UTF8.GetBytes("abcdef"); - yield return new object[] { RedisKey.Null, abcString, false }; - yield return new object[] { RedisKey.Null, abcBytes, false }; - yield return new object[] { abcString, RedisKey.Null, false }; - yield return new object[] { abcBytes, RedisKey.Null, false }; - yield return new object[] { RedisKey.Null, RedisKey.Null, true }; - yield return new object[] { new RedisKey((string?)null), RedisKey.Null, true }; - yield return new object[] { new RedisKey(null, (byte[]?)null), RedisKey.Null, true }; - yield return new object[] { new RedisKey(""), RedisKey.Null, false }; - yield return new object[] { new RedisKey(null, Array.Empty()), RedisKey.Null, false }; - - yield return new object[] { abcString, abcString, true }; - yield return new object[] { abcBytes, abcBytes, true }; - yield return new object[] { abcString, abcBytes, true }; - yield return new object[] { abcBytes, abcString, true }; - - yield return new object[] { abcdefString, abcdefString, true }; - yield return new object[] { abcdefBytes, abcdefBytes, true }; - yield return new object[] { abcdefString, abcdefBytes, true }; - yield return new object[] { abcdefBytes, abcdefString, true }; - - yield return new object[] { abcString, abcdefString, false }; - yield return new object[] { abcBytes, abcdefBytes, false }; - yield return new object[] { abcString, abcdefBytes, false }; - yield return new object[] { abcBytes, abcdefString, false }; - - yield return new object[] { abcdefString, abcString, false }; - yield return new object[] { abcdefBytes, abcBytes, false }; - yield return new object[] { abcdefString, abcBytes, false }; - yield return new object[] { abcdefBytes, abcString, false }; + yield return new(RedisKey.Null, abcString, false); + yield return new(RedisKey.Null, abcBytes, false); + yield return new(abcString, RedisKey.Null, false); + yield return new(abcBytes, RedisKey.Null, false); + yield return new(RedisKey.Null, RedisKey.Null, true); + yield return new(new RedisKey((string?)null), RedisKey.Null, true); + yield return new(new RedisKey(null, (byte[]?)null), RedisKey.Null, true); + yield return new(new RedisKey(""), RedisKey.Null, false); + yield return new(new RedisKey(null, Array.Empty()), RedisKey.Null, false); + + yield return new(abcString, abcString, true); + yield return new(abcBytes, abcBytes, true); + yield return new(abcString, abcBytes, true); + yield return new(abcBytes, abcString, true); + + yield return new(abcdefString, abcdefString, true); + yield return new(abcdefBytes, abcdefBytes, true); + yield return new(abcdefString, abcdefBytes, true); + yield return new(abcdefBytes, abcdefString, true); + + yield return new(abcString, abcdefString, false); + yield return new(abcBytes, abcdefBytes, false); + yield return new(abcString, abcdefBytes, false); + yield return new(abcBytes, abcdefString, false); + + yield return new(abcdefString, abcString, false); + yield return new(abcdefBytes, abcBytes, false); + yield return new(abcdefString, abcBytes, false); + yield return new(abcdefBytes, abcString, false); var x = abcString.Append("def"); - yield return new object[] { abcdefString, x, true }; - yield return new object[] { abcdefBytes, x, true }; - yield return new object[] { x, abcdefBytes, true }; - yield return new object[] { x, abcdefString, true }; - yield return new object[] { abcString, x, false }; - yield return new object[] { abcString, x, false }; - yield return new object[] { x, abcString, false }; - yield return new object[] { x, abcString, false }; + yield return new(abcdefString, x, true); + yield return new(abcdefBytes, x, true); + yield return new(x, abcdefBytes, true); + yield return new(x, abcdefString, true); + yield return new(abcString, x, false); + yield return new(abcString, x, false); + yield return new(x, abcString, false); + yield return new(x, abcString, false); } } diff --git a/tests/StackExchange.Redis.Tests/LatencyTests.cs b/tests/StackExchange.Redis.Tests/LatencyTests.cs index c82c947b7..42b4d7b05 100644 --- a/tests/StackExchange.Redis.Tests/LatencyTests.cs +++ b/tests/StackExchange.Redis.Tests/LatencyTests.cs @@ -1,18 +1,15 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class LatencyTests : TestBase +[Collection(NonParallelCollection.Name)] +public class LatencyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public LatencyTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task CanCallDoctor() { - using var conn = Create(); + await using var conn = Create(); var server = conn.GetServer(conn.GetEndPoints()[0]); string? doctor = server.LatencyDoctor(); @@ -27,24 +24,25 @@ public async Task CanCallDoctor() [Fact] public async Task CanReset() { - using var conn = Create(); + await using var conn = Create(); var server = conn.GetServer(conn.GetEndPoints()[0]); _ = server.LatencyReset(); - var count = await server.LatencyResetAsync(new[] { "command" }); + var count = await server.LatencyResetAsync(["command"]); Assert.Equal(0, count); - count = await server.LatencyResetAsync(new[] { "command", "fast-command" }); + count = await server.LatencyResetAsync(["command", "fast-command"]); Assert.Equal(0, count); } [Fact] public async Task GetLatest() { - using var conn = Create(allowAdmin: true); + Skip.UnlessLongRunning(); + await using var conn = Create(allowAdmin: true); var server = conn.GetServer(conn.GetEndPoints()[0]); - server.ConfigSet("latency-monitor-threshold", 100); + server.ConfigSet("latency-monitor-threshold", 50); server.LatencyReset(); var arr = server.LatencyLatest(); Assert.Empty(arr); @@ -63,10 +61,11 @@ public async Task GetLatest() [Fact] public async Task GetHistory() { - using var conn = Create(allowAdmin: true); + Skip.UnlessLongRunning(); + await using var conn = Create(allowAdmin: true); var server = conn.GetServer(conn.GetEndPoints()[0]); - server.ConfigSet("latency-monitor-threshold", 100); + server.ConfigSet("latency-monitor-threshold", 50); server.LatencyReset(); var arr = server.LatencyHistory("command"); Assert.Empty(arr); diff --git a/tests/StackExchange.Redis.Tests/LexTests.cs b/tests/StackExchange.Redis.Tests/LexTests.cs index a72aeb142..e29255b24 100644 --- a/tests/StackExchange.Redis.Tests/LexTests.cs +++ b/tests/StackExchange.Redis.Tests/LexTests.cs @@ -1,17 +1,14 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class LexTests : TestBase +public class LexTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public LexTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void QueryRangeAndLengthByLex() + public async Task QueryRangeAndLengthByLex() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -19,8 +16,7 @@ public void QueryRangeAndLengthByLex() db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("a", 0), new SortedSetEntry("b", 0), new SortedSetEntry("c", 0), @@ -28,7 +24,7 @@ public void QueryRangeAndLengthByLex() new SortedSetEntry("e", 0), new SortedSetEntry("f", 0), new SortedSetEntry("g", 0), - }, + ], CommandFlags.FireAndForget); var set = db.SortedSetRangeByValue(key, default(RedisValue), "c"); @@ -58,9 +54,9 @@ public void QueryRangeAndLengthByLex() } [Fact] - public void RemoveRangeByLex() + public async Task RemoveRangeByLex() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -68,25 +64,23 @@ public void RemoveRangeByLex() db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("aaaa", 0), new SortedSetEntry("b", 0), new SortedSetEntry("c", 0), new SortedSetEntry("d", 0), new SortedSetEntry("e", 0), - }, + ], CommandFlags.FireAndForget); db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("foo", 0), new SortedSetEntry("zap", 0), new SortedSetEntry("zip", 0), new SortedSetEntry("ALPHA", 0), new SortedSetEntry("alpha", 0), - }, + ], CommandFlags.FireAndForget); var set = db.SortedSetRangeByRank(key); diff --git a/tests/StackExchange.Redis.Tests/ListTests.cs b/tests/StackExchange.Redis.Tests/ListTests.cs index 5fdb5d60a..cd0f2e0a3 100644 --- a/tests/StackExchange.Redis.Tests/ListTests.cs +++ b/tests/StackExchange.Redis.Tests/ListTests.cs @@ -2,20 +2,16 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class ListTests : TestBase +public class ListTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ListTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void Ranges() + public async Task Ranges() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -35,9 +31,9 @@ public void Ranges() } [Fact] - public void ListLeftPushEmptyValues() + public async Task ListLeftPushEmptyValues() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -47,29 +43,29 @@ public void ListLeftPushEmptyValues() } [Fact] - public void ListLeftPushKeyDoesNotExists() + public async Task ListLeftPushKeyDoesNotExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var result = db.ListLeftPush(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); + var result = db.ListLeftPush(key, ["testvalue"], When.Exists, CommandFlags.None); Assert.Equal(0, result); } [Fact] - public void ListLeftPushToExisitingKey() + public async Task ListLeftPushToExisitingKey() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = db.ListLeftPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = db.ListLeftPush(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = db.ListLeftPush(key, new RedisValue[] { "testvalue2" }, When.Exists, CommandFlags.None); + var pushXResult = db.ListLeftPush(key, ["testvalue2"], When.Exists, CommandFlags.None); Assert.Equal(2, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -79,17 +75,17 @@ public void ListLeftPushToExisitingKey() } [Fact] - public void ListLeftPushMultipleToExisitingKey() + public async Task ListLeftPushMultipleToExisitingKey() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = db.ListLeftPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = db.ListLeftPush(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = db.ListLeftPush(key, new RedisValue[] { "testvalue2", "testvalue3" }, When.Exists, CommandFlags.None); + var pushXResult = db.ListLeftPush(key, ["testvalue2", "testvalue3"], When.Exists, CommandFlags.None); Assert.Equal(3, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -102,7 +98,7 @@ public void ListLeftPushMultipleToExisitingKey() [Fact] public async Task ListLeftPushAsyncEmptyValues() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -114,27 +110,27 @@ public async Task ListLeftPushAsyncEmptyValues() [Fact] public async Task ListLeftPushAsyncKeyDoesNotExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var result = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); + var result = await db.ListLeftPushAsync(key, ["testvalue"], When.Exists, CommandFlags.None); Assert.Equal(0, result); } [Fact] public async Task ListLeftPushAsyncToExisitingKey() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = await db.ListLeftPushAsync(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue2" }, When.Exists, CommandFlags.None); + var pushXResult = await db.ListLeftPushAsync(key, ["testvalue2"], When.Exists, CommandFlags.None); Assert.Equal(2, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -146,15 +142,15 @@ public async Task ListLeftPushAsyncToExisitingKey() [Fact] public async Task ListLeftPushAsyncMultipleToExisitingKey() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = await db.ListLeftPushAsync(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = await db.ListLeftPushAsync(key, new RedisValue[] { "testvalue2", "testvalue3" }, When.Exists, CommandFlags.None); + var pushXResult = await db.ListLeftPushAsync(key, ["testvalue2", "testvalue3"], When.Exists, CommandFlags.None); Assert.Equal(3, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -165,9 +161,9 @@ public async Task ListLeftPushAsyncMultipleToExisitingKey() } [Fact] - public void ListRightPushEmptyValues() + public async Task ListRightPushEmptyValues() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -177,29 +173,29 @@ public void ListRightPushEmptyValues() } [Fact] - public void ListRightPushKeyDoesNotExists() + public async Task ListRightPushKeyDoesNotExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var result = db.ListRightPush(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); + var result = db.ListRightPush(key, ["testvalue"], When.Exists, CommandFlags.None); Assert.Equal(0, result); } [Fact] - public void ListRightPushToExisitingKey() + public async Task ListRightPushToExisitingKey() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = db.ListRightPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = db.ListRightPush(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = db.ListRightPush(key, new RedisValue[] { "testvalue2" }, When.Exists, CommandFlags.None); + var pushXResult = db.ListRightPush(key, ["testvalue2"], When.Exists, CommandFlags.None); Assert.Equal(2, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -209,17 +205,17 @@ public void ListRightPushToExisitingKey() } [Fact] - public void ListRightPushMultipleToExisitingKey() + public async Task ListRightPushMultipleToExisitingKey() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = db.ListRightPush(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = db.ListRightPush(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = db.ListRightPush(key, new RedisValue[] { "testvalue2", "testvalue3" }, When.Exists, CommandFlags.None); + var pushXResult = db.ListRightPush(key, ["testvalue2", "testvalue3"], When.Exists, CommandFlags.None); Assert.Equal(3, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -232,7 +228,7 @@ public void ListRightPushMultipleToExisitingKey() [Fact] public async Task ListRightPushAsyncEmptyValues() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -244,27 +240,27 @@ public async Task ListRightPushAsyncEmptyValues() [Fact] public async Task ListRightPushAsyncKeyDoesNotExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var result = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue" }, When.Exists, CommandFlags.None); + var result = await db.ListRightPushAsync(key, ["testvalue"], When.Exists, CommandFlags.None); Assert.Equal(0, result); } [Fact] public async Task ListRightPushAsyncToExisitingKey() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = await db.ListRightPushAsync(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue2" }, When.Exists, CommandFlags.None); + var pushXResult = await db.ListRightPushAsync(key, ["testvalue2"], When.Exists, CommandFlags.None); Assert.Equal(2, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -276,15 +272,15 @@ public async Task ListRightPushAsyncToExisitingKey() [Fact] public async Task ListRightPushAsyncMultipleToExisitingKey() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - var pushResult = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue1" }, CommandFlags.None); + var pushResult = await db.ListRightPushAsync(key, ["testvalue1"], CommandFlags.None); Assert.Equal(1, pushResult); - var pushXResult = await db.ListRightPushAsync(key, new RedisValue[] { "testvalue2", "testvalue3" }, When.Exists, CommandFlags.None); + var pushXResult = await db.ListRightPushAsync(key, ["testvalue2", "testvalue3"], When.Exists, CommandFlags.None); Assert.Equal(3, pushXResult); var rangeResult = db.ListRange(key, 0, -1); @@ -297,14 +293,14 @@ public async Task ListRightPushAsyncMultipleToExisitingKey() [Fact] public async Task ListMove() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); RedisKey src = Me(); RedisKey dest = Me() + "dest"; db.KeyDelete(src, CommandFlags.FireAndForget); - var pushResult = await db.ListRightPushAsync(src, new RedisValue[] { "testvalue1", "testvalue2" }); + var pushResult = await db.ListRightPushAsync(src, ["testvalue1", "testvalue2"]); Assert.Equal(2, pushResult); var rangeResult1 = db.ListMove(src, dest, ListSide.Left, ListSide.Right); @@ -318,9 +314,9 @@ public async Task ListMove() } [Fact] - public void ListMoveKeyDoesNotExist() + public async Task ListMoveKeyDoesNotExist() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); RedisKey src = Me(); @@ -332,9 +328,9 @@ public void ListMoveKeyDoesNotExist() } [Fact] - public void ListPositionHappyPath() + public async Task ListPositionHappyPath() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -348,9 +344,9 @@ public void ListPositionHappyPath() } [Fact] - public void ListPositionEmpty() + public async Task ListPositionEmpty() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -363,9 +359,9 @@ public void ListPositionEmpty() } [Fact] - public void ListPositionsHappyPath() + public async Task ListPositionsHappyPath() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -393,9 +389,9 @@ public void ListPositionsHappyPath() } [Fact] - public void ListPositionsTooFew() + public async Task ListPositionsTooFew() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -419,9 +415,9 @@ public void ListPositionsTooFew() } [Fact] - public void ListPositionsAll() + public async Task ListPositionsAll() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -449,9 +445,9 @@ public void ListPositionsAll() } [Fact] - public void ListPositionsAllLimitLength() + public async Task ListPositionsAllLimitLength() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -479,9 +475,9 @@ public void ListPositionsAllLimitLength() } [Fact] - public void ListPositionsEmpty() + public async Task ListPositionsEmpty() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -503,9 +499,9 @@ public void ListPositionsEmpty() } [Fact] - public void ListPositionByRank() + public async Task ListPositionByRank() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -530,9 +526,9 @@ public void ListPositionByRank() } [Fact] - public void ListPositionLimitSoNull() + public async Task ListPositionLimitSoNull() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -558,7 +554,7 @@ public void ListPositionLimitSoNull() [Fact] public async Task ListPositionHappyPathAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -574,7 +570,7 @@ public async Task ListPositionHappyPathAsync() [Fact] public async Task ListPositionEmptyAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -589,7 +585,7 @@ public async Task ListPositionEmptyAsync() [Fact] public async Task ListPositionsHappyPathAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -619,7 +615,7 @@ public async Task ListPositionsHappyPathAsync() [Fact] public async Task ListPositionsTooFewAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -645,7 +641,7 @@ public async Task ListPositionsTooFewAsync() [Fact] public async Task ListPositionsAllAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -675,7 +671,7 @@ public async Task ListPositionsAllAsync() [Fact] public async Task ListPositionsAllLimitLengthAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -705,7 +701,7 @@ public async Task ListPositionsAllLimitLengthAsync() [Fact] public async Task ListPositionsEmptyAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -729,7 +725,7 @@ public async Task ListPositionsEmptyAsync() [Fact] public async Task ListPositionByRankAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -756,7 +752,7 @@ public async Task ListPositionByRankAsync() [Fact] public async Task ListPositionLimitSoNullAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -782,7 +778,7 @@ public async Task ListPositionLimitSoNullAsync() [Fact] public async Task ListPositionFireAndForgetAsync() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -807,9 +803,9 @@ public async Task ListPositionFireAndForgetAsync() } [Fact] - public void ListPositionFireAndForget() + public async Task ListPositionFireAndForget() { - using var conn = Create(require: RedisFeatures.v6_0_6); + await using var conn = Create(require: RedisFeatures.v6_0_6); var db = conn.GetDatabase(); var key = Me(); @@ -836,7 +832,7 @@ public void ListPositionFireAndForget() [Fact] public async Task ListMultiPopSingleKeyAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -848,13 +844,13 @@ public async Task ListMultiPopSingleKeyAsync() db.ListLeftPush(key, "red sox"); db.ListLeftPush(key, "rays"); - var res = await db.ListLeftPopAsync(new RedisKey[] { key }, 1); + var res = await db.ListLeftPopAsync([key], 1); Assert.False(res.IsNull); Assert.Single(res.Values); Assert.Equal("rays", res.Values[0]); - res = await db.ListRightPopAsync(new RedisKey[] { key }, 2); + res = await db.ListRightPopAsync([key], 2); Assert.False(res.IsNull); Assert.Equal(2, res.Values.Length); @@ -865,7 +861,7 @@ public async Task ListMultiPopSingleKeyAsync() [Fact] public async Task ListMultiPopMultipleKeysAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -877,14 +873,14 @@ public async Task ListMultiPopMultipleKeysAsync() db.ListLeftPush(key, "red sox"); db.ListLeftPush(key, "rays"); - var res = await db.ListLeftPopAsync(new RedisKey[] { "empty-key", key, "also-empty" }, 2); + var res = await db.ListLeftPopAsync(["empty-key", key, "also-empty"], 2); Assert.False(res.IsNull); Assert.Equal(2, res.Values.Length); Assert.Equal("rays", res.Values[0]); Assert.Equal("red sox", res.Values[1]); - res = await db.ListRightPopAsync(new RedisKey[] { "empty-key", key, "also-empty" }, 1); + res = await db.ListRightPopAsync(["empty-key", key, "also-empty"], 1); Assert.False(res.IsNull); Assert.Single(res.Values); @@ -892,9 +888,9 @@ public async Task ListMultiPopMultipleKeysAsync() } [Fact] - public void ListMultiPopSingleKey() + public async Task ListMultiPopSingleKey() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -906,13 +902,13 @@ public void ListMultiPopSingleKey() db.ListLeftPush(key, "red sox"); db.ListLeftPush(key, "rays"); - var res = db.ListLeftPop(new RedisKey[] { key }, 1); + var res = db.ListLeftPop([key], 1); Assert.False(res.IsNull); Assert.Single(res.Values); Assert.Equal("rays", res.Values[0]); - res = db.ListRightPop(new RedisKey[] { key }, 2); + res = db.ListRightPop([key], 2); Assert.False(res.IsNull); Assert.Equal(2, res.Values.Length); @@ -923,33 +919,33 @@ public void ListMultiPopSingleKey() [Fact] public async Task ListMultiPopZeroCount() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key); - var exception = await Assert.ThrowsAsync(() => db.ListLeftPopAsync(new RedisKey[] { key }, 0)); + var exception = await Assert.ThrowsAsync(() => db.ListLeftPopAsync([key], 0)); Assert.Contains("ERR count should be greater than 0", exception.Message); } [Fact] public async Task ListMultiPopEmpty() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key); - var res = await db.ListLeftPopAsync(new RedisKey[] { key }, 1); + var res = await db.ListLeftPopAsync([key], 1); Assert.True(res.IsNull); } [Fact] - public void ListMultiPopEmptyKeys() + public async Task ListMultiPopEmptyKeys() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var exception = Assert.Throws(() => db.ListRightPop(Array.Empty(), 5)); diff --git a/tests/StackExchange.Redis.Tests/LockingTests.cs b/tests/StackExchange.Redis.Tests/LockingTests.cs index 4f9dbd402..52d03bb83 100644 --- a/tests/StackExchange.Redis.Tests/LockingTests.cs +++ b/tests/StackExchange.Redis.Tests/LockingTests.cs @@ -3,16 +3,12 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class LockingTests : TestBase +public class LockingTests(ITestOutputHelper output) : TestBase(output) { - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public LockingTests(ITestOutputHelper output) : base(output) { } - public enum TestMode { MultiExec, @@ -20,11 +16,11 @@ public enum TestMode Twemproxy, } - public static IEnumerable TestModes() + public static IEnumerable> TestModes() { - yield return new object[] { TestMode.MultiExec }; - yield return new object[] { TestMode.NoMultiExec }; - yield return new object[] { TestMode.Twemproxy }; + yield return new(TestMode.MultiExec); + yield return new(TestMode.NoMultiExec); + yield return new(TestMode.Twemproxy); } [Theory, MemberData(nameof(TestModes))] @@ -67,9 +63,9 @@ void Inner(object? obj) } [Fact] - public void TestOpCountByVersionLocal_UpLevel() + public async Task TestOpCountByVersionLocal_UpLevel() { - using var conn = Create(shared: false); + await using var conn = Create(shared: false); TestLockOpCountByVersion(conn, 1, false); TestLockOpCountByVersion(conn, 1, true); @@ -105,7 +101,7 @@ private void TestLockOpCountByVersion(IConnectionMultiplexer conn, int expectedO private IConnectionMultiplexer Create(TestMode mode) => mode switch { TestMode.MultiExec => Create(), - TestMode.NoMultiExec => Create(disabledCommands: new[] { "multi", "exec" }), + TestMode.NoMultiExec => Create(disabledCommands: ["multi", "exec"]), TestMode.Twemproxy => Create(proxy: Proxy.Twemproxy), _ => throw new NotSupportedException(mode.ToString()), }; @@ -113,7 +109,7 @@ private void TestLockOpCountByVersion(IConnectionMultiplexer conn, int expectedO [Theory, MemberData(nameof(TestModes))] public async Task TakeLockAndExtend(TestMode testMode) { - using var conn = Create(testMode); + await using var conn = Create(testMode); RedisValue right = Guid.NewGuid().ToString(), wrong = Guid.NewGuid().ToString(); @@ -165,7 +161,7 @@ public async Task TakeLockAndExtend(TestMode testMode) [Theory, MemberData(nameof(TestModes))] public async Task TestBasicLockNotTaken(TestMode testMode) { - using var conn = Create(testMode); + await using var conn = Create(testMode); int errorCount = 0; conn.ErrorMessage += (sender, e) => Interlocked.Increment(ref errorCount); @@ -194,7 +190,7 @@ public async Task TestBasicLockNotTaken(TestMode testMode) [Theory, MemberData(nameof(TestModes))] public async Task TestBasicLockTaken(TestMode testMode) { - using var conn = Create(testMode); + await using var conn = Create(testMode); var db = conn.GetDatabase(); var key = Me() + testMode; diff --git a/tests/StackExchange.Redis.Tests/LoggerTests.cs b/tests/StackExchange.Redis.Tests/LoggerTests.cs index 75077f9a9..bc097d24c 100644 --- a/tests/StackExchange.Redis.Tests/LoggerTests.cs +++ b/tests/StackExchange.Redis.Tests/LoggerTests.cs @@ -6,16 +6,12 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class LoggerTests : TestBase +public class LoggerTests(ITestOutputHelper output) : TestBase(output) { - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public LoggerTests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task BasicLoggerConfig() { @@ -29,7 +25,7 @@ public async Task BasicLoggerConfig() var options = ConfigurationOptions.Parse(GetConfiguration()); options.LoggerFactory = new TestWrapperLoggerFactory(new TestMultiLogger(traceLogger, debugLogger, infoLogger, warningLogger, errorLogger, criticalLogger)); - using var conn = await ConnectionMultiplexer.ConnectAsync(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); // We expect more at the trace level: GET, ECHO, PING on commands Assert.True(traceLogger.CallCount > debugLogger.CallCount); // Many calls for all log lines - don't set exact here since every addition would break the test @@ -48,26 +44,23 @@ public async Task WrappedLogger() var wrapped = new TestWrapperLoggerFactory(NullLogger.Instance); options.LoggerFactory = wrapped; - using var conn = await ConnectionMultiplexer.ConnectAsync(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); Assert.True(wrapped.Logger.LogCount > 0); } - public class TestWrapperLoggerFactory : ILoggerFactory + public class TestWrapperLoggerFactory(ILogger logger) : ILoggerFactory { - public TestWrapperLogger Logger { get; } - public TestWrapperLoggerFactory(ILogger logger) => Logger = new TestWrapperLogger(logger); + public TestWrapperLogger Logger { get; } = new TestWrapperLogger(logger); public void AddProvider(ILoggerProvider provider) => throw new NotImplementedException(); public ILogger CreateLogger(string categoryName) => Logger; public void Dispose() { } } - public class TestWrapperLogger : ILogger + public class TestWrapperLogger(ILogger toWrap) : ILogger { public int LogCount = 0; - private ILogger Inner { get; } - - public TestWrapperLogger(ILogger toWrap) => Inner = toWrap; + private ILogger Inner { get; } = toWrap; #if NET8_0_OR_GREATER public IDisposable? BeginScope(TState state) where TState : notnull => Inner.BeginScope(state); @@ -85,11 +78,8 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except /// /// To save on test time, no reason to spin up n connections just to test n logging implementations... /// - private class TestMultiLogger : ILogger + private class TestMultiLogger(params ILogger[] loggers) : ILogger { - private readonly ILogger[] _loggers; - public TestMultiLogger(params ILogger[] loggers) => _loggers = loggers; - #if NET8_0_OR_GREATER public IDisposable? BeginScope(TState state) where TState : notnull => throw new NotImplementedException(); #else @@ -98,7 +88,7 @@ private class TestMultiLogger : ILogger public bool IsEnabled(LogLevel logLevel) => true; public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { - foreach (var logger in _loggers) + foreach (var logger in loggers) { logger.Log(logLevel, eventId, state, exception, formatter); } diff --git a/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs b/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs index 3b3f8157e..0140c7c97 100644 --- a/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs +++ b/tests/StackExchange.Redis.Tests/MassiveOpsTests.cs @@ -2,19 +2,17 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class MassiveOpsTests : TestBase +public class MassiveOpsTests(ITestOutputHelper output) : TestBase(output) { - public MassiveOpsTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task LongRunning() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var key = Me(); var db = conn.GetDatabase(); @@ -33,7 +31,7 @@ public async Task LongRunning() [InlineData(false)] public async Task MassiveBulkOpsAsync(bool withContinuation) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -57,14 +55,15 @@ static void NonTrivial(Task unused) Log($"{Me()}: Time for {AsyncOpsQty} ops: {watch.ElapsedMilliseconds}ms ({(withContinuation ? "with continuation" : "no continuation")}, any order); ops/s: {AsyncOpsQty / watch.Elapsed.TotalSeconds}"); } - [TheoryLongRunning] + [Theory] [InlineData(1)] [InlineData(5)] [InlineData(10)] [InlineData(50)] - public void MassiveBulkOpsSync(int threads) + public async Task MassiveBulkOpsSync(int threads) { - using var conn = Create(syncTimeout: 30000); + Skip.UnlessLongRunning(); + await using var conn = Create(syncTimeout: 30000); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -88,13 +87,13 @@ public void MassiveBulkOpsSync(int threads) [Theory] [InlineData(1)] [InlineData(5)] - public void MassiveBulkOpsFireAndForget(int threads) + public async Task MassiveBulkOpsFireAndForget(int threads) { - using var conn = Create(syncTimeout: 30000); + await using var conn = Create(syncTimeout: 30000); RedisKey key = Me(); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); db.KeyDelete(key, CommandFlags.FireAndForget); int perThread = AsyncOpsQty / threads; diff --git a/tests/StackExchange.Redis.Tests/MemoryTests.cs b/tests/StackExchange.Redis.Tests/MemoryTests.cs index 50812e597..48d3ea705 100644 --- a/tests/StackExchange.Redis.Tests/MemoryTests.cs +++ b/tests/StackExchange.Redis.Tests/MemoryTests.cs @@ -1,18 +1,14 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class MemoryTests : TestBase +public class MemoryTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public MemoryTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task CanCallDoctor() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var server = conn.GetServer(conn.GetEndPoints()[0]); string? doctor = server.MemoryDoctor(); @@ -27,7 +23,7 @@ public async Task CanCallDoctor() [Fact] public async Task CanPurge() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var server = conn.GetServer(conn.GetEndPoints()[0]); server.MemoryPurge(); @@ -39,7 +35,7 @@ public async Task CanPurge() [Fact] public async Task GetAllocatorStats() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var server = conn.GetServer(conn.GetEndPoints()[0]); @@ -53,7 +49,7 @@ public async Task GetAllocatorStats() [Fact] public async Task GetStats() { - using var conn = Create(require: RedisFeatures.v4_0_0); + await using var conn = Create(require: RedisFeatures.v4_0_0); var server = conn.GetServer(conn.GetEndPoints()[0]); var stats = server.MemoryStats(); diff --git a/tests/StackExchange.Redis.Tests/MigrateTests.cs b/tests/StackExchange.Redis.Tests/MigrateTests.cs index 54fe77649..9939e0632 100644 --- a/tests/StackExchange.Redis.Tests/MigrateTests.cs +++ b/tests/StackExchange.Redis.Tests/MigrateTests.cs @@ -2,25 +2,23 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class MigrateTests : TestBase +public class MigrateTests(ITestOutputHelper output) : TestBase(output) { - public MigrateTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task Basic() { + Skip.UnlessLongRunning(); var fromConfig = new ConfigurationOptions { EndPoints = { { TestConfig.Current.SecureServer, TestConfig.Current.SecurePort } }, Password = TestConfig.Current.SecurePassword, AllowAdmin = true }; var toConfig = new ConfigurationOptions { EndPoints = { { TestConfig.Current.PrimaryServer, TestConfig.Current.PrimaryPort } }, AllowAdmin = true }; - using var fromConn = ConnectionMultiplexer.Connect(fromConfig, Writer); - using var toConn = ConnectionMultiplexer.Connect(toConfig, Writer); + await using var fromConn = ConnectionMultiplexer.Connect(fromConfig, Writer); + await using var toConn = ConnectionMultiplexer.Connect(toConfig, Writer); if (await IsWindows(fromConn) || await IsWindows(toConn)) - Skip.Inconclusive("'migrate' is unreliable on redis-64"); + Assert.Skip("'migrate' is unreliable on redis-64"); RedisKey key = Me(); var fromDb = fromConn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/MultiAddTests.cs b/tests/StackExchange.Redis.Tests/MultiAddTests.cs index cf5f70c23..f5fb66335 100644 --- a/tests/StackExchange.Redis.Tests/MultiAddTests.cs +++ b/tests/StackExchange.Redis.Tests/MultiAddTests.cs @@ -1,18 +1,15 @@ using System.Linq; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class MultiAddTests : TestBase +public class MultiAddTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public MultiAddTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void AddSortedSetEveryWay() + public async Task AddSortedSetEveryWay() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -21,37 +18,33 @@ public void AddSortedSetEveryWay() db.SortedSetAdd(key, "a", 1, CommandFlags.FireAndForget); db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("b", 2), - }, + ], CommandFlags.FireAndForget); db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("c", 3), new SortedSetEntry("d", 4), - }, + ], CommandFlags.FireAndForget); db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("e", 5), new SortedSetEntry("f", 6), new SortedSetEntry("g", 7), - }, + ], CommandFlags.FireAndForget); db.SortedSetAdd( key, - new[] - { + [ new SortedSetEntry("h", 8), new SortedSetEntry("i", 9), new SortedSetEntry("j", 10), new SortedSetEntry("k", 11), - }, + ], CommandFlags.FireAndForget); var vals = db.SortedSetRangeByScoreWithScores(key); string s = string.Join(",", vals.OrderByDescending(x => x.Score).Select(x => x.Element)); @@ -61,9 +54,9 @@ public void AddSortedSetEveryWay() } [Fact] - public void AddHashEveryWay() + public async Task AddHashEveryWay() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); @@ -72,37 +65,33 @@ public void AddHashEveryWay() db.HashSet(key, "a", 1, flags: CommandFlags.FireAndForget); db.HashSet( key, - new[] - { + [ new HashEntry("b", 2), - }, + ], CommandFlags.FireAndForget); db.HashSet( key, - new[] - { + [ new HashEntry("c", 3), new HashEntry("d", 4), - }, + ], CommandFlags.FireAndForget); db.HashSet( key, - new[] - { + [ new HashEntry("e", 5), new HashEntry("f", 6), new HashEntry("g", 7), - }, + ], CommandFlags.FireAndForget); db.HashSet( key, - new[] - { + [ new HashEntry("h", 8), new HashEntry("i", 9), new HashEntry("j", 10), new HashEntry("k", 11), - }, + ], CommandFlags.FireAndForget); var vals = db.HashGetAll(key); string s = string.Join(",", vals.OrderByDescending(x => (double)x.Value).Select(x => x.Name)); @@ -112,19 +101,19 @@ public void AddHashEveryWay() } [Fact] - public void AddSetEveryWay() + public async Task AddSetEveryWay() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SetAdd(key, "a", CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "b" }, CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "c", "d" }, CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "e", "f", "g" }, CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "h", "i", "j", "k" }, CommandFlags.FireAndForget); + db.SetAdd(key, ["b"], CommandFlags.FireAndForget); + db.SetAdd(key, ["c", "d"], CommandFlags.FireAndForget); + db.SetAdd(key, ["e", "f", "g"], CommandFlags.FireAndForget); + db.SetAdd(key, ["h", "i", "j", "k"], CommandFlags.FireAndForget); var vals = db.SetMembers(key); string s = string.Join(",", vals.OrderByDescending(x => x)); @@ -132,18 +121,18 @@ public void AddSetEveryWay() } [Fact] - public void AddSetEveryWayNumbers() + public async Task AddSetEveryWayNumbers() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SetAdd(key, "a", CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "1" }, CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "11", "2" }, CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "10", "3", "1.5" }, CommandFlags.FireAndForget); - db.SetAdd(key, new RedisValue[] { "2.2", "-1", "s", "t" }, CommandFlags.FireAndForget); + db.SetAdd(key, ["1"], CommandFlags.FireAndForget); + db.SetAdd(key, ["11", "2"], CommandFlags.FireAndForget); + db.SetAdd(key, ["10", "3", "1.5"], CommandFlags.FireAndForget); + db.SetAdd(key, ["2.2", "-1", "s", "t"], CommandFlags.FireAndForget); var vals = db.SetMembers(key); string s = string.Join(",", vals.OrderByDescending(x => x)); diff --git a/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs b/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs index bf3e5690e..3d88e097c 100644 --- a/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs +++ b/tests/StackExchange.Redis.Tests/MultiPrimaryTests.cs @@ -1,23 +1,22 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class MultiPrimaryTests : TestBase +public class MultiPrimaryTests(ITestOutputHelper output) : TestBase(output) { protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword; - public MultiPrimaryTests(ITestOutputHelper output) : base(output) { } [Fact] - public void CannotFlushReplica() + public async Task CannotFlushReplica() { - var ex = Assert.Throws(() => + var ex = await Assert.ThrowsAsync(async () => { - using var conn = ConnectionMultiplexer.Connect(TestConfig.Current.ReplicaServerAndPort + ",allowAdmin=true"); + await using var conn = await ConnectionMultiplexer.ConnectAsync(TestConfig.Current.ReplicaServerAndPort + ",allowAdmin=true"); var servers = conn.GetEndPoints().Select(e => conn.GetServer(e)); var replica = servers.FirstOrDefault(x => x.IsReplica); @@ -45,7 +44,7 @@ public void TestMultiNoTieBreak() yield return new object?[] { TestConfig.Current.SecureServerAndPort, TestConfig.Current.PrimaryServerAndPort, null }; yield return new object?[] { TestConfig.Current.PrimaryServerAndPort, TestConfig.Current.SecureServerAndPort, null }; - yield return new object?[] { null, TestConfig.Current.PrimaryServerAndPort, TestConfig.Current.PrimaryServerAndPort }; + yield return new object?[] { null, TestConfig.Current.PrimaryServerAndPort, null }; yield return new object?[] { TestConfig.Current.PrimaryServerAndPort, null, TestConfig.Current.PrimaryServerAndPort }; yield return new object?[] { null, TestConfig.Current.SecureServerAndPort, TestConfig.Current.SecureServerAndPort }; yield return new object?[] { TestConfig.Current.SecureServerAndPort, null, TestConfig.Current.SecureServerAndPort }; diff --git a/tests/StackExchange.Redis.Tests/NamingTests.cs b/tests/StackExchange.Redis.Tests/NamingTests.cs index 2990e04c4..d0474f782 100644 --- a/tests/StackExchange.Redis.Tests/NamingTests.cs +++ b/tests/StackExchange.Redis.Tests/NamingTests.cs @@ -5,14 +5,11 @@ using System.Reflection; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class NamingTests : TestBase +public class NamingTests(ITestOutputHelper output) : TestBase(output) { - public NamingTests(ITestOutputHelper output) : base(output) { } - [Theory] [InlineData(typeof(IDatabase), false)] [InlineData(typeof(IDatabaseAsync), true)] diff --git a/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs b/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs index f562a850b..c695488f2 100644 --- a/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs +++ b/tests/StackExchange.Redis.Tests/OverloadCompatTests.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -9,15 +8,12 @@ namespace StackExchange.Redis.Tests; /// This test set is for when we add an overload, to making sure all /// past versions work correctly and aren't source breaking. /// -[Collection(SharedConnectionFixture.Key)] -public class OverloadCompatTests : TestBase +public class OverloadCompatTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public OverloadCompatTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task KeyExpire() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); var expiresIn = TimeSpan.FromSeconds(10); @@ -62,7 +58,7 @@ public async Task KeyExpire() [Fact] public async Task StringBitCount() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var key = Me(); @@ -108,7 +104,7 @@ public async Task StringBitCount() [Fact] public async Task StringBitPosition() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var key = Me(); @@ -158,7 +154,7 @@ public async Task StringBitPosition() [Fact] public async Task SortedSetAdd() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); RedisKey key = Me(); RedisValue val = "myval"; @@ -212,7 +208,7 @@ public async Task SortedSetAdd() [Fact] public async Task StringSet() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); var val = "myval"; diff --git a/tests/StackExchange.Redis.Tests/ParseTests.cs b/tests/StackExchange.Redis.Tests/ParseTests.cs index 80e1fbbef..51c17fbf3 100644 --- a/tests/StackExchange.Redis.Tests/ParseTests.cs +++ b/tests/StackExchange.Redis.Tests/ParseTests.cs @@ -4,14 +4,11 @@ using System.Text; using Pipelines.Sockets.Unofficial.Arenas; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ParseTests : TestBase +public class ParseTests(ITestOutputHelper output) : TestBase(output) { - public ParseTests(ITestOutputHelper output) : base(output) { } - public static IEnumerable GetTestData() { yield return new object[] { "$4\r\nPING\r\n$4\r\nPON", 1 }; diff --git a/tests/StackExchange.Redis.Tests/PerformanceTests.cs b/tests/StackExchange.Redis.Tests/PerformanceTests.cs index 068ff2870..b308bf0ac 100644 --- a/tests/StackExchange.Redis.Tests/PerformanceTests.cs +++ b/tests/StackExchange.Redis.Tests/PerformanceTests.cs @@ -2,26 +2,24 @@ using System.Text; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class PerformanceTests : TestBase +public class PerformanceTests(ITestOutputHelper output) : TestBase(output) { - public PerformanceTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] - public void VerifyPerformanceImprovement() + [Fact] + public async Task VerifyPerformanceImprovement() { + Skip.UnlessLongRunning(); int asyncTimer, sync, op = 0, asyncFaF, syncFaF; var key = Me(); - using (var conn = Create()) + await using (var conn = Create()) { // do these outside the timings, just to ensure the core methods are JITted etc for (int dbId = 0; dbId < 5; dbId++) { - conn.GetDatabase(dbId).KeyDeleteAsync(key); + _ = conn.GetDatabase(dbId).KeyDeleteAsync(key); } var timer = Stopwatch.StartNew(); @@ -33,7 +31,9 @@ public void VerifyPerformanceImprovement() { var db = conn.GetDatabase(dbId); for (int j = 0; j < 10; j++) - db.StringIncrementAsync(key); + { + _ = db.StringIncrementAsync(key); + } } } asyncFaF = (int)timer.ElapsedMilliseconds; @@ -102,7 +102,7 @@ public void VerifyPerformanceImprovement() [Fact] public async Task BasicStringGetPerf() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs b/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs index 0cb5eb271..ce20ccf7b 100644 --- a/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs +++ b/tests/StackExchange.Redis.Tests/PreserveOrderTests.cs @@ -2,20 +2,17 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class PreserveOrderTests : TestBase +public class PreserveOrderTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public PreserveOrderTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void Execute() + public async Task Execute() { - using var conn = Create(); + await using var conn = Create(); var sub = conn.GetSubscriber(); var channel = Me(); diff --git a/tests/StackExchange.Redis.Tests/ProfilingTests.cs b/tests/StackExchange.Redis.Tests/ProfilingTests.cs index 2d0264984..f374788db 100644 --- a/tests/StackExchange.Redis.Tests/ProfilingTests.cs +++ b/tests/StackExchange.Redis.Tests/ProfilingTests.cs @@ -6,19 +6,16 @@ using System.Threading.Tasks; using StackExchange.Redis.Profiling; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class ProfilingTests : TestBase +public class ProfilingTests(ITestOutputHelper output) : TestBase(output) { - public ProfilingTests(ITestOutputHelper output) : base(output) { } - [Fact] - public void Simple() + public async Task Simple() { - using var conn = Create(); + await using var conn = Create(); var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); var script = LuaScript.Prepare("return redis.call('get', @key)"); @@ -49,7 +46,7 @@ public void Simple() var i = 0; foreach (var cmd in cmds) { - Log("Command {0} (DB: {1}): {2}", i++, cmd.Db, cmd?.ToString()?.Replace("\n", ", ")); + Log($"Command {i++} (DB: {cmd.Db}): {cmd?.ToString()?.Replace("\n", ", ")}"); } var all = string.Join(",", cmds.Select(x => x.Command)); @@ -98,10 +95,11 @@ private static void AssertProfiledCommandValues(IProfiledCommand command, IConne Assert.True(command.RetransmissionReason == null, nameof(command.RetransmissionReason)); } - [FactLongRunning] - public void ManyThreads() + [Fact] + public async Task ManyThreads() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var session = new ProfilingSession(); var prefix = Me(); @@ -156,10 +154,11 @@ public void ManyThreads() } } - [FactLongRunning] - public void ManyContexts() + [Fact] + public async Task ManyContexts() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var profiler = new AsyncLocalProfiler(); var prefix = Me(); @@ -228,9 +227,9 @@ public ProfilingSession GetSession() } [Fact] - public void LowAllocationEnumerable() + public async Task LowAllocationEnumerable() { - using var conn = Create(); + await using var conn = Create(); const int OuterLoop = 1000; var session = new ProfilingSession(); @@ -273,10 +272,11 @@ public void LowAllocationEnumerable() Assert.Equal(OuterLoop * 2, res.Count(r => r.Db > 0)); } - [FactLongRunning] - public void ProfilingMD_Ex1() + [Fact] + public async Task ProfilingMD_Ex1() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var session = new ProfilingSession(); var prefix = Me(); @@ -313,10 +313,11 @@ public void ProfilingMD_Ex1() Assert.Equal(16000, timings.Count()); } - [FactLongRunning] - public void ProfilingMD_Ex2() + [Fact] + public async Task ProfilingMD_Ex2() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var profiler = new PerThreadProfiler(); var prefix = Me(); @@ -356,10 +357,11 @@ public void ProfilingMD_Ex2() Assert.True(perThreadTimings.All(kv => kv.Value.Count == 1000)); } - [FactLongRunning] + [Fact] public async Task ProfilingMD_Ex2_Async() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var profiler = new AsyncLocalProfiler(); var prefix = Me(); diff --git a/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs b/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs index f3ea9eca7..71b82e262 100644 --- a/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs +++ b/tests/StackExchange.Redis.Tests/PubSubCommandTests.cs @@ -3,20 +3,16 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class PubSubCommandTests : TestBase +public class PubSubCommandTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public PubSubCommandTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void SubscriberCount() + public async Task SubscriberCount() { - using var conn = Create(); + await using var conn = Create(); #pragma warning disable CS0618 RedisChannel channel = Me() + Guid.NewGuid(); @@ -42,7 +38,7 @@ public void SubscriberCount() [Fact] public async Task SubscriberCountAsync() { - using var conn = Create(); + await using var conn = Create(); #pragma warning disable CS0618 RedisChannel channel = Me() + Guid.NewGuid(); @@ -79,7 +75,7 @@ public static async Task WithTimeout(this Task task, int timeoutMs, [CallerMembe } else { - throw new TimeoutException($"timout from {caller} line {line}"); + throw new TimeoutException($"timeout from {caller} line {line}"); } } public static async Task WithTimeout(this Task task, int timeoutMs, [CallerMemberName] string? caller = null, [CallerLineNumber] int line = 0) diff --git a/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs b/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs index d7a0ee513..43bb4b2b8 100644 --- a/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs +++ b/tests/StackExchange.Redis.Tests/PubSubMultiserverTests.cs @@ -2,22 +2,18 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class PubSubMultiserverTests : TestBase +public class PubSubMultiserverTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public PubSubMultiserverTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - protected override string GetConfiguration() => TestConfig.Current.ClusterServersAndPorts + ",connectTimeout=10000"; [Fact] - public void ChannelSharding() + public async Task ChannelSharding() { - using var conn = Create(channelPrefix: Me()); + await using var conn = Create(channelPrefix: Me()); var defaultSlot = conn.ServerSelectionStrategy.HashSlot(default(RedisChannel)); var slot1 = conn.ServerSelectionStrategy.HashSlot(RedisChannel.Literal("hey")); @@ -31,9 +27,10 @@ public void ChannelSharding() [Fact] public async Task ClusterNodeSubscriptionFailover() { + Skip.UnlessLongRunning(); Log("Connecting..."); - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true, shared: false); var sub = conn.GetSubscriber(); var channel = RedisChannel.Literal(Me()); @@ -72,7 +69,7 @@ await sub.SubscribeAsync(channel, (_, val) => Log("Connected to: " + initialServer); conn.AllowConnect = false; - if (Context.IsResp3) + if (TestContext.Current.IsResp3()) { subscribedServerEndpoint.SimulateConnectionFailure(SimulatedFailureType.All); @@ -106,7 +103,7 @@ await sub.SubscribeAsync(channel, (_, val) => ClearAmbientFailures(); } - [Theory] + [Theory(Skip="TODO: Hostile")] [InlineData(CommandFlags.PreferMaster, true)] [InlineData(CommandFlags.PreferReplica, true)] [InlineData(CommandFlags.DemandMaster, false)] @@ -116,7 +113,7 @@ public async Task PrimaryReplicaSubscriptionFailover(CommandFlags flags, bool ex var config = TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; Log("Connecting..."); - using var conn = Create(configuration: config, shared: false, allowAdmin: true); + await using var conn = Create(configuration: config, shared: false, allowAdmin: true); var sub = conn.GetSubscriber(); var channel = RedisChannel.Literal(Me() + flags.ToString()); // Individual channel per case to not overlap publishers @@ -157,7 +154,7 @@ await sub.SubscribeAsync( Log("Connected to: " + initialServer); conn.AllowConnect = false; - if (Context.IsResp3) + if (TestContext.Current.IsResp3()) { subscribedServerEndpoint.SimulateConnectionFailure(SimulatedFailureType.All); // need to kill the main connection Assert.False(subscribedServerEndpoint.IsConnected, "subscribedServerEndpoint.IsConnected"); diff --git a/tests/StackExchange.Redis.Tests/PubSubTests.cs b/tests/StackExchange.Redis.Tests/PubSubTests.cs index 249b8e63d..9418fe80f 100644 --- a/tests/StackExchange.Redis.Tests/PubSubTests.cs +++ b/tests/StackExchange.Redis.Tests/PubSubTests.cs @@ -7,20 +7,16 @@ using System.Threading.Tasks; using StackExchange.Redis.Maintenance; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class PubSubTests : TestBase +public class PubSubTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public PubSubTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task ExplicitPublishMode() { - using var conn = Create(channelPrefix: "foo:", log: Writer); + await using var conn = Create(channelPrefix: "foo:", log: Writer); var pub = conn.GetSubscriber(); int a = 0, b = 0, c = 0, d = 0; @@ -58,12 +54,12 @@ await UntilConditionAsync( [InlineData("Foo:", true, "f")] public async Task TestBasicPubSub(string? channelPrefix, bool wildCard, string breaker) { - using var conn = Create(channelPrefix: channelPrefix, shared: false, log: Writer); + await using var conn = Create(channelPrefix: channelPrefix, shared: false, log: Writer); var pub = GetAnyPrimary(conn); var sub = conn.GetSubscriber(); await PingAsync(pub, sub).ForAwait(); - HashSet received = new(); + HashSet received = []; int secondHandler = 0; string subChannel = (wildCard ? "a*c" : "abc") + breaker; string pubChannel = "abc" + breaker; @@ -143,14 +139,14 @@ public async Task TestBasicPubSub(string? channelPrefix, bool wildCard, string b [Fact] public async Task TestBasicPubSubFireAndForget() { - using var conn = Create(shared: false, log: Writer); + await using var conn = Create(shared: false, log: Writer); var profiler = conn.AddProfiler(); var pub = GetAnyPrimary(conn); var sub = conn.GetSubscriber(); RedisChannel key = RedisChannel.Literal(Me() + Guid.NewGuid()); - HashSet received = new(); + HashSet received = []; int secondHandler = 0; await PingAsync(pub, sub).ForAwait(); sub.Subscribe( @@ -218,12 +214,12 @@ private async Task PingAsync(IServer pub, ISubscriber sub, int times = 1) [Fact] public async Task TestPatternPubSub() { - using var conn = Create(shared: false, log: Writer); + await using var conn = Create(shared: false, log: Writer); var pub = GetAnyPrimary(conn); var sub = conn.GetSubscriber(); - HashSet received = new(); + HashSet received = []; int secondHandler = 0; #pragma warning disable CS0618 sub.Subscribe("a*c", (channel, payload) => @@ -275,9 +271,9 @@ public async Task TestPatternPubSub() } [Fact] - public void TestPublishWithNoSubscribers() + public async Task TestPublishWithNoSubscribers() { - using var conn = Create(); + await using var conn = Create(); var sub = conn.GetSubscriber(); #pragma warning disable CS0618 @@ -285,19 +281,21 @@ public void TestPublishWithNoSubscribers() #pragma warning restore CS0618 } - [FactLongRunning] - public void TestMassivePublishWithWithoutFlush_Local() + [Fact] + public async Task TestMassivePublishWithWithoutFlush_Local() { - using var conn = Create(); + Skip.UnlessLongRunning(); + await using var conn = Create(); var sub = conn.GetSubscriber(); TestMassivePublish(sub, Me(), "local"); } - [FactLongRunning] - public void TestMassivePublishWithWithoutFlush_Remote() + [Fact] + public async Task TestMassivePublishWithWithoutFlush_Remote() { - using var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort); + Skip.UnlessLongRunning(); + await using var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort); var sub = conn.GetSubscriber(); TestMassivePublish(sub, Me(), "remote"); @@ -337,7 +335,7 @@ private void TestMassivePublish(ISubscriber sub, string channel, string caption) [Fact] public async Task SubscribeAsyncEnumerable() { - using var conn = Create(syncTimeout: 20000, shared: false, log: Writer); + await using var conn = Create(syncTimeout: 20000, shared: false, log: Writer); var sub = conn.GetSubscriber(); RedisChannel channel = RedisChannel.Literal(Me()); @@ -372,9 +370,9 @@ public async Task SubscribeAsyncEnumerable() [Fact] public async Task PubSubGetAllAnyOrder() { - using var sonn = Create(syncTimeout: 20000, shared: false, log: Writer); + await using var conn = Create(syncTimeout: 20000, shared: false, log: Writer); - var sub = sonn.GetSubscriber(); + var sub = conn.GetSubscriber(); RedisChannel channel = RedisChannel.Literal(Me()); const int count = 1000; var syncLock = new object(); @@ -420,7 +418,7 @@ await sub.SubscribeAsync(channel, (_, val) => [Fact] public async Task PubSubGetAllCorrectOrder() { - using (var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort, syncTimeout: 20000, log: Writer)) + await using (var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort, syncTimeout: 20000, log: Writer)) { var sub = conn.GetSubscriber(); RedisChannel channel = RedisChannel.Literal(Me()); @@ -490,7 +488,7 @@ async Task RunLoop() [Fact] public async Task PubSubGetAllCorrectOrder_OnMessage_Sync() { - using (var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort, syncTimeout: 20000, log: Writer)) + await using (var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort, syncTimeout: 20000, log: Writer)) { var sub = conn.GetSubscriber(); RedisChannel channel = RedisChannel.Literal(Me()); @@ -556,7 +554,7 @@ public async Task PubSubGetAllCorrectOrder_OnMessage_Sync() [Fact] public async Task PubSubGetAllCorrectOrder_OnMessage_Async() { - using (var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort, syncTimeout: 20000, log: Writer)) + await using (var conn = Create(configuration: TestConfig.Current.RemoteServerAndPort, syncTimeout: 20000, log: Writer)) { var sub = conn.GetSubscriber(); RedisChannel channel = RedisChannel.Literal(Me()); @@ -627,9 +625,9 @@ public async Task PubSubGetAllCorrectOrder_OnMessage_Async() [Fact] public async Task TestPublishWithSubscribers() { - using var connA = Create(shared: false, log: Writer); - using var connB = Create(shared: false, log: Writer); - using var connPub = Create(); + await using var connA = Create(shared: false, log: Writer); + await using var connB = Create(shared: false, log: Writer); + await using var connPub = Create(); var channel = Me(); var listenA = connA.GetSubscriber(); @@ -654,14 +652,14 @@ public async Task TestPublishWithSubscribers() [Fact] public async Task TestMultipleSubscribersGetMessage() { - using var connA = Create(shared: false, log: Writer); - using var connB = Create(shared: false, log: Writer); - using var connPub = Create(); + await using var connA = Create(shared: false, log: Writer); + await using var connB = Create(shared: false, log: Writer); + await using var connPub = Create(); var channel = RedisChannel.Literal(Me()); var listenA = connA.GetSubscriber(); var listenB = connB.GetSubscriber(); - connPub.GetDatabase().Ping(); + await connPub.GetDatabase().PingAsync(); var pub = connPub.GetSubscriber(); int gotA = 0, gotB = 0; var tA = listenA.SubscribeAsync(channel, (_, msg) => { if (msg == "message") Interlocked.Increment(ref gotA); }); @@ -684,7 +682,7 @@ public async Task TestMultipleSubscribersGetMessage() [Fact] public async Task Issue38() { - using var conn = Create(log: Writer); + await using var conn = Create(log: Writer); var sub = conn.GetSubscriber(); int count = 0; @@ -719,9 +717,9 @@ public async Task Issue38() [Fact] public async Task TestPartialSubscriberGetMessage() { - using var connA = Create(); - using var connB = Create(); - using var connPub = Create(); + await using var connA = Create(); + await using var connB = Create(); + await using var connPub = Create(); int gotA = 0, gotB = 0; var listenA = connA.GetSubscriber(); @@ -752,8 +750,8 @@ public async Task TestPartialSubscriberGetMessage() [Fact] public async Task TestSubscribeUnsubscribeAndSubscribeAgain() { - using var connPub = Create(); - using var connSub = Create(); + await using var connPub = Create(); + await using var connSub = Create(); var prefix = Me(); var pub = connPub.GetSubscriber(); @@ -799,7 +797,7 @@ public async Task AzureRedisEventsAutomaticSubscribe() using (var connection = await ConnectionMultiplexer.ConnectAsync(options)) { - connection.ServerMaintenanceEvent += (object? _, ServerMaintenanceEvent e) => + connection.ServerMaintenanceEvent += (_, e) => { if (e is AzureMaintenanceEvent) { diff --git a/tests/StackExchange.Redis.Tests/RealWorldTests.cs b/tests/StackExchange.Redis.Tests/RealWorldTests.cs index 340303f22..ba9605b4f 100644 --- a/tests/StackExchange.Redis.Tests/RealWorldTests.cs +++ b/tests/StackExchange.Redis.Tests/RealWorldTests.cs @@ -1,13 +1,10 @@ using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class RealWorldTests : TestBase +public class RealWorldTests(ITestOutputHelper output) : TestBase(output) { - public RealWorldTests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task WhyDoesThisNotWork() { @@ -17,7 +14,7 @@ public async Task WhyDoesThisNotWork() Log("Endpoint 0: {0} (AddressFamily: {1})", config.EndPoints[0], config.EndPoints[0].AddressFamily); Log("Endpoint 1: {0} (AddressFamily: {1})", config.EndPoints[1], config.EndPoints[1].AddressFamily); - using (var conn = ConnectionMultiplexer.Connect("localhost:6379,localhost:6380,name=Core (Q&A),tiebreaker=:RedisPrimary,abortConnect=False", Writer)) + await using (var conn = ConnectionMultiplexer.Connect("localhost:6379,localhost:6380,name=Core (Q&A),tiebreaker=:RedisPrimary,abortConnect=False", Writer)) { Log(""); Log("pausing..."); diff --git a/tests/StackExchange.Redis.Tests/RedisResultTests.cs b/tests/StackExchange.Redis.Tests/RedisResultTests.cs index 47ac20a9e..1f58ceecf 100644 --- a/tests/StackExchange.Redis.Tests/RedisResultTests.cs +++ b/tests/StackExchange.Redis.Tests/RedisResultTests.cs @@ -16,7 +16,7 @@ public sealed class RedisResultTests public void ToDictionaryWorks() { var redisArrayResult = RedisResult.Create( - new RedisValue[] { "one", 1, "two", 2, "three", 3, "four", 4 }); + ["one", 1, "two", 2, "three", 3, "four", 4]); var dict = redisArrayResult.ToDictionary(); @@ -35,14 +35,13 @@ public void ToDictionaryWorks() public void ToDictionaryWorksWhenNested() { var redisArrayResult = RedisResult.Create( - new[] - { + [ RedisResult.Create((RedisValue)"one"), - RedisResult.Create(new RedisValue[] { "two", 2, "three", 3 }), + RedisResult.Create(["two", 2, "three", 3]), RedisResult.Create((RedisValue)"four"), - RedisResult.Create(new RedisValue[] { "five", 5, "six", 6 }), - }); + RedisResult.Create(["five", 5, "six", 6]), + ]); var dict = redisArrayResult.ToDictionary(); var nestedDict = dict["one"].ToDictionary(); @@ -61,7 +60,7 @@ public void ToDictionaryWorksWhenNested() public void ToDictionaryFailsWithDuplicateKeys() { var redisArrayResult = RedisResult.Create( - new RedisValue[] { "banana", 1, "BANANA", 2, "orange", 3, "apple", 4 }); + ["banana", 1, "BANANA", 2, "orange", 3, "apple", 4]); Assert.Throws(() => redisArrayResult.ToDictionary(/* Use default comparer, causes collision of banana */)); } @@ -73,7 +72,7 @@ public void ToDictionaryFailsWithDuplicateKeys() public void ToDictionaryWorksWithCustomComparator() { var redisArrayResult = RedisResult.Create( - new RedisValue[] { "banana", 1, "BANANA", 2, "orange", 3, "apple", 4 }); + ["banana", 1, "BANANA", 2, "orange", 3, "apple", 4]); var dict = redisArrayResult.ToDictionary(StringComparer.Ordinal); @@ -90,7 +89,7 @@ public void ToDictionaryWorksWithCustomComparator() public void ToDictionaryFailsOnMishapenResults() { var redisArrayResult = RedisResult.Create( - new RedisValue[] { "one", 1, "two", 2, "three", 3, "four" /* missing 4 */ }); + ["one", 1, "two", 2, "three", 3, "four" /* missing 4 */]); Assert.Throws(() => redisArrayResult.ToDictionary(StringComparer.Ordinal)); } diff --git a/tests/StackExchange.Redis.Tests/TestConfig.json b/tests/StackExchange.Redis.Tests/RedisTestConfig.json similarity index 100% rename from tests/StackExchange.Redis.Tests/TestConfig.json rename to tests/StackExchange.Redis.Tests/RedisTestConfig.json diff --git a/tests/StackExchange.Redis.Tests/RespProtocolTests.cs b/tests/StackExchange.Redis.Tests/RespProtocolTests.cs index 44932cf96..08e31b699 100644 --- a/tests/StackExchange.Redis.Tests/RespProtocolTests.cs +++ b/tests/StackExchange.Redis.Tests/RespProtocolTests.cs @@ -3,20 +3,16 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public sealed class RespProtocolTests : TestBase +public sealed class RespProtocolTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public RespProtocolTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] [RunPerProtocol] public async Task ConnectWithTiming() { - using var conn = Create(shared: false, log: Writer); + await using var conn = Create(shared: false, log: Writer); await conn.GetDatabase().PingAsync(); } @@ -81,11 +77,11 @@ public async Task TryConnect() await muxer.GetDatabase().PingAsync(); var server = muxer.GetServerEndPoint(muxer.GetEndPoints().Single()); - if (Context.IsResp3 && !server.GetFeatures().Resp3) + if (TestContext.Current.IsResp3() && !server.GetFeatures().Resp3) { - Skip.Inconclusive("server does not support RESP3"); + Assert.Skip("server does not support RESP3"); } - if (Context.IsResp3) + if (TestContext.Current.IsResp3()) { Assert.Equal(RedisProtocol.Resp3, server.Protocol); } @@ -114,7 +110,7 @@ public async Task ConnectWithBrokenHello(string command, bool isResp3) config.Protocol = RedisProtocol.Resp3; config.CommandMap = CommandMap.Create(new() { ["hello"] = command }); - using var muxer = await ConnectionMultiplexer.ConnectAsync(config, Writer); + await using var muxer = await ConnectionMultiplexer.ConnectAsync(config, Writer); await muxer.GetDatabase().PingAsync(); // is connected var ep = muxer.GetServerEndPoint(muxer.GetEndPoints()[0]); if (!ep.GetFeatures().Resp3) // this is just a v6 check @@ -131,8 +127,8 @@ public async Task ConnectWithBrokenHello(string command, bool isResp3) [InlineData("return 'abc'", RedisProtocol.Resp2, ResultType.BulkString, ResultType.BulkString, "abc")] [InlineData(@"return {1,2,3}", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, ARR_123)] [InlineData("return nil", RedisProtocol.Resp2, ResultType.BulkString, ResultType.Null, null)] - [InlineData(@"return redis.pcall('hgetall', 'key')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] - [InlineData(@"redis.setresp(3) return redis.pcall('hgetall', 'key')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] + [InlineData(@"return redis.pcall('hgetall', '{key}')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] + [InlineData(@"redis.setresp(3) return redis.pcall('hgetall', '{key}')", RedisProtocol.Resp2, ResultType.Array, ResultType.Array, MAP_ABC)] [InlineData("return true", RedisProtocol.Resp2, ResultType.Integer, ResultType.Integer, 1)] [InlineData("return false", RedisProtocol.Resp2, ResultType.BulkString, ResultType.Null, null)] [InlineData("redis.setresp(3) return true", RedisProtocol.Resp2, ResultType.Integer, ResultType.Integer, 1)] @@ -146,8 +142,8 @@ public async Task ConnectWithBrokenHello(string command, bool isResp3) [InlineData("return 'abc'", RedisProtocol.Resp3, ResultType.BulkString, ResultType.BulkString, "abc")] [InlineData("return {1,2,3}", RedisProtocol.Resp3, ResultType.Array, ResultType.Array, ARR_123)] [InlineData("return nil", RedisProtocol.Resp3, ResultType.BulkString, ResultType.Null, null)] - [InlineData(@"return redis.pcall('hgetall', 'key')", RedisProtocol.Resp3, ResultType.Array, ResultType.Array, MAP_ABC)] - [InlineData(@"redis.setresp(3) return redis.pcall('hgetall', 'key')", RedisProtocol.Resp3, ResultType.Array, ResultType.Map, MAP_ABC)] + [InlineData(@"return redis.pcall('hgetall', '{key}')", RedisProtocol.Resp3, ResultType.Array, ResultType.Array, MAP_ABC)] + [InlineData(@"redis.setresp(3) return redis.pcall('hgetall', '{key}')", RedisProtocol.Resp3, ResultType.Array, ResultType.Map, MAP_ABC)] [InlineData("return true", RedisProtocol.Resp3, ResultType.Integer, ResultType.Integer, 1)] [InlineData("return false", RedisProtocol.Resp3, ResultType.BulkString, ResultType.Null, null)] [InlineData("redis.setresp(3) return true", RedisProtocol.Resp3, ResultType.Integer, ResultType.Boolean, true)] @@ -163,22 +159,24 @@ public async Task CheckLuaResult(string script, RedisProtocol protocol, ResultTy var ep = muxer.GetServerEndPoint(muxer.GetEndPoints().Single()); if (serverMin > ep.Version.Major) { - Skip.Inconclusive($"applies to v{serverMin} onwards - detected v{ep.Version.Major}"); + Assert.Skip($"applies to v{serverMin} onwards - detected v{ep.Version.Major}"); } if (script.Contains("redis.setresp(3)") && !ep.GetFeatures().Resp3) /* v6 check */ { - Skip.Inconclusive("debug protocol not available"); + Assert.Skip("debug protocol not available"); } if (ep.Protocol is null) throw new InvalidOperationException($"No protocol! {ep.InteractiveConnectionState}"); Assert.Equal(protocol, ep.Protocol); + var key = Me(); + script = script.Replace("{key}", key); var db = muxer.GetDatabase(); if (expected is MAP_ABC) { - db.KeyDelete("key"); - db.HashSet("key", "a", 1); - db.HashSet("key", "b", 2); - db.HashSet("key", "c", 3); + db.KeyDelete(key); + db.HashSet(key, "a", 1); + db.HashSet(key, "b", 2); + db.HashSet(key, "c", 3); } var result = await db.ScriptEvaluateAsync(script: script, flags: CommandFlags.NoScriptCache); Assert.Equal(resp2, result.Resp2Type); @@ -319,7 +317,7 @@ public async Task CheckCommandResult(string command, RedisProtocol protocol, Res var ep = muxer.GetServerEndPoint(muxer.GetEndPoints().Single()); if (command == "debug" && args.Length > 0 && args[0] is "protocol" && !ep.GetFeatures().Resp3 /* v6 check */) { - Skip.Inconclusive("debug protocol not available"); + Assert.Skip("debug protocol not available"); } Assert.Equal(protocol, ep.Protocol); @@ -333,10 +331,10 @@ public async Task CheckCommandResult(string command, RedisProtocol protocol, Res await db.StringSetAsync("ikey", "40"); break; case "skey": - await db.SetAddAsync("skey", new RedisValue[] { "a", "b", "c" }); + await db.SetAddAsync("skey", ["a", "b", "c"]); break; case "hkey": - await db.HashSetAsync("hkey", new HashEntry[] { new("a", 1), new("b", 2), new("c", 3) }); + await db.HashSetAsync("hkey", [new("a", 1), new("b", 2), new("c", 3)]); break; } } diff --git a/tests/StackExchange.Redis.Tests/RoleTests.cs b/tests/StackExchange.Redis.Tests/RoleTests.cs index 396877283..198ae6da7 100644 --- a/tests/StackExchange.Redis.Tests/RoleTests.cs +++ b/tests/StackExchange.Redis.Tests/RoleTests.cs @@ -1,22 +1,19 @@ using System.Linq; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class Roles : TestBase +public class Roles(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public Roles(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort + "," + TestConfig.Current.ReplicaServerAndPort; [Theory] [InlineData(true)] [InlineData(false)] - public void PrimaryRole(bool allowAdmin) // should work with or without admin now + public async Task PrimaryRole(bool allowAdmin) // should work with or without admin now { - using var conn = Create(allowAdmin: allowAdmin); + await using var conn = Create(allowAdmin: allowAdmin); var servers = conn.GetServers(); Log("Server list:"); foreach (var s in servers) @@ -69,9 +66,9 @@ public void PrimaryRole(bool allowAdmin) // should work with or without admin no } [Fact] - public void ReplicaRole() + public async Task ReplicaRole() { - using var conn = ConnectionMultiplexer.Connect($"{TestConfig.Current.ReplicaServerAndPort},allowAdmin=true"); + await using var conn = await ConnectionMultiplexer.ConnectAsync($"{TestConfig.Current.ReplicaServerAndPort},allowAdmin=true"); var server = conn.GetServers().First(conn => conn.IsReplica); var role = server.Role(); diff --git a/tests/StackExchange.Redis.Tests/SSDBTests.cs b/tests/StackExchange.Redis.Tests/SSDBTests.cs index b05a781b2..a1f2f3d5e 100644 --- a/tests/StackExchange.Redis.Tests/SSDBTests.cs +++ b/tests/StackExchange.Redis.Tests/SSDBTests.cs @@ -1,18 +1,16 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; -public class SSDBTests : TestBase +public class SSDBTests(ITestOutputHelper output) : TestBase(output) { - public SSDBTests(ITestOutputHelper output) : base(output) { } - [Fact] - public void ConnectToSSDB() + public async Task ConnectToSSDB() { Skip.IfNoConfig(nameof(TestConfig.Config.SSDBServer), TestConfig.Current.SSDBServer); - using var conn = ConnectionMultiplexer.Connect(new ConfigurationOptions + await using var conn = await ConnectionMultiplexer.ConnectAsync(new ConfigurationOptions { EndPoints = { { TestConfig.Current.SSDBServer, TestConfig.Current.SSDBPort } }, CommandMap = CommandMap.SSDB, diff --git a/tests/StackExchange.Redis.Tests/SSLTests.cs b/tests/StackExchange.Redis.Tests/SSLTests.cs index 5b11f68c8..0dafe3f9b 100644 --- a/tests/StackExchange.Redis.Tests/SSLTests.cs +++ b/tests/StackExchange.Redis.Tests/SSLTests.cs @@ -7,28 +7,23 @@ using System.Net; using System.Net.Security; using System.Reflection; -using System.Runtime.InteropServices; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; -using NSubstitute.Exceptions; using StackExchange.Redis.Tests.Helpers; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class SSLTests : TestBase, IClassFixture +public class SSLTests(ITestOutputHelper output, SSLTests.SSLServerFixture fixture) : TestBase(output), IClassFixture { - private SSLServerFixture Fixture { get; } - - public SSLTests(ITestOutputHelper output, SSLServerFixture fixture) : base(output) => Fixture = fixture; + private SSLServerFixture Fixture { get; } = fixture; [Theory] // (note the 6379 port is closed) [InlineData(null, true)] // auto-infer port (but specify 6380) [InlineData(6380, true)] // all explicit - public void ConnectToAzure(int? port, bool ssl) + public async Task ConnectToAzure(int? port, bool ssl) { Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer); Skip.IfNoConfig(nameof(TestConfig.Config.AzureCachePassword), TestConfig.Current.AzureCachePassword); @@ -48,7 +43,7 @@ public void ConnectToAzure(int? port, bool ssl) Log(options.ToString()); using (var connection = ConnectionMultiplexer.Connect(options)) { - var ttl = connection.GetDatabase().Ping(); + var ttl = await connection.GetDatabase().PingAsync(); Log(ttl.ToString()); } } @@ -78,7 +73,7 @@ public async Task ConnectToSSLServer(bool useSsl, bool specifyHost) var config = new ConfigurationOptions { AllowAdmin = true, - SyncTimeout = Debugger.IsAttached ? int.MaxValue : 5000, + SyncTimeout = Debugger.IsAttached ? int.MaxValue : 2000, Password = password, }; var map = new Dictionary @@ -115,7 +110,7 @@ public async Task ConnectToSSLServer(bool useSsl, bool specifyHost) if (useSsl) { - using var conn = ConnectionMultiplexer.Connect(config, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer); Log("Connect log:"); lock (log) @@ -215,7 +210,7 @@ public async Task ConnectSslClientAuthenticationOptions(SslProtocols protocols, if (expectSuccess) { - using var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer); + await using var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer); var db = conn.GetDatabase(); Log("Pinging..."); @@ -228,19 +223,19 @@ public async Task ConnectSslClientAuthenticationOptions(SslProtocols protocols, Log("(Expected) Failure connecting: " + ex.Message); if (ex.InnerException is PlatformNotSupportedException pnse) { - Skip.Inconclusive("Expected failure, but also test not supported on this platform: " + pnse.Message); + Assert.Skip("Expected failure, but also test not supported on this platform: " + pnse.Message); } } } catch (RedisException ex) when (ex.InnerException is PlatformNotSupportedException pnse) { - Skip.Inconclusive("Test not supported on this platform: " + pnse.Message); + Assert.Skip("Test not supported on this platform: " + pnse.Message); } } #endif [Fact] - public void RedisLabsSSL() + public async Task RedisLabsSSL() { Skip.IfNoConfig(nameof(TestConfig.Config.RedisLabsSslServer), TestConfig.Current.RedisLabsSslServer); Skip.IfNoConfig(nameof(TestConfig.Config.RedisLabsPfxPath), TestConfig.Current.RedisLabsPfxPath); @@ -275,7 +270,7 @@ public void RedisLabsSSL() options.Ssl = true; options.CertificateSelection += (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => cert; - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = ConnectionMultiplexer.Connect(options); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -286,7 +281,7 @@ public void RedisLabsSSL() s = db.StringGet(key); Assert.Equal("abc", s); - var latency = db.Ping(); + var latency = await db.PingAsync(); Log("RedisLabs latency: {0:###,##0.##}ms", latency.TotalMilliseconds); using (var file = File.Create("RedisLabs.zip")) @@ -298,7 +293,7 @@ public void RedisLabsSSL() [Theory] [InlineData(false)] [InlineData(true)] - public void RedisLabsEnvironmentVariableClientCertificate(bool setEnv) + public async Task RedisLabsEnvironmentVariableClientCertificate(bool setEnv) { try { @@ -336,7 +331,7 @@ public void RedisLabsEnvironmentVariableClientCertificate(bool setEnv) #endif options.Ssl = true; - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = ConnectionMultiplexer.Connect(options); RedisKey key = Me(); if (!setEnv) Assert.Fail("Could not set environment"); @@ -349,7 +344,7 @@ public void RedisLabsEnvironmentVariableClientCertificate(bool setEnv) s = db.StringGet(key); Assert.Equal("abc", s); - var latency = db.Ping(); + var latency = await db.PingAsync(); Log("RedisLabs latency: {0:###,##0.##}ms", latency.TotalMilliseconds); using (var file = File.Create("RedisLabs.zip")) @@ -399,6 +394,7 @@ public void Issue883_Exhaustive() var old = CultureInfo.CurrentCulture; try { + var fields = typeof(ConfigurationOptions).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); var all = CultureInfo.GetCultures(CultureTypes.AllCultures); Log($"Checking {all.Length} cultures..."); foreach (var ci in all) @@ -427,7 +423,6 @@ public void Issue883_Exhaustive() Check(nameof(c.Port), c.Port, d.Port); Check(nameof(c.AddressFamily), c.AddressFamily, d.AddressFamily); - var fields = typeof(ConfigurationOptions).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Log($"Comparing {fields.Length} fields..."); Array.Sort(fields, (x, y) => string.CompareOrdinal(x.Name, y.Name)); foreach (var field in fields) @@ -443,7 +438,7 @@ public void Issue883_Exhaustive() } [Fact] - public void SSLParseViaConfig_Issue883_ConfigObject() + public async Task SSLParseViaConfig_Issue883_ConfigObject() { Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer); Skip.IfNoConfig(nameof(TestConfig.Config.AzureCachePassword), TestConfig.Current.AzureCachePassword); @@ -461,9 +456,9 @@ public void SSLParseViaConfig_Issue883_ConfigObject() }; options.CertificateValidation += ShowCertFailures(Writer); - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = ConnectionMultiplexer.Connect(options); - conn.GetDatabase().Ping(); + await conn.GetDatabase().PingAsync(); } public static RemoteCertificateValidationCallback? ShowCertFailures(TextWriterOutputHelper output) @@ -514,7 +509,7 @@ void WriteStatus(X509ChainStatus[] status) } [Fact] - public void SSLParseViaConfig_Issue883_ConfigString() + public async Task SSLParseViaConfig_Issue883_ConfigString() { Skip.IfNoConfig(nameof(TestConfig.Config.AzureCacheServer), TestConfig.Current.AzureCacheServer); Skip.IfNoConfig(nameof(TestConfig.Config.AzureCachePassword), TestConfig.Current.AzureCachePassword); @@ -523,9 +518,9 @@ public void SSLParseViaConfig_Issue883_ConfigString() var options = ConfigurationOptions.Parse(configString); options.CertificateValidation += ShowCertFailures(Writer); - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = ConnectionMultiplexer.Connect(options); - conn.GetDatabase().Ping(); + await conn.GetDatabase().PingAsync(); } [Fact] @@ -563,7 +558,7 @@ public void SkipIfNoServer() Skip.IfNoConfig(nameof(TestConfig.Config.SslServer), TestConfig.Current.SslServer); if (!ServerRunning) { - Skip.Inconclusive($"SSL/TLS Server was not running at {TestConfig.Current.SslServer}:{TestConfig.Current.SslPort}"); + Assert.Skip($"SSL/TLS Server was not running at {TestConfig.Current.SslServer}:{TestConfig.Current.SslPort}"); } } diff --git a/tests/StackExchange.Redis.Tests/ScanTests.cs b/tests/StackExchange.Redis.Tests/ScanTests.cs index a95435e4d..fe03cbf86 100644 --- a/tests/StackExchange.Redis.Tests/ScanTests.cs +++ b/tests/StackExchange.Redis.Tests/ScanTests.cs @@ -1,30 +1,27 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class ScanTests : TestBase +public class ScanTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ScanTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Theory] [InlineData(true)] [InlineData(false)] - public void KeysScan(bool supported) + public async Task KeysScan(bool supported) { - string[]? disabledCommands = supported ? null : new[] { "scan" }; - using var conn = Create(disabledCommands: disabledCommands, allowAdmin: true); + string[]? disabledCommands = supported ? null : ["scan"]; + await using var conn = Create(disabledCommands: disabledCommands, allowAdmin: true); var dbId = TestConfig.GetDedicatedDB(conn); var db = conn.GetDatabase(dbId); var prefix = Me() + ":"; var server = GetServer(conn); - Assert.Equal(Context.Test.Protocol, server.Protocol); + Assert.Equal(TestContext.Current.GetProtocol(), server.Protocol); server.FlushDatabase(dbId); for (int i = 0; i < 100; i++) { @@ -52,9 +49,9 @@ public void KeysScan(bool supported) } [Fact] - public void ScansIScanning() + public async Task ScansIScanning() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var prefix = Me() + Guid.NewGuid(); var dbId = TestConfig.GetDedicatedDB(conn); @@ -99,9 +96,9 @@ public void ScansIScanning() } [Fact] - public void ScanResume() + public async Task ScanResume() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_8_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_8_0); var dbId = TestConfig.GetDedicatedDB(conn); var db = conn.GetDatabase(dbId); @@ -184,11 +181,11 @@ public void ScanResume() [Theory] [InlineData(true)] [InlineData(false)] - public void SetScan(bool supported) + public async Task SetScan(bool supported) { - string[]? disabledCommands = supported ? null : new[] { "sscan" }; + string[]? disabledCommands = supported ? null : ["sscan"]; - using var conn = Create(disabledCommands: disabledCommands); + await using var conn = Create(disabledCommands: disabledCommands); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -207,11 +204,11 @@ public void SetScan(bool supported) [Theory] [InlineData(true)] [InlineData(false)] - public void SortedSetScan(bool supported) + public async Task SortedSetScan(bool supported) { - string[]? disabledCommands = supported ? null : new[] { "zscan" }; + string[]? disabledCommands = supported ? null : ["zscan"]; - using var conn = Create(disabledCommands: disabledCommands); + await using var conn = Create(disabledCommands: disabledCommands); RedisKey key = Me() + supported; var db = conn.GetDatabase(); @@ -275,11 +272,11 @@ public void SortedSetScan(bool supported) [Theory] [InlineData(true)] [InlineData(false)] - public void HashScan(bool supported) + public async Task HashScan(bool supported) { - string[]? disabledCommands = supported ? null : new[] { "hscan" }; + string[]? disabledCommands = supported ? null : ["hscan"]; - using var conn = Create(disabledCommands: disabledCommands); + await using var conn = Create(disabledCommands: disabledCommands); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -317,9 +314,9 @@ public void HashScan(bool supported) [InlineData(100)] [InlineData(1000)] [InlineData(10000)] - public void HashScanLarge(int pageSize) + public async Task HashScanLarge(int pageSize) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me() + pageSize; var db = conn.GetDatabase(); @@ -335,11 +332,11 @@ public void HashScanLarge(int pageSize) [Theory] [InlineData(true)] [InlineData(false)] - public void HashScanNoValues(bool supported) + public async Task HashScanNoValues(bool supported) { - string[]? disabledCommands = supported ? null : new[] { "hscan" }; + string[]? disabledCommands = supported ? null : ["hscan"]; - using var conn = Create(require: RedisFeatures.v7_4_0_rc1, disabledCommands: disabledCommands); + await using var conn = Create(require: RedisFeatures.v7_4_0_rc1, disabledCommands: disabledCommands); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -367,9 +364,9 @@ public void HashScanNoValues(bool supported) [InlineData(100)] [InlineData(1000)] [InlineData(10000)] - public void HashScanNoValuesLarge(int pageSize) + public async Task HashScanNoValuesLarge(int pageSize) { - using var conn = Create(require: RedisFeatures.v7_4_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_4_0_rc1); RedisKey key = Me() + pageSize; var db = conn.GetDatabase(); @@ -388,9 +385,9 @@ public void HashScanNoValuesLarge(int pageSize) /// See . /// [Fact] - public void HashScanThresholds() + public async Task HashScanThresholds() { - using var conn = Create(allowAdmin: true); + await using var conn = Create(allowAdmin: true); var config = conn.GetServer(conn.GetEndPoints(true)[0]).ConfigGet("hash-max-ziplist-entries").First(); var threshold = int.Parse(config.Value); @@ -430,9 +427,9 @@ private static bool GotCursors(IConnectionMultiplexer conn, RedisKey key, int co [InlineData(100)] [InlineData(1000)] [InlineData(10000)] - public void SetScanLarge(int pageSize) + public async Task SetScanLarge(int pageSize) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me() + pageSize; var db = conn.GetDatabase(); @@ -450,9 +447,9 @@ public void SetScanLarge(int pageSize) [InlineData(100)] [InlineData(1000)] [InlineData(10000)] - public void SortedSetScanLarge(int pageSize) + public async Task SortedSetScanLarge(int pageSize) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me() + pageSize; var db = conn.GetDatabase(); diff --git a/tests/StackExchange.Redis.Tests/ScriptingTests.cs b/tests/StackExchange.Redis.Tests/ScriptingTests.cs index f6de8044a..15ea6adb1 100644 --- a/tests/StackExchange.Redis.Tests/ScriptingTests.cs +++ b/tests/StackExchange.Redis.Tests/ScriptingTests.cs @@ -1,4 +1,5 @@ -using System; +#if NET // Since we're flushing and reloading scripts, only run this in once suite +using System; using System.Diagnostics; using System.Linq; using System.Security.Cryptography; @@ -6,7 +7,6 @@ using System.Threading.Tasks; using StackExchange.Redis.KeyspaceIsolation; using Xunit; -using Xunit.Abstractions; // ReSharper disable UseAwaitUsing # for consistency with existing tests // ReSharper disable MethodHasAsyncOverload # grandfathered existing usage @@ -14,11 +14,8 @@ namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class ScriptingTests : TestBase +public class ScriptingTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public ScriptingTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - private IConnectionMultiplexer GetScriptConn(bool allowAdmin = false) { int syncTimeout = 5000; @@ -27,26 +24,26 @@ private IConnectionMultiplexer GetScriptConn(bool allowAdmin = false) } [Fact] - public void ClientScripting() + public async Task ClientScripting() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); _ = conn.GetDatabase().ScriptEvaluate(script: "return redis.call('info','server')", keys: null, values: null); } [Fact] public async Task BasicScripting() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); var noCache = db.ScriptEvaluateAsync( script: "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", - keys: new RedisKey[] { "key1", "key2" }, - values: new RedisValue[] { "first", "second" }); + keys: ["key1", "key2"], + values: ["first", "second"]); var cache = db.ScriptEvaluateAsync( script: "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", - keys: new RedisKey[] { "key1", "key2" }, - values: new RedisValue[] { "first", "second" }); + keys: ["key1", "key2"], + values: ["first", "second"]); var results = (string[]?)(await noCache)!; Assert.NotNull(results); Assert.Equal(4, results.Length); @@ -65,14 +62,14 @@ public async Task BasicScripting() } [Fact] - public void KeysScripting() + public async Task KeysScripting() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); var key = Me(); db.StringSet(key, "bar", flags: CommandFlags.FireAndForget); - var result = (string?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: new RedisKey[] { key }, values: null); + var result = (string?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: [key], values: null); Assert.Equal("bar", result); } @@ -85,7 +82,7 @@ public async Task TestRandomThingFromForum() return redis.call('INCRBY', KEYS[1], -tonumber(ARGV[1])); """; - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var prefix = Me(); var db = conn.GetDatabase(); @@ -93,11 +90,11 @@ public async Task TestRandomThingFromForum() db.StringSet(prefix + "B", "5", flags: CommandFlags.FireAndForget); db.StringSet(prefix + "C", "10", flags: CommandFlags.FireAndForget); - var a = db.ScriptEvaluateAsync(script: Script, keys: new RedisKey[] { prefix + "A" }, values: new RedisValue[] { 6 }).ForAwait(); - var b = db.ScriptEvaluateAsync(script: Script, keys: new RedisKey[] { prefix + "B" }, values: new RedisValue[] { 6 }).ForAwait(); - var c = db.ScriptEvaluateAsync(script: Script, keys: new RedisKey[] { prefix + "C" }, values: new RedisValue[] { 6 }).ForAwait(); + var a = db.ScriptEvaluateAsync(script: Script, keys: [prefix + "A"], values: [6]).ForAwait(); + var b = db.ScriptEvaluateAsync(script: Script, keys: [prefix + "B"], values: [6]).ForAwait(); + var c = db.ScriptEvaluateAsync(script: Script, keys: [prefix + "C"], values: [6]).ForAwait(); - var values = await db.StringGetAsync(new RedisKey[] { prefix + "A", prefix + "B", prefix + "C" }).ForAwait(); + var values = await db.StringGetAsync([prefix + "A", prefix + "B", prefix + "C"]).ForAwait(); Assert.Equal(1, (long)await a); // exit code when current val is non-positive Assert.Equal(0, (long)await b); // exit code when result would be negative @@ -110,12 +107,12 @@ public async Task TestRandomThingFromForum() [Fact] public async Task MultiIncrWithoutReplies() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); var prefix = Me(); // prime some initial values - db.KeyDelete(new RedisKey[] { prefix + "a", prefix + "b", prefix + "c" }, CommandFlags.FireAndForget); + db.KeyDelete([prefix + "a", prefix + "b", prefix + "c"], CommandFlags.FireAndForget); db.StringIncrement(prefix + "b", flags: CommandFlags.FireAndForget); db.StringIncrement(prefix + "c", flags: CommandFlags.FireAndForget); db.StringIncrement(prefix + "c", flags: CommandFlags.FireAndForget); @@ -124,7 +121,7 @@ public async Task MultiIncrWithoutReplies() // increment a & b by 1, c twice var result = db.ScriptEvaluateAsync( script: "for i,key in ipairs(KEYS) do redis.call('incr', key) end", - keys: new RedisKey[] { prefix + "a", prefix + "b", prefix + "c", prefix + "c" }, // <== aka "KEYS" in the script + keys: [prefix + "a", prefix + "b", prefix + "c", prefix + "c"], // <== aka "KEYS" in the script values: null).ForAwait(); // <== aka "ARGV" in the script // check the incremented values @@ -143,12 +140,12 @@ public async Task MultiIncrWithoutReplies() [Fact] public async Task MultiIncrByWithoutReplies() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); var prefix = Me(); // prime some initial values - db.KeyDelete(new RedisKey[] { prefix + "a", prefix + "b", prefix + "c" }, CommandFlags.FireAndForget); + db.KeyDelete([prefix + "a", prefix + "b", prefix + "c"], CommandFlags.FireAndForget); db.StringIncrement(prefix + "b", flags: CommandFlags.FireAndForget); db.StringIncrement(prefix + "c", flags: CommandFlags.FireAndForget); db.StringIncrement(prefix + "c", flags: CommandFlags.FireAndForget); @@ -157,8 +154,8 @@ public async Task MultiIncrByWithoutReplies() // increment a & b by 1, c twice var result = db.ScriptEvaluateAsync( script: "for i,key in ipairs(KEYS) do redis.call('incrby', key, ARGV[i]) end", - keys: new RedisKey[] { prefix + "a", prefix + "b", prefix + "c" }, // <== aka "KEYS" in the script - values: new RedisValue[] { 1, 1, 2 }).ForAwait(); // <== aka "ARGV" in the script + keys: [prefix + "a", prefix + "b", prefix + "c"], // <== aka "KEYS" in the script + values: [1, 1, 2]).ForAwait(); // <== aka "ARGV" in the script // check the incremented values var a = db.StringGetAsync(prefix + "a").ForAwait(); @@ -172,45 +169,45 @@ public async Task MultiIncrByWithoutReplies() } [Fact] - public void DisableStringInference() + public async Task DisableStringInference() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); var key = Me(); db.StringSet(key, "bar", flags: CommandFlags.FireAndForget); - var result = (byte[]?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: new RedisKey[] { key }); + var result = (byte[]?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: [key]); Assert.NotNull(result); Assert.Equal("bar", Encoding.UTF8.GetString(result)); } [Fact] - public void FlushDetection() + public async Task FlushDetection() { // we don't expect this to handle everything; we just expect it to be predictable - using var conn = GetScriptConn(allowAdmin: true); + await using var conn = GetScriptConn(allowAdmin: true); var db = conn.GetDatabase(); var key = Me(); db.StringSet(key, "bar", flags: CommandFlags.FireAndForget); - var result = (string?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: new RedisKey[] { key }, values: null); + var result = (string?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: [key], values: null); Assert.Equal("bar", result); // now cause all kinds of problems GetServer(conn).ScriptFlush(); // expect this one to fail just work fine (self-fix) - db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: new RedisKey[] { key }, values: null); + db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: [key], values: null); - result = (string?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: new RedisKey[] { key }, values: null); + result = (string?)db.ScriptEvaluate(script: "return redis.call('get', KEYS[1])", keys: [key], values: null); Assert.Equal("bar", result); } [Fact] - public void PrepareScript() + public async Task PrepareScript() { - string[] scripts = { "return redis.call('get', KEYS[1])", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" }; - using (var conn = GetScriptConn(allowAdmin: true)) + string[] scripts = ["return redis.call('get', KEYS[1])", "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}"]; + await using (var conn = GetScriptConn(allowAdmin: true)) { var server = GetServer(conn); server.ScriptFlush(); @@ -223,7 +220,7 @@ public void PrepareScript() server.ScriptLoad(scripts[0]); server.ScriptLoad(scripts[1]); } - using (var conn = GetScriptConn()) + await using (var conn = GetScriptConn()) { var server = GetServer(conn); @@ -242,9 +239,9 @@ public void PrepareScript() } [Fact] - public void NonAsciiScripts() + public async Task NonAsciiScripts() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); const string Evil = "return '僕'"; var db = conn.GetDatabase(); @@ -257,7 +254,7 @@ public void NonAsciiScripts() [Fact] public async Task ScriptThrowsError() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); await Assert.ThrowsAsync(async () => { var db = conn.GetDatabase(); @@ -273,9 +270,9 @@ await Assert.ThrowsAsync(async () => } [Fact] - public void ScriptThrowsErrorInsideTransaction() + public async Task ScriptThrowsErrorInsideTransaction() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var key = Me(); var db = conn.GetDatabase(); @@ -318,7 +315,7 @@ private static Task QuickWait(Task task) [Fact] public async Task ChangeDbInScript() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var key = Me(); conn.GetDatabase(1).StringSet(key, "db 1", flags: CommandFlags.FireAndForget); @@ -341,7 +338,7 @@ public async Task ChangeDbInScript() [Fact] public async Task ChangeDbInTranScript() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var key = Me(); conn.GetDatabase(1).StringSet(key, "db 1", flags: CommandFlags.FireAndForget); @@ -363,9 +360,9 @@ public async Task ChangeDbInTranScript() } [Fact] - public void TestBasicScripting() + public async Task TestBasicScripting() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); RedisValue newId = Guid.NewGuid().ToString(); RedisKey key = Me(); @@ -375,15 +372,15 @@ public void TestBasicScripting() var wasSet = (bool)db.ScriptEvaluate( script: "if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", - keys: new[] { key }, - values: new[] { newId }); + keys: [key], + values: [newId]); Assert.True(wasSet); wasSet = (bool)db.ScriptEvaluate( script: "if redis.call('hexists', KEYS[1], 'UniqueId') then return redis.call('hset', KEYS[1], 'UniqueId', ARGV[1]) else return 0 end", - keys: new[] { key }, - values: new[] { newId }); + keys: [key], + values: [newId]); Assert.False(wasSet); } @@ -392,54 +389,56 @@ public void TestBasicScripting() [InlineData(false)] public async Task CheckLoads(bool async) { - using var conn0 = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); - using var conn1 = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn0 = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn1 = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); // note that these are on different connections (so we wouldn't expect // the flush to drop the local cache - assume it is a surprise!) var server = conn0.GetServer(TestConfig.Current.PrimaryServerAndPort); var db = conn1.GetDatabase(); - const string Script = "return 1;"; + var key = Me(); + var Script = $"return '{key}';"; // start empty server.ScriptFlush(); Assert.False(server.ScriptExists(Script)); // run once, causes to be cached - Assert.True(await EvaluateScript()); + Assert.Equal(key, await EvaluateScript()); Assert.True(server.ScriptExists(Script)); // can run again - Assert.True(await EvaluateScript()); + Assert.Equal(key, await EvaluateScript()); // ditch the scripts; should no longer exist - db.Ping(); + await db.PingAsync(); server.ScriptFlush(); Assert.False(server.ScriptExists(Script)); - db.Ping(); + await db.PingAsync(); // just works; magic - Assert.True(await EvaluateScript()); + Assert.Equal(key, await EvaluateScript()); // but gets marked as unloaded, so we can use it again... - Assert.True(await EvaluateScript()); + Assert.Equal(key, await EvaluateScript()); // which will cause it to be cached Assert.True(server.ScriptExists(Script)); - async Task EvaluateScript() + async Task EvaluateScript() { return async ? - (bool)await db.ScriptEvaluateAsync(script: Script) : - (bool)db.ScriptEvaluate(script: Script); + (string?)await db.ScriptEvaluateAsync(script: Script) : + (string?)db.ScriptEvaluate(script: Script); } } [Fact] - public void CompareScriptToDirect() + public async Task CompareScriptToDirect() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + Skip.UnlessLongRunning(); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "return redis.call('incr', KEYS[1])"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -447,12 +446,12 @@ public void CompareScriptToDirect() server.ScriptLoad(Script); var db = conn.GetDatabase(); - db.Ping(); // k, we're all up to date now; clean db, minimal script cache + await db.PingAsync(); // k, we're all up to date now; clean db, minimal script cache // we're using a pipeline here, so send 1000 messages, but for timing: only care about the last const int Loop = 5000; RedisKey key = Me(); - RedisKey[] keys = new[] { key }; // script takes an array + RedisKey[] keys = [key]; // script takes an array // run via script db.KeyDelete(key, CommandFlags.FireAndForget); @@ -483,9 +482,9 @@ public void CompareScriptToDirect() } [Fact] - public void TestCallByHash() + public async Task TestCallByHash() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "return redis.call('incr', KEYS[1])"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -497,7 +496,7 @@ public void TestCallByHash() var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); - RedisKey[] keys = { key }; + RedisKey[] keys = [key]; string hexHash = string.Concat(hash.Select(x => x.ToString("X2"))); Assert.Equal("2BAB3B661081DB58BD2341920E0BA7CF5DC77B25", hexHash); @@ -510,9 +509,9 @@ public void TestCallByHash() } [Fact] - public void SimpleLuaScript() + public async Task SimpleLuaScript() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "return @ident"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -556,7 +555,7 @@ public void SimpleLuaScript() } { - var val = prepared.Evaluate(db, new { ident = new ReadOnlyMemory(new byte[] { 4, 5, 6 }) }); + var val = prepared.Evaluate(db, new { ident = new ReadOnlyMemory([4, 5, 6]) }); var valArray = (byte[]?)val; Assert.NotNull(valArray); Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual(valArray)); @@ -564,9 +563,9 @@ public void SimpleLuaScript() } [Fact] - public void SimpleRawScriptEvaluate() + public async Task SimpleRawScriptEvaluate() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "return ARGV[1]"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -576,39 +575,39 @@ public void SimpleRawScriptEvaluate() // Scopes for repeated use { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { "hello" }); + var val = db.ScriptEvaluate(script: Script, values: ["hello"]); Assert.Equal("hello", (string?)val); } { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { 123 }); + var val = db.ScriptEvaluate(script: Script, values: [123]); Assert.Equal(123, (int)val); } { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { 123L }); + var val = db.ScriptEvaluate(script: Script, values: [123L]); Assert.Equal(123L, (long)val); } { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { 1.1 }); + var val = db.ScriptEvaluate(script: Script, values: [1.1]); Assert.Equal(1.1, (double)val); } { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { true }); + var val = db.ScriptEvaluate(script: Script, values: [true]); Assert.True((bool)val); } { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { new byte[] { 4, 5, 6 } }); + var val = db.ScriptEvaluate(script: Script, values: [new byte[] { 4, 5, 6 }]); var valArray = (byte[]?)val; Assert.NotNull(valArray); Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual(valArray)); } { - var val = db.ScriptEvaluate(script: Script, values: new RedisValue[] { new ReadOnlyMemory(new byte[] { 4, 5, 6 }) }); + var val = db.ScriptEvaluate(script: Script, values: [new ReadOnlyMemory([4, 5, 6])]); var valArray = (byte[]?)val; Assert.NotNull(valArray); Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual(valArray)); @@ -616,9 +615,9 @@ public void SimpleRawScriptEvaluate() } [Fact] - public void LuaScriptWithKeys() + public async Task LuaScriptWithKeys() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -644,9 +643,9 @@ public void LuaScriptWithKeys() } [Fact] - public void NoInlineReplacement() + public async Task NoInlineReplacement() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, 'hello@example')"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -677,9 +676,9 @@ public void EscapeReplacement() } [Fact] - public void SimpleLoadedLuaScript() + public async Task SimpleLoadedLuaScript() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "return @ident"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -724,7 +723,7 @@ public void SimpleLoadedLuaScript() } { - var val = loaded.Evaluate(db, new { ident = new ReadOnlyMemory(new byte[] { 4, 5, 6 }) }); + var val = loaded.Evaluate(db, new { ident = new ReadOnlyMemory([4, 5, 6]) }); var valArray = (byte[]?)val; Assert.NotNull(valArray); Assert.True(new byte[] { 4, 5, 6 }.SequenceEqual(valArray)); @@ -732,9 +731,9 @@ public void SimpleLoadedLuaScript() } [Fact] - public void LoadedLuaScriptWithKeys() + public async Task LoadedLuaScriptWithKeys() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var server = conn.GetServer(TestConfig.Current.PrimaryServerAndPort); @@ -783,9 +782,10 @@ private static void PurgeLuaScriptOnFinalizeImpl(string script) Assert.Equal(1, LuaScript.GetCachedScriptCount()); } - [FactLongRunning] + [Fact] public void PurgeLuaScriptOnFinalize() { + Skip.UnlessLongRunning(); const string Script = "redis.call('set', @PurgeLuaScriptOnFinalizeKey, @PurgeLuaScriptOnFinalizeValue)"; LuaScript.PurgeCache(); Assert.Equal(0, LuaScript.GetCachedScriptCount()); @@ -802,9 +802,9 @@ public void PurgeLuaScriptOnFinalize() } [Fact] - public void DatabaseLuaScriptConvenienceMethods() + public async Task DatabaseLuaScriptConvenienceMethods() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var script = LuaScript.Prepare(Script); @@ -823,9 +823,9 @@ public void DatabaseLuaScriptConvenienceMethods() } [Fact] - public void ServerLuaScriptConvenienceMethods() + public async Task ServerLuaScriptConvenienceMethods() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var script = LuaScript.Prepare(Script); @@ -861,9 +861,9 @@ public void LuaScriptPrefixedKeys() } [Fact] - public void LuaScriptWithWrappedDatabase() + public async Task LuaScriptWithWrappedDatabase() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var db = conn.GetDatabase(); @@ -886,7 +886,7 @@ public void LuaScriptWithWrappedDatabase() [Fact] public async Task AsyncLuaScriptWithWrappedDatabase() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var db = conn.GetDatabase(); @@ -907,9 +907,9 @@ public async Task AsyncLuaScriptWithWrappedDatabase() } [Fact] - public void LoadedLuaScriptWithWrappedDatabase() + public async Task LoadedLuaScriptWithWrappedDatabase() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var db = conn.GetDatabase(); @@ -933,7 +933,7 @@ public void LoadedLuaScriptWithWrappedDatabase() [Fact] public async Task AsyncLoadedLuaScriptWithWrappedDatabase() { - using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); + await using var conn = Create(allowAdmin: true, require: RedisFeatures.v2_6_0); const string Script = "redis.call('set', @key, @value)"; var db = conn.GetDatabase(); @@ -955,9 +955,9 @@ public async Task AsyncLoadedLuaScriptWithWrappedDatabase() } [Fact] - public void ScriptWithKeyPrefixViaTokens() + public async Task ScriptWithKeyPrefixViaTokens() { - using var conn = Create(); + await using var conn = Create(); var p = conn.GetDatabase().WithKeyPrefix("prefix/"); @@ -977,9 +977,9 @@ public void ScriptWithKeyPrefixViaTokens() } [Fact] - public void ScriptWithKeyPrefixViaArrays() + public async Task ScriptWithKeyPrefixViaArrays() { - using var conn = Create(); + await using var conn = Create(); var p = conn.GetDatabase().WithKeyPrefix("prefix/"); @@ -990,7 +990,7 @@ public void ScriptWithKeyPrefixViaArrays() arr[3] = ARGV[2]; return arr; "; - var result = (RedisValue[]?)p.ScriptEvaluate(script: Script, keys: new RedisKey[] { "def" }, values: new RedisValue[] { "abc", 123 }); + var result = (RedisValue[]?)p.ScriptEvaluate(script: Script, keys: ["def"], values: ["abc", 123]); Assert.NotNull(result); Assert.Equal("abc", result[0]); Assert.Equal("prefix/def", result[1]); @@ -998,16 +998,16 @@ public void ScriptWithKeyPrefixViaArrays() } [Fact] - public void ScriptWithKeyPrefixCompare() + public async Task ScriptWithKeyPrefixCompare() { - using var conn = Create(); + await using var conn = Create(); var p = conn.GetDatabase().WithKeyPrefix("prefix/"); var args = new { k = (RedisKey)"key", s = "str", v = 123 }; LuaScript lua = LuaScript.Prepare("return {@k, @s, @v}"); var viaArgs = (RedisValue[]?)p.ScriptEvaluate(lua, args); - var viaArr = (RedisValue[]?)p.ScriptEvaluate(script: "return {KEYS[1], ARGV[1], ARGV[2]}", keys: new[] { args.k }, values: new RedisValue[] { args.s, args.v }); + var viaArr = (RedisValue[]?)p.ScriptEvaluate(script: "return {KEYS[1], ARGV[1], ARGV[2]}", keys: [args.k], values: [args.s, args.v]); Assert.NotNull(viaArr); Assert.NotNull(viaArgs); Assert.Equal(string.Join(",", viaArr), string.Join(",", viaArgs)); @@ -1053,14 +1053,14 @@ private static void TestNullArray(RedisResult? value) public void RedisResultUnderstandsNullValue() => TestNullValue(RedisResult.Create(RedisValue.Null, ResultType.None)); [Fact] - public void TestEvalReadonly() + public async Task TestEvalReadonly() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); string script = "return KEYS[1]"; - RedisKey[] keys = { "key1" }; - RedisValue[] values = { "first" }; + RedisKey[] keys = ["key1"]; + RedisValue[] values = ["first"]; var result = db.ScriptEvaluateReadOnly(script, keys, values); Assert.Equal("key1", result.ToString()); @@ -1069,28 +1069,30 @@ public void TestEvalReadonly() [Fact] public async Task TestEvalReadonlyAsync() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); string script = "return KEYS[1]"; - RedisKey[] keys = { "key1" }; - RedisValue[] values = { "first" }; + RedisKey[] keys = ["key1"]; + RedisValue[] values = ["first"]; var result = await db.ScriptEvaluateReadOnlyAsync(script, keys, values); Assert.Equal("key1", result.ToString()); } [Fact] - public void TestEvalShaReadOnly() + public async Task TestEvalShaReadOnly() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); - db.StringSet("foo", "bar"); - db.ScriptEvaluate(script: "return redis.call('get','foo')"); - // Create a SHA1 hash of the script: 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 - SHA1 sha1Hash = SHA1.Create(); + var key = Me(); + var script = $"return redis.call('get','{key}')"; + db.StringSet(key, "bar"); + db.ScriptEvaluate(script: script); - byte[] hash = sha1Hash.ComputeHash(Encoding.UTF8.GetBytes("return redis.call('get','foo')")); + SHA1 sha1Hash = SHA1.Create(); + byte[] hash = sha1Hash.ComputeHash(Encoding.UTF8.GetBytes(script)); + Log("Hash: " + Convert.ToBase64String(hash)); var result = db.ScriptEvaluateReadOnly(hash); Assert.Equal("bar", result.ToString()); @@ -1099,14 +1101,16 @@ public void TestEvalShaReadOnly() [Fact] public async Task TestEvalShaReadOnlyAsync() { - using var conn = GetScriptConn(); + await using var conn = GetScriptConn(); var db = conn.GetDatabase(); - db.StringSet("foo", "bar"); - db.ScriptEvaluate(script: "return redis.call('get','foo')"); - // Create a SHA1 hash of the script: 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 - SHA1 sha1Hash = SHA1.Create(); + var key = Me(); + var script = $"return redis.call('get','{key}')"; + db.StringSet(key, "bar"); + db.ScriptEvaluate(script: script); - byte[] hash = sha1Hash.ComputeHash(Encoding.UTF8.GetBytes("return redis.call('get','foo')")); + SHA1 sha1Hash = SHA1.Create(); + byte[] hash = sha1Hash.ComputeHash(Encoding.UTF8.GetBytes(script)); + Log("Hash: " + Convert.ToBase64String(hash)); var result = await db.ScriptEvaluateReadOnlyAsync(hash); Assert.Equal("bar", result.ToString()); @@ -1149,3 +1153,4 @@ private static void TestNullValue(RedisResult? value) Assert.Null((byte[]?)value); } } +#endif diff --git a/tests/StackExchange.Redis.Tests/SecureTests.cs b/tests/StackExchange.Redis.Tests/SecureTests.cs index 35e9dd580..8f90e04ba 100644 --- a/tests/StackExchange.Redis.Tests/SecureTests.cs +++ b/tests/StackExchange.Redis.Tests/SecureTests.cs @@ -1,26 +1,23 @@ using System.Diagnostics; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class SecureTests : TestBase +public class SecureTests(ITestOutputHelper output) : TestBase(output) { protected override string GetConfiguration() => TestConfig.Current.SecureServerAndPort + ",password=" + TestConfig.Current.SecurePassword + ",name=MyClient"; - public SecureTests(ITestOutputHelper output) : base(output) { } - [Fact] - public void MassiveBulkOpsFireAndForgetSecure() + public async Task MassiveBulkOpsFireAndForgetSecure() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); var watch = Stopwatch.StartNew(); @@ -47,11 +44,11 @@ public void CheckConfig() } [Fact] - public void Connect() + public async Task Connect() { - using var conn = Create(); + await using var conn = Create(); - conn.GetDatabase().Ping(); + await conn.GetDatabase().PingAsync(); } [Theory] @@ -59,7 +56,7 @@ public void Connect() [InlineData("", "NOAUTH Returned - connection has not yet authenticated")] public async Task ConnectWithWrongPassword(string password, string exepctedMessage) { - using var checkConn = Create(); + await using var checkConn = Create(); var checkServer = GetServer(checkConn); var config = ConfigurationOptions.Parse(GetConfiguration()); @@ -71,9 +68,9 @@ public async Task ConnectWithWrongPassword(string password, string exepctedMessa { SetExpectedAmbientFailureCount(-1); - using var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer).ConfigureAwait(false); + await using var conn = await ConnectionMultiplexer.ConnectAsync(config, Writer).ConfigureAwait(false); - conn.GetDatabase().Ping(); + await conn.GetDatabase().PingAsync(); }).ConfigureAwait(false); Log($"Exception ({ex.FailureType}): {ex.Message}"); Assert.Equal(ConnectionFailureType.AuthenticationFailure, ex.FailureType); diff --git a/tests/StackExchange.Redis.Tests/SentinelBase.cs b/tests/StackExchange.Redis.Tests/SentinelBase.cs index fc1a74967..826b9c613 100644 --- a/tests/StackExchange.Redis.Tests/SentinelBase.cs +++ b/tests/StackExchange.Redis.Tests/SentinelBase.cs @@ -5,7 +5,6 @@ using System.Net; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -28,9 +27,9 @@ public SentinelBase(ITestOutputHelper output) : base(output) } #nullable enable - public Task DisposeAsync() => Task.CompletedTask; + public ValueTask DisposeAsync() => default; - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { var options = ServiceOptions.Clone(); options.EndPoints.Add(TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA); @@ -43,7 +42,7 @@ public async Task InitializeAsync() await Task.Delay(100).ForAwait(); if (Conn.IsConnected) { - using var checkConn = Conn.GetSentinelMasterConnection(options, Writer); + await using var checkConn = Conn.GetSentinelMasterConnection(options, Writer); if (checkConn.IsConnected) { break; @@ -54,7 +53,7 @@ public async Task InitializeAsync() SentinelServerA = Conn.GetServer(TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA)!; SentinelServerB = Conn.GetServer(TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortB)!; SentinelServerC = Conn.GetServer(TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortC)!; - SentinelsServers = new[] { SentinelServerA, SentinelServerB, SentinelServerC }; + SentinelsServers = [SentinelServerA, SentinelServerB, SentinelServerC]; SentinelServerA.AllowReplicaWrites = true; // Wait until we are in a state of a single primary and replica @@ -99,14 +98,14 @@ protected async Task WaitForReadyAsync(EndPoint? expectedPrimary = null, bool wa throw new RedisException($"Primary was expected to be {expectedPrimary}"); Log($"Primary is {primary}"); - using var checkConn = Conn.GetSentinelMasterConnection(ServiceOptions); + await using var checkConn = Conn.GetSentinelMasterConnection(ServiceOptions); await WaitForRoleAsync(checkConn.GetServer(primary), "master", duration.Value.Subtract(sw.Elapsed)).ForAwait(); var replicas = SentinelServerA.SentinelGetReplicaAddresses(ServiceName); if (replicas?.Length > 0) { - await Task.Delay(1000).ForAwait(); + await Task.Delay(100).ForAwait(); replicas = SentinelServerA.SentinelGetReplicaAddresses(ServiceName); await WaitForRoleAsync(checkConn.GetServer(replicas[0]), "slave", duration.Value.Subtract(sw.Elapsed)).ForAwait(); } @@ -138,7 +137,7 @@ protected async Task WaitForRoleAsync(IServer server, string role, TimeSpan? dur // ignore } - await Task.Delay(500).ForAwait(); + await Task.Delay(100).ForAwait(); } throw new RedisException($"Timeout waiting for server ({server.EndPoint}) to have expected role (\"{role}\") assigned"); diff --git a/tests/StackExchange.Redis.Tests/SentinelFailoverTests.cs b/tests/StackExchange.Redis.Tests/SentinelFailoverTests.cs index 873e93d3e..358722839 100644 --- a/tests/StackExchange.Redis.Tests/SentinelFailoverTests.cs +++ b/tests/StackExchange.Redis.Tests/SentinelFailoverTests.cs @@ -3,20 +3,18 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [Collection(NonParallelCollection.Name)] -public class SentinelFailoverTests : SentinelBase +public class SentinelFailoverTests(ITestOutputHelper output) : SentinelBase(output) { - public SentinelFailoverTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] + [Fact] public async Task ManagedPrimaryConnectionEndToEndWithFailoverTest() { + Skip.UnlessLongRunning(); var connectionString = $"{TestConfig.Current.SentinelServer}:{TestConfig.Current.SentinelPortA},serviceName={ServiceOptions.ServiceName},allowAdmin=true"; - using var conn = await ConnectionMultiplexer.ConnectAsync(connectionString); + await using var conn = await ConnectionMultiplexer.ConnectAsync(connectionString); conn.ConfigurationChanged += (s, e) => Log($"Configuration changed: {e.EndPoint}"); diff --git a/tests/StackExchange.Redis.Tests/SentinelTests.cs b/tests/StackExchange.Redis.Tests/SentinelTests.cs index 3fc2afd4e..e58f530fd 100644 --- a/tests/StackExchange.Redis.Tests/SentinelTests.cs +++ b/tests/StackExchange.Redis.Tests/SentinelTests.cs @@ -4,14 +4,11 @@ using System.Net; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class SentinelTests : SentinelBase +public class SentinelTests(ITestOutputHelper output) : SentinelBase(output) { - public SentinelTests(ITestOutputHelper output) : base(output) { } - [Fact] public async Task PrimaryConnectTest() { @@ -20,7 +17,7 @@ public async Task PrimaryConnectTest() var conn = ConnectionMultiplexer.Connect(connectionString); var db = conn.GetDatabase(); - db.Ping(); + await db.PingAsync(); var endpoints = conn.GetEndPoints(); Assert.Equal(2, endpoints.Length); @@ -87,19 +84,19 @@ public async Task PrimaryConnectAsyncTest() [Fact] [RunPerProtocol] - public void SentinelConnectTest() + public async Task SentinelConnectTest() { var options = ServiceOptions.Clone(); options.EndPoints.Add(TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA); - using var conn = ConnectionMultiplexer.SentinelConnect(options); + await using var conn = ConnectionMultiplexer.SentinelConnect(options); var db = conn.GetDatabase(); - var test = db.Ping(); + var test = await db.PingAsync(); Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); } [Fact] - public void SentinelRepeatConnectTest() + public async Task SentinelRepeatConnectTest() { var options = ConfigurationOptions.Parse($"{TestConfig.Current.SentinelServer}:{TestConfig.Current.SentinelPortA}"); options.ServiceName = ServiceName; @@ -111,10 +108,10 @@ public void SentinelRepeatConnectTest() Log(" Endpoint: " + ep); } - using var conn = ConnectionMultiplexer.Connect(options); + await using var conn = await ConnectionMultiplexer.ConnectAsync(options); var db = conn.GetDatabase(); - var test = db.Ping(); + var test = await db.PingAsync(); Log("ping to 1st sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); Log("Service Name: " + options.ServiceName); @@ -123,10 +120,10 @@ public void SentinelRepeatConnectTest() Log(" Endpoint: " + ep); } - using var conn2 = ConnectionMultiplexer.Connect(options); + await using var conn2 = ConnectionMultiplexer.Connect(options); var db2 = conn2.GetDatabase(); - var test2 = db2.Ping(); + var test2 = await db2.PingAsync(); Log("ping to 2nd sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test2.TotalMilliseconds); } @@ -156,13 +153,13 @@ public void SentinelRole() } [Fact] - public void PingTest() + public async Task PingTest() { - var test = SentinelServerA.Ping(); + var test = await SentinelServerA.PingAsync(); Log("ping to sentinel {0}:{1} took {2} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortA, test.TotalMilliseconds); - test = SentinelServerB.Ping(); + test = await SentinelServerB.PingAsync(); Log("ping to sentinel {0}:{1} took {1} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortB, test.TotalMilliseconds); - test = SentinelServerC.Ping(); + test = await SentinelServerC.PingAsync(); Log("ping to sentinel {0}:{1} took {1} ms", TestConfig.Current.SentinelServer, TestConfig.Current.SentinelPortC, test.TotalMilliseconds); } @@ -267,7 +264,7 @@ public void SentinelSentinelsTest() } Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerA.EndPoint.ToString())); - Assert.True(sentinels.Length == 2); + Assert.Equal(2, sentinels.Length); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); sentinels = SentinelServerB.SentinelSentinels(ServiceName); @@ -277,14 +274,14 @@ public void SentinelSentinelsTest() actual.Add(data["ip"] + ":" + data["port"]); } - expected = new List - { + expected = + [ SentinelServerA.EndPoint.ToString(), SentinelServerC.EndPoint.ToString(), - }; + ]; Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerB.EndPoint.ToString())); - Assert.True(sentinels.Length == 2); + Assert.Equal(2, sentinels.Length); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); sentinels = SentinelServerC.SentinelSentinels(ServiceName); @@ -294,14 +291,14 @@ public void SentinelSentinelsTest() actual.Add(data["ip"] + ":" + data["port"]); } - expected = new List - { + expected = + [ SentinelServerA.EndPoint.ToString(), SentinelServerB.EndPoint.ToString(), - }; + ]; Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerC.EndPoint.ToString())); - Assert.True(sentinels.Length == 2); + Assert.Equal(2, sentinels.Length); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); } @@ -323,18 +320,18 @@ public async Task SentinelSentinelsAsyncTest() } Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerA.EndPoint.ToString())); - Assert.True(sentinels.Length == 2); + Assert.Equal(2, sentinels.Length); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); sentinels = await SentinelServerB.SentinelSentinelsAsync(ServiceName).ForAwait(); - expected = new List - { + expected = + [ SentinelServerA.EndPoint.ToString(), SentinelServerC.EndPoint.ToString(), - }; + ]; - actual = new List(); + actual = []; foreach (var kv in sentinels) { var data = kv.ToDictionary(); @@ -342,16 +339,16 @@ public async Task SentinelSentinelsAsyncTest() } Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerB.EndPoint.ToString())); - Assert.True(sentinels.Length == 2); + Assert.Equal(2, sentinels.Length); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); sentinels = await SentinelServerC.SentinelSentinelsAsync(ServiceName).ForAwait(); - expected = new List - { + expected = + [ SentinelServerA.EndPoint.ToString(), SentinelServerB.EndPoint.ToString(), - }; - actual = new List(); + ]; + actual = []; foreach (var kv in sentinels) { var data = kv.ToDictionary(); @@ -359,7 +356,7 @@ public async Task SentinelSentinelsAsyncTest() } Assert.All(expected, ep => Assert.NotEqual(ep, SentinelServerC.EndPoint.ToString())); - Assert.True(sentinels.Length == 2); + Assert.Equal(2, sentinels.Length); Assert.All(expected, ep => Assert.Contains(ep, actual, _ipComparer)); } @@ -458,7 +455,7 @@ public async Task ReadOnlyConnectionReplicasTest() var replicas = SentinelServerA.SentinelGetReplicaAddresses(ServiceName); if (replicas.Length == 0) { - Skip.Inconclusive("Sentinel race: 0 replicas to test against."); + Assert.Skip("Sentinel race: 0 replicas to test against."); } var config = new ConfigurationOptions(); diff --git a/tests/StackExchange.Redis.Tests/SetTests.cs b/tests/StackExchange.Redis.Tests/SetTests.cs index 22df40be7..9326ca7a7 100644 --- a/tests/StackExchange.Redis.Tests/SetTests.cs +++ b/tests/StackExchange.Redis.Tests/SetTests.cs @@ -2,20 +2,16 @@ using System.Linq; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class SetTests : TestBase +public class SetTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public SetTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void SetContains() + public async Task SetContains() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -30,7 +26,7 @@ public void SetContains() Assert.True(isMemeber); // Multi members - var areMemebers = db.SetContains(key, new RedisValue[] { 0, 1, 2 }); + var areMemebers = db.SetContains(key, [0, 1, 2]); Assert.Equal(3, areMemebers.Length); Assert.False(areMemebers[0]); Assert.True(areMemebers[1]); @@ -39,7 +35,7 @@ public void SetContains() db.KeyDelete(key); isMemeber = db.SetContains(key, 1); Assert.False(isMemeber); - areMemebers = db.SetContains(key, new RedisValue[] { 0, 1, 2 }); + areMemebers = db.SetContains(key, [0, 1, 2]); Assert.Equal(3, areMemebers.Length); Assert.True(areMemebers.All(i => !i)); // Check that all the elements are False } @@ -47,7 +43,7 @@ public void SetContains() [Fact] public async Task SetContainsAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -62,7 +58,7 @@ public async Task SetContainsAsync() Assert.True(isMemeber); // Multi members - var areMemebers = await db.SetContainsAsync(key, new RedisValue[] { 0, 1, 2 }); + var areMemebers = await db.SetContainsAsync(key, [0, 1, 2]); Assert.Equal(3, areMemebers.Length); Assert.False(areMemebers[0]); Assert.True(areMemebers[1]); @@ -71,67 +67,67 @@ public async Task SetContainsAsync() await db.KeyDeleteAsync(key); isMemeber = await db.SetContainsAsync(key, 1); Assert.False(isMemeber); - areMemebers = await db.SetContainsAsync(key, new RedisValue[] { 0, 1, 2 }); + areMemebers = await db.SetContainsAsync(key, [0, 1, 2]); Assert.Equal(3, areMemebers.Length); Assert.True(areMemebers.All(i => !i)); // Check that all the elements are False } [Fact] - public void SetIntersectionLength() + public async Task SetIntersectionLength() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key1 = Me() + "1"; db.KeyDelete(key1, CommandFlags.FireAndForget); - db.SetAdd(key1, new RedisValue[] { 0, 1, 2, 3, 4 }, CommandFlags.FireAndForget); + db.SetAdd(key1, [0, 1, 2, 3, 4], CommandFlags.FireAndForget); var key2 = Me() + "2"; db.KeyDelete(key2, CommandFlags.FireAndForget); - db.SetAdd(key2, new RedisValue[] { 1, 2, 3, 4, 5 }, CommandFlags.FireAndForget); + db.SetAdd(key2, [1, 2, 3, 4, 5], CommandFlags.FireAndForget); - Assert.Equal(4, db.SetIntersectionLength(new RedisKey[] { key1, key2 })); + Assert.Equal(4, db.SetIntersectionLength([key1, key2])); // with limit - Assert.Equal(3, db.SetIntersectionLength(new RedisKey[] { key1, key2 }, 3)); + Assert.Equal(3, db.SetIntersectionLength([key1, key2], 3)); // Missing keys should be 0 var key3 = Me() + "3"; var key4 = Me() + "4"; db.KeyDelete(key3, CommandFlags.FireAndForget); - Assert.Equal(0, db.SetIntersectionLength(new RedisKey[] { key1, key3 })); - Assert.Equal(0, db.SetIntersectionLength(new RedisKey[] { key3, key4 })); + Assert.Equal(0, db.SetIntersectionLength([key1, key3])); + Assert.Equal(0, db.SetIntersectionLength([key3, key4])); } [Fact] public async Task SetIntersectionLengthAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key1 = Me() + "1"; db.KeyDelete(key1, CommandFlags.FireAndForget); - db.SetAdd(key1, new RedisValue[] { 0, 1, 2, 3, 4 }, CommandFlags.FireAndForget); + db.SetAdd(key1, [0, 1, 2, 3, 4], CommandFlags.FireAndForget); var key2 = Me() + "2"; db.KeyDelete(key2, CommandFlags.FireAndForget); - db.SetAdd(key2, new RedisValue[] { 1, 2, 3, 4, 5 }, CommandFlags.FireAndForget); + db.SetAdd(key2, [1, 2, 3, 4, 5], CommandFlags.FireAndForget); - Assert.Equal(4, await db.SetIntersectionLengthAsync(new RedisKey[] { key1, key2 })); + Assert.Equal(4, await db.SetIntersectionLengthAsync([key1, key2])); // with limit - Assert.Equal(3, await db.SetIntersectionLengthAsync(new RedisKey[] { key1, key2 }, 3)); + Assert.Equal(3, await db.SetIntersectionLengthAsync([key1, key2], 3)); // Missing keys should be 0 var key3 = Me() + "3"; var key4 = Me() + "4"; db.KeyDelete(key3, CommandFlags.FireAndForget); - Assert.Equal(0, await db.SetIntersectionLengthAsync(new RedisKey[] { key1, key3 })); - Assert.Equal(0, await db.SetIntersectionLengthAsync(new RedisKey[] { key3, key4 })); + Assert.Equal(0, await db.SetIntersectionLengthAsync([key1, key3])); + Assert.Equal(0, await db.SetIntersectionLengthAsync([key3, key4])); } [Fact] - public void SScan() + public async Task SScan() { - using var conn = Create(); + await using var conn = Create(); var server = GetAnyPrimary(conn); @@ -157,7 +153,7 @@ public void SScan() [Fact] public async Task SetRemoveArgTests() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -166,15 +162,15 @@ public async Task SetRemoveArgTests() Assert.Throws(() => db.SetRemove(key, values!)); await Assert.ThrowsAsync(async () => await db.SetRemoveAsync(key, values!).ForAwait()).ForAwait(); - values = Array.Empty(); + values = []; Assert.Equal(0, db.SetRemove(key, values)); Assert.Equal(0, await db.SetRemoveAsync(key, values).ForAwait()); } [Fact] - public void SetPopMulti_Multi() + public async Task SetPopMulti_Multi() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -182,7 +178,7 @@ public void SetPopMulti_Multi() db.KeyDelete(key, CommandFlags.FireAndForget); for (int i = 1; i < 11; i++) { - db.SetAddAsync(key, i, CommandFlags.FireAndForget); + _ = db.SetAddAsync(key, i, CommandFlags.FireAndForget); } var random = db.SetPop(key); @@ -198,9 +194,9 @@ public void SetPopMulti_Multi() } [Fact] - public void SetPopMulti_Single() + public async Task SetPopMulti_Single() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -226,7 +222,7 @@ public void SetPopMulti_Single() [Fact] public async Task SetPopMulti_Multi_Async() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -252,7 +248,7 @@ public async Task SetPopMulti_Multi_Async() [Fact] public async Task SetPopMulti_Single_Async() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -278,7 +274,7 @@ public async Task SetPopMulti_Single_Async() [Fact] public async Task SetPopMulti_Zero_Async() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -298,9 +294,9 @@ public async Task SetPopMulti_Zero_Async() } [Fact] - public void SetAdd_Zero() + public async Task SetAdd_Zero() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -316,7 +312,7 @@ public void SetAdd_Zero() [Fact] public async Task SetAdd_Zero_Async() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -332,9 +328,9 @@ public async Task SetAdd_Zero_Async() } [Fact] - public void SetPopMulti_Nil() + public async Task SetPopMulti_Nil() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -348,7 +344,7 @@ public void SetPopMulti_Nil() [Fact] public async Task TestSortReadonlyPrimary() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -369,7 +365,7 @@ public async Task TestSortReadonlyPrimary() [Fact] public async Task TestSortReadonlyReplica() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -379,7 +375,7 @@ public async Task TestSortReadonlyReplica() var items = Enumerable.Repeat(0, 200).Select(_ => random.Next()).ToList(); await db.SetAddAsync(key, items.Select(x => (RedisValue)x).ToArray()); - using var readonlyConn = Create(configuration: TestConfig.Current.ReplicaServerAndPort, require: RedisFeatures.v7_0_0_rc1); + await using var readonlyConn = Create(configuration: TestConfig.Current.ReplicaServerAndPort, require: RedisFeatures.v7_0_0_rc1); var readonlyDb = conn.GetDatabase(); items.Sort(); diff --git a/tests/StackExchange.Redis.Tests/SocketTests.cs b/tests/StackExchange.Redis.Tests/SocketTests.cs index 71a1ffe47..2d11c0014 100644 --- a/tests/StackExchange.Redis.Tests/SocketTests.cs +++ b/tests/StackExchange.Redis.Tests/SocketTests.cs @@ -1,20 +1,19 @@ using System.Diagnostics; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; -public class SocketTests : TestBase +public class SocketTests(ITestOutputHelper output) : TestBase(output) { - protected override string GetConfiguration() => TestConfig.Current.PrimaryServerAndPort; - public SocketTests(ITestOutputHelper output) : base(output) { } - - [FactLongRunning] - public void CheckForSocketLeaks() + [Fact] + public async Task CheckForSocketLeaks() { + Skip.UnlessLongRunning(); const int count = 2000; for (var i = 0; i < count; i++) { - using var _ = Create(clientName: "Test: " + i); + await using var _ = Create(clientName: "Test: " + i); // Intentionally just creating and disposing to leak sockets here // ...so we can figure out what's happening. } diff --git a/tests/StackExchange.Redis.Tests/SortedSetTests.cs b/tests/StackExchange.Redis.Tests/SortedSetTests.cs index 7ba86fcf6..a6e6271ea 100644 --- a/tests/StackExchange.Redis.Tests/SortedSetTests.cs +++ b/tests/StackExchange.Redis.Tests/SortedSetTests.cs @@ -1,18 +1,14 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class SortedSetTests : TestBase +public class SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - - private static readonly SortedSetEntry[] entries = new SortedSetEntry[] - { + private static readonly SortedSetEntry[] entries = + [ new SortedSetEntry("a", 1), new SortedSetEntry("b", 2), new SortedSetEntry("c", 3), @@ -23,10 +19,10 @@ public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) new SortedSetEntry("h", 8), new SortedSetEntry("i", 9), new SortedSetEntry("j", 10), - }; + ]; - private static readonly SortedSetEntry[] entriesPow2 = new SortedSetEntry[] - { + private static readonly SortedSetEntry[] entriesPow2 = + [ new SortedSetEntry("a", 1), new SortedSetEntry("b", 2), new SortedSetEntry("c", 4), @@ -37,19 +33,19 @@ public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) new SortedSetEntry("h", 128), new SortedSetEntry("i", 256), new SortedSetEntry("j", 512), - }; + ]; - private static readonly SortedSetEntry[] entriesPow3 = new SortedSetEntry[] - { + private static readonly SortedSetEntry[] entriesPow3 = + [ new SortedSetEntry("a", 1), new SortedSetEntry("c", 4), new SortedSetEntry("e", 16), new SortedSetEntry("g", 64), new SortedSetEntry("i", 256), - }; + ]; - private static readonly SortedSetEntry[] lexEntries = new SortedSetEntry[] - { + private static readonly SortedSetEntry[] lexEntries = + [ new SortedSetEntry("a", 0), new SortedSetEntry("b", 0), new SortedSetEntry("c", 0), @@ -60,12 +56,12 @@ public SortedSetTests(ITestOutputHelper output, SharedConnectionFixture fixture) new SortedSetEntry("h", 0), new SortedSetEntry("i", 0), new SortedSetEntry("j", 0), - }; + ]; [Fact] - public void SortedSetCombine() + public async Task SortedSetCombine() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -76,15 +72,15 @@ public void SortedSetCombine() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var diff = db.SortedSetCombine(SetOperation.Difference, new RedisKey[] { key1, key2 }); + var diff = db.SortedSetCombine(SetOperation.Difference, [key1, key2]); Assert.Equal(5, diff.Length); Assert.Equal("b", diff[0]); - var inter = db.SortedSetCombine(SetOperation.Intersect, new RedisKey[] { key1, key2 }); + var inter = db.SortedSetCombine(SetOperation.Intersect, [key1, key2]); Assert.Equal(5, inter.Length); Assert.Equal("a", inter[0]); - var union = db.SortedSetCombine(SetOperation.Union, new RedisKey[] { key1, key2 }); + var union = db.SortedSetCombine(SetOperation.Union, [key1, key2]); Assert.Equal(10, union.Length); Assert.Equal("a", union[0]); } @@ -92,7 +88,7 @@ public void SortedSetCombine() [Fact] public async Task SortedSetCombineAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -103,23 +99,23 @@ public async Task SortedSetCombineAsync() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var diff = await db.SortedSetCombineAsync(SetOperation.Difference, new RedisKey[] { key1, key2 }); + var diff = await db.SortedSetCombineAsync(SetOperation.Difference, [key1, key2]); Assert.Equal(5, diff.Length); Assert.Equal("b", diff[0]); - var inter = await db.SortedSetCombineAsync(SetOperation.Intersect, new RedisKey[] { key1, key2 }); + var inter = await db.SortedSetCombineAsync(SetOperation.Intersect, [key1, key2]); Assert.Equal(5, inter.Length); Assert.Equal("a", inter[0]); - var union = await db.SortedSetCombineAsync(SetOperation.Union, new RedisKey[] { key1, key2 }); + var union = await db.SortedSetCombineAsync(SetOperation.Union, [key1, key2]); Assert.Equal(10, union.Length); Assert.Equal("a", union[0]); } [Fact] - public void SortedSetCombineWithScores() + public async Task SortedSetCombineWithScores() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -130,15 +126,15 @@ public void SortedSetCombineWithScores() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var diff = db.SortedSetCombineWithScores(SetOperation.Difference, new RedisKey[] { key1, key2 }); + var diff = db.SortedSetCombineWithScores(SetOperation.Difference, [key1, key2]); Assert.Equal(5, diff.Length); Assert.Equal(new SortedSetEntry("b", 2), diff[0]); - var inter = db.SortedSetCombineWithScores(SetOperation.Intersect, new RedisKey[] { key1, key2 }); + var inter = db.SortedSetCombineWithScores(SetOperation.Intersect, [key1, key2]); Assert.Equal(5, inter.Length); Assert.Equal(new SortedSetEntry("a", 2), inter[0]); - var union = db.SortedSetCombineWithScores(SetOperation.Union, new RedisKey[] { key1, key2 }); + var union = db.SortedSetCombineWithScores(SetOperation.Union, [key1, key2]); Assert.Equal(10, union.Length); Assert.Equal(new SortedSetEntry("a", 2), union[0]); } @@ -146,7 +142,7 @@ public void SortedSetCombineWithScores() [Fact] public async Task SortedSetCombineWithScoresAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -157,23 +153,23 @@ public async Task SortedSetCombineWithScoresAsync() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var diff = await db.SortedSetCombineWithScoresAsync(SetOperation.Difference, new RedisKey[] { key1, key2 }); + var diff = await db.SortedSetCombineWithScoresAsync(SetOperation.Difference, [key1, key2]); Assert.Equal(5, diff.Length); Assert.Equal(new SortedSetEntry("b", 2), diff[0]); - var inter = await db.SortedSetCombineWithScoresAsync(SetOperation.Intersect, new RedisKey[] { key1, key2 }); + var inter = await db.SortedSetCombineWithScoresAsync(SetOperation.Intersect, [key1, key2]); Assert.Equal(5, inter.Length); Assert.Equal(new SortedSetEntry("a", 2), inter[0]); - var union = await db.SortedSetCombineWithScoresAsync(SetOperation.Union, new RedisKey[] { key1, key2 }); + var union = await db.SortedSetCombineWithScoresAsync(SetOperation.Union, [key1, key2]); Assert.Equal(10, union.Length); Assert.Equal(new SortedSetEntry("a", 2), union[0]); } [Fact] - public void SortedSetCombineAndStore() + public async Task SortedSetCombineAndStore() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -186,20 +182,20 @@ public void SortedSetCombineAndStore() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var diff = db.SortedSetCombineAndStore(SetOperation.Difference, destination, new RedisKey[] { key1, key2 }); + var diff = db.SortedSetCombineAndStore(SetOperation.Difference, destination, [key1, key2]); Assert.Equal(5, diff); - var inter = db.SortedSetCombineAndStore(SetOperation.Intersect, destination, new RedisKey[] { key1, key2 }); + var inter = db.SortedSetCombineAndStore(SetOperation.Intersect, destination, [key1, key2]); Assert.Equal(5, inter); - var union = db.SortedSetCombineAndStore(SetOperation.Union, destination, new RedisKey[] { key1, key2 }); + var union = db.SortedSetCombineAndStore(SetOperation.Union, destination, [key1, key2]); Assert.Equal(10, union); } [Fact] public async Task SortedSetCombineAndStoreAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -212,20 +208,20 @@ public async Task SortedSetCombineAndStoreAsync() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var diff = await db.SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, new RedisKey[] { key1, key2 }); + var diff = await db.SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, [key1, key2]); Assert.Equal(5, diff); - var inter = await db.SortedSetCombineAndStoreAsync(SetOperation.Intersect, destination, new RedisKey[] { key1, key2 }); + var inter = await db.SortedSetCombineAndStoreAsync(SetOperation.Intersect, destination, [key1, key2]); Assert.Equal(5, inter); - var union = await db.SortedSetCombineAndStoreAsync(SetOperation.Union, destination, new RedisKey[] { key1, key2 }); + var union = await db.SortedSetCombineAndStoreAsync(SetOperation.Union, destination, [key1, key2]); Assert.Equal(10, union); } [Fact] public async Task SortedSetCombineErrors() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key1 = Me(); @@ -239,55 +235,55 @@ public async Task SortedSetCombineErrors() db.SortedSetAdd(key2, entriesPow3); // ZDIFF can't be used with weights - var ex = Assert.Throws(() => db.SortedSetCombine(SetOperation.Difference, new RedisKey[] { key1, key2 }, new double[] { 1, 2 })); + var ex = Assert.Throws(() => db.SortedSetCombine(SetOperation.Difference, [key1, key2], [1, 2])); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = Assert.Throws(() => db.SortedSetCombineWithScores(SetOperation.Difference, new RedisKey[] { key1, key2 }, new double[] { 1, 2 })); + ex = Assert.Throws(() => db.SortedSetCombineWithScores(SetOperation.Difference, [key1, key2], [1, 2])); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = Assert.Throws(() => db.SortedSetCombineAndStore(SetOperation.Difference, destination, new RedisKey[] { key1, key2 }, new double[] { 1, 2 })); + ex = Assert.Throws(() => db.SortedSetCombineAndStore(SetOperation.Difference, destination, [key1, key2], [1, 2])); Assert.Equal("ZDIFFSTORE cannot be used with weights or aggregation.", ex.Message); // and Async... - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAsync(SetOperation.Difference, new RedisKey[] { key1, key2 }, new double[] { 1, 2 })); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAsync(SetOperation.Difference, [key1, key2], [1, 2])); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineWithScoresAsync(SetOperation.Difference, new RedisKey[] { key1, key2 }, new double[] { 1, 2 })); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineWithScoresAsync(SetOperation.Difference, [key1, key2], [1, 2])); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, new RedisKey[] { key1, key2 }, new double[] { 1, 2 })); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, [key1, key2], [1, 2])); Assert.Equal("ZDIFFSTORE cannot be used with weights or aggregation.", ex.Message); // ZDIFF can't be used with aggregation - ex = Assert.Throws(() => db.SortedSetCombine(SetOperation.Difference, new RedisKey[] { key1, key2 }, aggregate: Aggregate.Max)); + ex = Assert.Throws(() => db.SortedSetCombine(SetOperation.Difference, [key1, key2], aggregate: Aggregate.Max)); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = Assert.Throws(() => db.SortedSetCombineWithScores(SetOperation.Difference, new RedisKey[] { key1, key2 }, aggregate: Aggregate.Max)); + ex = Assert.Throws(() => db.SortedSetCombineWithScores(SetOperation.Difference, [key1, key2], aggregate: Aggregate.Max)); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = Assert.Throws(() => db.SortedSetCombineAndStore(SetOperation.Difference, destination, new RedisKey[] { key1, key2 }, aggregate: Aggregate.Max)); + ex = Assert.Throws(() => db.SortedSetCombineAndStore(SetOperation.Difference, destination, [key1, key2], aggregate: Aggregate.Max)); Assert.Equal("ZDIFFSTORE cannot be used with weights or aggregation.", ex.Message); // and Async... - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAsync(SetOperation.Difference, new RedisKey[] { key1, key2 }, aggregate: Aggregate.Max)); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAsync(SetOperation.Difference, [key1, key2], aggregate: Aggregate.Max)); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineWithScoresAsync(SetOperation.Difference, new RedisKey[] { key1, key2 }, aggregate: Aggregate.Max)); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineWithScoresAsync(SetOperation.Difference, [key1, key2], aggregate: Aggregate.Max)); Assert.Equal("ZDIFF cannot be used with weights or aggregation.", ex.Message); - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, new RedisKey[] { key1, key2 }, aggregate: Aggregate.Max)); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAndStoreAsync(SetOperation.Difference, destination, [key1, key2], aggregate: Aggregate.Max)); Assert.Equal("ZDIFFSTORE cannot be used with weights or aggregation.", ex.Message); // Too many weights - ex = Assert.Throws(() => db.SortedSetCombine(SetOperation.Union, new RedisKey[] { key1, key2 }, new double[] { 1, 2, 3 })); + ex = Assert.Throws(() => db.SortedSetCombine(SetOperation.Union, [key1, key2], [1, 2, 3])); Assert.StartsWith("Keys and weights should have the same number of elements.", ex.Message); - ex = Assert.Throws(() => db.SortedSetCombineWithScores(SetOperation.Union, new RedisKey[] { key1, key2 }, new double[] { 1, 2, 3 })); + ex = Assert.Throws(() => db.SortedSetCombineWithScores(SetOperation.Union, [key1, key2], [1, 2, 3])); Assert.StartsWith("Keys and weights should have the same number of elements.", ex.Message); - ex = Assert.Throws(() => db.SortedSetCombineAndStore(SetOperation.Union, destination, new RedisKey[] { key1, key2 }, new double[] { 1, 2, 3 })); + ex = Assert.Throws(() => db.SortedSetCombineAndStore(SetOperation.Union, destination, [key1, key2], [1, 2, 3])); Assert.StartsWith("Keys and weights should have the same number of elements.", ex.Message); // and Async... - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAsync(SetOperation.Union, new RedisKey[] { key1, key2 }, new double[] { 1, 2, 3 })); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAsync(SetOperation.Union, [key1, key2], [1, 2, 3])); Assert.StartsWith("Keys and weights should have the same number of elements.", ex.Message); - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineWithScoresAsync(SetOperation.Union, new RedisKey[] { key1, key2 }, new double[] { 1, 2, 3 })); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineWithScoresAsync(SetOperation.Union, [key1, key2], [1, 2, 3])); Assert.StartsWith("Keys and weights should have the same number of elements.", ex.Message); - ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAndStoreAsync(SetOperation.Union, destination, new RedisKey[] { key1, key2 }, new double[] { 1, 2, 3 })); + ex = await Assert.ThrowsAsync(() => db.SortedSetCombineAndStoreAsync(SetOperation.Union, destination, [key1, key2], [1, 2, 3])); Assert.StartsWith("Keys and weights should have the same number of elements.", ex.Message); } [Fact] - public void SortedSetIntersectionLength() + public async Task SortedSetIntersectionLength() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key1 = Me(); @@ -298,18 +294,18 @@ public void SortedSetIntersectionLength() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var inter = db.SortedSetIntersectionLength(new RedisKey[] { key1, key2 }); + var inter = db.SortedSetIntersectionLength([key1, key2]); Assert.Equal(5, inter); // with limit - inter = db.SortedSetIntersectionLength(new RedisKey[] { key1, key2 }, 3); + inter = db.SortedSetIntersectionLength([key1, key2], 3); Assert.Equal(3, inter); } [Fact] public async Task SortedSetIntersectionLengthAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key1 = Me(); @@ -320,41 +316,41 @@ public async Task SortedSetIntersectionLengthAsync() db.SortedSetAdd(key1, entries); db.SortedSetAdd(key2, entriesPow3); - var inter = await db.SortedSetIntersectionLengthAsync(new RedisKey[] { key1, key2 }); + var inter = await db.SortedSetIntersectionLengthAsync([key1, key2]); Assert.Equal(5, inter); // with limit - inter = await db.SortedSetIntersectionLengthAsync(new RedisKey[] { key1, key2 }, 3); + inter = await db.SortedSetIntersectionLengthAsync([key1, key2], 3); Assert.Equal(3, inter); } [Fact] - public void SortedSetRangeViaScript() + public async Task SortedSetRangeViaScript() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, entries, CommandFlags.FireAndForget); - var result = db.ScriptEvaluate(script: "return redis.call('ZRANGE', KEYS[1], 0, -1, 'WITHSCORES')", keys: new RedisKey[] { key }); + var result = db.ScriptEvaluate(script: "return redis.call('ZRANGE', KEYS[1], 0, -1, 'WITHSCORES')", keys: [key]); AssertFlatArrayEntries(result); } [Fact] - public void SortedSetRangeViaExecute() + public async Task SortedSetRangeViaExecute() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key, CommandFlags.FireAndForget); db.SortedSetAdd(key, entries, CommandFlags.FireAndForget); - var result = db.Execute("ZRANGE", new object[] { key, 0, -1, "WITHSCORES" }); + var result = db.Execute("ZRANGE", [key, 0, -1, "WITHSCORES"]); - if (Context.IsResp3) + if (TestContext.Current.IsResp3()) { AssertJaggedArrayEntries(result); } @@ -404,9 +400,9 @@ private void AssertJaggedArrayEntries(RedisResult result) } [Fact] - public void SortedSetPopMulti_Multi() + public async Task SortedSetPopMulti_Multi() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -427,9 +423,9 @@ public void SortedSetPopMulti_Multi() } [Fact] - public void SortedSetPopMulti_Single() + public async Task SortedSetPopMulti_Single() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -451,7 +447,7 @@ public void SortedSetPopMulti_Single() [Fact] public async Task SortedSetPopMulti_Multi_Async() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -474,7 +470,7 @@ public async Task SortedSetPopMulti_Multi_Async() [Fact] public async Task SortedSetPopMulti_Single_Async() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -496,7 +492,7 @@ public async Task SortedSetPopMulti_Single_Async() [Fact] public async Task SortedSetPopMulti_Zero_Async() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -514,9 +510,9 @@ public async Task SortedSetPopMulti_Zero_Async() } [Fact] - public void SortedSetRandomMembers() + public async Task SortedSetRandomMembers() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -560,7 +556,7 @@ public void SortedSetRandomMembers() [Fact] public async Task SortedSetRandomMembersAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -603,14 +599,14 @@ public async Task SortedSetRandomMembersAsync() [Fact] public async Task SortedSetRangeStoreByRankAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entries, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, 0, -1); Assert.Equal(entries.Length, res); @@ -619,14 +615,14 @@ public async Task SortedSetRangeStoreByRankAsync() [Fact] public async Task SortedSetRangeStoreByRankLimitedAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entries, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, 1, 4); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -640,14 +636,14 @@ public async Task SortedSetRangeStoreByRankLimitedAsync() [Fact] public async Task SortedSetRangeStoreByScoreAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, 64, 128, SortedSetOrder.ByScore); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -661,14 +657,14 @@ public async Task SortedSetRangeStoreByScoreAsync() [Fact] public async Task SortedSetRangeStoreByScoreAsyncDefault() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, double.NegativeInfinity, double.PositiveInfinity, SortedSetOrder.ByScore); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -682,14 +678,14 @@ public async Task SortedSetRangeStoreByScoreAsyncDefault() [Fact] public async Task SortedSetRangeStoreByScoreAsyncLimited() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, double.NegativeInfinity, double.PositiveInfinity, SortedSetOrder.ByScore, skip: 1, take: 6); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -703,14 +699,14 @@ public async Task SortedSetRangeStoreByScoreAsyncLimited() [Fact] public async Task SortedSetRangeStoreByScoreAsyncExclusiveRange() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, 32, 256, SortedSetOrder.ByScore, exclude: Exclude.Both); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -724,14 +720,14 @@ public async Task SortedSetRangeStoreByScoreAsyncExclusiveRange() [Fact] public async Task SortedSetRangeStoreByScoreAsyncReverse() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, start: double.PositiveInfinity, double.NegativeInfinity, SortedSetOrder.ByScore, order: Order.Descending); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -745,14 +741,14 @@ public async Task SortedSetRangeStoreByScoreAsyncReverse() [Fact] public async Task SortedSetRangeStoreByLexAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, lexEntries, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, "a", "j", SortedSetOrder.ByLex); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -766,14 +762,14 @@ public async Task SortedSetRangeStoreByLexAsync() [Fact] public async Task SortedSetRangeStoreByLexExclusiveRangeAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, lexEntries, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, "a", "j", SortedSetOrder.ByLex, Exclude.Both); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -787,14 +783,14 @@ public async Task SortedSetRangeStoreByLexExclusiveRangeAsync() [Fact] public async Task SortedSetRangeStoreByLexRevRangeAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); await db.SortedSetAddAsync(sourceKey, lexEntries, CommandFlags.FireAndForget); var res = await db.SortedSetRangeAndStoreAsync(sourceKey, destinationKey, "j", "a", SortedSetOrder.ByLex, exclude: Exclude.None, order: Order.Descending); var range = await db.SortedSetRangeByRankWithScoresAsync(destinationKey); @@ -806,32 +802,32 @@ public async Task SortedSetRangeStoreByLexRevRangeAsync() } [Fact] - public void SortedSetRangeStoreByRank() + public async Task SortedSetRangeStoreByRank() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entries, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, 0, -1); Assert.Equal(entries.Length, res); } [Fact] - public void SortedSetRangeStoreByRankLimited() + public async Task SortedSetRangeStoreByRankLimited() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entries, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, 1, 4); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -843,16 +839,16 @@ public void SortedSetRangeStoreByRankLimited() } [Fact] - public void SortedSetRangeStoreByScore() + public async Task SortedSetRangeStoreByScore() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, 64, 128, SortedSetOrder.ByScore); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -864,16 +860,16 @@ public void SortedSetRangeStoreByScore() } [Fact] - public void SortedSetRangeStoreByScoreDefault() + public async Task SortedSetRangeStoreByScoreDefault() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, double.NegativeInfinity, double.PositiveInfinity, SortedSetOrder.ByScore); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -885,16 +881,16 @@ public void SortedSetRangeStoreByScoreDefault() } [Fact] - public void SortedSetRangeStoreByScoreLimited() + public async Task SortedSetRangeStoreByScoreLimited() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, double.NegativeInfinity, double.PositiveInfinity, SortedSetOrder.ByScore, skip: 1, take: 6); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -906,16 +902,16 @@ public void SortedSetRangeStoreByScoreLimited() } [Fact] - public void SortedSetRangeStoreByScoreExclusiveRange() + public async Task SortedSetRangeStoreByScoreExclusiveRange() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, 32, 256, SortedSetOrder.ByScore, exclude: Exclude.Both); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -927,16 +923,16 @@ public void SortedSetRangeStoreByScoreExclusiveRange() } [Fact] - public void SortedSetRangeStoreByScoreReverse() + public async Task SortedSetRangeStoreByScoreReverse() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, entriesPow2, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, start: double.PositiveInfinity, double.NegativeInfinity, SortedSetOrder.ByScore, order: Order.Descending); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -948,16 +944,16 @@ public void SortedSetRangeStoreByScoreReverse() } [Fact] - public void SortedSetRangeStoreByLex() + public async Task SortedSetRangeStoreByLex() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, lexEntries, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, "a", "j", SortedSetOrder.ByLex); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -969,16 +965,16 @@ public void SortedSetRangeStoreByLex() } [Fact] - public void SortedSetRangeStoreByLexExclusiveRange() + public async Task SortedSetRangeStoreByLexExclusiveRange() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, lexEntries, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, "a", "j", SortedSetOrder.ByLex, Exclude.Both); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -990,16 +986,16 @@ public void SortedSetRangeStoreByLexExclusiveRange() } [Fact] - public void SortedSetRangeStoreByLexRevRange() + public async Task SortedSetRangeStoreByLexRevRange() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, lexEntries, CommandFlags.FireAndForget); var res = db.SortedSetRangeAndStore(sourceKey, destinationKey, "j", "a", SortedSetOrder.ByLex, Exclude.None, Order.Descending); var range = db.SortedSetRangeByRankWithScores(destinationKey); @@ -1011,41 +1007,41 @@ public void SortedSetRangeStoreByLexRevRange() } [Fact] - public void SortedSetRangeStoreFailErroneousTake() + public async Task SortedSetRangeStoreFailErroneousTake() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, lexEntries, CommandFlags.FireAndForget); var exception = Assert.Throws(() => db.SortedSetRangeAndStore(sourceKey, destinationKey, 0, -1, take: 5)); Assert.Equal("take", exception.ParamName); } [Fact] - public void SortedSetRangeStoreFailExclude() + public async Task SortedSetRangeStoreFailExclude() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, lexEntries, CommandFlags.FireAndForget); var exception = Assert.Throws(() => db.SortedSetRangeAndStore(sourceKey, destinationKey, 0, -1, exclude: Exclude.Both)); Assert.Equal("exclude", exception.ParamName); } [Fact] - public void SortedSetMultiPopSingleKey() + public async Task SortedSetMultiPopSingleKey() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -1053,23 +1049,22 @@ public void SortedSetMultiPopSingleKey() db.SortedSetAdd( key, - new SortedSetEntry[] - { + [ new SortedSetEntry("rays", 100), new SortedSetEntry("yankees", 92), new SortedSetEntry("red sox", 92), new SortedSetEntry("blue jays", 91), new SortedSetEntry("orioles", 52), - }); + ]); - var highest = db.SortedSetPop(new RedisKey[] { key }, 1, order: Order.Descending); + var highest = db.SortedSetPop([key], 1, order: Order.Descending); Assert.False(highest.IsNull); Assert.Equal(key, highest.Key); var entry = Assert.Single(highest.Entries); Assert.Equal("rays", entry.Element); Assert.Equal(100, entry.Score); - var bottom2 = db.SortedSetPop(new RedisKey[] { key }, 2); + var bottom2 = db.SortedSetPop([key], 2); Assert.False(bottom2.IsNull); Assert.Equal(key, bottom2.Key); Assert.Equal(2, bottom2.Entries.Length); @@ -1080,9 +1075,9 @@ public void SortedSetMultiPopSingleKey() } [Fact] - public void SortedSetMultiPopMultiKey() + public async Task SortedSetMultiPopMultiKey() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -1090,23 +1085,22 @@ public void SortedSetMultiPopMultiKey() db.SortedSetAdd( key, - new SortedSetEntry[] - { + [ new SortedSetEntry("rays", 100), new SortedSetEntry("yankees", 92), new SortedSetEntry("red sox", 92), new SortedSetEntry("blue jays", 91), new SortedSetEntry("orioles", 52), - }); + ]); - var highest = db.SortedSetPop(new RedisKey[] { "not a real key", key, "yet another not a real key" }, 1, order: Order.Descending); + var highest = db.SortedSetPop(["not a real key", key, "yet another not a real key"], 1, order: Order.Descending); Assert.False(highest.IsNull); Assert.Equal(key, highest.Key); var entry = Assert.Single(highest.Entries); Assert.Equal("rays", entry.Element); Assert.Equal(100, entry.Score); - var bottom2 = db.SortedSetPop(new RedisKey[] { "not a real key", key, "yet another not a real key" }, 2); + var bottom2 = db.SortedSetPop(["not a real key", key, "yet another not a real key"], 2); Assert.False(bottom2.IsNull); Assert.Equal(key, bottom2.Key); Assert.Equal(2, bottom2.Entries.Length); @@ -1117,33 +1111,33 @@ public void SortedSetMultiPopMultiKey() } [Fact] - public void SortedSetMultiPopNoSet() + public async Task SortedSetMultiPopNoSet() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key); - var res = db.SortedSetPop(new RedisKey[] { key }, 1); + var res = db.SortedSetPop([key], 1); Assert.True(res.IsNull); } [Fact] - public void SortedSetMultiPopCount0() + public async Task SortedSetMultiPopCount0() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); db.KeyDelete(key); - var exception = Assert.Throws(() => db.SortedSetPop(new RedisKey[] { key }, 0)); + var exception = Assert.Throws(() => db.SortedSetPop([key], 0)); Assert.Contains("ERR count should be greater than 0", exception.Message); } [Fact] public async Task SortedSetMultiPopAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -1151,24 +1145,23 @@ public async Task SortedSetMultiPopAsync() db.SortedSetAdd( key, - new SortedSetEntry[] - { + [ new SortedSetEntry("rays", 100), new SortedSetEntry("yankees", 92), new SortedSetEntry("red sox", 92), new SortedSetEntry("blue jays", 91), new SortedSetEntry("orioles", 52), - }); + ]); var highest = await db.SortedSetPopAsync( - new RedisKey[] { "not a real key", key, "yet another not a real key" }, 1, order: Order.Descending); + ["not a real key", key, "yet another not a real key"], 1, order: Order.Descending); Assert.False(highest.IsNull); Assert.Equal(key, highest.Key); var entry = Assert.Single(highest.Entries); Assert.Equal("rays", entry.Element); Assert.Equal(100, entry.Score); - var bottom2 = await db.SortedSetPopAsync(new RedisKey[] { "not a real key", key, "yet another not a real key" }, 2); + var bottom2 = await db.SortedSetPopAsync(["not a real key", key, "yet another not a real key"], 2); Assert.False(bottom2.IsNull); Assert.Equal(key, bottom2.Key); Assert.Equal(2, bottom2.Entries.Length); @@ -1179,9 +1172,9 @@ public async Task SortedSetMultiPopAsync() } [Fact] - public void SortedSetMultiPopEmptyKeys() + public async Task SortedSetMultiPopEmptyKeys() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var exception = Assert.Throws(() => db.SortedSetPop(Array.Empty(), 5)); @@ -1189,25 +1182,25 @@ public void SortedSetMultiPopEmptyKeys() } [Fact] - public void SortedSetRangeStoreFailForReplica() + public async Task SortedSetRangeStoreFailForReplica() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var me = Me(); var sourceKey = $"{me}:ZSetSource"; var destinationKey = $"{me}:ZSetDestination"; - db.KeyDelete(new RedisKey[] { sourceKey, destinationKey }, CommandFlags.FireAndForget); + db.KeyDelete([sourceKey, destinationKey], CommandFlags.FireAndForget); db.SortedSetAdd(sourceKey, lexEntries, CommandFlags.FireAndForget); var exception = Assert.Throws(() => db.SortedSetRangeAndStore(sourceKey, destinationKey, 0, -1, flags: CommandFlags.DemandReplica)); Assert.Contains("Command cannot be issued to a replica", exception.Message); } [Fact] - public void SortedSetScoresSingle() + public async Task SortedSetScoresSingle() { - using var conn = Create(require: RedisFeatures.v2_1_0); + await using var conn = Create(require: RedisFeatures.v2_1_0); var db = conn.GetDatabase(); var key = Me(); @@ -1225,7 +1218,7 @@ public void SortedSetScoresSingle() [Fact] public async Task SortedSetScoresSingleAsync() { - using var conn = Create(require: RedisFeatures.v2_1_0); + await using var conn = Create(require: RedisFeatures.v2_1_0); var db = conn.GetDatabase(); var key = Me(); @@ -1241,9 +1234,9 @@ public async Task SortedSetScoresSingleAsync() } [Fact] - public void SortedSetScoresSingle_MissingSetStillReturnsNull() + public async Task SortedSetScoresSingle_MissingSetStillReturnsNull() { - using var conn = Create(require: RedisFeatures.v2_1_0); + await using var conn = Create(require: RedisFeatures.v2_1_0); var db = conn.GetDatabase(); var key = Me(); @@ -1259,7 +1252,7 @@ public void SortedSetScoresSingle_MissingSetStillReturnsNull() [Fact] public async Task SortedSetScoresSingle_MissingSetStillReturnsNullAsync() { - using var conn = Create(require: RedisFeatures.v2_1_0); + await using var conn = Create(require: RedisFeatures.v2_1_0); var db = conn.GetDatabase(); var key = Me(); @@ -1273,9 +1266,9 @@ public async Task SortedSetScoresSingle_MissingSetStillReturnsNullAsync() } [Fact] - public void SortedSetScoresSingle_ReturnsNullForMissingMember() + public async Task SortedSetScoresSingle_ReturnsNullForMissingMember() { - using var conn = Create(require: RedisFeatures.v2_1_0); + await using var conn = Create(require: RedisFeatures.v2_1_0); var db = conn.GetDatabase(); var key = Me(); @@ -1292,7 +1285,7 @@ public void SortedSetScoresSingle_ReturnsNullForMissingMember() [Fact] public async Task SortedSetScoresSingle_ReturnsNullForMissingMemberAsync() { - using var conn = Create(require: RedisFeatures.v2_1_0); + await using var conn = Create(require: RedisFeatures.v2_1_0); var db = conn.GetDatabase(); var key = Me(); @@ -1307,9 +1300,9 @@ public async Task SortedSetScoresSingle_ReturnsNullForMissingMemberAsync() } [Fact] - public void SortedSetScoresMultiple() + public async Task SortedSetScoresMultiple() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -1322,7 +1315,7 @@ public void SortedSetScoresMultiple() db.SortedSetAdd(key, member2, 1.75); db.SortedSetAdd(key, member3, 2); - var scores = db.SortedSetScores(key, new RedisValue[] { member1, member2, member3 }); + var scores = db.SortedSetScores(key, [member1, member2, member3]); Assert.NotNull(scores); Assert.Equal(3, scores.Length); @@ -1334,7 +1327,7 @@ public void SortedSetScoresMultiple() [Fact] public async Task SortedSetScoresMultipleAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -1347,7 +1340,7 @@ public async Task SortedSetScoresMultipleAsync() await db.SortedSetAddAsync(key, member2, 1.75); await db.SortedSetAddAsync(key, member3, 2); - var scores = await db.SortedSetScoresAsync(key, new RedisValue[] { member1, member2, member3 }); + var scores = await db.SortedSetScoresAsync(key, [member1, member2, member3]); Assert.NotNull(scores); Assert.Equal(3, scores.Length); @@ -1357,9 +1350,9 @@ public async Task SortedSetScoresMultipleAsync() } [Fact] - public void SortedSetScoresMultiple_ReturnsNullItemsForMissingSet() + public async Task SortedSetScoresMultiple_ReturnsNullItemsForMissingSet() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -1367,7 +1360,7 @@ public void SortedSetScoresMultiple_ReturnsNullItemsForMissingSet() db.KeyDelete(key); // Missing set but should still return an array of nulls. - var scores = db.SortedSetScores(key, new RedisValue[] { "bogus1", "bogus2", "bogus3" }); + var scores = db.SortedSetScores(key, ["bogus1", "bogus2", "bogus3"]); Assert.NotNull(scores); Assert.Equal(3, scores.Length); @@ -1379,7 +1372,7 @@ public void SortedSetScoresMultiple_ReturnsNullItemsForMissingSet() [Fact] public async Task SortedSetScoresMultiple_ReturnsNullItemsForMissingSetAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -1387,7 +1380,7 @@ public async Task SortedSetScoresMultiple_ReturnsNullItemsForMissingSetAsync() await db.KeyDeleteAsync(key); // Missing set but should still return an array of nulls. - var scores = await db.SortedSetScoresAsync(key, new RedisValue[] { "bogus1", "bogus2", "bogus3" }); + var scores = await db.SortedSetScoresAsync(key, ["bogus1", "bogus2", "bogus3"]); Assert.NotNull(scores); Assert.Equal(3, scores.Length); @@ -1397,9 +1390,9 @@ public async Task SortedSetScoresMultiple_ReturnsNullItemsForMissingSetAsync() } [Fact] - public void SortedSetScoresMultiple_ReturnsScoresAndNullItems() + public async Task SortedSetScoresMultiple_ReturnsScoresAndNullItems() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -1414,7 +1407,7 @@ public void SortedSetScoresMultiple_ReturnsScoresAndNullItems() db.SortedSetAdd(key, member2, 1.75); db.SortedSetAdd(key, member3, 2); - var scores = db.SortedSetScores(key, new RedisValue[] { member1, bogusMember, member2, member3 }); + var scores = db.SortedSetScores(key, [member1, bogusMember, member2, member3]); Assert.NotNull(scores); Assert.Equal(4, scores.Length); @@ -1427,7 +1420,7 @@ public void SortedSetScoresMultiple_ReturnsScoresAndNullItems() [Fact] public async Task SortedSetScoresMultiple_ReturnsScoresAndNullItemsAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -1442,7 +1435,7 @@ public async Task SortedSetScoresMultiple_ReturnsScoresAndNullItemsAsync() await db.SortedSetAddAsync(key, member2, 1.75); await db.SortedSetAddAsync(key, member3, 2); - var scores = await db.SortedSetScoresAsync(key, new RedisValue[] { member1, bogusMember, member2, member3 }); + var scores = await db.SortedSetScoresAsync(key, [member1, bogusMember, member2, member3]); Assert.NotNull(scores); Assert.Equal(4, scores.Length); @@ -1455,7 +1448,7 @@ public async Task SortedSetScoresMultiple_ReturnsScoresAndNullItemsAsync() [Fact] public async Task SortedSetUpdate() { - using var conn = Create(require: RedisFeatures.v3_0_0); + await using var conn = Create(require: RedisFeatures.v3_0_0); var db = conn.GetDatabase(); var key = Me(); diff --git a/tests/StackExchange.Redis.Tests/SortedSetWhenTests.cs b/tests/StackExchange.Redis.Tests/SortedSetWhenTests.cs index a26f2d5ba..17c587079 100644 --- a/tests/StackExchange.Redis.Tests/SortedSetWhenTests.cs +++ b/tests/StackExchange.Redis.Tests/SortedSetWhenTests.cs @@ -1,17 +1,14 @@ -using Xunit; -using Xunit.Abstractions; +using System.Threading.Tasks; +using Xunit; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class SortedSetWhenTest : TestBase +public class SortedSetWhenTest(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public SortedSetWhenTest(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void GreaterThanLessThan() + public async Task GreaterThanLessThan() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -26,9 +23,9 @@ public void GreaterThanLessThan() } [Fact] - public void IllegalCombinations() + public async Task IllegalCombinations() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); diff --git a/tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj b/tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj index 80a5762cf..50d4ae3d1 100644 --- a/tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj +++ b/tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj @@ -1,6 +1,7 @@  net481;net8.0 + Exe StackExchange.Redis.Tests true true @@ -20,17 +21,14 @@ + - + + - - - - - diff --git a/tests/StackExchange.Redis.Tests/StreamTests.cs b/tests/StackExchange.Redis.Tests/StreamTests.cs index 0ea744848..aef914293 100644 --- a/tests/StackExchange.Redis.Tests/StreamTests.cs +++ b/tests/StackExchange.Redis.Tests/StreamTests.cs @@ -4,23 +4,19 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class StreamTests : TestBase +public class StreamTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public StreamTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - public override string Me([CallerFilePath] string? filePath = null, [CallerMemberName] string? caller = null) => base.Me(filePath, caller) + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); [Fact] - public void IsStreamType() + public async Task IsStreamType() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -32,9 +28,9 @@ public void IsStreamType() } [Fact] - public void StreamAddSinglePairWithAutoId() + public async Task StreamAddSinglePairWithAutoId() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -44,9 +40,9 @@ public void StreamAddSinglePairWithAutoId() } [Fact] - public void StreamAddMultipleValuePairsWithAutoId() + public async Task StreamAddMultipleValuePairsWithAutoId() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -72,9 +68,9 @@ public void StreamAddMultipleValuePairsWithAutoId() } [Fact] - public void StreamAddWithManualId() + public async Task StreamAddWithManualId() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); const string id = "42-0"; @@ -86,9 +82,9 @@ public void StreamAddWithManualId() } [Fact] - public void StreamAddMultipleValuePairsWithManualId() + public async Task StreamAddMultipleValuePairsWithManualId() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); const string id = "42-0"; @@ -112,7 +108,7 @@ public void StreamAddMultipleValuePairsWithManualId() [Fact] public async Task StreamAutoClaim_MissingKey() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -129,9 +125,9 @@ public async Task StreamAutoClaim_MissingKey() } [Fact] - public void StreamAutoClaim_ClaimsPendingMessages() + public async Task StreamAutoClaim_ClaimsPendingMessages() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -148,7 +144,7 @@ public void StreamAutoClaim_ClaimsPendingMessages() Assert.Equal("0-0", result.NextStartId); Assert.NotEmpty(result.ClaimedEntries); Assert.Empty(result.DeletedIds); - Assert.True(result.ClaimedEntries.Length == 2); + Assert.Equal(2, result.ClaimedEntries.Length); Assert.Equal("value1", result.ClaimedEntries[0].Values[0].Value); Assert.Equal("value2", result.ClaimedEntries[1].Values[0].Value); } @@ -156,7 +152,7 @@ public void StreamAutoClaim_ClaimsPendingMessages() [Fact] public async Task StreamAutoClaim_ClaimsPendingMessagesAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -173,15 +169,15 @@ public async Task StreamAutoClaim_ClaimsPendingMessagesAsync() Assert.Equal("0-0", result.NextStartId); Assert.NotEmpty(result.ClaimedEntries); Assert.Empty(result.DeletedIds); - Assert.True(result.ClaimedEntries.Length == 2); + Assert.Equal(2, result.ClaimedEntries.Length); Assert.Equal("value1", result.ClaimedEntries[0].Values[0].Value); Assert.Equal("value2", result.ClaimedEntries[1].Values[0].Value); } [Fact] - public void StreamAutoClaim_ClaimsSingleMessageWithCountOption() + public async Task StreamAutoClaim_ClaimsSingleMessageWithCountOption() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -199,14 +195,14 @@ public void StreamAutoClaim_ClaimsSingleMessageWithCountOption() Assert.Equal(messageIds[1], result.NextStartId); Assert.NotEmpty(result.ClaimedEntries); Assert.Empty(result.DeletedIds); - Assert.True(result.ClaimedEntries.Length == 1); + Assert.Single(result.ClaimedEntries); Assert.Equal("value1", result.ClaimedEntries[0].Values[0].Value); } [Fact] - public void StreamAutoClaim_ClaimsSingleMessageWithCountOptionIdsOnly() + public async Task StreamAutoClaim_ClaimsSingleMessageWithCountOptionIdsOnly() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -223,7 +219,7 @@ public void StreamAutoClaim_ClaimsSingleMessageWithCountOptionIdsOnly() // Should be the second message ID from the call to prepare. Assert.Equal(messageIds[1], result.NextStartId); Assert.NotEmpty(result.ClaimedIds); - Assert.True(result.ClaimedIds.Length == 1); + Assert.Single(result.ClaimedIds); Assert.Equal(messageIds[0], result.ClaimedIds[0]); Assert.Empty(result.DeletedIds); } @@ -231,7 +227,7 @@ public void StreamAutoClaim_ClaimsSingleMessageWithCountOptionIdsOnly() [Fact] public async Task StreamAutoClaim_ClaimsSingleMessageWithCountOptionAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -249,14 +245,14 @@ public async Task StreamAutoClaim_ClaimsSingleMessageWithCountOptionAsync() Assert.Equal(messageIds[1], result.NextStartId); Assert.NotEmpty(result.ClaimedEntries); Assert.Empty(result.DeletedIds); - Assert.True(result.ClaimedEntries.Length == 1); + Assert.Single(result.ClaimedEntries); Assert.Equal("value1", result.ClaimedEntries[0].Values[0].Value); } [Fact] public async Task StreamAutoClaim_ClaimsSingleMessageWithCountOptionIdsOnlyAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -273,15 +269,15 @@ public async Task StreamAutoClaim_ClaimsSingleMessageWithCountOptionIdsOnlyAsync // Should be the second message ID from the call to prepare. Assert.Equal(messageIds[1], result.NextStartId); Assert.NotEmpty(result.ClaimedIds); - Assert.True(result.ClaimedIds.Length == 1); + Assert.Single(result.ClaimedIds); Assert.Equal(messageIds[0], result.ClaimedIds[0]); Assert.Empty(result.DeletedIds); } [Fact] - public void StreamAutoClaim_IncludesDeletedMessageId() + public async Task StreamAutoClaim_IncludesDeletedMessageId() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var key = Me(); var db = conn.GetDatabase(); @@ -293,7 +289,7 @@ public void StreamAutoClaim_IncludesDeletedMessageId() var messageIds = StreamAutoClaim_PrepareTestData(db, key, group, consumer1); // Delete one of the messages, it should be included in the deleted message ID array. - db.StreamDelete(key, new RedisValue[] { messageIds[0] }); + db.StreamDelete(key, [messageIds[0]]); // Claim a single pending message and reassign it to consumer2. var result = db.StreamAutoClaim(key, group, consumer2, 0, "0-0", count: 2); @@ -301,15 +297,15 @@ public void StreamAutoClaim_IncludesDeletedMessageId() Assert.Equal("0-0", result.NextStartId); Assert.NotEmpty(result.ClaimedEntries); Assert.NotEmpty(result.DeletedIds); - Assert.True(result.ClaimedEntries.Length == 1); - Assert.True(result.DeletedIds.Length == 1); + Assert.Single(result.ClaimedEntries); + Assert.Single(result.DeletedIds); Assert.Equal(messageIds[0], result.DeletedIds[0]); } [Fact] public async Task StreamAutoClaim_IncludesDeletedMessageIdAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var key = Me(); var db = conn.GetDatabase(); @@ -321,7 +317,7 @@ public async Task StreamAutoClaim_IncludesDeletedMessageIdAsync() var messageIds = StreamAutoClaim_PrepareTestData(db, key, group, consumer1); // Delete one of the messages, it should be included in the deleted message ID array. - db.StreamDelete(key, new RedisValue[] { messageIds[0] }); + db.StreamDelete(key, [messageIds[0]]); // Claim a single pending message and reassign it to consumer2. var result = await db.StreamAutoClaimAsync(key, group, consumer2, 0, "0-0", count: 2); @@ -329,15 +325,15 @@ public async Task StreamAutoClaim_IncludesDeletedMessageIdAsync() Assert.Equal("0-0", result.NextStartId); Assert.NotEmpty(result.ClaimedEntries); Assert.NotEmpty(result.DeletedIds); - Assert.True(result.ClaimedEntries.Length == 1); - Assert.True(result.DeletedIds.Length == 1); + Assert.Single(result.ClaimedEntries); + Assert.Single(result.DeletedIds); Assert.Equal(messageIds[0], result.DeletedIds[0]); } [Fact] - public void StreamAutoClaim_NoMessagesToClaim() + public async Task StreamAutoClaim_NoMessagesToClaim() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -361,7 +357,7 @@ public void StreamAutoClaim_NoMessagesToClaim() [Fact] public async Task StreamAutoClaim_NoMessagesToClaimAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -383,9 +379,9 @@ public async Task StreamAutoClaim_NoMessagesToClaimAsync() } [Fact] - public void StreamAutoClaim_NoMessageMeetsMinIdleTime() + public async Task StreamAutoClaim_NoMessageMeetsMinIdleTime() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -407,7 +403,7 @@ public void StreamAutoClaim_NoMessageMeetsMinIdleTime() [Fact] public async Task StreamAutoClaim_NoMessageMeetsMinIdleTimeAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -427,9 +423,9 @@ public async Task StreamAutoClaim_NoMessageMeetsMinIdleTimeAsync() } [Fact] - public void StreamAutoClaim_ReturnsMessageIdOnly() + public async Task StreamAutoClaim_ReturnsMessageIdOnly() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -446,7 +442,7 @@ public void StreamAutoClaim_ReturnsMessageIdOnly() Assert.Equal("0-0", result.NextStartId); Assert.NotEmpty(result.ClaimedIds); Assert.Empty(result.DeletedIds); - Assert.True(result.ClaimedIds.Length == 2); + Assert.Equal(2, result.ClaimedIds.Length); Assert.Equal(messageIds[0], result.ClaimedIds[0]); Assert.Equal(messageIds[1], result.ClaimedIds[1]); } @@ -454,7 +450,7 @@ public void StreamAutoClaim_ReturnsMessageIdOnly() [Fact] public async Task StreamAutoClaim_ReturnsMessageIdOnlyAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var key = Me(); var db = conn.GetDatabase(); @@ -471,12 +467,12 @@ public async Task StreamAutoClaim_ReturnsMessageIdOnlyAsync() Assert.Equal("0-0", result.NextStartId); Assert.NotEmpty(result.ClaimedIds); Assert.Empty(result.DeletedIds); - Assert.True(result.ClaimedIds.Length == 2); + Assert.Equal(2, result.ClaimedIds.Length); Assert.Equal(messageIds[0], result.ClaimedIds[0]); Assert.Equal(messageIds[1], result.ClaimedIds[1]); } - private RedisValue[] StreamAutoClaim_PrepareTestData(IDatabase db, RedisKey key, RedisValue group, RedisValue consumer) + private static RedisValue[] StreamAutoClaim_PrepareTestData(IDatabase db, RedisKey key, RedisValue group, RedisValue consumer) { // Create the group. db.KeyDelete(key); @@ -489,13 +485,13 @@ private RedisValue[] StreamAutoClaim_PrepareTestData(IDatabase db, RedisKey key, // Read the messages into the "c1" db.StreamReadGroup(key, group, consumer); - return new RedisValue[2] { id1, id2 }; + return [id1, id2]; } [Fact] - public void StreamConsumerGroupSetId() + public async Task StreamConsumerGroupSetId() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -524,9 +520,9 @@ public void StreamConsumerGroupSetId() } [Fact] - public void StreamConsumerGroupWithNoConsumers() + public async Task StreamConsumerGroupWithNoConsumers() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -545,9 +541,9 @@ public void StreamConsumerGroupWithNoConsumers() } [Fact] - public void StreamCreateConsumerGroup() + public async Task StreamCreateConsumerGroup() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -563,9 +559,9 @@ public void StreamCreateConsumerGroup() } [Fact] - public void StreamCreateConsumerGroupBeforeCreatingStream() + public async Task StreamCreateConsumerGroupBeforeCreatingStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -584,9 +580,9 @@ public void StreamCreateConsumerGroupBeforeCreatingStream() } [Fact] - public void StreamCreateConsumerGroupFailsIfKeyDoesntExist() + public async Task StreamCreateConsumerGroupFailsIfKeyDoesntExist() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -601,9 +597,9 @@ public void StreamCreateConsumerGroupFailsIfKeyDoesntExist() } [Fact] - public void StreamCreateConsumerGroupSucceedsWhenKeyExists() + public async Task StreamCreateConsumerGroupSucceedsWhenKeyExists() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -622,9 +618,9 @@ public void StreamCreateConsumerGroupSucceedsWhenKeyExists() } [Fact] - public void StreamConsumerGroupReadOnlyNewMessagesWithEmptyResponse() + public async Task StreamConsumerGroupReadOnlyNewMessagesWithEmptyResponse() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -644,9 +640,9 @@ public void StreamConsumerGroupReadOnlyNewMessagesWithEmptyResponse() } [Fact] - public void StreamConsumerGroupReadFromStreamBeginning() + public async Task StreamConsumerGroupReadFromStreamBeginning() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -665,9 +661,9 @@ public void StreamConsumerGroupReadFromStreamBeginning() } [Fact] - public void StreamConsumerGroupReadFromStreamBeginningWithCount() + public async Task StreamConsumerGroupReadFromStreamBeginningWithCount() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -690,9 +686,9 @@ public void StreamConsumerGroupReadFromStreamBeginningWithCount() } [Fact] - public void StreamConsumerGroupAcknowledgeMessage() + public async Task StreamConsumerGroupAcknowledgeMessage() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -715,7 +711,7 @@ public void StreamConsumerGroupAcknowledgeMessage() var oneAck = db.StreamAcknowledge(key, groupName, id1); // Multiple message Id overload. - var twoAck = db.StreamAcknowledge(key, groupName, new[] { id3, id4 }); + var twoAck = db.StreamAcknowledge(key, groupName, [id3, id4]); // Read the group again, it should only return the unacknowledged message. var notAcknowledged = db.StreamReadGroup(key, groupName, consumer, "0-0"); @@ -728,9 +724,9 @@ public void StreamConsumerGroupAcknowledgeMessage() } [Fact] - public void StreamConsumerGroupClaimMessages() + public async Task StreamConsumerGroupClaimMessages() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -778,9 +774,9 @@ public void StreamConsumerGroupClaimMessages() } [Fact] - public void StreamConsumerGroupClaimMessagesReturningIds() + public async Task StreamConsumerGroupClaimMessagesReturningIds() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -826,14 +822,14 @@ public void StreamConsumerGroupClaimMessagesReturningIds() } [Fact] - public void StreamConsumerGroupReadMultipleOneReadBeginningOneReadNew() + public async Task StreamConsumerGroupReadMultipleOneReadBeginningOneReadNew() { // Create a group for each stream. One set to read from the beginning of the // stream and the other to begin reading only new messages. // Ask redis to read from the beginning of both stream, expect messages // for only the stream set to read from the beginning. - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); const string groupName = "test_group"; @@ -870,9 +866,9 @@ public void StreamConsumerGroupReadMultipleOneReadBeginningOneReadNew() } [Fact] - public void StreamConsumerGroupReadMultipleOnlyNewMessagesExpectNoResult() + public async Task StreamConsumerGroupReadMultipleOnlyNewMessagesExpectNoResult() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); const string groupName = "test_group"; @@ -902,9 +898,9 @@ public void StreamConsumerGroupReadMultipleOnlyNewMessagesExpectNoResult() } [Fact] - public void StreamConsumerGroupReadMultipleOnlyNewMessagesExpect1Result() + public async Task StreamConsumerGroupReadMultipleOnlyNewMessagesExpect1Result() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); const string groupName = "test_group"; @@ -941,9 +937,9 @@ public void StreamConsumerGroupReadMultipleOnlyNewMessagesExpect1Result() } [Fact] - public void StreamConsumerGroupReadMultipleRestrictCount() + public async Task StreamConsumerGroupReadMultipleRestrictCount() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); const string groupName = "test_group"; @@ -979,9 +975,9 @@ public void StreamConsumerGroupReadMultipleRestrictCount() } [Fact] - public void StreamConsumerGroupViewPendingInfoNoConsumers() + public async Task StreamConsumerGroupViewPendingInfoNoConsumers() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1001,9 +997,9 @@ public void StreamConsumerGroupViewPendingInfoNoConsumers() } [Fact] - public void StreamConsumerGroupViewPendingInfoWhenNothingPending() + public async Task StreamConsumerGroupViewPendingInfoWhenNothingPending() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1024,9 +1020,9 @@ public void StreamConsumerGroupViewPendingInfoWhenNothingPending() } [Fact] - public void StreamConsumerGroupViewPendingInfoSummary() + public async Task StreamConsumerGroupViewPendingInfoSummary() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1052,7 +1048,7 @@ public void StreamConsumerGroupViewPendingInfoSummary() Assert.Equal(4, pendingInfo.PendingMessageCount); Assert.Equal(id1, pendingInfo.LowestPendingMessageId); Assert.Equal(id4, pendingInfo.HighestPendingMessageId); - Assert.True(pendingInfo.Consumers.Length == 2); + Assert.Equal(2, pendingInfo.Consumers.Length); var consumer1Count = pendingInfo.Consumers.First(c => c.Name == consumer1).PendingMessageCount; var consumer2Count = pendingInfo.Consumers.First(c => c.Name == consumer2).PendingMessageCount; @@ -1064,7 +1060,7 @@ public void StreamConsumerGroupViewPendingInfoSummary() [Fact] public async Task StreamConsumerGroupViewPendingMessageInfo() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1099,9 +1095,9 @@ public async Task StreamConsumerGroupViewPendingMessageInfo() } [Fact] - public void StreamConsumerGroupViewPendingMessageInfoForConsumer() + public async Task StreamConsumerGroupViewPendingMessageInfoForConsumer() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1134,9 +1130,9 @@ public void StreamConsumerGroupViewPendingMessageInfoForConsumer() } [Fact] - public void StreamDeleteConsumer() + public async Task StreamDeleteConsumer() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1165,9 +1161,9 @@ public void StreamDeleteConsumer() } [Fact] - public void StreamDeleteConsumerGroup() + public async Task StreamDeleteConsumerGroup() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1194,9 +1190,9 @@ public void StreamDeleteConsumerGroup() } [Fact] - public void StreamDeleteMessage() + public async Task StreamDeleteMessage() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1206,7 +1202,7 @@ public void StreamDeleteMessage() var id3 = db.StreamAdd(key, "field3", "value3"); db.StreamAdd(key, "field4", "value4"); - var deletedCount = db.StreamDelete(key, new[] { id3 }); + var deletedCount = db.StreamDelete(key, [id3]); var messages = db.StreamRange(key); Assert.Equal(1, deletedCount); @@ -1214,9 +1210,9 @@ public void StreamDeleteMessage() } [Fact] - public void StreamDeleteMessages() + public async Task StreamDeleteMessages() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1226,7 +1222,7 @@ public void StreamDeleteMessages() var id3 = db.StreamAdd(key, "field3", "value3"); db.StreamAdd(key, "field4", "value4"); - var deletedCount = db.StreamDelete(key, new[] { id2, id3 }, CommandFlags.None); + var deletedCount = db.StreamDelete(key, [id2, id3], CommandFlags.None); var messages = db.StreamRange(key); Assert.Equal(2, deletedCount); @@ -1234,7 +1230,7 @@ public void StreamDeleteMessages() } [Fact] - public void StreamGroupInfoGet() + public async Task StreamGroupInfoGet() { var key = Me(); const string group1 = "test_group_1", @@ -1242,7 +1238,7 @@ public void StreamGroupInfoGet() consumer1 = "test_consumer_1", consumer2 = "test_consumer_2"; - using (var conn = Create(require: RedisFeatures.v5_0_0)) + await using (var conn = Create(require: RedisFeatures.v5_0_0)) { var db = conn.GetDatabase(); db.KeyDelete(key); @@ -1293,9 +1289,9 @@ static bool IsMessageId(string? value) } [Fact] - public void StreamGroupConsumerInfoGet() + public async Task StreamGroupConsumerInfoGet() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1325,9 +1321,9 @@ public void StreamGroupConsumerInfoGet() } [Fact] - public void StreamInfoGet() + public async Task StreamInfoGet() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1347,9 +1343,9 @@ public void StreamInfoGet() } [Fact] - public void StreamInfoGetWithEmptyStream() + public async Task StreamInfoGetWithEmptyStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1358,7 +1354,7 @@ public void StreamInfoGetWithEmptyStream() // to ensure it functions properly on an empty stream. Namely, the first-entry // and last-entry messages should be null. var id = db.StreamAdd(key, "field1", "value1"); - db.StreamDelete(key, new[] { id }); + db.StreamDelete(key, [id]); Assert.Equal(0, db.StreamLength(key)); @@ -1369,9 +1365,9 @@ public void StreamInfoGetWithEmptyStream() } [Fact] - public void StreamNoConsumerGroups() + public async Task StreamNoConsumerGroups() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1385,16 +1381,16 @@ public void StreamNoConsumerGroups() } [Fact] - public void StreamPendingNoMessagesOrConsumers() + public async Task StreamPendingNoMessagesOrConsumers() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); const string groupName = "test_group"; var id = db.StreamAdd(key, "field1", "value1"); - db.StreamDelete(key, new[] { id }); + db.StreamDelete(key, [id]); db.StreamCreateConsumerGroup(key, groupName, "0-0"); @@ -1444,9 +1440,9 @@ public void StreamPositionValidateNew() } [Fact] - public void StreamRead() + public async Task StreamRead() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1465,9 +1461,9 @@ public void StreamRead() } [Fact] - public void StreamReadEmptyStream() + public async Task StreamReadEmptyStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1476,7 +1472,7 @@ public void StreamReadEmptyStream() var id1 = db.StreamAdd(key, "field1", "value1"); // Delete the key to empty the stream. - db.StreamDelete(key, new[] { id1 }); + db.StreamDelete(key, [id1]); var len = db.StreamLength(key); // Read the entire stream from the beginning. @@ -1487,9 +1483,9 @@ public void StreamReadEmptyStream() } [Fact] - public void StreamReadEmptyStreams() + public async Task StreamReadEmptyStreams() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -1500,8 +1496,8 @@ public void StreamReadEmptyStreams() var id2 = db.StreamAdd(key2, "field2", "value2"); // Delete the key to empty the stream. - db.StreamDelete(key1, new[] { id1 }); - db.StreamDelete(key2, new[] { id2 }); + db.StreamDelete(key1, [id1]); + db.StreamDelete(key2, [id2]); var len1 = db.StreamLength(key1); var len2 = db.StreamLength(key2); @@ -1518,9 +1514,9 @@ public void StreamReadEmptyStreams() } [Fact] - public void StreamReadLastMessage() + public async Task StreamReadLastMessage() { - using var conn = Create(require: RedisFeatures.v7_4_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_4_0_rc1); var db = conn.GetDatabase(); var key1 = Me(); @@ -1536,9 +1532,9 @@ public void StreamReadLastMessage() } [Fact] - public void StreamReadExpectedExceptionInvalidCountMultipleStream() + public async Task StreamReadExpectedExceptionInvalidCountMultipleStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var streamPositions = new[] @@ -1550,9 +1546,9 @@ public void StreamReadExpectedExceptionInvalidCountMultipleStream() } [Fact] - public void StreamReadExpectedExceptionInvalidCountSingleStream() + public async Task StreamReadExpectedExceptionInvalidCountSingleStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1560,18 +1556,18 @@ public void StreamReadExpectedExceptionInvalidCountSingleStream() } [Fact] - public void StreamReadExpectedExceptionNullStreamList() + public async Task StreamReadExpectedExceptionNullStreamList() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); Assert.Throws(() => db.StreamRead(null!)); } [Fact] - public void StreamReadExpectedExceptionEmptyStreamList() + public async Task StreamReadExpectedExceptionEmptyStreamList() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var emptyList = Array.Empty(); @@ -1579,9 +1575,9 @@ public void StreamReadExpectedExceptionEmptyStreamList() } [Fact] - public void StreamReadMultipleStreams() + public async Task StreamReadMultipleStreams() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -1601,7 +1597,7 @@ public void StreamReadMultipleStreams() var streams = db.StreamRead(streamList); - Assert.True(streams.Length == 2); + Assert.Equal(2, streams.Length); Assert.Equal(key1, streams[0].Key); Assert.Equal(2, streams[0].Entries.Length); @@ -1615,9 +1611,9 @@ public void StreamReadMultipleStreams() } [Fact] - public void StreamReadMultipleStreamsLastMessage() + public async Task StreamReadMultipleStreamsLastMessage() { - using var conn = Create(require: RedisFeatures.v7_4_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_4_0_rc1); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -1638,12 +1634,12 @@ public void StreamReadMultipleStreamsLastMessage() db.StreamAdd(key2, "field7", "value7"); db.StreamAdd(key2, "field8", "value8"); - streamList = new[] { new StreamPosition(key1, "+"), new StreamPosition(key2, "+") }; + streamList = [new StreamPosition(key1, "+"), new StreamPosition(key2, "+")]; streams = db.StreamRead(streamList); Assert.NotNull(streams); - Assert.True(streams.Length == 2); + Assert.Equal(2, streams.Length); var stream1 = streams.Where(e => e.Key == key1).First(); Assert.NotNull(stream1.Entries); @@ -1657,9 +1653,9 @@ public void StreamReadMultipleStreamsLastMessage() } [Fact] - public void StreamReadMultipleStreamsWithCount() + public async Task StreamReadMultipleStreamsWithCount() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -1691,9 +1687,9 @@ public void StreamReadMultipleStreamsWithCount() } [Fact] - public void StreamReadMultipleStreamsWithReadPastSecondStream() + public async Task StreamReadMultipleStreamsWithReadPastSecondStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -1722,9 +1718,9 @@ public void StreamReadMultipleStreamsWithReadPastSecondStream() } [Fact] - public void StreamReadMultipleStreamsWithEmptyResponse() + public async Task StreamReadMultipleStreamsWithEmptyResponse() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -1749,9 +1745,9 @@ public void StreamReadMultipleStreamsWithEmptyResponse() } [Fact] - public void StreamReadPastEndOfStream() + public async Task StreamReadPastEndOfStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1766,9 +1762,9 @@ public void StreamReadPastEndOfStream() } [Fact] - public void StreamReadRange() + public async Task StreamReadRange() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1784,9 +1780,9 @@ public void StreamReadRange() } [Fact] - public void StreamReadRangeOfEmptyStream() + public async Task StreamReadRangeOfEmptyStream() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1794,7 +1790,7 @@ public void StreamReadRangeOfEmptyStream() var id1 = db.StreamAdd(key, "field1", "value1"); var id2 = db.StreamAdd(key, "field2", "value2"); - var deleted = db.StreamDelete(key, new[] { id1, id2 }); + var deleted = db.StreamDelete(key, [id1, id2]); var entries = db.StreamRange(key); @@ -1804,9 +1800,9 @@ public void StreamReadRangeOfEmptyStream() } [Fact] - public void StreamReadRangeWithCount() + public async Task StreamReadRangeWithCount() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1821,9 +1817,9 @@ public void StreamReadRangeWithCount() } [Fact] - public void StreamReadRangeReverse() + public async Task StreamReadRangeReverse() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1839,9 +1835,9 @@ public void StreamReadRangeReverse() } [Fact] - public void StreamReadRangeReverseWithCount() + public async Task StreamReadRangeReverseWithCount() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1856,9 +1852,9 @@ public void StreamReadRangeReverseWithCount() } [Fact] - public void StreamReadWithAfterIdAndCount_1() + public async Task StreamReadWithAfterIdAndCount_1() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1875,9 +1871,9 @@ public void StreamReadWithAfterIdAndCount_1() } [Fact] - public void StreamReadWithAfterIdAndCount_2() + public async Task StreamReadWithAfterIdAndCount_2() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1896,9 +1892,9 @@ public void StreamReadWithAfterIdAndCount_2() } [Fact] - public void StreamTrimLength() + public async Task StreamTrimLength() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1917,9 +1913,9 @@ public void StreamTrimLength() } [Fact] - public void StreamVerifyLength() + public async Task StreamVerifyLength() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1936,7 +1932,7 @@ public void StreamVerifyLength() [Fact] public async Task AddWithApproxCountAsync() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1944,9 +1940,9 @@ public async Task AddWithApproxCountAsync() } [Fact] - public void AddWithApproxCount() + public async Task AddWithApproxCount() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1954,9 +1950,9 @@ public void AddWithApproxCount() } [Fact] - public void StreamReadGroupWithNoAckShowsNoPendingMessages() + public async Task StreamReadGroupWithNoAckShowsNoPendingMessages() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key = Me(); @@ -1981,9 +1977,9 @@ public void StreamReadGroupWithNoAckShowsNoPendingMessages() } [Fact] - public void StreamReadGroupMultiStreamWithNoAckShowsNoPendingMessages() + public async Task StreamReadGroupMultiStreamWithNoAckShowsNoPendingMessages() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var key1 = Me() + "a"; @@ -2001,11 +1997,10 @@ public void StreamReadGroupMultiStreamWithNoAckShowsNoPendingMessages() db.StreamCreateConsumerGroup(key2, groupName, StreamPosition.NewMessages); db.StreamReadGroup( - new[] - { + [ new StreamPosition(key1, StreamPosition.NewMessages), new StreamPosition(key2, StreamPosition.NewMessages), - }, + ], groupName, consumer, noAck: true); @@ -2020,19 +2015,18 @@ public void StreamReadGroupMultiStreamWithNoAckShowsNoPendingMessages() [Fact] public async Task StreamReadIndexerUsage() { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); var db = conn.GetDatabase(); var streamName = Me(); await db.StreamAddAsync( streamName, - new[] - { + [ new NameValueEntry("x", "blah"), new NameValueEntry("msg", /*lang=json,strict*/ @"{""name"":""test"",""id"":123}"), new NameValueEntry("y", "more blah"), - }); + ]); var streamResult = await db.StreamRangeAsync(streamName, count: 1000); var evntJson = streamResult diff --git a/tests/StackExchange.Redis.Tests/StringTests.cs b/tests/StackExchange.Redis.Tests/StringTests.cs index d430b90a6..85bcc7dd5 100644 --- a/tests/StackExchange.Redis.Tests/StringTests.cs +++ b/tests/StackExchange.Redis.Tests/StringTests.cs @@ -4,7 +4,6 @@ using System.Text; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -12,15 +11,12 @@ namespace StackExchange.Redis.Tests; /// Tests for . /// [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class StringTests : TestBase +public class StringTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public StringTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] public async Task Append() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var server = GetServer(conn); @@ -54,7 +50,7 @@ public async Task Append() [Fact] public async Task Set() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -73,7 +69,7 @@ public async Task Set() [Fact] public async Task SetEmpty() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -91,7 +87,7 @@ public async Task SetEmpty() [Fact] public async Task StringGetSetExpiryNoValue() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -105,7 +101,7 @@ public async Task StringGetSetExpiryNoValue() [Fact] public async Task StringGetSetExpiryRelative() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -124,7 +120,7 @@ public async Task StringGetSetExpiryRelative() [Fact] public async Task StringGetSetExpiryAbsolute() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -148,7 +144,7 @@ public async Task StringGetSetExpiryAbsolute() [Fact] public async Task StringGetSetExpiryPersist() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -165,7 +161,7 @@ public async Task StringGetSetExpiryPersist() [Fact] public async Task GetLease() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -182,7 +178,7 @@ public async Task GetLease() [Fact] public async Task GetLeaseAsStream() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -202,9 +198,9 @@ public async Task GetLeaseAsStream() } [Fact] - public void GetDelete() + public async Task GetDelete() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var prefix = Me(); @@ -226,7 +222,7 @@ public void GetDelete() [Fact] public async Task GetDeleteAsync() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var prefix = Me(); @@ -248,7 +244,7 @@ public async Task GetDeleteAsync() [Fact] public async Task SetNotExists() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var prefix = Me(); @@ -284,7 +280,7 @@ public async Task SetNotExists() [Fact] public async Task SetKeepTtl() { - using var conn = Create(require: RedisFeatures.v6_0_0); + await using var conn = Create(require: RedisFeatures.v6_0_0); var db = conn.GetDatabase(); var prefix = Me(); @@ -322,7 +318,7 @@ public async Task SetKeepTtl() [Fact] public async Task SetAndGet() { - using var conn = Create(require: RedisFeatures.v6_2_0); + await using var conn = Create(require: RedisFeatures.v6_2_0); var db = conn.GetDatabase(); var prefix = Me(); @@ -390,7 +386,7 @@ public async Task SetAndGet() [Fact] public async Task SetNotExistsAndGet() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); @@ -420,7 +416,7 @@ public async Task SetNotExistsAndGet() [Fact] public async Task Ranges() { - using var conn = Create(require: RedisFeatures.v2_1_8); + await using var conn = Create(require: RedisFeatures.v2_1_8); var db = conn.GetDatabase(); var key = Me(); @@ -439,7 +435,7 @@ public async Task Ranges() [Fact] public async Task IncrDecr() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -466,7 +462,7 @@ public async Task IncrDecr() [Fact] public async Task IncrDecrFloat() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var key = Me(); @@ -494,7 +490,7 @@ public async Task IncrDecrFloat() [Fact] public async Task GetRange() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -511,7 +507,7 @@ public async Task GetRange() [Fact] public async Task BitCount() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var key = Me(); @@ -539,7 +535,7 @@ public async Task BitCount() [Fact] public async Task BitCountWithBitUnit() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -563,7 +559,7 @@ public async Task BitCountWithBitUnit() [Fact] public async Task BitOp() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var prefix = Me(); @@ -574,9 +570,9 @@ public async Task BitOp() db.StringSet(key2, new byte[] { 6 }, flags: CommandFlags.FireAndForget); db.StringSet(key3, new byte[] { 12 }, flags: CommandFlags.FireAndForget); - var len_and = db.StringBitOperationAsync(Bitwise.And, "and", new RedisKey[] { key1, key2, key3 }); - var len_or = db.StringBitOperationAsync(Bitwise.Or, "or", new RedisKey[] { key1, key2, key3 }); - var len_xor = db.StringBitOperationAsync(Bitwise.Xor, "xor", new RedisKey[] { key1, key2, key3 }); + var len_and = db.StringBitOperationAsync(Bitwise.And, "and", [key1, key2, key3]); + var len_or = db.StringBitOperationAsync(Bitwise.Or, "or", [key1, key2, key3]); + var len_xor = db.StringBitOperationAsync(Bitwise.Xor, "xor", [key1, key2, key3]); var len_not = db.StringBitOperationAsync(Bitwise.Not, "not", key1); Assert.Equal(1, await len_and); @@ -598,7 +594,7 @@ public async Task BitOp() [Fact] public async Task BitOpExtended() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var keyX = prefix + "X"; @@ -607,7 +603,7 @@ public async Task BitOpExtended() var keyY3 = prefix + "Y3"; // Clean up keys - db.KeyDelete(new RedisKey[] { keyX, keyY1, keyY2, keyY3 }, CommandFlags.FireAndForget); + db.KeyDelete([keyX, keyY1, keyY2, keyY3], CommandFlags.FireAndForget); // Set up test data with more complex patterns // X = 11110000 (240) @@ -622,7 +618,7 @@ public async Task BitOpExtended() // Test DIFF: X ∧ ¬(Y1 ∨ Y2 ∨ Y3) // Y1 ∨ Y2 ∨ Y3 = 170 | 85 | 204 = 255 // X ∧ ¬(Y1 ∨ Y2 ∨ Y3) = 240 & ~255 = 240 & 0 = 0 - var len_diff = await db.StringBitOperationAsync(Bitwise.Diff, "diff", new RedisKey[] { keyX, keyY1, keyY2, keyY3 }); + var len_diff = await db.StringBitOperationAsync(Bitwise.Diff, "diff", [keyX, keyY1, keyY2, keyY3]); Assert.Equal(1, len_diff); var r_diff = ((byte[]?)(await db.StringGetAsync("diff")))?.Single(); Assert.Equal((byte)0, r_diff); @@ -631,7 +627,7 @@ public async Task BitOpExtended() // ¬X = ~240 = 15 // Y1 ∨ Y2 ∨ Y3 = 255 // ¬X ∧ (Y1 ∨ Y2 ∨ Y3) = 15 & 255 = 15 - var len_diff1 = await db.StringBitOperationAsync(Bitwise.Diff1, "diff1", new RedisKey[] { keyX, keyY1, keyY2, keyY3 }); + var len_diff1 = await db.StringBitOperationAsync(Bitwise.Diff1, "diff1", [keyX, keyY1, keyY2, keyY3]); Assert.Equal(1, len_diff1); var r_diff1 = ((byte[]?)(await db.StringGetAsync("diff1")))?.Single(); Assert.Equal((byte)15, r_diff1); @@ -639,7 +635,7 @@ public async Task BitOpExtended() // Test ANDOR: X ∧ (Y1 ∨ Y2 ∨ Y3) // Y1 ∨ Y2 ∨ Y3 = 255 // X ∧ (Y1 ∨ Y2 ∨ Y3) = 240 & 255 = 240 - var len_andor = await db.StringBitOperationAsync(Bitwise.AndOr, "andor", new RedisKey[] { keyX, keyY1, keyY2, keyY3 }); + var len_andor = await db.StringBitOperationAsync(Bitwise.AndOr, "andor", [keyX, keyY1, keyY2, keyY3]); Assert.Equal(1, len_andor); var r_andor = ((byte[]?)(await db.StringGetAsync("andor")))?.Single(); Assert.Equal((byte)240, r_andor); @@ -647,7 +643,7 @@ public async Task BitOpExtended() // Test ONE: bits set in exactly one bitmap // For X=240, Y1=170, Y2=85, Y3=204 // We need to count bits that appear in exactly one of these values - var len_one = await db.StringBitOperationAsync(Bitwise.One, "one", new RedisKey[] { keyX, keyY1, keyY2, keyY3 }); + var len_one = await db.StringBitOperationAsync(Bitwise.One, "one", [keyX, keyY1, keyY2, keyY3]); Assert.Equal(1, len_one); var r_one = ((byte[]?)(await db.StringGetAsync("one")))?.Single(); @@ -667,42 +663,42 @@ public async Task BitOpExtended() [Fact] public async Task BitOpTwoOperands() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var key1 = prefix + "1"; var key2 = prefix + "2"; // Clean up keys - db.KeyDelete(new RedisKey[] { key1, key2 }, CommandFlags.FireAndForget); + db.KeyDelete([key1, key2], CommandFlags.FireAndForget); // Test with two operands: key1=10101010 (170), key2=11001100 (204) db.StringSet(key1, new byte[] { 170 }, flags: CommandFlags.FireAndForget); db.StringSet(key2, new byte[] { 204 }, flags: CommandFlags.FireAndForget); // Test DIFF: key1 ∧ ¬key2 = 170 & ~204 = 170 & 51 = 34 - var len_diff = await db.StringBitOperationAsync(Bitwise.Diff, "diff2", new RedisKey[] { key1, key2 }); + var len_diff = await db.StringBitOperationAsync(Bitwise.Diff, "diff2", [key1, key2]); Assert.Equal(1, len_diff); var r_diff = ((byte[]?)(await db.StringGetAsync("diff2")))?.Single(); Assert.Equal((byte)(170 & ~204), r_diff); // Test ONE with two operands (should be equivalent to XOR) - var len_one = await db.StringBitOperationAsync(Bitwise.One, "one2", new RedisKey[] { key1, key2 }); + var len_one = await db.StringBitOperationAsync(Bitwise.One, "one2", [key1, key2]); Assert.Equal(1, len_one); var r_one = ((byte[]?)(await db.StringGetAsync("one2")))?.Single(); Assert.Equal((byte)(170 ^ 204), r_one); // Verify ONE equals XOR for two operands - var len_xor = await db.StringBitOperationAsync(Bitwise.Xor, "xor2", new RedisKey[] { key1, key2 }); + var len_xor = await db.StringBitOperationAsync(Bitwise.Xor, "xor2", [key1, key2]); Assert.Equal(1, len_xor); var r_xor = ((byte[]?)(await db.StringGetAsync("xor2")))?.Single(); Assert.Equal(r_one, r_xor); } [Fact] - public void BitOpDiff() + public async Task BitOpDiff() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var keyX = prefix + "X"; @@ -711,7 +707,7 @@ public void BitOpDiff() var keyResult = prefix + "result"; // Clean up keys - db.KeyDelete(new RedisKey[] { keyX, keyY1, keyY2, keyResult }, CommandFlags.FireAndForget); + db.KeyDelete([keyX, keyY1, keyY2, keyResult], CommandFlags.FireAndForget); // Set up test data: X=11110000, Y1=10100000, Y2=01010000 // Expected DIFF result: X ∧ ¬(Y1 ∨ Y2) = 11110000 ∧ ¬(11110000) = 00000000 @@ -719,7 +715,7 @@ public void BitOpDiff() db.StringSet(keyY1, new byte[] { 0b10100000 }, flags: CommandFlags.FireAndForget); db.StringSet(keyY2, new byte[] { 0b01010000 }, flags: CommandFlags.FireAndForget); - var length = db.StringBitOperation(Bitwise.Diff, keyResult, new RedisKey[] { keyX, keyY1, keyY2 }); + var length = db.StringBitOperation(Bitwise.Diff, keyResult, [keyX, keyY1, keyY2]); Assert.Equal(1, length); var result = ((byte[]?)db.StringGet(keyResult))?.Single(); @@ -728,9 +724,9 @@ public void BitOpDiff() } [Fact] - public void BitOpDiff1() + public async Task BitOpDiff1() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var keyX = prefix + "X"; @@ -739,7 +735,7 @@ public void BitOpDiff1() var keyResult = prefix + "result"; // Clean up keys - db.KeyDelete(new RedisKey[] { keyX, keyY1, keyY2, keyResult }, CommandFlags.FireAndForget); + db.KeyDelete([keyX, keyY1, keyY2, keyResult], CommandFlags.FireAndForget); // Set up test data: X=11000000, Y1=10100000, Y2=01010000 // Expected DIFF1 result: ¬X ∧ (Y1 ∨ Y2) = ¬11000000 ∧ (10100000 ∨ 01010000) = 00111111 ∧ 11110000 = 00110000 @@ -747,7 +743,7 @@ public void BitOpDiff1() db.StringSet(keyY1, new byte[] { 0b10100000 }, flags: CommandFlags.FireAndForget); db.StringSet(keyY2, new byte[] { 0b01010000 }, flags: CommandFlags.FireAndForget); - var length = db.StringBitOperation(Bitwise.Diff1, keyResult, new RedisKey[] { keyX, keyY1, keyY2 }); + var length = db.StringBitOperation(Bitwise.Diff1, keyResult, [keyX, keyY1, keyY2]); Assert.Equal(1, length); var result = ((byte[]?)db.StringGet(keyResult))?.Single(); @@ -756,9 +752,9 @@ public void BitOpDiff1() } [Fact] - public void BitOpAndOr() + public async Task BitOpAndOr() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var keyX = prefix + "X"; @@ -767,7 +763,7 @@ public void BitOpAndOr() var keyResult = prefix + "result"; // Clean up keys - db.KeyDelete(new RedisKey[] { keyX, keyY1, keyY2, keyResult }, CommandFlags.FireAndForget); + db.KeyDelete([keyX, keyY1, keyY2, keyResult], CommandFlags.FireAndForget); // Set up test data: X=11110000, Y1=10100000, Y2=01010000 // Expected ANDOR result: X ∧ (Y1 ∨ Y2) = 11110000 ∧ (10100000 ∨ 01010000) = 11110000 ∧ 11110000 = 11110000 @@ -775,7 +771,7 @@ public void BitOpAndOr() db.StringSet(keyY1, new byte[] { 0b10100000 }, flags: CommandFlags.FireAndForget); db.StringSet(keyY2, new byte[] { 0b01010000 }, flags: CommandFlags.FireAndForget); - var length = db.StringBitOperation(Bitwise.AndOr, keyResult, new RedisKey[] { keyX, keyY1, keyY2 }); + var length = db.StringBitOperation(Bitwise.AndOr, keyResult, [keyX, keyY1, keyY2]); Assert.Equal(1, length); var result = ((byte[]?)db.StringGet(keyResult))?.Single(); @@ -784,9 +780,9 @@ public void BitOpAndOr() } [Fact] - public void BitOpOne() + public async Task BitOpOne() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var key1 = prefix + "1"; @@ -795,7 +791,7 @@ public void BitOpOne() var keyResult = prefix + "result"; // Clean up keys - db.KeyDelete(new RedisKey[] { key1, key2, key3, keyResult }, CommandFlags.FireAndForget); + db.KeyDelete([key1, key2, key3, keyResult], CommandFlags.FireAndForget); // Set up test data: key1=10100000, key2=01010000, key3=00110000 // Expected ONE result: bits set in exactly one bitmap = 11000000 @@ -803,7 +799,7 @@ public void BitOpOne() db.StringSet(key2, new byte[] { 0b01010000 }, flags: CommandFlags.FireAndForget); db.StringSet(key3, new byte[] { 0b00110000 }, flags: CommandFlags.FireAndForget); - var length = db.StringBitOperation(Bitwise.One, keyResult, new RedisKey[] { key1, key2, key3 }); + var length = db.StringBitOperation(Bitwise.One, keyResult, [key1, key2, key3]); Assert.Equal(1, length); var result = ((byte[]?)db.StringGet(keyResult))?.Single(); @@ -814,7 +810,7 @@ public void BitOpOne() [Fact] public async Task BitOpDiffAsync() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var keyX = prefix + "X"; @@ -822,14 +818,14 @@ public async Task BitOpDiffAsync() var keyResult = prefix + "result"; // Clean up keys - db.KeyDelete(new RedisKey[] { keyX, keyY1, keyResult }, CommandFlags.FireAndForget); + db.KeyDelete([keyX, keyY1, keyResult], CommandFlags.FireAndForget); // Set up test data: X=11110000, Y1=10100000 // Expected DIFF result: X ∧ ¬Y1 = 11110000 ∧ 01011111 = 01010000 db.StringSet(keyX, new byte[] { 0b11110000 }, flags: CommandFlags.FireAndForget); db.StringSet(keyY1, new byte[] { 0b10100000 }, flags: CommandFlags.FireAndForget); - var length = await db.StringBitOperationAsync(Bitwise.Diff, keyResult, new RedisKey[] { keyX, keyY1 }); + var length = await db.StringBitOperationAsync(Bitwise.Diff, keyResult, [keyX, keyY1]); Assert.Equal(1, length); var result = ((byte[]?)await db.StringGetAsync(keyResult))?.Single(); @@ -838,9 +834,9 @@ public async Task BitOpDiffAsync() } [Fact] - public void BitOpEdgeCases() + public async Task BitOpEdgeCases() { - using var conn = Create(require: RedisFeatures.v8_2_0_rc1); + await using var conn = Create(require: RedisFeatures.v8_2_0_rc1); var db = conn.GetDatabase(); var prefix = Me(); var keyEmpty = prefix + "empty"; @@ -848,20 +844,20 @@ public void BitOpEdgeCases() var keyResult = prefix + "result"; // Clean up keys - db.KeyDelete(new RedisKey[] { keyEmpty, keyNonEmpty, keyResult }, CommandFlags.FireAndForget); + db.KeyDelete([keyEmpty, keyNonEmpty, keyResult], CommandFlags.FireAndForget); // Test with empty bitmap db.StringSet(keyNonEmpty, new byte[] { 0b11110000 }, flags: CommandFlags.FireAndForget); // DIFF with empty key should return the first key - var length = db.StringBitOperation(Bitwise.Diff, keyResult, new RedisKey[] { keyNonEmpty, keyEmpty }); + var length = db.StringBitOperation(Bitwise.Diff, keyResult, [keyNonEmpty, keyEmpty]); Assert.Equal(1, length); var result = ((byte[]?)db.StringGet(keyResult))?.Single(); Assert.Equal((byte)0b11110000, result); // ONE with single key should return that key - length = db.StringBitOperation(Bitwise.One, keyResult, new RedisKey[] { keyNonEmpty }); + length = db.StringBitOperation(Bitwise.One, keyResult, [keyNonEmpty]); Assert.Equal(1, length); result = ((byte[]?)db.StringGet(keyResult))?.Single(); @@ -871,7 +867,7 @@ public void BitOpEdgeCases() [Fact] public async Task BitPosition() { - using var conn = Create(require: RedisFeatures.v2_6_0); + await using var conn = Create(require: RedisFeatures.v2_6_0); var db = conn.GetDatabase(); var key = Me(); @@ -899,7 +895,7 @@ public async Task BitPosition() [Fact] public async Task BitPositionWithBitUnit() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key = Me(); @@ -916,7 +912,7 @@ public async Task BitPositionWithBitUnit() [Fact] public async Task RangeString() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var key = Me(); @@ -928,7 +924,7 @@ public async Task RangeString() [Fact] public async Task HashStringLengthAsync() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -941,9 +937,9 @@ public async Task HashStringLengthAsync() } [Fact] - public void HashStringLength() + public async Task HashStringLength() { - using var conn = Create(require: RedisFeatures.v3_2_0); + await using var conn = Create(require: RedisFeatures.v3_2_0); var db = conn.GetDatabase(); var key = Me(); @@ -954,9 +950,9 @@ public void HashStringLength() } [Fact] - public void LongestCommonSubsequence() + public async Task LongestCommonSubsequence() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key1 = Me() + "1"; @@ -996,7 +992,7 @@ public void LongestCommonSubsequence() [Fact] public async Task LongestCommonSubsequenceAsync() { - using var conn = Create(require: RedisFeatures.v7_0_0_rc1); + await using var conn = Create(require: RedisFeatures.v7_0_0_rc1); var db = conn.GetDatabase(); var key1 = Me() + "1"; diff --git a/tests/StackExchange.Redis.Tests/SyncContextTests.cs b/tests/StackExchange.Redis.Tests/SyncContextTests.cs index fcc183ca4..8eddc9f1d 100644 --- a/tests/StackExchange.Redis.Tests/SyncContextTests.cs +++ b/tests/StackExchange.Redis.Tests/SyncContextTests.cs @@ -3,14 +3,11 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests { - public class SyncContextTests : TestBase + public class SyncContextTests(ITestOutputHelper testOutput) : TestBase(testOutput) { - public SyncContextTests(ITestOutputHelper testOutput) : base(testOutput) { } - /* Note A (referenced below) * * When sync-context is *enabled*, we don't validate OpCount > 0 - this is because *with the additional checks*, @@ -44,10 +41,10 @@ private void AssertState(bool continueOnCapturedContext, MySyncContext ctx) } [Fact] - public void SyncPing() + public async Task SyncPing() { using var ctx = new MySyncContext(Writer); - using var conn = Create(); + await using var conn = Create(); Assert.Equal(0, ctx.OpCount); var db = conn.GetDatabase(); db.Ping(); @@ -60,7 +57,7 @@ public void SyncPing() public async Task AsyncPing(bool continueOnCapturedContext) { using var ctx = new MySyncContext(Writer); - using var conn = Create(); + await using var conn = Create(); Assert.Equal(0, ctx.OpCount); var db = conn.GetDatabase(); Log($"Context before await: {ctx}"); @@ -70,10 +67,10 @@ public async Task AsyncPing(bool continueOnCapturedContext) } [Fact] - public void SyncConfigure() + public async Task SyncConfigure() { using var ctx = new MySyncContext(Writer); - using var conn = Create(); + await using var conn = Create(); Assert.Equal(0, ctx.OpCount); Assert.True(conn.Configure()); Assert.Equal(0, ctx.OpCount); @@ -85,7 +82,7 @@ public void SyncConfigure() public async Task AsyncConfigure(bool continueOnCapturedContext) { using var ctx = new MySyncContext(Writer); - using var conn = Create(); + await using var conn = Create(); Log($"Context initial: {ctx}"); await Task.Delay(500); diff --git a/tests/StackExchange.Redis.Tests/TaskExtensions.cs b/tests/StackExchange.Redis.Tests/TaskExtensions.cs new file mode 100644 index 000000000..19db48f7c --- /dev/null +++ b/tests/StackExchange.Redis.Tests/TaskExtensions.cs @@ -0,0 +1,49 @@ +#if !NET +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace StackExchange.Redis.Tests; + +internal static class TaskExtensions +{ + // suboptimal polyfill version of the .NET 6+ API; I'm not recommending this for production use, + // but it's good enough for tests + public static Task WaitAsync(this Task task, CancellationToken cancellationToken) + { + if (task.IsCompleted || !cancellationToken.CanBeCanceled) return task; + return Wrap(task, cancellationToken); + + static async Task Wrap(Task task, CancellationToken cancellationToken) + { + var tcs = new TaskCompletionSource(); + using var reg = cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken)); + _ = task.ContinueWith(t => + { + if (t.IsCanceled) tcs.TrySetCanceled(); + else if (t.IsFaulted) tcs.TrySetException(t.Exception!); + else tcs.TrySetResult(t.Result); + }); + return await tcs.Task; + } + } + + public static Task WaitAsync(this Task task, TimeSpan timeout) + { + if (task.IsCompleted) return task; + return Wrap(task, timeout); + + static async Task Wrap(Task task, TimeSpan timeout) + { + Task other = Task.Delay(timeout); + var first = await Task.WhenAny(task, other); + if (ReferenceEquals(first, other)) + { + throw new TimeoutException(); + } + return await task; + } + } +} + +#endif diff --git a/tests/StackExchange.Redis.Tests/TestBase.cs b/tests/StackExchange.Redis.Tests/TestBase.cs index 230438d07..94a14ee32 100644 --- a/tests/StackExchange.Redis.Tests/TestBase.cs +++ b/tests/StackExchange.Redis.Tests/TestBase.cs @@ -10,7 +10,6 @@ using StackExchange.Redis.Profiling; using StackExchange.Redis.Tests.Helpers; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; @@ -18,17 +17,9 @@ public abstract class TestBase : IDisposable { private ITestOutputHelper Output { get; } protected TextWriterOutputHelper Writer { get; } - protected static bool RunningInCI { get; } = Environment.GetEnvironmentVariable("APPVEYOR") != null; protected virtual string GetConfiguration() => GetDefaultConfiguration(); internal static string GetDefaultConfiguration() => TestConfig.Current.PrimaryServerAndPort; - /// - /// Gives the current TestContext, propulated by the runner (this type of thing will be built-in in xUnit 3.x). - /// - protected TestContext Context => _context.Value!; - private static readonly AsyncLocal _context = new(); - public static void SetContext(TestContext context) => _context.Value = context; - private readonly SharedConnectionFixture? _fixture; protected bool SharedFixtureAvailable => _fixture != null && _fixture.IsEnabled && !HighIntegrity; @@ -37,8 +28,7 @@ protected TestBase(ITestOutputHelper output, SharedConnectionFixture? fixture = { Output = output; Output.WriteFrameworkVersion(); - Output.WriteLine(" Context: " + Context.ToString()); - Writer = new TextWriterOutputHelper(output, TestConfig.Current.LogToConsole); + Writer = new TextWriterOutputHelper(output); _fixture = fixture; ClearAmbientFailures(); } @@ -60,22 +50,8 @@ public static void Log(TextWriter output, string message) { output?.WriteLine(Time() + ": " + message); } - if (TestConfig.Current.LogToConsole) - { - Console.WriteLine(message); - } - } - protected void Log(string? message, params object?[] args) - { - lock (Output) - { - Output.WriteLine(Time() + ": " + message, args); - } - if (TestConfig.Current.LogToConsole) - { - Console.WriteLine(message ?? "", args); - } } + protected void Log(string? message, params object[] args) => Output.WriteLine(Time() + ": " + message, args); protected ProfiledCommandEnumerable Log(ProfilingSession session) { @@ -157,8 +133,8 @@ protected void OnInternalError(object? sender, InternalErrorEventArgs e) private static readonly AsyncLocal sharedFailCount = new AsyncLocal(); private volatile int expectedFailCount; - private readonly List privateExceptions = new List(); - private static readonly List backgroundExceptions = new List(); + private readonly List privateExceptions = []; + private static readonly List backgroundExceptions = []; public void ClearAmbientFailures() { @@ -207,7 +183,7 @@ public void Teardown() Log(item); } } - Skip.Inconclusive($"There were {privateFailCount} private and {sharedFailCount.Value} ambient exceptions; expected {expectedFailCount}."); + Assert.Skip($"There were {privateFailCount} private and {sharedFailCount.Value} ambient exceptions; expected {expectedFailCount}."); } var pool = SocketManager.Shared?.SchedulerPool; Log($"Service Counts: (Scheduler) Queue: {pool?.TotalServicedByQueue.ToString()}, Pool: {pool?.TotalServicedByPool.ToString()}, Workers: {pool?.WorkerCount.ToString()}, Available: {pool?.AvailableCount.ToString()}"); @@ -270,22 +246,23 @@ internal virtual IInternalConnectionMultiplexer Create( } // Default to protocol context if not explicitly passed in - protocol ??= Context.Test.Protocol; + protocol ??= TestContext.Current.GetProtocol(); // Share a connection if instructed to and we can - many specifics mean no sharing bool highIntegrity = HighIntegrity; if (shared && expectedFailCount == 0 && _fixture != null && _fixture.IsEnabled + && GetConfiguration() == GetDefaultConfiguration() && CanShare(allowAdmin, password, tieBreaker, fail, disabledCommands, enabledCommands, channelPrefix, proxy, configuration, defaultDatabase, backlogPolicy, highIntegrity)) { configuration = GetConfiguration(); var fixtureConn = _fixture.GetConnection(this, protocol.Value, caller: caller); // Only return if we match - ThrowIfIncorrectProtocol(fixtureConn, protocol); + TestBase.ThrowIfIncorrectProtocol(fixtureConn, protocol); if (configuration == _fixture.Configuration) { - ThrowIfBelowMinVersion(fixtureConn, require); + TestBase.ThrowIfBelowMinVersion(fixtureConn, require); return fixtureConn; } } @@ -316,8 +293,8 @@ internal virtual IInternalConnectionMultiplexer Create( highIntegrity, caller); - ThrowIfIncorrectProtocol(conn, protocol); - ThrowIfBelowMinVersion(conn, require); + TestBase.ThrowIfIncorrectProtocol(conn, protocol); + TestBase.ThrowIfBelowMinVersion(conn, require); conn.InternalError += OnInternalError; conn.ConnectionFailed += OnConnectionFailed; @@ -351,7 +328,7 @@ internal static bool CanShare( && backlogPolicy == null && !highIntegrity; - internal void ThrowIfIncorrectProtocol(IInternalConnectionMultiplexer conn, RedisProtocol? requiredProtocol) + internal static void ThrowIfIncorrectProtocol(IInternalConnectionMultiplexer conn, RedisProtocol? requiredProtocol) { if (requiredProtocol is null) { @@ -361,14 +338,11 @@ internal void ThrowIfIncorrectProtocol(IInternalConnectionMultiplexer conn, Redi var serverProtocol = conn.GetServerEndPoint(conn.GetEndPoints()[0]).Protocol ?? RedisProtocol.Resp2; if (serverProtocol != requiredProtocol) { - throw new SkipTestException($"Requires protocol {requiredProtocol}, but connection is {serverProtocol}.") - { - MissingFeatures = $"Protocol {requiredProtocol}.", - }; + Assert.Skip($"Requires protocol {requiredProtocol}, but connection is {serverProtocol}."); } } - internal void ThrowIfBelowMinVersion(IInternalConnectionMultiplexer conn, Version? requiredVersion) + internal static void ThrowIfBelowMinVersion(IInternalConnectionMultiplexer conn, Version? requiredVersion) { if (requiredVersion is null) { @@ -378,10 +352,7 @@ internal void ThrowIfBelowMinVersion(IInternalConnectionMultiplexer conn, Versio var serverVersion = conn.GetServerEndPoint(conn.GetEndPoints()[0]).Version; if (!serverVersion.IsAtLeast(requiredVersion)) { - throw new SkipTestException($"Requires server version {requiredVersion}, but server is only {serverVersion}.") - { - MissingFeatures = $"Server version >= {requiredVersion}.", - }; + Assert.Skip($"Requires server version {requiredVersion}, but server is only {serverVersion}."); } } @@ -418,11 +389,11 @@ public static ConnectionMultiplexer CreateDefault( var config = ConfigurationOptions.Parse(configuration); if (disabledCommands != null && disabledCommands.Length != 0) { - config.CommandMap = CommandMap.Create(new HashSet(disabledCommands), false); + config.CommandMap = CommandMap.Create([.. disabledCommands], false); } else if (enabledCommands != null && enabledCommands.Length != 0) { - config.CommandMap = CommandMap.Create(new HashSet(enabledCommands), true); + config.CommandMap = CommandMap.Create([.. enabledCommands], true); } if (Debugger.IsAttached) @@ -471,7 +442,7 @@ public static ConnectionMultiplexer CreateDefault( { // If fail is true, we throw. Assert.False(fail, failMessage + "Server is not available"); - Skip.Inconclusive(failMessage + "Server is not available"); + Assert.Skip(failMessage + "Server is not available"); } if (output != null) { @@ -502,13 +473,23 @@ public static ConnectionMultiplexer CreateDefault( } public virtual string Me([CallerFilePath] string? filePath = null, [CallerMemberName] string? caller = null) => - Environment.Version.ToString() + Path.GetFileNameWithoutExtension(filePath) + "-" + caller + Context.KeySuffix; + Environment.Version.ToString() + "-" + GetType().Name + "-" + Path.GetFileNameWithoutExtension(filePath) + "-" + caller + TestContext.Current.KeySuffix(); protected TimeSpan RunConcurrent(Action work, int threads, int timeout = 10000, [CallerMemberName] string? caller = null) { - if (work == null) throw new ArgumentNullException(nameof(work)); - if (threads < 1) throw new ArgumentOutOfRangeException(nameof(threads)); - if (string.IsNullOrWhiteSpace(caller)) caller = Me(); + if (work == null) + { + throw new ArgumentNullException(nameof(work)); + } + if (threads < 1) + { + throw new ArgumentOutOfRangeException(nameof(threads)); + } + if (string.IsNullOrWhiteSpace(caller)) + { + caller = Me(); + } + Stopwatch? watch = null; ManualResetEvent allDone = new ManualResetEvent(false); object token = new object(); diff --git a/tests/StackExchange.Redis.Tests/TransactionTests.cs b/tests/StackExchange.Redis.Tests/TransactionTests.cs index db4554bef..daee7ee00 100644 --- a/tests/StackExchange.Redis.Tests/TransactionTests.cs +++ b/tests/StackExchange.Redis.Tests/TransactionTests.cs @@ -1,20 +1,16 @@ using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; [RunPerProtocol] -[Collection(SharedConnectionFixture.Key)] -public class TransactionTests : TestBase +public class TransactionTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public TransactionTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void BasicEmptyTran() + public async Task BasicEmptyTran() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -28,9 +24,9 @@ public void BasicEmptyTran() } [Fact] - public void NestedTransactionThrows() + public async Task NestedTransactionThrows() { - using var conn = Create(); + await using var conn = Create(); var db = conn.GetDatabase(); var tran = db.CreateTransaction(); @@ -45,7 +41,7 @@ public void NestedTransactionThrows() [InlineData(true, true, true)] public async Task BasicTranWithExistsCondition(bool demandKeyExists, bool keyExists, bool expectTranResult) { - using var conn = Create(disabledCommands: new[] { "info", "config" }); + await using var conn = Create(disabledCommands: ["info", "config"]); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -92,7 +88,7 @@ public async Task BasicTranWithExistsCondition(bool demandKeyExists, bool keyExi [InlineData(null, null, false, false)] public async Task BasicTranWithEqualsCondition(string? expected, string? value, bool expectEqual, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -133,7 +129,7 @@ public async Task BasicTranWithEqualsCondition(string? expected, string? value, [InlineData(true, true, true)] public async Task BasicTranWithHashExistsCondition(bool demandKeyExists, bool keyExists, bool expectTranResult) { - using var conn = Create(disabledCommands: new[] { "info", "config" }); + await using var conn = Create(disabledCommands: ["info", "config"]); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -181,7 +177,7 @@ public async Task BasicTranWithHashExistsCondition(bool demandKeyExists, bool ke [InlineData(null, null, false, false)] public async Task BasicTranWithHashEqualsCondition(string? expected, string? value, bool expectEqual, bool expectedTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -245,7 +241,7 @@ private static TaskStatus SafeStatus(Task task) [InlineData(true, true, true)] public async Task BasicTranWithListExistsCondition(bool demandKeyExists, bool keyExists, bool expectTranResult) { - using var conn = Create(disabledCommands: new[] { "info", "config" }); + await using var conn = Create(disabledCommands: ["info", "config"]); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -292,7 +288,7 @@ public async Task BasicTranWithListExistsCondition(bool demandKeyExists, bool ke [InlineData(null, null, false, false)] public async Task BasicTranWithListEqualsCondition(string? expected, string? value, bool expectEqual, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -359,7 +355,7 @@ public enum ComparisonType [InlineData(null, ComparisonType.GreaterThan, 0L, false)] public async Task BasicTranWithStringLengthCondition(string? value, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -438,7 +434,7 @@ public async Task BasicTranWithStringLengthCondition(string? value, ComparisonTy [InlineData("", ComparisonType.GreaterThan, 0L, false)] public async Task BasicTranWithHashLengthCondition(string value, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -517,7 +513,7 @@ public async Task BasicTranWithHashLengthCondition(string value, ComparisonType [InlineData("", ComparisonType.GreaterThan, 0L, false)] public async Task BasicTranWithSetCardinalityCondition(string value, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -583,7 +579,7 @@ public async Task BasicTranWithSetCardinalityCondition(string value, ComparisonT [InlineData(true, true, true)] public async Task BasicTranWithSetContainsCondition(bool demandKeyExists, bool keyExists, bool expectTranResult) { - using var conn = Create(disabledCommands: new[] { "info", "config" }); + await using var conn = Create(disabledCommands: ["info", "config"]); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -637,7 +633,7 @@ public async Task BasicTranWithSetContainsCondition(bool demandKeyExists, bool k [InlineData("", ComparisonType.GreaterThan, 0L, false)] public async Task BasicTranWithSortedSetCardinalityCondition(string value, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -716,7 +712,7 @@ public async Task BasicTranWithSortedSetCardinalityCondition(string value, Compa [InlineData(0, 0, ComparisonType.GreaterThan, 0L, true)] public async Task BasicTranWithSortedSetRangeCountCondition(double min, double max, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -782,7 +778,7 @@ public async Task BasicTranWithSortedSetRangeCountCondition(double min, double m [InlineData(true, true, true)] public async Task BasicTranWithSortedSetContainsCondition(bool demandKeyExists, bool keyExists, bool expectTranResult) { - using var conn = Create(disabledCommands: new[] { "info", "config" }); + await using var conn = Create(disabledCommands: ["info", "config"]); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -830,7 +826,7 @@ public async Task BasicTranWithSortedSetContainsCondition(bool demandKeyExists, [InlineData(null, null, false, false)] public async Task BasicTranWithSortedSetEqualCondition(double? expected, double? value, bool expectEqual, bool expectedTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -876,7 +872,7 @@ public async Task BasicTranWithSortedSetEqualCondition(double? expected, double? [InlineData(false, false, false, true)] public async Task BasicTranWithSortedSetScoreExistsCondition(bool member1HasScore, bool member2HasScore, bool demandScoreExists, bool expectedTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -942,7 +938,7 @@ public async Task BasicTranWithSortedSetScoreExistsCondition(bool member1HasScor [InlineData(false, false, 1L, false, true)] public async Task BasicTranWithSortedSetScoreCountExistsCondition(bool member1HasScore, bool member2HasScore, long expectedLength, bool expectEqual, bool expectedTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -1011,7 +1007,7 @@ public async Task BasicTranWithSortedSetScoreCountExistsCondition(bool member1Ha [InlineData("", ComparisonType.GreaterThan, 0L, false)] public async Task BasicTranWithListLengthCondition(string value, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -1090,7 +1086,7 @@ public async Task BasicTranWithListLengthCondition(string value, ComparisonType [InlineData("", ComparisonType.GreaterThan, 0L, false)] public async Task BasicTranWithStreamLengthCondition(string value, ComparisonType type, long length, bool expectTranResult) { - using var conn = Create(require: RedisFeatures.v5_0_0); + await using var conn = Create(require: RedisFeatures.v5_0_0); RedisKey key = Me(), key2 = Me() + "2"; var db = conn.GetDatabase(); @@ -1152,7 +1148,7 @@ public async Task BasicTranWithStreamLengthCondition(string value, ComparisonTyp [Fact] public async Task BasicTran() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -1196,7 +1192,7 @@ public async Task BasicTran() [Fact] public async Task CombineFireAndForgetAndRegularAsyncInTransaction() { - using var conn = Create(); + await using var conn = Create(); RedisKey key = Me(); var db = conn.GetDatabase(); @@ -1222,7 +1218,7 @@ public async Task CombineFireAndForgetAndRegularAsyncInTransaction() [Fact] public async Task TransactionWithAdHocCommandsAndSelectDisabled() { - using var conn = Create(disabledCommands: new string[] { "SELECT" }); + await using var conn = Create(disabledCommands: ["SELECT"]); RedisKey key = Me(); var db = conn.GetDatabase(); db.KeyDelete(key, CommandFlags.FireAndForget); @@ -1239,8 +1235,8 @@ public async Task TransactionWithAdHocCommandsAndSelectDisabled() [Fact] public async Task WatchAbort_StringEqual() { - using var vicConn = Create(); - using var perpConn = Create(); + await using var vicConn = Create(); + await using var perpConn = Create(); var key = Me(); var db = vicConn.GetDatabase(); @@ -1263,8 +1259,8 @@ public async Task WatchAbort_StringEqual() [Fact] public async Task WatchAbort_HashLengthEqual() { - using var vicConn = Create(); - using var perpConn = Create(); + await using var vicConn = Create(); + await using var perpConn = Create(); var key = Me(); var db = vicConn.GetDatabase(); @@ -1285,21 +1281,22 @@ public async Task WatchAbort_HashLengthEqual() } #endif - [FactLongRunning] + [Fact] public async Task ExecCompletes_Issue943() { + Skip.UnlessLongRunning(); int hashHit = 0, hashMiss = 0, expireHit = 0, expireMiss = 0; - using (var conn = Create()) + await using (var conn = Create()) { var db = conn.GetDatabase(); for (int i = 0; i < 40000; i++) { RedisKey key = Me(); await db.KeyDeleteAsync(key); - HashEntry[] hashEntries = new[] - { + HashEntry[] hashEntries = + [ new HashEntry("blah", DateTime.UtcNow.ToString("R")), - }; + ]; ITransaction transaction = db.CreateTransaction(); transaction.AddCondition(Condition.KeyNotExists(key)); Task hashSetTask = transaction.HashSetAsync(key, hashEntries); diff --git a/tests/StackExchange.Redis.Tests/ValueTests.cs b/tests/StackExchange.Redis.Tests/ValueTests.cs index 1877eb7c7..69a8a2cbc 100644 --- a/tests/StackExchange.Redis.Tests/ValueTests.cs +++ b/tests/StackExchange.Redis.Tests/ValueTests.cs @@ -2,14 +2,11 @@ using System.IO; using System.Text; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -public class ValueTests : TestBase +public class ValueTests(ITestOutputHelper output) : TestBase(output) { - public ValueTests(ITestOutputHelper output) : base(output) { } - [Fact] public void NullValueChecks() { diff --git a/tests/StackExchange.Redis.Tests/WithKeyPrefixTests.cs b/tests/StackExchange.Redis.Tests/WithKeyPrefixTests.cs index 72a99f2cc..acbef74cf 100644 --- a/tests/StackExchange.Redis.Tests/WithKeyPrefixTests.cs +++ b/tests/StackExchange.Redis.Tests/WithKeyPrefixTests.cs @@ -1,19 +1,16 @@ using System; +using System.Threading.Tasks; using StackExchange.Redis.KeyspaceIsolation; using Xunit; -using Xunit.Abstractions; namespace StackExchange.Redis.Tests; -[Collection(SharedConnectionFixture.Key)] -public class WithKeyPrefixTests : TestBase +public class WithKeyPrefixTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture) { - public WithKeyPrefixTests(ITestOutputHelper output, SharedConnectionFixture fixture) : base(output, fixture) { } - [Fact] - public void BlankPrefixYieldsSame_Bytes() + public async Task BlankPrefixYieldsSame_Bytes() { - using var conn = Create(); + await using var conn = Create(); var raw = conn.GetDatabase(); var prefixed = raw.WithKeyPrefix(Array.Empty()); @@ -21,9 +18,9 @@ public void BlankPrefixYieldsSame_Bytes() } [Fact] - public void BlankPrefixYieldsSame_String() + public async Task BlankPrefixYieldsSame_String() { - using var conn = Create(); + await using var conn = Create(); var raw = conn.GetDatabase(); var prefixed = raw.WithKeyPrefix(""); @@ -31,11 +28,11 @@ public void BlankPrefixYieldsSame_String() } [Fact] - public void NullPrefixIsError_Bytes() + public async Task NullPrefixIsError_Bytes() { - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - using var conn = Create(); + await using var conn = Create(); var raw = conn.GetDatabase(); raw.WithKeyPrefix((byte[]?)null); @@ -43,11 +40,11 @@ public void NullPrefixIsError_Bytes() } [Fact] - public void NullPrefixIsError_String() + public async Task NullPrefixIsError_String() { - Assert.Throws(() => + await Assert.ThrowsAsync(async () => { - using var conn = Create(); + await using var conn = Create(); var raw = conn.GetDatabase(); raw.WithKeyPrefix((string?)null); @@ -68,9 +65,9 @@ public void NullDatabaseIsError(string? prefix) } [Fact] - public void BasicSmokeTest() + public async Task BasicSmokeTest() { - using var conn = Create(); + await using var conn = Create(); var raw = conn.GetDatabase(); @@ -101,9 +98,9 @@ public void BasicSmokeTest() } [Fact] - public void ConditionTest() + public async Task ConditionTest() { - using var conn = Create(); + await using var conn = Create(); var raw = conn.GetDatabase(); @@ -117,7 +114,7 @@ public void ConditionTest() raw.StringSet(prefix + "abc", "def", flags: CommandFlags.FireAndForget); var tran = foo.CreateTransaction(); tran.AddCondition(Condition.KeyExists("abc")); - tran.StringIncrementAsync("i"); + _ = tran.StringIncrementAsync("i"); tran.Execute(); int i = (int)raw.StringGet(prefix + "i"); @@ -127,7 +124,7 @@ public void ConditionTest() raw.KeyDelete(prefix + "abc", CommandFlags.FireAndForget); tran = foo.CreateTransaction(); tran.AddCondition(Condition.KeyExists("abc")); - tran.StringIncrementAsync("i"); + _ = tran.StringIncrementAsync("i"); tran.Execute(); i = (int)raw.StringGet(prefix + "i"); diff --git a/tests/StackExchange.Redis.Tests/xunit.runner.json b/tests/StackExchange.Redis.Tests/xunit.runner.json index 99e81e741..dc36b1875 100644 --- a/tests/StackExchange.Redis.Tests/xunit.runner.json +++ b/tests/StackExchange.Redis.Tests/xunit.runner.json @@ -1,9 +1,8 @@ { "methodDisplay": "classAndMethod", - "maxParallelThreads": 16, "parallelizeAssembly": true, + "maxParallelThreads": "2x", "parallelizeTestCollections": true, - "parallelAlgorithm": "aggressive", "diagnosticMessages": false, "longRunningTestSeconds": 60 } \ No newline at end of file