persistence/DD.Persistence.IntegrationTests/Controllers/ChangeLogControllerTest.cs

444 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.ChangeLog;
using DD.Persistence.Models.Requests;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using UuidExtensions;
using Xunit;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace DD.Persistence.IntegrationTests.Controllers;
public class ChangeLogControllerTest : BaseIntegrationTest
{
private readonly IChangeLogClient client;
private readonly PaginationRequest paginationRequest;
private static readonly Random random = new();
public ChangeLogControllerTest(WebAppFactoryFixture factory) : base(factory)
{
var refitClientFactory = scope.ServiceProvider
.GetRequiredService<IRefitClientFactory<IRefitChangeLogClient>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<ChangeLogClient>>();
client = scope.ServiceProvider
.GetRequiredService<IChangeLogClient>();
paginationRequest = new PaginationRequest()
{
Skip = 0,
Take = 10,
SortSettings = string.Empty,
};
}
[Fact]
public async Task ClearAndInsertRange()
{
// arrange
var insertedCount = 10;
var idDiscriminator = Guid.NewGuid();
var otherOldDtos = GenerateChangeLogCreateRequest(10);
await client.AddRange(Guid.NewGuid(), otherOldDtos, Guid.NewGuid().ToString(), CancellationToken.None);
var oldDtos = GenerateChangeLogCreateRequest(10);
await client.AddRange(idDiscriminator, oldDtos, Guid.NewGuid().ToString(), CancellationToken.None);
var newDtos = GenerateChangeLogCreateRequest(insertedCount);
//act
var result = await client.ClearAndAddRange(idDiscriminator, newDtos, "Добавление новых элементов и очистка старых", CancellationToken.None);
// assert
Assert.Equal(insertedCount * 2, result);
var data = await client.GetByDate(idDiscriminator, DateTimeOffset.Now.AddSeconds(1), new PaginationRequest { Take = 10 * insertedCount }, CancellationToken.None);
Assert.Equal(insertedCount, data.Count);
}
[Fact]
public async Task AddRange_returns_success()
{
// arrange
var count = 3;
var idDiscriminator = Guid.NewGuid();
var dtos = GenerateChangeLogCreateRequest(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
var begin = DateTimeOffset.UtcNow;
var idDiscriminator = Guid.NewGuid();
var dtos = GenerateChangeLogCreateRequest(1);
var original = dtos.First();
var comment = "Создаю 1 элемент";
var result = await client.AddRange(idDiscriminator, [original], comment, CancellationToken.None);
var query = dbContext.Set<ChangeLog>()
.Include(x => x.CreatedCommit)
.Where(x => x.CreatedCommit.DiscriminatorId == idDiscriminator);
var entity = await query.FirstAsync();
var modified = entity.Adapt<ChangeLogBaseDto>();
var key = modified.Value.First().Key;
modified.Value[key] = random.NextDouble();
// act
comment = "Обновляю 1 элемент";
result = await client.UpdateRange(idDiscriminator, [modified], comment, CancellationToken.None);
// assert
Assert.Equal(2, result);
var now = DateTimeOffset.UtcNow.AddSeconds(1);
var changeLogResult = await client.GetChangeLogForInterval(idDiscriminator, begin, now, new CancellationToken());
Assert.NotNull(changeLogResult);
var obsoleteDto = changeLogResult
.Where(e => e.Obsolete.HasValue)
.First();
var activeDto = changeLogResult
.Where(e => !e.Obsolete.HasValue)
.OrderByDescending(e => e.Creation)
.First();
Assert.Equal(activeDto.Id, obsoleteDto.IdNext);
}
[Fact]
public async Task UpdateRange_returns_success()
{
var count = 2;
var idDiscriminator = Guid.NewGuid();
var dtos = GenerateChangeLogCreateRequest(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(idDiscriminator, paginatedResult.Items, comment, CancellationToken.None);
// assert
Assert.Equal(count * 2, result);
}
[Fact]
public async Task DeleteRange_returns_success()
{
// arrange
var insertedCount = 10;
var idDiscriminator = Guid.NewGuid();
var otherOldDtos = GenerateChangeLogCreateRequest(10);
await client.AddRange(Guid.NewGuid(), otherOldDtos, Guid.NewGuid().ToString(), CancellationToken.None);
var oldDtos = GenerateChangeLogCreateRequest(10);
await client.AddRange(idDiscriminator, oldDtos, Guid.NewGuid().ToString(), CancellationToken.None);
var existing = await client.GetByDate(idDiscriminator, DateTimeOffset.UtcNow.AddSeconds(1), new PaginationRequest { Take= 100*insertedCount}, CancellationToken.None);
var ids = existing.Items.Select(e => e.Id);
// act
var result = await client.DeleteRange(idDiscriminator, ids, "Удаление нескольких записей", CancellationToken.None);
// assert
Assert.Equal(insertedCount, result);
var items = await dbContext.Set<ChangeLog>()
.Where(e=> ids.Contains(e.Id))
.ToArrayAsync(CancellationToken.None);
Assert.Equal(insertedCount, items.Count());
Assert.All(items, i => Assert.NotNull(i.IdObsoletedCommit));
}
static ChangeLogCommit GenerateCommit(Guid discriminatorId, DateTimeOffset creation)
=> GenerateCommit(discriminatorId, Guid.NewGuid(), creation);
static ChangeLogCommit GenerateCommit(Guid discriminatorId, Guid userId, DateTimeOffset creation)
=> new ChangeLogCommit
{
Id = Guid.NewGuid(),
DiscriminatorId = discriminatorId,
IdAuthor = userId,
Creation = creation,
Comment = Guid.NewGuid().ToString(),
};
static IEnumerable<ChangeLog> GenerateChangeLog(int count, ChangeLogCommit createCommit)
=> GenerateChangeLog(count, createCommit, null, null);
static IEnumerable<ChangeLog> GenerateChangeLog(int count, ChangeLogCommit createCommit, ChangeLogCommit? obsoleteCommit, Guid? idNext)
{
for (var i = 0; i< count; i++)
{
yield return new ChangeLog
{
Id = Guid.NewGuid(),
CreatedCommit = createCommit,
IdCreatedCommit = createCommit.Id,
ObsoletedCommit = obsoleteCommit,
IdObsoletedCommit = obsoleteCommit?.Id,
IdNext = idNext,
Value = new Dictionary<string, object> { { "Guid.NewGuid()", random.NextDouble() } }
};
}
}
static ChangeLogCommit GenerateCommitWithNewData(Guid discriminatorId, DateTimeOffset creation, int count)
{
var commit = GenerateCommit(discriminatorId, creation);
commit.ChangeLogCreatedItems = GenerateChangeLog(count, commit).ToList();
return commit;
}
async Task<ChangeLogCommit> SeedCommitWithNewData(Guid discriminatorId, DateTimeOffset creation, int count)
{
var data = GenerateCommitWithNewData(discriminatorId, creation, count);
dbContext.Set<ChangeLogCommit>().Add(data);
await dbContext.SaveChangesAsync();
return data;
}
[Fact]
public async Task GetDatesRange_returns_success()
{
//arrange
var dateMin = DateTimeOffset.UtcNow.AddDays(-1);
var dateMax = DateTimeOffset.UtcNow;
var dateMid = dateMin + 0.5 * (dateMax - dateMin);
var idDiscriminator = Guid.NewGuid();
var idOtherDiscriminator = Guid.NewGuid();
var count = 15;
await SeedCommitWithNewData(idDiscriminator, dateMin, count);
await SeedCommitWithNewData(idDiscriminator, dateMid, count);
await SeedCommitWithNewData(idDiscriminator, dateMax, count);
await SeedCommitWithNewData(idOtherDiscriminator, dateMin.AddDays(-1), count);
// act
var result = await client.GetDatesRange(idDiscriminator, CancellationToken.None);
// assert
Assert.NotNull(result);
Assert.Equal(dateMin, result.From, TimeSpan.FromSeconds(1));
Assert.Equal(dateMax, result.To, TimeSpan.FromSeconds(1));
}
[Fact]
public async Task GetByDate_returns_success()
{
// arrange
var dbSetCommit = dbContext.Set<ChangeLogCommit>();
var dbSet = dbContext.Set<ChangeLog>();
var idDiscriminator = Guid.NewGuid();
var date = DateTimeOffset.UtcNow;
var expected = 10;
var skip = 2;
var take = skip + 2;
var count = expected + take;
var commit = GenerateCommit(idDiscriminator, date);
dbSetCommit.Add(commit);
var commitData = GenerateChangeLog(count, commit);
dbSet.AddRange(commitData);
await dbContext.SaveChangesAsync(CancellationToken.None);
var dataWithIds = await dbSet
.Where(e=>e.CreatedCommit.DiscriminatorId == idDiscriminator)
.AsNoTracking()
.ToArrayAsync(CancellationToken.None);
var itemsToDelete = dataWithIds.Skip(skip).Take(take);
var idsToDelete = itemsToDelete.Select(x => x.Id).ToArray();
// act
var deletedCount = await client.DeleteRange(idDiscriminator, idsToDelete, "Удаление нескольких записей", CancellationToken.None);
// assert
var moment = DateTimeOffset.UtcNow.AddSeconds(1);
var result = await client.GetByDate(idDiscriminator, moment, new() { Take = count *100}, new CancellationToken());
Assert.NotNull(result);
Assert.Equal(expected, result.Items.Count());
}
[Fact]
public async Task GetChangeLogForInterval_returns_success()
{
// arrange
var dateMin = DateTimeOffset.UtcNow.AddDays(- 11);
var dateMax = DateTimeOffset.UtcNow;
var dateMid = dateMin + 0.5 * (dateMax - dateMin);
var idDiscriminator = Guid.NewGuid();
var idOtherDiscriminator = Guid.NewGuid();
var count = 17;
var commitMin = await SeedCommitWithNewData(idDiscriminator, dateMin, count);
var commitMid = await SeedCommitWithNewData(idDiscriminator, dateMid, count);
await SeedCommitWithNewData(idDiscriminator, dateMax, count);
await SeedCommitWithNewData(idOtherDiscriminator, dateMin.AddDays(-1), count);
var dateBegin = commitMin.Creation;
var dateEnd = commitMid.Creation.AddSeconds(1);
var expectedCount = commitMin.ChangeLogCreatedItems.Count()
+ commitMid.ChangeLogCreatedItems.Count();
//act
var result = await client.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, CancellationToken.None);
//assert
Assert.Equal(expectedCount, result.Count());
}
[Fact]
public async Task GetStatistics_returns_success()
{
// arrange
var discriminatorId = Guid.NewGuid();
// создаем записи
var date0 = DateTimeOffset.UtcNow.AddDays(-17);
var day0 = new DateOnly(date0.Year, date0.Month, date0.Day);
var inserted0 = 17;
var commit0 = await SeedCommitWithNewData(discriminatorId, date0, inserted0);
// создаем еще записи
var date1 = DateTimeOffset.UtcNow.AddDays(-7);
var day1 = new DateOnly(date1.Year, date1.Month, date1.Day);
var inserted1 = inserted0 + 5;
var commit1 = await SeedCommitWithNewData(discriminatorId, date1, inserted1);
// создаем еще записи с новым дискриминатором
await SeedCommitWithNewData(Guid.NewGuid(), date1, 17);
// обновим
var date2 = DateTimeOffset.UtcNow;
var day2 = new DateOnly(date2.Year, date2.Month, date2.Day);
var updated = commit0.ChangeLogCreatedItems.Select(i => new ChangeLogBaseDto { Id = i.Id, Value = i.Value });
await client.UpdateRange(commit0.DiscriminatorId, updated, Guid.NewGuid().ToString(), CancellationToken.None);
// удалим из коммита
var idToDelete = commit1.ChangeLogCreatedItems.First().Id;
await client.DeleteRange(commit1.DiscriminatorId, [idToDelete], Guid.NewGuid().ToString(), CancellationToken.None);
//act
var request = new ChangeLogQuery()
{
DiscriminatorId = commit0.DiscriminatorId,
UserId = null
};
var statistics = await client.GetStatistics(request, CancellationToken.None);
//assert
Assert.Equal(3, statistics.Count());
var stat0 = statistics.First(s => s.Date == day0);
Assert.Equal(inserted0, stat0.CreatedChangeLogCount);
Assert.Equal(0, stat0.ObsoletedCount);
Assert.Equal(1, stat0.CommitCount);
var stat1 = statistics.First(s => s.Date == day1);
Assert.Equal(inserted1, stat1.CreatedChangeLogCount);
Assert.Equal(0, stat1.ObsoletedCount);
Assert.Equal(1, stat1.CommitCount);
var stat2 = statistics.First(s => s.Date == day2);
Assert.Equal(inserted0, stat2.CreatedChangeLogCount);
Assert.Equal(inserted0 + 1, stat2.ObsoletedCount);
Assert.Equal(2, stat2.CommitCount);
}
[Fact]
public async Task GetHistory_returns_success()
{
// arrange
var discriminatorId = Guid.NewGuid();
// создаем записи
var date0 = DateTimeOffset.UtcNow.AddDays(-17);
var inserted0 = 17;
var commit0 = await SeedCommitWithNewData(discriminatorId, date0, inserted0);
// обновим
var date2 = DateTimeOffset.UtcNow;
var updated = commit0.ChangeLogCreatedItems.Skip(1).Select(i => new ChangeLogBaseDto { Id = i.Id, Value = i.Value });
await client.UpdateRange(commit0.DiscriminatorId, updated, Guid.NewGuid().ToString(), CancellationToken.None);
// удалим из коммита
var idToDelete = commit0.ChangeLogCreatedItems.First().Id;
await client.DeleteRange(commit0.DiscriminatorId, [idToDelete], Guid.NewGuid().ToString(), CancellationToken.None);
var request = new ChangeLogQuery()
{
DiscriminatorId = commit0.DiscriminatorId,
UserId = null
};
var history = await client.GetHistory(request, CancellationToken.None);
Assert.Equal(3, history.Count());
var items = history.OrderBy(e => e.Creation);
var firstItem = items.First();
Assert.Equal(date0.DateTime.ToString(), firstItem.Creation.DateTime.ToString());
Assert.Equal(inserted0, firstItem.ChangeLogCreatedItems.Count());
Assert.Empty(firstItem.ChangeLogObsoletedItems);
var middleItem = items.Skip(1).Take(1).First();
Assert.Equal(date2.DateTime.ToString(), middleItem.Creation.DateTime.ToString());
Assert.Equal(updated.Count(), middleItem.ChangeLogObsoletedItems.Count());
Assert.Equal(updated.Count(), middleItem.ChangeLogCreatedItems.Count());
var lastItem = items.Last();
Assert.Equal(date2.DateTime.ToString(), lastItem.Creation.DateTime.ToString());
Assert.Single(lastItem.ChangeLogObsoletedItems);
//тест случая, когда данных за указанный период нет
request = new ChangeLogQuery()
{
DiscriminatorId = commit0.DiscriminatorId,
UserId = null,
GeDate = DateTimeOffset.UtcNow.AddMinutes(1),
LeDate = DateTimeOffset.UtcNow.AddDays(10),
};
history = await client.GetHistory(request, CancellationToken.None);
Assert.Empty(history);
//тест случая, когда данные за указанный период есть
request = new ChangeLogQuery()
{
DiscriminatorId = commit0.DiscriminatorId,
UserId = null,
GeDate = DateTimeOffset.UtcNow.AddDays(-17).AddMinutes(-10),
LeDate = DateTimeOffset.UtcNow.AddDays(-1),
};
history = await client.GetHistory(request, CancellationToken.None);
Assert.Single(history);
var createdChangeLogs = history.First().ChangeLogCreatedItems;
Assert.Equal(17, createdChangeLogs.Count());
}
private static IEnumerable<IDictionary<string, object>> GenerateChangeLogCreateRequest(int count)
{
for (int i = 0; i < count; i++)
yield return new Dictionary<string, object>()
{
{ "Key", random.NextDouble() }
};
}
}