def test_tx_id_exhaustion(pubmock):
    pubmock.reset_mock()

    attrs = {"addr": "0011223344556677"}

    mgr = XBeeEventManager(registry)
    pollermock = mgr.poller
    pollermock.poll.return_value = [(mgr.socket.fileno.return_value,
                                     selectmock.POLLOUT)]

    # Get the listener from subscribe's last call
    listener = get_listener(pubmock)
    assert listener is not None

    # Create command object
    el = Element("send_serial", attrib=attrs)
    el.text = "1234"

    rsp = Mock()
    for _ in xrange(255):
        listener(element=el, response=rsp)
        eq_(rsp.put.call_count, 1)
        rsp.put.assert_called_once_with(ResponsePending)
        rsp.reset_mock()

    # tx_callbacks should contain entries for range [1,255] inclusive

    # Push it over the limit
    listener(element=el, response=rsp)
    eq_(rsp.put.call_count, 1)
    r = rsp.put.call_args[0][0]

    assert_command_error(r, "Too many outstanding transmits")
def test_empty_poll_result(pubmock):
    pubmock.reset_mock()

    mgr = DDOEventManager()

    # Make manager's poller.poll return an empty list
    mgr.poller.poll.return_value = []

    # Get the listener from subscribe's last call
    listener = get_dout_listener(pubmock)
    assert listener is not None

    attrs = {'addr': '123456', 'index': '1'}

    el = Element("set_digital_output", attrib=attrs)
    el.text = "low"

    response = Mock()
    listener(element=el, response=response)

    eq_(response.put.call_count, 1)

    # Extract the listener's response
    r = response.put.call_args[0][0]
    assert_command_error(r, errors['txfailed'], "No poll events returned")

    # Check that we never reached the socket.sendto call
    assert not sockmock.return_value.sendto.called
def test_socket_unavailable_on_poll(pubmock):
    pubmock.reset_mock()

    mgr = DDOEventManager()

    # Make manager's poller.poll return a non-empty list which does not include
    # the manager socket's fileno
    mgr.poller.poll.return_value = [(-1, selectmock.POLLOUT)]

    # Get the listener from subscribe's last call
    listener = get_dout_listener(pubmock)
    assert listener is not None

    attrs = {'addr': '123456', 'index': '1'}

    el = Element("set_digital_output", attrib=attrs)
    el.text = "low"

    response = Mock()
    listener(element=el, response=response)

    eq_(response.put.call_count, 1)

    # Extract the listener's response
    r = response.put.call_args[0][0]
    errmsg = "Socket not available for write"
    assert_command_error(r, errors['txfailed'], errmsg)

    # Check that we never reached the socket.sendto call
    assert not sockmock.return_value.sendto.called
def test_tx_id_exhaustion(pubmock):
    pubmock.reset_mock()

    mgr = DDOEventManager()

    # Fill manager's status callbacks
    # (Get the manager's TxStatusCallbacks object and fill it manually. This is
    # easier than, say, calling the pubsub listener for set_digital_output 255
    # times)
    callbacks = mgr.tx_callbacks
    cb = lambda *a: None
    for _ in xrange(255):
        callbacks.add_callback(cb)

    # Now, get the pubsub listener, send a set_digital_output command, check
    # the return value.
    listener = get_dout_listener(pubmock)

    # Command object
    attrs = {'addr': '123456', 'name': "DIO4"}
    el = Element("set_digital_output", attrib=attrs)
    el.text = "high"

    rsp_mock = Mock(name="response queue mock")

    listener(element=el, response=rsp_mock)
    assert rsp_mock.put.call_count == 1
    response = rsp_mock.put.call_args[0][0]

    assert_command_error(response, "Too many outstanding transmits")
def test_with_raised_error(pubmock):
    DDOEventManager()

    # Get the listener from subscribe's last call
    listener = get_dout_listener(pubmock)
    assert listener is not None

    el = Element("set_digital_output")
    el.set("addr", "0011223344556677")
    el.set("index", "5")
    el.text = "on"

    old_se = sockmock.return_value.sendto.side_effect

    sockmock.return_value.sendto.side_effect = Exception("-- exc --")

    response = Mock()
    listener(element=el, response=response)

    assert response.put.call_count == 1
    assert sockmock.return_value.sendto.called

    # Extract the listener's response
    r = response.put.call_args[0][0]
    print tostring(r)
    assert_command_error(r, errors['txfailed'],
                         sockmock.return_value.sendto.side_effect.message)

    # Reset the side effect
    sockmock.return_value.sendto.side_effect = old_se
def test_tx_id_exhaustion(pubmock):
    pubmock.reset_mock()

    attrs = {"addr": "0011223344556677"}

    mgr = XBeeEventManager(registry)
    pollermock = mgr.poller
    pollermock.poll.return_value = [(mgr.socket.fileno.return_value,
                                     selectmock.POLLOUT)]

    # Get the listener from subscribe's last call
    listener = get_listener(pubmock)
    assert listener is not None

    # Create command object
    el = Element("send_serial", attrib=attrs)
    el.text = "1234"

    rsp = Mock()
    for _ in xrange(255):
        listener(element=el, response=rsp)
        eq_(rsp.put.call_count, 1)
        rsp.put.assert_called_once_with(ResponsePending)
        rsp.reset_mock()

    # tx_callbacks should contain entries for range [1,255] inclusive

    # Push it over the limit
    listener(element=el, response=rsp)
    eq_(rsp.put.call_count, 1)
    r = rsp.put.call_args[0][0]

    assert_command_error(r, "Too many outstanding transmits")
def test_no_response():
    with captured_callback() as cb, captured_queue():
        # UUT keeps the reference alive for CB handling
        # pylint: disable=unused-variable
        uut = RCICommandProcessor()
        rtn = cb("<test/>")

    root = ET.fromstring(rtn)
    assert_that(root.tag, equal_to("responses"))
    assert_that(root.get("command"), equal_to("test"))
    assert_that(len(root), equal_to(1))  # Single response
    assert_command_error(root[0], "Command not handled")
def test_no_response():
    with captured_callback() as cb, captured_queue():
        # UUT keeps the reference alive for CB handling
        # pylint: disable=unused-variable
        uut = RCICommandProcessor()
        rtn = cb("<test/>")

    root = ET.fromstring(rtn)
    assert_that(root.tag, equal_to("responses"))
    assert_that(root.get("command"), equal_to("test"))
    assert_that(len(root), equal_to(1))  # Single response
    assert_command_error(root[0], "Command not handled")
def do_status_error(pubmock, addr, name, status, message, hint=None):
    pubmock.reset_mock()
    mgr = DDOEventManager()

    # Get the listener from subscribe's last call
    listener = get_dout_listener(pubmock)
    assert listener is not None

    attrs = {'addr': addr, 'name': name}

    el = Element("set_digital_output", attrib=attrs)
    el.text = "low"

    response = Mock()
    listener(element=el, response=response)

    eq_(response.put.call_count, 1)
    assert mgr.socket.sendto.called
    # Extract the transaction ID
    sent_addr = mgr.socket.sendto.call_args[0][1]
    tx_id = sent_addr[-1]
    assert response.put.call_args[0][0] is ResponsePending

    response.reset_mock()

    # Normalize the input address, because recvfrom() return values have the
    # normalized addresses.
    recv_addr = normalize_ieee_address(addr)

    mgr.socket.recvfrom.return_value = ("", (recv_addr, name, 0, tx_id,
                                             status))

    # Trigger a read on the socket
    mgr.handle_read()

    eq_(response.put.call_count, 1)
    r = response.put.call_args[0][0]

    assert isinstance(r, DeferredResponse)
    print r.response

    assert_command_error(r.response, message, hint)
def do_error_starts_with(pubmock, message, attrs={}, text="", hint=None):
    pubmock.reset_mock()
    DDOEventManager()

    # Get the listener from subscribe's last call
    listener = get_dout_listener(pubmock)
    assert listener is not None

    el = Element("set_digital_output", attrib=attrs)
    el.text = text

    response = Mock()
    listener(element=el, response=response)

    eq_(response.put.call_count, 1)

    # Extract the listener's response
    r = response.put.call_args[0][0]
    assert_command_error(r, message, hint)

    # Check that we never reached the socket.sendto call
    assert not sockmock.return_value.sendto.called
def test_socket_error(pubmock):
    pubmock.reset_mock()

    mgr = DDOEventManager()

    # Make the socket appear to be ready for writing
    mgr.poller.poll.return_value = [(mgr.socket.fileno(), selectmock.POLLOUT)]

    # Get the listener from subscribe's last call
    listener = get_dout_listener(pubmock)
    assert listener is not None

    attrs = {'addr': '123456', 'index': '1'}

    el = Element("set_digital_output", attrib=attrs)
    el.text = "low"

    # Set socket.error as a side effect
    old_se = mgr.socket.sendto.side_effect
    mgr.socket.sendto.side_effect = socket.error(70, "")

    response = Mock()
    listener(element=el, response=response)

    eq_(response.put.call_count, 1)

    # Extract the listener's response
    r = response.put.call_args[0][0]
    # Check that the error message is the return value of os.strerror on the
    # error's errno
    import os
    errmsg = os.strerror(70)
    assert_command_error(r, errors['txfailed'], errmsg)

    # Reset the socket sendto side effect
    mgr.socket.sendto.side_effect = old_se
def do_send_serial_error(pubmock,
                         attrs,
                         data,
                         error_prefix,
                         error_hint=None,
                         tx_status_err=0,
                         send_exc=None,
                         fileno_val=0):
    pubmock.reset_mock()
    mgr = XBeeEventManager(registry)
    pollermock = mgr.poller

    if fileno_val:
        fno_return = fileno_val
    else:
        fno_return = mgr.socket.fileno.return_value

    pollermock.poll.return_value = [(fno_return, selectmock.POLLOUT)]

    # Get the listener from subscribe's last call
    listener = get_listener(pubmock)
    assert listener is not None

    # Create command object
    el = Element("send_serial", attrib=attrs)
    el.text = data

    if send_exc:
        mgr.socket.sendto.side_effect = send_exc

    rsp = Mock()
    listener(element=el, response=rsp)

    if send_exc:
        mgr.socket.sendto.side_effect = None

    if not tx_status_err:
        assert_that(rsp.put.call_count, equal_to(1))
        r = rsp.put.call_args[0][0]
        rsp.put.assert_called_once_with(match_equality(instance_of(Element)))
        # Only call, only arg is hopeful error element
        el = rsp.put.call_args[0][0]
        assert_command_error(el, error_prefix, error_hint)

        return

    #### Deal only with tx_status errors beyond here

    # Grab the transmit identifier so we can comlete it
    # First call, second argument, sixth member of address tuple
    tx_id = mgr.socket.sendto.call_args[0][1][5]

    rsp.put.assert_called_once_with(ResponsePending)
    rsp.reset_mock()

    # Trigger completion with transmit status
    mgr.socket.recvfrom.return_value = (
        # TX Status response, frame info, dst, and other
        # indicators all success
        '\x8b\x00\x00\x00\x00' + chr(tx_status_err) + '\x00',
        ('[00:00:00:00:00:00:00:00]!', 0x0, 0xc105, 0x8b, 0x0, tx_id))

    print mgr.socket.recvfrom.return_value

    # Tell dispatcher portion that it has data
    mgr.handle_read()

    rsp.put.assert_called_once_with(
        match_equality(instance_of(DeferredResponse)))
    # First call, only arg
    dr = rsp.put.call_args[0][0]
    el = dr.response
    assert_command_error(el, error_prefix, error_hint)
def do_send_serial_error(pubmock, attrs, data, error_prefix, error_hint=None,
                         tx_status_err=0, send_exc=None, fileno_val=0):
    pubmock.reset_mock()
    mgr = XBeeEventManager(registry)
    pollermock = mgr.poller

    if fileno_val:
        fno_return = fileno_val
    else:
        fno_return = mgr.socket.fileno.return_value

    pollermock.poll.return_value = [(fno_return,
                                     selectmock.POLLOUT)]

    # Get the listener from subscribe's last call
    listener = get_listener(pubmock)
    assert listener is not None

    # Create command object
    el = Element("send_serial", attrib=attrs)
    el.text = data

    if send_exc:
        mgr.socket.sendto.side_effect = send_exc

    rsp = Mock()
    listener(element=el, response=rsp)

    if send_exc:
        mgr.socket.sendto.side_effect = None

    if not tx_status_err:
        assert_that(rsp.put.call_count, equal_to(1))
        r = rsp.put.call_args[0][0]
        rsp.put.assert_called_once_with(match_equality(instance_of(Element)))
        # Only call, only arg is hopeful error element
        el = rsp.put.call_args[0][0]
        assert_command_error(el, error_prefix, error_hint)

        return

    #### Deal only with tx_status errors beyond here

    # Grab the transmit identifier so we can comlete it
    # First call, second argument, sixth member of address tuple
    tx_id = mgr.socket.sendto.call_args[0][1][5]

    rsp.put.assert_called_once_with(ResponsePending)
    rsp.reset_mock()

    # Trigger completion with transmit status
    mgr.socket.recvfrom.return_value = (
        # TX Status response, frame info, dst, and other
        # indicators all success
        '\x8b\x00\x00\x00\x00' + chr(tx_status_err) + '\x00',
        ('[00:00:00:00:00:00:00:00]!',
         0x0, 0xc105, 0x8b, 0x0, tx_id))

    print mgr.socket.recvfrom.return_value

    # Tell dispatcher portion that it has data
    mgr.handle_read()

    rsp.put.assert_called_once_with(
        match_equality(instance_of(DeferredResponse)))
    # First call, only arg
    dr = rsp.put.call_args[0][0]
    el = dr.response
    assert_command_error(el, error_prefix, error_hint)