107 lines
3.6 KiB
C#
107 lines
3.6 KiB
C#
using FluentAssertions;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NSubstitute;
|
|
using Workflow.Application.BuildFlow.Common.Services;
|
|
using Workflow.Application.BuildFlow.Imports.Services;
|
|
using Workflow.Application.Form.Aggregates;
|
|
using Workflow.Application.Form.Derivation;
|
|
using Workflow.Application.Form.Schema;
|
|
using Xunit;
|
|
|
|
namespace BuildFlow.Workflow.Tests.Performance;
|
|
|
|
/// <summary>
|
|
/// 导入批次写入、错误隔离和确定性实例 ID 测试。
|
|
/// </summary>
|
|
public class ImportBatchWriterTests
|
|
{
|
|
[Fact]
|
|
public async Task WritesValidRowsAndReturnsInvalidRowsWithoutPerRowAggregateCalls()
|
|
{
|
|
await using var db = CreateDbContext();
|
|
var aggregates = Substitute.For<IFormAggregateRefreshService>();
|
|
var writer = new ImportBatchWriter(
|
|
db,
|
|
new FormValueDerivationService([], []),
|
|
aggregates);
|
|
var formDefinitionId = Guid.NewGuid();
|
|
var prepared = PreparedFormSchema.Create(Schema);
|
|
|
|
var result = await writer.WriteAsync(
|
|
Guid.NewGuid(),
|
|
formDefinitionId,
|
|
prepared,
|
|
[
|
|
new ImportBatchItem(0, ValidRow(2, "first")),
|
|
new ImportBatchItem(
|
|
1,
|
|
new ExcelParsedRow(
|
|
3,
|
|
"{}",
|
|
[new ExcelCellError("name", "必填字段为空")])),
|
|
new ImportBatchItem(2, ValidRow(4, "third")),
|
|
],
|
|
CancellationToken.None);
|
|
|
|
result.SuccessCount.Should().Be(2);
|
|
result.Errors.Should().ContainSingle(x => x.Row == 3);
|
|
(await db.FormData.CountAsync()).Should().Be(2);
|
|
await aggregates.Received(1).RefreshBatchAsync(
|
|
formDefinitionId,
|
|
Arg.Is<IReadOnlyCollection<Guid>>(ids => ids.Count == 2),
|
|
Arg.Any<CancellationToken>());
|
|
await aggregates.Received(1).RefreshAffectedBatchAsync(
|
|
formDefinitionId,
|
|
Arg.Is<IReadOnlyCollection<Guid>>(ids => ids.Count == 2),
|
|
Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UsesFullJobAndRowIndexForDeterministicInstanceIds()
|
|
{
|
|
await using var db = CreateDbContext();
|
|
var aggregates = Substitute.For<IFormAggregateRefreshService>();
|
|
var writer = new ImportBatchWriter(
|
|
db,
|
|
new FormValueDerivationService([], []),
|
|
aggregates);
|
|
|
|
await writer.WriteAsync(
|
|
Guid.Parse("8e6fcacf-3bc1-4d5e-84c4-92be4208855c"),
|
|
Guid.NewGuid(),
|
|
PreparedFormSchema.Create(Schema),
|
|
[
|
|
new ImportBatchItem(1, ValidRow(2, "first")),
|
|
new ImportBatchItem(65537, ValidRow(3, "second")),
|
|
],
|
|
CancellationToken.None);
|
|
|
|
var instanceIds = await db.FormData
|
|
.Select(x => x.InstanceId)
|
|
.ToListAsync();
|
|
instanceIds.Should().OnlyHaveUniqueItems();
|
|
}
|
|
|
|
private static WorkflowDbContext CreateDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<WorkflowDbContext>()
|
|
.UseInMemoryDatabase($"import-batch-writer-{Guid.NewGuid():N}")
|
|
.Options;
|
|
var db = new WorkflowDbContext(options);
|
|
db.SavingChanges += AuditStub.OnSave;
|
|
return db;
|
|
}
|
|
|
|
private static ExcelParsedRow ValidRow(int rowNumber, string name)
|
|
=> new(rowNumber, $$"""{"name":"{{name}}"}""", []);
|
|
|
|
private const string Schema = """
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string", "required": true, "x-component": "Input" }
|
|
}
|
|
}
|
|
""";
|
|
}
|