feat: create request projects for basic CQRS
This commit is contained in:
commit
d614788e06
190 changed files with 12236 additions and 0 deletions
243
src/request.dispatcher.tests/StreamDispatcherTests.cs
Normal file
243
src/request.dispatcher.tests/StreamDispatcherTests.cs
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
// Copyright (c) The Geekeey Authors
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Geekeey.Request.Dispatcher.Tests;
|
||||
|
||||
public class StreamDispatcherTests
|
||||
{
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_open_generic_handler()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(OpenStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new OpenStreamRequest { Data = "Hello" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Hello-Stream-0", "Hello-Stream-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_open_generic_handler_that_has_constraints()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(ConstrainedStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new ConstrainedStreamRequest { Value = 123 };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["123-Constrained-0", "123-Constrained-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_see_it_fail_if_no_handler_is_found_even_with_an_open_generic_available()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(OpenStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new UnhandledStreamRequest();
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await dispatcher.DispatchAsync(request).FirstOrDefaultAsync().AsTask());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_inherited_request()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(OpenStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new InheritedStreamRequest { Data = "Sub" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Sub-Stream-0", "Sub-Stream-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_inherited_handler()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(DerivedStreamHandler)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new DerivedStreamRequest { Value = 42 };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Derived: 42-0", "Derived: 42-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_interface_inherited_request()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(InterfaceInheritedStreamHandler)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new InterfaceInheritedStreamRequest { Name = "InterfaceTest" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["InterfaceTest-InterfaceHandled-0", "InterfaceTest-InterfaceHandled-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_deep_inheritance_in_the_request()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(OpenStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new DeepDerivedStreamRequest { Data = "Deep", DeepValue = 99 };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Deep-Stream-0", "Deep-Stream-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_interface_constrained_handler()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(InterfaceInheritedStreamHandler))
|
||||
.Add(typeof(InterfaceConstrainedStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new InterfaceInheritedStreamRequest { Name = "Constrained" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
// Both InterfaceInheritedStreamHandler and InterfaceConstrainedStreamHandler could match.
|
||||
// InterfaceInheritedStreamHandler is a concrete match for InterfaceInheritedStreamRequest.
|
||||
// InterfaceConstrainedStreamHandler is an open generic match.
|
||||
// Currently Dispatcher checks concrete handlers first.
|
||||
await Assert.That(results).IsEquivalentTo(["Constrained-InterfaceHandled-0", "Constrained-InterfaceHandled-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_an_interface_only_match()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(InterfaceConstrainedStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new AnotherNamedStreamRequest { Name = "InterfaceOnly" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["InterfaceOnly-ConstrainedByInterface-0", "InterfaceOnly-ConstrainedByInterface-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_a_nested_generic_request()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(WrapperStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new WrapperStreamRequest<int> { Item = 42 };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Handled-42-0", "Handled-42-1"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_handle_multiple_interface_implementations()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(MultiInterfaceStreamHandler)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new MultiInterfaceStreamRequest();
|
||||
|
||||
var results1 = await dispatcher.DispatchAsync<int>(request).ToListAsync();
|
||||
var results2 = await dispatcher.DispatchAsync<string>(request).ToListAsync();
|
||||
|
||||
await Assert.That(results1).IsEquivalentTo([1, 2]);
|
||||
await Assert.That(results2).IsEquivalentTo(["One", "Two"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_see_it_fail_if_there_are_ambiguous_handle_methods()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(AmbiguousStreamHandler)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new AmbiguousStreamRequest();
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Interface-Handled"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_dispatch_a_request_async_with_a_generic_interface_explicit_implementation()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(ExplicitGenericStreamHandler<>)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new ExplicitGenericStreamRequest { Value = "Explicit" };
|
||||
var results = await dispatcher.DispatchAsync(request).ToListAsync();
|
||||
|
||||
await Assert.That(results).IsEquivalentTo(["Explicit-ExplicitHandled"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_see_it_throw_the_original_exception()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(FailingStreamHandler)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
|
||||
|
||||
var request = new FailingStreamRequest();
|
||||
var enumerable = dispatcher.DispatchAsync(request);
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await enumerable.ToListAsync().AsTask());
|
||||
|
||||
using (Assert.Multiple())
|
||||
{
|
||||
await Assert.That(ex?.Message).IsEquivalentTo("Handler failed");
|
||||
await Assert.That(ex?.StackTrace).Contains(nameof(FailingStreamHandler.HandleAsync));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task I_can_see_it_throw_if_dispatcher_options_are_modified_after_build()
|
||||
{
|
||||
var sc = new ServiceCollection();
|
||||
sc.AddRequestDispatcher(builder => builder
|
||||
.Add(typeof(FailingStreamHandler)));
|
||||
var provider = sc.BuildServiceProvider();
|
||||
var options = provider.GetRequiredService<Microsoft.Extensions.Options.IOptions<RequestDispatcherOptions>>().Value;
|
||||
options.GetRequestHandlers<IStreamRequestHandler<FailingStreamRequest, string>>(default!);
|
||||
|
||||
await Assert.That(() => options.Inspect([])).Throws<InvalidOperationException>();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue