From 86af253df7e5f28a96494dfec89a093ff15c5971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 24 Oct 2023 10:55:50 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9A=D1=8D=D1=88=20=D1=82=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Небольшой рефакторинг 2. Покрытие кода тестами --- .../Services/SAUB/TelemetryDataCache.cs | 79 ++++++++++--------- .../AsbCloudWebApi.Tests.csproj | 1 + .../SAUB/TelemetryDataSaubCacheTests.cs | 69 ++++++++++++++++ 3 files changed, 111 insertions(+), 38 deletions(-) create mode 100644 AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index b579c876..dd602a1a 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -6,7 +6,6 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Mapster; using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using AsbCloudInfrastructure.Background; using System.Threading; @@ -24,8 +23,7 @@ namespace AsbCloudInfrastructure.Services.SAUB public CyclycArray LastData { get; init; } = null!; public double TimezoneHours { get; init; } = 5; } - - private IServiceProvider provider = null!; + private const int activeWellCapacity = 12 * 60 * 60; private const int doneWellCapacity = 65 * 60; @@ -40,6 +38,8 @@ namespace AsbCloudInfrastructure.Services.SAUB private static TelemetryDataCache? instance; + public int CacheItemCount => caches.Count; + public static TelemetryDataCache GetInstance(IServiceProvider provider) where TEntity : class, AsbCloudDb.Model.ITelemetryData { @@ -55,7 +55,6 @@ namespace AsbCloudInfrastructure.Services.SAUB work.Timeout = TimeSpan.FromMinutes(15); worker.WorkStore.RunOnceQueue.Enqueue(work); } - instance.provider = provider; return instance; } @@ -69,10 +68,9 @@ namespace AsbCloudInfrastructure.Services.SAUB if (!range.Any()) return; - var newItems = range - .OrderBy(i => i.DateTime); + range = range.OrderBy(x => x.DateTime); - foreach (var item in newItems) + foreach (var item in range) item.IdTelemetry = idTelemetry; TelemetryDataCacheItem cacheItem; @@ -87,12 +85,12 @@ namespace AsbCloudInfrastructure.Services.SAUB { cacheItem = caches.GetOrAdd(idTelemetry, _ => new TelemetryDataCacheItem() { - FirstByDate = newItems.ElementAt(0), + FirstByDate = range.ElementAt(0), LastData = new CyclycArray(activeWellCapacity) }); } - cacheItem.LastData.AddRange(newItems); + cacheItem.LastData.AddRange(range); } /// @@ -153,39 +151,44 @@ namespace AsbCloudInfrastructure.Services.SAUB private async Task InitializeCacheFromDBAsync(IAsbCloudDbContext db, Action onProgress, CancellationToken token) where TEntity : class, AsbCloudDb.Model.ITelemetryData { - if (isLoading) - throw new Exception("Multiple cache loading detected."); - - isLoading = true; - - var defaultTimeout = db.Database.GetCommandTimeout(); - db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); - - Well[] wells = await db.Set() - .Include(well => well.Telemetry) - .Include(well => well.Cluster) - .Where(well => well.IdTelemetry != null) - .ToArrayAsync(token); - - var count = wells.Length; - var i = 0d; - foreach (Well well in wells) + try { - var capacity = well.IdState == 1 - ? activeWellCapacity - : doneWellCapacity; + if (isLoading) + throw new Exception("Multiple cache loading detected."); - var idTelemetry = well.IdTelemetry!.Value; - var hoursOffset = well.Timezone.Hours; + isLoading = true; + + db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5)); + + Well[] wells = await db.Set() + .Include(well => well.Telemetry) + .Include(well => well.Cluster) + .Where(well => well.IdTelemetry != null) + .ToArrayAsync(token); + + var count = wells.Length; + var i = 0d; + foreach (Well well in wells) + { + var capacity = well.IdState == 1 + ? activeWellCapacity + : doneWellCapacity; + + var idTelemetry = well.IdTelemetry!.Value; + var hoursOffset = well.Timezone.Hours; - onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count); - var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); - if(cacheItem is not null) - caches.TryAdd(idTelemetry, cacheItem); + onProgress($"Loading for well: {well.Cluster?.Caption}/{well.Caption} (capacity:{capacity}) idTelemetry:{idTelemetry}", i++/count); + var cacheItem = await GetOrDefaultCacheDataFromDbAsync(db, idTelemetry, capacity, hoursOffset, token); + if(cacheItem is not null) + caches.TryAdd(idTelemetry, cacheItem); + } + } + finally + { + isLoading = false; + var defaultTimeout = db.Database.GetCommandTimeout(); + db.Database.SetCommandTimeout(defaultTimeout); } - - isLoading = false; - db.Database.SetCommandTimeout(defaultTimeout); } private static async Task GetOrDefaultCacheDataFromDbAsync(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset, CancellationToken token) diff --git a/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj b/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj index 4cf2783e..4024a917 100644 --- a/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj +++ b/AsbCloudWebApi.Tests/AsbCloudWebApi.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs b/AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs new file mode 100644 index 00000000..a5e9f12a --- /dev/null +++ b/AsbCloudWebApi.Tests/ServicesTests/SAUB/TelemetryDataSaubCacheTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using AsbCloudApp.Data.SAUB; +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Background; +using AsbCloudInfrastructure.Services.SAUB; +using Bogus; +using Microsoft.Extensions.DependencyInjection; +using NSubstitute; +using Xunit; + +namespace AsbCloudWebApi.Tests.ServicesTests.SAUB; + +public class TelemetryDataSaubCacheTests +{ + private readonly IEnumerable fakeTelemetries = new Faker() + .RuleFor(t => t.DateTime, DateTime.UtcNow) + .Generate(5) + .OrderBy(t => t.DateTime); + + private readonly IServiceProvider serviceProvider = Substitute.For(); + + private readonly TelemetryDataCache telemetryDataCache; + + public TelemetryDataSaubCacheTests() + { + serviceProvider.GetService().Returns(new BackgroundWorker(serviceProvider)); + + telemetryDataCache = TelemetryDataCache.GetInstance(serviceProvider); + } + + [Fact] + public void AddRange_ShouldReturn_OneAddedElementToCache() + { + //arrange + const int expectedCacheItemCount = 1; + + var idTelemetry = new Random().Next(1, 100); + var telemetryDataCacheType = telemetryDataCache.GetType(); + + telemetryDataCacheType.GetField("isLoading", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(telemetryDataCache, false); + + //act + telemetryDataCache.AddRange(idTelemetry, fakeTelemetries); + + //assert + Assert.True(telemetryDataCache.CacheItemCount == expectedCacheItemCount); + } + + [Fact] + public void AddRange_ShouldReturn_ZeroAddedElementToCache() + { + //arrange + const int expectedCacheItemCount = 0; + + var idTelemetry = new Random().Next(1, 100); + var telemetryDataCacheType = telemetryDataCache.GetType(); + + telemetryDataCacheType.GetField("isLoading", BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(telemetryDataCache, true); + + //act + telemetryDataCache.AddRange(idTelemetry, fakeTelemetries); + + //assert + Assert.True(telemetryDataCache.CacheItemCount == expectedCacheItemCount); + } +} \ No newline at end of file