Пример #1
0
        public async Task Validate_Dup_Message_Processing(DeduplicationMode mode)
        {
            var  simulatedDevice  = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1));
            bool messageProcessed = mode == DeduplicationMode.Drop;

            messageProcessed = false;

            this.LoRaDeviceApi.Setup(x => x.ExecuteFunctionBundlerAsync(simulatedDevice.DevEUI, It.IsNotNull <FunctionBundlerRequest>()))
            .Returns <string, FunctionBundlerRequest>((dev, req) =>
            {
                var isDup        = messageProcessed;
                messageProcessed = true;
                return(Task.FromResult <FunctionBundlerResult>(new FunctionBundlerResult()
                {
                    DeduplicationResult = new DeduplicationResult
                    {
                        IsDuplicate = isDup
                    }
                }));
            });

            this.LoRaDeviceApi
            .Setup(x => x.NextFCntDownAsync(It.IsAny <string>(), It.IsAny <uint>(), It.IsAny <uint>(), It.IsAny <string>()))
            .ReturnsAsync((uint)(simulatedDevice.FrmCntDown + 1))
            .Callback(() =>
            {
                // this call should only be made, if we do not have a deduplication strategy
                // since otherwise we expect the fcntDown to be calculated in the same API call as deduplication
                Assert.True(mode == DeduplicationMode.None);
            });

            this.LoRaDeviceApi.Setup(x => x.ABPFcntCacheResetAsync(It.IsNotNull <string>(), It.IsAny <uint>(), It.IsNotNull <string>()))
            .ReturnsAsync(true);

            var shouldBeMarked = false;

            this.LoRaDeviceClient
            .Setup(x => x.SendEventAsync(It.IsNotNull <LoRaDeviceTelemetry>(), null))
            .ReturnsAsync(true)
            .Callback <LoRaDeviceTelemetry, Dictionary <string, string> >((telemetry, dict) =>
            {
                if (shouldBeMarked)
                {
                    Assert.True(telemetry.DupMsg);
                }
                else
                {
                    Assert.Null(telemetry.DupMsg);
                }

                shouldBeMarked = mode == DeduplicationMode.Mark;
            });

            this.LoRaDeviceClient
            .Setup(x => x.ReceiveAsync(It.IsAny <TimeSpan>()))
            .ReturnsAsync((Message)null);

            await this.SendTwoMessages(mode);
        }
Пример #2
0
        private async Task SendTwoMessages(DeduplicationMode mode)
        {
            var simulatedDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(1));

            var loRaDevice = this.CreateLoRaDevice(simulatedDevice);

            loRaDevice.Deduplication = mode;

            var loRaDeviceRegistry1 = new LoRaDeviceRegistry(this.ServerConfiguration, this.NewNonEmptyCache(loRaDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory);
            var loRaDeviceRegistry2 = new LoRaDeviceRegistry(this.SecondServerConfiguration, this.NewNonEmptyCache(loRaDevice), this.LoRaDeviceApi.Object, this.LoRaDeviceFactory);

            var messageProcessor1 = new MessageDispatcher(
                this.ServerConfiguration,
                loRaDeviceRegistry1,
                this.FrameCounterUpdateStrategyProvider);

            var messageProcessor2 = new MessageDispatcher(
                this.SecondServerConfiguration,
                loRaDeviceRegistry2,
                this.SecondFrameCounterUpdateStrategyProvider);

            var payload = simulatedDevice.CreateUnconfirmedDataUpMessage("1234", fcnt: 1);

            // Create Rxpk
            var rxpk = payload.SerializeUplink(simulatedDevice.AppSKey, simulatedDevice.NwkSKey).Rxpk[0];

            var request1 = this.CreateWaitableRequest(rxpk);
            var request2 = this.CreateWaitableRequest(rxpk);

            messageProcessor1.DispatchRequest(request1);

            _ = Task.Run(() =>
            {
                messageProcessor2.DispatchRequest(request2);
            });

            await Task.WhenAll(request1.WaitCompleteAsync(Timeout.Infinite), request2.WaitCompleteAsync(Timeout.Infinite));

            switch (mode)
            {
            case DeduplicationMode.Drop:
                Assert.True(request1.ProcessingSucceeded);
                Assert.True(request2.ProcessingFailed);
                Assert.Equal <LoRaDeviceRequestFailedReason>(LoRaDeviceRequestFailedReason.DeduplicationDrop, request2.ProcessingFailedReason);
                break;

            case DeduplicationMode.Mark:
                Assert.True(request1.ProcessingSucceeded);
                Assert.True(request2.ProcessingSucceeded);
                break;

            case DeduplicationMode.None:
                break;
            }
        }
 public DeduplicationTestDataAttribute(string station1,
                                       string station2,
                                       DeduplicationMode deduplicationMode,
                                       int expectedFrameCounterResets,
                                       int expectedBundlerCalls,
                                       int expectedFrameCounterDownCalls,
                                       int expectedMessagesUp,
                                       int expectedMessagesDown,
                                       int expectedTwinSaves)
 {
     this.args = new object[] { station1, station2, deduplicationMode, expectedFrameCounterResets, expectedBundlerCalls, expectedFrameCounterDownCalls, expectedMessagesUp, expectedMessagesDown, expectedTwinSaves };
 }
        public async Task When_Different_Strategies_Are_Used_Ensures_Correct_Upstream_And_Downstream_Processing(DeduplicationMode mode, bool confirmedMessages)
        {
            var messageProcessed = false;
            var counterFctnDown  = 0;

            foreach (var api in new[] { LoRaDeviceApi, SecondLoRaDeviceApi })
            {
                api.Setup(x => x.ExecuteFunctionBundlerAsync(this.simulatedDevice.DevEUI, It.IsNotNull <FunctionBundlerRequest>()))
                .ReturnsAsync((DevEui _, FunctionBundlerRequest _) =>
                {
                    if (mode != DeduplicationMode.None)
                    {
                        lock (this.functionLock)
                        {
                            var isDup        = messageProcessed;
                            messageProcessed = true;
                            return(new FunctionBundlerResult()
                            {
                                DeduplicationResult = new DeduplicationResult {
                                    IsDuplicate = isDup
                                }
                            });
                        }
                    }

                    // when DeduplicationMode is None, the Bundler deduplication is not invoked
                    return(new FunctionBundlerResult());
                });

                if (confirmedMessages)
                {
                    api.Setup(x => x.NextFCntDownAsync(It.IsAny <DevEui>(), It.IsAny <uint>(), It.IsAny <uint>(), It.IsAny <string>()))
                    .ReturnsAsync(() =>
                    {
                        lock (this.functionLock)
                        {
                            counterFctnDown++;
                            return(counterFctnDown switch
                            {
                                1 => this.simulatedDevice.FrmCntDown + 1,    // the first time the message is encountered, it gets a valid frame counter down
                                _ => 0                                       // any other time, it does not
                            });
                        }
                    });
        public void When_Data_Message_Encountered_Should_Find_Duplicates_For_Different_Deduplication_Strategies(string station1, string station2, DeduplicationMode deduplicationMode, ConcentratorDeduplicationResult expectedResult)
        {
            // arrange
            var station1Eui = StationEui.Parse(station1);

            this.dataRequest.SetStationEui(station1Eui);
            _ = this.concentratorDeduplication.CheckDuplicateData(this.dataRequest, this.loRaDevice);

            this.dataRequest.SetStationEui(StationEui.Parse(station2));
            this.loRaDevice.Deduplication = deduplicationMode;

            // act/assert
            Assert.Equal(expectedResult, this.concentratorDeduplication.CheckDuplicateData(this.dataRequest, this.loRaDevice));
            Assert.Equal(1, this.cache.Count);
            var key = ConcentratorDeduplication.CreateCacheKey(this.dataPayload, this.loRaDevice);

            Assert.True(this.cache.TryGetValue(key, out var foundStation));
            Assert.Equal(station1Eui, foundStation);
        }
 public Task <Validation> SubmitAsync(IEnumerable <ValidationRequestEntry> entries, QualityLevelName quality = default, DeduplicationMode deduplication = default, WaitingStrategy waitingStrategy = default, CancellationToken cancellationToken = default)
 {
     return(SubmitAsync(new ValidationRequest(entries, quality, deduplication),
                        waitingStrategy: waitingStrategy,
                        cancellationToken: cancellationToken));
 }
        public Task <Validation> SubmitAsync(IEnumerable <string> emailAddresses, QualityLevelName quality = default, DeduplicationMode deduplication = default, WaitingStrategy waitingStrategy = default, CancellationToken cancellationToken = default)
        {
            if (emailAddresses == null)
            {
                throw new ArgumentNullException(nameof(emailAddresses));
            }

            return(SubmitAsync(emailAddresses.Select(emailAddress => new ValidationRequestEntry(emailAddress)),
                               quality: quality,
                               deduplication: deduplication,
                               waitingStrategy: waitingStrategy,
                               cancellationToken: cancellationToken));
        }
        public async Task <Validation> SubmitAsync(Stream file, MediaTypeHeaderValue contentType, QualityLevelName quality = default, DeduplicationMode deduplication = default, WaitingStrategy waitingStrategy = default, CancellationToken cancellationToken = default)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }
            if (contentType == null)
            {
                throw new ArgumentNullException(nameof(contentType));
            }

            using var request = new FileValidationRequest(file, contentType, quality, deduplication, leaveOpen: true);

            return(await SubmitAsync(request,
                                     waitingStrategy,
                                     cancellationToken)
                   .ConfigureAwait(false));
        }
        public async Task <Validation> SubmitAsync(byte[] file, MediaTypeHeaderValue contentType, QualityLevelName quality = default, DeduplicationMode deduplication = default, WaitingStrategy waitingStrategy = default, CancellationToken cancellationToken = default)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            using var stream = new MemoryStream(file);
            return(await SubmitAsync(stream,
                                     contentType,
                                     quality,
                                     deduplication,
                                     waitingStrategy,
                                     cancellationToken)
                   .ConfigureAwait(false));
        }