public async Task when_subscribing_new_topics_then_subscriptions_are_created_and_ack_is_sent()
        {
            var configuration = new MqttConfiguration {
                MaximumQualityOfService = MqttQualityOfService.AtLeastOnce
            };
            var topicEvaluator            = new Mock <IMqttTopicEvaluator> ();
            var sessionRepository         = new Mock <IRepository <ClientSession> > ();
            var packetIdProvider          = Mock.Of <IPacketIdProvider> ();
            var retainedMessageRepository = Mock.Of <IRepository <RetainedMessage> > ();
            var senderFlow = Mock.Of <IPublishSenderFlow> ();

            var clientId = Guid.NewGuid().ToString();
            var session  = new ClientSession(clientId, clean: false);

            topicEvaluator.Setup(e => e.IsValidTopicFilter(It.IsAny <string> ())).Returns(true);
            sessionRepository.Setup(r => r.Read(It.IsAny <string> ())).Returns(session);

            var fooQoS          = MqttQualityOfService.AtLeastOnce;
            var fooTopic        = "test/foo/1";
            var fooSubscription = new Subscription(fooTopic, fooQoS);
            var barQoS          = MqttQualityOfService.AtMostOnce;
            var barTopic        = "test/bar/1";
            var barSubscription = new Subscription(barTopic, barQoS);

            var packetId  = (ushort)new Random().Next(0, ushort.MaxValue);
            var subscribe = new Subscribe(packetId, fooSubscription, barSubscription);

            var channel = new Mock <IMqttChannel <IPacket> > ();

            var response = default(IPacket);

            channel.Setup(c => c.SendAsync(It.IsAny <IPacket> ()))
            .Callback <IPacket> (p => response = p)
            .Returns(Task.Delay(0));

            var connectionProvider = new Mock <IConnectionProvider> ();

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

            var flow = new ServerSubscribeFlow(topicEvaluator.Object, sessionRepository.Object,
                                               retainedMessageRepository, packetIdProvider, senderFlow, configuration);

            await flow.ExecuteAsync(clientId, subscribe, channel.Object)
            .ConfigureAwait(continueOnCapturedContext: false);

            sessionRepository.Verify(r => r.Update(It.Is <ClientSession> (s => s.Id == clientId && s.Subscriptions.Count == 2 &&
                                                                          s.Subscriptions.All(x => x.TopicFilter == fooTopic || x.TopicFilter == barTopic))));
            Assert.NotNull(response);

            var subscribeAck = response as SubscribeAck;

            Assert.NotNull(subscribeAck);
            Assert.Equal(packetId, subscribeAck.PacketId);
            Assert.Equal(2, subscribeAck.ReturnCodes.Count());
            Assert.Contains(subscribeAck.ReturnCodes, c => c == SubscribeReturnCode.MaximumQoS0);
            Assert.Contains(subscribeAck.ReturnCodes, c => c == SubscribeReturnCode.MaximumQoS1);
        }
        public async Task when_subscribing_topic_with_retain_message_then_retained_is_sent()
        {
            var configuration = new MqttConfiguration {
                MaximumQualityOfService = MqttQualityOfService.AtLeastOnce
            };
            var topicEvaluator            = new Mock <IMqttTopicEvaluator> ();
            var sessionRepository         = new Mock <IRepository <ClientSession> > ();
            var packetIdProvider          = Mock.Of <IPacketIdProvider> ();
            var retainedMessageRepository = new Mock <IRepository <RetainedMessage> > ();
            var senderFlow = new Mock <IPublishSenderFlow> ();

            var clientId = Guid.NewGuid().ToString();
            var session  = new ClientSession(clientId, clean: false);

            sessionRepository.Setup(r => r.Read(It.IsAny <string> ())).Returns(session);

            var fooQoS          = MqttQualityOfService.AtLeastOnce;
            var fooTopic        = "test/foo/#";
            var fooSubscription = new Subscription(fooTopic, fooQoS);

            var retainedTopic    = "test/foo/bar";
            var retainedQoS      = MqttQualityOfService.ExactlyOnce;
            var retainedPayload  = Encoding.UTF8.GetBytes("Retained Message Test");
            var retainedMessages = new List <RetainedMessage> {
                new RetainedMessage(retainedTopic, retainedQoS, retainedPayload)
            };

            topicEvaluator.Setup(e => e.IsValidTopicFilter(It.IsAny <string> ())).Returns(true);
            topicEvaluator.Setup(e => e.Matches(It.IsAny <string> (), It.IsAny <string> ())).Returns(true);
            retainedMessageRepository.Setup(r => r.ReadAll()).Returns(retainedMessages.AsQueryable());

            var packetId  = (ushort)new Random().Next(0, ushort.MaxValue);
            var subscribe = new Subscribe(packetId, fooSubscription);

            var channel = new Mock <IMqttChannel <IPacket> > ();

            var connectionProvider = new Mock <IConnectionProvider> ();

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

            var flow = new ServerSubscribeFlow(topicEvaluator.Object,
                                               sessionRepository.Object, retainedMessageRepository.Object,
                                               packetIdProvider, senderFlow.Object, configuration);

            await flow.ExecuteAsync(clientId, subscribe, channel.Object)
            .ConfigureAwait(continueOnCapturedContext: false);

            senderFlow.Verify(f => f.SendPublishAsync(It.Is <string>(s => s == clientId),
                                                      It.Is <Publish> (p => p.Topic == retainedTopic &&
                                                                       p.QualityOfService == fooQoS &&
                                                                       p.Payload.ToList().SequenceEqual(retainedPayload) &&
                                                                       p.PacketId.HasValue &&
                                                                       p.Retain),
                                                      It.Is <IMqttChannel <IPacket> >(c => c == channel.Object),
                                                      It.Is <PendingMessageStatus>(x => x == PendingMessageStatus.PendingToSend)));
        }
        public async Task when_subscribing_invalid_topic_then_failure_is_sent_in_ack()
        {
            var configuration = new MqttConfiguration {
                MaximumQualityOfService = MqttQualityOfService.AtLeastOnce
            };
            var topicEvaluator            = new Mock <IMqttTopicEvaluator> ();
            var sessionRepository         = new Mock <IRepository <ClientSession> > ();
            var packetIdProvider          = Mock.Of <IPacketIdProvider> ();
            var retainedMessageRepository = Mock.Of <IRepository <RetainedMessage> > ();
            var senderFlow = Mock.Of <IPublishSenderFlow> ();

            var clientId = Guid.NewGuid().ToString();
            var session  = new ClientSession {
                ClientId = clientId, Clean = false
            };

            topicEvaluator.Setup(e => e.IsValidTopicFilter(It.IsAny <string> ())).Returns(false);
            sessionRepository.Setup(r => r.Get(It.IsAny <Expression <Func <ClientSession, bool> > > ())).Returns(session);

            var fooQoS          = MqttQualityOfService.AtLeastOnce;
            var fooTopic        = "test/foo/1";
            var fooSubscription = new Subscription(fooTopic, fooQoS);

            var packetId  = (ushort)new Random().Next(0, ushort.MaxValue);
            var subscribe = new Subscribe(packetId, fooSubscription);

            var channel = new Mock <IMqttChannel <IPacket> > ();

            var response = default(IPacket);

            channel.Setup(c => c.SendAsync(It.IsAny <IPacket> ()))
            .Callback <IPacket> (p => response = p)
            .Returns(Task.Delay(0));

            var connectionProvider = new Mock <IConnectionProvider> ();

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

            var flow = new ServerSubscribeFlow(topicEvaluator.Object, sessionRepository.Object,
                                               retainedMessageRepository, packetIdProvider,
                                               senderFlow, configuration);

            await flow.ExecuteAsync(clientId, subscribe, channel.Object)
            .ConfigureAwait(continueOnCapturedContext: false);

            Assert.NotNull(response);

            var subscribeAck = response as SubscribeAck;

            Assert.NotNull(subscribeAck);
            Assert.Equal(packetId, subscribeAck.PacketId);
            Assert.Equal(1, subscribeAck.ReturnCodes.Count());
            Assert.Equal(SubscribeReturnCode.Failure, subscribeAck.ReturnCodes.First());
        }
        public async Task when_subscribing_invalid_topic_then_failure_is_sent_in_ack()
        {
            MqttConfiguration configuration = new MqttConfiguration {
                MaximumQualityOfService = MqttQualityOfService.AtLeastOnce
            };
            Mock <IMqttTopicEvaluator>          topicEvaluator      = new Mock <IMqttTopicEvaluator>();
            Mock <IRepository <ClientSession> > sessionRepository   = new Mock <IRepository <ClientSession> >();
            IPacketIdProvider             packetIdProvider          = Mock.Of <IPacketIdProvider>();
            IRepository <RetainedMessage> retainedMessageRepository = Mock.Of <IRepository <RetainedMessage> >();
            IPublishSenderFlow            senderFlow = Mock.Of <IPublishSenderFlow>();

            string        clientId = Guid.NewGuid().ToString();
            ClientSession session  = new ClientSession(clientId, clean: false);

            topicEvaluator.Setup(e => e.IsValidTopicFilter(It.IsAny <string>())).Returns(false);
            sessionRepository.Setup(r => r.Read(It.IsAny <string>())).Returns(session);

            MqttQualityOfService fooQoS  = MqttQualityOfService.AtLeastOnce;
            string       fooTopic        = "test/foo/1";
            Subscription fooSubscription = new Subscription(fooTopic, fooQoS);

            ushort    packetId  = (ushort)new Random().Next(0, ushort.MaxValue);
            Subscribe subscribe = new Subscribe(packetId, fooSubscription);

            Mock <IMqttChannel <IPacket> > channel = new Mock <IMqttChannel <IPacket> >();

            IPacket response = default;

            channel.Setup(c => c.SendAsync(It.IsAny <IPacket>()))
            .Callback <IPacket>(p => response = p)
            .Returns(Task.Delay(0));

            Mock <IConnectionProvider> connectionProvider = new Mock <IConnectionProvider>();

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

            ServerSubscribeFlow flow = new ServerSubscribeFlow(topicEvaluator.Object, sessionRepository.Object,
                                                               retainedMessageRepository, packetIdProvider,
                                                               senderFlow, configuration);

            await flow.ExecuteAsync(clientId, subscribe, channel.Object);

            Assert.NotNull(response);

            SubscribeAck subscribeAck = response as SubscribeAck;

            Assert.NotNull(subscribeAck);
            packetId.Should().Be(subscribeAck.PacketId);
            1.Should().Be(subscribeAck.ReturnCodes.Count());
            SubscribeReturnCode.Failure.Should().Be(subscribeAck.ReturnCodes.First());
        }
        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);
        }