Пример #1
0
def ping_observing_task(address):
    logger = logging.getLogger('moler.user.app-code')
    observer_done = Deferred()

    # Lowest layer of Moler's usage (you manually glue all elements):
    # 1. create observer
    net_down_detector = NetworkDownDetector()
    # 2. ObservableConnection is a proxy-glue between observer (speaks str)
    #                                   and twisted-connection (speaks bytes)
    moler_conn = ObservableConnection(
        decoder=lambda data: data.decode("utf-8"))
    # 3a. glue from proxy to observer
    moler_conn.subscribe(net_down_detector.data_received)

    logger.debug('waiting for data to observe')

    def feed_moler(connection_data):
        # 3b. glue to proxy from external-IO (twisted tcp client connection)
        #    (client has to pass it's received data into Moler's connection)
        moler_conn.data_received(connection_data)
        # 4. Moler's client code must manually check status of observer ...
        if net_down_detector.done():
            # 5. ... to know when it can ask for result
            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(timestamp))
            observer_done.callback(None)  # break tcp client and server

    start_tcp_connection(address, feed_moler)
    return observer_done
Пример #2
0
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.connection import ObservableConnection

    moler_conn = ObservableConnection()
    moler_received_data = []

    def one_time_observer(data):
        moler_received_data.append(data)
        moler_conn.unsubscribe(one_time_observer)

    moler_conn.subscribe(one_time_observer)

    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(
        one_time_observer
    )  # 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
Пример #3
0
def test_notifies_only_subscribed_observers_about_data_comming_from_external_io(
        buffer_transport_class):
    from moler.connection import ObservableConnection

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

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

    buffer_observer1 = BufferObserver()
    buffer_observer2 = BufferObserver()
    buffer_observer3 = BufferObserver()

    moler_conn = ObservableConnection()
    moler_conn.subscribe(buffer_observer1.on_new_data)
    moler_conn.subscribe(buffer_observer2.on_new_data)

    used_io = buffer_transport_class(
        moler_connection=moler_conn)  # external-IO internally sets .how2send
    used_io.write(
        input_bytes=b"incoming data")  # inject to buffer for next line read
    used_io.read()

    assert b"incoming data" in buffer_observer1.received_data
    assert b"incoming data" in buffer_observer2.received_data
    assert b"incoming data" not in buffer_observer3.received_data  # that one was not subscribed
Пример #4
0
async def terminal_io_test():
    from moler.connection import ObservableConnection

    received_data = []

    moler_conn = ObservableConnection(
        encoder=lambda data: data.encode("utf-8"),
        decoder=lambda data: data.decode("utf-8"))
    terminal = AsyncioTerminal(moler_connection=moler_conn)
    cmds = ['pwd', 'ssh [email protected]', 'password', 'ls\r', 'exit\r']
    cmd_idx = [0]

    def data_observer(data):
        print(data)
        received_data.append(data)
        print(received_data)

        if cmd_idx[0] < len(cmds):
            cmd2send = cmds[cmd_idx[0]]
            if (cmd2send == 'password') and ('Password' not in data):
                return
            moler_conn.send(data=cmd2send + '\n')
            cmd_idx[0] += 1

    moler_conn.subscribe(data_observer)

    await terminal.open()
    await asyncio.sleep(10)
    await terminal.close()
    print("end of test")
Пример #5
0
async def ping_observing_task(address):
    logger = logging.getLogger('moler.user.app-code')

    # Lowest layer of Moler's usage (you manually glue all elements):
    # 1. create observer
    net_down_detector = NetworkDownDetector('10.0.2.15')
    # 2. ObservableConnection is a proxy-glue between observer (speaks str)
    #                                   and curio-connection (speaks bytes)
    moler_conn = ObservableConnection(
        decoder=lambda data: data.decode("utf-8"))
    # 3a. glue from proxy to observer
    moler_conn.subscribe(net_down_detector.data_received)

    logger.debug('waiting for data to observe')
    async with curio.meta.finalize(tcp_connection(address)) as tcp_conn:
        async for connection_data in tcp_conn:
            # 3b. glue to proxy from external-IO (curio tcp client connection)
            #    (client has to pass it's received data into Moler's connection)
            moler_conn.data_received(connection_data)
            # 4. Moler's client code must manually check status of observer ...
            if net_down_detector.done():
                # 5. ... to know when it can ask for result
                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(timestamp))
                break
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
Пример #7
0
def test_can_work_with_multiple_connections(tcp_connection_class,
                                            integration_tcp_server_and_pipe,
                                            integration_second_tcp_server_and_pipe):
    """Check open/close/send/receive on multiple connections"""
    from moler.connection import ObservableConnection
    (tcp_server0, tcp_server0_pipe) = integration_tcp_server_and_pipe
    (tcp_server1, tcp_server1_pipe) = integration_second_tcp_server_and_pipe
    received_data = [bytearray(), bytearray()]
    receiver_called = [threading.Event(), threading.Event()]

    def receiver0(data):
        received_data[0].extend(data)
        receiver_called[0].set()

    def receiver1(data):
        received_data[1].extend(data)
        receiver_called[1].set()

    moler_conn0 = ObservableConnection()
    moler_conn0.subscribe(receiver0)
    moler_conn1 = ObservableConnection()
    moler_conn1.subscribe(receiver1)
    connection0 = tcp_connection_class(moler_connection=moler_conn0, port=tcp_server0.port, host=tcp_server0.host)
    connection1 = tcp_connection_class(moler_connection=moler_conn1, port=tcp_server1.port, host=tcp_server1.host)
    with connection0.open():
        with connection1.open():
            time.sleep(0.1)  # to let servers notify connecting clients
            tcp_server0_pipe.send(("send async msg", {'msg': b'data from server 0'}))
            tcp_server1_pipe.send(("send async msg", {'msg': b'data from server 1'}))
            assert receiver_called[0].wait(timeout=0.5)
            assert receiver_called[1].wait(timeout=0.5)
            moler_conn0.send(data=b'data to server 0')
            moler_conn1.send(data=b'data to server 1')

    time.sleep(0.1)  # to let servers get what was sent
    # what we got from servers
    assert b'data from server 0' == received_data[0]
    assert b'data from server 1' == received_data[1]

    # what servers know about clients
    tcp_server0_pipe.send(("get history", {}))
    tcp_server1_pipe.send(("get history", {}))
    dialog_with_server0 = tcp_server0_pipe.recv()
    dialog_with_server1 = tcp_server1_pipe.recv()
    assert 'Client connected' == dialog_with_server0[0]
    assert 'Client connected' == dialog_with_server0[0]
    assert ['Received data:', b'data to server 0'] == dialog_with_server0[-2]
    assert ['Received data:', b'data to server 1'] == dialog_with_server1[-2]
    assert 'Client disconnected' == dialog_with_server0[-1]
    assert 'Client disconnected' == dialog_with_server1[-1]
Пример #8
0
def test_can_notify_its_observer_about_data_comming_from_external_io(buffer_transport_class):
    from moler.connection import ObservableConnection

    moler_received_data = []

    def buffer_observer(data):
        moler_received_data.append(data)

    moler_conn = ObservableConnection()
    moler_conn.subscribe(buffer_observer)

    used_io = buffer_transport_class(moler_connection=moler_conn)  # external-IO internally sets .how2send
    used_io.write(input_bytes=b"incoming data")  # inject to buffer for next line read
    used_io.read()

    assert b"incoming data" in moler_received_data
Пример #9
0
def test_subscription_doesnt_block_subscriber_to_be_garbage_collected():
    from moler.connection import ObservableConnection

    moler_conn = ObservableConnection()
    garbage_collected_subscribers = []

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

    subscr = Subscriber()
    moler_conn.subscribe(subscr)

    del subscr
    gc.collect()

    assert 'Subscriber' in garbage_collected_subscribers
Пример #10
0
def test_garbage_collected_subscriber_is_not_notified():
    from moler.connection import ObservableConnection

    moler_conn = ObservableConnection()
    received_data = []

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

    subscr1 = Subscriber()
    subscr2 = Subscriber()
    moler_conn.subscribe(subscr1)
    moler_conn.subscribe(subscr2)

    del subscr1
    gc.collect()

    moler_conn.data_received("data")
    assert len(received_data) == 1
Пример #11
0
def test_can_receive_binary_data_from_connection(tcp_connection_class,
                                                 integration_tcp_server_and_pipe):
    from moler.connection import ObservableConnection
    (tcp_server, tcp_server_pipe) = integration_tcp_server_and_pipe
    received_data = bytearray()
    receiver_called = threading.Event()

    def receiver(data):
        received_data.extend(data)
        receiver_called.set()

    moler_conn = ObservableConnection()  # no decoder, just pass bytes 1:1
    moler_conn.subscribe(receiver)       # build forwarding path
    connection = tcp_connection_class(moler_connection=moler_conn, port=tcp_server.port, host=tcp_server.host)
    with connection.open():  # TODO: async with connection.open():
        time.sleep(0.1)  # otherwise we have race between server's pipe and from-client-connection
        tcp_server_pipe.send(("send async msg", {'msg': b'data to read'}))
        receiver_called.wait(timeout=0.5)

    assert b'data to read' == received_data
Пример #12
0
def test_notified_observer_may_stop_subscription_of_data_comming_from_external_io(buffer_transport_class):
    from moler.connection import ObservableConnection

    moler_conn = ObservableConnection()
    moler_received_data = []

    def one_time_observer(data):
        moler_received_data.append(data)
        moler_conn.unsubscribe(one_time_observer)

    moler_conn.subscribe(one_time_observer)

    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()
    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
Пример #13
0
def test_exception_in_observer_doesnt_break_connection_nor_other_observers(
        buffer_transport_class):
    from moler.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(one_time_observer)

    moler_conn.subscribe(failing_observer)
    moler_conn.subscribe(one_time_observer)

    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(failing_observer)

    assert b"data 1" in moler_received_data
Пример #14
0
def test_single_unsubscription_doesnt_impact_other_subscribers():
    from moler.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(observer1.on_new_data)
    moler_conn.subscribe(observer2.on_new_data)
    moler_conn.subscribe(observer2.on_new_data)
    moler_conn.unsubscribe(observer1.on_new_data)
    moler_conn.unsubscribe(observer1.on_new_data)

    moler_conn.subscribe(raw_fun1)
    moler_conn.subscribe(raw_fun2)
    moler_conn.subscribe(raw_fun2)
    moler_conn.unsubscribe(raw_fun1)

    moler_conn.subscribe(callable1)
    moler_conn.subscribe(callable2)
    moler_conn.subscribe(callable2)
    moler_conn.unsubscribe(callable1)

    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"]