elsa-core/test/unit/Elsa.Scheduling.UnitTests/StartupTasks/CreateSchedulesStartupTaskTests.cs
Sipke Schoorstra 8e301d4e1e
[codex] Scope console logs to workflow instances (#7535)
* 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
2026-05-25 11:49:51 +02:00

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();
}
}