def test_exception_in_observer_doesnt_break_connection_nor_other_observers( buffer_transport_class): from moler.observable_connection import ObservableConnection moler_conn = ObservableConnection() moler_received_data = [] def failing_observer(data): raise Exception("Fail inside observer") def one_time_observer(data): moler_received_data.append(data) moler_conn.unsubscribe(observer=one_time_observer, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=failing_observer, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=one_time_observer, connection_closed_handler=do_nothing_func) used_io = buffer_transport_class( moler_connection=moler_conn) # external-IO internally sets .how2send used_io.write(input_bytes=b"data 1") # inject to buffer for next line read used_io.read() moler_conn.unsubscribe(observer=failing_observer, connection_closed_handler=do_nothing_func) assert b"data 1" in moler_received_data
def test_repeated_unsubscription_does_nothing_but_logs_warning( buffer_transport_class): """ 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.observable_connection import ObservableConnection moler_conn = ObservableConnection() moler_received_data = [] def one_time_observer(data): moler_received_data.append(data) moler_conn.unsubscribe(observer=one_time_observer, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=one_time_observer, connection_closed_handler=do_nothing_func) used_io = buffer_transport_class( moler_connection=moler_conn) # external-IO internally sets .how2send used_io.write(input_bytes=b"data 1") # inject to buffer for next line read used_io.read() moler_conn.unsubscribe( observer=one_time_observer, connection_closed_handler=do_nothing_func) # TODO: check # warning in logs (when we set logging system) used_io.write(input_bytes=b"data 2") # inject to buffer for next line read used_io.read() assert b"data 1" in moler_received_data assert b"data 2" not in moler_received_data # because of unsubscription during notification
def ping_observing_task(address, ping_ip): logger = logging.getLogger('moler.user.app-code') net_addr = 'tcp://{}:{}'.format(*address) # Lowest layer of Moler's usage (you manually glue all elements): # 1. create observers net_down_detector = NetworkDownDetector(ping_ip) net_drop_found = False net_up_detector = NetworkUpDetector(ping_ip) moler_conn = ObservableConnection( decoder=lambda data: data.decode("utf-8")) # 2. virtually "start" observer by making it data-listener moler_conn.subscribe(net_down_detector.data_received) info = '{} on {} using {}'.format(ping_ip, net_addr, net_down_detector) logger.debug('observe ' + info) for _ in tcp_connection(address, moler_conn): # anytime new data comes it may change status of observer if not net_drop_found and net_down_detector.done(): net_drop_found = True net_down_time = net_down_detector.result() timestamp = time.strftime("%H:%M:%S", time.localtime(net_down_time)) logger.debug('Network {} is down from {}'.format( ping_ip, timestamp)) # 3. virtually "stop" that observer moler_conn.unsubscribe(net_down_detector.data_received) # 4. and start subsequent one (to know when net is back "up") info = '{} on {} using {}'.format(ping_ip, net_addr, net_up_detector) logger.debug('observe ' + info) moler_conn.subscribe(net_up_detector.data_received) if net_up_detector.done(): net_up_time = net_up_detector.result() timestamp = time.strftime("%H:%M:%S", time.localtime(net_up_time)) logger.debug('Network {} is back "up" from {}'.format( ping_ip, timestamp)) # 5. virtually "stop" that observer moler_conn.unsubscribe(net_up_detector.data_received) break
def test_single_unsubscription_doesnt_impact_other_subscribers(): from moler.observable_connection import ObservableConnection class TheObserver(object): def __init__(self): self.received_data = [] def on_new_data(self, data): self.received_data.append(data) observer1 = TheObserver() observer2 = TheObserver() 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() moler_conn = ObservableConnection() moler_conn.subscribe(observer=observer1.on_new_data, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=observer2.on_new_data, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=observer2.on_new_data, connection_closed_handler=do_nothing_func) moler_conn.unsubscribe(observer=observer1.on_new_data, connection_closed_handler=do_nothing_func) moler_conn.unsubscribe(observer=observer1.on_new_data, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=raw_fun1, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=raw_fun2, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=raw_fun2, connection_closed_handler=do_nothing_func) moler_conn.unsubscribe(observer=raw_fun1, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=callable1, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=callable2, connection_closed_handler=do_nothing_func) moler_conn.subscribe(observer=callable2, connection_closed_handler=do_nothing_func) moler_conn.unsubscribe(observer=callable1, connection_closed_handler=do_nothing_func) moler_conn.data_received("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"]