public async Task Unconfirmed_Cloud_To_Device_From_Decoder_Should_Call_ClassC_Message_Sender()
        {
            const uint PayloadFcnt           = 10;
            const uint InitialDeviceFcntUp   = 9;
            const uint InitialDeviceFcntDown = 20;
            var        devEui = new DevEui(2);

            var simulatedDevice = new SimulatedDevice(
                TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerConfiguration.GatewayID),
                frmCntUp: InitialDeviceFcntUp,
                frmCntDown: InitialDeviceFcntDown);

            var loraDevice = CreateLoRaDevice(simulatedDevice);

            LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null))
            .ReturnsAsync(true);

            LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>()))
            .ReturnsAsync((Message)null);

            var decoderResult = new DecodePayloadResult("1")
            {
                CloudToDeviceMessage = new ReceivedLoRaCloudToDeviceMessage()
                {
                    Fport     = FramePorts.App1,
                    MessageId = "123",
                    Payload   = "12",
                    DevEUI    = devEui,
                },
            };

            var payloadDecoder = new Mock <ILoRaPayloadDecoder>(MockBehavior.Strict);

            payloadDecoder.Setup(x => x.DecodeMessageAsync(simulatedDevice.DevEUI, It.IsNotNull <byte[]>(), FramePorts.App1, It.IsAny <string>()))
            .ReturnsAsync(decoderResult);
            PayloadDecoder.SetDecoder(payloadDecoder.Object);

            using var cache           = EmptyMemoryCache();
            using var loraDeviceCache = CreateDeviceCache(loraDevice);
            using var deviceRegistry  = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache);

            using var c2dMessageSent = new SemaphoreSlim(0);
            var classCMessageSender = new Mock <IClassCDeviceMessageSender>(MockBehavior.Strict);

            classCMessageSender.Setup(x => x.SendAsync(It.Is <IReceivedLoRaCloudToDeviceMessage>(m => !m.Confirmed && m.DevEUI == devEui), It.IsAny <CancellationToken>()))
            .ReturnsAsync(true)
            .Callback <IReceivedLoRaCloudToDeviceMessage, CancellationToken>((m, _) => c2dMessageSent.Release());
            RequestHandlerImplementation.SetClassCMessageSender(classCMessageSender.Object);

            // Send to message processor
            using var messageProcessor = new MessageDispatcher(
                      ServerConfiguration,
                      deviceRegistry,
                      FrameCounterUpdateStrategyProvider);

            var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: PayloadFcnt);

            using var request = CreateWaitableRequest(payload);
            messageProcessor.DispatchRequest(request);
            Assert.True(await request.WaitCompleteAsync());

            // Expectations
            // 1. Message was sent to IoT Hub
            LoRaDeviceClient.VerifyAll();
            LoRaDeviceApi.VerifyAll();

            // 2. No downstream message for the current device is sent
            Assert.Null(request.ResponseDownlink);
            Assert.True(request.ProcessingSucceeded);

            // 4. Frame counter up was updated
            Assert.Equal(PayloadFcnt, loraDevice.FCntUp);

            // 5. Frame counter down is unchanged
            Assert.Equal(InitialDeviceFcntDown, loraDevice.FCntDown);

            // 6. Frame count has pending changes
            Assert.True(loraDevice.HasFrameCountChanges);

            // Ensure the message was sent
            Assert.True(await c2dMessageSent.WaitAsync(10 * 1000));

            payloadDecoder.VerifyAll();
            classCMessageSender.VerifyAll();
        }
        public async Task When_Using_Custom_Fails_Returns_Sets_Error_Information_In_Value()
        {
            var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerGatewayID));
            var loRaDevice      = CreateLoRaDevice(simulatedDevice);

            loRaDevice.SensorDecoder = "http://customdecoder/test1";

            // message will be sent
            LoRaDeviceTelemetry loRaDeviceTelemetry = null;

            LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null))
            .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => loRaDeviceTelemetry = t)
            .ReturnsAsync(true);

            // C2D message will be checked
            LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>()))
            .ReturnsAsync((Message)null);

            using var cache           = EmptyMemoryCache();
            using var loraDeviceCache = CreateDeviceCache(loRaDevice);
            using var deviceRegistry  = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache);

            // Send to message processor
            using var messageDispatcher = new MessageDispatcher(
                      ServerConfiguration,
                      deviceRegistry,
                      FrameCounterUpdateStrategyProvider);

            using var httpMessageHandler = new HttpMessageHandlerMock();
            httpMessageHandler.SetupHandler((r) =>
            {
                return(new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
                {
                    Content = new StringContent("my error", Encoding.UTF8, "application/json"),
                });
            });

            using var httpClient = new HttpClient(httpMessageHandler);
            PayloadDecoder.SetDecoder(new LoRaPayloadDecoder(httpClient));

            // sends unconfirmed message
            var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 1);

            using var request = CreateWaitableRequest(unconfirmedMessagePayload);
            messageDispatcher.DispatchRequest(request);
            Assert.True(await request.WaitCompleteAsync());

            Assert.NotNull(loRaDeviceTelemetry);
            var rawPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes("1"));

            Assert.Equal(rawPayload, loRaDeviceTelemetry.Rawdata);
            Assert.IsType <DecodingFailedPayload>(loRaDeviceTelemetry.Data);
            var decodedPayload = (DecodingFailedPayload)loRaDeviceTelemetry.Data;

            Assert.Equal("SensorDecoderModule 'http://customdecoder/test1?devEUI=0000000000000001&fport=1&payload=MQ%3d%3d' returned bad request.", decodedPayload.Error);
            Assert.Equal("my error", decodedPayload.ErrorDetail);

            // Validate json
            var actualJsonTelemetry   = JsonConvert.SerializeObject(loRaDeviceTelemetry, Formatting.None);
            var expectedTelemetryJson = $"{{\"time\":100000,\"tmms\":100000,\"freq\":868.3,\"chan\":2,\"rfch\":1,\"modu\":\"LoRa\",\"datr\":\"SF10BW125\",\"rssi\":2.0,\"lsnr\":0.1,\"data\":{{\"error\":\"SensorDecoderModule 'http://customdecoder/test1?devEUI=0000000000000001&fport=1&payload=MQ%3d%3d' returned bad request.\",\"errorDetail\":\"my error\"}},\"port\":1,\"fcnt\":1,\"edgets\":{loRaDeviceTelemetry.Edgets},\"rawdata\":\"{ rawPayload}\",\"eui\":\"0000000000000001\",\"gatewayid\":\"test-gateway\",\"stationeui\":\"0000000000000000\"}}";

            Assert.Equal(expectedTelemetryJson, actualJsonTelemetry);

            LoRaDeviceApi.VerifyAll();
            LoRaDeviceClient.VerifyAll();
        }
        public async Task When_Resent_Message_Using_Custom_Decoder_Returns_Complex_Object_Should_Send_Decoded_Value()
        {
            var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerGatewayID));
            var loRaDevice      = CreateLoRaDevice(simulatedDevice);

            loRaDevice.SensorDecoder = "http://customdecoder/test1";

            // message will be sent
            LoRaDeviceTelemetry loRaDeviceTelemetry = null;

            _ = LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null))
                .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => loRaDeviceTelemetry = t)
                .ReturnsAsync(true);
            _ = LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>(), It.IsAny <CancellationToken>())).ReturnsAsync(true);

            // C2D message will be checked
            // LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull<TimeSpan>()))
            // .ReturnsAsync((Message)null);
            using var cache           = EmptyMemoryCache();
            using var loraDeviceCache = CreateDeviceCache(loRaDevice);
            using var deviceRegistry  = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache);

            // Send to message processor
            using var messageDispatcher = new MessageDispatcher(
                      ServerConfiguration,
                      deviceRegistry,
                      FrameCounterUpdateStrategyProvider);

            var decodedObject = new { temp = 10, humidity = 22.1, text = "abc", cloudToDeviceMessage = new { test = 1 } };

            using var httpMessageHandler = new HttpMessageHandlerMock();
            _ = httpMessageHandler.SetupHandler((r) =>
            {
                return(new HttpResponseMessage(System.Net.HttpStatusCode.OK)
                {
                    Content = new StringContent(JsonConvert.SerializeObject(decodedObject), Encoding.UTF8, "application/json"),
                });
            });

            using var httpClient = new HttpClient(httpMessageHandler);
            PayloadDecoder.SetDecoder(new LoRaPayloadDecoder(httpClient));

            // sends confirmed message
            var confirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("1", fcnt: 10);

            using var request = CreateWaitableRequest(confirmedMessagePayload);
            messageDispatcher.DispatchRequest(request);
            Assert.True(await request.WaitCompleteAsync());
            Assert.NotNull(request.ResponseDownlink);

            Assert.NotNull(loRaDeviceTelemetry);
            var rawPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes("1"));

            Assert.Equal(rawPayload, loRaDeviceTelemetry.Rawdata);

            // Validate json
            var actualJsonTelemetry = JsonConvert.SerializeObject(loRaDeviceTelemetry, Formatting.None);

            var expectedTelemetryJson = $"{{\"time\":100000,\"tmms\":100000,\"freq\":868.3,\"chan\":2,\"rfch\":1,\"modu\":\"LoRa\",\"datr\":\"SF10BW125\",\"rssi\":2.0,\"lsnr\":0.1,\"data\":{{\"temp\":10,\"humidity\":22.1,\"text\":\"abc\"}},\"port\":1,\"fcnt\":10,\"edgets\":{loRaDeviceTelemetry.Edgets},\"rawdata\":\"{rawPayload}\",\"eui\":\"0000000000000001\",\"gatewayid\":\"test-gateway\",\"stationeui\":\"0000000000000000\"}}";

            Assert.Equal(expectedTelemetryJson, actualJsonTelemetry);

            // send a second confirmed message with same fcnt to simulate
            using var request2 = CreateWaitableRequest(confirmedMessagePayload);
            messageDispatcher.DispatchRequest(request2);
            Assert.True(await request2.WaitCompleteAsync());
            Assert.NotNull(request2.ResponseDownlink);
            Assert.NotNull(loRaDeviceTelemetry);
            var rawPayload2 = Convert.ToBase64String(Encoding.UTF8.GetBytes("1"));

            Assert.Equal(rawPayload2, loRaDeviceTelemetry.Rawdata);
            LoRaDeviceClient.Verify(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null), Times.Exactly(2));
            LoRaDeviceApi.VerifyAll();
            LoRaDeviceClient.VerifyAll();
        }
Пример #4
0
        public async Task Unconfirmed_Cloud_To_Device_From_Decoder_Should_Send_Downstream_Message(string c2dDevEUI)
        {
            const uint PayloadFcnt           = 10;
            const uint InitialDeviceFcntUp   = 9;
            const uint InitialDeviceFcntDown = 20;

            var simulatedDevice = new SimulatedDevice(
                TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerConfiguration.GatewayID),
                frmCntUp: InitialDeviceFcntUp,
                frmCntDown: InitialDeviceFcntDown);

            var loraDevice = CreateLoRaDevice(simulatedDevice);

            LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null))
            .ReturnsAsync(true);

            var decoderResult = new DecodePayloadResult("1")
            {
                CloudToDeviceMessage = new ReceivedLoRaCloudToDeviceMessage()
                {
                    Fport     = TestPort,
                    MessageId = "123",
                    Payload   = "12",
                    DevEUI    = c2dDevEUI is { } someDevEui?DevEui.Parse(someDevEui) : null
                },
            };

            var payloadDecoder = new Mock <ILoRaPayloadDecoder>(MockBehavior.Strict);

            payloadDecoder.Setup(x => x.DecodeMessageAsync(simulatedDevice.DevEUI, It.IsNotNull <byte[]>(), TestPort, It.IsAny <string>()))
            .ReturnsAsync(decoderResult);
            PayloadDecoder.SetDecoder(payloadDecoder.Object);

            using var cache           = EmptyMemoryCache();
            using var loraDeviceCache = CreateDeviceCache(loraDevice);
            using var deviceRegistry  = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache);

            // Send to message processor
            using var messageProcessor = new MessageDispatcher(
                      ServerConfiguration,
                      deviceRegistry,
                      FrameCounterUpdateStrategyProvider);

            var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: PayloadFcnt);

            using var request = CreateWaitableRequest(payload);
            messageProcessor.DispatchRequest(request);
            Assert.True(await request.WaitCompleteAsync());

            // Expectations
            // 1. Message was sent to IoT Hub
            LoRaDeviceClient.VerifyAll();
            LoRaDeviceApi.VerifyAll();

            // 2. Return is downstream message
            Assert.NotNull(request.ResponseDownlink);
            Assert.True(request.ProcessingSucceeded);
            Assert.Single(DownstreamMessageSender.DownlinkMessages);
            var downlinkMessage = DownstreamMessageSender.DownlinkMessages[0];
            var payloadDataDown = new LoRaPayloadData(downlinkMessage.Data);

            payloadDataDown.Serialize(loraDevice.AppSKey.Value);
            Assert.Equal(payloadDataDown.DevAddr, loraDevice.DevAddr);
            Assert.False(payloadDataDown.IsConfirmed);
            Assert.Equal(MacMessageType.UnconfirmedDataDown, payloadDataDown.MessageType);

            // 4. Frame counter up was updated
            Assert.Equal(PayloadFcnt, loraDevice.FCntUp);

            // 5. Frame counter down is updated
            Assert.Equal(InitialDeviceFcntDown + 1, loraDevice.FCntDown);
            Assert.Equal(InitialDeviceFcntDown + 1, payloadDataDown.Fcnt);

            // 6. Frame count has pending changes
            Assert.True(loraDevice.HasFrameCountChanges);

            LoRaDeviceApi.VerifyAll();
            LoRaDeviceClient.VerifyAll();

            payloadDecoder.VerifyAll();
        }