Skip to content

Commit 9ef34d3

Browse files
committed
[ECO-5646] Added test to make sure non-recoverable errors are always retried
on primary host first
1 parent 957977c commit 9ef34d3

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

src/IO.Ably.Tests.Shared/Realtime/ConnectionSpecs/AblyRealtimeTestExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ public static async Task DisconnectWithRetryableError(this AblyRealtime client)
3030
await client.WaitForState(ConnectionState.Disconnected);
3131
}
3232

33+
public static void DisconnectWithNonRetryableError(this AblyRealtime client)
34+
{
35+
client.FakeProtocolMessageReceived(new ProtocolMessage(ProtocolMessage.MessageAction.Disconnected)
36+
{
37+
Error = new ErrorInfo { StatusCode = HttpStatusCode.Forbidden }
38+
});
39+
}
40+
3341
public static async Task ConnectClient(this AblyRealtime client)
3442
{
3543
await client.WaitForState(ConnectionState.Connecting, TimeSpan.FromMilliseconds(10000));

src/IO.Ably.Tests.Shared/Realtime/ConnectionSpecs/ConnectionFallbackSpecs.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using FluentAssertions;
88
using IO.Ably.Realtime;
99
using IO.Ably.Realtime.Workflow;
10+
using IO.Ably.Tests.Infrastructure;
1011
using IO.Ably.Types;
1112
using Xunit;
1213
using Xunit.Abstractions;
@@ -342,6 +343,96 @@ public async Task WhenItMovesFromDisconnectedToSuspended_ShouldTryDefaultHostAga
342343
realtimeHosts.Last().Should().Be("realtime.ably.io");
343344
}
344345

346+
[Fact]
347+
[Trait("spec", "RTN17f")]
348+
public async Task WhenNonRetryableError_ShouldAlwaysTryDefaultHostFirst()
349+
{
350+
var client = await GetConnectedClient(opts =>
351+
{
352+
opts.DisconnectedRetryTimeout = TimeSpan.FromSeconds(2);
353+
opts.SuspendedRetryTimeout = TimeSpan.FromSeconds(2);
354+
});
355+
356+
// Reduced connectionStateTTL for limited disconnected retries upto 20 seconds
357+
client.State.Connection.ConnectionStateTtl = TimeSpan.FromSeconds(20);
358+
359+
var realtimeHosts = new List<string>();
360+
FakeTransportFactory.InitialiseFakeTransport = p => realtimeHosts.Add(p.Parameters.Host);
361+
362+
client.Connection.On(ConnectionEvent.Connecting, stateChange =>
363+
{
364+
if (stateChange.Previous == ConnectionState.Disconnected)
365+
{
366+
client.DisconnectWithNonRetryableError();
367+
}
368+
});
369+
370+
// Receive first disconnect message on CONNECTED client, will call above callback after timeout
371+
client.DisconnectWithNonRetryableError();
372+
373+
await new ConditionalAwaiter(() => client.Connection.State == ConnectionState.Suspended, null, 120);
374+
375+
client.Connection.State.Should().Be(ConnectionState.Suspended);
376+
await client.WaitForState(ConnectionState.Connecting);
377+
378+
client.DisconnectWithNonRetryableError();
379+
380+
await client.WaitForState(ConnectionState.Suspended);
381+
await client.WaitForState(ConnectionState.Connecting);
382+
383+
realtimeHosts.Should().AllBe("realtime.ably.io");
384+
}
385+
386+
[Fact]
387+
[Trait("spec", "RTN17j")]
388+
public async Task WhenInternetConenctionIsDown_ShouldAlwaysTryDefaultHostFirst()
389+
{
390+
var response = new HttpResponseMessage(HttpStatusCode.Forbidden) {
391+
Content = new StringContent("Internet not available")
392+
};
393+
var handler = new FakeHttpMessageHandler(response);
394+
395+
var realtimeHosts = new List<string>();
396+
FakeTransportFactory.InitialiseFakeTransport = p => realtimeHosts.Add(p.Parameters.Host);
397+
398+
var client = GetClientWithFakeTransportAndMessageHandler(
399+
opts =>
400+
{
401+
opts.DisconnectedRetryTimeout = TimeSpan.FromSeconds(2);
402+
opts.SuspendedRetryTimeout = TimeSpan.FromSeconds(2);
403+
},
404+
handler);
405+
client.Options.SkipInternetCheck = false;
406+
407+
// Reduced connectionStateTTL for limited disconnected retries upto 20 seconds
408+
client.State.Connection.ConnectionStateTtl = TimeSpan.FromSeconds(20);
409+
410+
await client.ConnectClient(); // On the default host
411+
412+
client.Connection.On(ConnectionEvent.Connecting, stateChange =>
413+
{
414+
if (stateChange.Previous == ConnectionState.Disconnected)
415+
{
416+
client.DisconnectWithRetryableError();
417+
}
418+
});
419+
420+
// Receive first disconnect message on CONNECTED client, will call above callback after timeout
421+
await client.DisconnectWithRetryableError();
422+
423+
await new ConditionalAwaiter(() => client.Connection.State == ConnectionState.Suspended, null, 120);
424+
425+
client.Connection.State.Should().Be(ConnectionState.Suspended);
426+
await client.WaitForState(ConnectionState.Connecting);
427+
428+
client.DisconnectWithNonRetryableError();
429+
430+
await client.WaitForState(ConnectionState.Suspended);
431+
await client.WaitForState(ConnectionState.Connecting);
432+
433+
realtimeHosts.Should().AllBe("realtime.ably.io");
434+
}
435+
345436
public ConnectionFallbackSpecs(ITestOutputHelper output)
346437
: base(output)
347438
{

0 commit comments

Comments
 (0)