elsa-core/test/unit/Elsa.Workflows.Runtime.UnitTests/Services/KeyValueFeatureTests.cs
Sipke Schoorstra d09a1b7cb4
Add workflow dispatch transactional outbox (#7517)
* Add workflow dispatch transactional outbox

* Address workflow dispatch outbox review

* Make outbox state lookup null-safe

* Generate stable outbox dispatch instance ids

* Limit eager outbox processing to marked commits

* Avoid blocking eager outbox processing on lock contention

* Expire uncommitted outbox items after retention

* Harden eager workflow outbox processing

* Prune delivered workflow outbox markers

* Batch workflow dispatch outbox processing

* Bound workflow dispatch outbox processing batches

* Harden workflow dispatch outbox processing

* Address transactional outbox review feedback

* Address transactional outbox follow-up review

* Address outbox recovery review feedback

* Address outbox key-value review fixes

* Address outbox cleanup review feedback

* Address workflow outbox review feedback

* Address outbox key-value review feedback

* Preserve outbox key-value tenant ids

* Address workflow outbox marker cleanup review

* Ensure key value store factory registrations override

* Address workflow outbox review follow-ups
2026-05-22 00:13:16 +02:00

127 lines
4.4 KiB
C#

using Elsa.Common.Services;
using Elsa.Features.Services;
using Elsa.KeyValues.Contracts;
using Elsa.KeyValues.Entities;
using Elsa.KeyValues.Models;
using Elsa.KeyValues.Stores;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using ModuleKeyValueFeature = Elsa.KeyValues.Features.KeyValueFeature;
using ShellKeyValueFeature = Elsa.KeyValues.ShellFeatures.KeyValueFeature;
namespace Elsa.Workflows.Runtime.UnitTests.Services;
public class KeyValueFeatureTests
{
private readonly IServiceCollection _services = new ServiceCollection();
private readonly IModule _module = Substitute.For<IModule>();
public KeyValueFeatureTests()
{
_module.Services.Returns(_services);
}
[Fact]
public void ModuleFeature_DoesNotRegisterMemoryStore_WhenKeyValueStoreIsCustomized()
{
var feature = new ModuleKeyValueFeature(_module)
{
KeyValueStore = _ => new CustomKeyValueStore()
};
feature.Apply();
Assert.DoesNotContain(_services, x => x.ServiceType == typeof(MemoryStore<SerializedKeyValuePair>));
Assert.Contains(_services, x => x.ServiceType == typeof(IKeyValueStore));
}
[Fact]
public void ModuleFeature_CanExplicitlyRegisterMemoryStore_WhenKeyValueStoreIsCustomized()
{
var feature = new ModuleKeyValueFeature(_module)
{
KeyValueStore = sp => ActivatorUtilities.CreateInstance<MemoryKeyValueStore>(sp),
RegisterMemoryStore = true
};
feature.Apply();
Assert.Contains(_services, x => x.ServiceType == typeof(MemoryStore<SerializedKeyValuePair>));
}
[Fact]
public void ModuleFeature_ConfiguredKeyValueStoreOverridesExistingRegistration()
{
_services.AddScoped<IKeyValueStore>(_ => new ExistingKeyValueStore());
var feature = new ModuleKeyValueFeature(_module)
{
KeyValueStore = _ => new CustomKeyValueStore()
};
feature.Apply();
using var provider = _services.BuildServiceProvider();
var store = provider.GetRequiredService<IKeyValueStore>();
Assert.IsType<CustomKeyValueStore>(store);
}
[Fact]
public void ShellFeature_DoesNotRegisterMemoryStore_WhenKeyValueStoreIsCustomized()
{
var feature = new ShellKeyValueFeature
{
KeyValueStore = _ => new CustomKeyValueStore()
};
feature.ConfigureServices(_services);
Assert.DoesNotContain(_services, x => x.ServiceType == typeof(MemoryStore<SerializedKeyValuePair>));
Assert.Contains(_services, x => x.ServiceType == typeof(IKeyValueStore));
}
[Fact]
public void ShellFeature_CanExplicitlyRegisterMemoryStore_WhenKeyValueStoreIsCustomized()
{
var feature = new ShellKeyValueFeature
{
KeyValueStore = sp => ActivatorUtilities.CreateInstance<MemoryKeyValueStore>(sp),
RegisterMemoryStore = true
};
feature.ConfigureServices(_services);
Assert.Contains(_services, x => x.ServiceType == typeof(MemoryStore<SerializedKeyValuePair>));
}
[Fact]
public void ShellFeature_ConfiguredKeyValueStoreOverridesExistingRegistration()
{
_services.AddScoped<IKeyValueStore>(_ => new ExistingKeyValueStore());
var feature = new ShellKeyValueFeature
{
KeyValueStore = _ => new CustomKeyValueStore()
};
feature.ConfigureServices(_services);
using var provider = _services.BuildServiceProvider();
var store = provider.GetRequiredService<IKeyValueStore>();
Assert.IsType<CustomKeyValueStore>(store);
}
private class ExistingKeyValueStore : TestKeyValueStore;
private class CustomKeyValueStore : TestKeyValueStore;
private abstract class TestKeyValueStore : IKeyValueStore
{
public Task SaveAsync(SerializedKeyValuePair keyValuePair, CancellationToken cancellationToken) => Task.CompletedTask;
public Task<SerializedKeyValuePair?> FindAsync(KeyValueFilter filter, CancellationToken cancellationToken) => Task.FromResult<SerializedKeyValuePair?>(null);
public Task<IEnumerable<SerializedKeyValuePair>> FindManyAsync(KeyValueFilter filter, CancellationToken cancellationToken) => Task.FromResult<IEnumerable<SerializedKeyValuePair>>([]);
public Task DeleteAsync(string key, CancellationToken cancellationToken) => Task.CompletedTask;
}
}