From 938678970a17b10948459d8dff9fc43168f868ca Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 25 Sep 2023 21:00:38 +0530 Subject: [PATCH] Refactored test for ack/nack to fail when connection goes into disconnected state --- .../Infrastructure/ConnectionAwaiter.cs | 2 +- .../Realtime/PresenceSandboxSpecs.cs | 121 ++++++++++++------ 2 files changed, 81 insertions(+), 42 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/Infrastructure/ConnectionAwaiter.cs b/src/IO.Ably.Tests.Shared/Infrastructure/ConnectionAwaiter.cs index bb80eccc3..3f288526d 100644 --- a/src/IO.Ably.Tests.Shared/Infrastructure/ConnectionAwaiter.cs +++ b/src/IO.Ably.Tests.Shared/Infrastructure/ConnectionAwaiter.cs @@ -78,7 +78,7 @@ public async Task Wait(TimeSpan timeout) DefaultLogger.Debug($"[{_id} Timeout exceeded. Throwing TimeoutException"); RemoveListener(); throw new TimeoutException( - $"Expected ''{_awaitedStates.Select(x => x.ToString()).JoinStrings()}' but current state was '{_connection.State}'"); + $"Expected '{_awaitedStates.Select(x => x.ToString()).JoinStrings()}' but current state was '{_connection.State}'"); } } } diff --git a/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs index 049589315..f940e9221 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/PresenceSandboxSpecs.cs @@ -1657,78 +1657,117 @@ public async Task ChannelStateCondition_WhenQueueMessagesIsFalse_WhenChannelIsIn [Theory] [ProtocolData] [Trait("spec", "RTP16b")] - [Trait("spec", "RTP19a")] - public async Task ChannelStateCondition_WhenQueueMessagesIsFalse_ShouldFailAckQueueMessages_WhenSendFails(Protocol protocol) + public async Task ChannelStateCondition_WhenQueueMessagesIsFalse_WhenChannelIsInitializedOrAttaching_MessageAreNotPublished(Protocol protocol) { - var transportFactory = new TestTransportFactory + var client = await GetRealtimeClient(protocol, (options, settings) => { - BeforeMessageSent = message => + options.ClientId = "RTP16b"; + options.QueueMessages = false; + }); + + await client.WaitForState(ConnectionState.Connected); + + var channel = GetRandomChannel(client, "RTP16a"); + channel.State.Should().Be(ChannelState.Initialized); + await EnterPresenceAndCheckForError(); + + client.BlockActionFromSending(ProtocolMessage.MessageAction.Attach); + channel.Attach(); + await channel.WaitForState(ChannelState.Attaching); + await EnterPresenceAndCheckForError(); + + // QueueCommand will not retry instantly + client.Workflow.QueueCommand(SetDisconnectedStateCommand.Create(null)); + await client.WaitForState(ConnectionState.Disconnected); + await EnterPresenceAndCheckForError(); + + // clean up + client.Close(); + + async Task EnterPresenceAndCheckForError() + { + var enterPresenceAwaiter = new TaskCompletionAwaiter(); + ErrorInfo err = null; + bool? success = null; + channel.Presence.Enter("dummy data", (b, info) => { - if (message.Action == ProtocolMessage.MessageAction.Presence) - { - throw new Exception("RTP16b : error while sending message"); - } + success = b; + err = info; + enterPresenceAwaiter.SetCompleted(); + }); + await client.ProcessCommands(); + + // No messages sent because queueMessages false + channel.Presence.PendingPresenceQueue.Should().HaveCount(0); + client.State.PendingMessages.Should().HaveCount(0); + + if (client.Connection.State != ConnectionState.Disconnected) + { + var presenceMessagesSent = client.GetTestTransport().ProtocolMessagesSent + .FindAll(msg => msg.Action == ProtocolMessage.MessageAction.Presence); + presenceMessagesSent.Should().HaveCount(0); } - }; + await enterPresenceAwaiter.Task; + + success.Should().HaveValue(); + success.Value.Should().BeFalse(); + err.Should().NotBeNull(); + err.Message.Should().Be("Unable enqueue message because Options.QueueMessages is set to False."); + } + } + + [Theory] + [ProtocolData] + [Trait("spec", "RTN7d")] + public async Task ChannelStateCondition_WhenQueueMessagesIsFalse_ShouldFailAckQueueMessages_WhenSendFails(Protocol protocol) + { var client = await GetRealtimeClient(protocol, (options, settings) => { - options.ClientId = "RTP16b"; + options.ClientId = "RTN7d"; options.QueueMessages = false; - options.TransportFactory = transportFactory; }); await client.WaitForState(ConnectionState.Connected); - var channel = GetRandomChannel(client, "RTP16a"); + var channel = GetRandomChannel(client, "RTN7d"); channel.Attach(); await channel.WaitForAttachedState(); - var tsc = new TaskCompletionAwaiter(); + client.BlockActionFromSending(ProtocolMessage.MessageAction.Presence); + + var enterPresenceAwaiter = new TaskCompletionAwaiter(); ErrorInfo err = null; bool? success = null; - channel.Presence.Enter(client.Connection.State.ToString(), (b, info) => + channel.Presence.Enter("dummy data", (b, info) => { success = b; err = info; - tsc.SetCompleted(); - }); - - await WaitFor(done => - { - // Ack Queue has one presence message - if (channel.RealtimeClient.State.WaitingForAck.Count == 1) - { - done(); - } + enterPresenceAwaiter.SetCompleted(); }); + await client.ProcessCommands(); - // No pending message queue, since QueueMessages is false - channel.RealtimeClient.State.PendingMessages.Should().HaveCount(0); - - Presence.QueuedPresenceMessage[] presenceMessages = channel.Presence.PendingPresenceQueue.ToArray(); + // All messages sent + channel.Presence.PendingPresenceQueue.Should().HaveCount(0); + client.State.PendingMessages.Should().HaveCount(0); - presenceMessages.Should().HaveCount(0); + // no ack received, so ack queue has one presence message + await new ConditionalAwaiter(() => channel.RealtimeClient.State.WaitingForAck.Count == 1); - await tsc.Task; + // Disconnect using QueueCommand will not retry instantly + client.Workflow.QueueCommand(SetDisconnectedStateCommand.Create(null)); + await client.WaitForState(ConnectionState.Disconnected); - // No pending message queue, since QueueMessages=false - channel.RealtimeClient.State.PendingMessages.Should().HaveCount(0); + await enterPresenceAwaiter.Task; - await WaitFor(done => - { - // Ack cleared after flushing the queue for transport disconnection, because QueueMessages=false - if (channel.RealtimeClient.State.WaitingForAck.Count == 0) - { - done(); - } - }); + // Fail all ack/nack, because QueueMessages=false + channel.RealtimeClient.State.WaitingForAck.Should().HaveCount(0); success.Should().HaveValue(); success.Value.Should().BeFalse(); err.Should().NotBeNull(); err.Message.Should().Be("Clearing message AckQueue(created at connected state) because Options.QueueMessages is false"); - err.Cause.InnerException.Message.Should().Be("RTP16b : error while sending message"); + err.Code.Should().Be(ErrorCodes.Disconnected); // cleared because of disconnection // clean up client.Close();