示例#1
0
        public void A_borken_Flow_must_cancel_upstream_and_call_onError_on_current_and_future_downstream_subscribers_if_an_internal_error_occurs()
        {
            var setup = new ChainSetup <string, string, NotUsed>(FaultyFlow <string, string, string>, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 16), this);

            Action <TestSubscriber.ManualProbe <string> > checkError = sprobe =>
            {
                var error = sprobe.ExpectError();
                error.Should().BeOfType <AbruptTerminationException>();
                error.Message.Should().StartWith("Processor actor");
            };

            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            var downstream2Subscription = downstream2.ExpectSubscription();

            setup.DownstreamSubscription.Request(5);
            downstream2Subscription.Request(5);
            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("a1");
            setup.Downstream.ExpectNext("a1");
            downstream2.ExpectNext("a1");

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("a2");
            setup.Downstream.ExpectNext("a2");
            downstream2.ExpectNext("a2");

            var filters = new EventFilterBase[]
            {
                new ErrorFilter(typeof(NullReferenceException)),
                new ErrorFilter(typeof(IllegalStateException)),
                new ErrorFilter(typeof(PostRestartException)),// This is thrown because we attach the dummy failing actor to toplevel
            };

            try
            {
                Sys.EventStream.Publish(new Mute(filters));

                setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
                setup.UpstreamSubscription.SendNext("a3");
                setup.UpstreamSubscription.ExpectCancellation();

                // IllegalStateException terminated abruptly
                checkError(setup.Downstream);
                checkError(downstream2);

                var downstream3 = this.CreateManualSubscriberProbe <string>();
                setup.Publisher.Subscribe(downstream3);
                downstream3.ExpectSubscription();
                // IllegalStateException terminated abruptly
                checkError(downstream3);
            }
            finally
            {
                Sys.EventStream.Publish(new Unmute(filters));
            }
        }
示例#2
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_adapt_speed_to_the_currently_slowest_subscriber()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 1), this);
            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            var downstream2Subscription = downstream2.ExpectSubscription();

            setup.DownstreamSubscription.Request(5);
            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1); // because initialInputBufferSize=1

            setup.UpstreamSubscription.SendNext("firstElement");
            setup.Downstream.ExpectNext("firstElement");

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("element2");

            setup.Downstream.ExpectNoMsg(TimeSpan.FromSeconds(1));
            downstream2Subscription.Request(1);
            downstream2.ExpectNext("firstElement");

            setup.Downstream.ExpectNext("element2");

            downstream2Subscription.Request(1);
            downstream2.ExpectNext("element2");
        }
示例#3
0
        public void A_Flow_must_deliver_complete_signal_when_publisher_immediately_completes()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings,
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);

            setup.UpstreamSubscription.SendComplete();
            setup.Downstream.ExpectComplete();
        }
示例#4
0
        public void A_Flow_must_deliver_error_signal_when_publisher_immediately_fails()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings,
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);
            var weirdError = new Exception("weird test exception");

            setup.UpstreamSubscription.SendError(weirdError);
            setup.Downstream.ExpectError().Should().Be(weirdError);
        }
示例#5
0
        public void A_Flow_must_deliver_events_when_publisher_sends_elements_and_then_completes()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings,
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);

            setup.DownstreamSubscription.Request(1);
            setup.UpstreamSubscription.SendNext("test");
            setup.UpstreamSubscription.SendComplete();
            setup.Downstream.ExpectNext("test");
            setup.Downstream.ExpectComplete();
        }
示例#6
0
        public void A_flow_must_request_initial_elements_from_upstream(string name, int n)
        {
            ChainSetup <int, int, NotUsed> setup;

            if (name.Equals("identity"))
            {
                setup = new ChainSetup <int, int, NotUsed>(Identity, Settings.WithInputBuffer(n, n),
                                                           (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);
            }
            else
            {
                setup = new ChainSetup <int, int, NotUsed>(Identity2, Settings.WithInputBuffer(n, n),
                                                           (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);
            }

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, setup.Settings.MaxInputBufferSize);
        }
示例#7
0
        public void A_Flow_must_cancel_upstream_when_single_subscriber_cancels_subscription_while_receiving_data()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);

            setup.DownstreamSubscription.Request(5);
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("test");
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("test2");
            setup.Downstream.ExpectNext("test");
            setup.Downstream.ExpectNext("test2");
            setup.DownstreamSubscription.Cancel();

            // because of the "must cancel its upstream Subscription if its last downstream Subscription has been canceled" rule
            setup.UpstreamSubscription.ExpectCancellation();
        }
示例#8
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_call_future_subscribers_OnError_when_all_subscriptions_were_cancelled()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 16), this);

            // make sure stream is initialized before canceling downstream
            Thread.Sleep(100);

            setup.UpstreamSubscription.ExpectRequest(1);
            setup.DownstreamSubscription.Cancel();
            setup.UpstreamSubscription.ExpectCancellation();

            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            // IllegalStateException shut down
            downstream2.ExpectSubscriptionAndError().Should().BeAssignableTo <IllegalStateException>();
        }
示例#9
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_support_slow_subscriber_with_fan_out_2()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 2), this);
            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            var downstream2Subscription = downstream2.ExpectSubscription();

            setup.DownstreamSubscription.Request(5);
            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1); // because initialInputBufferSize=1

            setup.UpstreamSubscription.SendNext("element1");
            setup.Downstream.ExpectNext("element1");

            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("element2");
            setup.Downstream.ExpectNext("element2");
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("element3");
            // downstream2 has not requested anything, fan-out buffer 2
            setup.Downstream.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(100)));

            downstream2Subscription.Request(2);
            setup.Downstream.ExpectNext("element3");
            downstream2.ExpectNext("element1");
            downstream2.ExpectNext("element2");
            downstream2.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(100)));

            setup.UpstreamSubscription.Request(1);
            setup.UpstreamSubscription.SendNext("element4");
            setup.Downstream.ExpectNext("element4");

            downstream2Subscription.Request(2);
            downstream2.ExpectNext("element3");
            downstream2.ExpectNext("element4");

            setup.UpstreamSubscription.SendComplete();
            setup.Downstream.ExpectComplete();
            downstream2.ExpectComplete();
        }
示例#10
0
        public void A_Flow_must_request_more_elements_from_upstream_when_downstream_requests_more_elements()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings,
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings), ToPublisher, this);

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, Settings.MaxInputBufferSize);
            setup.DownstreamSubscription.Request(1);
            setup.Upstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100));
            setup.DownstreamSubscription.Request(2);
            setup.Upstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100));
            setup.UpstreamSubscription.SendNext("a");
            setup.Downstream.ExpectNext("a");
            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.Upstream.ExpectNoMsg(TimeSpan.FromMilliseconds(100));
            setup.UpstreamSubscription.SendNext("b");
            setup.UpstreamSubscription.SendNext("c");
            setup.UpstreamSubscription.SendNext("d");
            setup.Downstream.ExpectNext("b");
            setup.Downstream.ExpectNext("c");
        }
示例#11
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_call_future_subscribers_OnError_after_OnSubscribe_if_initial_upstream_was_completed()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 1), this);
            var downstream2 = this.CreateManualSubscriberProbe <string>();

            // don't link it just yet

            setup.DownstreamSubscription.Request(5);
            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("a1");
            setup.Downstream.ExpectNext("a1");

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("a2");
            setup.Downstream.ExpectNext("a2");

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);

            // link now while an upstream element is already requested
            setup.Publisher.Subscribe(downstream2);
            var downstream2Subscription = downstream2.ExpectSubscription();

            setup.UpstreamSubscription.SendNext("a3");
            setup.UpstreamSubscription.SendComplete();
            setup.Downstream.ExpectNext("a3");
            setup.Downstream.ExpectComplete();

            downstream2.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(100))); // as nothing was requested yet, fanOutBox needs to cache element in this case

            downstream2Subscription.Request(1);
            downstream2.ExpectNext("a3");
            downstream2.ExpectComplete();

            var downstream3 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream3);
            downstream3.ExpectSubscription();
            downstream3.ExpectError().Should().BeOfType <NormalShutdownException>();
        }
示例#12
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_support_incoming_subscriber_while_elements_were_requested_before()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 1), this);

            setup.DownstreamSubscription.Request(5);
            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("a1");
            setup.Downstream.ExpectNext("a1");

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);
            setup.UpstreamSubscription.SendNext("a2");
            setup.Downstream.ExpectNext("a2");

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1);

            // link now while an upstream element is already requested
            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            var downstream2Subscription = downstream2.ExpectSubscription();

            // situation here:
            // downstream 1 now has 3 outstanding
            // downstream 2 has 0 outstanding

            setup.UpstreamSubscription.SendNext("a3");
            setup.Downstream.ExpectNext("a3");
            downstream2.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(100))); // as nothing was requested yet, fanOutBox needs to cache element in this case

            downstream2Subscription.Request(1);
            downstream2.ExpectNext("a3");

            // d1 now has 2 outstanding
            // d2 now has 0 outstanding
            // buffer should be empty so we should be requesting one new element

            setup.Upstream.ExpectRequest(setup.UpstreamSubscription, 1); // because of buffer size 1
        }
示例#13
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_call_future_subscribers_OnError_should_be_called_instead_of_OnSubscribed_after_initial_upstream_reported_an_error()
        {
            var setup = new ChainSetup <int, string, NotUsed>(flow => flow.Select <int, int, string, NotUsed>(_ =>
            {
                throw new TestException("test");
            }), Settings.WithInputBuffer(1, 1),
                                                              (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                              (source, materializer) => ToFanoutPublisher(source, materializer, 1), this);

            setup.DownstreamSubscription.Request(1);
            setup.UpstreamSubscription.ExpectRequest(1);

            setup.UpstreamSubscription.SendNext(5);
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.ExpectCancellation();
            setup.Downstream.ExpectError().Should().BeOfType <TestException>();

            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            downstream2.ExpectSubscriptionAndError().Should().BeOfType <TestException>();
        }
示例#14
0
        public void A_Flow_with_multiple_subscribers_FanOutBox_must_be_unblocked_when_blocking_subscriber_cancels_subscription()
        {
            var setup = new ChainSetup <string, string, NotUsed>(Identity, Settings.WithInputBuffer(1, 1),
                                                                 (settings, factory) => ActorMaterializer.Create(factory, settings),
                                                                 (source, materializer) => ToFanoutPublisher(source, materializer, 1), this);
            var downstream2 = this.CreateManualSubscriberProbe <string>();

            setup.Publisher.Subscribe(downstream2);
            var downstream2Subscription = downstream2.ExpectSubscription();

            setup.DownstreamSubscription.Request(5);
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("firstElement");
            setup.Downstream.ExpectNext("firstElement");

            downstream2Subscription.Request(1);
            downstream2.ExpectNext("firstElement");
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("element2");

            setup.Downstream.ExpectNext("element2");
            setup.UpstreamSubscription.ExpectRequest(1);
            setup.UpstreamSubscription.SendNext("element3");
            setup.UpstreamSubscription.ExpectRequest(1);


            setup.Downstream.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(200)));
            setup.Upstream.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(200)));
            downstream2.ExpectNoMsg(Dilated(TimeSpan.FromMilliseconds(200)));

            // should unblock fanoutbox
            downstream2Subscription.Cancel();
            setup.Downstream.ExpectNext("element3");
            setup.UpstreamSubscription.SendNext("element4");
            setup.Downstream.ExpectNext("element4");

            setup.UpstreamSubscription.SendComplete();
            setup.Downstream.ExpectComplete();
        }