IEnumerable <TestScenarioStep> GetPart2SpecificSteps(Func <object> currentMessageFunc)
            {
                yield return(TestScenarioStep.ReadMore());

                var packets = new Packet[2];

                for (int i = packets.Length - 1; i >= 0; i--)
                {
                    packets[i] = Assert.IsAssignableFrom <Packet>(currentMessageFunc());
                    if (i > 0)
                    {
                        yield return(TestScenarioStep.ReadMore());
                    }
                }

                PublishPacket qos1Packet = Assert.Single(packets.OfType <PublishPacket>());

                Assert.Equal(QualityOfService.AtLeastOnce, qos1Packet.QualityOfService);
                this.AssertPacketCoreValue(qos1Packet, Encoding.ASCII.GetString(qos1Packet.Payload.ToArray()));

                PubRelPacket pubRelQos2Packet = Assert.Single(packets.OfType <PubRelPacket>());

                yield return(TestScenarioStep.Write(
                                 false,
                                 PubAckPacket.InResponseTo(qos1Packet),
                                 PubCompPacket.InResponseTo(pubRelQos2Packet),
                                 DisconnectPacket.Instance));
            }
        public async Task PubComp(IChannelHandlerContext context, PubCompPacket packet)
        {
            int messageId   = packet.PacketId;
            var mqttChannel = _channelService.GetMqttChannel(await _channelService.GetDeviceId(context.Channel));
            var message     = mqttChannel.GetMqttMessage(messageId);

            message.ConfirmStatus = ConfirmStatus.COMPLETE;
        }
Exemple #3
0
 /// <summary>
 /// Sends to pub comp.
 /// </summary>
 /// <param name="channel">The channel.</param>
 /// <param name="messageId">The message identifier.</param>
 public async Task SendToPubComp(IChannel channel, int messageId)
 {
     var mqttPubAckMessage = new PubCompPacket
     {
         PacketId = messageId
     };
     await channel.WriteAndFlushAsync(mqttPubAckMessage);
 }
            async Task GetPart1SpecificSteps(IChannel channel, ReadListeningHandler readHandler)
            {
                int publishQoS1PacketId = GetRandomPacketId();
                await channel.WriteAndFlushManyAsync(
                    new PublishPacket(QualityOfService.AtMostOnce, false, false)
                    {
                        //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId),
                        TopicName = $"devices/{this.clientId}/messages/events",
                        Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}"))
                    },
                    new PublishPacket(QualityOfService.AtLeastOnce, false, false)
                    {
                        PacketId = publishQoS1PacketId,
                        TopicName = $"devices/{this.clientId}/messages/events",
                        Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}"))
                    });

                var packets = new Packet[5];
                for (int i = packets.Length - 1; i >= 0; i--)
                {
                    packets[i] = Assert.IsAssignableFrom<Packet>(await readHandler.ReceiveAsync());
                }

                PubAckPacket pubAckPacket = Assert.Single(packets.OfType<PubAckPacket>());
                Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId);

                PublishPacket publishQoS0Packet = Assert.Single(packets.OfType<PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce));
                this.AssertPacketCoreValue(publishQoS0Packet, NotificationQoS0Content);

                PublishPacket publishQoS1Packet = Assert.Single(packets.OfType<PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce));
                this.AssertPacketCoreValue(publishQoS1Packet, NotificationQoS1Content);

                PublishPacket[] publishQoS2Packets = packets.OfType<PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce).Reverse().ToArray();
                Assert.Equal(2, publishQoS2Packets.Length);
                PublishPacket publishQoS2Packet1 = publishQoS2Packets[0];
                this.AssertPacketCoreValue(publishQoS2Packet1, NotificationQoS2Content);
                PublishPacket publishQoS2Packet2 = publishQoS2Packets[1];
                this.AssertPacketCoreValue(publishQoS2Packet2, NotificationQoS2Content2);

                await channel.WriteAndFlushManyAsync(
                    PubAckPacket.InResponseTo(publishQoS1Packet),
                    PubRecPacket.InResponseTo(publishQoS2Packet1),
                    PubRecPacket.InResponseTo(publishQoS2Packet2));

                var pubRelQoS2Packet1 = Assert.IsAssignableFrom<PubRelPacket>(await readHandler.ReceiveAsync());
                Assert.Equal(publishQoS2Packet1.PacketId, pubRelQoS2Packet1.PacketId);

                var pubRelQoS2Packet2 = Assert.IsAssignableFrom<PubRelPacket>(await readHandler.ReceiveAsync());
                Assert.Equal(publishQoS2Packet2.PacketId, pubRelQoS2Packet2.PacketId);

                await channel.WriteAndFlushManyAsync(
                    PubCompPacket.InResponseTo(pubRelQoS2Packet1),
                    DisconnectPacket.Instance);

                // device queue still contains QoS 2 packet 2 which was PUBRECed but not PUBCOMPed.
            }
Exemple #5
0
 public void OnPubComp(IChannelHandlerContext context, PubCompPacket packet)
 {
     if (pendingPublishes.TryGetValue(packet.PacketId, out PendingPublish pendingPublish))
     {
         pendingPublish.Promise.SetResult(null);
         pendingPublishes.TryRemove(packet.PacketId, out _);
         pendingPublish.Packet.Release();
         pendingPublish.OnPubCompReceived();
     }
 }
Exemple #6
0
 public void OnPubRel(IChannelHandlerContext context, PubRelPacket packet)
 {
     if (pendingIncomingQoS2Publishes.ContainsKey(packet.PacketId))
     {
         var qos2Publish = pendingIncomingQoS2Publishes[packet.PacketId];
         publishCallback(qos2Publish.PublishPacket);
         qos2Publish.OnPubRelReceived();
         pendingIncomingQoS2Publishes.TryRemove(packet.PacketId, out _);
     }
     context.WriteAndFlushAsync(PubCompPacket.InResponseTo(packet));
 }
        /// <summary>
        /// Pubs the comp.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="packet">The packet.</param>
        public async Task PubComp(IChannelHandlerContext context, PubCompPacket packet)
        {
            var messageId   = packet.PacketId;
            var mqttChannel = _channelService.GetMqttChannel(await _channelService.GetDeviceId(context.Channel));
            var message     = mqttChannel.GetMqttMessage(messageId);

            if (message != null)
            {
                message.ConfirmStatus = ConfirmStatus.COMPLETE;
            }

            await context.WriteAndFlushAsync(packet);
        }
        async Task ReceiveAndCompleteCommandAsync(IChannel clientChannel, ReadListeningHandler readHandler, IotHubConnectionStringBuilder hubConnectionStringBuilder, Device device)
        {
            var packet = Assert.IsType <PublishPacket>(await readHandler.ReceiveAsync());

            Assert.Equal($"devices/{this.deviceId}/messages/devicebound", packet.TopicName);
            Assert.Equal(MethodContent, Encoding.UTF8.GetString(packet.Payload.ToArray()));

            await clientChannel.WriteAndFlushManyAsync(PubAckPacket.InResponseTo(packet), PubRecPacket.InResponseTo(packet));

            var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync());

            await clientChannel.WriteAndFlushManyAsync(
                PubCompPacket.InResponseTo(pubRelQoS2Packet2),
                DisconnectPacket.Instance);

            await this.EnsureDeviceQueueLengthAsync(hubConnectionStringBuilder.HostName, device, 0);
        }
Exemple #9
0
        Packet DecodePacketInternal(IByteBuffer buffer, byte packetSignature, ref int remainingLength)
        {
            Packet packet;
            var    fixedHeader = new FixedHeader(packetSignature, remainingLength);

            switch (fixedHeader.PacketType)
            {
            case PacketType.CONNECT: packet = new ConnectPacket(); break;

            case PacketType.CONNACK: packet = new ConnAckPacket(); break;

            case PacketType.DISCONNECT: packet = new DisconnectPacket(); break;

            case PacketType.PINGREQ: packet = new PingReqPacket(); break;

            case PacketType.PINGRESP: packet = new PingRespPacket(); break;

            case PacketType.PUBACK: packet = new PubAckPacket(); break;

            case PacketType.PUBCOMP: packet = new PubCompPacket(); break;

            case PacketType.PUBLISH: packet = new PublishPacket(); break;

            case PacketType.PUBREC: packet = new PubRecPacket(); break;

            case PacketType.PUBREL: packet = new PubRelPacket(); break;

            case PacketType.SUBSCRIBE: packet = new SubscribePacket(); break;

            case PacketType.SUBACK: packet = new SubAckPacket(); break;

            case PacketType.UNSUBSCRIBE: packet = new UnsubscribePacket(); break;

            case PacketType.UNSUBACK: packet = new UnsubscribePacket(); break;

            default:
                throw new DecoderException("Unsupported Message Type");
            }
            packet.FixedHeader = fixedHeader;
            packet.Decode(buffer);
            remainingLength = packet.RemaingLength;
            return(packet);
        }
            async Task GetPart2SpecificSteps(IChannel channel, ReadListeningHandler readHandler)
            {
                var packets = new Packet[2];
                for (int i = packets.Length - 1; i >= 0; i--)
                {
                    packets[i] = Assert.IsAssignableFrom<Packet>(await readHandler.ReceiveAsync());
                }

                PublishPacket qos1Packet = Assert.Single(packets.OfType<PublishPacket>());

                Assert.Equal(QualityOfService.AtLeastOnce, qos1Packet.QualityOfService);
                this.AssertPacketCoreValue(qos1Packet, Encoding.ASCII.GetString(qos1Packet.Payload.ToArray()));

                PubRelPacket pubRelQos2Packet = Assert.Single(packets.OfType<PubRelPacket>());

                await channel.WriteAndFlushManyAsync(
                    PubAckPacket.InResponseTo(qos1Packet),
                    PubCompPacket.InResponseTo(pubRelQos2Packet),
                    DisconnectPacket.Instance);
            }
            IEnumerable <TestScenarioStep> GetPart1SpecificSteps(Func <object> currentMessageFunc)
            {
                int publishQoS1PacketId = GetRandomPacketId();

                yield return(TestScenarioStep.Write(
                                 new PublishPacket(QualityOfService.AtMostOnce, false, false)
                {
                    //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId),
                    TopicName = $"devices/{this.clientId}/messages/events",
                    Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}"))
                },
                                 new PublishPacket(QualityOfService.AtLeastOnce, false, false)
                {
                    PacketId = publishQoS1PacketId,
                    TopicName = $"devices/{this.clientId}/messages/events",
                    Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}"))
                }));

                var packets = new Packet[5];

                for (int i = packets.Length - 1; i >= 0; i--)
                {
                    packets[i] = Assert.IsAssignableFrom <Packet>(currentMessageFunc());
                    if (i > 0)
                    {
                        yield return(TestScenarioStep.ReadMore());
                    }
                }

                PubAckPacket pubAckPacket = Assert.Single(packets.OfType <PubAckPacket>());

                Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId);

                PublishPacket publishQoS0Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce));

                this.AssertPacketCoreValue(publishQoS0Packet, NotificationQoS0Content);

                PublishPacket publishQoS1Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce));

                this.AssertPacketCoreValue(publishQoS1Packet, NotificationQoS1Content);

                PublishPacket[] publishQoS2Packets = packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce).Reverse().ToArray();
                Assert.Equal(2, publishQoS2Packets.Length);
                PublishPacket publishQoS2Packet1 = publishQoS2Packets[0];

                this.AssertPacketCoreValue(publishQoS2Packet1, NotificationQoS2Content);
                PublishPacket publishQoS2Packet2 = publishQoS2Packets[1];

                this.AssertPacketCoreValue(publishQoS2Packet2, NotificationQoS2Content2);

                yield return(TestScenarioStep.Write(
                                 PubAckPacket.InResponseTo(publishQoS1Packet),
                                 PubRecPacket.InResponseTo(publishQoS2Packet1),
                                 PubRecPacket.InResponseTo(publishQoS2Packet2)));

                var pubRelQoS2Packet1 = Assert.IsAssignableFrom <PubRelPacket>(currentMessageFunc());

                Assert.Equal(publishQoS2Packet1.PacketId, pubRelQoS2Packet1.PacketId);

                yield return(TestScenarioStep.ReadMore());

                var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(currentMessageFunc());

                Assert.Equal(publishQoS2Packet2.PacketId, pubRelQoS2Packet2.PacketId);

                yield return(TestScenarioStep.Write(
                                 false, // it is a final step and we do not expect response
                                 PubCompPacket.InResponseTo(pubRelQoS2Packet1),
                                 DisconnectPacket.Instance));

                // device queue still contains QoS 2 packet 2 which was PUBRECed but not PUBCOMPed.
            }
        static IEnumerable <TestScenarioStep> GetClientScenario(Func <object> currentMessageFunc, string iotHubName, string clientId, string password)
        {
            yield return(TestScenarioStep.Write(new ConnectPacket
            {
                ClientId = clientId,
                HasUsername = true,
                Username = iotHubName + "/" + clientId,
                HasPassword = true,
                Password = password,
                KeepAliveInSeconds = 120,
                HasWill = true,
                WillTopicName = "last/word",
                WillMessage = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("oops"))
            }));

            var connAckPacket = Assert.IsType <ConnAckPacket>(currentMessageFunc());

            Assert.Equal(ConnectReturnCode.Accepted, connAckPacket.ReturnCode);

            int subscribePacketId = GetRandomPacketId();

            yield return(TestScenarioStep.Write(new SubscribePacket
            {
                PacketId = subscribePacketId,
                Requests = new[]
                {
                    new SubscriptionRequest(string.Format("devices/{0}/messages/devicebound/#", clientId), QualityOfService.ExactlyOnce)
                }
            }));

            var subAckPacket = Assert.IsType <SubAckPacket>(currentMessageFunc());

            Assert.Equal(subscribePacketId, subAckPacket.PacketId);
            Assert.Equal(1, subAckPacket.ReturnCodes.Count);
            Assert.Equal(QualityOfService.ExactlyOnce, subAckPacket.ReturnCodes[0]);

            int publishQoS1PacketId = GetRandomPacketId();

            yield return(TestScenarioStep.Write(
                             new PublishPacket(QualityOfService.AtMostOnce, false, false)
            {
                //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId),
                TopicName = string.Format("devices/{0}/messages/events", clientId),
                Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}"))
            },
                             new PublishPacket(QualityOfService.AtLeastOnce, false, false)
            {
                PacketId = publishQoS1PacketId,
                TopicName = string.Format("devices/{0}/messages/events", clientId),
                Payload = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}"))
            }));

            var packets = new Packet[4];

            for (int i = packets.Length - 1; i >= 0; i--)
            {
                packets[i] = Assert.IsAssignableFrom <Packet>(currentMessageFunc());
                if (i > 0)
                {
                    yield return(TestScenarioStep.ReadMore());
                }
            }

            PubAckPacket pubAckPacket = Assert.Single(packets.OfType <PubAckPacket>());

            Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId);

            PublishPacket publishQoS0Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce));

            //Assert.Equal(string.Format("devices/{0}/messages/devicebound/tips", clientId), publishQoS0Packet.TopicName);
            Assert.Equal(string.Format("devices/{0}/messages/devicebound", clientId), publishQoS0Packet.TopicName);
            Assert.Equal(NotificationQoS0Content, Encoding.UTF8.GetString(publishQoS0Packet.Payload.ToArray()));

            PublishPacket publishQoS1Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce));

            //Assert.Equal(string.Format("devices/{0}/messages/devicebound/firmware-update", clientId), publishQoS1Packet.TopicName);
            Assert.Equal(string.Format("devices/{0}/messages/devicebound", clientId), publishQoS1Packet.TopicName);
            Assert.Equal(NotificationQoS1Content, Encoding.UTF8.GetString(publishQoS1Packet.Payload.ToArray()));

            PublishPacket publishQoS2Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce));

            //Assert.Equal(string.Format("devices/{0}/messages/devicebound/critical-alert", clientId), publishQoS2Packet.TopicName);
            Assert.Equal(string.Format("devices/{0}/messages/devicebound", clientId), publishQoS2Packet.TopicName);
            Assert.Equal(NotificationQoS2Content, Encoding.UTF8.GetString(publishQoS2Packet.Payload.ToArray()));

            yield return(TestScenarioStep.Write(
                             PubAckPacket.InResponseTo(publishQoS1Packet),
                             PubRecPacket.InResponseTo(publishQoS2Packet)));

            var pubRelQoS2Packet = Assert.IsAssignableFrom <PubRelPacket>(currentMessageFunc());

            Assert.Equal(publishQoS2Packet.PacketId, pubRelQoS2Packet.PacketId);

            yield return(TestScenarioStep.Write(
                             false, // it is a final step and we do not expect response
                             PubCompPacket.InResponseTo(pubRelQoS2Packet),
                             DisconnectPacket.Instance));
        }
Exemple #13
0
        Packet DecodePacketInternal(IByteBuffer buffer, int packetSignature, ref int remainingLength, IChannelHandlerContext context)
        {
            if (Signatures.IsPublish(packetSignature))
            {
                var qualityOfService = (QualityOfService)((packetSignature >> 1) & 0x3); // take bits #1 and #2 ONLY and convert them into QoS value
                if (qualityOfService == QualityOfService.Reserved)
                {
                    ThrowHelper.ThrowDecoderException_UnexpectedQoSValueForPublish(qualityOfService);
                }

                bool duplicate = (packetSignature & 0x8) == 0x8; // test bit#3
                bool retain    = (packetSignature & 0x1) != 0;   // test bit#0
                var  packet    = new PublishPacket(qualityOfService, duplicate, retain);
                DecodePublishPacket(buffer, packet, ref remainingLength);
                return(packet);
            }

            switch (packetSignature) // strict match checks for valid message type + correct values in flags part
            {
            case Signatures.PubAck:
                var pubAckPacket = new PubAckPacket();
                DecodePacketIdVariableHeader(buffer, pubAckPacket, ref remainingLength);
                return(pubAckPacket);

            case Signatures.PubRec:
                var pubRecPacket = new PubRecPacket();
                DecodePacketIdVariableHeader(buffer, pubRecPacket, ref remainingLength);
                return(pubRecPacket);

            case Signatures.PubRel:
                var pubRelPacket = new PubRelPacket();
                DecodePacketIdVariableHeader(buffer, pubRelPacket, ref remainingLength);
                return(pubRelPacket);

            case Signatures.PubComp:
                var pubCompPacket = new PubCompPacket();
                DecodePacketIdVariableHeader(buffer, pubCompPacket, ref remainingLength);
                return(pubCompPacket);

            case Signatures.PingReq:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                return(PingReqPacket.Instance);

            case Signatures.Subscribe:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                var subscribePacket = new SubscribePacket();
                DecodePacketIdVariableHeader(buffer, subscribePacket, ref remainingLength);
                DecodeSubscribePayload(buffer, subscribePacket, ref remainingLength);
                return(subscribePacket);

            case Signatures.Unsubscribe:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                var unsubscribePacket = new UnsubscribePacket();
                DecodePacketIdVariableHeader(buffer, unsubscribePacket, ref remainingLength);
                DecodeUnsubscribePayload(buffer, unsubscribePacket, ref remainingLength);
                return(unsubscribePacket);

            case Signatures.Connect:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                var connectPacket = new ConnectPacket();
                DecodeConnectPacket(buffer, connectPacket, ref remainingLength, context);
                return(connectPacket);

            case Signatures.Disconnect:
                if (!_isServer)
                {
                    ValidateServerPacketExpected(packetSignature);
                }
                return(DisconnectPacket.Instance);

            case Signatures.ConnAck:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                var connAckPacket = new ConnAckPacket();
                DecodeConnAckPacket(buffer, connAckPacket, ref remainingLength);
                return(connAckPacket);

            case Signatures.SubAck:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                var subAckPacket = new SubAckPacket();
                DecodePacketIdVariableHeader(buffer, subAckPacket, ref remainingLength);
                DecodeSubAckPayload(buffer, subAckPacket, ref remainingLength);
                return(subAckPacket);

            case Signatures.UnsubAck:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                var unsubAckPacket = new UnsubAckPacket();
                DecodePacketIdVariableHeader(buffer, unsubAckPacket, ref remainingLength);
                return(unsubAckPacket);

            case Signatures.PingResp:
                if (_isServer)
                {
                    ValidateClientPacketExpected(packetSignature);
                }
                return(PingRespPacket.Instance);

            default:
                return(ThrowHelper.FromDecoderException_FirstPacketByteValueIsInvalid(packetSignature));
            }
        }
 public abstract void PubComp(IChannelHandlerContext context, PubCompPacket packet);
Exemple #15
0
            async Task GetPart1SpecificSteps(IChannel channel, ReadListeningHandler readHandler)
            {
                int publishQoS1PacketId = 1003;
                await channel.WriteAndFlushManyAsync(
                    new PublishPacket(QualityOfService.AtMostOnce, false, false)
                {
                    //TopicName = string.Format("devices/{0}/messages/log/verbose/", clientId),
                    TopicName = $"devices/{this.clientId}/messages/events",
                    Payload   = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry-QoS0\"}"))
                },
                    new PublishPacket(QualityOfService.AtLeastOnce, false, false)
                {
                    PacketId  = publishQoS1PacketId,
                    TopicName = $"devices/{this.clientId}/messages/events",
                    Payload   = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("{\"test\": \"telemetry\"}"))
                });

                Packet[] packets = (await Task.WhenAll(Enumerable.Repeat(0, 6).Select(_ => readHandler.ReceiveAsync())))
                                   .Select(Assert.IsAssignableFrom <Packet>)
                                   .ToArray();

                PubAckPacket pubAckPacket = Assert.Single(packets.OfType <PubAckPacket>());

                Assert.Equal(publishQoS1PacketId, pubAckPacket.PacketId);

                PublishPacket publishQoS0Packet = Assert.Single(packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtMostOnce));

                this.AssertPacketCoreValue(publishQoS0Packet, "tips", NotificationQoS0Content);

                PublishPacket[] publishQoS1Packets = packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.AtLeastOnce).ToArray();
                Assert.Equal(2, publishQoS1Packets.Length);
                var qos1Notification = Assert.Single(publishQoS1Packets, x => x.TopicName.EndsWith("firmware-update"));

                this.AssertPacketCoreValue(qos1Notification, "firmware-update", NotificationQoS1Content);
                var methodCall = Assert.Single(publishQoS1Packets, x => x.TopicName.EndsWith("commands"));

                this.AssertPacketCoreValue(methodCall, "commands", MethodCallContent);

                PublishPacket[] publishQoS2Packets = packets.OfType <PublishPacket>().Where(x => x.QualityOfService == QualityOfService.ExactlyOnce).ToArray();
                Assert.Equal(2, publishQoS2Packets.Length);
                PublishPacket publishQoS2Packet1 = publishQoS2Packets[0];

                this.AssertPacketCoreValue(publishQoS2Packet1, "critical-alert", NotificationQoS2Content);
                PublishPacket publishQoS2Packet2 = publishQoS2Packets[1];

                this.AssertPacketCoreValue(publishQoS2Packet2, string.Empty, NotificationQoS2Content2);

                await channel.WriteAndFlushManyAsync(
                    PubAckPacket.InResponseTo(qos1Notification),
                    PubAckPacket.InResponseTo(methodCall),
                    PubRecPacket.InResponseTo(publishQoS2Packet1),
                    PubRecPacket.InResponseTo(publishQoS2Packet2));

                var pubRelQoS2Packet1 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync());

                Assert.Equal(publishQoS2Packet1.PacketId, pubRelQoS2Packet1.PacketId);

                var pubRelQoS2Packet2 = Assert.IsAssignableFrom <PubRelPacket>(await readHandler.ReceiveAsync());

                Assert.Equal(publishQoS2Packet2.PacketId, pubRelQoS2Packet2.PacketId);

                await channel.WriteAndFlushManyAsync(
                    PubCompPacket.InResponseTo(pubRelQoS2Packet1),
                    DisconnectPacket.Instance);

                // device queue still contains QoS 2 packet 2 which was PUBRECed but not PUBCOMPed.
            }