This commit is contained in:
ngfrolov 2022-11-15 17:44:48 +05:00
parent 698fb33651
commit eed8c3eeaa
28 changed files with 318 additions and 101 deletions

View File

@ -90,12 +90,16 @@ namespace System.Collections.Generic
{ {
get get
{ {
if (used == 0)
return default;
var i = (current + 1 + index) % used; var i = (current + 1 + index) % used;
return array[i]; return array[i];
} }
set set
{ {
var i = (current + 1 + index) % used; var devider = used > 0 ? used : array.Length;
var i = (current + 1 + index) % devider;
array[i] = value; array[i] = value;
UpdatedInvoke(current, value); UpdatedInvoke(current, value);
} }

View File

@ -3,7 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
#nullable enable
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
/// <summary> /// <summary>
@ -22,7 +22,7 @@ namespace AsbCloudApp.Services
/// <param name="approxPointsCount">кол-во элементов до которых эти данные прореживаются</param> /// <param name="approxPointsCount">кол-во элементов до которых эти данные прореживаются</param>
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<TDto>> GetAsync(int idWell, Task<IEnumerable<TDto>?> GetOrDefaultAsync(int idWell,
DateTime dateBegin = default, double intervalSec = 600d, DateTime dateBegin = default, double intervalSec = 600d,
int approxPointsCount = 1024, CancellationToken token = default); int approxPointsCount = 1024, CancellationToken token = default);
@ -35,4 +35,5 @@ namespace AsbCloudApp.Services
/// <returns></returns> /// <returns></returns>
Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default); Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default);
} }
} }
#nullable disable

View File

@ -55,7 +55,7 @@ namespace AsbCloudApp.Services
/// </summary> /// </summary>
/// <param name="idWell"></param> /// <param name="idWell"></param>
/// <returns></returns> /// <returns></returns>
int? GetIdTelemetryByIdWell(int idWell); int? GetOrDefaultIdTelemetryByIdWell(int idWell);
/// <summary> /// <summary>
/// получить диапазон дат за которые есть данные /// получить диапазон дат за которые есть данные

View File

@ -16,6 +16,7 @@ using AsbCloudInfrastructure.Services.SAUB;
using AsbCloudInfrastructure.Services.Subsystems; using AsbCloudInfrastructure.Services.Subsystems;
using AsbCloudInfrastructure.Services.WellOperationService; using AsbCloudInfrastructure.Services.WellOperationService;
using AsbCloudInfrastructure.Validators; using AsbCloudInfrastructure.Validators;
using DocumentFormat.OpenXml.Spreadsheet;
using FluentValidation.AspNetCore; using FluentValidation.AspNetCore;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -100,6 +101,8 @@ namespace AsbCloudInfrastructure
services.AddSingleton(new WitsInfoService()); services.AddSingleton(new WitsInfoService());
services.AddSingleton(new CacheDb()); services.AddSingleton(new CacheDb());
services.AddSingleton(new InstantDataRepository()); services.AddSingleton(new InstantDataRepository());
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSaubDto>.GetInstance<TelemetryDataSaub>(configuration));
services.AddSingleton(provider=> TelemetryDataCache<TelemetryDataSpinDto>.GetInstance<TelemetryDataSpin>(configuration));
services.AddSingleton<ITelemetryTracker, TelemetryTracker>(); services.AddSingleton<ITelemetryTracker, TelemetryTracker>();
services.AddSingleton<IRequerstTrackerService, RequestTrackerService>(); services.AddSingleton<IRequerstTrackerService, RequestTrackerService>();
services.AddSingleton<IBackgroundWorkerService, BackgroundWorkerService>(); services.AddSingleton<IBackgroundWorkerService, BackgroundWorkerService>();

View File

@ -27,7 +27,7 @@ namespace AsbCloudInfrastructure.Services
public async Task<DrillParamsDto?> GetDefaultDrillParamsAsync(int idWell, public async Task<DrillParamsDto?> GetDefaultDrillParamsAsync(int idWell,
double startDepth, double endDepth, CancellationToken token = default) double startDepth, double endDepth, CancellationToken token = default)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return null; return null;

View File

@ -113,7 +113,7 @@ namespace AsbCloudInfrastructure.Services
public DatesRangeDto GetDatesRangeOrDefault(int idWell) public DatesRangeDto GetDatesRangeOrDefault(int idWell)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return null; return null;
var range = telemetryService.GetDatesRange((int)idTelemetry); var range = telemetryService.GetDatesRange((int)idTelemetry);

View File

@ -34,7 +34,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
int take = 32, int take = 32,
CancellationToken token = default) CancellationToken token = default)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return null; return null;

View File

@ -10,26 +10,31 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
#nullable enable
namespace AsbCloudInfrastructure.Services.SAUB namespace AsbCloudInfrastructure.Services.SAUB
{ {
public abstract class TelemetryDataBaseService<TDto, TModel> : ITelemetryDataService<TDto> public abstract class TelemetryDataBaseService<TDto, TEntity> : ITelemetryDataService<TDto>
where TDto : AsbCloudApp.Data.ITelemetryData where TDto : AsbCloudApp.Data.ITelemetryData
where TModel : class, ITelemetryData where TEntity : class, ITelemetryData
{ {
protected readonly IAsbCloudDbContext db; protected readonly IAsbCloudDbContext db;
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers; protected readonly CacheTable<TelemetryUser> cacheTelemetryUsers;
private readonly TelemetryDataCache<TDto> telemetryDataCache;
public TelemetryDataBaseService( public TelemetryDataBaseService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
TelemetryDataCache<TDto> telemetryDataCache,
CacheDb cacheDb) CacheDb cacheDb)
{ {
this.db = db; this.db = db;
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
cacheTelemetryUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db); cacheTelemetryUsers = cacheDb.GetCachedTable<TelemetryUser>((AsbCloudDbContext)db);
this.telemetryDataCache = telemetryDataCache;
} }
/// <inheritdoc/>
public virtual async Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default) public virtual async Task<int> UpdateDataAsync(string uid, IEnumerable<TDto> dtos, CancellationToken token = default)
{ {
if (dtos == default || !dtos.Any()) if (dtos == default || !dtos.Any())
@ -53,6 +58,8 @@ namespace AsbCloudInfrastructure.Services.SAUB
var idTelemetry = telemetryService.GetOrCreateTelemetryIdByUid(uid); var idTelemetry = telemetryService.GetOrCreateTelemetryIdByUid(uid);
var timezone = telemetryService.GetTimezone(idTelemetry); var timezone = telemetryService.GetTimezone(idTelemetry);
telemetryDataCache.AddRange(idTelemetry, dtos);
var entities = dtosList.Select(dto => var entities = dtosList.Select(dto =>
{ {
var entity = Convert(dto, timezone.Hours); var entity = Convert(dto, timezone.Hours);
@ -63,7 +70,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
var entityMaxDate = entities.Max(e => e.DateTime); var entityMaxDate = entities.Max(e => e.DateTime);
telemetryService.TelemetryTracker.SaveRequestDate(uid, entityMaxDate); telemetryService.TelemetryTracker.SaveRequestDate(uid, entityMaxDate);
var dbset = db.Set<TModel>(); var dbset = db.Set<TEntity>();
var stopwatch = Stopwatch.StartNew(); var stopwatch = Stopwatch.StartNew();
try try
{ {
@ -82,12 +89,15 @@ namespace AsbCloudInfrastructure.Services.SAUB
return 0; return 0;
} }
} }
// TODO: It shouldn`t be nullable. Throw exceptions instead and return empty.
/// <inheritdoc/> /// <inheritdoc/>
public virtual async Task<IEnumerable<TDto>> GetAsync(int idWell, public virtual async Task<IEnumerable<TDto>?> GetOrDefaultAsync(int idWell,
DateTime dateBegin = default, double intervalSec = 600d, DateTime dateBegin = default, double intervalSec = 600d,
int approxPointsCount = 1024, CancellationToken token = default) int approxPointsCount = 1024, CancellationToken token = default)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell) ?? -1; var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell) ?? -1;
if (idTelemetry == -1) if (idTelemetry == -1)
return null; return null;
@ -110,8 +120,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
if (dateBeginUtc == default) if (dateBeginUtc == default)
dateBeginUtc = DateTime.UtcNow.AddSeconds(-intervalSec); 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 dateEnd = dateBeginUtc.AddSeconds(intervalSec);
var dbSet = db.Set<TModel>(); var dbSet = db.Set<TEntity>();
var query = dbSet var query = dbSet
.Where(d => d.IdTelemetry == idTelemetry .Where(d => d.IdTelemetry == idTelemetry
@ -144,9 +158,10 @@ namespace AsbCloudInfrastructure.Services.SAUB
return dtos; 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

View File

@ -5,74 +5,79 @@ using System;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Mapster; using Mapster;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
#nullable enable #nullable enable
namespace AsbCloudInfrastructure.Services.SAUB namespace AsbCloudInfrastructure.Services.SAUB
{ {
public class TelemetryDataCache<TDto, TEntity> public class TelemetryDataCache<TDto>
where TDto : AsbCloudApp.Data.ITelemetryData where TDto : AsbCloudApp.Data.ITelemetryData
where TEntity : class, ITelemetryData
{ {
private const int activeWellCapacity = 24 * 60 * 60; private const int activeWellCapacity = 24 * 60 * 60;
private const int doneWellCapacity = 65 * 60; private const int doneWellCapacity = 65 * 60;
private readonly ConcurrentDictionary<int, CyclycArray<TDto>> caches; private readonly ConcurrentDictionary<int, CyclycArray<TDto>> caches;
private bool isLoading = false;
public TelemetryDataCache(IAsbCloudDbContext db)
private TelemetryDataCache()
{ {
caches = new (); caches = new();
LoadCaches(db);
} }
private void LoadCaches(IAsbCloudDbContext db) private static TelemetryDataCache<TDto>? instance;
{
Well[] wells = db.Set<Well>()
.Include(well => well.Telemetry)
.Where(well => well.IdTelemetry != null)
.ToArray();
foreach (Well well in wells) //TODO: Move initialize fromDB to bacground service task
public static TelemetryDataCache<TDto> GetInstance<TEntity>(IConfiguration configuration)
where TEntity : class, ITelemetryData
{
if (instance is null)
{ {
var capacity = well.IdState == 1 instance = new TelemetryDataCache<TDto>();
? activeWellCapacity _ = Task.Run(() =>
: doneWellCapacity; {
using var db = MakeContext(configuration);
var idTelemetry = well.IdTelemetry!.Value; instance.InitializeCacheFromDB<TEntity>(db);
var hoursOffset = well.Timezone.Hours; });
IEnumerable<TDto> cacheItemData = GetCacheDataFromDb(db, idTelemetry, capacity, hoursOffset);
var cacheItem = new CyclycArray<TDto>(capacity);
cacheItem.AddRange(cacheItemData);
caches.TryAdd(idTelemetry, cacheItem);
} }
return instance;
} }
public static TelemetryDataCache<TDto> GetInstance<TEntity>(IAsbCloudDbContext db, out Task initializationTask)
private static IEnumerable<TDto> GetCacheDataFromDb(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset) where TEntity : class, ITelemetryData
{ {
var entities = db.Set<TEntity>() if (instance is null)
.Where(i => i.IdTelemetry == idTelemetry) {
.OrderByDescending(i => i.DateTime) instance = new TelemetryDataCache<TDto>();
.Take(capacity) initializationTask = Task.Run(() =>
.ToArray() {
.OrderBy(i => i.DateTime); instance.InitializeCacheFromDB<TEntity>(db);
});
var dtos = entities.Select(entity => { }
var dto = entity.Adapt<TDto>(); else
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset); initializationTask = Task.CompletedTask;
return dto; return instance;
});
return dtos;
} }
/// <summary> /// <summary>
/// Добавить элементы в кеш /// Добавить новые элементы в кеш
/// </summary> /// </summary>
/// <param name="idTelemetry"></param> /// <param name="idTelemetry"></param>
/// <param name="range"></param> /// <param name="range"></param>
public void AddRange(int idTelemetry, IEnumerable<TDto> range) public void AddRange(int idTelemetry, IEnumerable<TDto> range)
{ {
var cacheItem = caches.GetOrAdd(idTelemetry, _ => new CyclycArray<TDto>(activeWellCapacity)); CyclycArray<TDto> cacheItem;
if (isLoading)
{
if (caches.TryGetValue(idTelemetry, out CyclycArray<TDto>? localCacheItem))
cacheItem = localCacheItem;
else
return;
}
else
{
cacheItem = caches.GetOrAdd(idTelemetry, _ => new CyclycArray<TDto>(activeWellCapacity));
}
var newItems = range var newItems = range
.OrderBy(i => i.DateTime); .OrderBy(i => i.DateTime);
foreach (var item in newItems) foreach (var item in newItems)
@ -95,7 +100,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
if(!caches.TryGetValue(idTelemetry, out CyclycArray<TDto>? cacheItem)) if(!caches.TryGetValue(idTelemetry, out CyclycArray<TDto>? cacheItem))
return null; return null;
if (cacheItem is null || cacheItem[0].DateTime > dateBegin) if (cacheItem is null || !cacheItem.Any() || cacheItem[0].DateTime > dateBegin)
return null; return null;
var dateEnd = dateBegin.AddSeconds(intervalSec); var dateEnd = dateBegin.AddSeconds(intervalSec);
@ -109,6 +114,77 @@ namespace AsbCloudInfrastructure.Services.SAUB
return items; return items;
} }
private void InitializeCacheFromDB<TEntity>(IAsbCloudDbContext db)
where TEntity : class, ITelemetryData
{
if (isLoading)
throw new Exception("Multiple cache loading detected.");
isLoading = true;
Well[] wells = Array.Empty<Well>();
try
{
wells = db.Set<Well>()
.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<TDto> cacheItemData = GetCacheDataFromDb<TEntity>(db, idTelemetry, capacity, hoursOffset);
var cacheItem = new CyclycArray<TDto>(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<AsbCloudDbContext>()
.UseNpgsql(connectionString)
.Options;
var db = new AsbCloudDbContext(options);
return db;
}
private static IEnumerable<TDto> GetCacheDataFromDb<TEntity>(IAsbCloudDbContext db, int idTelemetry, int capacity, double hoursOffset)
where TEntity : class, ITelemetryData
{
var entities = db.Set<TEntity>()
.Where(i => i.IdTelemetry == idTelemetry)
.OrderByDescending(i => i.DateTime)
.Take(capacity)
.ToArray()
.AsEnumerable()
.Reverse();
var dtos = entities.Select(entity => {
var dto = entity.Adapt<TDto>();
dto.DateTime = entity.DateTime.ToRemoteDateTime(hoursOffset);
return dto;
});
return dtos;
}
} }
} }
#nullable disable #nullable disable

View File

@ -16,8 +16,9 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryDataSaubService( public TelemetryDataSaubService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
TelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache,
CacheDb cacheDb) CacheDb cacheDb)
: base(db, telemetryService, cacheDb) : base(db, telemetryService, telemetryDataCache, cacheDb)
{ } { }
public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset) public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset)

View File

@ -13,8 +13,9 @@ namespace AsbCloudInfrastructure.Services.SAUB
public TelemetryDataSpinService( public TelemetryDataSpinService(
IAsbCloudDbContext db, IAsbCloudDbContext db,
ITelemetryService telemetryService, ITelemetryService telemetryService,
TelemetryDataCache<TelemetryDataSpinDto> telemetryDataCache,
CacheDb cacheDb) CacheDb cacheDb)
: base(db, telemetryService, cacheDb) : base(db, telemetryService, telemetryDataCache, cacheDb)
{ } { }
public override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset) public override TelemetryDataSpin Convert(TelemetryDataSpinDto src, double timezoneOffset)

View File

@ -141,7 +141,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
throw new Exception($"Telemetry id: {idTelemetry} can't find timezone."); throw new Exception($"Telemetry id: {idTelemetry} can't find timezone.");
} }
public int? GetIdTelemetryByIdWell(int idWell) public int? GetOrDefaultIdTelemetryByIdWell(int idWell)
{ {
var telemetry = GetTelemetryCache() var telemetry = GetTelemetryCache()
.FirstOrDefault(t => t.Value.Well?.Id == idWell).Value; .FirstOrDefault(t => t.Value.Well?.Id == idWell).Value;

View File

@ -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<IAsbCloudDbContext> dbMock;
private TelemetryDataCache<TTelemetryData> 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<IAsbCloudDbContext>();
dbMock
.AddDbSetMock(wellData)
.AddDbSetMock(telemetryData);
cacheTest = TelemetryDataCache<TTelemetryData>.GetInstance<TTelemetryData>(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));
}
}
}

View File

@ -69,7 +69,7 @@ public class ClusterServiceTest
public ClusterServiceTest() public ClusterServiceTest()
{ {
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
wellService = new Mock<IWellService>(); wellService = new Mock<IWellService>();
context.Deposits.RemoveRange(context.Deposits); context.Deposits.RemoveRange(context.Deposits);
context.Clusters.RemoveRange(context.Clusters); context.Clusters.RemoveRange(context.Clusters);

View File

@ -21,7 +21,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
protected override ICrudService<DepositDto> MakeService() protected override ICrudService<DepositDto> MakeService()
{ {
var dbContext = TestHelpter.MakeTestContext(); var dbContext = TestHelpter.MakeRealTestContext();
return new CrudCacheServiceBase<DepositDto, Deposit>(dbContext); return new CrudCacheServiceBase<DepositDto, Deposit>(dbContext);
} }
} }

View File

@ -107,7 +107,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
public DetectedOperationServiceTest() public DetectedOperationServiceTest()
{ {
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
context.SaveChanges(); context.SaveChanges();
context.Telemetries.Add(telemetry); context.Telemetries.Add(telemetry);

View File

@ -90,7 +90,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
{ {
AsbCloudInfrastructure.DependencyInjection.MapsterSetup(); AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
db = TestHelpter.MakeTestContext(); db = TestHelpter.MakeRealTestContext();
db.Wells.AddRange(wells); db.Wells.AddRange(wells);
db.Companies.AddRange(companies); db.Companies.AddRange(companies);
db.SaveChanges(); db.SaveChanges();

View File

@ -19,7 +19,7 @@ public class EventServiceTest
public EventServiceTest() public EventServiceTest()
{ {
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
cacheDb = new CacheDb(); cacheDb = new CacheDb();
var telemetryTracker = new Mock<ITelemetryTracker>(); var telemetryTracker = new Mock<ITelemetryTracker>();
var imezoneServiceMock = new Mock<ITimezoneService>(); var imezoneServiceMock = new Mock<ITimezoneService>();

View File

@ -17,7 +17,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
public FileCategoryServiceTest() public FileCategoryServiceTest()
{ {
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
context.SaveChanges(); context.SaveChanges();
service = new FileCategoryService(context); service = new FileCategoryService(context);
} }

View File

@ -58,7 +58,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
public ScheduleServiceTest() public ScheduleServiceTest()
{ {
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
context.SaveChanges(); context.SaveChanges();
context.Deposits.Add(deposit); context.Deposits.Add(deposit);

View File

@ -40,7 +40,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
timezoneService.Setup(s => s.GetByCoordinates(It.IsAny<double>(), It.IsAny<double>())) timezoneService.Setup(s => s.GetByCoordinates(It.IsAny<double>(), It.IsAny<double>()))
.Returns(timezone); .Returns(timezone);
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
cacheDb = new CacheDb(); cacheDb = new CacheDb();
telemetryService = new TelemetryService(context, telemetryTracker.Object, timezoneService.Object); telemetryService = new TelemetryService(context, telemetryTracker.Object, timezoneService.Object);
@ -64,7 +64,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
public async Task UpdateDataAsync() public async Task UpdateDataAsync()
{ {
// Arrange // 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 now = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(timezone.Hours)).DateTime;
var tuser = "Завулон"; var tuser = "Завулон";

View File

@ -43,7 +43,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
public WellFinalDocumentsServiceTest() public WellFinalDocumentsServiceTest()
{ {
context = TestHelpter.MakeTestContext(); context = TestHelpter.MakeRealTestContext();
context.SaveChanges(); context.SaveChanges();
fileServiceMock = new Mock<FileService>(); fileServiceMock = new Mock<FileService>();

View File

@ -1,7 +1,8 @@
using AsbCloudApp.Services; using AsbCloudDb.Model;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics; using Moq;
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudWebApi.Tests namespace AsbCloudWebApi.Tests
{ {
@ -9,7 +10,7 @@ namespace AsbCloudWebApi.Tests
{ {
// Попробовать когда-нибудь https://github.com/MichalJankowskii/Moq.EntityFrameworkCore // Попробовать когда-нибудь https://github.com/MichalJankowskii/Moq.EntityFrameworkCore
public static AsbCloudDbContext MakeTestContext() public static AsbCloudDbContext MakeRealTestContext()
{ {
var options = new DbContextOptionsBuilder<AsbCloudDbContext>() var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
//.UseInMemoryDatabase(System.Guid.NewGuid().ToString()) //.UseInMemoryDatabase(System.Guid.NewGuid().ToString())
@ -22,5 +23,38 @@ namespace AsbCloudWebApi.Tests
context.Database.EnsureCreated(); context.Database.EnsureCreated();
return context; return context;
} }
public static Mock<IAsbCloudDbContext> AddDbSetMock<T>(this Mock<IAsbCloudDbContext> contextMock, IEnumerable<T> dbSetData)
where T : class
{
var dbSetMock = MakeDbSetMock(dbSetData);
contextMock.Setup(o => o.Set<T>())
.Returns(() => dbSetMock.Object);
return contextMock;
}
public static Mock<DbSet<T>> MakeDbSetMock<T>()
where T : class
{
var dbSetData = new List<T>();
return MakeDbSetMock(dbSetData);
}
public static Mock<DbSet<T>> MakeDbSetMock<T>(IEnumerable<T> dbSetData)
where T : class
{
var dbSetDataQueriable = dbSetData
.ToList()
.AsQueryable();
Mock<DbSet<T>> dbSetMock = new();
dbSetMock.As<IQueryable<T>>().Setup(o => o.Provider).Returns(() => dbSetDataQueriable.Provider);
dbSetMock.As<IQueryable<T>>().Setup(o => o.Expression).Returns(() => dbSetDataQueriable.Expression);
dbSetMock.As<IQueryable<T>>().Setup(o => o.ElementType).Returns(() => dbSetDataQueriable.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(o => o.GetEnumerator()).Returns(() => dbSetDataQueriable.GetEnumerator());
return dbSetMock;
}
} }
} }

View File

@ -86,7 +86,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
if (!isCompanyOwnsWell) if (!isCompanyOwnsWell)
return Forbid(); return Forbid();
var content = await telemetryDataService.GetAsync(idWell, begin, var content = await telemetryDataService.GetOrDefaultAsync(idWell, begin,
intervalSec, approxPointsCount, token).ConfigureAwait(false); intervalSec, approxPointsCount, token).ConfigureAwait(false);
return Ok(content); return Ok(content);

View File

@ -89,7 +89,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
if (!isCompanyOwnsWell) if (!isCompanyOwnsWell)
return Forbid(); return Forbid();
int? idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); int? idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return NoContent(); return NoContent();

View File

@ -72,7 +72,7 @@ namespace AsbCloudWebApi.Controllers.WITS
[FromServices] IWitsRecordRepository<TDto> witsRecordRepository, [FromServices] IWitsRecordRepository<TDto> witsRecordRepository,
CancellationToken token) CancellationToken token)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return NoContent(); return NoContent();
var dtos = await witsRecordRepository.GetLastAsync((int)idTelemetry, token); var dtos = await witsRecordRepository.GetLastAsync((int)idTelemetry, token);
@ -96,7 +96,7 @@ namespace AsbCloudWebApi.Controllers.WITS
[FromServices] IWitsRecordRepository<TDto> witsRecordRepository, [FromServices] IWitsRecordRepository<TDto> witsRecordRepository,
CancellationToken token) CancellationToken token)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return NoContent(); return NoContent();
var dtos = await witsRecordRepository.GetAsync((int)idTelemetry, begin, end, token); var dtos = await witsRecordRepository.GetAsync((int)idTelemetry, begin, end, token);
@ -118,7 +118,7 @@ namespace AsbCloudWebApi.Controllers.WITS
[FromServices] IWitsRecordRepository<TDto> witsRecordRepository, [FromServices] IWitsRecordRepository<TDto> witsRecordRepository,
CancellationToken token) CancellationToken token)
{ {
var idTelemetry = telemetryService.GetIdTelemetryByIdWell(idWell); var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell);
if (idTelemetry is null) if (idTelemetry is null)
return NoContent(); return NoContent();
var dtos = await witsRecordRepository.GetStatAsync((int)idTelemetry, token); var dtos = await witsRecordRepository.GetStatAsync((int)idTelemetry, token);

View File

@ -1 +1 @@
<!doctype html><html lang="ru"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="white"/><meta name="theme-color" media="(prefers-color-scheme: light)" content="white"/><meta name="theme-color" media="(prefers-color-scheme: dark)" content="black"/><meta name="description" content="Онлайн мониторинг процесса бурения в реальном времени в офисе заказчика"/><title>DDrilling</title><script defer="defer" src="/vendors.1920da1d.js"></script><script defer="defer" src="/main.101601f2.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html> <!doctype html><html lang="ru"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="white"/><meta name="theme-color" media="(prefers-color-scheme: light)" content="white"/><meta name="theme-color" media="(prefers-color-scheme: dark)" content="black"/><meta name="description" content="Онлайн мониторинг процесса бурения в реальном времени в офисе заказчика"/><title>DDrilling</title><script defer="defer" src="/vendors.1920da1d.js"></script><script defer="defer" src="/main.25114aff.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -2,7 +2,9 @@
using AsbCloudApp.Data.DailyReport; using AsbCloudApp.Data.DailyReport;
using AsbCloudDb; using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure;
using AsbCloudInfrastructure.Services.DailyReport; using AsbCloudInfrastructure.Services.DailyReport;
using AsbCloudInfrastructure.Services.SAUB;
using ClosedXML.Excel; using ClosedXML.Excel;
using DocumentFormat.OpenXml.Wordprocessing; using DocumentFormat.OpenXml.Wordprocessing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -17,33 +19,20 @@ using System.Threading.Tasks;
namespace ConsoleApp1 namespace ConsoleApp1
{ {
class Program class Program
{ {
private static AsbCloudDbContext db = ServiceFactory.Context; private static AsbCloudDbContext db = ServiceFactory.Context;
// use ServiceFactory to make services // use ServiceFactory to make services
static void Main(/*string[] args*/) 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<string>(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(); Console.ReadLine();
} }
} }