using Elsa.Common; using Elsa.Testing.Shared; using Elsa.Workflows.Activities; using Elsa.Workflows.LogPersistence; using Elsa.Workflows.Management.Options; using Elsa.Workflows.Runtime.Entities; using Microsoft.Extensions.Options; using NSubstitute; namespace Elsa.Workflows.Runtime.UnitTests.Services; /// /// Unit tests for DefaultActivityExecutionMapper. /// public class DefaultActivityExecutionMapperTests { /// /// Tests that the mapper correctly maps CallStackDepth, SchedulingActivityExecutionId, /// and SchedulingActivityId from the ActivityExecutionContext to the record. /// [Fact] public async Task MapAsync_MapsCallStackDepth_Correctly() { // Arrange var safeSerializer = Substitute.For(); safeSerializer.Serialize(Arg.Any()).Returns("serialized"); var payloadSerializer = Substitute.For(); payloadSerializer.Serialize(Arg.Any()).Returns("serialized"); var compressionCodecResolver = Substitute.For(); var compressionCodec = Substitute.For(); compressionCodecResolver.Resolve(Arg.Any()).Returns(compressionCodec); compressionCodec.CompressAsync(Arg.Any(), Arg.Any()).Returns(new ValueTask("compressed")); var managementOptions = Substitute.For>(); managementOptions.Value.Returns(new ManagementOptions()); var mapper = new DefaultActivityExecutionMapper( safeSerializer, payloadSerializer, compressionCodecResolver, managementOptions); // Use ActivityTestFixture to create real context objects var activity = new WriteLine("Test"); var fixture = new ActivityTestFixture(activity); var activityExecutionContext = await fixture.BuildAsync(); // Set the properties we want to test activityExecutionContext.CallStackDepth = 2; activityExecutionContext.SchedulingActivityExecutionId = "context-b"; activityExecutionContext.SchedulingActivityId = "activity-b"; // Act var record = await mapper.MapAsync(activityExecutionContext); // Assert Assert.NotNull(record); Assert.Equal(2, record.CallStackDepth); Assert.Equal("context-b", record.SchedulingActivityExecutionId); Assert.Equal("activity-b", record.SchedulingActivityId); } [Fact] public async Task MapAsync_IncludesPropertiesAndPayload_WhenInternalStateIsInclude_EvenIfInputsAreExcluded() { var record = await MapWithPersistenceAsync( LogPersistenceMode.Include, inputs: LogPersistenceMode.Exclude); Assert.NotNull(record.Properties); Assert.Equal("property-value", record.Properties["InternalKey"]); Assert.NotNull(record.Payload); Assert.Equal("journal-value", record.Payload["JournalKey"]); Assert.False(record.ActivityState?.ContainsKey("Text")); } [Fact] public async Task MapAsync_ExcludesPropertiesAndPayload_WhenInternalStateIsExclude_EvenIfInputsAreIncluded() { var record = await MapWithPersistenceAsync( LogPersistenceMode.Exclude, inputs: LogPersistenceMode.Include); Assert.Null(record.Properties); Assert.Null(record.Payload); Assert.True(record.ActivityState?.ContainsKey("Text")); } private static async Task MapWithPersistenceAsync( LogPersistenceMode internalState, LogPersistenceMode inputs) { var mapper = CreateMapper(); var activity = new WriteLine("Test"); var context = await new ActivityTestFixture(activity).BuildAsync(); context.ActivityState["Text"] = "Test"; context.Properties["InternalKey"] = "property-value"; context.JournalData["JournalKey"] = "journal-value"; context.SetLogPersistenceModeMap(new ActivityLogPersistenceModeMap { InternalState = internalState, Inputs = { [nameof(WriteLine.Text)] = inputs } }); return await mapper.MapAsync(context); } private static DefaultActivityExecutionMapper CreateMapper() { var safeSerializer = Substitute.For(); safeSerializer.Serialize(Arg.Any()).Returns("serialized"); var payloadSerializer = Substitute.For(); payloadSerializer.Serialize(Arg.Any()).Returns("serialized"); var compressionCodecResolver = Substitute.For(); var compressionCodec = Substitute.For(); compressionCodecResolver.Resolve(Arg.Any()).Returns(compressionCodec); compressionCodec.CompressAsync(Arg.Any(), Arg.Any()).Returns(new ValueTask("compressed")); var managementOptions = Substitute.For>(); managementOptions.Value.Returns(new ManagementOptions()); return new DefaultActivityExecutionMapper( safeSerializer, payloadSerializer, compressionCodecResolver, managementOptions); } }