using AsbCloudApp.Data; using AsbCloudApp.Data.DailyReport; using AsbCloudApp.Data.DailyReport.Blocks.Sign; using AsbCloudApp.Data.DailyReport.Blocks.Subsystems; using AsbCloudApp.Data.DailyReport.Blocks.TimeBalance; using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.ProcessMaps.Report; using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Data.Trajectory; using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.ProcessMaps.WellDrilling; using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.DailyReport; using NSubstitute; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using AsbCloudApp.Data.WellOperation; using Xunit; namespace AsbCloudInfrastructure.Tests.Services; public class DailyReportServiceTest { private const int idDailyReport = 1; private const int idUser = 3; private const int idWell = 2; private readonly SubsystemBlockDto fakeSubsystemBlock = new() { IdUser = idUser, Wellbore = 999, MeasurementsPerDay = 999, TotalRopPlan = 999, Comment = "Увеличить обороты", Subsystems = new[] { new SubsystemRecordDto { Name = "АвтоСПО", UsagePerDay = new SubsystemParametersDto { UsedTimeHours = 24, SumDepthInterval = 1500, KUsage = 15 }, UsagePerWell = new SubsystemParametersDto { UsedTimeHours = 500, SumDepthInterval = 3000, KUsage = 100 } } } }; private readonly SignBlockDto fakeSignBlock = new() { IdUser = idUser, DrillingMaster = new SignRecordDto { Name = "Иван", Patronymic = "Иванович", Surname = "Иванов" }, Supervisor = new SignRecordDto() { Name = "Илья", Patronymic = "Ильич", Surname = "Бурилов" } }; private readonly TimeBalanceBlockDto fakeTimeBalanceBlock = new() { IdUser = idUser, IdSection = 1, WellDepth = new PlanFactDto { Plan = 2000 }, WellOperations = new[] { new TimeBalanceRecordDto { IdWellOperation = 1, DurationHours = new PlanFactDto { Fact = 100, Plan = 150, }, DrillingDeviationPerSection = 90, DrillingDeviationPerDay = 100, ReasonDeviation = "Отклонение" } } }; private readonly DetectedOperationListDto fakeWellOperationSlipsTime = new() { Stats = new[] { new DetectedOperationDrillersStatDto { Count = 40 } } }; private readonly ProcessMapReportDataSaubStatDto fakeProcessMapReportWellDrilling = new() { DrillingMode = "Ротор", DateStart = new DateTimeOffset(2023, 10, 26, 0, 0, 0, TimeSpan.Zero), DeltaDepth = 500, Rop = new PlanFactDto { Plan = 300, Fact = 500 }, DrilledTime = 100 }; private readonly WellSectionTypeDto fakeSectionType = new() { Id = 1, Caption = "Пилотный ствол", }; private readonly TrajectoryGeoFactDto fakeLastFactTrajectory = new() { WellboreDepth = 100, VerticalDepth = 150, ZenithAngle = 3, AzimuthGeo = 5 }; private readonly CompanyDto fakeCustomer = new() { Caption = "Тестовый заказчик", IdCompanyType = 1 }; private readonly CompanyDto fakeContractor = new() { Caption = "Тестовый подрядчик", IdCompanyType = 2 }; private readonly WellOperationDto fakeFirstFactWellOperation = new() { IdWell = idWell, IdParentCategory = 4001, IdWellSectionType = 1, OperationCategoryName = "Механическое. бурение", DateStart = new DateTime(2023, 10, 26, 0, 0, 0), DepthStart = 80, DepthEnd = 150, DurationHours = 8, }; private readonly WellOperationDto fakeLastFactWellOperation = new() { IdWell = idWell, OperationCategoryName = "Механическое. бурение", IdWellSectionType = 1, IdParentCategory = 4001, DateStart = new DateTime(2023, 10, 26, 23, 59, 59), DepthStart = 150, DepthEnd = 200, DurationHours = 8, }; private readonly ScheduleDto fakeShedule = new() { IdWell = idWell, ShiftStart = new TimeDto(1), ShiftEnd = new TimeDto(5), DrillStart = new DateTimeOffset(2023, 01, 26, 0, 0, 0, TimeSpan.Zero), DrillEnd = new DateTimeOffset(2023, 12, 26, 0, 0, 0, TimeSpan.Zero), Driller = new() { Name = "Иван", Surname = "Иванов", Patronymic = "Бурила" } }; private readonly SubsystemStatDto fakeSubsystemsStat = new() { SubsystemName = "АПД", SumDepthInterval = 250, UsedTimeHours = 200, KUsage = 30 }; private readonly SimpleTimezoneDto fakeWellTimezone = new() { Hours = 5, }; private readonly IWellService wellServiceMock = Substitute.For(); private readonly ITrajectoryNnbRepository trajectoryFactNnbRepositoryMock = Substitute.For(); private readonly IDailyReportRepository dailyReportRepositoryMock = Substitute.For(); private readonly IScheduleRepository scheduleRepositoryMock = Substitute.For(); private readonly ISubsystemService subsystemServiceMock = Substitute.For(); private readonly IProcessMapReportDrillingService processMapReportWellDrillingServiceMock = Substitute.For(); private readonly IDetectedOperationService detectedOperationServiceMock = Substitute.For(); private readonly IWellOperationService wellOperationServiceMock = Substitute.For(); private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For(); private readonly DailyReportService dailyReportService; private readonly DailyReportDto fakeDailyReport; private readonly WellDto fakeWell; private readonly DatesRangeDto fakeDatesRange; private readonly DataSaubStatRequest fakeRequest = new DataSaubStatRequest(); public DailyReportServiceTest() { fakeDailyReport = new DailyReportDto { Id = idDailyReport, IdWell = idWell, Date = new(2023, 10, 26), DateLastUpdate = null }; fakeWell = new WellDto { Id = idWell, Caption = "Тестовое название", WellType = "Горизонтальная", Cluster = "Тестовый куст", Deposit = "Тестовое месторождение", Companies = new[] { fakeCustomer, fakeContractor } }; fakeDatesRange = new DatesRangeDto { From = fakeFirstFactWellOperation.DateStart.DateTime, To = fakeLastFactWellOperation.DateStart.DateTime }; dailyReportService = new DailyReportService(wellServiceMock, trajectoryFactNnbRepositoryMock, dailyReportRepositoryMock, scheduleRepositoryMock, wellOperationRepositoryMock, subsystemServiceMock, processMapReportWellDrillingServiceMock, detectedOperationServiceMock, wellOperationServiceMock); dailyReportRepositoryMock.InsertAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(idDailyReport); dailyReportRepositoryMock.GetOrDefaultAsync(Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(fakeDailyReport); dailyReportRepositoryMock.UpdateAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(idDailyReport); wellServiceMock.GetOrDefaultAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(fakeWell); trajectoryFactNnbRepositoryMock.GetByRequestAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(new[] { fakeLastFactTrajectory }); wellOperationServiceMock.GetAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(new[] { fakeFirstFactWellOperation, fakeLastFactWellOperation }); wellOperationRepositoryMock.GetDatesRangeAsync(Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(fakeDatesRange); wellOperationRepositoryMock.GetSectionTypes() .ReturnsForAnyArgs(new[] { fakeSectionType }); detectedOperationServiceMock.GetAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(fakeWellOperationSlipsTime); subsystemServiceMock.GetStatAsync(Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(new[] { fakeSubsystemsStat }); scheduleRepositoryMock.GetAsync(Arg.Any(), Arg.Any(), Arg.Any()) .ReturnsForAnyArgs(new[] { fakeShedule }); processMapReportWellDrillingServiceMock.GetAsync(Arg.Any(), fakeRequest, Arg.Any()) .ReturnsForAnyArgs(new[] { fakeProcessMapReportWellDrilling }); wellServiceMock.GetTimezone(Arg.Any()) .ReturnsForAnyArgs(fakeWellTimezone); } [Fact] public async Task UpdateOrInsertAsync_ShouldReturn_UpdatedSubsystemBlock() { //act var result = await dailyReportService.UpdateOrInsertAsync(idWell, fakeDailyReport.Date, idUser, fakeSubsystemBlock, CancellationToken.None); //assert Assert.NotNull(fakeSubsystemBlock.LastUpdateDate); Assert.NotNull(fakeDailyReport.DateLastUpdate); Assert.Equal(fakeSubsystemBlock.IdUser, idUser); Assert.Equal(fakeDailyReport.SubsystemBlock, fakeSubsystemBlock); Assert.Equal(idDailyReport, result); } [Theory] [MemberData(nameof(DateDailyReport))] public async Task UpdateOrInsertAsync_ShouldReturn_UnableToUpdateDailyReport(DateOnly dateDailyReport) { //act var result = await Assert.ThrowsAsync(() => dailyReportService.UpdateOrInsertAsync( idWell, dateDailyReport, idUser, fakeSignBlock, CancellationToken.None)); //assert Assert.Contains("Невозможно обновить суточный отчёт", result.Message); } [Fact] public async Task UpdateOrInsertAsync_ShouldReturn_UpdatedSignBlock() { //act var result = await dailyReportService.UpdateOrInsertAsync(idWell, fakeDailyReport.Date, idUser, fakeSignBlock, CancellationToken.None); //assert Assert.NotNull(fakeSignBlock.LastUpdateDate); Assert.NotNull(fakeDailyReport.DateLastUpdate); Assert.Equal(fakeSignBlock.IdUser, idUser); Assert.Equal(fakeDailyReport.SignBlock, fakeSignBlock); Assert.Equal(idDailyReport, result); } [Fact] public async Task UpdateOrInsertAsync_ShouldReturn_UpdatedTimeBalanceBlock() { //act var result = await dailyReportService.UpdateOrInsertAsync(idWell, fakeDailyReport.Date, idUser, fakeTimeBalanceBlock, CancellationToken.None); //assert Assert.NotNull(fakeTimeBalanceBlock.LastUpdateDate); Assert.NotNull(fakeDailyReport.DateLastUpdate); Assert.Equal(fakeTimeBalanceBlock.IdUser, idUser); Assert.Equal(fakeDailyReport.TimeBalanceBlock, fakeTimeBalanceBlock); Assert.Equal(idDailyReport, result); } [Theory] [MemberData(nameof(DateDailyReport))] public async Task GetAsync_ShouldReturn_UnableToGetDailyReport(DateOnly dateDailyReport) { //act var result = await Assert.ThrowsAsync(() => dailyReportService.GetAsync(idWell, dateDailyReport, CancellationToken.None)); //assert Assert.Contains("Невозможно получить суточный отчёт", result.Message); } [Fact] public async Task GetAsync_ShouldReturn_AddedWellInfo() { //act var result = await dailyReportService.GetAsync(idWell, fakeDailyReport.Date, CancellationToken.None); //assert Assert.Equal(result.IdWell, fakeWell.Id); Assert.Equal(result.WellCaption, fakeWell.Caption); Assert.Equal(result.WellType, fakeWell.WellType); Assert.Equal(result.Cluster, fakeWell.Cluster); Assert.Equal(result.Deposit, fakeWell.Deposit); Assert.Equal(result.Customer, fakeCustomer.Caption); Assert.Equal(result.Contractor, fakeContractor.Caption); Assert.Equal(result.DepthStart, fakeFirstFactWellOperation.DepthStart); Assert.Equal(result.DepthEnd, fakeLastFactWellOperation.DepthEnd); } [Fact] public async Task GetAsync_ShouldReturn_AddedTrajectoryBlock() { //act var result = await dailyReportService.GetAsync(idWell, fakeDailyReport.Date, CancellationToken.None); //assert Assert.Equal(fakeLastFactTrajectory.WellboreDepth, result.TrajectoryBlock.WellboreDepth); Assert.Equal(fakeLastFactTrajectory.VerticalDepth, result.TrajectoryBlock.VerticalDepth); Assert.Equal(fakeLastFactTrajectory.ZenithAngle, result.TrajectoryBlock.ZenithAngle); Assert.Equal(fakeLastFactTrajectory.AzimuthGeo, result.TrajectoryBlock.AzimuthGeo); } [Fact] public async Task GetAsync_ShouldReturn_AddedFactWellOperationBlock() { //act var result = await dailyReportService.GetAsync(idWell, fakeDailyReport.Date, CancellationToken.None); //assert Assert.Equal(16, result.FactWellOperationBlock.SectionDrillingHours); Assert.Single(result.FactWellOperationBlock.WellOperations); var wellOperation = result.FactWellOperationBlock.WellOperations.Single(); Assert.Equal("Механическое. бурение", wellOperation.CategoryName); Assert.Equal(16, wellOperation.DurationHours); } [Fact] public async Task GetAsync_ShouldReturn_AddedScheduleBlock() { //act var result = await dailyReportService.GetAsync(idWell, fakeDailyReport.Date, CancellationToken.None); //assert Assert.Single(result.ScheduleBlock); var sheduleRecord = result.ScheduleBlock.Single(); Assert.Equal(fakeShedule.ShiftStart, sheduleRecord.ShiftStart); Assert.Equal(fakeShedule.ShiftEnd, sheduleRecord.ShiftEnd); Assert.Equal(fakeShedule.Driller?.Name, sheduleRecord.Name); Assert.Equal(fakeShedule.Driller?.Surname, sheduleRecord.Surname); Assert.Equal(fakeShedule.Driller?.Patronymic, sheduleRecord.Patronymic); } [Fact] public async Task GetAsync_ShouldReturn_UpdatedTimeBalanceBlock() { //arrange fakeDailyReport.TimeBalanceBlock = fakeTimeBalanceBlock; //act var result = await dailyReportService.GetAsync(idWell, fakeDailyReport.Date, CancellationToken.None); //assert Assert.NotNull(result.TimeBalanceBlock); Assert.Equal(fakeSectionType.Id, result.TimeBalanceBlock.IdSection); Assert.Equal(fakeSectionType.Caption, result.TimeBalanceBlock.SectionName); Assert.Equal(2000, result.TimeBalanceBlock?.WellDepth.Plan); Assert.Equal(120, result.TimeBalanceBlock?.WellDepth.Fact); Assert.Equal(40, result.TimeBalanceBlock?.WellOperationSlipsTimeCount); } [Fact] public async Task GetAsync_ShouldReturn_AddedProcessMapWellDrillingBlock() { //act var result = await dailyReportService.GetAsync(idWell, fakeDailyReport.Date, CancellationToken.None); //assert Assert.Single(result.ProcessMapWellDrillingBlock); var processMapWellDrillingRecord = result.ProcessMapWellDrillingBlock.Single(); Assert.Equal(fakeProcessMapReportWellDrilling.DrillingMode, processMapWellDrillingRecord.DrillingMode); Assert.Equal(fakeProcessMapReportWellDrilling.Rop.Plan, processMapWellDrillingRecord.Rop.Plan); Assert.Equal(fakeProcessMapReportWellDrilling.Rop.Fact, processMapWellDrillingRecord.Rop.Fact); Assert.Equal(fakeProcessMapReportWellDrilling.DeltaDepth, processMapWellDrillingRecord.WellBoreDepth); Assert.Equal(fakeProcessMapReportWellDrilling.DrilledTime, processMapWellDrillingRecord.MechDrillingHours); } [Fact] public async Task GetAsync_ShouldReturn_UpdatedSubsystemBlock() { //arrange fakeDailyReport.SubsystemBlock = fakeSubsystemBlock; //act var result = await dailyReportService.GetAsync(idDailyReport, fakeDailyReport.Date, CancellationToken.None); //assert Assert.NotNull(result.SubsystemBlock); Assert.Equal(2, result.SubsystemBlock?.Subsystems.Count()); var subsystemRecord0 = result.SubsystemBlock?.Subsystems.ElementAt(0); Assert.Equal("АвтоСПО", subsystemRecord0?.Name); Assert.Equal(24, subsystemRecord0?.UsagePerDay?.UsedTimeHours); Assert.Equal(1500, subsystemRecord0?.UsagePerDay?.SumDepthInterval); Assert.Equal(15, subsystemRecord0?.UsagePerDay?.KUsage); Assert.Equal(500, subsystemRecord0?.UsagePerWell?.UsedTimeHours); Assert.Equal(3000, subsystemRecord0?.UsagePerWell?.SumDepthInterval); Assert.Equal(100, subsystemRecord0?.UsagePerWell?.KUsage); var subsystemRecord1 = result.SubsystemBlock?.Subsystems.ElementAt(1); Assert.Equal("АПД", subsystemRecord1?.Name); Assert.Equal(200, subsystemRecord1?.UsagePerDay?.UsedTimeHours); Assert.Equal(250, subsystemRecord1?.UsagePerDay?.SumDepthInterval); Assert.Equal(30, subsystemRecord1?.UsagePerDay?.KUsage); Assert.Equal(200, subsystemRecord1?.UsagePerWell?.UsedTimeHours); Assert.Equal(250, subsystemRecord1?.UsagePerWell?.SumDepthInterval); Assert.Equal(30, subsystemRecord1?.UsagePerWell?.KUsage); } [Fact] public async Task GetAsync_ShouldReturn_FictiveDailyReport() { //arrange var expectedCount = fakeLastFactWellOperation.DateStart.Day - fakeFirstFactWellOperation.DateStart.Day; //act var result = await dailyReportService.GetAsync(idWell, new FileReportRequest(), CancellationToken.None); //assert Assert.Equal(expectedCount, result.Count); } [Theory] [MemberData(nameof(FactWellOperationDatesRange))] public async Task GetDatesRangeAsync_ShouldReturn_DateRangeByFactWellOperations(DatesRangeDto datesRange) { //arrange wellOperationRepositoryMock.GetDatesRangeAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(datesRange); //act var result = await wellOperationRepositoryMock.GetDatesRangeAsync(idWell, WellOperation.IdOperationTypeFact, CancellationToken.None); //assert Assert.NotNull(result); Assert.True(result.From <= result.To); Assert.True(result.To < DateTimeOffset.UtcNow); } public static IEnumerable DateDailyReport() { yield return new object[] { new DateOnly(2090, 01, 01), }; yield return new object[] { new DateOnly(2000, 01, 01) }; } public static IEnumerable FactWellOperationDatesRange() { yield return new object[] { new DatesRangeDto { From = new DateTime(2023, 11, 1), To = new DateTime(2023, 11, 9) } }; yield return new object[] { new DatesRangeDto { From = new DateTime(2023, 11, 1), To = new DateTime(2023, 11, 1) } }; yield return new object[] { new DatesRangeDto { From = DateTime.UtcNow, To = DateTime.UtcNow } }; yield return new object[] { new DatesRangeDto { From = new DateTime(2023, 11, 1), To = new DateTime(2023, 11, 11) } }; } }