public void StartAutoExportTxt() { tokenSource = new CancellationTokenSource(); Console.WriteLine("StartAutoExportTxt"); IQueryable <GroundTruth> groundtruths = null; _ExportTask = Task.Factory.StartNew(() => { var GVContext = Startup.CreateDBContext(); while (true) { groundtruths = GVContext.GroundTruths.OrderBy(item => item.ip); foreach (GroundTruth groundtruth in groundtruths) { DeviceCache dv = GetDevice(groundtruth.ip); dv.ProcessOnce(); } Thread.Sleep(30000); if (tokenSource.IsCancellationRequested == true) { Console.WriteLine("Task {0} was cancelled before it got started.", tokenSource); tokenSource.Token.ThrowIfCancellationRequested(); } } }); }
public async Task When_Devices_From_Another_Gateway_Is_Cached_Return_Null() { var simulatedDevice1 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: "another-gateway")); using var loraDevice1 = TestUtils.CreateFromSimulatedDevice(simulatedDevice1, ConnectionManager); loraDevice1.IsOurDevice = false; DeviceCache.Register(loraDevice1); var payload = simulatedDevice1.CreateUnconfirmedDataUpMessage("1234"); var apiService = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, this.loraDeviceFactoryMock.Object, DeviceCache); using var request = WaitableLoRaRequest.Create(payload); var queue = target.GetLoRaRequestQueue(request); queue.Queue(request); Assert.IsType <ExternalGatewayLoRaRequestQueue>(queue); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request.ProcessingFailedReason); // Device was searched by DevAddr apiService.VerifyAll(); // Device was created by factory this.loraDeviceFactoryMock.VerifyAll(); }
public async Task GetDeviceForJoinRequestAsync_When_Join_Handled_By_Other_Cache_Is_Updated(bool joinedDevice) { var devNonce = new DevNonce(1); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var otaaDevice = TestDeviceInfo.CreateOTAADevice(1); if (joinedDevice) { otaaDevice.AppSKey = new AppSessionKey(); } var simulatedDevice = new SimulatedDevice(otaaDevice); apiService.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, simulatedDevice.DevEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult() { IsDevNonceAlreadyUsed = true }); DeviceCache.Register(CreateLoRaDevice(simulatedDevice)); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, this.loraDeviceFactoryMock.Object, DeviceCache); Assert.Null(await target.GetDeviceForJoinRequestAsync(simulatedDevice.DevEUI, devNonce)); Assert.Equal(joinedDevice, !DeviceCache.TryGetByDevEui(simulatedDevice.DevEUI, out _)); }
/// <summary> /// 以新增和删除设备为例,使用单例模式和MVP设计模式 /// </summary> /// <param name="args"></param> static void Main(string[] args) { Demo demo = new Demo(); //获取缓存 DeviceCache cacheInstance = DeviceCache.GetInstance(); //创建View实例 DemoView view = new DemoView(); //创建四个新设备 Device device1 = Device.CreatDevice("device_1", new Point(0, 0)); Device device2 = Device.CreatDevice("device_2", new Point(0, 1)); Device device3 = Device.CreatDevice("device_3", new Point(1, 0)); Device device4 = Device.CreatDevice("device_4", new Point(1, 1)); //添加四个设备 List <Device> newDevices = new List <Device>() { device1, device2, device3, device4 }; foreach (Device newDevice in newDevices) { view.NewDeviceAdding(newDevice); } cacheInstance.ShowCache(); //删除设备2 view.DeviceRemoving(device2); cacheInstance.ShowCache(); Console.ReadKey(); }
public DemoPresenter(IDemoView view) { _view = view; _operation = new CacheOperation(); DeviceCache cacheInstance = DeviceCache.GetInstance(); cacheInstance.AddAction += AddDeviceToView; cacheInstance.RemoveAction += RemoveDeviceFromView; }
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_Fcnt_Down_Fails_Should_Stop_And_Not_Update_Device_Twin(uint initialFcntDown, uint initialFcntUp, uint payloadFcnt) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: null)) { FrmCntDown = initialFcntDown, FrmCntUp = initialFcntUp }; var devEui = simulatedDevice.LoRaDevice.DevEui; var devAddr = simulatedDevice.LoRaDevice.DevAddr; LoRaDeviceApi .Setup(x => x.ExecuteFunctionBundlerAsync(devEui, It.IsAny <FunctionBundlerRequest>())) .ReturnsAsync(() => new FunctionBundlerResult { AdrResult = new LoRaTools.ADR.LoRaADRResult { CanConfirmToDevice = true, FCntDown = 0 }, NextFCntDown = 0 }); LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEui, It.IsAny <uint>(), It.IsNotNull <string>())) .ReturnsAsync(true); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); var device = CreateLoRaDevice(simulatedDevice); DeviceCache.Register(device); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("hello", fcnt: payloadFcnt); using var request = CreateWaitableRequest(unconfirmedMessagePayload); messageDispatcher.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.Null(request.ResponseDownlink); // verify that the device in device registry has correct properties and frame counters 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(initialFcntUp, loRaDevice.FCntUp); Assert.Equal(initialFcntDown, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }
public DeviceRepository() { if (DeviceCache.Count == 0) { lock (lockObject) { if (DeviceCache.Count == 0) { LoadDevices().ToList().ForEach(x => DeviceCache.TryAdd(x.Name, x)); } } } }
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_Device_Is_Assigned_To_Another_Gateway_Cache_Locally_And_Return_Null() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: "another-gateway")); var apiService = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DevEui, "pk") { GatewayId = "another-gateway", NwkSKey = simulatedDevice.NwkSKey.Value }; apiService.Setup(x => x.SearchByDevAddrAsync(It.IsAny <DevAddr>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); var deviceFactory = new TestLoRaDeviceFactory(LoRaDeviceClient.Object, DeviceCache, ConnectionManager); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, deviceFactory, DeviceCache); // request #1 var payload1 = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 11); using var request1 = WaitableLoRaRequest.Create(payload1); target.GetLoRaRequestQueue(request1).Queue(request1); Assert.True(await request1.WaitCompleteAsync()); Assert.True(request1.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request1.ProcessingFailedReason); // request #2 var payload2 = simulatedDevice.CreateUnconfirmedDataUpMessage("2", fcnt: 12); using var request2 = WaitableLoRaRequest.Create(payload2); target.GetLoRaRequestQueue(request2).Queue(request2); Assert.True(await request2.WaitCompleteAsync()); Assert.True(request2.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request2.ProcessingFailedReason); // Device was searched by DevAddr apiService.VerifyAll(); apiService.Verify(x => x.SearchByDevAddrAsync(It.IsAny <DevAddr>()), Times.Once()); // Device should not be connected LoRaDeviceClient.VerifyAll(); LoRaDeviceClient.Verify(x => x.GetTwinAsync(CancellationToken.None), Times.Never()); LoRaDeviceClient.Verify(x => x.Disconnect(), Times.Never()); // device is in cache Assert.True(DeviceCache.TryGetForPayload(request1.Payload, out var loRaDevice)); Assert.False(loRaDevice.IsOurDevice); }
public DeviceCache GetDevice(string ip) { if (_DevicesCache.ContainsKey(ip)) { return(_DevicesCache[ip]); } else { DeviceCache cache = new DeviceCache(); cache._IP = ip; cache._LastRevTime = DateTime.Now; _DevicesCache.Add(ip, cache); return(cache); } }
public async Task When_Device_Is_Assigned_To_Another_Gateway_After_No_Connection_Should_Be_Established() { const string gatewayId = "another-gateway"; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: gatewayId)); var apiService = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DevEui, "pk") { NwkSKey = simulatedDevice.NwkSKey.Value, GatewayId = gatewayId }; apiService.Setup(x => x.SearchByDevAddrAsync(It.IsAny <DevAddr>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); var deviceFactory = new TestLoRaDeviceFactory(LoRaDeviceClient.Object, DeviceCache, ConnectionManager); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, deviceFactory, DeviceCache); // setup 2 requests - ensure the cache is validated before fetching from the function var requests = Enumerable.Range(1, 2).Select((n) => { var payload = simulatedDevice.CreateUnconfirmedDataUpMessage(n.ToString(CultureInfo.InvariantCulture), fcnt: (uint)n + 10); var request = WaitableLoRaRequest.Create(payload); target.GetLoRaRequestQueue(request).Queue(request); return(request); } ).ToList(); foreach (var request in requests) { Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request.ProcessingFailedReason); } // Device was searched by DevAddr apiService.VerifyAll(); apiService.Verify(x => x.SearchByDevAddrAsync(It.IsAny <DevAddr>()), Times.Once()); LoRaDeviceClient.Verify(x => x.GetTwinAsync(CancellationToken.None), Times.Never()); // device is in cache Assert.True(DeviceCache.TryGetForPayload(requests.First().Payload, out var cachedLoRaDevice)); Assert.False(cachedLoRaDevice.IsOurDevice); }
public void Insert(string ip, byte nodeindex, int timestamp, int timestampms, byte lr) { DeviceCache dv = GetDevice(ip); DateTime dt = DateTime.Now; App_GroundTruthData data = new App_GroundTruthData(); data.createtime = dt; data.device = ip; data.timestamp = timestamp; data.timestampms = timestampms; data.leftright = lr; data.nodeindex = nodeindex; dv.AddMiniteCache(data); }
public void Insert(string ip, UInt32 timestamps, UInt32 timestampms, UInt16 rate, UInt16 gain, byte[] bufferdata) { DeviceCache dv = GetDevice(ip); DateTime dt = DateTime.Now; App_SensorData data = new App_SensorData(); data.createtime = dt; data.device = ip; data.gain = (short)gain; data.rate = (short)rate; data.sensorvalue = bufferdata; data.timestampms = (int)timestampms; data.timestamps = (int)timestamps; dv.AddMiniteCache(data); }
public async Task When_Device_With_Downlink_Disabled_Received_Unconfirmed_Data_Should_Not_Check_For_C2D(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); // message will be sent LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); if (string.IsNullOrEmpty(deviceGatewayID)) { LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(It.IsNotNull <DevEui>(), It.IsAny <uint>(), It.IsNotNull <string>())) .ReturnsAsync(true); } using var memoryCache = new MemoryCache(new MemoryCacheOptions()); var cachedDevice = CreateLoRaDevice(simulatedDevice); cachedDevice.DownlinkEnabled = false; DeviceCache.Register(cachedDevice); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234"); using var request = CreateWaitableRequest(unconfirmedMessagePayload); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.Null(request.ResponseDownlink); Assert.True(request.ProcessingSucceeded); LoRaDeviceClient.Verify(x => x.ReceiveAsync(It.IsAny <TimeSpan>()), Times.Never()); LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }
public async Task When_Device_Is_Not_In_Cache_And_Found_In_Api_Should_Cache_And_Process_Request(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234"); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DevEui, "pk") { GatewayId = deviceGatewayID }; apiService.Setup(x => x.SearchByDevAddrAsync(It.IsAny <DevAddr>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); // device will be initialized LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simulatedDevice.CreateABPTwin()); using var request = WaitableLoRaRequest.Create(payload); var requestHandler = new Mock <ILoRaDataRequestHandler>(MockBehavior.Strict); requestHandler.Setup(x => x.ProcessRequestAsync(request, It.IsNotNull <LoRaDevice>())) .ReturnsAsync(new LoRaDeviceRequestProcessResult(null, request)); var deviceFactory = new TestLoRaDeviceFactory(LoRaDeviceClient.Object, requestHandler.Object, DeviceCache, ConnectionManager); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, deviceFactory, DeviceCache); target.GetLoRaRequestQueue(request).Queue(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); // Device was searched by DevAddr apiService.VerifyAll(); // ensure device is in cache Assert.True(DeviceCache.TryGetForPayload(request.Payload, out var actualCachedLoRaDevice)); // request was handled requestHandler.VerifyAll(); }
private bool SaveDeviceCache(Device device) { var serializer = new JsonSerializer(); Directory.CreateDirectory(GetProviderCacheDirectory(device.ProviderName)); using (var streamWriter = new StreamWriter(GetDeviceCachePath(device))) { var deviceCache = new DeviceCache() { Title = device.Title, ProviderName = device.ProviderName, DeviceHandle = device.DeviceHandle, DeviceNumber = device.DeviceNumber, DeviceBindingMenu = GetDeviceBindingMenu(device, DeviceIoType.Input, false) }; serializer.Serialize(streamWriter, deviceCache); } return(true); }
public async Task When_Multiple_Devices_With_Same_DevAddr_Are_Cached_Should_Find_Matching_By_Mic(string deviceGatewayID) { var connectionManager = new Mock <ILoRaDeviceClientConnectionManager>(); var simulatedDevice1 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); using var loraDevice1 = TestUtils.CreateFromSimulatedDevice(simulatedDevice1, connectionManager.Object); var simulatedDevice2 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: ServerConfiguration.GatewayID)); simulatedDevice2.LoRaDevice.DeviceID = new DevEui(2).ToString(); simulatedDevice2.LoRaDevice.NwkSKey = TestKeys.CreateNetworkSessionKey(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); using var loraDevice2 = TestUtils.CreateFromSimulatedDevice(simulatedDevice2, connectionManager.Object); DeviceCache.Register(loraDevice1); DeviceCache.Register(loraDevice2); var payload = simulatedDevice1.CreateUnconfirmedDataUpMessage("1234"); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); using var request = WaitableLoRaRequest.Create(payload); var requestHandler = new Mock <ILoRaDataRequestHandler>(MockBehavior.Strict); requestHandler.Setup(x => x.ProcessRequestAsync(request, loraDevice1)) .ReturnsAsync(new LoRaDeviceRequestProcessResult(loraDevice1, request)); loraDevice1.SetRequestHandler(requestHandler.Object); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, this.loraDeviceFactoryMock.Object, DeviceCache); 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(); requestHandler.VerifyAll(); }
public void When_Cache_Clear_Is_Called_Should_Removed_Cached_Devices(string deviceGatewayID) { LoRaDeviceClient.Setup(ldc => ldc.Dispose()); const int deviceCount = 10; var deviceList = new HashSet <LoRaDevice>(); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var deviceFactory = new TestLoRaDeviceFactory(LoRaDeviceClient.Object, DeviceCache); using var target = new LoRaDeviceRegistry(ServerConfiguration, this.cache, apiService.Object, deviceFactory, DeviceCache); using var connectionManager = new SingleDeviceConnectionManager(LoRaDeviceClient.Object); for (var deviceID = 1; deviceID <= deviceCount; ++deviceID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice((uint)deviceID, gatewayID: deviceGatewayID)); #pragma warning disable CA2000 // Dispose objects before losing scope - transfer ownership var device = TestUtils.CreateFromSimulatedDevice(simulatedDevice, connectionManager); #pragma warning restore CA2000 // Dispose objects before losing scope DeviceCache.Register(device); deviceList.Add(device); } Assert.Equal(deviceCount, DeviceCache.CalculateStatistics().Count); // Device was searched by DevAddr apiService.VerifyAll(); // Device was created by factory this.loraDeviceFactoryMock.VerifyAll(); // ensure all devices are in cache Assert.Equal(deviceCount, deviceList.Count(x => DeviceCache.TryGetByDevEui(x.DevEUI, out _))); target.ResetDeviceCache(); Assert.False(deviceList.Any(x => DeviceCache.TryGetByDevEui(x.DevEUI, out _)), "Should not find devices again"); }
public async Task ABP_New_Loaded_Device_With_Fcnt_1_Or_0_Should_Reset_Fcnt_And_Send_To_IotHub( string twinGatewayID, uint payloadFcntUp, uint?deviceTwinFcntUp, uint?deviceTwinFcntDown) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: null)); 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(); if (twinGatewayID != null) { initialTwin.Properties.Desired[TwinProperty.GatewayID] = twinGatewayID; } 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 int?fcntUpSavedInTwin = null; int?fcntDownSavedInTwin = null; var shouldSaveTwin = (deviceTwinFcntDown ?? 0) != 0 || (deviceTwinFcntUp ?? 0) != 0; if (shouldSaveTwin) { LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((t, _) => { fcntUpSavedInTwin = (int)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (int)t[TwinProperty.FCntDown]; }) .ReturnsAsync(true); } LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEui, It.IsAny <uint>(), It.IsNotNull <string>())) .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 memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, 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(unconfirmedMessagePayload); messageDispatcher.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.Null(request.ResponseDownlink); // Ensure that a telemetry was sent Assert.NotNull(loRaDeviceTelemetry); // Ensure that the device twins were saved if (shouldSaveTwin) { Assert.NotNull(fcntDownSavedInTwin); Assert.NotNull(fcntUpSavedInTwin); Assert.Equal(0, fcntDownSavedInTwin.Value); Assert.Equal(0, fcntUpSavedInTwin.Value); } // verify that the device in device registry has correct properties and frame counters 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); // should have changes! } LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.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)); }
private async Task Join_With_Subsequent_Unconfirmed_And_Confirmed_Messages(string deviceGatewayID, uint initialFcntUp, uint initialFcntDown, uint startingPayloadFcnt, int netId, Region region) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequestPayload = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; ServerConfiguration.NetId = new NetId(netId); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); if (deviceGatewayID != null) { twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; } twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; twin.Properties.Reported[TwinProperty.FCntUp] = initialFcntUp; twin.Properties.Reported[TwinProperty.FCntDown] = initialFcntDown; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)).ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; uint afterJoinFcntDown = 0; uint afterJoinFcntUp = 0; TwinCollection actualSavedTwin = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { if (updatedTwin.Contains(TwinProperty.AppSKey)) { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); } if (updatedTwin.Contains(TwinProperty.NwkSKey)) { afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); } if (updatedTwin.Contains(TwinProperty.DevAddr)) { afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; } afterJoinFcntDown = updatedTwin[TwinProperty.FCntDown]; afterJoinFcntUp = updatedTwin[TwinProperty.FCntUp]; actualSavedTwin = updatedTwin; }) .ReturnsAsync(true); // message will be sent var sentTelemetry = new List <LoRaDeviceTelemetry>(); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, _) => sentTelemetry.Add(t)) .ReturnsAsync(true); // C2D message will be checked LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); // multi gateway will request a next frame count down from the lora device api, prepare it if (string.IsNullOrEmpty(deviceGatewayID)) { LoRaDeviceApi.Setup(x => x.NextFCntDownAsync(devEui, 0, startingPayloadFcnt + 1, ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)1); LoRaDeviceApi .Setup(x => x.ExecuteFunctionBundlerAsync(devEui, It.IsAny <FunctionBundlerRequest>())) .ReturnsAsync(() => new FunctionBundlerResult { AdrResult = new LoRaTools.ADR.LoRaADRResult { CanConfirmToDevice = false, FCntDown = 1, NbRepetition = 1, TxPower = 0 }, NextFCntDown = 1 }); } // using factory to create mock of using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // Create a join request and join with the device. using var joinRequest = CreateWaitableRequest(joinRequestPayload, constantElapsedTime: TimeSpan.FromMilliseconds(300), region: region); messageProcessor.DispatchRequest(joinRequest); Assert.True(await joinRequest.WaitCompleteAsync()); Assert.True(joinRequest.ProcessingSucceeded, $"Failed due to '{joinRequest.ProcessingFailedReason}'."); Assert.NotNull(joinRequest.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downlinkJoinAcceptMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(downlinkJoinAcceptMessage.Data, simulatedDevice.LoRaDevice.AppKey.Value); Assert.Equal(joinAccept.DevAddr.ToString(), afterJoinDevAddr); // check that the device is in cache Assert.True(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); Assert.Equal(afterJoinAppSKey, loRaDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, loRaDevice.NwkSKey); Assert.Equal(afterJoinDevAddr, loRaDevice.DevAddr.ToString()); var netIdBytes = BitConverter.GetBytes(netId); Assert.Equal(netIdBytes[0] & 0b01111111, DevAddr.Parse(afterJoinDevAddr).NetworkId); if (deviceGatewayID == null) { Assert.Null(loRaDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, loRaDevice.GatewayID); } // Assert that after a join the fcnt is restarted Assert.Equal(0U, afterJoinFcntDown); Assert.Equal(0U, afterJoinFcntUp); Assert.Equal(0U, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); simulatedDevice.LoRaDevice.AppSKey = afterJoinAppSKey; simulatedDevice.LoRaDevice.NwkSKey = afterJoinNwkSKey; simulatedDevice.LoRaDevice.DevAddr = DevAddr.Parse(afterJoinDevAddr); // sends unconfirmed message with a given starting frame counter var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("100", fcnt: startingPayloadFcnt); var radioMetadata = TestUtils.GenerateTestRadioMetadata(); using var unconfirmedRequest = CreateWaitableRequest(radioMetadata, unconfirmedMessagePayload, constantElapsedTime: TimeSpan.FromMilliseconds(300)); messageProcessor.DispatchRequest(unconfirmedRequest); Assert.True(await unconfirmedRequest.WaitCompleteAsync()); Assert.Null(unconfirmedRequest.ResponseDownlink); Assert.True(unconfirmedRequest.ProcessingSucceeded); // fcnt up was updated Assert.Equal(startingPayloadFcnt, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); // If the starting payload was not 0, it is expected that it updates the framecounter char // The device will perform the frame counter update and at this point in time it will have the same frame counter as the desired // Therefore savechangesasync will set the hasframcounter change to false // if (startingPayloadFcnt != 0) // { // // Frame change flag will be set, only saving every 10 messages // Assert.True(loRaDevice.HasFrameCountChanges); // } Assert.Single(sentTelemetry); // sends confirmed message var confirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("200", fcnt: startingPayloadFcnt + 1); using var confirmedRequest = CreateWaitableRequest(confirmedMessagePayload, constantElapsedTime: TimeSpan.FromMilliseconds(300), region: region); messageProcessor.DispatchRequest(confirmedRequest); Assert.True(await confirmedRequest.WaitCompleteAsync()); Assert.True(confirmedRequest.ProcessingSucceeded); Assert.NotNull(confirmedRequest.ResponseDownlink); Assert.Equal(2, DownstreamMessageSender.DownlinkMessages.Count); Assert.Equal(2, sentTelemetry.Count); var downstreamMessage = DownstreamMessageSender.DownlinkMessages[1]; // validates txpk according to region DeviceJoinInfo deviceJoinInfo = null; if (region is RegionCN470RP2 cnRegion && cnRegion.TryGetJoinChannelIndex(confirmedRequest.RadioMetadata.Frequency, out var channelIndex)) { deviceJoinInfo = new DeviceJoinInfo(channelIndex); } Assert.True(region.TryGetDownstreamChannelFrequency(confirmedRequest.RadioMetadata.Frequency, confirmedRequest.RadioMetadata.DataRate, deviceJoinInfo, downstreamFrequency: out var frequency)); Assert.Equal(frequency, downstreamMessage.Rx1?.Frequency); var rx2Freq = region.GetDownstreamRX2Freq(null, deviceJoinInfo, NullLogger.Instance); Assert.Equal(rx2Freq, downstreamMessage.Rx2.Frequency); var rx2DataRate = region.GetDownstreamRX2DataRate(null, null, deviceJoinInfo, NullLogger.Instance); Assert.Equal(rx2DataRate, downstreamMessage.Rx2.DataRate); // fcnt up was updated Assert.Equal(startingPayloadFcnt + 1, loRaDevice.FCntUp); Assert.Equal(1U, loRaDevice.FCntDown); // Frame change flag will be set, only saving every 10 messages Assert.True(loRaDevice.HasFrameCountChanges); // C2D message will be checked twice (for AS923 only once, since we use the first C2D message to send the dwell time MAC command) var numberOfC2DMessageChecks = region is RegionAS923 ? 1 : 2; LoRaDeviceClient.Verify(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>()), Times.Exactly(numberOfC2DMessageChecks)); // has telemetry with both fcnt Assert.Single(sentTelemetry, (t) => t.Fcnt == startingPayloadFcnt); Assert.Single(sentTelemetry, (t) => t.Fcnt == (startingPayloadFcnt + 1)); // should not save class C device properties Assert.False(actualSavedTwin.Contains(TwinProperty.Region)); Assert.False(actualSavedTwin.Contains(TwinProperty.PreferredGatewayID)); LoRaDeviceClient.VerifyAll(); }
public async Task When_Join_Fails_Due_To_Timeout_Second_Try_Should_Reuse_Cached_Device_Twin(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequestPayload1 = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; // Device twin will be queried twice, 1st time will take 7 seconds, 2nd time 0.1 second var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); if (deviceGatewayID != null) { twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; } twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload1.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // 1st join request // Should fail using var joinRequest1 = CreateWaitableRequest(joinRequestPayload1, constantElapsedTime: TimeSpan.FromSeconds(7)); messageProcessor.DispatchRequest(joinRequest1); Assert.True(await joinRequest1.WaitCompleteAsync()); Assert.True(joinRequest1.ProcessingFailed); Assert.Null(joinRequest1.ResponseDownlink); Assert.Equal(LoRaDeviceRequestFailedReason.ReceiveWindowMissed, joinRequest1.ProcessingFailedReason); // 2nd attempt var joinRequestPayload2 = simulatedDevice.CreateJoinRequest(); // setup response to this device search LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload2.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var joinRequest2 = CreateWaitableRequest(joinRequestPayload2); messageProcessor.DispatchRequest(joinRequest2); Assert.True(await joinRequest2.WaitCompleteAsync()); Assert.True(joinRequest2.ProcessingSucceeded); Assert.NotNull(joinRequest2.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); var joinRequestDownlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(joinRequestDownlinkMessage.Data, simulatedDevice.LoRaDevice.AppKey.Value); Assert.Equal(joinAccept.DevAddr.ToString(), afterJoinDevAddr); Assert.True(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); Assert.Equal(simulatedDevice.AppKey, loRaDevice.AppKey); Assert.Equal(simulatedDevice.AppEui, loRaDevice.AppEui); Assert.Equal(afterJoinAppSKey, loRaDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, loRaDevice.NwkSKey); Assert.Equal(joinAccept.DevAddr, loRaDevice.DevAddr); if (deviceGatewayID == null) { Assert.Null(loRaDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, loRaDevice.GatewayID); } // fcnt is restarted Assert.Equal(0U, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); // searching the device should happen twice LoRaDeviceApi.Verify(x => x.SearchAndLockForJoinAsync(ServerGatewayID, devEui, It.IsAny <DevNonce>()), Times.Exactly(2)); // getting the device twin should happens once LoRaDeviceClient.Verify(x => x.GetTwinAsync(CancellationToken.None), Times.Once()); LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }
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.DevEui; var devAddr = simulatedDevice.LoRaDevice.DevAddr.Value; // Using loose mock because sometimes we might call receive async var looseDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Loose); 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, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)); }); // 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(); 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(CancellationToken.None)) .Returns(() => { var duration = parallelTestConfiguration.LoadTwinDuration.Next(); Console.WriteLine($"{nameof(looseDeviceClient.Object.GetTwinAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith(_ => initialTwin, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)); }); // 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>(), It.IsAny <CancellationToken>())) .Returns <TwinCollection, CancellationToken>((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, CancellationToken.None) .ContinueWith((a) => true, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)); }); } if (expectedToSaveTwin && string.IsNullOrEmpty(parallelTestConfiguration.GatewayID)) { LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEui, It.IsAny <uint>(), It.IsNotNull <string>())) .Returns(() => { var duration = parallelTestConfiguration.DeviceApiResetFcntDuration.Next(); Console.WriteLine($"{nameof(LoRaDeviceApi.Object.ABPFcntCacheResetAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith((a) => true, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)); }); } // device api will be searched for payload LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)) .Returns(() => { var duration = parallelTestConfiguration.SearchByDevAddrDuration.Next(); Console.WriteLine($"{nameof(LoRaDeviceApi.Object.SearchByDevAddrAsync)} sleeping for {duration}"); return(Task.Delay(duration) .ContinueWith((a) => new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "abc").AsList()), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)); }); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); // sends unconfirmed message var unconfirmedMessage1 = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 1); var unconfirmedMessage2 = simulatedDevice.CreateUnconfirmedDataUpMessage("2", fcnt: 2); var unconfirmedMessage3 = simulatedDevice.CreateUnconfirmedDataUpMessage("3", fcnt: 3); var req1 = CreateWaitableRequest(unconfirmedMessage1, this.downstreamMessageSender); messageDispatcher.DispatchRequest(req1); await Task.Delay(parallelTestConfiguration.BetweenMessageDuration.Next()); var req2 = CreateWaitableRequest(unconfirmedMessage2, this.downstreamMessageSender); messageDispatcher.DispatchRequest(req2); await Task.Delay(parallelTestConfiguration.BetweenMessageDuration.Next()); var req3 = CreateWaitableRequest(unconfirmedMessage3, this.downstreamMessageSender); 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(CancellationToken.None), Times.Exactly(1)); if (expectedToSaveTwin) { looseDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>(), It.IsAny <CancellationToken>()), Times.Exactly(1)); } 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 Assert.True(DeviceCache.TryGetForPayload(req1.Payload, 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(); LoRaDeviceApi.VerifyAll(); }
public async Task When_First_Join_Fails_Due_To_Slow_Twin_Update_Retry_Second_Attempt_Should_Succeed(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequestPayload1 = simulatedDevice.CreateJoinRequest(); var joinRequestPayload2 = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoin2AppSKey = null; NetworkSessionKey?afterJoin2NwkSKey = null; DevAddr? afterJoin2DevAddr = null; var mockSequence = new MockSequence(); LoRaDeviceClient.InSequence(mockSequence) .Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Returns <TwinCollection, CancellationToken>(async(_, token) => { try { await Task.Delay(TimeSpan.FromSeconds(20), token); Assert.True(false, "Token timeout expected"); } catch (OperationCanceledException) { } return(false); }); LoRaDeviceClient.InSequence(mockSequence) .Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Returns <TwinCollection, CancellationToken>((updatedTwin, token) => { afterJoin2AppSKey = updatedTwin.SafeRead <AppSessionKey>(TwinProperty.AppSKey); afterJoin2NwkSKey = updatedTwin.SafeRead <NetworkSessionKey>(TwinProperty.NwkSKey); afterJoin2DevAddr = updatedTwin.SafeRead <DevAddr>(TwinProperty.DevAddr); return(Task.FromResult(true)); }); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload1.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequestPayload2.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); using var joinRequest1 = CreateWaitableRequest(joinRequestPayload1, useRealTimer: true); messageProcessor.DispatchRequest(joinRequest1); await Task.Delay(TimeSpan.FromSeconds(7)); using var joinRequest2 = CreateWaitableRequest(joinRequestPayload2, useRealTimer: true); messageProcessor.DispatchRequest(joinRequest2); await Task.WhenAll(joinRequest1.WaitCompleteAsync(), joinRequest2.WaitCompleteAsync()); Assert.True(joinRequest1.ProcessingFailed); Assert.Null(joinRequest1.ResponseDownlink); Assert.Equal(LoRaDeviceRequestFailedReason.IoTHubProblem, joinRequest1.ProcessingFailedReason); Assert.True(joinRequest2.ProcessingSucceeded); Assert.NotNull(joinRequest2.ResponseDownlink); Assert.Single(DownstreamMessageSender.DownlinkMessages); Assert.True(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); Assert.True(loRaDevice.IsOurDevice); Assert.Equal(afterJoin2DevAddr, loRaDevice.DevAddr); Assert.Equal(afterJoin2NwkSKey, loRaDevice.NwkSKey); Assert.Equal(afterJoin2AppSKey, loRaDevice.AppSKey); // get twin should happen only once LoRaDeviceClient.Verify(x => x.GetTwinAsync(CancellationToken.None), Times.Once()); LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); }
public async Task When_ABP_Sends_Upstream_Followed_By_DirectMethod_Should_Send_Upstream_And_Downstream(string deviceGatewayID, uint fcntDownFromTwin, uint fcntDelta, Region region) { const uint payloadFcnt = 2; // to avoid relax mode reset var simDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID, deviceClassType: 'c'), frmCntDown: fcntDownFromTwin); LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .ReturnsAsync(true); var twin = simDevice.CreateABPTwin(reportedProperties: new Dictionary <string, object> { { TwinProperty.Region, region.LoRaRegion.ToString() } }); LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(simDevice.DevAddr.Value)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(simDevice.DevAddr, simDevice.DevEUI, "123").AsList())); if (deviceGatewayID == null) { LoRaDeviceApi.Setup(x => x.ExecuteFunctionBundlerAsync(simDevice.DevEUI, It.IsNotNull <FunctionBundlerRequest>())) .ReturnsAsync(new FunctionBundlerResult()); } using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var payloadData = simDevice.CreateUnconfirmedDataUpMessage("1", fcnt: payloadFcnt); using var request = CreateWaitableRequest(payloadData, region: region); request.SetStationEui(new StationEui(ulong.MaxValue)); messageDispatcher.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingSucceeded); // wait until cache has been updated await Task.Delay(50); // Adds fcntdown to device, simulating multiple downstream calls Assert.True(DeviceCache.TryGetForPayload(request.Payload, out var loRaDevice)); loRaDevice.SetFcntDown(fcntDelta + loRaDevice.FCntDown); var classCSender = new DefaultClassCDevicesMessageSender( ServerConfiguration, deviceRegistry, DownstreamMessageSender, FrameCounterUpdateStrategyProvider, new TestOutputLogger <DefaultClassCDevicesMessageSender>(this.testOutputHelper), TestMeter.Instance); var c2d = new ReceivedLoRaCloudToDeviceMessage() { DevEUI = simDevice.DevEUI, MessageId = Guid.NewGuid().ToString(), Payload = "aaaa", Fport = FramePorts.App18, }; var expectedFcntDown = fcntDownFromTwin + Constants.MaxFcntUnsavedDelta + fcntDelta; if (string.IsNullOrEmpty(deviceGatewayID)) { LoRaDeviceApi.Setup(x => x.NextFCntDownAsync(simDevice.DevEUI, fcntDownFromTwin + fcntDelta, 0, ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)expectedFcntDown); } Assert.True(await classCSender.SendAsync(c2d)); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downstreamMsg = DownstreamMessageSender.DownlinkMessages[0]; var downstreamPayloadBytes = downstreamMsg.Data; var downstreamPayload = new LoRaPayloadData(downstreamPayloadBytes); Assert.Equal(expectedFcntDown, downstreamPayload.Fcnt); Assert.Equal(c2d.Fport, downstreamPayload.Fport); Assert.Equal(downstreamPayload.DevAddr, simDevice.DevAddr); var decryptedPayload = downstreamPayload.GetDecryptedPayload(simDevice.AppSKey.Value); Assert.Equal(c2d.Payload, Encoding.UTF8.GetString(decryptedPayload)); Assert.Equal(expectedFcntDown, loRaDevice.FCntDown); Assert.Equal(payloadFcnt, loRaDevice.FCntUp); LoRaDeviceApi.VerifyAll(); LoRaDeviceClient.VerifyAll(); }
public async Task When_Joining_Should_Save_Region_And_Preferred_Gateway( [CombinatorialValues(null, ServerGatewayID)] string deviceGatewayID, [CombinatorialValues(null, ServerGatewayID, "another-gateway")] string initialPreferredGatewayID, [CombinatorialValues(null, LoRaRegionType.EU868, LoRaRegionType.US915)] LoRaRegionType?initialLoRaRegion) { var simDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, deviceClassType: 'c', gatewayID: deviceGatewayID)); var customReportedProperties = new Dictionary <string, object>(); // reported: { 'PreferredGateway': '' } -> if device is for multiple gateways and one initial was defined if (string.IsNullOrEmpty(deviceGatewayID) && !string.IsNullOrEmpty(initialPreferredGatewayID)) { customReportedProperties[TwinProperty.PreferredGatewayID] = initialPreferredGatewayID; } if (initialLoRaRegion.HasValue) { customReportedProperties[TwinProperty.Region] = initialLoRaRegion.Value.ToString(); } LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(simDevice.CreateOTAATwin(reportedProperties: customReportedProperties)); var shouldSavePreferredGateway = string.IsNullOrEmpty(deviceGatewayID) && initialPreferredGatewayID != ServerGatewayID; var shouldSaveRegion = !initialLoRaRegion.HasValue || initialLoRaRegion.Value != LoRaRegionType.EU868; var savedAppSKey = string.Empty; var savedNwkSKey = string.Empty; var savedDevAddr = string.Empty; TwinCollection actualTwinCollection = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .ReturnsAsync(true) .Callback <TwinCollection, CancellationToken>((t, _) => { savedAppSKey = t[TwinProperty.AppSKey]; savedNwkSKey = t[TwinProperty.NwkSKey]; savedDevAddr = t[TwinProperty.DevAddr]; actualTwinCollection = t; }); LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, simDevice.DevEUI, It.IsAny <DevNonce>())) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(simDevice.DevAddr, simDevice.DevEUI, "123").AsList())); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var joinPayload = simDevice.CreateJoinRequest(); using var joinRequest = CreateWaitableRequest(joinPayload); messageDispatcher.DispatchRequest(joinRequest); Assert.True(await joinRequest.WaitCompleteAsync()); Assert.True(joinRequest.ProcessingSucceeded); Assert.NotEmpty(savedAppSKey); Assert.NotEmpty(savedNwkSKey); Assert.NotEmpty(savedDevAddr); if (shouldSaveRegion) { Assert.Equal(LoRaRegionType.EU868.ToString(), actualTwinCollection[TwinProperty.Region].Value as string); } else { Assert.False(actualTwinCollection.Contains(TwinProperty.Region)); } // Only save preferred gateway if device does not have one assigned if (shouldSavePreferredGateway) { Assert.Equal(ServerConfiguration.GatewayID, actualTwinCollection[TwinProperty.PreferredGatewayID].Value as string); } else { Assert.False(actualTwinCollection.Contains(TwinProperty.PreferredGatewayID)); } Assert.True(DeviceCache.TryGetByDevEui(simDevice.DevEUI, out var loRaDevice)); Assert.Equal(LoRaDeviceClassType.C, loRaDevice.ClassType); if (string.IsNullOrEmpty(simDevice.LoRaDevice.GatewayID)) { Assert.Equal(ServerConfiguration.GatewayID, loRaDevice.PreferredGatewayID); } else { Assert.Empty(loRaDevice.PreferredGatewayID); } Assert.Equal(LoRaRegionType.EU868, loRaDevice.LoRaRegion); LoRaDeviceApi.VerifyAll(); LoRaDeviceClient.VerifyAll(); }
public async Task When_Getting_Device_Information_From_Twin_Returns_JoinAccept(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); var devAddr = (DevAddr?)null; var devEui = simulatedDevice.LoRaDevice.DevEui; // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEui.ToString(); twin.Properties.Desired[TwinProperty.AppEui] = simulatedDevice.LoRaDevice.AppEui?.ToString(); twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey?.ToString(); if (deviceGatewayID != null) { twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; } twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; LoRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)).ReturnsAsync(twin); // Device twin will be updated AppSessionKey? afterJoinAppSKey = null; NetworkSessionKey?afterJoinNwkSKey = null; string afterJoinDevAddr = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((updatedTwin, _) => { afterJoinAppSKey = AppSessionKey.Parse(updatedTwin[TwinProperty.AppSKey].Value); afterJoinNwkSKey = NetworkSessionKey.Parse(updatedTwin[TwinProperty.NwkSKey].Value); afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(ServerConfiguration.GatewayID, devEui, joinRequest.DevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "aabb").AsList())); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, 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.LoRaDevice.AppKey.Value); Assert.Equal(joinAccept.DevAddr.ToString(), afterJoinDevAddr); // check that the device is in cache Assert.True(DeviceCache.HasRegistrations(joinAccept.DevAddr)); Assert.True(DeviceCache.TryGetByDevEui(devEui, out var cachedDevice)); Assert.Equal(afterJoinAppSKey, cachedDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, cachedDevice.NwkSKey); Assert.Equal(joinAccept.DevAddr, cachedDevice.DevAddr); Assert.True(cachedDevice.IsOurDevice); if (deviceGatewayID == null) { Assert.Null(cachedDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, cachedDevice.GatewayID); } // fcnt is restarted Assert.Equal(0U, cachedDevice.FCntUp); Assert.Equal(0U, cachedDevice.FCntDown); Assert.False(cachedDevice.HasFrameCountChanges); }
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: ServerConfiguration.GatewayID, supports32BitFcnt: supports32Bit)); var devEui = simulatedDevice.LoRaDevice.DevEui; var devAddr = simulatedDevice.LoRaDevice.DevAddr.Value; LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)).ReturnsAsync(true); var initialTwin = SetupTwins(deviceFcntUp, deviceFcntDown, startFcntUp, startFcntDown, abpRelaxed, supports32Bit, simulatedDevice, devEui, devAddr); LoRaDeviceClient .Setup(x => x.GetTwinAsync(CancellationToken.None)).Returns(() => { return(Task.FromResult(initialTwin)); }); uint?fcntUpSavedInTwin = null; uint?fcntDownSavedInTwin = null; LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Returns <TwinCollection, CancellationToken>((t, _) => { fcntUpSavedInTwin = (uint)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (uint)t[TwinProperty.FCntDown]; return(Task.FromResult(true)); }); LoRaDeviceClient .Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync((Message)null); var shouldReset = payloadFcntUp == 0 && abpRelaxed; if (shouldReset) { LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEui, It.IsAny <uint>(), It.IsNotNull <string>())).ReturnsAsync(true); } LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(devAddr)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEui, "abc").AsList())); using var memoryCache = new MemoryCache(new MemoryCacheOptions()); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, memoryCache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); // Send to message processor using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var loRaPayloadData = confirmed ? simulatedDevice.CreateConfirmedDataUpMessage("1234", fcnt: payloadFcntUp, appSKey: simulatedDevice.AppSKey, nwkSKey: simulatedDevice.NwkSKey) : simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: payloadFcntUp); using var req = CreateWaitableRequest(TestUtils.GenerateTestRadioMetadata(), loRaPayloadData); 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(DeviceCache.TryGetByDevEui(devEui, out var loRaDevice)); if (confirmed) { Assert.NotNull(req.ResponseDownlink); Assert.True(req.ProcessingSucceeded); Assert.Single(DownstreamMessageSender.DownlinkMessages); var downlinkMessage = DownstreamMessageSender.DownlinkMessages[0]; var payloadDataDown = new LoRaPayloadData(downlinkMessage.Data); payloadDataDown.Serialize(simulatedDevice.AppSKey.Value); Assert.Equal(expectedFcntDown, payloadDataDown.Fcnt); } Assert.Equal(expectedFcntUp, loRaDevice.FCntUp); } }
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(); }