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(); }
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(); }