using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using DD.Persistence.Database.Model; using DD.Persistence.Models; using DD.Persistence.Models.Requests; using Xunit; using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client; namespace DD.Persistence.IntegrationTests.Controllers; public class ChangeLogControllerTest : BaseIntegrationTest { private readonly IChangeLogClient client; private static readonly Random generatorRandomDigits = new(); public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory) { var persistenceClientFactory = scope.ServiceProvider .GetRequiredService(); client = persistenceClientFactory.GetChangeLogClient(); } [Fact] public async Task ClearAndInsertRange_InEmptyDb() { // arrange dbContext.CleanupDbSet(); var idDiscriminator = Guid.NewGuid(); var dtos = Generate(2); // act var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken()); // assert Assert.Equal(2, result); } [Fact] public async Task ClearAndInsertRange_InNotEmptyDb() { // arrange var insertedCount = 10; var createdResult = CreateChangeLogItems(insertedCount, (-15, 15)); var idDiscriminator = createdResult.Item1; var dtos = createdResult.Item2.Select(e => e.Adapt()); // act var result = await client.ClearAndAddRange(idDiscriminator, dtos, new CancellationToken()); // assert Assert.Equal(insertedCount*2, result); } [Fact] public async Task Add_returns_success() { // arrange var count = 1; var idDiscriminator = Guid.NewGuid(); var dtos = Generate(count); var dto = dtos.FirstOrDefault()!; // act var result = await client.Add(idDiscriminator, dto, new CancellationToken()); // assert Assert.Equal(count, result); } [Fact] public async Task AddRange_returns_success() { // arrange var count = 3; var idDiscriminator = Guid.NewGuid(); var dtos = Generate(count); // act var result = await client.AddRange(idDiscriminator, dtos, new CancellationToken()); // assert Assert.Equal(count, result); } [Fact] public async Task Update_returns_success() { // arrange dbContext.CleanupDbSet(); var idDiscriminator = Guid.NewGuid(); var dtos = Generate(1); var dto = dtos.FirstOrDefault()!; var result = await client.Add(idDiscriminator, dto, new CancellationToken()); var entity = dbContext.ChangeLog .Where(x => x.IdDiscriminator == idDiscriminator) .FirstOrDefault(); dto = entity.Adapt(); dto.DepthEnd += 10; // act result = await client.Update(dto, new CancellationToken()); // assert Assert.Equal(2, result); var dateBegin = DateTimeOffset.UtcNow.AddDays(-1); var dateEnd = DateTimeOffset.UtcNow.AddDays(1); var changeLogResult = await client.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, new CancellationToken()); Assert.NotNull(changeLogResult); var obsoleteDto = changeLogResult .Where(e => e.Obsolete.HasValue) .FirstOrDefault(); var activeDto = changeLogResult .Where(e => !e.Obsolete.HasValue) .FirstOrDefault(); if (obsoleteDto == null || activeDto == null) { Assert.Fail(); return; } Assert.Equal(activeDto.Id, obsoleteDto.IdNext); } [Fact] public async Task UpdateRange_returns_success() { // arrange var count = 2; var dtos = Generate(count); var entities = dtos.Select(d => d.Adapt()).ToArray(); dbContext.ChangeLog.AddRange(entities); dbContext.SaveChanges(); dtos = entities.Select(c => new DataWithWellDepthAndSectionDto() { DepthEnd = c.DepthEnd + 10, DepthStart = c.DepthStart + 10, Id = c.Id, IdSection = c.IdSection, Value = c.Value }).ToArray(); // act var result = await client.UpdateRange(dtos, new CancellationToken()); // assert Assert.Equal(count * 2, result); } [Fact] public async Task Delete_returns_success() { // arrange var dtos = Generate(1); var dto = dtos.FirstOrDefault()!; var entity = dto.Adapt(); dbContext.ChangeLog.Add(entity); dbContext.SaveChanges(); // act var result = await client.Delete(entity.Id, new CancellationToken()); // assert Assert.Equal(1, result); } [Fact] public async Task DeleteRange_returns_success() { // arrange var count = 10; var dtos = Generate(count); var entities = dtos.Select(d => d.Adapt()).ToArray(); dbContext.ChangeLog.AddRange(entities); dbContext.SaveChanges(); // act var ids = entities.Select(e => e.Id); var result = await client.DeleteRange(ids, new CancellationToken()); // assert Assert.Equal(count, result); } [Fact] public async Task GetDatesRange_returns_success() { // arrange var changeLogItems = CreateChangeLogItems(3, (-15, 15)); var idDiscriminator = changeLogItems.Item1; var entities = changeLogItems.Item2.OrderBy(e => e.Creation); // act var result = await client.GetDatesRange(idDiscriminator, new CancellationToken()); // assert Assert.NotNull(result); var minDate = entities.First().Creation; var maxDate = entities.Last().Creation; var expectedMinDate = minDate.ToUniversalTime().ToString(); var actualMinDate = result.From.ToUniversalTime().ToString(); Assert.Equal(expectedMinDate, actualMinDate); var expectedMaxDate = maxDate.ToUniversalTime().ToString(); var actualMaxDate = result.To.ToUniversalTime().ToString(); Assert.Equal(expectedMaxDate, actualMaxDate); } [Fact] public async Task GetByDate_returns_success() { // arrange dbContext.CleanupDbSet(); //создаем записи var count = 5; var changeLogItems = CreateChangeLogItems(count, (-15, 15)); var idDiscriminator = changeLogItems.Item1; var entities = changeLogItems.Item2; //удаляем все созданные записи за исключением первой и второй //даты 2-х оставшихся записей должны вернуться в методе GetByDate var ids = entities.Select(e => e.Id); var idsToDelete = ids.Skip(2); var deletedCount = await client.DeleteRange(idsToDelete, new CancellationToken()); var filterRequest = new SectionPartRequest() { DepthStart = 0, DepthEnd = 1000, }; var paginationRequest = new PaginationRequest() { Skip = 0, Take = 10, SortSettings = String.Empty, }; var moment = DateTimeOffset.UtcNow.AddDays(16); var result = await client.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, new CancellationToken()); Assert.NotNull(result); var restEntities = entities.Where(e => !idsToDelete.Contains(e.Id)); Assert.Equal(restEntities.Count(), result.Count); var actualIds = restEntities.Select(e => e.Id); var expectedIds = result.Items.Select(e => e.Id); Assert.Equivalent(expectedIds, actualIds); } [Theory] [InlineData(5, -15, 15, -20, 20, 10)] [InlineData(5, -15, -10, -16, -9, 5)] public async Task GetChangeLogForInterval_returns_success( int insertedCount, int daysBeforeNowChangeLog, int daysAfterNowChangeLog, int daysBeforeNowFilter, int daysAfterNowFilter, int changeLogCount) { // arrange dbContext.CleanupDbSet(); //создаем записи var count = insertedCount; var daysRange = (daysBeforeNowChangeLog, daysAfterNowChangeLog); var changeLogItems = CreateChangeLogItems(count, daysRange); var idDiscriminator = changeLogItems.Item1; var entities = changeLogItems.Item2; foreach (var entity in entities) { entity.DepthEnd += 10; } var dtos = entities.Select(e => e.Adapt()).ToArray(); await client.UpdateRange(dtos, new CancellationToken()); //act var dateBegin = DateTimeOffset.UtcNow.AddDays(daysBeforeNowFilter); var dateEnd = DateTimeOffset.UtcNow.AddDays(daysAfterNowFilter); var result = await client.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, new CancellationToken()); //assert Assert.NotNull(result); Assert.Equal(changeLogCount, result.Count()); } private static IEnumerable Generate(int count) { for (int i = 0; i < count; i++) yield return new DataWithWellDepthAndSectionDto() { Value = new Dictionary() { { "Key", 1 } }, DepthStart = generatorRandomDigits.Next(1, 5), DepthEnd = generatorRandomDigits.Next(5, 15), Id = Guid.NewGuid(), IdSection = Guid.NewGuid() }; } private (Guid, ChangeLog[]) CreateChangeLogItems(int count, (int, int) daysRange) { var minDayCount = daysRange.Item1; var maxDayCount = daysRange.Item2; Guid idDiscriminator = Guid.NewGuid(); var dtos = Generate(count); var entities = dtos.Select(d => { var entity = d.Adapt(); entity.IdDiscriminator = idDiscriminator; entity.Creation = DateTimeOffset.UtcNow.AddDays(generatorRandomDigits.Next(minDayCount, maxDayCount)); return entity; }).ToArray(); dbContext.ChangeLog.AddRange(entities); dbContext.SaveChanges(); return (idDiscriminator, entities); } }