public async Task When_Processing_Data_Request_Should_Compute_Preferred_Gateway_And_Region( [CombinatorialValues(null, ServerGatewayID)] string deviceGatewayID, [CombinatorialValues(null, ServerGatewayID, "another-gateway")] string initialPreferredGatewayID, [CombinatorialValues(ServerGatewayID, "another-gateway")] string preferredGatewayID, [CombinatorialValues(null, LoRaRegionType.EU868, LoRaRegionType.US915)] LoRaRegionType?initialLoRaRegion) { const uint PayloadFcnt = 10; const uint InitialDeviceFcntUp = 9; const uint InitialDeviceFcntDown = 20; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(1, gatewayID: deviceGatewayID, deviceClassType: 'c'), frmCntUp: InitialDeviceFcntUp, frmCntDown: InitialDeviceFcntDown); var loraDevice = this.CreateLoRaDevice(simulatedDevice); loraDevice.UpdatePreferredGatewayID(initialPreferredGatewayID, acceptChanges: true); if (initialLoRaRegion.HasValue) { loraDevice.UpdateRegion(initialLoRaRegion.Value, acceptChanges: true); } var shouldSavePreferredGateway = string.IsNullOrEmpty(deviceGatewayID) && initialPreferredGatewayID != preferredGatewayID && preferredGatewayID == ServerGatewayID; var shouldSaveRegion = (!initialLoRaRegion.HasValue || initialLoRaRegion.Value != LoRaRegionType.EU868) && (preferredGatewayID == ServerGatewayID || deviceGatewayID != null); var bundlerResult = new FunctionBundlerResult() { PreferredGatewayResult = new PreferredGatewayResult() { DevEUI = simulatedDevice.DevEUI, PreferredGatewayID = preferredGatewayID, CurrentFcntUp = PayloadFcnt, RequestFcntUp = PayloadFcnt, } }; if (string.IsNullOrEmpty(deviceGatewayID)) { this.LoRaDeviceApi.Setup(x => x.ExecuteFunctionBundlerAsync(simulatedDevice.DevEUI, It.IsNotNull <FunctionBundlerRequest>())) .Callback <string, FunctionBundlerRequest>((devEUI, bundlerRequest) => { Assert.Equal(PayloadFcnt, bundlerRequest.ClientFCntUp); Assert.Equal(ServerGatewayID, bundlerRequest.GatewayId); Assert.Equal(FunctionBundlerItemType.PreferredGateway, bundlerRequest.FunctionItems); }) .ReturnsAsync(bundlerResult); } if (shouldSavePreferredGateway || shouldSaveRegion) { this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((savedTwin) => { if (shouldSavePreferredGateway) { Assert.Equal(ServerGatewayID, savedTwin[TwinProperty.PreferredGatewayID].Value as string); } else { Assert.False(savedTwin.Contains(TwinProperty.PreferredGatewayID)); } if (shouldSaveRegion) { Assert.Equal(LoRaRegionType.EU868.ToString(), savedTwin[TwinProperty.Region].Value as string); } else { Assert.False(savedTwin.Contains(TwinProperty.Region)); } }) .ReturnsAsync(true); } this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync((Message)null); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(loraDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageProcessor = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: PayloadFcnt); var rxpk = payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request = this.CreateWaitableRequest(rxpk); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub this.LoRaDeviceClient.VerifyAll(); this.LoRaDeviceApi.VerifyAll(); // 2. No downstream message for the current device is sent Assert.Null(request.ResponseDownlink); Assert.True(request.ProcessingSucceeded); if (!string.IsNullOrEmpty(deviceGatewayID)) { Assert.Equal(initialPreferredGatewayID, loraDevice.PreferredGatewayID); } else { Assert.Equal(preferredGatewayID, loraDevice.PreferredGatewayID); } Assert.Equal(LoRaRegionType.EU868, loraDevice.LoRaRegion); }
public async Task When_Updating_PreferredGateway_And_FcntUp_Should_Save_Twin_Once() { const uint PayloadFcnt = 10; const uint InitialDeviceFcntUp = 9; const uint InitialDeviceFcntDown = 20; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(1, deviceClassType: 'c'), frmCntUp: InitialDeviceFcntUp, frmCntDown: InitialDeviceFcntDown); var loraDevice = this.CreateLoRaDevice(simulatedDevice); loraDevice.UpdatePreferredGatewayID("another-gateway", acceptChanges: true); var bundlerResult = new FunctionBundlerResult() { PreferredGatewayResult = new PreferredGatewayResult() { DevEUI = simulatedDevice.DevEUI, PreferredGatewayID = ServerGatewayID, CurrentFcntUp = PayloadFcnt, RequestFcntUp = PayloadFcnt, } }; this.LoRaDeviceApi.Setup(x => x.ExecuteFunctionBundlerAsync(simulatedDevice.DevEUI, It.IsNotNull <FunctionBundlerRequest>())) .Callback <string, FunctionBundlerRequest>((devEUI, bundlerRequest) => { Assert.Equal(PayloadFcnt, bundlerRequest.ClientFCntUp); Assert.Equal(ServerGatewayID, bundlerRequest.GatewayId); Assert.Equal(FunctionBundlerItemType.PreferredGateway, bundlerRequest.FunctionItems); }) .ReturnsAsync(bundlerResult); this.LoRaDeviceClient.Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>())) .Callback <TwinCollection>((savedTwin) => { Assert.Equal(ServerGatewayID, savedTwin[TwinProperty.PreferredGatewayID].Value as string); Assert.Equal(LoRaRegionType.EU868.ToString(), savedTwin[TwinProperty.Region].Value as string); Assert.Equal(PayloadFcnt, (uint)savedTwin[TwinProperty.FCntUp].Value); }) .ReturnsAsync(true); this.LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); this.LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync((Message)null); var deviceRegistry = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(loraDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory); // Send to message processor var messageProcessor = new MessageDispatcher( this.ServerConfiguration, deviceRegistry, this.FrameCounterUpdateStrategyProvider); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: PayloadFcnt); var rxpk = payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0]; var request = this.CreateWaitableRequest(rxpk); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub this.LoRaDeviceClient.VerifyAll(); this.LoRaDeviceApi.VerifyAll(); // 2. No downstream message for the current device is sent Assert.Null(request.ResponseDownlink); Assert.True(request.ProcessingSucceeded); Assert.Equal(ServerGatewayID, loraDevice.PreferredGatewayID); Assert.Equal(LoRaRegionType.EU868, loraDevice.LoRaRegion); Assert.Equal(PayloadFcnt, loraDevice.FCntUp); this.LoRaDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>()), Times.Once()); }
public async Task When_Updating_PreferredGateway_And_FcntUp_Should_Save_Twin_Once() { const uint PayloadFcnt = 10; const uint InitialDeviceFcntUp = 9; const uint InitialDeviceFcntDown = 20; var simulatedDevice = new SimulatedDevice( TestDeviceInfo.CreateABPDevice(1, deviceClassType: 'c'), frmCntUp: InitialDeviceFcntUp, frmCntDown: InitialDeviceFcntDown); var loraDevice = CreateLoRaDevice(simulatedDevice); loraDevice.UpdatePreferredGatewayID("another-gateway", acceptChanges: true); var bundlerResult = new FunctionBundlerResult() { PreferredGatewayResult = new PreferredGatewayResult() { DevEUI = simulatedDevice.DevEUI, PreferredGatewayID = ServerGatewayID, CurrentFcntUp = PayloadFcnt, RequestFcntUp = PayloadFcnt, } }; LoRaDeviceApi .Setup(x => x.ExecuteFunctionBundlerAsync(simulatedDevice.DevEUI, It.Is((FunctionBundlerRequest r) => PayloadFcnt == r.ClientFCntUp && ServerGatewayID == r.GatewayId && FunctionBundlerItemType.PreferredGateway == r.FunctionItems))) .ReturnsAsync(bundlerResult); TwinCollection actualSavedTwin = null; LoRaDeviceClient .Setup(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>())) .Callback <TwinCollection, CancellationToken>((savedTwin, _) => actualSavedTwin = savedTwin) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .ReturnsAsync(true); LoRaDeviceClient.Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>())) .ReturnsAsync((Message)null); using var cache = EmptyMemoryCache(); using var loraDeviceCache = CreateDeviceCache(loraDevice); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, loraDeviceCache); // Send to message processor using var messageProcessor = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: PayloadFcnt); using var request = CreateWaitableRequest(payload); messageProcessor.DispatchRequest(request); Assert.True(await request.WaitCompleteAsync()); // Expectations // 1. Message was sent to IoT Hub LoRaDeviceClient.VerifyAll(); LoRaDeviceApi.VerifyAll(); // 2. No downstream message for the current device is sent Assert.Null(request.ResponseDownlink); Assert.True(request.ProcessingSucceeded); Assert.Equal(ServerGatewayID, loraDevice.PreferredGatewayID); Assert.Equal(LoRaRegionType.EU868, loraDevice.LoRaRegion); Assert.Equal(PayloadFcnt, loraDevice.FCntUp); LoRaDeviceClient.Verify(x => x.UpdateReportedPropertiesAsync(It.IsNotNull <TwinCollection>(), It.IsAny <CancellationToken>()), Times.Once()); Assert.Equal(ServerGatewayID, actualSavedTwin[TwinProperty.PreferredGatewayID].Value as string); Assert.Equal(LoRaRegionType.EU868.ToString(), actualSavedTwin[TwinProperty.Region].Value as string); Assert.Equal(PayloadFcnt, (uint)actualSavedTwin[TwinProperty.FCntUp].Value); }