using DD.Persistence.Client; using DD.Persistence.Client.Clients; using DD.Persistence.Client.Clients.Interfaces; using DD.Persistence.Client.Clients.Interfaces.Refit; using DD.Persistence.Database.Entity; using DD.Persistence.Models; using DD.Persistence.Models.Requests; using Mapster; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Xunit; namespace DD.Persistence.IntegrationTests.Controllers; public class ChangeLogControllerTest : BaseIntegrationTest { private readonly IChangeLogClient client; private readonly PaginationRequest paginationRequest; private static readonly Random generatorRandomDigits = new(); public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory) { var refitClientFactory = scope.ServiceProvider .GetRequiredService>(); var logger = scope.ServiceProvider.GetRequiredService>(); client = scope.ServiceProvider .GetRequiredService(); paginationRequest = new PaginationRequest() { Skip = 0, Take = 10, SortSettings = String.Empty, }; } [Fact] public async Task ClearAndInsertRange_InNotEmptyDb() { // arrange var insertedCount = 10; var newEntitiesData = await CreateAndReturnNewDtos(insertedCount, (-15, -1)); var idDiscriminator = newEntitiesData.Item1; var dtos = newEntitiesData.Item2; //act var result = await client.ClearAndAddRange(idDiscriminator, dtos, "Добавление новых элементов и очистка старых", CancellationToken.None); // assert Assert.Equal(insertedCount * 2, result); } [Fact] public async Task AddRange_returns_success() { // arrange var count = 3; var idDiscriminator = Guid.NewGuid(); var dtos = Generate(count); var comment = "Создаю 3 элемента"; // act var result = await client.AddRange(idDiscriminator, dtos, comment, CancellationToken.None); // 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 comment = "Создаю 1 элемент"; var result = await client.AddRange(idDiscriminator, [dto], comment, CancellationToken.None); var entity = dbContext.ChangeLog .Where(x => x.DiscriminatorId == idDiscriminator) .FirstOrDefault(); dto = entity.Adapt(); // act comment = "Обновляю 1 элемент"; result = await client.UpdateRange([dto], comment, CancellationToken.None); // 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() { var count = 2; var idDiscriminator = Guid.NewGuid(); var dtos = Generate(count); var comment = "Создаю 3 элемента"; // act var result = await client.AddRange(idDiscriminator, dtos, comment, CancellationToken.None); var paginatedResult = await client.GetByDate(idDiscriminator, DateTimeOffset.UtcNow.AddDays(1), paginationRequest, CancellationToken.None); // act comment = "Обновляю 3 элемента"; result = await client.UpdateRange(paginatedResult.Items, comment, CancellationToken.None); // assert Assert.Equal(count * 2, result); } [Fact] public async Task DeleteRange_returns_success() { // arrange var insertedCount = 10; var newEntitiesData = await CreateAndReturnNewDtos(insertedCount, (-15, -1)); var idDiscriminator = newEntitiesData.Item1; var dtos = newEntitiesData.Item2; // act var ids = dtos.Select(e => e.Id); var result = await client.DeleteRange(ids, "Удаление нескольких записей", CancellationToken.None); // assert Assert.Equal(insertedCount, result); } [Fact] public async Task GetDatesRange_returns_success() { //arrange var changeLogItems = await CreateAndReturnNewEntities(3, (-15, -1)); var idDiscriminator = changeLogItems.Item1; var entities = changeLogItems.Item2.OrderBy(c => c.Creation); // act var result = await client.GetDatesRange(idDiscriminator, CancellationToken.None); // 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 = await CreateAndReturnNewDtos(count, (-15, -1)); 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, "Удаление нескольких записей", CancellationToken.None); var moment = DateTimeOffset.UtcNow.AddDays(16); var result = await client.GetByDate(idDiscriminator, moment, 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, -5, -20, 20, 10)] [InlineData(5, -15, -10, -16, 9, 10)] 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 = await CreateAndReturnNewDtos(count, daysRange); var idDiscriminator = changeLogItems.Item1; var dtos = changeLogItems.Item2; await client.UpdateRange(dtos, "Обновляем несколько записей", CancellationToken.None); //act var dateBegin = DateTimeOffset.UtcNow.AddDays(daysBeforeNowFilter); var dateEnd = DateTimeOffset.UtcNow.AddDays(daysAfterNowFilter); var result = await client.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, CancellationToken.None); //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 ChangeLogValuesDto() { Value = new Dictionary() { { "Key", 1 } }, Id = Guid.NewGuid() }; } private async Task<(Guid, IEnumerable)> CreateAndReturnNewDtos(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.DiscriminatorId = idDiscriminator; entity.Creation = DateTimeOffset.UtcNow.AddDays(generatorRandomDigits.Next(minDayCount, maxDayCount)); return entity; }).ToArray(); dtos = entities.Select(e => e.Adapt()); // act var result = await client.AddRange(idDiscriminator, dtos, "Добавление элементов", CancellationToken.None); var paginatedResult = await client.GetByDate(idDiscriminator, DateTimeOffset.UtcNow.AddDays(1), paginationRequest, CancellationToken.None); return (idDiscriminator, paginatedResult.Items); } private async Task<(Guid, IEnumerable)> CreateAndReturnNewEntities(int count, (int, int) daysRange) { var commit = new ChangeLogCommit() { Comment = "Комментарий к коммиту", Creation = DateTimeOffset.UtcNow, Id = Guid.NewGuid(), }; dbContext.ChangeLogCommit.Add(commit); await dbContext.SaveChangesAsync(); 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.DiscriminatorId = idDiscriminator; entity.Creation = DateTimeOffset.UtcNow.AddDays(generatorRandomDigits.Next(minDayCount, maxDayCount)); entity.IdCreatedCommit = commit.Id; return entity; }).ToArray(); dbContext.ChangeLog.AddRange(entities); await dbContext.SaveChangesAsync(); return (idDiscriminator, entities); } }