public async Task When_CN470JoinChannel_Is_In_Twin_Should_Have_JoinChannel_Set() { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "CN470JoinChannel", 10 } }, reported: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "CN470JoinChannel", 2 } }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.Equal(2, loRaDevice.ReportedCN470JoinChannel); // check that reported property is prioritized }
public async Task When_Initialized_With_Keep_Alive_Should_Read_Value_From_Twin(object keepAliveTimeoutValue, int expectedKeepAliveTimeout) { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "GatewayID", "mygateway" }, { "SensorDecoder", "DecoderValueSensor" }, { "KeepAliveTimeout", keepAliveTimeoutValue }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" } }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.Equal(expectedKeepAliveTimeout, loRaDevice.KeepAliveTimeout); }
public async Task When_PreferredWindow_Is_Not_Define_In_Twin_Should_Have_Window1_As_Preferred() { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "GatewayID", "mygateway" }, { "SensorDecoder", "DecoderValueSensor" }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.Equal(ReceiveWindow1, loRaDevice.PreferredWindow); }
public async Task When_Downlink_Is_Enabled_In_Twin_Should_Have_DownlinkEnabled_Equals_True(object downlinkTwinPropertyValue) { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "GatewayID", "mygateway" }, { "SensorDecoder", "DecoderValueSensor" }, { TwinProperty.DownlinkEnabled, downlinkTwinPropertyValue }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.True(loRaDevice.DownlinkEnabled); }
public async Task When_StationEui_Missing_Should_Fail() { var devAddr = new DevAddr(0x023637F8); var appSKey = TestKeys.CreateAppSessionKey(0xABC0200000000000, 0x09); var nwkSKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var simDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, deviceClassType: 'c', gatewayID: ServerGatewayID)); var devEUI = simDevice.DevEUI; simDevice.SetupJoin(appSKey, nwkSKey, devAddr); this.deviceApi.Setup(x => x.GetPrimaryKeyByEuiAsync(devEUI)) .ReturnsAsync("123"); var twin = simDevice.CreateOTAATwin( desiredProperties: new Dictionary <string, object> { { TwinProperty.RX2DataRate, "10" } }, reportedProperties: new Dictionary <string, object> { { TwinProperty.RX2DataRate, 10 }, { TwinProperty.Region, LoRaRegionType.US915.ToString() }, // OTAA device, already joined { TwinProperty.DevAddr, devAddr.ToString() }, { TwinProperty.AppSKey, appSKey.ToString() }, { TwinProperty.NwkSKey, nwkSKey.ToString() }, }); this.deviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); var c2dToDeviceMessage = new ReceivedLoRaCloudToDeviceMessage() { Payload = "hello", DevEUI = devEUI, Fport = TestPort, MessageId = Guid.NewGuid().ToString(), }; var target = new DefaultClassCDevicesMessageSender( this.serverConfiguration, this.loRaDeviceRegistry, this.downstreamMessageSender.Object, this.frameCounterStrategyProvider, NullLogger <DefaultClassCDevicesMessageSender> .Instance, TestMeter.Instance); Assert.False(await target.SendAsync(c2dToDeviceMessage)); this.downstreamMessageSender.VerifyAll(); this.deviceApi.VerifyAll(); this.deviceClient.VerifyAll(); }
public async Task When_Initialized_With_Class_C_And_Custom_RX2DR_Should_Have_Correct_Properties() { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "AppEUI", new JoinEui(0xABCD1234).ToString() }, { "AppKey", "ABCD2000000000000000000000000009" }, { "ClassType", "C" }, { "GatewayID", "mygateway" }, { "SensorDecoder", "http://mydecoder" }, { "RX2DataRate", "10" }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "FCntDown", 9 }, { "FCntUp", 100 }, { "DevEUI", "ABC0200000000009" }, { "NetId", "010000" }, { "DevNonce", "C872" }, { "RX2DataRate", 10 }, { "Region", "US915" }, }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.Equal(LoRaDeviceClassType.C, loRaDevice.ClassType); Assert.Equal("mygateway", loRaDevice.GatewayID); Assert.Equal(9u, loRaDevice.FCntDown); Assert.Equal(100u, loRaDevice.FCntUp); Assert.Equal(DR10, loRaDevice.ReportedRX2DataRate.Value); Assert.Equal(DR10, loRaDevice.DesiredRX2DataRate.Value); Assert.Equal(appSessionKey, loRaDevice.AppSKey); Assert.Equal(networkSessionKey, loRaDevice.NwkSKey); Assert.Equal(LoRaRegionType.US915, loRaDevice.LoRaRegion); Assert.False(loRaDevice.IsABP); }
public async Task When_Initialized_With_PreferredGateway_And_Region_Should_Get_Properties( [CombinatorialValues("EU868", "3132", "eu868", "US915", "us915", "eu")] string regionValue) { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "GatewayID", "mygateway" }, { "SensorDecoder", "DecoderValueSensor" }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "FCntDown", 10 }, { "FCntUp", 20 }, { "PreferredGatewayID", "gateway1" }, { "Region", regionValue } }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); if (string.Equals(LoRaRegionType.EU868.ToString(), regionValue, StringComparison.OrdinalIgnoreCase)) { Assert.Equal(LoRaRegionType.EU868, loRaDevice.LoRaRegion); } else if (string.Equals(LoRaRegionType.US915.ToString(), regionValue, StringComparison.OrdinalIgnoreCase)) { Assert.Equal(LoRaRegionType.US915, loRaDevice.LoRaRegion); } else { Assert.Equal(LoRaRegionType.NotSet, loRaDevice.LoRaRegion); } }
public async Task When_Initialized_ABP_Device_Should_Have_All_Properties() { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "GatewayID", this.configuration.GatewayID }, { "SensorDecoder", "DecoderValueSensor" }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.Null(loRaDevice.AppEui); Assert.Null(loRaDevice.AppKey); Assert.Equal(this.configuration.GatewayID, loRaDevice.GatewayID); Assert.Equal("DecoderValueSensor", loRaDevice.SensorDecoder); Assert.True(loRaDevice.IsABP); Assert.True(loRaDevice.IsOurDevice); Assert.Equal(0U, loRaDevice.FCntDown); Assert.Equal(0U, loRaDevice.LastSavedFCntDown); Assert.Equal(0U, loRaDevice.FCntUp); Assert.Equal(0U, loRaDevice.LastSavedFCntUp); Assert.False(loRaDevice.HasFrameCountChanges); Assert.Equal(networkSessionKey, loRaDevice.NwkSKey); Assert.Equal(appSessionKey, loRaDevice.AppSKey); Assert.Null(loRaDevice.DevNonce); Assert.Equal(new DevAddr(0x0000aabb), loRaDevice.DevAddr); Assert.Null(loRaDevice.ReportedDwellTimeSetting); }
public async Task When_Initialized_ABP_Device_Has_Fcnt_Should_Have_Non_Zero_Fcnt_Values() { var networkSessionKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var appSessionKey = TestKeys.CreateAppSessionKey(0xABCD200000000000, 0x09); var twin = TestUtils.CreateTwin( desired: new Dictionary <string, object> { { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "GatewayID", this.configuration.GatewayID }, { "SensorDecoder", "DecoderValueSensor" }, { "$version", 1 }, }, reported: new Dictionary <string, object> { { "$version", 1 }, { "NwkSKey", networkSessionKey.ToString() }, { "AppSKey", appSessionKey.ToString() }, { "DevAddr", "0000AABB" }, { "FCntDown", 10 }, { "FCntUp", 20 }, }); this.loRaDeviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); using var loRaDevice = CreateDefaultDevice(); await loRaDevice.InitializeAsync(this.configuration); Assert.True(loRaDevice.IsOurDevice); Assert.Equal(10U, loRaDevice.FCntDown); Assert.Equal(10U, loRaDevice.LastSavedFCntDown); Assert.Equal(20U, loRaDevice.FCntUp); Assert.Equal(20U, loRaDevice.LastSavedFCntUp); Assert.Empty(loRaDevice.PreferredGatewayID); Assert.Equal(LoRaRegionType.NotSet, loRaDevice.LoRaRegion); Assert.False(loRaDevice.HasFrameCountChanges); }
// [InlineData(200, 500, 100, 100, 1)] public async Task When_Multiple_Devices_And_Conflicting_DevAddr_Send_Telemetry_Queue_Sends_Messages_To_IoTHub( int searchDelay, int getTwinDelay, int sendMessageDelay, int receiveDelay, int delayBetweenMessages) { const int messagePerDeviceCount = 10; const int payloadInitialFcnt = 2; var device1 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1)); var device1Twin = TestUtils.CreateABPTwin(device1); var device2 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(2)) { DevAddr = device1.DevAddr }; var device2Twin = TestUtils.CreateABPTwin(device2); var device3 = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(3)); device3.SetupJoin(TestKeys.CreateAppSessionKey(0x88), TestKeys.CreateNetworkSessionKey(0x88), new DevAddr(0x02000088)); var device3Twin = TestUtils.CreateOTAATwin(device3); var device4 = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(4)); var device4Twin = TestUtils.CreateABPTwin(device4); var device1And2Result = new IoTHubDeviceInfo[] { new IoTHubDeviceInfo(device1.DevAddr, device1.DevEUI, "1"), new IoTHubDeviceInfo(device2.DevAddr, device2.DevEUI, "2"), }; LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(device1.DevAddr.Value)) .ReturnsAsync(new SearchDevicesResult(device1And2Result), TimeSpan.FromMilliseconds(searchDelay)); LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(device3.DevAddr.Value)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(device3.DevAddr, device3.DevEUI, "3").AsList()), TimeSpan.FromMilliseconds(searchDelay)); LoRaDeviceApi.Setup(x => x.SearchByDevAddrAsync(device4.DevAddr.Value)) .ReturnsAsync(new SearchDevicesResult(new IoTHubDeviceInfo(device4.DevAddr, device4.DevEUI, "3").AsList()), TimeSpan.FromMilliseconds(searchDelay)); var deviceClient1 = new Mock <ILoRaDeviceClient>(); var deviceClient1Telemetry = new List <LoRaDeviceTelemetry>(); deviceClient1.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(device1Twin, TimeSpan.FromMilliseconds(getTwinDelay)); deviceClient1.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, d) => deviceClient1Telemetry.Add(t)) .ReturnsAsync(true, TimeSpan.FromMilliseconds(sendMessageDelay)); deviceClient1.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync(null, TimeSpan.FromMilliseconds(receiveDelay)); deviceClient1.Setup(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>(), It.IsAny <CancellationToken>())).ReturnsAsync(true); var deviceClient2 = new Mock <ILoRaDeviceClient>(); var deviceClient2Telemetry = new List <LoRaDeviceTelemetry>(); deviceClient2.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(device2Twin, TimeSpan.FromMilliseconds(getTwinDelay)); deviceClient2.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, d) => deviceClient2Telemetry.Add(t)) .ReturnsAsync(true, TimeSpan.FromMilliseconds(sendMessageDelay)); deviceClient2.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync(null, TimeSpan.FromMilliseconds(receiveDelay)); deviceClient2.Setup(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>(), It.IsAny <CancellationToken>())).ReturnsAsync(true); var deviceClient3 = new Mock <ILoRaDeviceClient>(); var deviceClient3Telemetry = new List <LoRaDeviceTelemetry>(); deviceClient3.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(device3Twin, TimeSpan.FromMilliseconds(getTwinDelay)); deviceClient3.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, d) => deviceClient3Telemetry.Add(t)) .ReturnsAsync(true, TimeSpan.FromMilliseconds(sendMessageDelay)); deviceClient3.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync(null, TimeSpan.FromMilliseconds(receiveDelay)); deviceClient3.Setup(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>(), It.IsAny <CancellationToken>())).ReturnsAsync(true); var deviceClient4 = new Mock <ILoRaDeviceClient>(); var deviceClient4Telemetry = new List <LoRaDeviceTelemetry>(); deviceClient4.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(device4Twin, TimeSpan.FromMilliseconds(getTwinDelay)); deviceClient4.Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null)) .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((t, d) => deviceClient4Telemetry.Add(t)) .ReturnsAsync(true, TimeSpan.FromMilliseconds(sendMessageDelay)); deviceClient4.Setup(x => x.ReceiveAsync(It.IsNotNull <TimeSpan>())) .ReturnsAsync(null, TimeSpan.FromMilliseconds(receiveDelay)); deviceClient4.Setup(x => x.UpdateReportedPropertiesAsync(It.IsAny <TwinCollection>(), It.IsAny <CancellationToken>())).ReturnsAsync(true); LoRaDeviceFactory.SetClient(device1.DevEUI, deviceClient1.Object); LoRaDeviceFactory.SetClient(device2.DevEUI, deviceClient2.Object); LoRaDeviceFactory.SetClient(device3.DevEUI, deviceClient3.Object); LoRaDeviceFactory.SetClient(device4.DevEUI, deviceClient4.Object); using var cache = NewMemoryCache(); using var deviceRegistry = new LoRaDeviceRegistry(ServerConfiguration, cache, LoRaDeviceApi.Object, LoRaDeviceFactory, DeviceCache); using var messageDispatcher = new MessageDispatcher( ServerConfiguration, deviceRegistry, FrameCounterUpdateStrategyProvider); var device1Messages = await SendMessages(device1, messageDispatcher, payloadInitialFcnt, delayBetweenMessages, messagePerDeviceCount); var device2Messages = await SendMessages(device2, messageDispatcher, payloadInitialFcnt, delayBetweenMessages, messagePerDeviceCount); var device3Messages = await SendMessages(device3, messageDispatcher, payloadInitialFcnt, delayBetweenMessages, messagePerDeviceCount); var device4Messages = await SendMessages(device4, messageDispatcher, payloadInitialFcnt, delayBetweenMessages, messagePerDeviceCount); var allMessages = device1Messages .Concat(device2Messages) .Concat(device3Messages) .Concat(device4Messages) .ToList(); Assert.Equal(messagePerDeviceCount * 4, allMessages.Count); await Task.WhenAll(allMessages.Select(x => x.WaitCompleteAsync())); Assert.All(allMessages, m => Assert.True(m.ProcessingSucceeded)); var telemetries = new[] { deviceClient1Telemetry, deviceClient2Telemetry, deviceClient3Telemetry, deviceClient4Telemetry }; foreach (var telemetry in telemetries) { Assert.Equal(messagePerDeviceCount, telemetry.Count); for (var i = 0; i < messagePerDeviceCount; ++i) { Assert.Equal(payloadInitialFcnt + i, telemetry[i].Fcnt); } } deviceClient1.VerifyAll(); deviceClient1.Verify(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null), Times.Exactly(messagePerDeviceCount)); deviceClient2.VerifyAll(); deviceClient2.Verify(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null), Times.Exactly(messagePerDeviceCount)); deviceClient3.VerifyAll(); deviceClient3.Verify(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null), Times.Exactly(messagePerDeviceCount)); deviceClient4.VerifyAll(); deviceClient4.Verify(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null), Times.Exactly(messagePerDeviceCount)); LoRaDeviceApi.VerifyAll(); }
public async Task When_Has_Custom_RX2DR_Should_Send_Correctly() { var devAddr = new DevAddr(0x023637F8); var appSKey = TestKeys.CreateAppSessionKey(0xABC0200000000000, 0x09); var nwkSKey = TestKeys.CreateNetworkSessionKey(0xABC0200000000000, 0x09); var simDevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(1, deviceClassType: 'c', gatewayID: ServerGatewayID)); var devEUI = simDevice.DevEUI; simDevice.SetupJoin(appSKey, nwkSKey, devAddr); this.deviceApi.Setup(x => x.GetPrimaryKeyByEuiAsync(devEUI)) .ReturnsAsync("123"); var twin = simDevice.CreateOTAATwin( desiredProperties: new Dictionary <string, object> { { TwinProperty.RX2DataRate, "10" } }, reportedProperties: new Dictionary <string, object> { { TwinProperty.RX2DataRate, 10 }, { TwinProperty.Region, LoRaRegionType.US915.ToString() }, // OTAA device, already joined { TwinProperty.DevAddr, devAddr.ToString() }, { TwinProperty.AppSKey, appSKey.ToString() }, { TwinProperty.NwkSKey, nwkSKey.ToString() }, { TwinProperty.LastProcessingStationEui, new StationEui(ulong.MaxValue).ToString() } }); this.deviceClient.Setup(x => x.GetTwinAsync(CancellationToken.None)) .ReturnsAsync(twin); var c2dToDeviceMessage = new ReceivedLoRaCloudToDeviceMessage() { Payload = "hello", DevEUI = devEUI, Fport = TestPort, MessageId = Guid.NewGuid().ToString(), }; DownlinkMessage receivedDownlinkMessage = null; this.downstreamMessageSender.Setup(x => x.SendDownstreamAsync(It.IsNotNull <DownlinkMessage>())) .Returns(Task.CompletedTask) .Callback <DownlinkMessage>(d => receivedDownlinkMessage = d); var target = new DefaultClassCDevicesMessageSender( this.serverConfiguration, this.loRaDeviceRegistry, this.downstreamMessageSender.Object, this.frameCounterStrategyProvider, NullLogger <DefaultClassCDevicesMessageSender> .Instance, TestMeter.Instance); Assert.True(await target.SendAsync(c2dToDeviceMessage)); this.downstreamMessageSender.Verify(x => x.SendDownstreamAsync(It.IsNotNull <DownlinkMessage>()), Times.Once()); EnsureDownlinkIsCorrect(receivedDownlinkMessage, simDevice, c2dToDeviceMessage); Assert.Equal(DataRateIndex.DR10, receivedDownlinkMessage.Rx2.DataRate); Assert.Equal(Hertz.Mega(923.3), receivedDownlinkMessage.Rx2.Frequency); this.downstreamMessageSender.VerifyAll(); this.deviceApi.VerifyAll(); this.deviceClient.VerifyAll(); }