public void When_Cache_Clear_Is_Called_Should_Removed_Cached_Devices(string deviceGatewayID) { const int deviceCount = 10; var deviceList = new HashSet<LoRaDevice>(); var apiService = new Mock<LoRaDeviceAPIServiceBase>(); var deviceFactory = new TestLoRaDeviceFactory(this.loRaDeviceClient.Object); var target = new LoRaDeviceRegistry(this.serverConfiguration, this.cache, apiService.Object, deviceFactory); var getTwinMockSequence = this.loRaDeviceClient.SetupSequence(x => x.GetTwinAsync()); for (var deviceID = 1; deviceID <= deviceCount; ++deviceID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice((uint)deviceID, gatewayID: deviceGatewayID)); var dict = target.InternalGetCachedDevicesForDevAddr(simulatedDevice.DevAddr); var device = TestUtils.CreateFromSimulatedDevice(simulatedDevice, this.loRaDeviceClient.Object); deviceList.Add(device); dict.TryAdd(simulatedDevice.DevEUI, device); } Assert.Equal(deviceCount, this.cache.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 => target.InternalGetCachedDevicesForDevAddr(x.DevAddr).Count == 1)); target.ResetDeviceCache(); Assert.False(deviceList.Any(x => target.InternalGetCachedDevicesForDevAddr(x.DevAddr).Count > 0), "Should not find devices again"); }
public async Task When_Loading_Device_By_DevAddr_Should_Be_Able_To_Load_By_DevEUI() { var simDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1)); var deviceApi = new Mock<LoRaDeviceAPIServiceBase>(MockBehavior.Strict); deviceApi.Setup(x => x.SearchByDevAddrAsync(simDevice.DevAddr)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(simDevice.DevAddr, simDevice.DevEUI, "123").AsList())); var deviceClient = new Mock<ILoRaDeviceClient>(MockBehavior.Strict); deviceClient.Setup(x => x.GetTwinAsync()) .ReturnsAsync(simDevice.CreateABPTwin()); var handlerImplementation = new Mock<ILoRaDataRequestHandler>(MockBehavior.Strict); var deviceFactory = new TestLoRaDeviceFactory(deviceClient.Object, handlerImplementation.Object); var deviceRegistry = new LoRaDeviceRegistry( this.serverConfiguration, this.cache, deviceApi.Object, deviceFactory); var payload = simDevice.CreateUnconfirmedDataUpMessage("1"); payload.SerializeUplink(simDevice.AppSKey, simDevice.NwkSKey); var request = new WaitableLoRaRequest(payload); deviceRegistry.GetLoRaRequestQueue(request).Queue(request); Assert.True(await request.WaitCompleteAsync()); await Task.Delay(50); Assert.NotNull(await deviceRegistry.GetDeviceByDevEUIAsync(simDevice.DevEUI)); handlerImplementation.VerifyAll(); deviceApi.VerifyAll(); deviceClient.VerifyAll(); deviceClient.Verify(x => x.GetTwinAsync(), Times.Once()); }
public MessageProcessorMultipleGatewayTest() { this.SecondServerConfiguration = new NetworkServerConfiguration { GatewayID = SecondServerGatewayID, LogToConsole = true, LogLevel = ((int)LogLevel.Debug).ToString(), }; this.SecondPacketForwarder = new TestPacketForwarder(); this.SecondLoRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); this.SecondFrameCounterUpdateStrategyProvider = new LoRaDeviceFrameCounterUpdateStrategyProvider(SecondServerGatewayID, this.SecondLoRaDeviceApi.Object); var deduplicationStrategyFactory = new DeduplicationStrategyFactory(this.SecondLoRaDeviceApi.Object); var loRaAdrManagerFactory = new LoRAADRManagerFactory(this.SecondLoRaDeviceApi.Object); var adrStrategyProvider = new LoRaADRStrategyProvider(); var functionBundlerProvider = new FunctionBundlerProvider(this.SecondLoRaDeviceApi.Object); this.secondRequestHandlerImplementation = new DefaultLoRaDataRequestHandler(this.SecondServerConfiguration, this.SecondFrameCounterUpdateStrategyProvider, new LoRaPayloadDecoder(), deduplicationStrategyFactory, adrStrategyProvider, loRaAdrManagerFactory, functionBundlerProvider); this.SecondLoRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); this.SecondConnectionManager = new LoRaDeviceClientConnectionManager(new MemoryCache(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromSeconds(5) })); this.SecondLoRaDeviceFactory = new TestLoRaDeviceFactory(this.SecondServerConfiguration, this.SecondFrameCounterUpdateStrategyProvider, this.SecondLoRaDeviceClient.Object, deduplicationStrategyFactory, adrStrategyProvider, loRaAdrManagerFactory, functionBundlerProvider, this.SecondConnectionManager); }
public async Task When_Fcnt_Down_Fails_Should_Stop_And_Not_Update_Device_Twin(int initialFcntDown, int initialFcntUp, int payloadFcnt) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: null)); simulatedDevice.FrmCntDown = initialFcntDown; simulatedDevice.FrmCntUp = initialFcntUp; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; // Lora device api var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.NextFCntDownAsync(devEUI, initialFcntDown, payloadFcnt, ServerGatewayID)).ReturnsAsync((ushort)0); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var device = TestUtils.CreateFromSimulatedDevice(simulatedDevice, loRaDeviceClient.Object); var dicForDevAddr = new DevEUIToLoRaDeviceDictionary(); dicForDevAddr.TryAdd(devEUI, device); memoryCache.Set(devAddr, dicForDevAddr); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("hello", fcnt: payloadFcnt); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var unconfirmedMessageResult = await messageProcessor.ProcessMessageAsync(rxpk); Assert.Null(unconfirmedMessageResult); // 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(initialFcntUp, loRaDevice.FCntUp); Assert.Equal(initialFcntDown, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task When_Getting_DLSettings_From_Twin_Returns_JoinAccept_With_Correct_Settings(int rx1DROffset, int rx2datarate) { string deviceGatewayID = ServerGatewayID; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); // Create Rxpk var rxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var devNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; twin.Properties.Desired[TwinProperty.RX1DROffset] = rx1DROffset; twin.Properties.Desired[TwinProperty.RX2DataRate] = rx2datarate; this.LoRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(twin); this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, this.LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); var loRaDeviceFactory = new TestLoRaDeviceFactory(this.LoRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageProcessor = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var request = this.CreateWaitableRequest(rxpk); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); Assert.Single(this.PacketForwarder.DownlinkMessages); var downlinkMessage = this.PacketForwarder.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(Convert.FromBase64String(downlinkMessage.Txpk.Data), simulatedDevice.LoRaDevice.AppKey); joinAccept.DlSettings.Span.Reverse(); Assert.Equal(rx1DROffset, joinAccept.Rx1DrOffset); Assert.Equal(rx2datarate, joinAccept.Rx2Dr); }
public async Task When_Device_With_Downlink_Disabled_Received_Confirmed_Data_Should_Not_Check_For_C2D(string deviceGatewayID) { const int payloadFcnt = 10; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; // message will be sent var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); loRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); // Lora device api var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); // multi gateway will ask for next fcnt down if (string.IsNullOrEmpty(deviceGatewayID)) { loRaDeviceApi.Setup(x => x.NextFCntDownAsync(devEUI, simulatedDevice.FrmCntDown, payloadFcnt, this.ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)(simulatedDevice.FrmCntDown + 1)); } // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var cachedDevice = TestUtils.CreateFromSimulatedDevice(simulatedDevice, loRaDeviceClient.Object); cachedDevice.DownlinkEnabled = false; var devEUIDeviceDict = new DevEUIToLoRaDeviceDictionary(); devEUIDeviceDict.TryAdd(devEUI, cachedDevice); memoryCache.Set(devAddr, devEUIDeviceDict); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // sends confirmed message var rxpk = simulatedDevice.CreateConfirmedMessageUplink("1234", fcnt: payloadFcnt).Rxpk[0]; var confirmedMessageResult = await messageProcessor.ProcessMessageAsync(rxpk); Assert.NotNull(confirmedMessageResult); loRaDeviceClient.Verify(x => x.ReceiveAsync(It.IsAny <TimeSpan>()), Times.Never()); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task Join_Device_Has_Mismatching_AppEUI_Should_Return_Null(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); // Create Rxpk var joinRequestRxpk = joinRequest.SerializeUplink(simulatedDevice.AppKey).Rxpk[0]; var joinRequestDevNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = "012345678901234567890123456789FF"; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; loRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(twin); // Lora device api will be search by devices with matching deveui, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, joinRequestDevNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // join request should fail var joinRequestDownlinkMessage = await messageProcessor.ProcessMessageAsync(joinRequestRxpk); Assert.Null(joinRequestDownlinkMessage); loRaDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>()), Times.Never); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task When_Device_Is_Assigned_To_Another_Gateway_After_Getting_Twin_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.DeviceID, string.Empty); apiService.Setup(x => x.SearchByDevAddrAsync(It.IsNotNull <string>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); this.loRaDeviceClient.Setup(x => x.GetTwinAsync()) .ReturnsAsync(simulatedDevice.CreateABPTwin()); this.loRaDeviceClient.Setup(x => x.Disconnect()) .Returns(true); var deviceFactory = new TestLoRaDeviceFactory(this.loRaDeviceClient.Object); var target = new LoRaDeviceRegistry(this.serverConfiguration, this.cache, apiService.Object, deviceFactory); // request #1 var payload1 = simulatedDevice.CreateUnconfirmedDataUpMessage("1", fcnt: 11); payload1.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey); var request1 = new WaitableLoRaRequest(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); payload2.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey); var request2 = new WaitableLoRaRequest(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.IsNotNull <string>()), Times.Once()); this.loRaDeviceClient.VerifyAll(); this.loRaDeviceClient.Verify(x => x.GetTwinAsync(), Times.Once()); // device is in cache var devAddrDictionary = target.InternalGetCachedDevicesForDevAddr(LoRaTools.Utils.ConversionHelper.ByteArrayToString(payload1.DevAddr)); Assert.NotNull(devAddrDictionary); Assert.True(devAddrDictionary.TryGetValue(simulatedDevice.DevEUI, out var cachedLoRaDevice)); Assert.False(cachedLoRaDevice.IsOurDevice); }
public async Task When_Device_Does_Not_Match_Gateway_Should_Fail_Request() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: "a_different_one")); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234"); payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DeviceID, string.Empty) { GatewayId = "a_different_one", }; apiService.Setup(x => x.SearchByDevAddrAsync(It.IsNotNull <string>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); var deviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var destinationDictionary = new DevEUIToLoRaDeviceDictionary(); var finished = new SemaphoreSlim(0); var target = new DeviceLoaderSynchronizer( simulatedDevice.DevAddr, apiService.Object, deviceFactory, destinationDictionary, null, this.serverConfiguration, (_, l) => { finished.Release(); }, (d) => destinationDictionary.TryAdd(d.DevEUI, d)); var request = new WaitableLoRaRequest(payload); target.Queue(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.BelongsToAnotherGateway, request.ProcessingFailedReason); // device should not be initialized, since it belongs to another gateway loRaDeviceClient.Verify(x => x.GetTwinAsync(), Times.Never()); // device should not be disconnected (was never connected) loRaDeviceClient.Verify(x => x.Disconnect(), Times.Never()); // Device was searched by DevAddr apiService.VerifyAll(); // Device was created by factory loRaDeviceClient.VerifyAll(); }
public MessageProcessor_End2End_NoDep_ClassC_CloudToDeviceMessage_SizeLimit_Tests() { this.serverConfiguration = new NetworkServerConfiguration() { GatewayID = ServerGatewayID, }; this.loRaRegion = RegionManager.EU868; this.PacketForwarder = new TestPacketForwarder(); this.deviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); this.deviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); this.loRaDeviceFactory = new TestLoRaDeviceFactory(this.deviceClient.Object); this.loRaDeviceRegistry = new LoRaDeviceRegistry(this.serverConfiguration, new MemoryCache(new MemoryCacheOptions()), this.deviceApi.Object, this.loRaDeviceFactory); this.frameCounterStrategyProvider = new LoRaDeviceFrameCounterUpdateStrategyProvider(this.serverConfiguration.GatewayID, this.deviceApi.Object); }
public DefaultClassCDevicesMessageSenderTest() { this.serverConfiguration = new NetworkServerConfiguration() { GatewayID = ServerGatewayID, }; this.loRaRegion = RegionManager.EU868; this.packetForwarder = new Mock <IPacketForwarder>(MockBehavior.Strict); this.deviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); this.deviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); this.loRaDeviceFactory = new TestLoRaDeviceFactory(this.deviceClient.Object); this.loRaDeviceRegistry = new LoRaDeviceRegistry(this.serverConfiguration, new MemoryCache(new MemoryCacheOptions()), this.deviceApi.Object, this.loRaDeviceFactory); this.frameCounterStrategyProvider = new LoRaDeviceFrameCounterUpdateStrategyProvider(this.serverConfiguration.GatewayID, this.deviceApi.Object); }
public async Task When_Device_Is_Not_In_Cache_And_Found_In_Api_Does_Not_Match_Mic_Should_Fail_Request(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID)); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DeviceID, string.Empty); apiService.Setup(x => x.SearchByDevAddrAsync(It.IsNotNull <string>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); // Will get device twin var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); loRaDeviceClient.Setup(x => x.GetTwinAsync()) .ReturnsAsync(TestUtils.CreateABPTwin(simulatedDevice)); var deviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var destinationDictionary = new DevEUIToLoRaDeviceDictionary(); var finished = new SemaphoreSlim(0); var target = new DeviceLoaderSynchronizer( simulatedDevice.DevAddr, apiService.Object, deviceFactory, destinationDictionary, null, this.serverConfiguration, (_, l) => { finished.Release(); }, (d) => destinationDictionary.TryAdd(d.DevEUI, d)); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234"); payload.SerializeUplink(simulatedDevice.AppSKey, "00000000000000000000000000EEAAFF"); var request = new WaitableLoRaRequest(payload); target.Queue(request); Assert.True(await request.WaitCompleteAsync()); Assert.True(request.ProcessingFailed); Assert.Equal(LoRaDeviceRequestFailedReason.NotMatchingDeviceByMicCheck, request.ProcessingFailedReason); // Device was searched by DevAddr apiService.VerifyAll(); loRaDeviceClient.VerifyAll(); }
public async Task When_Api_Returns_DevAlreadyUsed_Should_Return_Null() { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: null)); var joinRequest = simulatedDevice.CreateJoinRequest(); // Create Rxpk var rxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var payloadDecoder = new Mock <ILoRaPayloadDecoder>(); var devNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Lora device api will be search by devices with matching deveui, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult() { IsDevNonceAlreadyUsed = true }); var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyFactory.Object, payloadDecoder.Object); var downlinkMessage = await messageProcessor.ProcessMessageAsync(rxpk); Assert.Null(downlinkMessage); loRaDeviceApi.VerifyAll(); loRaDeviceClient.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"); payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DeviceID, string.Empty); apiService.Setup(x => x.SearchByDevAddrAsync(It.IsNotNull <string>())) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); // device will be initialized this.loRaDeviceClient.Setup(x => x.GetTwinAsync()) .ReturnsAsync(simulatedDevice.CreateABPTwin()); var request = new WaitableLoRaRequest(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(this.loRaDeviceClient.Object, requestHandler.Object); var target = new LoRaDeviceRegistry(this.serverConfiguration, this.cache, apiService.Object, deviceFactory); 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 var cachedItem = target.InternalGetCachedDevicesForDevAddr(simulatedDevice.DevAddr); Assert.NotNull(cachedItem); Assert.Single(cachedItem); Assert.True(cachedItem.TryGetValue(simulatedDevice.DevEUI, out var actualCachedLoRaDevice)); // request was handled requestHandler.VerifyAll(); }
public async Task When_Cache_Clear_Is_Called_Should_Removed_Cached_Devices(string deviceGatewayID) { const int deviceCount = 10; var foundDeviceList = new HashSet <LoRaDevice>(); var apiService = new Mock <LoRaDeviceAPIServiceBase>(); var deviceFactory = new TestLoRaDeviceFactory(this.loRaDeviceClient.Object); var target = new LoRaDeviceRegistry(this.serverConfiguration, this.cache, apiService.Object, deviceFactory); var getTwinMockSequence = this.loRaDeviceClient.SetupSequence(x => x.GetTwinAsync()); for (var deviceID = 1; deviceID <= deviceCount; ++deviceID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice((uint)deviceID, gatewayID: deviceGatewayID)); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234"); payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey); // force mic creation var iotHubDeviceInfo = new IoTHubDeviceInfo(simulatedDevice.LoRaDevice.DevAddr, simulatedDevice.LoRaDevice.DeviceID, string.Empty); apiService.Setup(x => x.SearchByDevAddrAsync(simulatedDevice.DevAddr)) .ReturnsAsync(new SearchDevicesResult(iotHubDeviceInfo.AsList())); // device will be initialized getTwinMockSequence.ReturnsAsync(simulatedDevice.CreateABPTwin()); var actual = await target.GetDeviceForPayloadAsync(payload); Assert.NotNull(actual); foundDeviceList.Add(actual); } Assert.Equal(deviceCount, foundDeviceList.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, foundDeviceList.Count(x => target.InternalGetCachedDevicesForDevAddr(x.DevAddr).Count == 1)); target.ResetDeviceCache(); Assert.False(foundDeviceList.Any(x => target.InternalGetCachedDevicesForDevAddr(x.DevAddr).Count > 0), "Should not find devices again"); }
public async Task GetDeviceByDevEUIAsync_When_Api_Returns_Empty_Should_Return_Null() { var deviceApi = new Mock<LoRaDeviceAPIServiceBase>(MockBehavior.Strict); deviceApi.Setup(x => x.SearchByDevEUIAsync(It.IsNotNull<string>())) .ReturnsAsync(new SearchDevicesResult()); var deviceClient = new Mock<ILoRaDeviceClient>(MockBehavior.Strict); var deviceFactory = new TestLoRaDeviceFactory(deviceClient.Object); var deviceRegistry = new LoRaDeviceRegistry( this.serverConfiguration, this.cache, deviceApi.Object, deviceFactory); var actual = await deviceRegistry.GetDeviceByDevEUIAsync("1"); Assert.Null(actual); deviceApi.VerifyAll(); deviceClient.VerifyAll(); }
public async Task OTAA_Join_Should_Use_Rchf_0(string deviceGatewayID, uint rfch) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); // Create Rxpk var joinRxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; joinRxpk.Rfch = rfch; var devNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; loRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(twin); // Device twin will be updated loRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); var downlinkJoinAcceptMessage = await messageProcessor.ProcessMessageAsync(joinRxpk); Assert.NotNull(downlinkJoinAcceptMessage); // validates txpk according to eu region Assert.Equal(0U, downlinkJoinAcceptMessage.Txpk.Rfch); Assert.Equal(RegionFactory.CreateEU868Region().GetDownstreamChannelFrequency(joinRxpk), downlinkJoinAcceptMessage.Txpk.Freq); Assert.Equal("4/5", downlinkJoinAcceptMessage.Txpk.Codr); Assert.False(downlinkJoinAcceptMessage.Txpk.Imme); Assert.True(downlinkJoinAcceptMessage.Txpk.Ipol); Assert.Equal("LORA", downlinkJoinAcceptMessage.Txpk.Modu); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task When_Getting_RXDelay_Offset_From_Twin_Returns_JoinAccept_With_Correct_Settings_And_Behaves_Correctly(int rxDelay, uint expectedDelay) { string deviceGatewayID = ServerGatewayID; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); string afterJoinAppSKey = null; string afterJoinNwkSKey = null; string afterJoinDevAddr = null; int afterJoinFcntDown = -1; int afterJoinFcntUp = -1; uint startingPayloadFcnt = 0; // Create Rxpk var rxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var devNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; // message will be sent var sentTelemetry = new List <LoRaDeviceTelemetry>(); this.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 this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; twin.Properties.Desired[TwinProperty.RXDelay] = rxDelay; twin.Properties.Desired[TwinProperty.PreferredWindow] = 1; this.LoRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(twin); this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((updatedTwin) => { afterJoinAppSKey = updatedTwin[TwinProperty.AppSKey].Value; afterJoinNwkSKey = updatedTwin[TwinProperty.NwkSKey].Value; afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr].Value; afterJoinFcntDown = updatedTwin[TwinProperty.FCntDown].Value; afterJoinFcntUp = updatedTwin[TwinProperty.FCntUp].Value; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, this.LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); var loRaDeviceFactory = new TestLoRaDeviceFactory(this.LoRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageProcessor = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var request = this.CreateWaitableRequest(rxpk); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); Assert.Single(this.PacketForwarder.DownlinkMessages); var downlinkMessage = this.PacketForwarder.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(Convert.FromBase64String(downlinkMessage.Txpk.Data), simulatedDevice.LoRaDevice.AppKey); joinAccept.RxDelay.Span.Reverse(); if (rxDelay > 0 && rxDelay < 16) { Assert.Equal((int)expectedDelay, (int)joinAccept.RxDelay.Span[0]); } else { Assert.Equal(0, (int)joinAccept.RxDelay.Span[0]); } // Send a message simulatedDevice.LoRaDevice.AppSKey = afterJoinAppSKey; simulatedDevice.LoRaDevice.NwkSKey = afterJoinNwkSKey; simulatedDevice.LoRaDevice.DevAddr = afterJoinDevAddr; // sends confirmed message var confirmedMessagePayload = simulatedDevice.CreateConfirmedDataUpMessage("200", fcnt: startingPayloadFcnt + 1); var confirmedMessageRxpk = confirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var confirmedRequest = this.CreateWaitableRequest(confirmedMessageRxpk); messageProcessor.DispatchRequest(confirmedRequest); Assert.True(await confirmedRequest.WaitCompleteAsync()); Assert.True(confirmedRequest.ProcessingSucceeded); Assert.NotNull(confirmedRequest.ResponseDownlink); Assert.NotNull(confirmedRequest.ResponseDownlink.Txpk); Assert.Equal(2, this.PacketForwarder.DownlinkMessages.Count); var downstreamMessage = this.PacketForwarder.DownlinkMessages[1]; // Message was sent on RX1 with correct delay and with a correct datarate offset if (rxDelay > 0 && rxDelay < 16) { Assert.Equal(expectedDelay * 1000000, downstreamMessage.Txpk.Tmst - confirmedMessageRxpk.Tmst); } else { Assert.Equal(expectedDelay * 1000000, downstreamMessage.Txpk.Tmst - confirmedMessageRxpk.Tmst); } }
public async Task When_Join_With_Custom_Join_Update_Old_Desired_Properties() { var beforeJoinValues = 2; var afterJoinValues = 3; int reportedBeforeJoinRx1DROffsetValue = 0; int reportedBeforeJoinRx2DRValue = 0; int reportedBeforeJoinRxDelayValue = 0; string deviceGatewayID = ServerGatewayID; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); string afterJoinAppSKey = null; string afterJoinNwkSKey = null; string afterJoinDevAddr = null; int afterJoinFcntDown = -1; int afterJoinFcntUp = -1; var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; // message will be sent var sentTelemetry = new List <LoRaDeviceTelemetry>(); this.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 this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync((Message)null); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; twin.Properties.Desired[TwinProperty.RX2DataRate] = afterJoinValues; twin.Properties.Desired[TwinProperty.RX1DROffset] = afterJoinValues; twin.Properties.Desired[TwinProperty.RXDelay] = afterJoinValues; this.LoRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(twin); this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((updatedTwin) => { if (updatedTwin.Contains(TwinProperty.AppSKey)) { afterJoinAppSKey = updatedTwin[TwinProperty.AppSKey].Value; afterJoinNwkSKey = updatedTwin[TwinProperty.NwkSKey].Value; afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr].Value; afterJoinFcntDown = updatedTwin[TwinProperty.FCntDown].Value; afterJoinFcntUp = updatedTwin[TwinProperty.FCntUp].Value; } else { reportedBeforeJoinRx1DROffsetValue = updatedTwin[TwinProperty.RX1DROffset].Value; reportedBeforeJoinRx2DRValue = updatedTwin[TwinProperty.RX2DataRate].Value; reportedBeforeJoinRxDelayValue = updatedTwin[TwinProperty.RXDelay].Value; } }) .ReturnsAsync(true); // create a state before the join var startingTwin = new TwinCollection(); startingTwin[TwinProperty.RX2DataRate] = beforeJoinValues; startingTwin[TwinProperty.RX1DROffset] = beforeJoinValues; startingTwin[TwinProperty.RXDelay] = beforeJoinValues; await this.LoRaDeviceClient.Object.UpdateReportedPropertiesAsync(startingTwin); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); var loRaDeviceFactory = new TestLoRaDeviceFactory(this.LoRaDeviceClient.Object); // Send to message processor var messageProcessor = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var joinRequest = simulatedDevice.CreateJoinRequest(); // Create Rxpk var rxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var devNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); // Lora device api will be search by devices with matching deveui, this.LoRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); var request = this.CreateWaitableRequest(rxpk); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); Assert.NotNull(request.ResponseDownlink); twin.Properties.Desired[TwinProperty.RX2DataRate] = 3; await Task.Delay(TimeSpan.FromMilliseconds(10)); var downlinkMessage = this.PacketForwarder.DownlinkMessages[0]; var joinAccept = new LoRaPayloadJoinAccept(Convert.FromBase64String(downlinkMessage.Txpk.Data), simulatedDevice.LoRaDevice.AppKey); joinAccept.DlSettings.Span.Reverse(); Assert.Equal(afterJoinValues, joinAccept.Rx2Dr); Assert.Equal(afterJoinValues, joinAccept.Rx1DrOffset); Assert.Equal(beforeJoinValues, reportedBeforeJoinRx1DROffsetValue); Assert.Equal(beforeJoinValues, reportedBeforeJoinRx2DRValue); Assert.Equal(afterJoinValues, (int)joinAccept.RxDelay.Span[0]); Assert.Equal(beforeJoinValues, reportedBeforeJoinRxDelayValue); }
public async Task When_Join_Fails_Due_To_GetTwin_Error_Second_Try_Should_Reload_Device_Twin(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest1 = simulatedDevice.CreateJoinRequest(); // Create Rxpk var joinRequestRxpk1 = joinRequest1.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var joinRequestDevNonce1 = ConversionHelper.ByteArrayToString(joinRequest1.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; loRaDeviceClient.SetupSequence(x => x.GetTwinAsync()) .ReturnsAsync((Twin)null) .ReturnsAsync(twin); // Device twin will be updated string afterJoinAppSKey = null; string afterJoinNwkSKey = null; string afterJoinDevAddr = null; loRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((updatedTwin) => { afterJoinAppSKey = updatedTwin[TwinProperty.AppSKey]; afterJoinNwkSKey = updatedTwin[TwinProperty.NwkSKey]; afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, joinRequestDevNonce1)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // 1st join request // Should fail var joinRequestDownlinkMessage1 = await messageProcessor.ProcessMessageAsync(joinRequestRxpk1); Assert.Null(joinRequestDownlinkMessage1); // 2nd attempt var joinRequest2 = simulatedDevice.CreateJoinRequest(); // will reload the device matched by deveui loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, ConversionHelper.ByteArrayToString(joinRequest2.DevNonce))) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); var joinRequestRxpk2 = joinRequest2.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var joinRequestDevNonce2 = LoRaTools.Utils.ConversionHelper.ByteArrayToString(joinRequest2.DevNonce); var joinRequestDownlinkMessage2 = await messageProcessor.ProcessMessageAsync(joinRequestRxpk2); Assert.NotNull(joinRequestDownlinkMessage2); var joinAccept = new LoRaPayloadJoinAccept(Convert.FromBase64String(joinRequestDownlinkMessage2.Txpk.Data), simulatedDevice.LoRaDevice.AppKey); Assert.Equal(joinAccept.DevAddr.ToArray(), ConversionHelper.StringToByteArray(afterJoinDevAddr)); var devicesForDevAddr = deviceRegistry.InternalGetCachedDevicesForDevAddr(afterJoinDevAddr); Assert.Single(devicesForDevAddr); // should have the single device Assert.True(devicesForDevAddr.TryGetValue(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(afterJoinDevAddr, loRaDevice.DevAddr); if (deviceGatewayID == null) { Assert.Null(loRaDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, loRaDevice.GatewayID); } // fcnt is restarted Assert.Equal(0, loRaDevice.FCntUp); Assert.Equal(0, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); // should get twin 2x (1st failed) loRaDeviceClient.Verify(x => x.GetTwinAsync(), Times.Exactly(2)); // should get device for join 2x loRaDeviceApi.Verify(x => x.SearchAndLockForJoinAsync(ServerGatewayID, devEUI, appEUI, It.IsAny <string>())); loRaDeviceClient.VerifyAll(); loRaDeviceApi.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(); // Create Rxpk var rxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var payloadDecoder = new Mock <ILoRaPayloadDecoder>(); var devNonce = ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; loRaDeviceClient.Setup(x => x.GetTwinAsync()).ReturnsAsync(twin); // Device twin will be updated string afterJoinAppSKey = null; string afterJoinNwkSKey = null; string afterJoinDevAddr = null; loRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((updatedTwin) => { afterJoinAppSKey = updatedTwin[TwinProperty.AppSKey]; afterJoinNwkSKey = updatedTwin[TwinProperty.NwkSKey]; afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, devNonce)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); // Setup frame counter strategy for FrameCounterLoRaDeviceInitializer if (deviceGatewayID == null) { this.FrameCounterUpdateStrategyFactory.Setup(x => x.GetMultiGatewayStrategy()) .Returns(this.FrameCounterUpdateStrategy.Object); } else { this.FrameCounterUpdateStrategyFactory.Setup(x => x.GetSingleGatewayStrategy()) .Returns(this.FrameCounterUpdateStrategy.Object); } // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyFactory.Object, payloadDecoder.Object); var downlinkMessage = await messageProcessor.ProcessMessageAsync(rxpk); Assert.NotNull(downlinkMessage); var joinAccept = new LoRaPayloadJoinAccept(Convert.FromBase64String(downlinkMessage.Txpk.Data), simulatedDevice.LoRaDevice.AppKey); Assert.Equal(joinAccept.DevAddr.ToArray(), ConversionHelper.StringToByteArray(afterJoinDevAddr)); // check that the device is in cache Assert.True(memoryCache.TryGetValue <DevEUIToLoRaDeviceDictionary>(afterJoinDevAddr, out var cachedDevices)); Assert.True(cachedDevices.TryGetValue(devEUI, out var cachedDevice)); Assert.Equal(afterJoinAppSKey, cachedDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, cachedDevice.NwkSKey); Assert.Equal(afterJoinDevAddr, cachedDevice.DevAddr); Assert.True(cachedDevice.IsOurDevice); if (deviceGatewayID == null) { Assert.Null(cachedDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, cachedDevice.GatewayID); } // fcnt is restarted Assert.Equal(0, cachedDevice.FCntUp); Assert.Equal(0, cachedDevice.FCntDown); Assert.False(cachedDevice.HasFrameCountChanges); }
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 joinRequest1 = simulatedDevice.CreateJoinRequest(); var joinRequest2 = simulatedDevice.CreateJoinRequest(); // Create Rxpk var joinRequestRxpk1 = joinRequest1.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var joinRequestRxpk2 = joinRequest2.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var joinRequestDevNonce1 = joinRequest1.GetDevNonceAsString(); var joinRequestDevNonce2 = joinRequest2.GetDevNonceAsString(); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; loRaDeviceClient.Setup(x => x.GetTwinAsync()) .ReturnsAsync(twin); // Device twin will be updated string afterJoin1AppSKey = null; string afterJoin1NwkSKey = null; string afterJoin1DevAddr = null; string afterJoin2AppSKey = null; string afterJoin2NwkSKey = null; string afterJoin2DevAddr = null; var isFirstTwinUpdate = true; loRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((updatedTwin) => { if (isFirstTwinUpdate) { afterJoin1AppSKey = updatedTwin[TwinProperty.AppSKey]; afterJoin1NwkSKey = updatedTwin[TwinProperty.NwkSKey]; afterJoin1DevAddr = updatedTwin[TwinProperty.DevAddr]; Thread.Sleep(TimeSpan.FromSeconds(10)); isFirstTwinUpdate = false; } else { afterJoin2AppSKey = updatedTwin[TwinProperty.AppSKey]; afterJoin2NwkSKey = updatedTwin[TwinProperty.NwkSKey]; afterJoin2DevAddr = updatedTwin[TwinProperty.DevAddr]; } }) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, joinRequestDevNonce1)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, joinRequestDevNonce2)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); var joinRequestTask1 = messageProcessor.ProcessMessageAsync(joinRequestRxpk1); await Task.Delay(TimeSpan.FromSeconds(7)); var joinRequestTask2 = messageProcessor.ProcessMessageAsync(joinRequestRxpk2); await Task.WhenAll(joinRequestTask1, joinRequestTask2); Assert.Null(joinRequestTask1.Result); Assert.NotNull(joinRequestTask2.Result); Assert.Empty(deviceRegistry.InternalGetCachedDevicesForDevAddr(afterJoin1DevAddr)); var devicesInDevAddr2 = deviceRegistry.InternalGetCachedDevicesForDevAddr(afterJoin2DevAddr); Assert.NotEmpty(devicesInDevAddr2); Assert.True(devicesInDevAddr2.TryGetValue(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(), Times.Once()); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task Join_And_Send_Unconfirmed_And_Confirmed_Messages(string deviceGatewayID, int initialFcntUp, int initialFcntDown, int startingPayloadFcnt, uint netId) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var joinRequest = simulatedDevice.CreateJoinRequest(); // Create Rxpk var joinRxpk = joinRequest.SerializeUplink(simulatedDevice.LoRaDevice.AppKey).Rxpk[0]; var devNonce = LoRaTools.Utils.ConversionHelper.ByteArrayToString(joinRequest.DevNonce); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); this.ServerConfiguration.NetId = netId; // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; 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()).ReturnsAsync(twin); // Device twin will be updated string afterJoinAppSKey = null; string afterJoinNwkSKey = null; string afterJoinDevAddr = null; int afterJoinFcntDown = -1; int afterJoinFcntUp = -1; loRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((updatedTwin) => { afterJoinAppSKey = updatedTwin[TwinProperty.AppSKey]; afterJoinNwkSKey = updatedTwin[TwinProperty.NwkSKey]; afterJoinDevAddr = updatedTwin[TwinProperty.DevAddr]; afterJoinFcntDown = updatedTwin[TwinProperty.FCntDown]; afterJoinFcntUp = updatedTwin[TwinProperty.FCntUp]; }) .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, var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, 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, this.ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)1); } // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); var downlinkJoinAcceptMessage = await messageProcessor.ProcessMessageAsync(joinRxpk); Assert.NotNull(downlinkJoinAcceptMessage); var joinAccept = new LoRaPayloadJoinAccept(Convert.FromBase64String(downlinkJoinAcceptMessage.Txpk.Data), simulatedDevice.LoRaDevice.AppKey); Assert.Equal(joinAccept.DevAddr.ToArray(), ConversionHelper.StringToByteArray(afterJoinDevAddr)); // check that the device is in cache var devicesForDevAddr = deviceRegistry.InternalGetCachedDevicesForDevAddr(afterJoinDevAddr); Assert.Single(devicesForDevAddr); // should have the single device Assert.True(devicesForDevAddr.TryGetValue(devEUI, out var loRaDevice)); Assert.Equal(afterJoinAppSKey, loRaDevice.AppSKey); Assert.Equal(afterJoinNwkSKey, loRaDevice.NwkSKey); Assert.Equal(afterJoinDevAddr, loRaDevice.DevAddr); var netIdBytes = BitConverter.GetBytes(netId); Assert.Equal((uint)(netIdBytes[0] & 0b01111111), NetIdHelper.GetNwkIdPart(afterJoinDevAddr)); if (deviceGatewayID == null) { Assert.Null(loRaDevice.GatewayID); } else { Assert.Equal(deviceGatewayID, loRaDevice.GatewayID); } // fcnt is restarted Assert.Equal(0, afterJoinFcntDown); Assert.Equal(0, afterJoinFcntUp); Assert.Equal(0, loRaDevice.FCntUp); Assert.Equal(0, loRaDevice.FCntDown); Assert.False(loRaDevice.HasFrameCountChanges); simulatedDevice.LoRaDevice.AppSKey = afterJoinAppSKey; simulatedDevice.LoRaDevice.NwkSKey = afterJoinNwkSKey; simulatedDevice.LoRaDevice.DevAddr = afterJoinDevAddr; // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("100", fcnt: startingPayloadFcnt); var unconfirmedMessageResult = await messageProcessor.ProcessMessageAsync(unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]); Assert.Null(unconfirmedMessageResult); // fcnt up was updated Assert.Equal(startingPayloadFcnt, loRaDevice.FCntUp); Assert.Equal(0, loRaDevice.FCntDown); 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); var confirmedMessageRxpk = confirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var confirmedMessage = await messageProcessor.ProcessMessageAsync(confirmedMessageRxpk); Assert.NotNull(confirmedMessage); Assert.NotNull(confirmedMessage.Txpk); Assert.Equal(2, sentTelemetry.Count); // validates txpk according to eu region Assert.Equal(RegionFactory.CreateEU868Region().GetDownstreamChannelFrequency(confirmedMessageRxpk), confirmedMessage.Txpk.Freq); Assert.Equal("4/5", confirmedMessage.Txpk.Codr); Assert.False(confirmedMessage.Txpk.Imme); Assert.True(confirmedMessage.Txpk.Ipol); Assert.Equal("LORA", confirmedMessage.Txpk.Modu); // fcnt up was updated Assert.Equal(startingPayloadFcnt + 1, loRaDevice.FCntUp); Assert.Equal(1, loRaDevice.FCntDown); // Frame change flag will be set, only saving every 10 messages Assert.True(loRaDevice.HasFrameCountChanges); // C2D message will be checked twice loRaDeviceClient.Verify(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>()), Times.Exactly(2)); // has telemetry with both fcnt Assert.Single(sentTelemetry, (t) => t.Fcnt == startingPayloadFcnt); Assert.Single(sentTelemetry, (t) => t.Fcnt == (startingPayloadFcnt + 1)); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task ABP_New_Loaded_Device_With_Fcnt_1_Or_0_Should_Reset_Fcnt_And_Send_To_IotHub( string twinGatewayID, int payloadFcntUp, int?deviceTwinFcntUp, int?deviceTwinFcntDown) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: null)); var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; // 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; 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 (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()).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>())) .Callback <TwinCollection>((t) => { fcntUpSavedInTwin = (int)t[TwinProperty.FCntUp]; fcntDownSavedInTwin = (int)t[TwinProperty.FCntDown]; }) .ReturnsAsync(true); } // Lora device api var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); // multi gateway will reset the fcnt if (shouldSaveTwin) { loRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(devEUI)) .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 factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("hello", fcnt: payloadFcntUp); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var unconfirmedMessageResult = await messageProcessor.ProcessMessageAsync(rxpk); Assert.Null(unconfirmedMessageResult); // Ensure that a telemetry was sent Assert.NotNull(loRaDeviceTelemetry); // Assert.Equal(msgPayload, loRaDeviceTelemetry.data); // 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 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(0, 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_Getting_C2D_Message_Fails_To_Resolve_Fcnt_Down_Should_Drop_Message_And_Return_Null() { const int initialFcntDown = 5; const int initialFcntUp = 21; const int payloadFcnt = 23; var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1, gatewayID: null)); simulatedDevice.FrmCntUp = initialFcntUp; simulatedDevice.FrmCntDown = initialFcntDown; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var devAddr = simulatedDevice.LoRaDevice.DevAddr; // message will be sent var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); loRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); var cloudToDeviceMessage = new Message(); cloudToDeviceMessage.Properties.Add("fport", "1"); // C2D message will be retrieved loRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync(cloudToDeviceMessage); // C2D message will be abandonned loRaDeviceClient.Setup(x => x.AbandonAsync(cloudToDeviceMessage)) .ReturnsAsync(true); // Lora device api var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); // getting the fcnt down will return 0! loRaDeviceApi.Setup(x => x.NextFCntDownAsync(devEUI, initialFcntDown, payloadFcnt, this.ServerConfiguration.GatewayID)) .ReturnsAsync((ushort)0); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var cachedDevice = TestUtils.CreateFromSimulatedDevice(simulatedDevice, loRaDeviceClient.Object); var devEUIDeviceDict = new DevEUIToLoRaDeviceDictionary(); devEUIDeviceDict.TryAdd(devEUI, cachedDevice); memoryCache.Set(devAddr, devEUIDeviceDict); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); // Send to message processor var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // sends unconfirmed message var unconfirmedMessagePayload = simulatedDevice.CreateUnconfirmedDataUpMessage("hello", fcnt: payloadFcnt); var rxpk = unconfirmedMessagePayload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var unconfirmedMessageResult = await messageProcessor.ProcessMessageAsync(rxpk); Assert.Null(unconfirmedMessageResult); var cachedDevices = deviceRegistry.InternalGetCachedDevicesForDevAddr(simulatedDevice.DevAddr); Assert.True(cachedDevices.TryGetValue(devEUI, out var loRaDevice)); // fcnt down did not change Assert.Equal(initialFcntDown, loRaDevice.FCntDown); // fcnt up changed Assert.Equal(unconfirmedMessagePayload.GetFcnt(), loRaDevice.FCntUp); loRaDeviceClient.Verify(x => x.ReceiveAsync(It.IsAny <TimeSpan>()), Times.Once()); loRaDeviceClient.Verify(x => x.AbandonAsync(It.IsAny <Message>()), Times.Once()); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }
public async Task When_Multiple_Joins_Are_Received_Should_Get_Twins_Once(string deviceGatewayID) { var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, gatewayID: deviceGatewayID)); var devAddr = string.Empty; var devEUI = simulatedDevice.LoRaDevice.DeviceID; var appEUI = simulatedDevice.LoRaDevice.AppEUI; var loRaDeviceClient = new Mock <ILoRaDeviceClient>(MockBehavior.Strict); // Device twin will be queried var twin = new Twin(); twin.Properties.Desired[TwinProperty.DevEUI] = devEUI; twin.Properties.Desired[TwinProperty.AppEUI] = simulatedDevice.LoRaDevice.AppEUI; twin.Properties.Desired[TwinProperty.AppKey] = simulatedDevice.LoRaDevice.AppKey; twin.Properties.Desired[TwinProperty.GatewayID] = deviceGatewayID; twin.Properties.Desired[TwinProperty.SensorDecoder] = simulatedDevice.LoRaDevice.SensorDecoder; loRaDeviceClient.Setup(x => x.GetTwinAsync()) .ReturnsAsync(twin); // Device twin will be updated loRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .ReturnsAsync(true); // Lora device api will be search by devices with matching deveui var loRaDeviceApi = new Mock <LoRaDeviceAPIServiceBase>(MockBehavior.Strict); loRaDeviceApi.Setup(x => x.SearchAndLockForJoinAsync(this.ServerConfiguration.GatewayID, devEUI, appEUI, It.IsAny <string>())) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(devAddr, devEUI, "aabb").AsList())); // using factory to create mock of var loRaDeviceFactory = new TestLoRaDeviceFactory(loRaDeviceClient.Object); var memoryCache = new MemoryCache(new MemoryCacheOptions()); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, memoryCache, loRaDeviceApi.Object, loRaDeviceFactory); var frameCounterUpdateStrategyFactory = new LoRaDeviceFrameCounterUpdateStrategyFactory(this.ServerConfiguration.GatewayID, loRaDeviceApi.Object); var messageProcessor = new MessageProcessor( this.ServerConfiguration, deviceRegistry, frameCounterUpdateStrategyFactory, new LoRaPayloadDecoder()); // 1st join request var joinRequest1Response = messageProcessor.ProcessMessageAsync(simulatedDevice.CreateJoinRequest().SerializeUplink(simulatedDevice.AppKey).Rxpk[0]); // 2nd join request var joinRequest2Response = messageProcessor.ProcessMessageAsync(simulatedDevice.CreateJoinRequest().SerializeUplink(simulatedDevice.AppKey).Rxpk[0]); await Task.WhenAll(joinRequest1Response, joinRequest2Response); Assert.NotNull(joinRequest1Response.Result); Assert.NotNull(joinRequest2Response.Result); // get twin only once called loRaDeviceClient.Verify(x => x.GetTwinAsync(), Times.Once()); // get device for join called x2 loRaDeviceApi.Verify(x => x.SearchAndLockForJoinAsync(ServerGatewayID, devEUI, appEUI, It.IsAny <string>())); loRaDeviceClient.VerifyAll(); loRaDeviceApi.VerifyAll(); }