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());
        }
예제 #4
0
        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();
        }
예제 #5
0
        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();
        }
예제 #7
0
        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();
        }
예제 #10
0
        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();
        }
예제 #12
0
        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();
        }
예제 #13
0
        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();
        }
예제 #16
0
        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();
        }
예제 #17
0
        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();
        }
예제 #18
0
        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();
        }
예제 #19
0
        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();
        }