From a9ac5bf6bc473ee386a7ce5e1b7709d0ccc3ba84 Mon Sep 17 00:00:00 2001 From: Valentin Clergue Date: Sun, 1 Nov 2026 11:29:42 +0100 Subject: [PATCH] refactor: clear the open SonarQube code smells and enforce them locally SonarQube's develop analysis carried 23 open issues: 22 VSTHRD202 (async/await that only forwards a Task) and one S3776 (ConnectionSupervisor.RunAsync at cognitive complexity 18 over the 15 limit). Neither failed the local build: VSTHRD202 ships at info severity and S3776 is not enabled by default in the SonarAnalyzer.CSharp package, so Sonar found what `dotnet build` let through. Raise both to warning in .editorconfig; with TreatWarningsAsErrors that makes them build errors, so the smells cannot come back unnoticed. Fixes: - Return the inner Task directly at the 22 VSTHRD202 sites (query forwarders on ConnectionSupervisor, GetCultureAsync helpers, the cancel buttons, the marker command handlers, EnsureChannelOrderAsync and two tests). MarkerReply.ForAsync now returns Task so the handlers can forward it under the ICommandHandler signature. - Extract the connect try/catch out of RunAsync into ConnectAsync, which maps a stopping unwind to null and a throwing source to Unreachable. Behaviour is unchanged; RunAsync drops to complexity 12. Co-Authored-By: Claude Fable 5.1 --- .editorconfig | 3 + .../Pairing/AlarmPairingCoordinator.cs | 4 +- .../Relaying/AlarmRefresher.cs | 4 +- .../Handlers/CargoCommandHandler.cs | 7 +- .../Handlers/ChinookCommandHandler.cs | 7 +- .../Handlers/HeliCommandHandler.cs | 7 +- .../Handlers/MarkerReply.cs | 2 +- .../Modules/ServerRemovalModule.cs | 3 +- .../Supervisor/ConnectionSupervisor.cs | 145 ++++++++++-------- .../Hosting/PairingHostedService.cs | 4 +- .../Modules/CredentialModule.cs | 3 +- .../Relaying/StorageMonitorStateRelay.cs | 4 +- .../Relaying/SwitchStateRelay.cs | 4 +- .../Gateway/DiscordWorkspaceGateway.cs | 12 +- .../Hosting/ChatHostedServiceTests.cs | 4 +- .../MapComposerTests.cs | 4 +- 16 files changed, 113 insertions(+), 104 deletions(-) diff --git a/.editorconfig b/.editorconfig index 2897f41f..2c250293 100644 --- a/.editorconfig +++ b/.editorconfig @@ -413,6 +413,9 @@ dotnet_diagnostic.Moq1400.severity = none # Choose a mock behaviour (strict, loo dotnet_diagnostic.Moq1410.severity = none # Set behaviour to Strict dotnet_diagnostic.S2094.severity = none # Empty classes — intentional discriminated-union marker records (Marker/Note/EventArg hierarchies) +dotnet_diagnostic.S3776.severity = warning # Cognitive complexity — fails locally on what SonarQube flags as Critical instead of only on the server + +dotnet_diagnostic.VSTHRD202.severity = warning # Return the Task directly when async/await adds nothing — SonarQube imports this INFO diagnostic as a code smell dotnet_diagnostic.T0003.severity = none # Do not use tuples dotnet_diagnostic.T0006.severity = none # Do not use Helper in type name diff --git a/src/RustPlusBot.Features.Alarms/Pairing/AlarmPairingCoordinator.cs b/src/RustPlusBot.Features.Alarms/Pairing/AlarmPairingCoordinator.cs index f40b9e41..31531843 100644 --- a/src/RustPlusBot.Features.Alarms/Pairing/AlarmPairingCoordinator.cs +++ b/src/RustPlusBot.Features.Alarms/Pairing/AlarmPairingCoordinator.cs @@ -127,10 +127,10 @@ await store.SetMessageIdAsync(guildId, serverId, entityId, mid, cancellationToke public bool TryDismiss(ulong guildId, Guid serverId, ulong entityId) => _pending.TryRemove((guildId, serverId, entityId), out _); - private static async Task GetCultureAsync(IServiceProvider provider, ulong guildId, CancellationToken ct) + private static Task GetCultureAsync(IServiceProvider provider, ulong guildId, CancellationToken ct) { var store = provider.GetRequiredService(); - return await store.GetCultureAsync(guildId, ct).ConfigureAwait(false); + return store.GetCultureAsync(guildId, ct); } private sealed record Pending(string DefaultName, ulong? MessageId); diff --git a/src/RustPlusBot.Features.Alarms/Relaying/AlarmRefresher.cs b/src/RustPlusBot.Features.Alarms/Relaying/AlarmRefresher.cs index 53badfe7..85670551 100644 --- a/src/RustPlusBot.Features.Alarms/Relaying/AlarmRefresher.cs +++ b/src/RustPlusBot.Features.Alarms/Relaying/AlarmRefresher.cs @@ -73,12 +73,12 @@ await store.SetMessageIdAsync(alarm.GuildId, alarm.ServerId, alarm.EntityId, mid } } - private static async Task GetCultureAsync( + private static Task GetCultureAsync( IServiceProvider provider, ulong guildId, CancellationToken ct) { var store = provider.GetRequiredService(); - return await store.GetCultureAsync(guildId, ct).ConfigureAwait(false); + return store.GetCultureAsync(guildId, ct); } } diff --git a/src/RustPlusBot.Features.Commands/Handlers/CargoCommandHandler.cs b/src/RustPlusBot.Features.Commands/Handlers/CargoCommandHandler.cs index 24f760c7..a0235dd4 100644 --- a/src/RustPlusBot.Features.Commands/Handlers/CargoCommandHandler.cs +++ b/src/RustPlusBot.Features.Commands/Handlers/CargoCommandHandler.cs @@ -23,12 +23,11 @@ internal sealed class CargoCommandHandler( public string Name => "cargo"; /// - public async Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) + public Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(context); - return await MarkerReply + return MarkerReply .ForAsync(new MarkerReplyServices(state, localizer, clock, mapSettings), context, MarkerKind.CargoShip, - "command.cargo", cancellationToken) - .ConfigureAwait(false); + "command.cargo", cancellationToken); } } diff --git a/src/RustPlusBot.Features.Commands/Handlers/ChinookCommandHandler.cs b/src/RustPlusBot.Features.Commands/Handlers/ChinookCommandHandler.cs index 2039de8f..519bb5fa 100644 --- a/src/RustPlusBot.Features.Commands/Handlers/ChinookCommandHandler.cs +++ b/src/RustPlusBot.Features.Commands/Handlers/ChinookCommandHandler.cs @@ -23,12 +23,11 @@ internal sealed class ChinookCommandHandler( public string Name => "chinook"; /// - public async Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) + public Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(context); - return await MarkerReply + return MarkerReply .ForAsync(new MarkerReplyServices(state, localizer, clock, mapSettings), context, MarkerKind.Chinook, - "command.chinook", cancellationToken) - .ConfigureAwait(false); + "command.chinook", cancellationToken); } } diff --git a/src/RustPlusBot.Features.Commands/Handlers/HeliCommandHandler.cs b/src/RustPlusBot.Features.Commands/Handlers/HeliCommandHandler.cs index ee5c9d75..9d5cf879 100644 --- a/src/RustPlusBot.Features.Commands/Handlers/HeliCommandHandler.cs +++ b/src/RustPlusBot.Features.Commands/Handlers/HeliCommandHandler.cs @@ -23,12 +23,11 @@ internal sealed class HeliCommandHandler( public string Name => "heli"; /// - public async Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) + public Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(context); - return await MarkerReply + return MarkerReply .ForAsync(new MarkerReplyServices(state, localizer, clock, mapSettings), context, - MarkerKind.PatrolHelicopter, "command.heli", cancellationToken) - .ConfigureAwait(false); + MarkerKind.PatrolHelicopter, "command.heli", cancellationToken); } } diff --git a/src/RustPlusBot.Features.Commands/Handlers/MarkerReply.cs b/src/RustPlusBot.Features.Commands/Handlers/MarkerReply.cs index 1ce924ac..dd3df827 100644 --- a/src/RustPlusBot.Features.Commands/Handlers/MarkerReply.cs +++ b/src/RustPlusBot.Features.Commands/Handlers/MarkerReply.cs @@ -15,7 +15,7 @@ internal static class MarkerReply /// The localization key prefix ("command.cargo" / "command.heli" / "command.chinook"). /// A cancellation token. /// The localized reply. - public static async Task ForAsync( + public static async Task ForAsync( MarkerReplyServices services, CommandContext context, MarkerKind kind, diff --git a/src/RustPlusBot.Features.Connections/Modules/ServerRemovalModule.cs b/src/RustPlusBot.Features.Connections/Modules/ServerRemovalModule.cs index c89131b8..056b3a4f 100644 --- a/src/RustPlusBot.Features.Connections/Modules/ServerRemovalModule.cs +++ b/src/RustPlusBot.Features.Connections/Modules/ServerRemovalModule.cs @@ -74,6 +74,5 @@ await FollowupAsync(removed ? "Server removed." : "That server no longer exists. /// Cancels the removal. [ComponentInteraction(RemoveCancelId)] - public async Task RemoveCancelAsync() => - await RespondAsync("Cancelled.", ephemeral: true).ConfigureAwait(false); + public Task RemoveCancelAsync() => RespondAsync("Cancelled.", ephemeral: true); } diff --git a/src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs b/src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs index 42c6a15e..fba477e7 100644 --- a/src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs +++ b/src/RustPlusBot.Features.Connections/Supervisor/ConnectionSupervisor.cs @@ -216,50 +216,48 @@ public async Task StopAllAsync() } /// - public async Task GetServerInfoAsync( + public Task GetServerInfoAsync( ulong guildId, Guid serverId, CancellationToken cancellationToken) { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return null; + return Task.FromResult(null); } - return await live.Connection.GetServerInfoAsync(_options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection.GetServerInfoAsync(_options.HeartbeatTimeout, cancellationToken); } /// - public async Task GetTimeAsync(ulong guildId, + public Task GetTimeAsync(ulong guildId, Guid serverId, CancellationToken cancellationToken) { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return null; + return Task.FromResult(null); } - return await live.Connection.GetTimeAsync(_options.HeartbeatTimeout, cancellationToken).ConfigureAwait(false); + return live.Connection.GetTimeAsync(_options.HeartbeatTimeout, cancellationToken); } /// - public async Task GetTeamInfoAsync( + public Task GetTeamInfoAsync( ulong guildId, Guid serverId, CancellationToken cancellationToken) { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return null; + return Task.FromResult(null); } - return await live.Connection.GetTeamInfoAsync(_options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection.GetTeamInfoAsync(_options.HeartbeatTimeout, cancellationToken); } /// - public async Task PromoteToLeaderAsync( + public Task PromoteToLeaderAsync( ulong guildId, Guid serverId, ulong steamId, @@ -267,11 +265,10 @@ public async Task PromoteToLeaderAsync( { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return false; + return Task.FromResult(false); } - return await live.Connection.PromoteToLeaderAsync(steamId, _options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection.PromoteToLeaderAsync(steamId, _options.HeartbeatTimeout, cancellationToken); } /// @@ -331,15 +328,14 @@ public async Task PromoteToLeaderAsync( } /// - public async Task GetWorldAsync(ulong guildId, Guid serverId, CancellationToken cancellationToken) + public Task GetWorldAsync(ulong guildId, Guid serverId, CancellationToken cancellationToken) { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return null; + return Task.FromResult(null); } - return await live.Connection.GetWorldAsync(_options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection.GetWorldAsync(_options.HeartbeatTimeout, cancellationToken); } /// @@ -392,7 +388,7 @@ public async Task> GetMonumentsAsync( } /// - public async Task GetSmartAlarmReadingAsync( + public Task GetSmartAlarmReadingAsync( ulong guildId, Guid serverId, ulong entityId, @@ -400,12 +396,11 @@ public async Task GetSmartAlarmReadingAsync( { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return new DeviceReading(null, DeviceReachability.NoResponse); + return Task.FromResult(new DeviceReading(null, DeviceReachability.NoResponse)); } - return await live.Connection - .GetSmartDeviceInfoAsync(entityId, SmartDeviceKind.Alarm, _options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection + .GetSmartDeviceInfoAsync(entityId, SmartDeviceKind.Alarm, _options.HeartbeatTimeout, cancellationToken); } /// @@ -427,7 +422,7 @@ public async Task GetSmartAlarmReadingAsync( } /// - public async Task SetSmartSwitchAsync( + public Task SetSmartSwitchAsync( ulong guildId, Guid serverId, ulong entityId, @@ -436,16 +431,14 @@ public async Task SetSmartSwitchAsync( { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return DeviceReachability.NoResponse; + return Task.FromResult(DeviceReachability.NoResponse); } - return await live.Connection - .SetSmartSwitchValueAsync(entityId, value, _options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection.SetSmartSwitchValueAsync(entityId, value, _options.HeartbeatTimeout, cancellationToken); } /// - public async Task StrobeSmartSwitchAsync( + public Task StrobeSmartSwitchAsync( ulong guildId, Guid serverId, ulong entityId, @@ -455,16 +448,15 @@ public async Task StrobeSmartSwitchAsync( { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return DeviceReachability.NoResponse; + return Task.FromResult(DeviceReachability.NoResponse); } - return await live.Connection - .StrobeSmartSwitchAsync(entityId, timeoutMs, value, _options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection + .StrobeSmartSwitchAsync(entityId, timeoutMs, value, _options.HeartbeatTimeout, cancellationToken); } /// - public async Task SetClanMotdAsync( + public Task SetClanMotdAsync( ulong guildId, Guid serverId, string motd, @@ -472,12 +464,10 @@ public async Task SetClanMotdAsync( { if (!_liveSockets.TryGetValue((guildId, serverId), out var live)) { - return false; + return Task.FromResult(false); } - return await live.Connection - .SetClanMotdAsync(motd, _options.HeartbeatTimeout, cancellationToken) - .ConfigureAwait(false); + return live.Connection.SetClanMotdAsync(motd, _options.HeartbeatTimeout, cancellationToken); } [LoggerMessage(Level = LogLevel.Error, Message = "Connection loop for server {ServerId} faulted.")] @@ -521,37 +511,11 @@ await PublishStatusAsync(key, ConnectionStatus.Connecting, null, p.CredentialId, .ConfigureAwait(false); var connection = source.Create(p.Ip, p.Port, p.SteamId, p.PlayerToken); - SocketConnectOutcome outcome; - try - { - outcome = await connection.ConnectAsync(_options.ConnectTimeout, ct).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - await connection.DisposeAsync().ConfigureAwait(false); - throw; - } - catch (Exception) when (ct.IsCancellationRequested) + var outcome = await ConnectAsync(connection, key.Server, ct).ConfigureAwait(false); + if (outcome is null) { - // Stopping. A socket library may unwind cancellation as something other than an - // OperationCanceledException (a client disposed underneath the connect, say). Dispose - // and end the loop as the cancellation it is — reporting the server unreachable and - // warning about a connect failure here would be noise pointing at the wrong problem. - await connection.DisposeAsync().ConfigureAwait(false); return; } -#pragma warning disable CA1031 // Broad catch is intentional: see below — a throwing source must not end the loop. - catch (Exception ex) -#pragma warning restore CA1031 - { - // A source that throws instead of reporting an outcome is still just an unreachable - // server. Letting it escape reaches the outer catch and ENDS the loop, and nothing - // re-arms a dead loop, so the server would stay offline until the process restarts. - // Fall through as Unreachable: the branch below disposes the socket, publishes the - // status and backs off, exactly as for a reported failure. - LogConnectThrew(logger, ex, key.Server); - outcome = SocketConnectOutcome.Unreachable; - } if (outcome == SocketConnectOutcome.AuthRejected) { @@ -612,6 +576,53 @@ await PublishStatusAsync(key, ConnectionStatus.Unreachable, null, p.CredentialId #pragma warning restore CA1031 } + /// + /// Connects the socket, folding a throwing source into an outcome so the connection loop never ends on it. + /// + /// The freshly created socket to connect. + /// The server the socket belongs to, for logging. + /// The loop's cancellation token. + /// + /// The connect outcome, or when the connect unwound because the loop is stopping; + /// the socket is disposed in that case and the caller just ends the loop. + /// + private async Task ConnectAsync( + IRustServerConnection connection, + Guid serverId, + CancellationToken ct) + { + try + { + return await connection.ConnectAsync(_options.ConnectTimeout, ct).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + await connection.DisposeAsync().ConfigureAwait(false); + throw; + } + catch (Exception) when (ct.IsCancellationRequested) + { + // Stopping. A socket library may unwind cancellation as something other than an + // OperationCanceledException (a client disposed underneath the connect, say). Dispose + // and end the loop as the cancellation it is — reporting the server unreachable and + // warning about a connect failure here would be noise pointing at the wrong problem. + await connection.DisposeAsync().ConfigureAwait(false); + return null; + } +#pragma warning disable CA1031 // Broad catch is intentional: see below — a throwing source must not end the loop. + catch (Exception ex) +#pragma warning restore CA1031 + { + // A source that throws instead of reporting an outcome is still just an unreachable + // server. Letting it escape reaches the loop's outer catch and ENDS the loop, and nothing + // re-arms a dead loop, so the server would stay offline until the process restarts. + // Report Unreachable instead: the loop disposes the socket, publishes the status and + // backs off, exactly as for a reported failure. + LogConnectThrew(logger, ex, serverId); + return SocketConnectOutcome.Unreachable; + } + } + private async Task RunConnectedAsync( (ulong Guild, Guid Server) key, IRustServerConnection connection, diff --git a/src/RustPlusBot.Features.Pairing/Hosting/PairingHostedService.cs b/src/RustPlusBot.Features.Pairing/Hosting/PairingHostedService.cs index 5a114da6..b3347616 100644 --- a/src/RustPlusBot.Features.Pairing/Hosting/PairingHostedService.cs +++ b/src/RustPlusBot.Features.Pairing/Hosting/PairingHostedService.cs @@ -24,10 +24,10 @@ public Task StartAsync(CancellationToken cancellationToken) } /// - public async Task StopAsync(CancellationToken cancellationToken) + public Task StopAsync(CancellationToken cancellationToken) { client.Ready -= OnReadyAsync; - await supervisor.StopAllAsync().ConfigureAwait(false); + return supervisor.StopAllAsync(); } private Task OnReadyAsync() diff --git a/src/RustPlusBot.Features.Pairing/Modules/CredentialModule.cs b/src/RustPlusBot.Features.Pairing/Modules/CredentialModule.cs index 7deea32f..7ba5d253 100644 --- a/src/RustPlusBot.Features.Pairing/Modules/CredentialModule.cs +++ b/src/RustPlusBot.Features.Pairing/Modules/CredentialModule.cs @@ -136,6 +136,5 @@ await FollowupAsync($"Account disconnected. Removed from {count} server(s).", ep /// Cancels the disconnect. [ComponentInteraction(DisconnectCancelId)] - public async Task DisconnectCancelAsync() => - await RespondAsync("Cancelled.", ephemeral: true).ConfigureAwait(false); + public Task DisconnectCancelAsync() => RespondAsync("Cancelled.", ephemeral: true); } diff --git a/src/RustPlusBot.Features.StorageMonitors/Relaying/StorageMonitorStateRelay.cs b/src/RustPlusBot.Features.StorageMonitors/Relaying/StorageMonitorStateRelay.cs index ffd1cb4e..b66cf68f 100644 --- a/src/RustPlusBot.Features.StorageMonitors/Relaying/StorageMonitorStateRelay.cs +++ b/src/RustPlusBot.Features.StorageMonitors/Relaying/StorageMonitorStateRelay.cs @@ -159,12 +159,12 @@ await store.SetMessageIdAsync(guildId, serverId, monitor.EntityId, mid, cancella } } - private static async Task GetCultureAsync( + private static Task GetCultureAsync( IServiceProvider provider, ulong guildId, CancellationToken cancellationToken) { var store = provider.GetRequiredService(); - return await store.GetCultureAsync(guildId, cancellationToken).ConfigureAwait(false); + return store.GetCultureAsync(guildId, cancellationToken); } } diff --git a/src/RustPlusBot.Features.Switches/Relaying/SwitchStateRelay.cs b/src/RustPlusBot.Features.Switches/Relaying/SwitchStateRelay.cs index 9c75c30e..3370c0e1 100644 --- a/src/RustPlusBot.Features.Switches/Relaying/SwitchStateRelay.cs +++ b/src/RustPlusBot.Features.Switches/Relaying/SwitchStateRelay.cs @@ -208,12 +208,12 @@ await store.SetMessageIdAsync(guildId, serverId, sw.EntityId, mid, cancellationT } } - private static async Task GetCultureAsync( + private static Task GetCultureAsync( IServiceProvider provider, ulong guildId, CancellationToken cancellationToken) { var store = provider.GetRequiredService(); - return await store.GetCultureAsync(guildId, cancellationToken).ConfigureAwait(false); + return store.GetCultureAsync(guildId, cancellationToken); } } diff --git a/src/RustPlusBot.Features.Workspace/Gateway/DiscordWorkspaceGateway.cs b/src/RustPlusBot.Features.Workspace/Gateway/DiscordWorkspaceGateway.cs index 3c297703..454567b0 100644 --- a/src/RustPlusBot.Features.Workspace/Gateway/DiscordWorkspaceGateway.cs +++ b/src/RustPlusBot.Features.Workspace/Gateway/DiscordWorkspaceGateway.cs @@ -181,7 +181,7 @@ await channel.DeleteMessageAsync(messageId, Options(cancellationToken)) } /// - public async Task EnsureChannelOrderAsync(ulong guildId, + public Task EnsureChannelOrderAsync(ulong guildId, ulong categoryId, IReadOnlyList orderedChannelIds, CancellationToken cancellationToken) @@ -190,7 +190,7 @@ public async Task EnsureChannelOrderAsync(ulong guildId, var guild = client.GetGuild(guildId); if (guild is null) { - return; + return Task.CompletedTask; } var live = orderedChannelIds @@ -199,25 +199,25 @@ public async Task EnsureChannelOrderAsync(ulong guildId, .ToList(); if (live.Count < 2) { - return; + return Task.CompletedTask; } // Discord sorts a category's channels by position, ties by snowflake. var current = live.OrderBy(c => c.Position).ThenBy(c => c.Id).Select(c => c.Id); if (current.SequenceEqual(live.Select(c => c.Id))) { - return; + return Task.CompletedTask; } // Permute the channels' existing position values rather than assigning fresh ones, so every // channel outside the list keeps its place relative to the reordered block. var slots = live.Select(c => c.Position).Order().ToList(); - await guild.ReorderChannelsAsync( + return guild.ReorderChannelsAsync( live.Select((c, i) => new ReorderChannelProperties(c.Id, slots[i])), new RequestOptions { CancelToken = cancellationToken - }).ConfigureAwait(false); + }); } /// diff --git a/tests/RustPlusBot.Features.Chat.Tests/Hosting/ChatHostedServiceTests.cs b/tests/RustPlusBot.Features.Chat.Tests/Hosting/ChatHostedServiceTests.cs index 70dca6bf..db918044 100644 --- a/tests/RustPlusBot.Features.Chat.Tests/Hosting/ChatHostedServiceTests.cs +++ b/tests/RustPlusBot.Features.Chat.Tests/Hosting/ChatHostedServiceTests.cs @@ -234,11 +234,11 @@ await bus.PublishAsync(new ClanMessageReceivedEvent(10UL, Guid.NewGuid(), 7UL, " #pragma warning disable S2699 // The implicit assertion is "no exception is thrown". [Fact] - public async Task StopAsync_without_a_start_completes() + public Task StopAsync_without_a_start_completes() { var (service, _, _, _) = Build(); - await service.StopAsync(default); + return service.StopAsync(default); } #pragma warning restore S2699 diff --git a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs index abbf4c1f..8af9e34e 100644 --- a/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs +++ b/tests/RustPlusBot.Features.Map.Tests/MapComposerTests.cs @@ -156,7 +156,7 @@ public async Task Tunnel_tokens_render_under_the_tunnels_layer_not_the_monuments Assert.False(tunResult.Png.SequenceEqual(baseResult.Png), "tunnel token must render under the Tunnels layer"); } - private static async Task ComposeTunnelScenarioAsync(bool monuments, bool tunnels) + private static Task ComposeTunnelScenarioAsync(bool monuments, bool tunnels) { var query = NewQuery(); query.GetMonumentsAsync(Guild, Server, Arg.Any()) @@ -165,7 +165,7 @@ public async Task Tunnel_tokens_render_under_the_tunnels_layer_not_the_monuments Grid: false, Markers: false, Monuments: monuments, Vendor: false, Players: false, Rigs: false, Tunnels: tunnels); var composer = Build(BaseJpeg(), Dims, query, NewEvents(), NewRigs(), NewSettings(settings)); - return await composer.ComposeAsync(Guild, Server, CancellationToken.None); + return composer.ComposeAsync(Guild, Server, CancellationToken.None); } [Fact]