WIP #738 - Add test coverage to replace big test
The large/complex test is now removed, replaced by smaller/simpler unit tests for the individual units in the overall process of getting triggers.
This commit is contained in:
parent
6700ac2402
commit
3943e64c70
|
|
@ -14,7 +14,6 @@ namespace Elsa.Services
|
|||
public ActivityExecutionContextForActivityBlueprintFactory(IServiceProvider serviceProvider)
|
||||
{
|
||||
this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -16,16 +16,32 @@ namespace Elsa.Services
|
|||
/// <returns>A collection of the blueprint's starting activities</returns>
|
||||
public IEnumerable<IActivityBlueprint> GetStartActivities(ICompositeActivityBlueprint compositeActivityBlueprint)
|
||||
{
|
||||
var targetActivityIds = compositeActivityBlueprint.Connections
|
||||
.Select(x => x.Target.Activity?.Id)
|
||||
.Distinct()
|
||||
.ToLookup(x => x);
|
||||
var activityIdsThatAreNotStartingActivities = GetAllActivityIdsWhichHaveInboundConnections(compositeActivityBlueprint);
|
||||
|
||||
var query = from activity in compositeActivityBlueprint.Activities
|
||||
where !targetActivityIds.Contains(activity.Id)
|
||||
where !activityIdsThatAreNotStartingActivities.Contains(activity.Id)
|
||||
select activity;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method gets activities that have inbound connections.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// "Start activities" are those with no inbound connections; IE no workflow connection-target will point to a start activity.
|
||||
/// What this method returns is essentially a blacklist of activity IDs which are not starting activities.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="compositeActivityBlueprint">A composite activity blueprint</param>
|
||||
/// <returns>A lookup of activity IDs which are not starting activities</returns>
|
||||
ILookup<string?,string?> GetAllActivityIdsWhichHaveInboundConnections(ICompositeActivityBlueprint compositeActivityBlueprint)
|
||||
{
|
||||
return compositeActivityBlueprint.Connections
|
||||
.Select(x => x.Target.Activity?.Id)
|
||||
.Distinct()
|
||||
.ToLookup(x => x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.Testing.Shared.AutoFixture.Attributes;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public class ActivityExecutionContextForActivityBlueprintFactoryTests
|
||||
{
|
||||
[Theory(DisplayName = "The CreateActivityExecutionContext method should create a context using the activity blueprint, the workflow execution context, cancellation token and injected service provider."), AutoMoqData]
|
||||
public void CreateActivityExecutionContextCreatesContextUsingBlueprintExecutionContextCancellationTokenAndServiceProvider([AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
IActivityBlueprint activityBlueprint,
|
||||
[OmitOnRecursion] WorkflowExecutionContext workflowExecutionContext,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var sut = new ActivityExecutionContextForActivityBlueprintFactory(serviceProvider);
|
||||
|
||||
var result = sut.CreateActivityExecutionContext(activityBlueprint, workflowExecutionContext, cancellationToken);
|
||||
|
||||
Assert.True(ReferenceEquals(activityBlueprint, result.ActivityBlueprint), "The activity blueprint should be the same");
|
||||
Assert.True(ReferenceEquals(workflowExecutionContext, result.WorkflowExecutionContext), "The workflow execution context should be the same");
|
||||
Assert.True(Equals(cancellationToken, result.CancellationToken), "The cancellation token should be equal");
|
||||
Assert.True(ReferenceEquals(serviceProvider, result.ServiceProvider), "The service provider should be the same");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Elsa.Services.Models;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public class StartActivitiesForCompositeActivityBlueprintProviderTests
|
||||
{
|
||||
[Theory(DisplayName = "The GetStartActivities returns only activities that have no inbound workflow connections"), AutoMoqData]
|
||||
public void GetStartActivitiesReturnsAllActivitiesWhichHaveNoInboundConnections(StartActivitiesForCompositeActivityBlueprintProvider sut,
|
||||
IWorkflowBlueprint workflowBlueprint,
|
||||
IActivityBlueprint activityBlueprint1,
|
||||
IActivityBlueprint activityBlueprint2,
|
||||
IActivityBlueprint activityBlueprint3,
|
||||
IActivityBlueprint activityBlueprint4,
|
||||
string activityBlueprintId1,
|
||||
string activityBlueprintId2,
|
||||
string activityBlueprintId3,
|
||||
string activityBlueprintId4,
|
||||
IConnection connection1,
|
||||
IConnection connection2,
|
||||
ITargetEndpoint endpoint1,
|
||||
ITargetEndpoint endpoint2)
|
||||
{
|
||||
SetupActivitiesWithIds(new () {
|
||||
{activityBlueprintId1, activityBlueprint1},
|
||||
{activityBlueprintId2, activityBlueprint2},
|
||||
{activityBlueprintId3, activityBlueprint3},
|
||||
{activityBlueprintId4, activityBlueprint4},
|
||||
});
|
||||
Mock.Get(workflowBlueprint).SetupGet(x => x.Connections).Returns(new [] { connection1, connection2 });
|
||||
Mock.Get(workflowBlueprint).SetupGet(x => x.Activities).Returns(new [] { activityBlueprint1, activityBlueprint2, activityBlueprint3, activityBlueprint4 });
|
||||
Mock.Get(connection1).SetupGet(x => x.Target).Returns(endpoint1);
|
||||
Mock.Get(connection2).SetupGet(x => x.Target).Returns(endpoint2);
|
||||
Mock.Get(endpoint1).SetupGet(x => x.Activity).Returns(activityBlueprint2);
|
||||
Mock.Get(endpoint2).SetupGet(x => x.Activity).Returns(activityBlueprint4);
|
||||
|
||||
var result = sut.GetStartActivities(workflowBlueprint).ToArray();
|
||||
|
||||
Assert.Equal(new [] { activityBlueprint1, activityBlueprint3 }, result);
|
||||
}
|
||||
|
||||
void SetupActivitiesWithIds(Dictionary<string,IActivityBlueprint> idsToBlueprints)
|
||||
{
|
||||
foreach(var kvp in idsToBlueprints)
|
||||
Mock.Get(kvp.Value).SetupGet(x => x.Id).Returns(kvp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.Testing.Shared.AutoFixture.Attributes;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
public class WorkflowExecutionContextForWorkflowBlueprintFactoryTests
|
||||
{
|
||||
[Theory(DisplayName = "The CreateWorkflowExecutionContextAsync method returns an execution context using the blueprint, an instance and the service provider"), AutoMoqData]
|
||||
public async Task CreateWorkflowExecutionContextAsyncReturnsContextWithBlueprintInstanceAndServiceProvider([AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
IWorkflowFactory workflowFactory,
|
||||
IWorkflowBlueprint workflowBlueprint,
|
||||
[OmitOnRecursion] WorkflowInstance instance)
|
||||
{
|
||||
var sut = new WorkflowExecutionContextForWorkflowBlueprintFactory(serviceProvider, workflowFactory);
|
||||
Mock.Get(workflowFactory)
|
||||
.Setup(x => x.InstantiateAsync(workflowBlueprint, default, default, default))
|
||||
.Returns(() => Task.FromResult(instance));
|
||||
|
||||
var result = await sut.CreateWorkflowExecutionContextAsync(workflowBlueprint);
|
||||
|
||||
Assert.Same(serviceProvider, result.ServiceProvider);
|
||||
Assert.Same(workflowBlueprint, result.WorkflowBlueprint);
|
||||
Assert.Same(instance, result.WorkflowInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.ActivityProviders;
|
||||
using Elsa.Bookmarks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Elsa.Testing.Shared.AutoFixture.Attributes;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Elsa.Triggers
|
||||
{
|
||||
public class TriggersForActivityBlueprintAndWorkflowProviderTests
|
||||
{
|
||||
[Theory(DisplayName = "The GetTriggersForActivityBlueprintAsync returns a trigger for every bookmark in the bookmark providers that support the activity"), AutoMoqData]
|
||||
public async Task GetTriggersForActivityBlueprintAsyncReturnsTriggersForEachBookmarkInSupportedBookmarkProviders(IBookmarkHasher bookmarkHasher,
|
||||
IBookmarkProvider bookmarkProvider1,
|
||||
IBookmarkProvider unsupportedBookmarkProvider,
|
||||
IBookmarkProvider bookmarkProvider2,
|
||||
ICreatesActivityExecutionContextForActivityBlueprint activityExecutionContextFactory,
|
||||
IActivityBlueprint activityBlueprint,
|
||||
[AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
IWorkflowBlueprint workflowBlueprint,
|
||||
[OmitOnRecursion] WorkflowInstance workflowInstance,
|
||||
ActivityType activityType,
|
||||
IBookmark bookmark1,
|
||||
IBookmark bookmark2,
|
||||
IBookmark bookmark3,
|
||||
IBookmark bookmark4)
|
||||
{
|
||||
var sut = new TriggersForActivityBlueprintAndWorkflowProvider(bookmarkHasher,
|
||||
new[] { bookmarkProvider1, unsupportedBookmarkProvider, bookmarkProvider2 },
|
||||
activityExecutionContextFactory);
|
||||
var workflowExecutionContext = new WorkflowExecutionContext(serviceProvider, workflowBlueprint, workflowInstance);
|
||||
var activityExecutionContext = new ActivityExecutionContext(serviceProvider, workflowExecutionContext, activityBlueprint, default, default, default);
|
||||
|
||||
Mock.Get(activityExecutionContextFactory)
|
||||
.Setup(x => x.CreateActivityExecutionContext(activityBlueprint, workflowExecutionContext, default))
|
||||
.Returns(activityExecutionContext);
|
||||
Mock.Get(activityBlueprint).SetupGet(x => x.Type).Returns(activityType.TypeName);
|
||||
Mock.Get(bookmarkProvider1)
|
||||
.Setup(x => x.SupportsActivityAsync(It.Is<BookmarkProviderContext>(c => c.ActivityType == activityType), default))
|
||||
.Returns(() => ValueTask.FromResult(true));
|
||||
Mock.Get(unsupportedBookmarkProvider)
|
||||
.Setup(x => x.SupportsActivityAsync(It.Is<BookmarkProviderContext>(c => c.ActivityType == activityType), default))
|
||||
.Returns(() => ValueTask.FromResult(false));
|
||||
Mock.Get(bookmarkProvider2)
|
||||
.Setup(x => x.SupportsActivityAsync(It.Is<BookmarkProviderContext>(c => c.ActivityType == activityType), default))
|
||||
.Returns(() => ValueTask.FromResult(true));
|
||||
Mock.Get(bookmarkProvider1)
|
||||
.Setup(x => x.GetBookmarksAsync(It.IsAny<BookmarkProviderContext>(), default))
|
||||
.Returns(() => ValueTask.FromResult<IEnumerable<IBookmark>>(new [] { bookmark1, bookmark2 }));
|
||||
Mock.Get(bookmarkProvider2)
|
||||
.Setup(x => x.GetBookmarksAsync(It.IsAny<BookmarkProviderContext>(), default))
|
||||
.Returns(() => ValueTask.FromResult<IEnumerable<IBookmark>>(new [] { bookmark3, bookmark4 }));
|
||||
|
||||
var result = await sut.GetTriggersForActivityBlueprintAsync(activityBlueprint,
|
||||
workflowExecutionContext,
|
||||
new Dictionary<string, ActivityType> { { activityType.TypeName, activityType } });
|
||||
|
||||
Assert.True(result.Any(x => x.Bookmark == bookmark1), "Result contains a trigger for bookmark 1");
|
||||
Assert.True(result.Any(x => x.Bookmark == bookmark2), "Result contains a trigger for bookmark 2");
|
||||
Assert.True(result.Any(x => x.Bookmark == bookmark3), "Result contains a trigger for bookmark 3");
|
||||
Assert.True(result.Any(x => x.Bookmark == bookmark4), "Result contains a trigger for bookmark 4");
|
||||
Assert.True(result.Count() == 4, "Result has 4 items");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,134 +18,6 @@ namespace Elsa.UnitTests.Triggers
|
|||
{
|
||||
public class TriggersForBlueprintsProviderTests
|
||||
{
|
||||
// [Theory(DisplayName = "The GetTriggersAsync method should return all triggers for the compatible bookmarks of the start activities of the blueprints. This is actually an integration test."), AutoMoqData]
|
||||
// public async Task GetTriggersAsyncGetsAllTriggersForAllBlueprintsStartActivitiesAndCompatibleBookmarks(IActivityTypeService activityTypeService,
|
||||
// IBookmarkHasher bookmarkHasher,
|
||||
// IBookmarkProvider provider1,
|
||||
// IBookmarkProvider provider2,
|
||||
// IBookmarkProvider provider3,
|
||||
// [AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
// IWorkflowFactory workflowFactory,
|
||||
// ActivityType activityType1,
|
||||
// ActivityType activityType2,
|
||||
// ActivityType activityType3,
|
||||
// IWorkflowBlueprint workflowBlueprint1,
|
||||
// IWorkflowBlueprint workflowBlueprint2,
|
||||
// IActivityBlueprint activityBlueprint1,
|
||||
// IActivityBlueprint activityBlueprint2,
|
||||
// IActivityBlueprint activityBlueprint3,
|
||||
// IActivityBlueprint activityBlueprint4,
|
||||
// IActivityBlueprint activityBlueprint5,
|
||||
// IActivityBlueprint activityBlueprint6,
|
||||
// string activityBlueprintId1,
|
||||
// string activityBlueprintId2,
|
||||
// string activityBlueprintId3,
|
||||
// string activityBlueprintId4,
|
||||
// string activityBlueprintId5,
|
||||
// string activityBlueprintId6,
|
||||
// IConnection connection1,
|
||||
// IConnection connection2,
|
||||
// IConnection connection3,
|
||||
// ITargetEndpoint endpoint1,
|
||||
// ITargetEndpoint endpoint2,
|
||||
// ITargetEndpoint endpoint3,
|
||||
// [OmitOnRecursion] WorkflowInstance workflow1,
|
||||
// [OmitOnRecursion] WorkflowInstance workflow2,
|
||||
// IBookmark bookmark1,
|
||||
// IBookmark bookmark2,
|
||||
// IBookmark bookmark3,
|
||||
// IBookmark bookmark4,
|
||||
// IBookmark bookmark5,
|
||||
// IBookmark bookmark6,
|
||||
// string bookmarkHash1,
|
||||
// string bookmarkHash2,
|
||||
// string bookmarkHash3,
|
||||
// string bookmarkHash4,
|
||||
// string bookmarkHash5,
|
||||
// string bookmarkHash6)
|
||||
// {
|
||||
// var workflowExecutionContextFactory = new WorkflowExecutionContextForWorkflowBlueprintFactory(serviceProvider, workflowFactory);
|
||||
// var activityExecutionContextFactory = new ActivityExecutionContextForActivityBlueprintFactory(serviceProvider);
|
||||
// var triggersForActivityProvider = new TriggersForActivityBlueprintAndWorkflowProvider(bookmarkHasher,
|
||||
// new[] { provider1, provider2, provider3 },
|
||||
// activityExecutionContextFactory);
|
||||
// var startingActivitiesProvider = new StartActivitiesForCompositeActivityBlueprintProvider();
|
||||
|
||||
// var sut = new TriggersForBlueprintsProvider(activityTypeService,
|
||||
// workflowExecutionContextFactory,
|
||||
// triggersForActivityProvider,
|
||||
// startingActivitiesProvider);
|
||||
|
||||
// Mock.Get(workflowBlueprint1).SetupGet(x => x.Connections).Returns(new [] { connection1 });
|
||||
// Mock.Get(workflowBlueprint2).SetupGet(x => x.Connections).Returns(new [] { connection2, connection3 });
|
||||
// Mock.Get(workflowBlueprint1).SetupGet(x => x.Activities).Returns(new [] { activityBlueprint1, activityBlueprint2, activityBlueprint4 });
|
||||
// Mock.Get(workflowBlueprint2).SetupGet(x => x.Activities).Returns(new [] { activityBlueprint3, activityBlueprint5, activityBlueprint6 });
|
||||
// Mock.Get(workflowFactory)
|
||||
// .Setup(x => x.InstantiateAsync(workflowBlueprint1, null, null, default))
|
||||
// .Returns(Task.FromResult(workflow1));
|
||||
// Mock.Get(workflowFactory)
|
||||
// .Setup(x => x.InstantiateAsync(workflowBlueprint2, null, null, default))
|
||||
// .Returns(Task.FromResult(workflow2));
|
||||
// Mock.Get(connection1).SetupGet(x => x.Target).Returns(endpoint1);
|
||||
// Mock.Get(connection2).SetupGet(x => x.Target).Returns(endpoint2);
|
||||
// Mock.Get(connection3).SetupGet(x => x.Target).Returns(endpoint3);
|
||||
// Mock.Get(endpoint1).SetupGet(x => x.Activity).Returns(activityBlueprint4);
|
||||
// Mock.Get(endpoint2).SetupGet(x => x.Activity).Returns(activityBlueprint5);
|
||||
// Mock.Get(endpoint3).SetupGet(x => x.Activity).Returns(activityBlueprint6);
|
||||
// Mock.Get(activityBlueprint1).SetupGet(x => x.Type).Returns(activityType1.TypeName);
|
||||
// Mock.Get(activityBlueprint2).SetupGet(x => x.Type).Returns(activityType2.TypeName);
|
||||
// Mock.Get(activityBlueprint3).SetupGet(x => x.Type).Returns(activityType3.TypeName);
|
||||
// Mock.Get(activityBlueprint1).SetupGet(x => x.Id).Returns(activityBlueprintId1);
|
||||
// Mock.Get(activityBlueprint2).SetupGet(x => x.Id).Returns(activityBlueprintId2);
|
||||
// Mock.Get(activityBlueprint3).SetupGet(x => x.Id).Returns(activityBlueprintId3);
|
||||
// Mock.Get(activityBlueprint4).SetupGet(x => x.Id).Returns(activityBlueprintId4);
|
||||
// Mock.Get(activityBlueprint5).SetupGet(x => x.Id).Returns(activityBlueprintId5);
|
||||
// Mock.Get(activityBlueprint6).SetupGet(x => x.Id).Returns(activityBlueprintId6);
|
||||
// SetupProviderToBeCompatibleWithActivityType(provider1, activityType1);
|
||||
// SetupProviderToBeCompatibleWithActivityType(provider2, activityType2);
|
||||
// SetupProviderToBeCompatibleWithActivityType(provider3, activityType3);
|
||||
// Mock.Get(provider1)
|
||||
// .Setup(x => x.GetBookmarksAsync(It.IsAny<BookmarkProviderContext>(), default))
|
||||
// .Returns(ValueTask.FromResult<IEnumerable<IBookmark>>(new [] { bookmark1, bookmark2 }));
|
||||
// Mock.Get(provider2)
|
||||
// .Setup(x => x.GetBookmarksAsync(It.IsAny<BookmarkProviderContext>(), default))
|
||||
// .Returns(ValueTask.FromResult<IEnumerable<IBookmark>>(new [] { bookmark3, bookmark4 }));
|
||||
// Mock.Get(provider3)
|
||||
// .Setup(x => x.GetBookmarksAsync(It.IsAny<BookmarkProviderContext>(), default))
|
||||
// .Returns(ValueTask.FromResult<IEnumerable<IBookmark>>(new [] { bookmark5, bookmark6 }));
|
||||
// Mock.Get(bookmarkHasher).Setup(x => x.Hash(bookmark1)).Returns(bookmarkHash1);
|
||||
// Mock.Get(bookmarkHasher).Setup(x => x.Hash(bookmark2)).Returns(bookmarkHash2);
|
||||
// Mock.Get(bookmarkHasher).Setup(x => x.Hash(bookmark3)).Returns(bookmarkHash3);
|
||||
// Mock.Get(bookmarkHasher).Setup(x => x.Hash(bookmark4)).Returns(bookmarkHash4);
|
||||
// Mock.Get(bookmarkHasher).Setup(x => x.Hash(bookmark5)).Returns(bookmarkHash5);
|
||||
// Mock.Get(bookmarkHasher).Setup(x => x.Hash(bookmark6)).Returns(bookmarkHash6);
|
||||
|
||||
// var result = await sut.GetTriggersAsync(new [] { workflowBlueprint1, workflowBlueprint2 });
|
||||
|
||||
// Assert.Equal(6, result.Count());
|
||||
// Assert.True(ContainsTriggerWithHash(result, bookmarkHash1)
|
||||
// && ContainsTriggerWithHash(result, bookmarkHash2)
|
||||
// && ContainsTriggerWithHash(result, bookmarkHash3)
|
||||
// && ContainsTriggerWithHash(result, bookmarkHash4)
|
||||
// && ContainsTriggerWithHash(result, bookmarkHash5)
|
||||
// && ContainsTriggerWithHash(result, bookmarkHash6),
|
||||
// "The returned triggers should contain a trigger with every one of the six expected hashes");
|
||||
// }
|
||||
|
||||
// void SetupProviderToBeCompatibleWithActivityType(IBookmarkProvider provider, ActivityType activityType)
|
||||
// {
|
||||
// Mock.Get(provider)
|
||||
// .Setup(x => x.SupportsActivityAsync(It.IsAny<BookmarkProviderContext>(), default))
|
||||
// .Returns(ValueTask.FromResult(false));
|
||||
// Mock.Get(provider)
|
||||
// .Setup(x => x.SupportsActivityAsync(It.Is<BookmarkProviderContext>(c => c.ActivityType == activityType), default))
|
||||
// .Returns(ValueTask.FromResult(true));
|
||||
// }
|
||||
|
||||
// bool ContainsTriggerWithHash(IEnumerable<WorkflowTrigger> triggers, string hash)
|
||||
// => triggers.Any(x => Equals(x.BookmarkHash, hash));
|
||||
|
||||
|
||||
[Theory(DisplayName = "The GetTriggersAsync method should return all triggers for start activities of the workflow blueprints"), AutoMoqData]
|
||||
public async Task GetTriggersAsyncGetsAllTriggersForAllBlueprintsStartActivitiesAndCompatibleBookmarks([Frozen] IActivityTypeService activityTypeService,
|
||||
[Frozen] ICreatesWorkflowExecutionContextForWorkflowBlueprint workflowExecutionContextFactory,
|
||||
|
|
|
|||
Loading…
Reference in a new issue