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

378 lines
14 KiB
C#
Raw Normal View History

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)
.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.ObsoletedChangeLogCount);
Assert.Equal(1, stat0.CommitCount);
var stat1 = statistics.First(s => s.Date == day1);
Assert.Equal(inserted1, stat1.CreatedChangeLogCount);
Assert.Equal(0, stat1.ObsoletedChangeLogCount);
Assert.Equal(1, stat1.CommitCount);
var stat2 = statistics.First(s => s.Date == day2);
Assert.Equal(inserted0, stat2.CreatedChangeLogCount);
Assert.Equal(inserted0 + 1, stat2.ObsoletedChangeLogCount);
Assert.Equal(2, stat2.CommitCount);
}
private static IEnumerable<ChangeLogCreateRequest> GenerateChangeLogCreateRequest(int count)
{
for (int i = 0; i < count; i++)
yield return new ChangeLogCreateRequest()
{
Value = new Dictionary<string, object>()
{
{ "Key", random.NextDouble() }
}
};
}
}