public async Task Test_CanRecoverFromConnectionLoss()
        {
            int reconnectsRemaining = 10;

            using (ManualResetEvent maxReconnectsReachedWaitHandle = new ManualResetEvent(false))
                using (PostgreSqlTaskQueueNotificationListener listener = CreateListener())
                {
                    listener.ListenerConnectionRestored += (sender, e) =>
                    {
                        reconnectsRemaining = Math.Max(reconnectsRemaining - 1, 0);
                        if (reconnectsRemaining > 0)
                        {
                            WaitAndTerminateConnectionAsync(listener.ListenerConnectionBackendProcessId,
                                                            syncHandle: null,
                                                            timeout: RandomTimeout());
                        }
                        else
                        {
                            maxReconnectsReachedWaitHandle.Set();
                        }
                    };

                    await listener.StartAsync();

                    WaitAndTerminateConnectionAsync(listener.ListenerConnectionBackendProcessId,
                                                    syncHandle: null,
                                                    timeout: 1000).WithoutAwait();

                    maxReconnectsReachedWaitHandle.WaitOne();
                    Assert.AreEqual(0, reconnectsRemaining);

                    await listener.StopAsync();
                }
        }
        public async Task Test_CanStartAndStopReceivingNotifications_NoConnectionLoss()
        {
            bool connectedReceived    = false;
            bool notificationReceived = false;

            using (ManualResetEvent notificationReceivedWaitHandle = new ManualResetEvent(false))
                using (PostgreSqlTaskQueueNotificationListener listener = CreateListener())
                {
                    listener.ListenerConnected += (sender, e) =>
                    {
                        connectedReceived = true;
                    };

                    listener.NewTaskPosted += (sender, e) =>
                    {
                        notificationReceived = true;
                        notificationReceivedWaitHandle.Set();
                    };

                    await listener.StartAsync();

                    Assert.IsTrue(listener.IsStarted);

                    await SendChannelNotificationAsync();

                    notificationReceivedWaitHandle.WaitOne();

                    Assert.IsTrue(notificationReceived);
                    Assert.IsTrue(connectedReceived);

                    notificationReceived = false;
                    notificationReceivedWaitHandle.Reset();

                    await listener.StopAsync();

                    Assert.IsFalse(listener.IsStarted);

                    await SendChannelNotificationAsync();

                    bool signalReceived = notificationReceivedWaitHandle.WaitOne(1000);

                    Assert.IsFalse(notificationReceived);
                    Assert.IsFalse(signalReceived);
                }
        }
        public async Task Test_CanStartAndStopReceivingNotifications_WithConnectionLossRecovery()
        {
            int reconnectsRemaining   = 10;
            int notificationsReceived = 0;

            using (ManualResetEvent maximumReconnectReachedWaitHandle = new ManualResetEvent(false))
                using (PostgreSqlTaskQueueNotificationListener listener = CreateListener())
                {
                    listener.NewTaskPosted += (sender, e) =>
                    {
                        notificationsReceived++;
                        if (reconnectsRemaining > 0)
                        {
                            WaitAndTerminateConnectionAsync(listener.ListenerConnectionBackendProcessId,
                                                            syncHandle: null,
                                                            timeout: RandomTimeout());
                        }
                        else
                        {
                            maximumReconnectReachedWaitHandle.Set();
                        }
                    };

                    listener.ListenerConnectionRestored += async(sender, e) =>
                    {
                        reconnectsRemaining = Math.Max(reconnectsRemaining - 1, 0);
                        await SendChannelNotificationAsync();
                    };

                    await listener.StartAsync();

                    WaitAndTerminateConnectionAsync(listener.ListenerConnectionBackendProcessId,
                                                    syncHandle: null,
                                                    timeout: RandomTimeout()).WithoutAwait();

                    maximumReconnectReachedWaitHandle.WaitOne();
                    await listener.StopAsync();

                    Assert.AreEqual(0, reconnectsRemaining);
                    Assert.AreEqual(10, notificationsReceived);
                }
        }