* Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines
79 lines
3.9 KiB
C#
79 lines
3.9 KiB
C#
using Elsa.Common;
|
|
using Elsa.Common.Multitenancy;
|
|
using Elsa.Scheduling.StartupTasks;
|
|
using Elsa.Workflows.Runtime;
|
|
using Elsa.Workflows.Runtime.Entities;
|
|
using Elsa.Workflows.Runtime.Filters;
|
|
using Elsa.Workflows.Runtime.Tasks;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using NSubstitute;
|
|
|
|
namespace Elsa.Scheduling.UnitTests.StartupTasks;
|
|
|
|
public class CreateSchedulesStartupTaskTests
|
|
{
|
|
private readonly StoredTrigger[] _triggers = [new() { WorkflowDefinitionId = "definition", WorkflowDefinitionVersionId = "version", ActivityId = "activity" }];
|
|
private readonly StoredBookmark[] _bookmarks = [new() { Hash = "hash", WorkflowInstanceId = "instance" }];
|
|
private readonly ITriggerStore _triggerStore = Substitute.For<ITriggerStore>();
|
|
private readonly IBookmarkStore _bookmarkStore = Substitute.For<IBookmarkStore>();
|
|
private readonly ITriggerScheduler _triggerScheduler = Substitute.For<ITriggerScheduler>();
|
|
private readonly IBookmarkScheduler _bookmarkScheduler = Substitute.For<IBookmarkScheduler>();
|
|
|
|
public CreateSchedulesStartupTaskTests()
|
|
{
|
|
_triggerStore.FindManyAsync(Arg.Any<TriggerFilter>(), Arg.Any<CancellationToken>()).Returns(_triggers);
|
|
_bookmarkStore.FindManyAsync(Arg.Any<BookmarkFilter>(), Arg.Any<CancellationToken>()).Returns(_bookmarks);
|
|
}
|
|
|
|
[Fact]
|
|
public void Task_DependsOnPopulateRegistriesStartupTask()
|
|
{
|
|
var dependency = Assert.Single(typeof(CreateSchedulesStartupTask).GetCustomAttributes(typeof(TaskDependencyAttribute), false).Cast<TaskDependencyAttribute>());
|
|
|
|
Assert.Equal(typeof(PopulateRegistriesStartupTask), dependency.DependencyTaskType);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_WithoutTenantBackgroundQueue_SchedulesImmediately()
|
|
{
|
|
var task = new CreateSchedulesStartupTask(CreateServiceProvider());
|
|
|
|
await task.ExecuteAsync(CancellationToken.None);
|
|
|
|
await _triggerScheduler.Received(1).ScheduleAsync(Arg.Is<IEnumerable<StoredTrigger>>(x => x.SequenceEqual(_triggers)), Arg.Any<CancellationToken>());
|
|
await _bookmarkScheduler.Received(1).ScheduleAsync(Arg.Is<IEnumerable<StoredBookmark>>(x => x.SequenceEqual(_bookmarks)), Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_WithTenantBackgroundQueue_EnqueuesScheduleCreation()
|
|
{
|
|
TenantBackgroundWorkItem? workItem = null;
|
|
var workQueue = Substitute.For<ITenantBackgroundWorkQueue>();
|
|
workQueue.EnqueueAsync(Arg.Do<TenantBackgroundWorkItem>(x => workItem = x), Arg.Any<CancellationToken>()).Returns(ValueTask.CompletedTask);
|
|
var serviceProvider = CreateServiceProvider(services => services.AddSingleton(workQueue));
|
|
var task = new CreateSchedulesStartupTask(serviceProvider);
|
|
|
|
await task.ExecuteAsync(CancellationToken.None);
|
|
|
|
await workQueue.Received(1).EnqueueAsync(Arg.Any<TenantBackgroundWorkItem>(), Arg.Any<CancellationToken>());
|
|
await _triggerScheduler.DidNotReceive().ScheduleAsync(Arg.Any<IEnumerable<StoredTrigger>>(), Arg.Any<CancellationToken>());
|
|
|
|
Assert.NotNull(workItem);
|
|
await workItem(serviceProvider, CancellationToken.None);
|
|
|
|
await _triggerScheduler.Received(1).ScheduleAsync(Arg.Is<IEnumerable<StoredTrigger>>(x => x.SequenceEqual(_triggers)), Arg.Any<CancellationToken>());
|
|
await _bookmarkScheduler.Received(1).ScheduleAsync(Arg.Is<IEnumerable<StoredBookmark>>(x => x.SequenceEqual(_bookmarks)), Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
private ServiceProvider CreateServiceProvider(Action<IServiceCollection>? configureServices = null)
|
|
{
|
|
var services = new ServiceCollection();
|
|
services.AddSingleton(_triggerStore);
|
|
services.AddSingleton(_bookmarkStore);
|
|
services.AddSingleton(_triggerScheduler);
|
|
services.AddSingleton(_bookmarkScheduler);
|
|
configureServices?.Invoke(services);
|
|
return services.BuildServiceProvider();
|
|
}
|
|
}
|