252 lines
9.5 KiB
C#
252 lines
9.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEngine.TestTools;
|
|
|
|
namespace ShrinkEventBus.Tests
|
|
{
|
|
[TestFixture]
|
|
public class ShrinkEventBusDeferredDiagnosticsTests
|
|
{
|
|
private IShrinkEventBusMainThreadDispatcher _originalDispatcher;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
_originalDispatcher = ShrinkEventBusRuntime.MainThreadDispatcher;
|
|
}
|
|
|
|
[TearDown]
|
|
public void TearDown()
|
|
{
|
|
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(_originalDispatcher);
|
|
}
|
|
|
|
[Test]
|
|
public void ObserveDiagnostics_ReportsMetadataAndUnsubscribes()
|
|
{
|
|
var diagnostics = new List<ShrinkEventDiagnostic>();
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("diagnostics", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, ShrinkBusOptions.Inline());
|
|
|
|
var subscription = EventBus.ObserveDiagnostics(diagnostics.Add);
|
|
bus.Post(new DeferredEvent(1));
|
|
subscription.Dispose();
|
|
bus.Post(new DeferredEvent(2));
|
|
|
|
Assert.AreEqual(1, diagnostics.Count);
|
|
Assert.AreEqual(typeof(DeferredEvent), diagnostics[0].EventType);
|
|
Assert.AreEqual(key, diagnostics[0].BusKey);
|
|
Assert.IsTrue(diagnostics[0].Result.Accepted);
|
|
Assert.IsFalse(diagnostics[0].IsAsync);
|
|
Assert.GreaterOrEqual(diagnostics[0].ElapsedTimestampTicks, 0L);
|
|
}
|
|
|
|
[Test]
|
|
public void ObserveDiagnostics_ThrowingObserverDoesNotBlockBusinessOrOtherObservers()
|
|
{
|
|
var calls = 0;
|
|
var secondObserverCalls = 0;
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("diagnostics", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, ShrinkBusOptions.Inline());
|
|
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
|
|
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
|
|
using var first = EventBus.ObserveDiagnostics(_ =>
|
|
throw new InvalidOperationException("observer failure"));
|
|
using var second = EventBus.ObserveDiagnostics(_ => secondObserverCalls++);
|
|
|
|
var previous = LogAssert.ignoreFailingMessages;
|
|
LogAssert.ignoreFailingMessages = true;
|
|
try
|
|
{
|
|
Assert.DoesNotThrow(() => bus.Post(new DeferredEvent(3)));
|
|
}
|
|
finally
|
|
{
|
|
LogAssert.ignoreFailingMessages = previous;
|
|
}
|
|
|
|
Assert.AreEqual(1, calls);
|
|
Assert.AreEqual(1, secondObserverCalls);
|
|
}
|
|
|
|
[Test]
|
|
public void PostDeferred_DoesNotDispatchBeforePump()
|
|
{
|
|
var dispatcher = new ManualDispatcher();
|
|
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, new ShrinkBusOptions
|
|
{
|
|
Scheduler = ShrinkBusSchedulerKind.MainThread,
|
|
QueueCapacity = 8
|
|
});
|
|
var calls = 0;
|
|
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
|
|
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
|
|
|
|
var result = EventBus.PostDeferred(bus, new DeferredEvent(4));
|
|
|
|
Assert.IsTrue(result.Accepted);
|
|
Assert.IsFalse(result.Handled);
|
|
Assert.AreEqual(0, calls);
|
|
Assert.AreEqual(1, dispatcher.Count);
|
|
|
|
dispatcher.PumpAll();
|
|
Assert.AreEqual(1, calls);
|
|
}
|
|
|
|
[Test]
|
|
public void PostDeferred_ReentrantPostWaitsForNextPump()
|
|
{
|
|
var dispatcher = new ManualDispatcher();
|
|
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, new ShrinkBusOptions
|
|
{
|
|
Scheduler = ShrinkBusSchedulerKind.MainThread,
|
|
QueueCapacity = 8
|
|
});
|
|
var calls = 0;
|
|
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
|
|
this, _ =>
|
|
{
|
|
calls++;
|
|
if (calls == 1)
|
|
EventBus.PostDeferred(bus, new DeferredEvent(5));
|
|
}, ShrinkEventPriority.Normal, 0, false);
|
|
|
|
EventBus.PostDeferred(bus, new DeferredEvent(4));
|
|
dispatcher.PumpAll();
|
|
Assert.AreEqual(1, calls);
|
|
Assert.AreEqual(1, dispatcher.Count);
|
|
|
|
dispatcher.PumpAll();
|
|
Assert.AreEqual(2, calls);
|
|
}
|
|
|
|
[Test]
|
|
public void PostDeferred_DropOldestKeepsNewest()
|
|
{
|
|
var dispatcher = new ManualDispatcher();
|
|
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, new ShrinkBusOptions
|
|
{
|
|
Scheduler = ShrinkBusSchedulerKind.MainThread,
|
|
QueueCapacity = 1,
|
|
OverflowPolicy = ShrinkQueueOverflowPolicy.DropOldest
|
|
});
|
|
var values = new List<int>();
|
|
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
|
|
this, evt => values.Add(evt.Value), ShrinkEventPriority.Normal, 0, false);
|
|
|
|
EventBus.PostDeferred(bus, new DeferredEvent(1));
|
|
EventBus.PostDeferred(bus, new DeferredEvent(2));
|
|
dispatcher.PumpAll();
|
|
|
|
CollectionAssert.AreEqual(new[] { 2 }, values);
|
|
}
|
|
|
|
[Test]
|
|
public void PostDeferred_InlineBusFailsWithoutDispatch()
|
|
{
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, ShrinkBusOptions.Inline());
|
|
var calls = 0;
|
|
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
|
|
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
|
|
|
|
var result = EventBus.PostDeferred(bus, new DeferredEvent(6));
|
|
|
|
Assert.AreEqual(ShrinkPostFailure.DeferredUnsupported, result.Failure);
|
|
Assert.AreEqual(0, calls);
|
|
}
|
|
|
|
[Test]
|
|
public void PostDeferred_WithoutDeferredDispatcherFailsWithoutDispatch()
|
|
{
|
|
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(new NonDeferredDispatcher());
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, new ShrinkBusOptions
|
|
{
|
|
Scheduler = ShrinkBusSchedulerKind.MainThread
|
|
});
|
|
var calls = 0;
|
|
using var binding = ShrinkGeneratedBinding.Subscribe<DeferredEvent>(host, key, string.Empty,
|
|
this, _ => calls++, ShrinkEventPriority.Normal, 0, false);
|
|
|
|
var result = EventBus.PostDeferred(bus, new DeferredEvent(7));
|
|
|
|
Assert.AreEqual(ShrinkPostFailure.DeferredUnsupported, result.Failure);
|
|
Assert.AreEqual(0, calls);
|
|
}
|
|
|
|
[Test]
|
|
public void PostDeferred_DisposedBusRejects()
|
|
{
|
|
var dispatcher = new ManualDispatcher();
|
|
ShrinkEventBusRuntime.ConfigureMainThreadDispatcher(dispatcher);
|
|
using var host = new ShrinkEventBusHost();
|
|
var key = new ShrinkBusKey("deferred", Guid.NewGuid().ToString("N"));
|
|
var bus = host.CreateBus(key, new ShrinkBusOptions
|
|
{
|
|
Scheduler = ShrinkBusSchedulerKind.MainThread
|
|
});
|
|
bus.Dispose();
|
|
|
|
var result = EventBus.PostDeferred(bus, new DeferredEvent(8));
|
|
|
|
Assert.AreEqual(ShrinkPostFailure.BusStopped, result.Failure);
|
|
}
|
|
|
|
private readonly struct DeferredEvent : IShrinkEvent
|
|
{
|
|
public DeferredEvent(int value) => Value = value;
|
|
public int Value { get; }
|
|
}
|
|
|
|
private sealed class ManualDispatcher : IShrinkEventBusMainThreadDispatcher,
|
|
ShrinkSDK.Runtime.IShrinkDeferredMainThreadDispatcher
|
|
{
|
|
private readonly Queue<Action> _queue = new();
|
|
|
|
public bool IsMainThread => true;
|
|
public int Count => _queue.Count;
|
|
|
|
public bool TryPost(Action action)
|
|
{
|
|
_queue.Enqueue(action);
|
|
return true;
|
|
}
|
|
|
|
public bool TryPostDeferred(Action action)
|
|
{
|
|
_queue.Enqueue(action);
|
|
return true;
|
|
}
|
|
|
|
public void PumpAll()
|
|
{
|
|
var count = _queue.Count;
|
|
for (var i = 0; i < count; i++)
|
|
_queue.Dequeue()();
|
|
}
|
|
}
|
|
|
|
private sealed class NonDeferredDispatcher : IShrinkEventBusMainThreadDispatcher
|
|
{
|
|
public bool IsMainThread => true;
|
|
public bool TryPost(Action action) => true;
|
|
}
|
|
}
|
|
}
|