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); }
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)); }