diff --git a/AsbCloudApp/CyclycArray.cs b/AsbCloudApp/CyclycArray.cs index 4a479f66..472957f1 100644 --- a/AsbCloudApp/CyclycArray.cs +++ b/AsbCloudApp/CyclycArray.cs @@ -90,12 +90,16 @@ namespace System.Collections.Generic { get { + if (used == 0) + return default; + var i = (current + 1 + index) % used; return array[i]; } set { - var i = (current + 1 + index) % used; + var devider = used > 0 ? used : array.Length; + var i = (current + 1 + index) % devider; array[i] = value; UpdatedInvoke(current, value); } diff --git a/AsbCloudApp/Services/ITelemetryDataService.cs b/AsbCloudApp/Services/ITelemetryDataService.cs index 6b0020ba..8efc74ae 100644 --- a/AsbCloudApp/Services/ITelemetryDataService.cs +++ b/AsbCloudApp/Services/ITelemetryDataService.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; - +#nullable enable namespace AsbCloudApp.Services { /// @@ -22,7 +22,7 @@ namespace AsbCloudApp.Services /// кол-во элементов до которых эти данные прореживаются /// /// - Task> GetAsync(int idWell, + Task?> GetOrDefaultAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default); @@ -35,4 +35,5 @@ namespace AsbCloudApp.Services /// Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default); } -} \ No newline at end of file +} +#nullable disable \ No newline at end of file diff --git a/AsbCloudApp/Services/ITelemetryService.cs b/AsbCloudApp/Services/ITelemetryService.cs index c4e50b35..62b8f8e1 100644 --- a/AsbCloudApp/Services/ITelemetryService.cs +++ b/AsbCloudApp/Services/ITelemetryService.cs @@ -55,7 +55,7 @@ namespace AsbCloudApp.Services /// /// /// - int? GetIdTelemetryByIdWell(int idWell); + int? GetOrDefaultIdTelemetryByIdWell(int idWell); /// /// получить диапазон дат за которые есть данные diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index a9e521ca..0b9c0bc6 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -16,6 +16,7 @@ using AsbCloudInfrastructure.Services.SAUB; using AsbCloudInfrastructure.Services.Subsystems; using AsbCloudInfrastructure.Services.WellOperationService; using AsbCloudInfrastructure.Validators; +using DocumentFormat.OpenXml.Spreadsheet; using FluentValidation.AspNetCore; using Mapster; using Microsoft.EntityFrameworkCore; @@ -100,6 +101,8 @@ namespace AsbCloudInfrastructure services.AddSingleton(new WitsInfoService()); services.AddSingleton(new CacheDb()); services.AddSingleton(new InstantDataRepository()); + services.AddSingleton(provider=> TelemetryDataCache.GetInstance(configuration)); + services.AddSingleton(provider=> TelemetryDataCache.GetInstance(configuration)); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/AsbCloudInfrastructure/Services/DrillParamsService.cs b/AsbCloudInfrastructure/Services/DrillParamsService.cs index 95528330..a2ac61c6 100644 --- a/AsbCloudInfrastructure/Services/DrillParamsService.cs +++ b/AsbCloudInfrastructure/Services/DrillParamsService.cs @@ -27,7 +27,7 @@ namespace AsbCloudInfrastructure.Services public async Task GetDefaultDrillParamsAsync(int idWell, double startDepth, double endDepth, CancellationToken token = default) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return null; diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs index 7d60f852..7143e063 100644 --- a/AsbCloudInfrastructure/Services/ReportService.cs +++ b/AsbCloudInfrastructure/Services/ReportService.cs @@ -113,7 +113,7 @@ namespace AsbCloudInfrastructure.Services public DatesRangeDto GetDatesRangeOrDefault(int idWell) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return null; var range = telemetryService.GetDatesRange((int)idTelemetry); diff --git a/AsbCloudInfrastructure/Services/SAUB/MessageService.cs b/AsbCloudInfrastructure/Services/SAUB/MessageService.cs index 541003e5..1911029a 100644 --- a/AsbCloudInfrastructure/Services/SAUB/MessageService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/MessageService.cs @@ -34,7 +34,7 @@ namespace AsbCloudInfrastructure.Services.SAUB int take = 32, CancellationToken token = default) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return null; diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index cee2cae8..e918025a 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -10,26 +10,31 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +#nullable enable namespace AsbCloudInfrastructure.Services.SAUB { - public abstract class TelemetryDataBaseService : ITelemetryDataService + public abstract class TelemetryDataBaseService : ITelemetryDataService where TDto : AsbCloudApp.Data.ITelemetryData - where TModel : class, ITelemetryData + where TEntity : class, ITelemetryData { protected readonly IAsbCloudDbContext db; private readonly ITelemetryService telemetryService; protected readonly CacheTable cacheTelemetryUsers; + private readonly TelemetryDataCache telemetryDataCache; public TelemetryDataBaseService( IAsbCloudDbContext db, ITelemetryService telemetryService, + TelemetryDataCache telemetryDataCache, CacheDb cacheDb) { this.db = db; this.telemetryService = telemetryService; cacheTelemetryUsers = cacheDb.GetCachedTable((AsbCloudDbContext)db); + this.telemetryDataCache = telemetryDataCache; } + /// public virtual async Task UpdateDataAsync(string uid, IEnumerable dtos, CancellationToken token = default) { if (dtos == default || !dtos.Any()) @@ -53,6 +58,8 @@ namespace AsbCloudInfrastructure.Services.SAUB var idTelemetry = telemetryService.GetOrCreateTelemetryIdByUid(uid); var timezone = telemetryService.GetTimezone(idTelemetry); + telemetryDataCache.AddRange(idTelemetry, dtos); + var entities = dtosList.Select(dto => { var entity = Convert(dto, timezone.Hours); @@ -63,7 +70,7 @@ namespace AsbCloudInfrastructure.Services.SAUB var entityMaxDate = entities.Max(e => e.DateTime); telemetryService.TelemetryTracker.SaveRequestDate(uid, entityMaxDate); - var dbset = db.Set(); + var dbset = db.Set(); var stopwatch = Stopwatch.StartNew(); try { @@ -82,12 +89,15 @@ namespace AsbCloudInfrastructure.Services.SAUB return 0; } } + + + // TODO: It shouldn`t be nullable. Throw exceptions instead and return empty. /// - public virtual async Task> GetAsync(int idWell, + public virtual async Task?> GetOrDefaultAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell) ?? -1; + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell) ?? -1; if (idTelemetry == -1) return null; @@ -110,8 +120,12 @@ namespace AsbCloudInfrastructure.Services.SAUB if (dateBeginUtc == default) dateBeginUtc = DateTime.UtcNow.AddSeconds(-intervalSec); + var cacheData = telemetryDataCache.GetOrDefault(idTelemetry, dateBeginUtc.ToRemoteDateTime(timezone.Hours), intervalSec, approxPointsCount); + if (cacheData is not null) + return cacheData; + var dateEnd = dateBeginUtc.AddSeconds(intervalSec); - var dbSet = db.Set(); + var dbSet = db.Set(); var query = dbSet .Where(d => d.IdTelemetry == idTelemetry @@ -144,9 +158,10 @@ namespace AsbCloudInfrastructure.Services.SAUB return dtos; } - public abstract TDto Convert(TModel src, double timezoneOffset); + public abstract TDto Convert(TEntity src, double timezoneOffset); - public abstract TModel Convert(TDto src, double timezoneOffset); + public abstract TEntity Convert(TDto src, double timezoneOffset); } } +#nullable disable \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 1caa0102..81362ca6 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -5,74 +5,79 @@ using System; using System.Linq; using Microsoft.EntityFrameworkCore; using Mapster; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; #nullable enable namespace AsbCloudInfrastructure.Services.SAUB { - public class TelemetryDataCache + public class TelemetryDataCache where TDto : AsbCloudApp.Data.ITelemetryData - where TEntity : class, ITelemetryData { private const int activeWellCapacity = 24 * 60 * 60; private const int doneWellCapacity = 65 * 60; private readonly ConcurrentDictionary> caches; - - public TelemetryDataCache(IAsbCloudDbContext db) + private bool isLoading = false; + + private TelemetryDataCache() { - caches = new (); - LoadCaches(db); + caches = new(); } - private void LoadCaches(IAsbCloudDbContext db) - { - Well[] wells = db.Set() - .Include(well => well.Telemetry) - .Where(well => well.IdTelemetry != null) - .ToArray(); + private static TelemetryDataCache? instance; - foreach (Well well in wells) + //TODO: Move initialize fromDB to bacground service task + public static TelemetryDataCache GetInstance(IConfiguration configuration) + where TEntity : class, ITelemetryData + { + if (instance is null) { - var capacity = well.IdState == 1 - ? activeWellCapacity - : doneWellCapacity; - - var idTelemetry = well.IdTelemetry!.Value; - var hoursOffset = well.Timezone.Hours; - - IEnumerable cacheItemData = GetCacheDataFromDb(db, idTelemetry, capacity, hoursOffset); - var cacheItem = new CyclycArray(capacity); - cacheItem.AddRange(cacheItemData); - caches.TryAdd(idTelemetry, cacheItem); + instance = new TelemetryDataCache(); + _ = Task.Run(() => + { + using var db = MakeContext(configuration); + instance.InitializeCacheFromDB(db); + }); } + return instance; } - - private static IEnumerable GetCacheDataFromDb(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset) + public static TelemetryDataCache GetInstance(IAsbCloudDbContext db, out Task initializationTask) + where TEntity : class, ITelemetryData { - var entities = db.Set() - .Where(i => i.IdTelemetry == idTelemetry) - .OrderByDescending(i => i.DateTime) - .Take(capacity) - .ToArray() - .OrderBy(i => i.DateTime); - - var dtos = entities.Select(entity => { - var dto = entity.Adapt(); - dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); - return dto; - }); - - return dtos; + if (instance is null) + { + instance = new TelemetryDataCache(); + initializationTask = Task.Run(() => + { + instance.InitializeCacheFromDB(db); + }); + } + else + initializationTask = Task.CompletedTask; + return instance; } /// - /// Добавить элементы в кеш + /// Добавить новые элементы в кеш /// /// /// - public void AddRange(int idTelemetry, IEnumerable range) + public void AddRange(int idTelemetry, IEnumerable range) { - var cacheItem = caches.GetOrAdd(idTelemetry, _ => new CyclycArray(activeWellCapacity)); + CyclycArray cacheItem; + if (isLoading) + { + if (caches.TryGetValue(idTelemetry, out CyclycArray? localCacheItem)) + cacheItem = localCacheItem; + else + return; + } + else + { + cacheItem = caches.GetOrAdd(idTelemetry, _ => new CyclycArray(activeWellCapacity)); + } + var newItems = range .OrderBy(i => i.DateTime); foreach (var item in newItems) @@ -95,7 +100,7 @@ namespace AsbCloudInfrastructure.Services.SAUB if(!caches.TryGetValue(idTelemetry, out CyclycArray? cacheItem)) return null; - if (cacheItem is null || cacheItem[0].DateTime > dateBegin) + if (cacheItem is null || !cacheItem.Any() || cacheItem[0].DateTime > dateBegin) return null; var dateEnd = dateBegin.AddSeconds(intervalSec); @@ -109,6 +114,77 @@ namespace AsbCloudInfrastructure.Services.SAUB return items; } + + private void InitializeCacheFromDB(IAsbCloudDbContext db) + where TEntity : class, ITelemetryData + { + if (isLoading) + throw new Exception("Multiple cache loading detected."); + + isLoading = true; + Well[] wells = Array.Empty(); + try + { + wells = db.Set() + .Include(well => well.Telemetry) + .Include(well => well.Cluster) + .Where(well => well.IdTelemetry != null) + .ToArray(); + } + catch(Exception ex) + { + ; + } + foreach (Well well in wells) + { + var capacity = well.IdState == 1 + ? activeWellCapacity + : doneWellCapacity; + + var idTelemetry = well.IdTelemetry!.Value; + var hoursOffset = well.Timezone.Hours; + + IEnumerable cacheItemData = GetCacheDataFromDb(db, idTelemetry, capacity, hoursOffset); + var cacheItem = new CyclycArray(capacity); + cacheItem.AddRange(cacheItemData); + caches.TryAdd(idTelemetry, cacheItem); + + System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}> for well: {well.Cluster?.Caption}/{well.Caption} loaded"); + } + + System.Diagnostics.Trace.TraceInformation($"cache<{typeof(TDto).Name}> load complete"); + isLoading = false; + } + + private static IAsbCloudDbContext MakeContext(IConfiguration configuration) + { + var connectionString = configuration.GetConnectionString("DefaultConnection"); + var options = new DbContextOptionsBuilder() + .UseNpgsql(connectionString) + .Options; + var db = new AsbCloudDbContext(options); + return db; + } + + private static IEnumerable GetCacheDataFromDb(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset) + where TEntity : class, ITelemetryData + { + var entities = db.Set() + .Where(i => i.IdTelemetry == idTelemetry) + .OrderByDescending(i => i.DateTime) + .Take(capacity) + .ToArray() + .AsEnumerable() + .Reverse(); + + var dtos = entities.Select(entity => { + var dto = entity.Adapt(); + dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); + return dto; + }); + + return dtos; + } } } #nullable disable \ No newline at end of file diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 419c5831..10a13913 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -16,8 +16,9 @@ namespace AsbCloudInfrastructure.Services.SAUB public TelemetryDataSaubService( IAsbCloudDbContext db, ITelemetryService telemetryService, + TelemetryDataCache telemetryDataCache, CacheDb cacheDb) - : base(db, telemetryService, cacheDb) + : base(db, telemetryService, telemetryDataCache, cacheDb) { } public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset) diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs index 5cd51161..14e84955 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSpinService.cs @@ -13,8 +13,9 @@ namespace AsbCloudInfrastructure.Services.SAUB public TelemetryDataSpinService( IAsbCloudDbContext db, ITelemetryService telemetryService, + TelemetryDataCache telemetryDataCache, CacheDb cacheDb) - : base(db, telemetryService, cacheDb) + : base(db, telemetryService, telemetryDataCache, cacheDb) { } public override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset) diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs index 21390596..c1b35fdb 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryService.cs @@ -141,7 +141,7 @@ namespace AsbCloudInfrastructure.Services.SAUB throw new Exception($"Telemetry id: {idTelemetry} can't find timezone."); } - public int? GetIdTelemetryByIdWell(int idWell) + public int? GetOrDefaultIdTelemetryByIdWell(int idWell) { var telemetry = GetTelemetryCache() .FirstOrDefault(t => t.Value.Well?.Id == idWell).Value; diff --git a/AsbCloudWebApi.Tests/CacheTests/TelemetryDataCacheTest.cs b/AsbCloudWebApi.Tests/CacheTests/TelemetryDataCacheTest.cs new file mode 100644 index 00000000..5ae1d78c --- /dev/null +++ b/AsbCloudWebApi.Tests/CacheTests/TelemetryDataCacheTest.cs @@ -0,0 +1,93 @@ +using AsbCloudDb.Model; +using AsbCloudInfrastructure.Services.SAUB; +using Moq; +using System; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace AsbCloudWebApi.Tests.CacheTests +{ + public class TelemetryDataCacheTest + { + private const int IdTelemetryOk = 10; + private static readonly DateTime baseDate = DateTime.Now; + private static readonly SimpleTimezone timezone = new() { Hours = TimeZoneInfo.Local.BaseUtcOffset.TotalHours }; + + private static readonly Well[] wellData = new Well[]{ + new(){ Id = 1, IdTelemetry = IdTelemetryOk, IdState = 1, Caption = "", Timezone = timezone} + }; + private static readonly TTelemetryData[] telemetryData = new TTelemetryData[]{ + new ( IdTelemetryOk, baseDate.AddSeconds(1), timezone.Hours ), + new ( IdTelemetryOk, baseDate.AddSeconds(2), timezone.Hours ), + new ( IdTelemetryOk, baseDate.AddSeconds(3), timezone.Hours ), + new ( IdTelemetryOk, baseDate.AddSeconds(4), timezone.Hours ), + }; + private readonly Mock dbMock; + + private TelemetryDataCache cacheTest; + + public class TTelemetryData : ITelemetryData, AsbCloudApp.Data.ITelemetryData + { + private DateTimeOffset _dateTime; + + public TTelemetryData(int idTelemetry, DateTime dateTime, double hoursOffset) + { + IdTelemetry = idTelemetry; + DateTime = dateTime; + var offset = TimeSpan.FromHours(hoursOffset); + var dateTimeUTC = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified); + _dateTime = new DateTimeOffset(dateTimeUTC, offset) + .ToUniversalTime(); + } + + public int IdTelemetry { get; set; } + public DateTime DateTime { get; set; } + DateTimeOffset ITelemetryData.DateTime { get => _dateTime; set => _dateTime = value; } + } + + public TelemetryDataCacheTest() + { + dbMock = new Mock(); + dbMock + .AddDbSetMock(wellData) + .AddDbSetMock(telemetryData); + + cacheTest = TelemetryDataCache.GetInstance(dbMock.Object, out Task cacheInitialization); + cacheInitialization.Wait(); + } + + [Fact] + public void Get_existing_cache_returns_some() + { + var startDate = baseDate.AddSeconds(3); + var data = cacheTest.GetOrDefault(IdTelemetryOk, startDate, 600, 600); + Assert.NotNull(data); + Assert.NotEmpty(data); + } + + [Fact] + public void Get_non_existing_cache_returns_null() + { + var startDate = baseDate.AddSeconds(-1); + var data = cacheTest.GetOrDefault(IdTelemetryOk, startDate, 600, 600); + Assert.Null(data); + } + + [Fact] + public void Add_new_data_should_replace_IdTelemetry() + { + var startDate = baseDate.AddSeconds(4); + var newTelemetryData = new TTelemetryData[]{ + new ( 0, startDate, timezone.Hours), + new ( 0, startDate.AddSeconds(1), timezone.Hours), + }; + cacheTest.AddRange(IdTelemetryOk, newTelemetryData); + var data = cacheTest.GetOrDefault(IdTelemetryOk, startDate, 600, 600); + + Assert.NotNull(data); + Assert.True(data?.Count() > 2); + Assert.All(data!, p => Assert.Equal(IdTelemetryOk, p.IdTelemetry)); + } + } +} diff --git a/AsbCloudWebApi.Tests/ServicesTests/ClusterServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/ClusterServiceTest.cs index 6ee6ec44..44e7b481 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/ClusterServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/ClusterServiceTest.cs @@ -69,7 +69,7 @@ public class ClusterServiceTest public ClusterServiceTest() { - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); wellService = new Mock(); context.Deposits.RemoveRange(context.Deposits); context.Clusters.RemoveRange(context.Clusters); diff --git a/AsbCloudWebApi.Tests/ServicesTests/DepositCrudCacheServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/DepositCrudCacheServiceTest.cs index 790a806a..91664385 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/DepositCrudCacheServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/DepositCrudCacheServiceTest.cs @@ -21,7 +21,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests protected override ICrudService MakeService() { - var dbContext = TestHelpter.MakeTestContext(); + var dbContext = TestHelpter.MakeRealTestContext(); return new CrudCacheServiceBase(dbContext); } } diff --git a/AsbCloudWebApi.Tests/ServicesTests/DetectedOperationServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/DetectedOperationServiceTest.cs index 014680e1..f341a15a 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/DetectedOperationServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/DetectedOperationServiceTest.cs @@ -107,7 +107,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests public DetectedOperationServiceTest() { - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); context.SaveChanges(); context.Telemetries.Add(telemetry); diff --git a/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs index 2c829eb4..e823189b 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/DrillingProgramServiceTest.cs @@ -90,7 +90,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests { AsbCloudInfrastructure.DependencyInjection.MapsterSetup(); - db = TestHelpter.MakeTestContext(); + db = TestHelpter.MakeRealTestContext(); db.Wells.AddRange(wells); db.Companies.AddRange(companies); db.SaveChanges(); diff --git a/AsbCloudWebApi.Tests/ServicesTests/EventServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/EventServiceTest.cs index dc8b9acf..0c406f1e 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/EventServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/EventServiceTest.cs @@ -19,7 +19,7 @@ public class EventServiceTest public EventServiceTest() { - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); cacheDb = new CacheDb(); var telemetryTracker = new Mock(); var imezoneServiceMock = new Mock(); diff --git a/AsbCloudWebApi.Tests/ServicesTests/FileCategoryServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/FileCategoryServiceTest.cs index 620261c5..345f2693 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/FileCategoryServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/FileCategoryServiceTest.cs @@ -17,7 +17,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests public FileCategoryServiceTest() { - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); context.SaveChanges(); service = new FileCategoryService(context); } diff --git a/AsbCloudWebApi.Tests/ServicesTests/ScheduleServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/ScheduleServiceTest.cs index 46d40eb0..ff009dea 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/ScheduleServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/ScheduleServiceTest.cs @@ -58,7 +58,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests public ScheduleServiceTest() { - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); context.SaveChanges(); context.Deposits.Add(deposit); diff --git a/AsbCloudWebApi.Tests/ServicesTests/TelemetryDataSaubServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/TelemetryDataSaubServiceTest.cs index 830edb3a..46d9136d 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/TelemetryDataSaubServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/TelemetryDataSaubServiceTest.cs @@ -40,7 +40,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests timezoneService.Setup(s => s.GetByCoordinates(It.IsAny(), It.IsAny())) .Returns(timezone); - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); cacheDb = new CacheDb(); telemetryService = new TelemetryService(context, telemetryTracker.Object, timezoneService.Object); @@ -64,7 +64,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests public async Task UpdateDataAsync() { // Arrange - var telemetryDataSaubService = new TelemetryDataSaubService(context, telemetryService, cacheDb); + var telemetryDataSaubService = new TelemetryDataSaubService(context, telemetryService, null, cacheDb); var now = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(timezone.Hours)).DateTime; var tuser = "Завулон"; diff --git a/AsbCloudWebApi.Tests/ServicesTests/WellFinalDocumentsServiceTest.cs b/AsbCloudWebApi.Tests/ServicesTests/WellFinalDocumentsServiceTest.cs index eb0d0a89..d65e29c7 100644 --- a/AsbCloudWebApi.Tests/ServicesTests/WellFinalDocumentsServiceTest.cs +++ b/AsbCloudWebApi.Tests/ServicesTests/WellFinalDocumentsServiceTest.cs @@ -43,7 +43,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests public WellFinalDocumentsServiceTest() { - context = TestHelpter.MakeTestContext(); + context = TestHelpter.MakeRealTestContext(); context.SaveChanges(); fileServiceMock = new Mock(); diff --git a/AsbCloudWebApi.Tests/TestHelpter.cs b/AsbCloudWebApi.Tests/TestHelpter.cs index f7c8e8a9..94bf1392 100644 --- a/AsbCloudWebApi.Tests/TestHelpter.cs +++ b/AsbCloudWebApi.Tests/TestHelpter.cs @@ -1,7 +1,8 @@ -using AsbCloudApp.Services; -using AsbCloudDb.Model; +using AsbCloudDb.Model; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; +using Moq; +using System.Collections.Generic; +using System.Linq; namespace AsbCloudWebApi.Tests { @@ -9,7 +10,7 @@ namespace AsbCloudWebApi.Tests { // Попробовать когда-нибудь https://github.com/MichalJankowskii/Moq.EntityFrameworkCore - public static AsbCloudDbContext MakeTestContext() + public static AsbCloudDbContext MakeRealTestContext() { var options = new DbContextOptionsBuilder() //.UseInMemoryDatabase(System.Guid.NewGuid().ToString()) @@ -22,5 +23,38 @@ namespace AsbCloudWebApi.Tests context.Database.EnsureCreated(); return context; } + + public static Mock AddDbSetMock(this Mock contextMock, IEnumerable dbSetData) + where T : class + { + var dbSetMock = MakeDbSetMock(dbSetData); + contextMock.Setup(o => o.Set()) + .Returns(() => dbSetMock.Object); + + return contextMock; + } + + public static Mock> MakeDbSetMock() + where T : class + { + var dbSetData = new List(); + return MakeDbSetMock(dbSetData); + } + + public static Mock> MakeDbSetMock(IEnumerable dbSetData) + where T : class + { + var dbSetDataQueriable = dbSetData + .ToList() + .AsQueryable(); + + Mock> dbSetMock = new(); + dbSetMock.As>().Setup(o => o.Provider).Returns(() => dbSetDataQueriable.Provider); + dbSetMock.As>().Setup(o => o.Expression).Returns(() => dbSetDataQueriable.Expression); + dbSetMock.As>().Setup(o => o.ElementType).Returns(() => dbSetDataQueriable.ElementType); + dbSetMock.As>().Setup(o => o.GetEnumerator()).Returns(() => dbSetDataQueriable.GetEnumerator()); + + return dbSetMock; + } } } diff --git a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs index 345ecf71..132f5513 100644 --- a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs @@ -86,7 +86,7 @@ namespace AsbCloudWebApi.Controllers.SAUB if (!isCompanyOwnsWell) return Forbid(); - var content = await telemetryDataService.GetAsync(idWell, begin, + var content = await telemetryDataService.GetOrDefaultAsync(idWell, begin, intervalSec, approxPointsCount, token).ConfigureAwait(false); return Ok(content); diff --git a/AsbCloudWebApi/Controllers/SAUB/TelemetryInstantDataController.cs b/AsbCloudWebApi/Controllers/SAUB/TelemetryInstantDataController.cs index 844f81cd..0f673938 100644 --- a/AsbCloudWebApi/Controllers/SAUB/TelemetryInstantDataController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/TelemetryInstantDataController.cs @@ -89,7 +89,7 @@ namespace AsbCloudWebApi.Controllers.SAUB if (!isCompanyOwnsWell) return Forbid(); - int? idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + int? idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return NoContent(); diff --git a/AsbCloudWebApi/Controllers/WITS/WitsControllerAbstract.cs b/AsbCloudWebApi/Controllers/WITS/WitsControllerAbstract.cs index 2077037f..f95512ab 100644 --- a/AsbCloudWebApi/Controllers/WITS/WitsControllerAbstract.cs +++ b/AsbCloudWebApi/Controllers/WITS/WitsControllerAbstract.cs @@ -72,7 +72,7 @@ namespace AsbCloudWebApi.Controllers.WITS [FromServices] IWitsRecordRepository witsRecordRepository, CancellationToken token) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return NoContent(); var dtos = await witsRecordRepository.GetLastAsync((int)idTelemetry, token); @@ -96,7 +96,7 @@ namespace AsbCloudWebApi.Controllers.WITS [FromServices] IWitsRecordRepository witsRecordRepository, CancellationToken token) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return NoContent(); var dtos = await witsRecordRepository.GetAsync((int)idTelemetry, begin, end, token); @@ -118,7 +118,7 @@ namespace AsbCloudWebApi.Controllers.WITS [FromServices] IWitsRecordRepository witsRecordRepository, CancellationToken token) { - var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); + var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell); if (idTelemetry is null) return NoContent(); var dtos = await witsRecordRepository.GetStatAsync((int)idTelemetry, token); diff --git a/AsbCloudWebApi/wwwroot/index.html b/AsbCloudWebApi/wwwroot/index.html index 80927d26..2b213ff2 100644 --- a/AsbCloudWebApi/wwwroot/index.html +++ b/AsbCloudWebApi/wwwroot/index.html @@ -1 +1 @@ -DDrilling
\ No newline at end of file +DDrilling
\ No newline at end of file diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs index 537b9f5a..754e0194 100644 --- a/ConsoleApp1/Program.cs +++ b/ConsoleApp1/Program.cs @@ -2,7 +2,9 @@ using AsbCloudApp.Data.DailyReport; using AsbCloudDb; using AsbCloudDb.Model; +using AsbCloudInfrastructure; using AsbCloudInfrastructure.Services.DailyReport; +using AsbCloudInfrastructure.Services.SAUB; using ClosedXML.Excel; using DocumentFormat.OpenXml.Wordprocessing; using Microsoft.EntityFrameworkCore; @@ -17,33 +19,20 @@ using System.Threading.Tasks; namespace ConsoleApp1 { - - - class Program { private static AsbCloudDbContext db = ServiceFactory.Context; - + // use ServiceFactory to make services static void Main(/*string[] args*/) { + DependencyInjection.MapsterSetup(); + var sw = System.Diagnostics.Stopwatch.StartNew(); - var set1 = new int[15].Select((v,i) => i.ToString()); - var set2 = new int[5].Select((v, i) => (i + 1000).ToString()); - var set3 = new int[5].Select((v, i) => (i + 2000).ToString()); - var set4 = new int[5].Select((v, i) => (i + 4000).ToString()); - var set5 = new int[8].Select((v, i) => (i + 5000).ToString()); - var set6 = new int[3].Select((v, i) => (i + 6000).ToString()); - var ca = new CyclycArray(10); - ca.AddRange(set1); - ca.AddRange(set2); - ca.AddRange(set3); - ca.AddRange(set4); - ca.AddRange(set5); - ca.AddRange(set6); - Console.WriteLine($"total time: ms"); + sw.Stop(); + Console.WriteLine($"total time: {sw.ElapsedMilliseconds} ms"); Console.ReadLine(); } }