Exemple #1
0
def test_subscription_doesnt_block_subscriber_to_be_garbage_collected():
    from moler.publisher import Publisher

    notifier = Publisher()
    garbage_collected_subscribers = []

    class GcSubscriber(object):
        def __del__(self):
            garbage_collected_subscribers.append('Subscriber')

    subscr = GcSubscriber()
    notifier.subscribe(subscr)

    del subscr
    gc.collect()

    assert 'Subscriber' in garbage_collected_subscribers
Exemple #2
0
def test_exception_in_subscriber_doesnt_break_publisher_nor_other_subscribers(
):
    from moler.publisher import Publisher

    notifier = Publisher()
    received_data = []

    def failing_observer(data):
        raise Exception("Fail inside observer")

    def one_time_observer(data):
        received_data.append(data)
        notifier.unsubscribe(subscriber=one_time_observer)

    notifier.subscribe(subscriber=failing_observer)
    notifier.subscribe(subscriber=one_time_observer)

    notifier.notify_subscribers(data=b"data 1")

    notifier.unsubscribe(subscriber=failing_observer)

    assert b"data 1" in received_data
Exemple #3
0
def test_repeated_unsubscription_does_nothing_but_logs_warning():
    """
    Because of possible different concurrency models (and their races)
    we don't want to raise exception when there is already
    "no such subscription" - just put warning to logs
    """
    from moler.publisher import Publisher

    notifier = Publisher()
    received_data = []

    def one_time_observer(data):
        received_data.append(data)
        notifier.unsubscribe(subscriber=one_time_observer)

    notifier.subscribe(subscriber=one_time_observer)

    notifier.notify_subscribers(data=b"data 1")
    notifier.unsubscribe(subscriber=one_time_observer)
    # TODO: check warning in logs (when we set logging system)
    notifier.notify_subscribers(data=b"data 2")

    assert b"data 1" in received_data
    assert b"data 2" not in received_data  # because of unsubscription during notification
Exemple #4
0
def test_doesnt_subscribe_same_subscriber_twice():
    from moler.publisher import Publisher

    observer = Subscriber()
    notifier = Publisher()

    notifier.subscribe(subscriber=observer.on_new_data)
    notifier.subscribe(subscriber=observer.on_new_data)

    notifier.notify_subscribers(data=b"incoming data")

    assert len(observer.received_data) == 1
Exemple #5
0
def test_can_notify_multiple_subscribers_about_data():
    from moler.publisher import Publisher

    observer1 = Subscriber()
    observer2 = Subscriber()
    notifier = Publisher()

    notifier.subscribe(subscriber=observer1.on_new_data)
    notifier.subscribe(subscriber=observer2.on_new_data)

    notifier.notify_subscribers(data=b"incoming data")

    assert b"incoming data" in observer1.received_data
    assert b"incoming data" in observer2.received_data
Exemple #6
0
def test_notifies_only_subscribed_ones_about_data():
    from moler.publisher import Publisher

    observer1 = Subscriber()
    observer2 = Subscriber()
    observer3 = Subscriber()
    notifier = Publisher()

    notifier.subscribe(subscriber=observer1.on_new_data)
    notifier.subscribe(subscriber=observer2.on_new_data)

    notifier.notify_subscribers(data=b"incoming data")

    assert b"incoming data" in observer1.received_data
    assert b"incoming data" in observer2.received_data
    assert b"incoming data" not in observer3.received_data  # that one was not subscribed
Exemple #7
0
def test_notified_subscriber_may_stop_subscription():
    from moler.publisher import Publisher

    notifier = Publisher()
    received_data = []

    def one_time_observer(data):
        received_data.append(data)
        notifier.unsubscribe(subscriber=one_time_observer)

    notifier.subscribe(subscriber=one_time_observer)

    notifier.notify_subscribers(data=b"data 1")
    notifier.notify_subscribers(data=b"data 2")

    assert b"data 1" in received_data
    assert b"data 2" not in received_data  # because of unsubscription during notification
Exemple #8
0
def test_garbage_collected_subscriber_is_not_notified():
    from moler.publisher import Publisher

    notifier = Publisher()
    received_data = []

    class GcSubscriber(object):
        def __call__(self, data):
            received_data.append(data)

    subscr1 = GcSubscriber()
    subscr2 = GcSubscriber()
    notifier.subscribe(subscriber=subscr1)
    notifier.subscribe(subscriber=subscr2)

    del subscr1
    gc.collect()

    notifier.notify_subscribers("data")
    assert len(received_data) == 1
Exemple #9
0
def test_single_unsubscription_doesnt_impact_other_subscribers():
    from moler.publisher import Publisher

    observer1 = Subscriber()
    observer2 = Subscriber()

    function_received_data = []

    def raw_fun1(data):
        function_received_data.append(data)

    def raw_fun2(data):
        function_received_data.append(data)

    class TheCallableClass(object):
        def __init__(self):
            self.received_data = []

        def __call__(self, data):
            self.received_data.append(data)

    callable1 = TheCallableClass()
    callable2 = TheCallableClass()

    notifier = Publisher()
    notifier.subscribe(subscriber=observer1.on_new_data)
    notifier.subscribe(subscriber=observer2.on_new_data)
    notifier.subscribe(subscriber=observer2.on_new_data)
    notifier.unsubscribe(subscriber=observer1.on_new_data)
    notifier.unsubscribe(subscriber=observer1.on_new_data)

    notifier.subscribe(subscriber=raw_fun1)
    notifier.subscribe(subscriber=raw_fun2)
    notifier.subscribe(subscriber=raw_fun2)
    notifier.unsubscribe(subscriber=raw_fun1)

    notifier.subscribe(subscriber=callable1)
    notifier.subscribe(subscriber=callable2)
    notifier.subscribe(subscriber=callable2)
    notifier.unsubscribe(subscriber=callable1)

    notifier.notify_subscribers("incoming data")

    assert observer1.received_data == []
    assert observer2.received_data == ["incoming data"]

    assert function_received_data == ["incoming data"]

    assert callable1.received_data == []
    assert callable2.received_data == ["incoming data"]
Exemple #10
0
def test_subscriber_must_have_function_signature_matching_the_one_expected_by_publisher(
):
    from moler.publisher import Publisher

    notifier = Publisher()
    received_data = []

    def compatible_fun(data, info, default=None):
        received_data.append(("compatible_fun", data, info, default))

    def incompatible_fun(data):
        received_data.append(("incompatible_fun", data))

    notifier.subscribe(subscriber=compatible_fun)
    notifier.subscribe(subscriber=incompatible_fun)

    def handle_exception(self, subscriber_owner, subscriber_function,
                         raised_exception):
        assert subscriber_owner is None
        assert subscriber_function.__name__ == "incompatible_fun"
        assert isinstance(raised_exception, TypeError)
        assert "unexpected keyword argument 'info'" in str(raised_exception)

    with mock.patch.object(notifier.__class__, "handle_subscriber_exception",
                           handle_exception):
        notifier.notify_subscribers(data="data1", info="INFO", default="DEF")
        assert received_data == [("compatible_fun", "data1", "INFO", "DEF")
                                 ]  # only 1 entry

    notifier.unsubscribe(subscriber=compatible_fun)
    notifier.unsubscribe(subscriber=incompatible_fun)
Exemple #11
0
def test_subscriber_may_have_different_function_signature():
    from moler.publisher import Publisher

    notifier = Publisher()
    received_data = []

    def no_param_fun():
        received_data.append("no_param_fun")

    notifier.subscribe(subscriber=no_param_fun)
    notifier.notify_subscribers()
    assert received_data[-1] == "no_param_fun"
    notifier.unsubscribe(subscriber=no_param_fun)

    def single_param_fun(data):
        received_data.append(("single_param_fun", data))

    notifier.subscribe(subscriber=single_param_fun)
    notifier.notify_subscribers(data=b"data 1")
    assert received_data[-1] == ("single_param_fun", b"data 1")
    notifier.unsubscribe(subscriber=single_param_fun)

    def multi_param_fun(data, info, default=None):
        received_data.append(("multi_param_fun", data, info, default))

    notifier.subscribe(subscriber=multi_param_fun)
    notifier.notify_subscribers(data="data1", info="INFO", default="DEF")
    assert received_data[-1] == ("multi_param_fun", "data1", "INFO", "DEF")
    notifier.notify_subscribers(data="data2", info="INFO")
    assert received_data[-1] == ("multi_param_fun", "data2", "INFO", None)
    notifier.unsubscribe(subscriber=multi_param_fun)

    def variable_param_fun(*args, **kwargs):
        received_data.append(("variable_param_fun", args, kwargs))

    notifier.subscribe(subscriber=variable_param_fun)
    notifier.notify_subscribers("data1", "INFO", "DEF")
    assert received_data[-1] == ("variable_param_fun", ("data1", "INFO",
                                                        "DEF"), {})
    notifier.notify_subscribers(data="data2", info="INFO", default="DEF")
    assert received_data[-1] == ("variable_param_fun", (), {
        "data": "data2",
        "info": "INFO",
        "default": "DEF"
    })
    notifier.notify_subscribers("data3", info="INFO", default="DEF")
    assert received_data[-1] == ("variable_param_fun", ("data3", ), {
        "info": "INFO",
        "default": "DEF"
    })
    notifier.unsubscribe(subscriber=variable_param_fun)