public async Task ABP_From_Another_Gateway_Unconfirmed_Message_Should_Load_Device_Cache_And_Disconnect() { const string gateway1 = "gateway1"; const string gateway2 = "gateway2"; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: gateway1)) { FrmCntUp = 9 }; LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(simulatedDevice.DevAddr.Value)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(simulatedDevice.DevAddr, simulatedDevice.DevEUI, "1234") { GatewayId = gateway2 }.AsList())); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var payload1 = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 10); using var request1 = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), payload1); messageProcessor.DispatchRequest(request1); Assert.True(await request1.WaitCompleteAsync()); Assert.True(request1.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request1.ProcessingFailedReason); // Let loading finish await Task.Delay(50); // device should be cached Assert.True(DeviceCache.TryGetByDevEui(simulatedDevice.DevEUI, out var cachedDevice)); var payload2 = simulatedDevice.CreateUnconfirmedDataUpMessage("2", fcnt: 11); using var request2 = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), payload2); messageProcessor.DispatchRequest(request2); Assert.True(await request2.WaitCompleteAsync()); Assert.True(request2.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request2.ProcessingFailedReason); // Expectations // 1. we never loaded the twins for the device not belonging to us LoRaDeviceClient.Verify(x => x.GetTwinAsync(It.IsAny <CancellationToken>()), Times.Never); LoRaDeviceClient.Verify(x => x.EnsureConnected(), Times.Never); LoRaDeviceApi.VerifyAll(); LoRaDeviceApi.Verify(x => x.SearchByDevAddrAsync(simulatedDevice.DevAddr.Value), Times.Once()); // 2. The device is registered Assert.Equal(1, DeviceCache.RegistrationCount(simulatedDevice.DevAddr.Value)); }
public async Task When_New_ABP_Device_Instance_Is_Created_Should_Increment_FCntDown() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerGatewayID)); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DevEui, "pk"); LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(It.IsAny <DevAddr>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); // device will: // - be initialized // - send event // - receive c2d LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simulatedDevice.CreateABPTwin()); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("2", fcnt: 2); using var request = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), payload, constantElapsedTime: TimeSpan.FromMilliseconds(300)); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); // Wait until loader updates the device cache await Task.Delay(50); Assert.Equal(1, DeviceCache.RegistrationCount(simulatedDevice.DevAddr.Value)); Assert.True(DeviceCache.TryGetForPayload(request.Payload, out var cachedDevice)); Assert.True(cachedDevice.IsOurDevice); Assert.Equal(Constants.MaxFcntUnsavedDelta - 1U, cachedDevice.FCntDown); Assert.Equal(payload.Fcnt, (ushort)cachedDevice.FCntUp); // Device was searched by DevAddr LoRaDeviceApi.VerifyAll(); // Device was created by factory LoRaDeviceClient.VerifyAll(); }
public async Task When_Payload_Has_Invalid_Mic_Should_Not_Send_Messages(int searchDevicesDelayMs) { // Setup var wrongSKey = TestKeys.CreateNetworkSessionKey(0xEEDDFF); var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1)); var searchResult = new SearchDevicesResult(new IoTHubDeviceInfo(simulatedDevice.DevAddr, simulatedDevice.DevEUI, "1321").AsList()); if (searchDevicesDelayMs > 0) { LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(simulatedDevice.DevAddr.Value)) .ReturnsAsync(searchResult, TimeSpan.FromMilliseconds(searchDevicesDelayMs)); } else { LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(simulatedDevice.DevAddr.Value)) .ReturnsAsync(searchResult); } LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(TestUtils.CreateABPTwin(simulatedDevice)); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // Send request #1 var payload1 = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 2, nwkSKey: wrongSKey); using var request1 = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), payload1); messageProcessor.DispatchRequest(request1); Assert.True(await request1.WaitCompleteAsync()); Assert.Null(request1.ResponseDownlink); Assert.True(request1.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.NotMatchingDeviceByMicCheck, request1.ProcessingFailedReason); await Task.Delay(2000); Assert.Equal(1, DeviceCache.RegistrationCount(simulatedDevice.DevAddr.Value)); // Send request #2 var payload2 = simulatedDevice.CreateUnconfirmedDataUpMessage("2", fcnt: 3, nwkSKey: wrongSKey); using var request2 = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), payload2); messageProcessor.DispatchRequest(request2); Assert.True(await request2.WaitCompleteAsync()); Assert.Null(request2.ResponseDownlink); Assert.True(request2.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.NotMatchingDeviceByMicCheck, request2.ProcessingFailedReason); Assert.Equal(1, DeviceCache.RegistrationCount(simulatedDevice.DevAddr.Value)); LoRaDeviceApi.VerifyAll(); LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.Verify(x => x.SearchByDevAddrAsync(simulatedDevice.DevAddr.Value), Times.Exactly(1)); }
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.DevEui; var devAddr = simulatedDevice.LoRaDevice.DevAddr.Value; // 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); // twin will be loaded var initialTwin = new Twin(); initialTwin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); initialTwin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); initialTwin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); initialTwin.Properties.Desired[TwinProperty.NwkSKey] = simulatedDevice.LoRaDevice.NwkSKey?.ToString(); initialTwin.Properties.Desired[TwinProperty.AppSKey] = simulatedDevice.LoRaDevice.AppSKey?.ToString(); initialTwin.Properties.Desired[TwinProperty.DevAddr] = devAddr.ToString(); initialTwin.Properties.Desired[TwinProperty.GatewayID] = 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; } LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)).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 LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((t, _) => { fcntUpSavedInTwin = (uint)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (uint)t[TwinProperty.FCntDown]; }) .ReturnsAsync(true); } // device api will be searched for payload LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "abc").AsList())); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("hello", fcnt: payloadFcntUp); using var request = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), unconfirmedMessagePayload); 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 Assert.Equal(1, DeviceCache.RegistrationCount(devAddr)); Assert.True(DeviceCache.TryGetForPayload(request.Payload, 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) } LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }
public async Task When_Device_Is_Found_In_Api_Should_Update_Twin_And_Return() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: ServerConfiguration.GatewayID)); simulatedDevice.LoRaDevice.NwkSKey = null; simulatedDevice.LoRaDevice.AppSKey = null; var joinRequest = simulatedDevice.CreateJoinRequest(); // this former join request is just to set the loradevice cache to another devnonce. _ = simulatedDevice.CreateJoinRequest(); var devEui = simulatedDevice.LoRaDevice.DevEui; LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(It.IsNotNull <string>(), devEui, joinRequest.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(null, devEui, "123") { GatewayId = ServerConfiguration.GatewayID }.AsList())); // Ensure that the device twin was updated LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.Is <TwinCollection>((t) => t.Contains(TwinProperty.DevAddr) && t.Contains(TwinProperty.FCntDown)), It.IsAny <CancellationToken>())) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simulatedDevice.CreateOTAATwin()); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); using var request = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), joinRequest); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(downlinkMessage.Data, simulatedDevice.AppKey.Value); Assert.Equal(1, DeviceCache.RegistrationCount(joinAccept.DevAddr)); Assert.True(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); Assert.Equal(joinAccept.DevAddr, loRaDevice.DevAddr); // Device properties were set with the computes values of the join operation Assert.Equal(joinAccept.AppNonce, loRaDevice.AppNonce); Assert.NotNull(loRaDevice.NwkSKey); Assert.NotNull(loRaDevice.AppSKey); Assert.True(loRaDevice.IsOurDevice); // Device frame counts were reset Assert.Equal(0U, loRaDevice.FCntDown); Assert.Equal(0U, loRaDevice.FCntUp); Assert.False(loRaDevice.HasFrameCountChanges); // Twin property were updated LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.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"); var loRaDeviceClient1 = new Mock <ILoRaDeviceClient>(MockBehavior.Loose); loRaDeviceClient1.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simulatedDevice1.CreateABPTwin()); using var connectionManager1 = new SingleDeviceConnectionManager(loRaDeviceClient1.Object); using var loraDevice1 = TestUtils.CreateFromSimulatedDevice(simulatedDevice1, connectionManager1); var devAddr = loraDevice1.DevAddr.Value; var reqHandler1 = new Mock <ILoRaDataRequestHandler>(MockBehavior.Strict); reqHandler1.Setup(x => x.ProcessRequestAsync(It.IsNotNull <LoRaRequest>(), loraDevice1)) .ReturnsAsync(new LoRaDeviceRequestProcessResult(loraDevice1, null)); loraDevice1.SetRequestHandler(reqHandler1.Object); var simulatedDevice2 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); simulatedDevice2.LoRaDevice.DeviceID = new DevEui(2).ToString(); simulatedDevice2.LoRaDevice.NwkSKey = TestKeys.CreateNetworkSessionKey(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); var loRaDeviceClient2 = new Mock <ILoRaDeviceClient>(MockBehavior.Loose); loRaDeviceClient2.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simulatedDevice2.CreateABPTwin()); using var connectionManager2 = new SingleDeviceConnectionManager(loRaDeviceClient2.Object); using var loraDevice2 = TestUtils.CreateFromSimulatedDevice(simulatedDevice2, connectionManager2); // 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.CreateAndRegisterAsync(iotHubDeviceInfo1, It.IsAny <CancellationToken>())).ReturnsAsync(() => { DeviceCache.Register(loraDevice1); return(loraDevice1); }); this.loraDeviceFactoryMock.Setup(x => x.CreateAndRegisterAsync(iotHubDeviceInfo2, It.IsAny <CancellationToken>())).ReturnsAsync(() => { DeviceCache.Register(loraDevice2); return(loraDevice2); }); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, this.loraDeviceFactoryMock.Object, DeviceCache); using var request = WaitableLoRaRequest.Create(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 Assert.Equal(2, DeviceCache.RegistrationCount(devAddr)); // 2 devices with same devAddr exist in cache // find device 1 Assert.True(DeviceCache.TryGetForPayload(request.Payload, out var actualCachedLoRaDevice1)); Assert.Same(loraDevice1, actualCachedLoRaDevice1); Assert.True(loraDevice1.IsOurDevice); // find device 2 Assert.True(DeviceCache.TryGetByDevEui(loraDevice2.DevEUI, out var actualCachedLoRaDevice2)); Assert.Same(loraDevice2, actualCachedLoRaDevice2); Assert.True(loraDevice2.IsOurDevice); reqHandler1.VerifyAll(); }