87 lines
4.0 KiB
C#
87 lines
4.0 KiB
C#
using MAX.Notification.NotificationPublishers;
|
|
using MAX.Notification;
|
|
|
|
var calls = new List<int>();
|
|
var services = new TestServices();
|
|
services.Handlers = [new First((_, _) => { calls.Add(1); return Task.CompletedTask; }),
|
|
new First((_, _) => { calls.Add(99); return Task.CompletedTask; }),
|
|
new Second((_, _) => { calls.Add(2); return Task.CompletedTask; })];
|
|
var publisher = new NotificationPublisher(services);
|
|
INotification message = new Changed();
|
|
await publisher.Publish(message);
|
|
Check(calls.SequenceEqual([1, 2]), "运行时类型分发、顺序和类型去重");
|
|
calls.Clear();
|
|
await publisher.Publish((object)message);
|
|
Check(calls.SequenceEqual([1, 2]) && services.Resolutions == 2, "对象分发和每次重新解析");
|
|
services.Handlers = [];
|
|
await publisher.Publish(message);
|
|
services.Handlers = null;
|
|
await publisher.Publish(message);
|
|
await Throws<ArgumentNullException>(() => publisher.Publish((object)null!));
|
|
await Throws<ArgumentException>(() => publisher.Publish(new object()));
|
|
await Throws<ArgumentNullException>(() => Task.FromResult(new NotificationPublisher(services, null!)));
|
|
using var cancelled = new CancellationTokenSource();
|
|
cancelled.Cancel();
|
|
// 原版只传递取消令牌;没有处理器时即使已取消也正常完成。
|
|
await publisher.Publish(message, cancelled.Token);
|
|
|
|
services.Handlers = [new First((_, _) => throw new InvalidOperationException("expected")),
|
|
new Second((_, _) => { calls.Add(3); return Task.CompletedTask; })];
|
|
calls.Clear();
|
|
await Throws<InvalidOperationException>(() => publisher.Publish(message));
|
|
Check(calls.Count == 0, "顺序模式失败后停止");
|
|
await Throws<InvalidOperationException>(() => new NotificationPublisher(services,
|
|
new TaskWhenAllPublisher()).Publish(message));
|
|
Check(calls.Count == 0, "原版并发模式同步异常阻止后续枚举");
|
|
|
|
var gate = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
var started = 0;
|
|
Task Handle(Changed _, CancellationToken token)
|
|
{
|
|
Check(token == cancelled.Token || !token.IsCancellationRequested, "取消令牌传递");
|
|
if (++started == 2) gate.SetResult();
|
|
return gate.Task;
|
|
}
|
|
services.Handlers = [new First(Handle), new Second(Handle)];
|
|
await new NotificationPublisher(services, new TaskWhenAllPublisher())
|
|
.Publish(message).WaitAsync(TimeSpan.FromSeconds(5));
|
|
Check(started == 2, "并发启动和等待全部完成");
|
|
|
|
using var during = new CancellationTokenSource();
|
|
services.Handlers = [new First((_, token) => { Check(token == during.Token, "原始令牌"); during.Cancel(); return Task.CompletedTask; }),
|
|
new Second((_, token) => { token.ThrowIfCancellationRequested(); return Task.CompletedTask; })];
|
|
await Throws<OperationCanceledException>(() => publisher.Publish(message, during.Token));
|
|
Console.WriteLine("All notification smoke tests passed.");
|
|
|
|
static void Check(bool condition, string name)
|
|
{
|
|
if (!condition) throw new Exception($"检查失败:{name}");
|
|
}
|
|
static async Task Throws<T>(Func<Task> action) where T : Exception
|
|
{
|
|
try { await action(); }
|
|
catch (T) { return; }
|
|
throw new Exception($"预期异常:{typeof(T).Name}");
|
|
}
|
|
sealed record Changed : INotification;
|
|
sealed class First(Func<Changed, CancellationToken, Task> action) : INotificationHandler<Changed>
|
|
{
|
|
public Task Handle(Changed notification, CancellationToken cancellationToken) => action(notification, cancellationToken);
|
|
}
|
|
sealed class Second(Func<Changed, CancellationToken, Task> action) : INotificationHandler<Changed>
|
|
{
|
|
public Task Handle(Changed notification, CancellationToken cancellationToken) => action(notification, cancellationToken);
|
|
}
|
|
sealed class TestServices : IServiceProvider
|
|
{
|
|
public INotificationHandler<Changed>[]? Handlers { get; set; }
|
|
public int Resolutions { get; private set; }
|
|
public object? GetService(Type serviceType)
|
|
{
|
|
if (serviceType != typeof(IEnumerable<INotificationHandler<Changed>>))
|
|
throw new Exception($"错误的解析类型:{serviceType}");
|
|
Resolutions++;
|
|
return Handlers;
|
|
}
|
|
}
|