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; /// /// 导入批次写入、错误隔离和确定性实例 ID 测试。 /// public class ImportBatchWriterTests { [Fact] public async Task WritesValidRowsAndReturnsInvalidRowsWithoutPerRowAggregateCalls() { await using var db = CreateDbContext(); var aggregates = Substitute.For(); 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>(ids => ids.Count == 2), Arg.Any()); await aggregates.Received(1).RefreshAffectedBatchAsync( formDefinitionId, Arg.Is>(ids => ids.Count == 2), Arg.Any()); } [Fact] public async Task UsesFullJobAndRowIndexForDeterministicInstanceIds() { await using var db = CreateDbContext(); var aggregates = Substitute.For(); 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() .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" } } } """; }