233 lines
6.9 KiB
C#
233 lines
6.9 KiB
C#
using FluentAssertions;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Workflow.Application.Features.WorkflowDefinitions.Commands;
|
|
using Workflow.Domain.Entities;
|
|
using Workflow.Domain.Enums;
|
|
using Workflow.Domain.Exceptions;
|
|
using Workflow.Infrastructure.Persistence;
|
|
using Xunit;
|
|
|
|
namespace Workflow.Tests.Handlers;
|
|
|
|
public class EdgeCommandHandlerTests
|
|
{
|
|
private static WorkflowDbContext CreateDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<WorkflowDbContext>()
|
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
|
.Options;
|
|
return new WorkflowDbContext(options);
|
|
}
|
|
|
|
private static async Task<(WorkflowDefinition Definition, WorkflowNode SourceNode, WorkflowNode TargetNode)> SeedDefinitionWithNodes(WorkflowDbContext db)
|
|
{
|
|
var definition = new WorkflowDefinition
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Workflow",
|
|
Code = $"test-wf-{Guid.NewGuid():N}",
|
|
Status = DefinitionStatus.Draft,
|
|
Version = 1
|
|
};
|
|
db.WorkflowDefinitions.Add(definition);
|
|
|
|
var sourceNode = new WorkflowNode
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
DefinitionId = definition.Id,
|
|
NodeType = NodeType.Start,
|
|
Name = "Start",
|
|
PositionX = 0,
|
|
PositionY = 0
|
|
};
|
|
var targetNode = new WorkflowNode
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
DefinitionId = definition.Id,
|
|
NodeType = NodeType.End,
|
|
Name = "End",
|
|
PositionX = 300,
|
|
PositionY = 0
|
|
};
|
|
db.WorkflowNodes.AddRange(sourceNode, targetNode);
|
|
await db.SaveChangesAsync();
|
|
|
|
return (definition, sourceNode, targetNode);
|
|
}
|
|
|
|
#region CreateEdge
|
|
|
|
[Fact]
|
|
public async Task CreateEdge_ReturnsEdgeDto()
|
|
{
|
|
// Arrange
|
|
await using var db = CreateDbContext();
|
|
var (definition, sourceNode, targetNode) = await SeedDefinitionWithNodes(db);
|
|
|
|
var handler = new CreateEdgeCommandHandler(db);
|
|
var command = new CreateEdgeCommand(
|
|
DefinitionId: definition.Id,
|
|
SourceNodeId: sourceNode.Id,
|
|
TargetNodeId: targetNode.Id,
|
|
EdgeType: EdgeType.Normal,
|
|
Label: "Normal Flow",
|
|
Condition: null,
|
|
Order: 1
|
|
);
|
|
|
|
// Act
|
|
var result = await handler.Handle(command, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.SourceNodeId.Should().Be(sourceNode.Id);
|
|
result.TargetNodeId.Should().Be(targetNode.Id);
|
|
result.EdgeType.Should().Be(EdgeType.Normal);
|
|
result.Label.Should().Be("Normal Flow");
|
|
result.Condition.Should().BeNull();
|
|
result.Order.Should().Be(1);
|
|
result.Id.Should().NotBeEmpty();
|
|
|
|
var entity = await db.WorkflowEdges.FindAsync(result.Id);
|
|
entity.Should().NotBeNull();
|
|
entity!.DefinitionId.Should().Be(definition.Id);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateEdge_WithMissingSource_ThrowsNotFoundException()
|
|
{
|
|
// Arrange
|
|
await using var db = CreateDbContext();
|
|
var (definition, _, targetNode) = await SeedDefinitionWithNodes(db);
|
|
|
|
var handler = new CreateEdgeCommandHandler(db);
|
|
var command = new CreateEdgeCommand(
|
|
DefinitionId: definition.Id,
|
|
SourceNodeId: Guid.NewGuid(), // Non-existent source
|
|
TargetNodeId: targetNode.Id,
|
|
EdgeType: EdgeType.Normal,
|
|
Label: null,
|
|
Condition: null,
|
|
Order: 0
|
|
);
|
|
|
|
// Act
|
|
var act = () => handler.Handle(command, CancellationToken.None);
|
|
|
|
// Assert
|
|
await act.Should().ThrowAsync<NotFoundException>();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateEdge
|
|
|
|
[Fact]
|
|
public async Task UpdateEdge_UpdatesLabelAndCondition()
|
|
{
|
|
// Arrange
|
|
await using var db = CreateDbContext();
|
|
var (definition, sourceNode, targetNode) = await SeedDefinitionWithNodes(db);
|
|
|
|
var edgeId = Guid.NewGuid();
|
|
db.WorkflowEdges.Add(new WorkflowEdge
|
|
{
|
|
Id = edgeId,
|
|
DefinitionId = definition.Id,
|
|
SourceNodeId = sourceNode.Id,
|
|
TargetNodeId = targetNode.Id,
|
|
EdgeType = EdgeType.Normal,
|
|
Label = "Old Label",
|
|
Condition = null,
|
|
Order = 0
|
|
});
|
|
await db.SaveChangesAsync();
|
|
|
|
var handler = new UpdateEdgeCommandHandler(db);
|
|
var command = new UpdateEdgeCommand(
|
|
EdgeId: edgeId,
|
|
EdgeType: EdgeType.Approved,
|
|
Label: "Approved Path",
|
|
Condition: "amount > 5000",
|
|
Order: 2
|
|
);
|
|
|
|
// Act
|
|
var result = await handler.Handle(command, CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.Id.Should().Be(edgeId);
|
|
result.Label.Should().Be("Approved Path");
|
|
result.Condition.Should().Be("amount > 5000");
|
|
result.EdgeType.Should().Be(EdgeType.Approved);
|
|
result.Order.Should().Be(2);
|
|
result.SourceNodeId.Should().Be(sourceNode.Id);
|
|
result.TargetNodeId.Should().Be(targetNode.Id);
|
|
|
|
var entity = await db.WorkflowEdges.FindAsync(edgeId);
|
|
entity.Should().NotBeNull();
|
|
entity!.Label.Should().Be("Approved Path");
|
|
entity.Condition.Should().Be("amount > 5000");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateEdge_WithMissingEdge_ThrowsNotFoundException()
|
|
{
|
|
// Arrange
|
|
await using var db = CreateDbContext();
|
|
var handler = new UpdateEdgeCommandHandler(db);
|
|
var command = new UpdateEdgeCommand(
|
|
EdgeId: Guid.NewGuid(),
|
|
EdgeType: EdgeType.Normal,
|
|
Label: "Ghost",
|
|
Condition: null,
|
|
Order: 0
|
|
);
|
|
|
|
// Act
|
|
var act = () => handler.Handle(command, CancellationToken.None);
|
|
|
|
// Assert
|
|
await act.Should().ThrowAsync<NotFoundException>();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DeleteEdge
|
|
|
|
[Fact]
|
|
public async Task DeleteEdge_RemovesEdge()
|
|
{
|
|
// Arrange
|
|
await using var db = CreateDbContext();
|
|
var (definition, sourceNode, targetNode) = await SeedDefinitionWithNodes(db);
|
|
|
|
var edgeId = Guid.NewGuid();
|
|
db.WorkflowEdges.Add(new WorkflowEdge
|
|
{
|
|
Id = edgeId,
|
|
DefinitionId = definition.Id,
|
|
SourceNodeId = sourceNode.Id,
|
|
TargetNodeId = targetNode.Id,
|
|
EdgeType = EdgeType.Normal,
|
|
Label = "To Delete",
|
|
Condition = null,
|
|
Order = 0
|
|
});
|
|
await db.SaveChangesAsync();
|
|
|
|
var handler = new DeleteEdgeCommandHandler(db);
|
|
var command = new DeleteEdgeCommand(EdgeId: edgeId);
|
|
|
|
// Act
|
|
await handler.Handle(command, CancellationToken.None);
|
|
|
|
// Assert
|
|
var edges = await db.WorkflowEdges.ToListAsync();
|
|
edges.Should().BeEmpty();
|
|
}
|
|
|
|
#endregion
|
|
}
|