Example #1
0
def test_notify(init, number_of_subscribers):
    """ Testing .notify(v) method """
    p = Publisher(init)
    m = mock.Mock()

    # subscribing Sinks to the publisher and test .notify on subscribe
    subscribers = [Sink(m, i) for i in range(number_of_subscribers)]

    m.assert_not_called()

    for s in subscribers:
        p.subscribe(s)

    if init is not NONE:
        m.assert_has_calls([mock.call(i, init) for i in range(number_of_subscribers)])
    else:
        m.assert_not_called()

    m.reset_mock()

    # test .notify() for listening subscribers
    p.notify(1)

    m.assert_has_calls([mock.call(i, 1) for i in range(number_of_subscribers)])

    m.reset_mock()

    # re- .notify() with the same value
    p.notify(1)

    m.assert_has_calls([mock.call(i, 1) for i in range(number_of_subscribers)])
Example #2
0
def test_operator_concat():
    DUT = Concat(Map(lambda v: v / 2), Map(lambda v: v + 1))
    mock_cb = mock.Mock()

    p = Publisher()

    o = p | DUT
    assert o.get() == NONE

    p.notify(0)
    assert o.get() == 1.0

    o.subscribe(Sink(mock_cb))

    for v in range(5):
        p.notify(v)

    mock_cb.assert_has_calls([
        mock.call(1.0),
        mock.call(1.5),
        mock.call(2.0),
        mock.call(2.5),
        mock.call(3.0)
    ])

    assert o.get() == 3.0
Example #3
0
async def test_throttle_errorhandler(event_loop):
    from broqer import default_error_handler

    p = Publisher()
    mock_sink = mock.Mock()
    mock_error_handler = mock.Mock()

    default_error_handler.set(mock_error_handler)

    throttle = p | op.Throttle(0.1)
    disposable = throttle.subscribe(Sink(mock_sink))

    mock_sink.side_effect = (None, ZeroDivisionError('FAIL'))

    # test error_handler
    p.notify(1)
    await asyncio.sleep(0.05, loop=event_loop)
    mock_sink.assert_called_once_with(1)
    p.notify(2)
    await asyncio.sleep(0.1, loop=event_loop)
    mock_error_handler.assert_called_once_with(ZeroDivisionError, mock.ANY,
                                               mock.ANY)
    mock_sink.assert_has_calls((mock.call(1), mock.call(2)))

    mock_sink.reset_mock()
Example #4
0
async def test_throttle_reset(event_loop):
    p = Publisher()
    mock_sink = mock.Mock()

    throttle = p | op.Throttle(0.1)
    disposable = throttle.subscribe(Sink(mock_sink))

    p.notify(1)
    await asyncio.sleep(0.05, loop=event_loop)
    throttle.reset()
    p.notify(3)

    await asyncio.sleep(0.05, loop=event_loop)

    # reset is called after "1" was emitted
    mock_sink.assert_has_calls((mock.call(1), mock.call(3)))

    ## wait until initial state is set and reset mock
    await asyncio.sleep(0.1, loop=event_loop)
    mock_sink.reset_mock()

    p.notify(1)
    await asyncio.sleep(0.05, loop=event_loop)
    p.notify(2)
    throttle.reset()
    p.notify(3)

    await asyncio.sleep(0.05, loop=event_loop)

    # reset is called after "1" was emitted, and while "2" was hold back,
    #   therefore "1" and "3" are emitted, but "2" is ignored
    mock_sink.assert_has_calls((mock.call(1), mock.call(3)))

    disposable.dispose()
Example #5
0
def test_reset_state():
    """ Test .reset_state() """
    m = mock.Mock()
    p = Publisher()

    p.subscribe(Sink(m, 1))

    m.assert_not_called()

    # test .reset_state() before and after subscribing
    p.reset_state()
    assert p.get() == NONE

    p.subscribe(Sink(m, 2))

    m.assert_not_called()

    m.reset_mock()

    # test .reset_state() after notify
    p.notify('check')
    assert p.get() == 'check'
    m.assert_has_calls([mock.call(1, 'check'), mock.call(2, 'check')])
    m.reset_mock()

    # test no subscribers get notified
    p.reset_state()
    m.assert_not_called()

    assert p.get() == NONE
Example #6
0
def test_stateless_nested():
    source1 = Publisher()
    dut1 = CombineLatest(source1, allow_stateless=True)

    source2 = Publisher()
    dut2 = CombineLatest(dut1, source2, allow_stateless=True)

    assert len(source1.subscriptions) == 0
    assert len(source2.subscriptions) == 0
    assert len(dut1.subscriptions) == 0
    assert len(dut2.subscriptions) == 0

    collector = Collector()
    dut2 | collector
    assert len(source1.subscriptions) == 1
    assert len(source2.subscriptions) == 1
    assert len(dut1.subscriptions) == 1
    assert len(dut2.subscriptions) == 1

    with pytest.raises(ValueError):
        dut2.get()

    assert collector.result_vector == ()

    collector.reset()
    source1.notify(True)
    assert collector.result_vector == (((True, ), NONE), )

    collector.reset()
    source2.notify(False)

    assert collector.result_vector == ((NONE, False), )
Example #7
0
async def test_future_return():
    class S(Subscriber):
        def __init__(self):
            self.future = asyncio.get_event_loop().create_future()

        def emit(self, value, who: Publisher) -> asyncio.Future:
            return self.future

    p = Publisher()
    s1 = S()

    p.subscribe(s1)

    assert p.notify(None) is s1.future

    s2 = S()

    p.subscribe(s2)

    gathered_future = p.notify(None)

    await asyncio.sleep(0)
    assert not gathered_future.done()

    s1.future.set_result(1)
    await asyncio.sleep(0)
    assert not gathered_future.done()

    s2.future.set_result(1)
    await asyncio.sleep(0)
    assert gathered_future.done()
def test_getattr_attribute():
    class Foo:
        a = None

        def __init__(self, a=5):
            self.a = a

    p = Publisher(Foo(3))
    p.inherit_type(Foo)

    dut = p.a
    m = mock.Mock()
    dut.subscribe(Sink(m))

    m.assert_called_once_with(3)
    assert dut.get() == 3
    m.reset_mock()

    p.notify(Foo(4))

    assert dut.get() == 4

    m.assert_called_once_with(4)

    with pytest.raises(ValueError):
        dut.emit(0, who=Publisher())

    with pytest.raises(AttributeError):
        dut.assnign(5)
Example #9
0
async def test_throttle_unsubscribe(event_loop):
    p = Publisher()
    mock_sink = mock.Mock()

    throttle = p | op.Throttle(0.1)
    disposable = throttle.subscribe(Sink(mock_sink))

    # test subscription and unsubscribe
    p.notify(2)
    mock_sink.assert_called_once_with(2)

    await asyncio.sleep(0.05, loop=event_loop)
    mock_sink.reset_mock()

    disposable.dispose()
    await asyncio.sleep(0.1, loop=event_loop)

    # dispose must not emit anything
    mock_sink.assert_not_called()

    p.notify(3)

    await asyncio.sleep(0.1, loop=event_loop)

    # after dispose was called, p.notify must not emit to mock_sink
    mock_sink.assert_not_called()
Example #10
0
async def test_cancel():
    p = Publisher()
    future = p | OnEmitFuture(timeout=0.01)
    future.cancel()
    p.notify(1)

    with pytest.raises(asyncio.CancelledError):
        future.result()
Example #11
0
 def _done(self, future: asyncio.Future):
     try:
         result = future.result()
     except Exception:  # pylint: disable=broad-except
         self._error_callback(*sys.exc_info())
     else:
         if result != NONE:
             Publisher.notify(self, result)
Example #12
0
    def emit(self, value: Any_, who: Publisher) -> None:
        if who is not self._orginator:
            raise ValueError('Emit from non assigned publisher')

        attribute = getattr(value, self._attribute_name)

        if self._args is None:
            return Publisher.notify(self, attribute)

        return Publisher.notify(self, attribute(*self._args, **self._kwargs))
Example #13
0
    def emit(self, value: Any, who: Publisher) -> None:
        if who is not self._orginator:
            raise ValueError('Emit from non assigned publisher')

        if self._unpack:
            if self._predicate(*value):
                return Publisher.notify(self, value)
        elif self._predicate(value):
            return Publisher.notify(self, value)
        return None
Example #14
0
def test_publisher():
    p = Publisher()
    future = p | OnEmitFuture()

    assert not future.done()

    p.notify(1)
    assert future.result() == 1

    p.notify(2)
    assert future.result() == 1
Example #15
0
 def _wait_done_cb(self):
     if self._last_state is not NONE:
         try:
             Publisher.notify(self, self._last_state)
         except Exception:  # pylint: disable=broad-except
             self._error_callback(*sys.exc_info())
         self._last_state = NONE
         self._call_later_handler = self._loop.call_later(
             self._duration, self._wait_done_cb)
     else:
         self._call_later_handler = None
Example #16
0
def test_partition():
    mock = Mock()
    p = Publisher()

    dut = p | Partition(3)
    dut | Sink(mock)
    p.notify(1)
    p.notify(2)
    mock.assert_not_called()
    dut.flush()
    mock.assert_called_once_with((1, 2))
Example #17
0
    def _delayed_emit_cb(self, value=NONE):
        if value is NONE:
            # since the last emit the given duration has passed without another
            # emit
            return

        try:
            Publisher.notify(self, value)
        except Exception:  # pylint: disable=broad-except
            self._error_callback(*sys.exc_info())

        self._timer.start(self._duration)
Example #18
0
    def subscribe(self, subscriber: 'Subscriber',
                  prepend: bool = False) -> SubscriptionDisposable:
        disposable = MultiOperator.subscribe(self, subscriber, prepend)

        if self._missing:
            self._missing.clear()
            if self._state is NONE:
                Publisher.notify(self, self._init)
            else:
                Publisher.notify(self, self._state)

        return disposable
Example #19
0
def test_allow_stateless_extensive():
    source1 = StatefulPublisher(0)
    source2 = Publisher()
    source3 = StatefulPublisher(0)
    source4 = Publisher()

    dut = CombineLatest(source1,
                        source2,
                        source3,
                        source4,
                        allow_stateless=True,
                        emit_on=(source2, source3))

    with pytest.raises(ValueError):
        dut | Sink()  # source4 is stateless but not in emit_on list

    def reverse(s1, s2, s3, s4):
        return (s4, s3, s2, s1)

    dut = CombineLatest(source1,
                        source2,
                        source3,
                        source4,
                        map_=reverse,
                        allow_stateless=True,
                        emit_on=(source2, source3, source4))

    with pytest.raises(ValueError):
        dut.get()

    collector = Collector()
    dut.subscribe(collector)

    with pytest.raises(ValueError):
        dut.get()
    assert collector.result_vector == ()

    collector.reset()
    source1.notify(1)
    source2.notify(2)
    with pytest.raises(ValueError):
        dut.get()
    assert collector.result_vector == ((NONE, 0, 2, 1), )

    collector.reset()
    source3.notify(3)
    source4.notify(4)
    with pytest.raises(ValueError):
        dut.get()
    assert collector.result_vector == (
        (NONE, 3, NONE, 1),
        (4, 3, NONE, 1),
    )
def test_inherit_getattr():
    p = Publisher('')
    p.inherit_type(str)

    dut = p.lower().split(' ')
    m = mock.Mock()
    dut.subscribe(Sink(m))
    m.assert_called_once_with([''])
    m.reset_mock()

    p.notify('This is a TEST')
    m.assert_called_once_with(['this', 'is', 'a', 'test'])
def test_inherit_with_operators():
    p = Publisher('')
    p.inherit_type(str)

    dut = op.Len(('abc' + p + 'ghi').upper())
    m = mock.Mock()
    dut.subscribe(Sink(m))
    m.assert_called_once_with(6)
    m.reset_mock()

    p.notify('def')
    m.assert_called_once_with(9)
def test_uninitialised_with_publisher():
    source = Publisher()
    dut = source | Cache()
    cb = mock.Mock()
    dut | Sink(cb)

    cb.assert_not_called()

    source.notify(1)
    cb.assert_called_once_with(1)

    source.notify(1)
    cb.assert_called_once_with(1)
Example #23
0
async def test_errorhandler():
    mock = Mock(side_effect=ZeroDivisionError)
    mock_errorhandler = Mock()

    p = Publisher()

    dut = p | Delay(0.1, error_callback=mock_errorhandler)
    dut | Sink(mock)

    p.notify(1)
    await asyncio.sleep(0.15)
    mock.assert_called_once_with(1)
    mock_errorhandler.assert_called_once_with(ZeroDivisionError, ANY, ANY)
Example #24
0
def test_stateless_only():
    source1 = Publisher()
    source2 = Publisher()

    dut = CombineLatest(source1, source2, allow_stateless=True)

    collector = Collector()
    dut.subscribe(collector)

    with pytest.raises(ValueError):
        dut.get()

    source1.notify(1)
    source2.notify(True)
    source1.notify(2)
    source2.notify(False)

    assert collector.result_vector == ((1, NONE), (NONE, True), (2, NONE),
                                       (NONE, False))

    # special case with one source
    dut2 = CombineLatest(source1, allow_stateless=True)
    collector2 = Collector()
    dut2.subscribe(collector2)

    with pytest.raises(ValueError):
        dut2.get()

    assert collector2.result_vector == ()
Example #25
0
    def emit(self, value: Any_, who: Publisher) -> None:
        if who is not self._orginator:
            raise ValueError('Emit from non assigned publisher')

        result = self._operation(value)

        return Publisher.notify(self, result)
Example #26
0
    def emit(self, value: Any, who: Publisher) -> None:
        if who is not self._orginator:
            raise ValueError('Emit from non assigned publisher')

        if not bool(value):
            return Publisher.notify(self, value)
        return None
Example #27
0
    def emit(self, value: Any, who: Publisher) -> None:
        if all(who is not p for p in self._orginators):
            raise ValueError('Emit from non assigned publisher')

        # remove source publisher from ._missing
        self._missing.discard(who)

        index = self._index[who]

        # remember state of this source
        self._partial_state[index] = value

        # if emits from publishers are missing or source of this emit
        # is not one of emit_on -> don't evaluate and notify subscribers

        if self._missing or (self._emit_on is not None
                             and all(who is not p for p in self._emit_on)):
            return None

        # evaluate
        if self._map:
            state = self._map(*self._partial_state)
        else:
            state = tuple(self._partial_state)

        # if result of _map() was NONE don't emit
        if state is NONE:
            return None

        self._state = state

        return Publisher.notify(self, state)
Example #28
0
async def test_throttle(event_loop, emit_sequence, expected_emits):
    p = Publisher()
    mock_sink = mock.Mock()

    throttle = p | op.Throttle(0.5)
    disposable = throttle.subscribe(Sink(mock_sink))

    mock_sink.assert_not_called()

    for item in emit_sequence:
        await asyncio.sleep(item[0], loop=event_loop)
        p.notify(item[1])

    await asyncio.sleep(0.5, loop=event_loop)

    mock_sink.assert_has_calls(expected_emits)
Example #29
0
def check_subscription(operator, input_vector, output_vector):
    assert len(input_vector) == len(output_vector)

    m = mock.Mock()

    p = Publisher(input_vector[0])
    o = p | operator

    o2 = Publisher() | operator

    # subscribe operator to publisher
    disposable = o.subscribe(Sink(m))

    assert p.subscriptions == (o,)  # now it should be subscribed
    assert o.dependencies == (p,)

    # test emit on subscription
    if output_vector[0] is not NONE:
        m.assert_called_once_with(output_vector[0])

    m.reset_mock()

    # test input_vector
    for input_value, output_value in zip(input_vector[1:], output_vector[1:]):
        if input_value is not NONE:
            p.notify(input_value)

        if output_value is NONE:
            m.assert_not_called()
        else:
            m.assert_called_with(output_value)
        m.reset_mock()

    # test input_vector with unsubscriptions between
    disposable.dispose()
    assert o.dependencies == (p,)
    disposable = o.subscribe(Sink(m))

    for input_value, output_value in zip(input_vector, output_vector):
        if input_value is not NONE:
            m.reset_mock()
            p.notify(input_value)
            if output_value is NONE:
                m.assert_not_called()
            else:
                m.assert_called_once_with(output_value)
def test_initialised_with_publisher():
    source = Publisher()
    dut = source | Cache(1)
    cb = mock.Mock()
    dut | Sink(cb)

    cb.assert_called_once_with(1)
    cb.reset_mock()

    source.notify(2)
    cb.assert_called_once_with(2)

    source.notify(2)
    cb.assert_called_once_with(2)

    with pytest.raises(ValueError):
        Publisher() | dut