def setUp(self):
     self.scheduler = TScheduler()
     self.source = TObservable()
     self.subject = CacheServeFirstObservableSubject(
         scheduler=self.scheduler)
     self.source.observe(init_observer_info(self.subject))
     self.exc = Exception()
    def unsafe_subscribe(self, subscriber: Subscriber) -> Subscription:
        # assert self.is_first and not self.is_stopped, (
        #     f'subject not initial state when `subscribe` is called, '
        #     f'consider to schedule the `on_next` action  with {self.scheduler}'
        # )

        if self._observable_subject is None:
            self._observable_subject = CacheServeFirstObservableSubject(
                scheduler=subscriber.scheduler)
        return init_subscription(observable=self._observable_subject)
Esempio n. 3
0
class Subject(SubjectBase):
    def __init__(self):
        super().__init__()

        self._obs_subject = None

    def unsafe_subscribe(self, subscriber: Subscriber) -> Subscription:
        self._obs_subject = CacheServeFirstObservableSubject(
            scheduler=subscriber.scheduler)
        return init_subscription(observable=self._obs_subject)

    def on_next(self, elem: Any):
        if self._obs_subject is not None:
            return self._obs_subject.on_next([elem])
        else:
            return continue_ack

    def on_error(self, exc: Exception):
        if self._obs_subject is not None:
            self._obs_subject.on_error(exc)

    def on_completed(self):
        if self._obs_subject is not None:
            self._obs_subject.on_completed()
Esempio n. 4
0
 def unsafe_subscribe(self, subscriber: Subscriber) -> Subscription:
     self._obs_subject = CacheServeFirstObservableSubject(
         scheduler=subscriber.scheduler)
     return init_subscription(observable=self._obs_subject)
Esempio n. 5
0
 def default_subject_gen(scheduler: Scheduler):
     return CacheServeFirstObservableSubject(scheduler=scheduler)
 def test_initialize(self):
     CacheServeFirstObservableSubject(scheduler=self.scheduler)
class TestCachedServeFirstSubject(TestCaseBase):
    def setUp(self):
        self.scheduler = TScheduler()
        self.source = TObservable()
        self.subject = CacheServeFirstObservableSubject(
            scheduler=self.scheduler)
        self.source.observe(init_observer_info(self.subject))
        self.exc = Exception()

    def test_initialize(self):
        CacheServeFirstObservableSubject(scheduler=self.scheduler)

    def test_on_next_synchronously(self):
        """
                                     on_next
        inactive_subscriptions = [s1] -> inactive_subscriptions = [s1]
        """

        # preparation
        observer = TObserver()
        self.subject.observe(init_observer_info(observer))

        # state change (change to the same state)
        ack = self.source.on_next_single(1)

        # verification
        self.assertIsInstance(ack, ContinueAck)
        self.assertEqual([1], observer.received)
        self.assertEqual(0, len(self.subject.shared_state.queue))

    def test_on_completed(self):
        """
               on_completed
        NormalState -> CompletedState
        """

        # preparation
        o1 = TObserver()
        self.subject.observe(init_observer_info(o1))

        # state change
        self.source.on_completed()

        # verification
        self.assertTrue(o1.is_completed)
        self.assertIsInstance(self.subject.state,
                              CacheServeFirstObservableSubject.CompletedState)

    def test_on_next_assynchronously(self):
        """
                                     on_next
        inactive_subscriptions = [s1] -> inactive_subscriptions = []
        """

        # preparation
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))

        # state change
        ack = self.source.on_next_single(1)

        # verification
        self.assertNotEqual(continue_ack, ack)
        self.assertEqual([1], o1.received)

    def test_on_next_assynchronously2(self):
        """
                                ack.on_next
        inactive_subscriptions = [] -> inactive_subscriptions = [s1]
        """

        # preparation
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        ack = self.source.on_next_single(1)

        # state change
        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        # verification
        self.assertEqual(len(self.subject.shared_state.inactive_subscriptions),
                         1)

    def test_on_next_multiple_elements_asynchronously(self):
        """
                 on_next
        queue = [] -> queue = [OnNext(2)]
        """

        # preparation
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.source.on_next_single(1)

        # state change
        self.source.on_next_single(2)

        # verification
        self.assertEqual([1], o1.received)
        queue = self.subject.shared_state.queue
        self.assertEqual(1, len(queue))
        self.assertEqual([2], queue[0].value)

    def test_on_next_assynchronously_enter_fast_loop(self):
        """
                        ack.on_next
        queue = [OnNext(2)] -> queue = []
        """

        #preparation
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.source.on_next_single(1)
        self.source.on_next_single(2)

        # enter fast loop
        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        # verification
        self.assertEqual([1, 2], o1.received)

    def test_on_next_assynchronously_iterate_in_fast_loop(self):
        """
                 on_next
        queue = [] -> queue = [OnNext(2)]
        """

        # preparation
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.source.on_next_single(1)
        self.source.on_next_single(2)
        self.source.on_next_single(3)

        # state change
        o1.immediate_continue = 1  # needs immediate continue to loop
        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        # validation
        self.assertEqual([1, 2, 3], o1.received)
        self.assertEqual(0, len(self.subject.shared_state.queue))

    def test_on_next_assynchronously_reenter_fast_loop(self):
        """
                        ack.on_next
        queue = [OnNext(3)] -> queue = []
        """

        # preparations
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.source.on_next_single(1)
        self.source.on_next_single(2)
        self.source.on_next_single(3)
        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        # state change
        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        # validation
        self.assertEqual([1, 2, 3], o1.received)
        self.assertEqual(0, len(self.subject.shared_state.queue))

    def test_on_next_two_subscribers_synchronously(self):
        """
                                     on_next
        inactive_subscriptions = [s1, s2] -> inactive_subscriptions = [s1, s2]
        """

        # preparation
        o1 = TObserver()
        o2 = TObserver()
        self.subject.observe(init_observer_info(o1))
        self.subject.observe(init_observer_info(o2))

        # state change
        ack = self.source.on_next_single(1)

        # verification
        self.assertIsInstance(ack, ContinueAck)
        self.assertEqual([1], o1.received)
        self.assertEqual([1], o2.received)
        self.assertEqual(0, len(self.subject.shared_state.queue))

    def test_on_next_multiple_elements_two_subscribers_asynchronously(self):
        """
                                       on_next
        inactive_subscriptions = [s1, s2] -> inactive_subscriptions = [s1, s2]
                               queue = [] -> queue = [OnNext(2)]
        """

        # preparation
        o1 = TObserver(immediate_continue=0)
        o2 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.subject.observe(init_observer_info(o2))
        self.source.on_next_single(1)

        # state change
        self.source.on_next_single(2)

        # validation
        self.assertEqual([1], o1.received)
        self.assertEqual([1], o2.received)
        self.assertEqual(1, len(self.subject.shared_state.queue))

    def test_on_next_enter_fast_loop_two_subscribers_asynchronously(self):
        o1 = TObserver(immediate_continue=0)
        o2 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.subject.observe(init_observer_info(o2))
        self.source.on_next_single(1)
        self.source.on_next_single(2)

        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        self.assertEqual([1, 2], o1.received)
        self.assertEqual([1], o2.received)

    def test_on_next_enter_fast_loop_two_subscribers_asynchronously2(self):
        o1 = TObserver()
        o2 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.subject.observe(init_observer_info(o2))

        self.source.on_next_single(1)
        self.source.on_next_single(2)

        o2.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        o2.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        self.source.on_next_single(3)

        self.assertEqual([1, 2, 3], o1.received)
        self.assertEqual([1, 2, 3], o2.received)

    def test_on_error(self):
        """
               on_completed
        NormalState -> ErrorState
        """

        # preparation
        o1 = TObserver()
        self.subject.observe(init_observer_info(o1))

        # state change
        self.source.on_error(self.exc)

        # verification
        self.assertEqual(self.exc, o1.exception)
        self.assertIsInstance(self.subject.state,
                              CacheServeFirstObservableSubject.ExceptionState)

    def test_on_next_on_error_asynchronously(self):
        o1 = TObserver(immediate_continue=0)
        o2 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.subject.observe(init_observer_info(o2))

        ack = self.source.on_next_single(1)
        self.source.on_error(self.exc)

        # o2.ack.on_next(continue_ack)
        # self.scheduler.advance_by(1)

        # verification
        self.assertEqual(self.exc, o1.exception)
        self.assertEqual(self.exc, o2.exception)

    def test_on_error_two_subscribers_asynchronously(self):
        o1 = TObserver()
        o2 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.subject.observe(init_observer_info(o2))
        self.source.on_next_single(1)

        self.source.on_error(self.exc)

        self.assertEqual(self.exc, o1.exception)
        self.assertEqual(self.exc, o2.exception)

    def test_on_error_asynchronously(self):
        o1 = TObserver(immediate_continue=0)
        self.subject.observe(init_observer_info(o1))
        self.source.on_next_single(1)
        self.source.on_error(self.exc)

        o1.ack.on_next(continue_ack)
        self.scheduler.advance_by(1)

        self.assertEqual(self.exc, o1.exception)

    def test_on_disposed(self):
        sink = TObserver(immediate_continue=0)
        disposable = self.subject.observe(init_observer_info(sink))

        disposable.dispose()

        self.source.on_next_single(1)

        self.assertEqual([], sink.received)
class SafeFlowableSubject(
        Flowable[ValueType],
        Observer,
        Generic[ValueType],
):
    composite_diposable: CompositeDisposable
    scheduler: Scheduler

    def __post_init__(self):
        self.is_first = True
        self.is_stopped = False
        self.subscribe_scheduler = TrampolineScheduler()

        self._observable_subject = None

    @property
    def underlying(self) -> FlowableMixin:
        return self

    @property
    def is_hot(self) -> bool:
        return True

    def _copy(self, underlying: FlowableMixin, *args, **kwargs):
        return init_flowable(underlying=underlying, )

    def unsafe_subscribe(self, subscriber: Subscriber) -> Subscription:
        # assert self.is_first and not self.is_stopped, (
        #     f'subject not initial state when `subscribe` is called, '
        #     f'consider to schedule the `on_next` action  with {self.scheduler}'
        # )

        if self._observable_subject is None:
            self._observable_subject = CacheServeFirstObservableSubject(
                scheduler=subscriber.scheduler)
        return init_subscription(observable=self._observable_subject)

    def subscribe_to(self, source: Flowable, scheduler: Scheduler = None):
        scheduler = scheduler or self.scheduler

        subscription = source.unsafe_subscribe(
            init_subscriber(
                scheduler=scheduler,
                subscribe_scheduler=self.subscribe_scheduler,
            ))

        outer_self = self

        class SafeFlowableObserver(Observer):
            def on_next(self, elem: Any):
                if not outer_self.is_stopped:
                    outer_self.is_first = False

                    if outer_self._observable_subject is not None:
                        return outer_self._observable_subject.on_next(elem)

                return continue_ack

            def on_error(self, exc: Exception):
                outer_self.on_error(exc)

            def on_completed(self):
                outer_self.on_completed()

        observer = SafeFlowableObserver()

        disposable = subscription.observable.observe(
            init_observer_info(observer=observer, ))

        self.composite_diposable.add(disposable)

    def on_next(self, elem: Any):
        if not self.is_stopped:
            self.is_first = False

            if self._observable_subject is not None:
                return self._observable_subject.on_next([elem])

        return continue_ack

    def on_next_batch(self, elem: List[Any]):
        if not self.is_stopped:
            self.is_first = False

            if self._observable_subject is not None:
                return self._observable_subject.on_next(elem)

        return continue_ack

    def on_error(self, exc: Exception):
        if not self.is_stopped and self._observable_subject is not None:
            self.is_stopped = True
            self._observable_subject.on_error(exc)

    def on_completed(self):
        if not self.is_stopped and self._observable_subject is not None:
            self.is_stopped = True
            self._observable_subject.on_completed()