public void when_sending_publish_received_and_no_complete_is_sent_after_receiving_publish_release_then_publish_release_is_re_transmitted()
        {
            string clientId = Guid.NewGuid().ToString();

            MqttConfiguration                   configuration      = Mock.Of <MqttConfiguration>(c => c.WaitTimeoutSecs == 1);
            Mock <IConnectionProvider>          connectionProvider = new Mock <IConnectionProvider>();
            Mock <IRepository <ClientSession> > sessionRepository  = new Mock <IRepository <ClientSession> >();

            sessionRepository
            .Setup(r => r.Read(It.IsAny <string>()))
            .Returns(new ClientSession(clientId)
            {
                PendingMessages = new List <PendingMessage> {
                    new PendingMessage()
                }
            });

            PublishSenderFlow flow = new PublishSenderFlow(sessionRepository.Object, configuration);

            ushort            packetId             = (ushort)new Random().Next(0, ushort.MaxValue);
            PublishReceived   publishReceived      = new PublishReceived(packetId);
            Subject <IPacket> receiver             = new Subject <IPacket>();
            Subject <IPacket> sender               = new Subject <IPacket>();
            Mock <IMqttChannel <IPacket> > channel = new Mock <IMqttChannel <IPacket> >();

            channel.Setup(c => c.IsConnected).Returns(true);
            channel.Setup(c => c.ReceiverStream).Returns(receiver);
            channel.Setup(c => c.SenderStream).Returns(sender);
            channel.Setup(c => c.SendAsync(It.IsAny <IPacket>()))
            .Callback <IPacket>(packet => sender.OnNext(packet))
            .Returns(Task.Delay(0));

            connectionProvider.Setup(m => m.GetConnection(It.Is <string>(s => s == clientId))).Returns(channel.Object);

            ManualResetEventSlim ackSentSignal = new ManualResetEventSlim(initialState: false);

            sender.Subscribe(p =>
            {
                if (p is PublishRelease)
                {
                    ackSentSignal.Set();
                }
            });

            Task flowTask = flow.ExecuteAsync(clientId, publishReceived, channel.Object);

            bool ackSent = ackSentSignal.Wait(2000);

            Assert.True(ackSent);
            channel.Verify(c => c.SendAsync(It.Is <IPacket>(p => p is PublishRelease &&
                                                            (p as PublishRelease).PacketId == packetId)), Times.AtLeast(1));
        }
        public void when_getting_explicit_client_flow_from_type_then_succeeds()
        {
            ClientProtocolFlowProvider flowProvider = new ClientProtocolFlowProvider(Mock.Of <IMqttTopicEvaluator>(), Mock.Of <IRepositoryProvider>(), new MqttConfiguration());

            ClientConnectFlow     connectFlow     = flowProvider.GetFlow <ClientConnectFlow>();
            PublishSenderFlow     senderFlow      = flowProvider.GetFlow <PublishSenderFlow>();
            PublishReceiverFlow   receiverFlow    = flowProvider.GetFlow <PublishReceiverFlow>();
            ClientSubscribeFlow   subscribeFlow   = flowProvider.GetFlow <ClientSubscribeFlow>();
            ClientUnsubscribeFlow unsubscribeFlow = flowProvider.GetFlow <ClientUnsubscribeFlow>();
            PingFlow disconnectFlow = flowProvider.GetFlow <PingFlow>();

            Assert.NotNull(connectFlow);
            Assert.NotNull(senderFlow);
            Assert.NotNull(receiverFlow);
            Assert.NotNull(subscribeFlow);
            Assert.NotNull(unsubscribeFlow);
            Assert.NotNull(disconnectFlow);
        }
        public void when_getting_explicit_server_flow_from_type_then_succeeds()
        {
            IMqttAuthenticationProvider authenticationProvider = Mock.Of <IMqttAuthenticationProvider>(p => p.Authenticate(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>()) == true);
            ServerProtocolFlowProvider  flowProvider           = new ServerProtocolFlowProvider(authenticationProvider, Mock.Of <IConnectionProvider>(), Mock.Of <IMqttTopicEvaluator>(),
                                                                                                Mock.Of <IRepositoryProvider>(), Mock.Of <IPacketIdProvider>(), Mock.Of <ISubject <MqttUndeliveredMessage> >(), new MqttConfiguration());

            ServerConnectFlow         connectFlow     = flowProvider.GetFlow <ServerConnectFlow>();
            PublishSenderFlow         senderFlow      = flowProvider.GetFlow <PublishSenderFlow>();
            ServerPublishReceiverFlow receiverFlow    = flowProvider.GetFlow <ServerPublishReceiverFlow>();
            ServerSubscribeFlow       subscribeFlow   = flowProvider.GetFlow <ServerSubscribeFlow>();
            ServerUnsubscribeFlow     unsubscribeFlow = flowProvider.GetFlow <ServerUnsubscribeFlow>();
            DisconnectFlow            disconnectFlow  = flowProvider.GetFlow <DisconnectFlow>();

            Assert.NotNull(connectFlow);
            Assert.NotNull(senderFlow);
            Assert.NotNull(receiverFlow);
            Assert.NotNull(subscribeFlow);
            Assert.NotNull(unsubscribeFlow);
            Assert.NotNull(disconnectFlow);
        }
        public void when_sending_publish_with_qos2_and_publish_received_is_not_received_then_publish_is_re_transmitted()
        {
            string clientId = Guid.NewGuid().ToString();

            MqttConfiguration                   configuration      = Mock.Of <MqttConfiguration>(c => c.WaitTimeoutSecs == 1 && c.MaximumQualityOfService == MqttQualityOfService.ExactlyOnce);
            Mock <IConnectionProvider>          connectionProvider = new Mock <IConnectionProvider>();
            Mock <IRepository <ClientSession> > sessionRepository  = new Mock <IRepository <ClientSession> >();

            sessionRepository
            .Setup(r => r.Read(It.IsAny <string>()))
            .Returns(new ClientSession(clientId)
            {
                PendingMessages = new List <PendingMessage> {
                    new PendingMessage()
                }
            });

            PublishSenderFlow flow = new PublishSenderFlow(sessionRepository.Object, configuration);

            string  topic    = "foo/bar";
            ushort? packetId = (ushort?)new Random().Next(0, ushort.MaxValue);
            Publish publish  = new Publish(topic, MqttQualityOfService.ExactlyOnce, retain: false, duplicated: false, packetId: packetId);

            publish.Payload = Encoding.UTF8.GetBytes("Publish Receiver Flow Test");

            Subject <IPacket> receiver             = new Subject <IPacket>();
            Subject <IPacket> sender               = new Subject <IPacket>();
            Mock <IMqttChannel <IPacket> > channel = new Mock <IMqttChannel <IPacket> >();

            channel.Setup(c => c.IsConnected).Returns(true);
            channel.Setup(c => c.ReceiverStream).Returns(receiver);
            channel.Setup(c => c.SenderStream).Returns(sender);
            channel.Setup(c => c.SendAsync(It.IsAny <IPacket>()))
            .Callback <IPacket>(packet => sender.OnNext(packet))
            .Returns(Task.Delay(0));

            connectionProvider.Setup(m => m.GetConnection(It.IsAny <string>())).Returns(channel.Object);

            ManualResetEventSlim retrySignal = new ManualResetEventSlim(initialState: false);
            int retries = 0;

            sender.Subscribe(p =>
            {
                if (p is Publish)
                {
                    retries++;
                }

                if (retries > 1)
                {
                    retrySignal.Set();
                }
            });

            Task flowTask = flow.SendPublishAsync(clientId, publish, channel.Object);

            bool retried = retrySignal.Wait(2000);

            Assert.True(retried);
            channel.Verify(c => c.SendAsync(It.Is <IPacket>(p => p is Publish &&
                                                            ((Publish)p).Topic == topic &&
                                                            ((Publish)p).QualityOfService == MqttQualityOfService.ExactlyOnce &&
                                                            ((Publish)p).PacketId == packetId)), Times.AtLeast(2));
        }