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 = this.CreateLoRaDevice(simulatedDevice); loRaDevice.SensorDecoder = "http://customdecoder/test1"; // message will be sent LoRaDeviceTelemetry loRaDeviceTelemetry = null; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => loRaDeviceTelemetry = t) .ReturnsAsync(true); // C2D message will be checked // this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull<TimeSpan>())) // .ReturnsAsync((Message)null); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(loRaDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var decodedObject = new { temp = 10, humidity = 22.1, text = "abc", cloudToDeviceMessage = new { test = 1 } }; var httpMessageHandler = new HttpMessageHandlerMock(); httpMessageHandler.SetupHandler((r) => { return(new HttpResponseMessage(System.Net.HttpStatusCode.OK) { Content = new StringContent(JsonConvert.SerializeObject(decodedObject), Encoding.UTF8, "application/json"), }); }); this.PayloadDecoder.SetDecoder(new LoRaPayloadDecoder(new HttpClient(httpMessageHandler))); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 10); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request = new WaitableLoRaRequest(rxpk, this.PacketForwarder); 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\":null,\"tmms\":0,\"tmst\":0,\"freq\":868.3,\"chan\":0,\"rfch\":1,\"stat\":0,\"modu\":\"LORA\",\"datr\":\"SF10BW125\",\"codr\":\"4/5\",\"rssi\":0,\"lsnr\":0.0,\"size\":{loRaDeviceTelemetry.Size},\"data\":{{\"temp\":10,\"humidity\":22.1,\"text\":\"abc\"}},\"port\":1,\"fcnt\":10,\"rawdata\":\"{rawPayload}\",\"eui\":\"0000000000000001\",\"gatewayid\":\"test-gateway\",\"edgets\":{loRaDeviceTelemetry.Edgets}}}"; Assert.Equal(expectedTelemetryJson, actualJsonTelemetry); // send a second message with same fcnt to simulate // sends unconfirmed message var confirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("1", fcnt: 10); var rxpk2 = confirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request2 = new WaitableLoRaRequest(rxpk2, this.PacketForwarder); 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(rawPayload, loRaDeviceTelemetry.Rawdata); // Only the first message should be sent this.LoRaDeviceClient.Verify(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null), Times.Once()); this.LoRaDeviceApi.VerifyAll(); this.LoRaDeviceClient.VerifyAll(); }
public async Task When_Queueing_To_Multiple_Devices_With_Same_DevAddr_Should_Queue_To_Device_Matching_Mic(string deviceGatewayID) { var simulatedDevice1 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); var payload = simulatedDevice1.CreateUnconfirmedDataUpMessage("1234"); payload.SerializeUplink(simulatedDevice1.AppSKey, simulatedDevice1.NwkSKey); var loRaDeviceClient1 = new Mock<ILoRaDeviceClient>(MockBehavior.Strict); loRaDeviceClient1.Setup(x => x.GetTwinAsync()) .ReturnsAsync(simulatedDevice1.CreateABPTwin()); var loraDevice1 = TestUtils.CreateFromSimulatedDevice(simulatedDevice1, loRaDeviceClient1.Object); var devAddr = loraDevice1.DevAddr; WaitableLoRaRequest request = null; var reqHandler1 = new Mock<ILoRaDataRequestHandler>(MockBehavior.Strict); reqHandler1.Setup(x => x.ProcessRequestAsync(It.IsNotNull<LoRaRequest>(), loraDevice1)) .ReturnsAsync(new LoRaDeviceRequestProcessResult(loraDevice1, request)); loraDevice1.SetRequestHandler(reqHandler1.Object); var simulatedDevice2 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); simulatedDevice2.LoRaDevice.DeviceID = "00000002"; simulatedDevice2.LoRaDevice.NwkSKey = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; var loRaDeviceClient2 = new Mock<ILoRaDeviceClient>(MockBehavior.Strict); loRaDeviceClient2.Setup(x => x.GetTwinAsync()) .ReturnsAsync(simulatedDevice2.CreateABPTwin()); var loraDevice2 = TestUtils.CreateFromSimulatedDevice(simulatedDevice2, loRaDeviceClient2.Object); // Api service: search devices async var iotHubDeviceInfo1 = new IoTHubDeviceInfo(devAddr, loraDevice1.DevEUI, string.Empty); var iotHubDeviceInfo2 = new IoTHubDeviceInfo(devAddr, loraDevice2.DevEUI, string.Empty); var apiService = new Mock<LoRaDeviceAPIServiceBase>(); apiService.Setup(x => x.SearchByDevAddrAsync(devAddr)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo[] { iotHubDeviceInfo2, iotHubDeviceInfo1, })); // Device factory: create 2 devices this.loraDeviceFactoryMock.Setup(x => x.Create(iotHubDeviceInfo1)).Returns(loraDevice1); this.loraDeviceFactoryMock.Setup(x => x.Create(iotHubDeviceInfo2)).Returns(loraDevice2); var target = new LoRaDeviceRegistry(this.serverConfiguration, this.cache, apiService.Object, this.loraDeviceFactoryMock.Object); request = new WaitableLoRaRequest(payload); target.GetLoRaRequestQueue(request).Queue(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); // Device was searched by DevAddr apiService.VerifyAll(); // Device was created by factory this.loraDeviceFactoryMock.VerifyAll(); // Both devices are in cache var devicesByDevAddrDictionary = target.InternalGetCachedDevicesForDevAddr(devAddr); Assert.NotNull(devicesByDevAddrDictionary); Assert.Equal(2, devicesByDevAddrDictionary.Count); // 2 devices with same devAddr exist in cache // find device 1 Assert.True(devicesByDevAddrDictionary.TryGetValue(loraDevice1.DevEUI, out var actualCachedLoRaDevice1)); Assert.Same(loraDevice1, actualCachedLoRaDevice1); Assert.True(loraDevice1.IsOurDevice); // find device 2 Assert.True(devicesByDevAddrDictionary.TryGetValue(loraDevice2.DevEUI, out var actualCachedLoRaDevice2)); Assert.Same(loraDevice2, actualCachedLoRaDevice2); Assert.True(loraDevice2.IsOurDevice); reqHandler1.VerifyAll(); loRaDeviceClient1.VerifyAll(); loRaDeviceClient2.VerifyAll(); }
public async Task When_ABP_New_Loaded_Device_With_Fcnt_1_Or_0_Should_Reset_Fcnt_And_Send_To_IotHub( uint payloadFcntUp, uint?deviceTwinFcntUp, uint?deviceTwinFcntDown) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1)); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; // message will be sent LoRaDeviceTelemetry loRaDeviceTelemetry = null; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => loRaDeviceTelemetry = t) .ReturnsAsync(true); // C2D message will be checked this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); // twin will be loaded var initialTwin = new Twin(); initialTwin.Properties.Desired[TwinProperty.DevEUI] = devEUI; initialTwin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; initialTwin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; initialTwin.Properties.Desired[TwinProperty.NwkSKey] = simulatedDevice.LoRaDevice.NwkSKey; initialTwin.Properties.Desired[TwinProperty.AppSKey] = simulatedDevice.LoRaDevice.AppSKey; initialTwin.Properties.Desired[TwinProperty.DevAddr] = devAddr; initialTwin.Properties.Desired[TwinProperty.GatewayID] = this.ServerConfiguration.GatewayID; initialTwin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; if (deviceTwinFcntDown.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntDown] = deviceTwinFcntDown.Value; } if (deviceTwinFcntUp.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntUp] = deviceTwinFcntUp.Value; } this.LoRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(initialTwin); // twin will be updated with new fcnt uint?fcntUpSavedInTwin = null; uint?fcntDownSavedInTwin = null; var expectedToSaveTwin = deviceTwinFcntDown > 0 || deviceTwinFcntUp > 0; if (expectedToSaveTwin) { // Twin will be save (0, 0) only if it was not 0, 0 this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((t) => { fcntUpSavedInTwin = (uint)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (uint)t[TwinProperty.FCntDown]; }) .ReturnsAsync(true); } // device api will be searched for payload this.LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "abc").AsList())); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewMemoryCache(), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("hello", fcnt: payloadFcntUp); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request = new WaitableLoRaRequest(rxpk, this.PacketForwarder); messageDispatcher.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.Null(request.ResponseDownlink); // Ensure that a telemetry was sent Assert.NotNull(loRaDeviceTelemetry); // Assert.Equal(msgPayload, loRaDeviceTelemetry.data); // Ensure that the device twins were saved if (expectedToSaveTwin) { Assert.NotNull(fcntDownSavedInTwin); Assert.NotNull(fcntUpSavedInTwin); Assert.Equal(0U, fcntDownSavedInTwin.Value); Assert.Equal(0U, fcntUpSavedInTwin.Value); } // Adding the loaded devices to the cache can take a while, give it time await Task.Delay(50); // verify that the device in device registry has correct properties and frame counters var devicesForDevAddr = deviceRegistry.InternalGetCachedDevicesForDevAddr(devAddr); Assert.Single(devicesForDevAddr); Assert.True(devicesForDevAddr.TryGetValue(devEUI, out var loRaDevice)); Assert.Equal(devAddr, loRaDevice.DevAddr); Assert.Equal(devEUI, loRaDevice.DevEUI); Assert.True(loRaDevice.IsABP); Assert.Equal(payloadFcntUp, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); if (payloadFcntUp == 0) { Assert.False(loRaDevice.HasFrameCountChanges); // no changes } else { Assert.True(loRaDevice.HasFrameCountChanges); // there are pending changes (fcntUp 0 => 1) } this.LoRaDeviceClient.VerifyAll(); this.LoRaDeviceApi.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 = this.CreateLoRaDevice(simulatedDevice); loRaDevice.SensorDecoder = "http://customdecoder/test1"; // message will be sent LoRaDeviceTelemetry loRaDeviceTelemetry = null; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => loRaDeviceTelemetry = t) .ReturnsAsync(true); // C2D message will be checked this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(loRaDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var httpMessageHandler = new HttpMessageHandlerMock(); httpMessageHandler.SetupHandler((r) => { return(new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest) { Content = new StringContent("my error", Encoding.UTF8, "application/json"), }); }); this.PayloadDecoder.SetDecoder(new LoRaPayloadDecoder(new HttpClient(httpMessageHandler))); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 1); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request = new WaitableLoRaRequest(rxpk, this.PacketForwarder); 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\":null,\"tmms\":0,\"tmst\":0,\"freq\":868.3,\"chan\":0,\"rfch\":1,\"stat\":0,\"modu\":\"LORA\",\"datr\":\"SF10BW125\",\"codr\":\"4/5\",\"rssi\":0,\"lsnr\":0.0,\"size\":{loRaDeviceTelemetry.Size},\"data\":{{\"error\":\"SensorDecoderModule 'http://customdecoder/test1?devEUI=0000000000000001&fport=1&payload=MQ%3d%3d' returned bad request.\",\"errorDetail\":\"my error\"}},\"port\":1,\"fcnt\":1,\"rawdata\":\"{rawPayload}\",\"eui\":\"0000000000000001\",\"gatewayid\":\"test-gateway\",\"edgets\":{loRaDeviceTelemetry.Edgets}}}"; Assert.Equal(expectedTelemetryJson, actualJsonTelemetry); this.LoRaDeviceApi.VerifyAll(); this.LoRaDeviceClient.VerifyAll(); }
public async Task Validate_Limits( uint payloadFcntUp, uint?deviceFcntUp, uint?deviceFcntDown, uint?startFcntUp, uint?startFcntDown, uint expectedFcntUp, uint expectedFcntDown, bool abpRelaxed, bool confirmed, bool supports32Bit = false, LoRaDeviceRequestFailedReason?failedReason = null) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: this.ServerConfiguration.GatewayID, supports32BitFcnt: supports32Bit)); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)).ReturnsAsync(true); var initialTwin = SetupTwins(deviceFcntUp, deviceFcntDown, startFcntUp, startFcntDown, abpRelaxed, supports32Bit, simulatedDevice, devEUI, devAddr); this.LoRaDeviceClient .Setup(x => x.GetTwinAsync()).Returns(() => { return(Task.FromResult(initialTwin)); }); uint?fcntUpSavedInTwin = null; uint?fcntDownSavedInTwin = null; this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Returns <TwinCollection>((t) => { fcntUpSavedInTwin = (uint)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (uint)t[TwinProperty.FCntDown]; return(Task.FromResult(true)); }); this.LoRaDeviceClient .Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync((Message)null); var shouldReset = payloadFcntUp == 0 && abpRelaxed; if (shouldReset) { this.LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEUI, It.IsAny <uint>(), It.IsNotNull <string>())).ReturnsAsync(true); } this.LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "abc").AsList())); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); WaitableLoRaRequest req = null; if (confirmed) { var payload = simulatedDevice.CreateConfirmedDataUpMessage("1234", fcnt: (uint)payloadFcntUp); var rxpk = payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; req = this.CreateWaitableRequest(rxpk); } else { var rxpk = simulatedDevice.CreateUnconfirmedMessageUplink("1234", fcnt: (uint)payloadFcntUp).Rxpk[0]; req = new WaitableLoRaRequest(rxpk, this.PacketForwarder); } messageDispatcher.DispatchRequest(req); Assert.True(await req.WaitCompleteAsync(-1)); if (failedReason.HasValue) { Assert.Equal(failedReason.Value, req.ProcessingFailedReason); } else { Assert.True(req.ProcessingSucceeded); Assert.True(this.LoRaDeviceFactory.TryGetLoRaDevice(devEUI, out var loRaDevice)); if (confirmed) { Assert.NotNull(req.ResponseDownlink); Assert.True(req.ProcessingSucceeded); Assert.Single(this.PacketForwarder.DownlinkMessages); var downlinkMessage = this.PacketForwarder.DownlinkMessages[0]; var payloadDataDown = new LoRaPayloadData(Convert.FromBase64String(downlinkMessage.Txpk.Data)); payloadDataDown.PerformEncryption(simulatedDevice.AppSKey); Assert.Equal(expectedFcntDown, payloadDataDown.GetFcnt()); } Assert.Equal(expectedFcntUp, loRaDevice.FCntUp); } }
public async Task ValidateFcnt_Start_Values_And_ResetCounter( short fcntUp, uint startFcntUpDesired, uint startFcntDownDesired, uint?startFcntUpReported, uint?startFcntDownReported, int?fcntResetCounterDesired, int?fcntResetCounterReported, uint startUpExpected, uint startDownExpected, bool saveExpected) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: this.ServerConfiguration.GatewayID)); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)).ReturnsAsync(true); var initialTwin = SetupTwins((uint)fcntUp, startFcntDownDesired, startFcntUpDesired, startFcntDownDesired, true, false, simulatedDevice, devEUI, devAddr); if (startFcntUpReported.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntUpStart] = startFcntUpReported.Value; } if (startFcntDownReported.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntDownStart] = startFcntDownReported.Value; } if (fcntResetCounterDesired.HasValue) { initialTwin.Properties.Desired[TwinProperty.FCntResetCounter] = fcntResetCounterDesired.Value; } if (fcntResetCounterReported.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntResetCounter] = fcntResetCounterReported.Value; } this.LoRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(initialTwin); uint?fcntUpSavedInTwin = null; uint?fcntDownSavedInTwin = null; uint?fcntStartUpSavedInTwin = null; uint?fcntStartDownSavedInTwin = null; this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Returns <TwinCollection>((t) => { fcntUpSavedInTwin = (uint)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (uint)t[TwinProperty.FCntDown]; fcntStartUpSavedInTwin = (uint)t[TwinProperty.FCntUpStart]; fcntStartDownSavedInTwin = (uint)t[TwinProperty.FCntDownStart]; return(Task.FromResult(true)); }); this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())).ReturnsAsync((Message)null); this.LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)).ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "abc").AsList())); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var rxpk = simulatedDevice.CreateUnconfirmedMessageUplink("1234", fcnt: (uint)fcntUp).Rxpk[0]; var req = new WaitableLoRaRequest(rxpk, this.PacketForwarder); messageDispatcher.DispatchRequest(req); await req.WaitCompleteAsync(); if (saveExpected) { Assert.True(req.ProcessingSucceeded); this.LoRaDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>()), Times.Exactly(1)); Assert.Equal(fcntUpSavedInTwin, fcntStartUpSavedInTwin); Assert.Equal(fcntDownSavedInTwin, fcntStartDownSavedInTwin); Assert.Equal(startUpExpected, fcntStartUpSavedInTwin.Value); Assert.Equal(startDownExpected, fcntStartDownSavedInTwin.Value); } else { this.LoRaDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>()), Times.Never()); } }
public async Task ABP_Load_And_Receiving_Multiple_Unconfirmed_Should_Send_All_ToHub(ParallelTestConfiguration parallelTestConfiguration) { Console.WriteLine("---"); var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(parallelTestConfiguration.DeviceID ?? 1, gatewayID: null)); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; // Using loose mock because sometimes we might call receive async var looseDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Loose); this.LoRaDeviceFactory.SetClient(devEUI, looseDeviceClient.Object); looseDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync((Message)null); // message will be sent var sentTelemetry = new List <LoRaDeviceTelemetry>(); looseDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Returns <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => { sentTelemetry.Add(t); var duration = parallelTestConfiguration.SendEventDuration.Next(); Console.WriteLine($"{nameof(looseDeviceClient.Object.SendEventAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith((a) => true, TaskContinuationOptions.ExecuteSynchronously)); }); // twin will be loaded var initialTwin = new Twin(); initialTwin.Properties.Desired[TwinProperty.DevEUI] = devEUI; initialTwin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; initialTwin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; initialTwin.Properties.Desired[TwinProperty.NwkSKey] = simulatedDevice.LoRaDevice.NwkSKey; initialTwin.Properties.Desired[TwinProperty.AppSKey] = simulatedDevice.LoRaDevice.AppSKey; initialTwin.Properties.Desired[TwinProperty.DevAddr] = devAddr; if (parallelTestConfiguration.GatewayID != null) { initialTwin.Properties.Desired[TwinProperty.GatewayID] = parallelTestConfiguration.GatewayID; } initialTwin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; if (parallelTestConfiguration.DeviceTwinFcntDown.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntDown] = parallelTestConfiguration.DeviceTwinFcntDown.Value; } if (parallelTestConfiguration.DeviceTwinFcntUp.HasValue) { initialTwin.Properties.Reported[TwinProperty.FCntUp] = parallelTestConfiguration.DeviceTwinFcntUp.Value; } looseDeviceClient.Setup(x => x.GetTwinAsync()) .Returns(() => { var duration = parallelTestConfiguration.LoadTwinDuration.Next(); Console.WriteLine($"{nameof(looseDeviceClient.Object.GetTwinAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith(_ => initialTwin, TaskContinuationOptions.ExecuteSynchronously)); }); // twin will be updated with new fcnt var expectedToSaveTwin = parallelTestConfiguration.DeviceTwinFcntDown > 0 || parallelTestConfiguration.DeviceTwinFcntUp > 0; uint?fcntUpSavedInTwin = null; uint?fcntDownSavedInTwin = null; if (expectedToSaveTwin) { looseDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Returns <TwinCollection>((t) => { fcntUpSavedInTwin = (uint)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (uint)t[TwinProperty.FCntDown]; var duration = parallelTestConfiguration.UpdateTwinDuration.Next(); Console.WriteLine($"{nameof(looseDeviceClient.Object.UpdateReportedPropertiesAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith((a) => true, TaskContinuationOptions.ExecuteSynchronously)); }); } if (expectedToSaveTwin && string.IsNullOrEmpty(parallelTestConfiguration.GatewayID)) { this.LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEUI)) .Returns(() => { var duration = parallelTestConfiguration.DeviceApiResetFcntDuration.Next(); Console.WriteLine($"{nameof(this.LoRaDeviceApi.Object.ABPFcntCacheResetAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith((a) => true, TaskContinuationOptions.ExecuteSynchronously)); }); } // device api will be searched for payload this.LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)) .Returns(() => { var duration = parallelTestConfiguration.SearchByDevAddrDuration.Next(); Console.WriteLine($"{nameof(this.LoRaDeviceApi.Object.SearchByDevAddrAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith((a) => new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "abc").AsList()), TaskContinuationOptions.ExecuteSynchronously)); }); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); // sends unconfirmed message var unconfirmedMessage1 = simulatedDevice.CreateUnconfirmedMessageUplink("1", fcnt: 1).Rxpk[0]; var unconfirmedMessage2 = simulatedDevice.CreateUnconfirmedMessageUplink("2", fcnt: 2).Rxpk[0]; var unconfirmedMessage3 = simulatedDevice.CreateUnconfirmedMessageUplink("3", fcnt: 3).Rxpk[0]; var req1 = new WaitableLoRaRequest(unconfirmedMessage1, this.packetForwarder); messageDispatcher.DispatchRequest(req1); await Task.Delay(parallelTestConfiguration.BetweenMessageDuration.Next()); var req2 = new WaitableLoRaRequest(unconfirmedMessage2, this.packetForwarder); messageDispatcher.DispatchRequest(req2); await Task.Delay(parallelTestConfiguration.BetweenMessageDuration.Next()); var req3 = new WaitableLoRaRequest(unconfirmedMessage3, this.packetForwarder); messageDispatcher.DispatchRequest(req3); await Task.Delay(parallelTestConfiguration.BetweenMessageDuration.Next()); await Task.WhenAll(req1.WaitCompleteAsync(20000), req2.WaitCompleteAsync(20000), req3.WaitCompleteAsync(20000)); var allRequests = new[] { req1, req2, req3 }; Assert.All(allRequests, x => Assert.Null(x.ResponseDownlink)); Assert.All(allRequests, x => Assert.True(x.ProcessingSucceeded)); looseDeviceClient.Verify(x => x.GetTwinAsync(), Times.Exactly(1)); if (expectedToSaveTwin) { looseDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>()), Times.Exactly(1)); } this.LoRaDeviceApi.Verify(x => x.SearchByDevAddrAsync(devAddr), Times.Once); // Ensure that all telemetry was sent Assert.Equal(3, sentTelemetry.Count); // Ensure data was sent in order Assert.Equal(1, sentTelemetry[0].Fcnt); Assert.Equal(2, sentTelemetry[1].Fcnt); Assert.Equal(3, sentTelemetry[2].Fcnt); // Ensure that the device twins were saved if (expectedToSaveTwin) { Assert.NotNull(fcntDownSavedInTwin); Assert.NotNull(fcntUpSavedInTwin); Assert.Equal(0U, fcntDownSavedInTwin.Value); Assert.Equal(0U, fcntUpSavedInTwin.Value); } // verify that the device in device registry has correct properties and frame counters var devicesForDevAddr = deviceRegistry.InternalGetCachedDevicesForDevAddr(devAddr); Assert.Single(devicesForDevAddr); Assert.True(devicesForDevAddr.TryGetValue(devEUI, out var loRaDevice)); Assert.Equal(devAddr, loRaDevice.DevAddr); Assert.Equal(devEUI, loRaDevice.DevEUI); Assert.True(loRaDevice.IsABP); Assert.Equal(3U, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); Assert.True(loRaDevice.HasFrameCountChanges); // should have changes! // looseDeviceClient.VerifyAll(); this.LoRaDeviceApi.VerifyAll(); }
public async Task After_Disconnecting_Should_Reconnect() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1)); simulatedDevice.FrmCntUp = 10; var isDisconnected = false; // message will be sent LoRaDeviceTelemetry loRaDeviceTelemetry = null; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => { Assert.False(isDisconnected); loRaDeviceTelemetry = t; }) .ReturnsAsync(true); // C2D message will be checked this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .Callback(() => { Assert.False(isDisconnected); }) .ReturnsAsync((Message)null); // will check client connection this.LoRaDeviceClient.Setup(x => x.EnsureConnected()) .Callback(() => isDisconnected = false) .Returns(true); // will disconnected client var disconnectedEvent = new SemaphoreSlim(0, 1); this.LoRaDeviceClient.Setup(x => x.Disconnect()) .Callback(() => { disconnectedEvent.Release(); isDisconnected = true; }) .Returns(true); var cachedDevice = this.CreateLoRaDevice(simulatedDevice); cachedDevice.KeepAliveTimeout = 3; var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(cachedDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); // sends unconfirmed message #1 var request1 = new WaitableLoRaRequest(simulatedDevice.CreateUnconfirmedMessageUplink("1").Rxpk[0], this.PacketForwarder); messageDispatcher.DispatchRequest(request1); Assert.True(await request1.WaitCompleteAsync()); Assert.True(request1.ProcessingSucceeded); await this.EnsureDisconnectedAsync(disconnectedEvent); // sends unconfirmed message #2 var request2 = new WaitableLoRaRequest(simulatedDevice.CreateUnconfirmedMessageUplink("2").Rxpk[0], this.PacketForwarder); messageDispatcher.DispatchRequest(request2); Assert.True(await request2.WaitCompleteAsync()); Assert.True(request2.ProcessingSucceeded); await this.EnsureDisconnectedAsync(disconnectedEvent); this.LoRaDeviceClient.Verify(x => x.Disconnect(), Times.Exactly(2)); this.LoRaDeviceClient.Verify(x => x.EnsureConnected(), Times.Exactly(2)); this.LoRaDeviceClient.VerifyAll(); this.LoRaDeviceApi.VerifyAll(); }
public async Task After_ClassA_Sends_Multiple_Data_Should_Disconnect() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1)); simulatedDevice.FrmCntUp = 10; var isDisconnected = false; // message will be sent LoRaDeviceTelemetry loRaDeviceTelemetry = null; this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => { Assert.False(isDisconnected); loRaDeviceTelemetry = t; }) .ReturnsAsync(true); // C2D message will be checked this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .Callback(() => { Assert.False(isDisconnected); }) .ReturnsAsync((Message)null); // will check client connection this.LoRaDeviceClient.Setup(x => x.EnsureConnected()) .Returns(true); // will disconnected client var disconnectedEvent = new SemaphoreSlim(0, 1); this.LoRaDeviceClient.Setup(x => x.Disconnect()) .Callback(() => { disconnectedEvent.Release(); isDisconnected = true; }) .Returns(true); var cachedDevice = this.CreateLoRaDevice(simulatedDevice); cachedDevice.KeepAliveTimeout = 3; var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(cachedDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); var messageDispatcher = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); // sends unconfirmed message foreach (var msg in Enumerable.Range(1, 3)) { var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage(msg.ToString()); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request = new WaitableLoRaRequest(rxpk, this.PacketForwarder); messageDispatcher.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); await Task.Delay(1500); } await this.EnsureDisconnectedAsync(disconnectedEvent); this.LoRaDeviceClient.VerifyAll(); this.LoRaDeviceApi.VerifyAll(); }