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