public async void SubscribersShouldNotBlockEachOther() { var source = new Subject <int>(); var queue1 = new QueuedObservable <int>(Mock.Of <ILogger <IHaContext> >()); queue1.Initialize(source); var subscriber = new Mock <IObserver <int> >(); queue1.Subscribe(subscriber.Object); // The second subscriber will block the first event var queue2 = new QueuedObservable <int>(Mock.Of <ILogger <IHaContext> >()); queue2.Initialize(source); var blockSubscribers = new ManualResetEvent(false); queue2.Subscribe(_ => blockSubscribers.WaitOne()); // now send three events source.OnNext(1); source.OnNext(2); source.OnNext(3); await queue1.DisposeAsync().ConfigureAwait(false); // all events should reach the first subscriber subscriber.Verify(s => s.OnNext(1), Times.Once); subscriber.Verify(s => s.OnNext(2), Times.Once); subscriber.Verify(s => s.OnNext(3), Times.Once); blockSubscribers.Set(); }
public async Task TestQueuedObservableShouldLogOnException() { var source = new Subject <int>(); var loggerMock = new Mock <ILogger <IHaContext> >(); var queue = new QueuedObservable <int>(loggerMock.Object); queue.Initialize(source); var subscriber = new Mock <IObserver <int> >(); subscriber.Setup(n => n.OnNext(1)).Throws <InvalidOperationException>(); queue.Subscribe(subscriber.Object); source.OnNext(1); await queue.DisposeAsync().ConfigureAwait(false); // Verify that an error has been logged loggerMock.Verify( x => x.Log( LogLevel.Error, It.IsAny <EventId>(), It.Is <It.IsAnyType>((_, __) => true), It.IsAny <Exception>(), It.Is <Func <It.IsAnyType, Exception?, string> >((_, _) => true)), Times.Once); }
public async Task WhenScopeIsDisposedSubscribersAreDetached() { var testSubject = new Subject <string>(); var loggerMock = new Mock <ILogger <IHaContext> >(); // Create 2 ScopedObservables for the same subject var scoped1 = new QueuedObservable <string>(loggerMock.Object); scoped1.Initialize(testSubject); var scoped2 = new QueuedObservable <string>(loggerMock.Object); scoped2.Initialize(testSubject); // First scope has 2 subscribers, second has 1 var scope1AObserverMock = new Mock <IObserver <string> >(); var scope1BObserverMock = new Mock <IObserver <string> >(); scoped1.Subscribe(scope1AObserverMock.Object); scoped1.Subscribe(scope1BObserverMock.Object); var scope2ObserverMock = new Mock <IObserver <string> >(); scoped2.Subscribe(scope2ObserverMock.Object); var waitTasks = new Task[] { scope1AObserverMock.WaitForInvocationAndVerify(o => o.OnNext("Event1")), scope1BObserverMock.WaitForInvocationAndVerify(o => o.OnNext("Event1")), scope2ObserverMock.WaitForInvocationAndVerify(o => o.OnNext("Event1")) }; // Now start firing events testSubject.OnNext("Event1"); await Task.WhenAll(waitTasks); await scoped1.DisposeAsync(); var waitTask2 = scope2ObserverMock.WaitForInvocationAndVerify(o => o.OnNext("Event2")); testSubject.OnNext("Event2"); await waitTask2.ConfigureAwait(false); scope1AObserverMock.Verify(o => o.OnNext("Event2"), Times.Never, "Event should not reach Observer of disposed scope"); scope1BObserverMock.Verify(o => o.OnNext("Event2"), Times.Never, "Event should not reach Observer of disposed scope"); scope2ObserverMock.Verify(o => o.OnNext("Event2"), Times.Once); await scoped2.DisposeAsync(); testSubject.OnNext("Event3"); scope1AObserverMock.Verify(o => o.OnNext("Event3"), Times.Never, "Event should not reach Observer of disposed scope"); scope1BObserverMock.Verify(o => o.OnNext("Event3"), Times.Never, "Event should not reach Observer of disposed scope"); scope2ObserverMock.Verify(o => o.OnNext("Event3"), Times.Never, "Event should not reach Observer of disposed scope"); }
public async void EventsSouldbeforwarded() { var source = new Subject <int>(); var queue = new QueuedObservable <int>(Mock.Of <ILogger <IHaContext> >()); queue.Initialize(source); var subscriber = new Mock <IObserver <int> >(); queue.Subscribe(subscriber.Object); source.OnNext(1); source.OnNext(2); source.OnNext(3); await queue.DisposeAsync().ConfigureAwait(false); subscriber.Verify(s => s.OnNext(1), Times.Once); subscriber.Verify(s => s.OnNext(2), Times.Once); subscriber.Verify(s => s.OnNext(3), Times.Once); }
public async Task TestQueuedObservableShouldHaveFinishedTasksOnDispose() { var source = new Subject <int>(); var queue = new QueuedObservable <int>(Mock.Of <ILogger <IHaContext> >()); queue.Initialize(source); var subscriber = new Mock <IObserver <int> >(); queue.Subscribe(subscriber.Object); // It is not enough that DisposeAsync waits on task // since it can be aborted by the cancellation token var waitOnCallTask = subscriber.WaitForInvocation(n => n.OnNext(1)); source.OnNext(1); await waitOnCallTask.ConfigureAwait(false); await queue.DisposeAsync().ConfigureAwait(false); subscriber.Verify(s => s.OnNext(1)); }
public async Task TestQueuedObservableShouldStillHaveSubscribersOnException() { var source = new Subject <int>(); var loggerMock = new Mock <ILogger <IHaContext> >(); var queue = new QueuedObservable <int>(loggerMock.Object); queue.Initialize(source); var subscriber = new Mock <IObserver <int> >(); subscriber.Setup(n => n.OnNext(1)).Throws <InvalidOperationException>(); queue.Subscribe(subscriber.Object); var waitOnCallTask = subscriber.WaitForInvocation(n => n.OnNext(1)); source.OnNext(1); await waitOnCallTask.ConfigureAwait(false); source.HasObservers.Should().BeTrue(); await queue.DisposeAsync().ConfigureAwait(false); source.HasObservers.Should().BeFalse(); }