def test_clean_session_PUB__2_CLEAN_CLEAN__NO_redelivery(xift):
    ''' see xi_ftest_clean_session_helpers.py for the matrix codes below '''
    clean_session_flag_queue = [1, 1]
    client_on_connect_action_queue = [1, 9]
    broker_on_message_action_queue = [2, 1]

    helpers.generator_test_case_setup(xift, clean_session_flag_queue,
                                      client_on_connect_action_queue,
                                      broker_on_message_action_queue)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(TestEssentials.topic, 1, b'tm0')),
        call.broker.on_client_disconnect(ANY, ANY, ANY),
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_disconnect(ANY, ANY, ANY)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
Exemplo n.º 2
0
def test_tls_connect_with_expired_cert(xift):
    def client_on_connect_finish(errorcode):
        xift.client_sut.stop()
        xift.broker.trigger_shutdown()

    # Arrange
    certfile = "self-signed-expired-cert.pem"

    xift.client_sut.setup_tls(certfile)
    xift.broker.setup_tls(
        "../../../xi_client_common/certs/test/" + certfile,
        "../../../xi_client_common/certs/test/" +
        "self-signed-expired-key.pem")

    xift.client_sut.on_connect_finish.side_effect = client_on_connect_finish

    # Act
    act(xift, setup_default_cert=False)

    # Assert
    expected_calls_client = [
        call.client.on_connect_finish(XiClientErrorCodes.CERTERROR)
    ]

    assert expected_calls_client == xift.mock_call_history_client.method_calls
Exemplo n.º 3
0
def test_tls_connect_with_bad_domain(xift):

    # Arrange
    certfile = "self-signed-bad-domain-cert.pem"

    xift.client_sut.setup_tls(certfile)
    xift.broker.setup_tls(
        "../../../xi_client_common/certs/test/" + certfile,
        "../../../xi_client_common/certs/test/" +
        "self-signed-bad-domain-key.pem")

    #xift.broker.on_ssl_error = lambda broker, username, ssl_err: print("Broker SSL error!!!")
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: xift.broker.trigger_shutdown(
    )

    def client_on_connect_finish(result):
        # problem: broker shutdown is here too because in case of py2 Client broker does not call its on_client_disconnect
        xift.broker.trigger_shutdown()
        xift.client_sut.stop()

    xift.client_sut.on_connect_finish.side_effect = client_on_connect_finish

    # Act
    act(xift, setup_default_cert=False)

    # Assert
    expected_calls_client = [
        call.client.on_connect_finish(XiClientErrorCodes.SSLERROR)
    ]

    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_connect_badDomain_conClbCalledWithError(xift):
    """
        Tests the behaviour of the client when the client tries to connect
        to an nonexisting domain name.

        Test scenario:
            Make the client to connect to a given domain that does not exists

        Expectation:
            Client should invoke connection finished callback with one of the error
            related to a socket or gethostbyname or socket connection error
    """
    def validate_params(state):
        xift.client_sut.stop()
        xift.broker.trigger_shutdown()

        assert state in [
            XiClientErrorCodes.SOCKET_ERROR
            #, XiClientErrorCodes.XI_SOCKET_GETHOSTBYNAME_ERROR
            #, XiClientErrorCodes.XI_SOCKET_CONNECTION_ERROR
        ]

    xift.client_sut.on_connect_finish.side_effect = validate_params

    act(xift, endpoint=("non_existing_domain.com", 666))
Exemplo n.º 5
0
def test_clean_session_SUB_PUB__2_UNCLEAN_UNCLEAN__client_reSUBPUBs_and_sends_new_SUB_PUB(
        xift):
    ''' see xi_ftest_clean_session_helpers.py for the matrix codes below '''
    clean_session_flag_queue = [0, 0]
    client_on_connect_action_queue = [22, 22]
    broker_on_message_action_queue = [2, 1, 1]
    client_on_publish_finish_action_queue = [0, 1]
    broker_on_subscribe_action_queue = [1, 0, 1, 1, 1]
    client_on_subscribe_finish_action_queue = [0, 0]

    helpers.generator_test_case_setup(xift, clean_session_flag_queue,
                                      client_on_connect_action_queue,
                                      broker_on_message_action_queue,
                                      client_on_publish_finish_action_queue,
                                      broker_on_subscribe_action_queue,
                                      client_on_subscribe_finish_action_queue)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 0)],
                                        0),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(TestEssentials.topic, 1, b'tm0')),
        call.broker.on_client_disconnect(ANY, ANY, ANY),
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 0)],
                                        1),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(TestEssentials.topic, 1, b'tm0', 1)),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 0)],
                                        0),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(TestEssentials.topic, 1, b'tm1', 0)),
        call.broker.on_client_disconnect(ANY, ANY, ANY)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish([XiClientErrorCodes.SUCCESS]),
        call.client.on_publish_finish(ANY),
        call.client.on_subscribe_finish([XiClientErrorCodes.SUCCESS]),
        call.client.on_publish_finish(ANY),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_connect_connectionTimeout_conClbCalledWithControlTopicError(xift):
    """
        Tests if the connection operation is timed out properly after CONNACK is sent by
        the broker, but no SUBACK is sent in response to control topic subscription

        Test scenario:
            Make the server to receive the CONNECT msg from the client
            send the CONNACK response but don't send SUBACK response

        Expectations:
            Client should close the connection and invoke the on_connect_finish
            callback connection using control topic error state within
            appropriate amount of time defined via the connection settings.
    """

    xift.client_sut.on_connect_finish.side_effect = \
        lambda connect_res: xift.client_sut.stop()

    # Remove side effect so that it won't raise exception on usage.
    xift.client_sut.on_disconnect.side_effect = None

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                    xift.broker.send_connack( mqtt_messages.CONNACK_ACCEPTED )
    xift.broker.on_client_subscribe.side_effect = None
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                    xift.broker.trigger_shutdown()

    # Set the connection timeout based on the actual test value
    TestEssentials.connection_timeout = 2

    # Sanity checks
    assert TestEssentials.connection_timeout > 0
    assert TestEssentials.test_timeout > TestEssentials.connection_timeout

    # Act
    act(xift)

    # Assert parameters
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(ANY, ANY, 1)
    ]
    #expected_calls_client = [ call.client.on_connect_finish(XiClientErrorCodes.CONTROL_TOPIC_SUBSCRIPTION_ERROR)]
    expected_calls_client = [
        call.client.on_connect_finish(XiClientErrorCodes.SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_connect_controlTopicSubscriptionRefused_conClbCalledWithSuccess(xift):
    """
        Tests the behaviour of the client when the broker responds to control topic
        subscription with an error code

        Test scenario:
            Make the server to receive the CONNECT msg from the client
            send the CONNACK response and send invalid SUBACK response

        Expectations:
            Client should invoke connection finished callback with SUCCESS
    """

    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: xift.client_sut.disconnect(
    )
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )


    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
            xift.broker.send_connack( mqtt_messages.CONNACK_ACCEPTED )
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
            xift.broker.send_suback(msg_id, [(TestEssentials.control_topic_name, 0x80)])
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
            xift.broker.trigger_shutdown()

    # Set the connection timeout based on the actual test value
    TestEssentials.connection_timeout = 2

    # Sanity checks
    assert TestEssentials.connection_timeout > 0
    assert TestEssentials.test_timeout > TestEssentials.connection_timeout

    # Act
    act(xift)

    # Assert parameters
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(ANY, ANY, 0)
    ]
    expected_calls_client = [
        call.client.on_connect_finish(XiClientErrorCodes.SUCCESS),
        call.client.on_disconnect(0)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_disconnect_brokerClosesConnectionBeforeConnackMessageSent_conClbCalledWithProperConnackError(xift):
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                       xift.broker.trigger_shutdown()
    xift.broker.on_client_disconnect.side_effect = None
    xift.broker.on_client_subscribe.side_effect = None

    xift.client_sut.on_connect_finish.side_effect  = lambda result: \
                                               xift.client_sut.stop()

# Act
    act(xift)

    # Assert
    expected_calls_client = [ call.client.on_connect_finish(XiClientErrorCodes.CONNECTION_RESET_BY_PEER) ]
    assert expected_calls_client == xift.mock_call_history_client.method_calls[:1]
Exemplo n.º 9
0
def test_clean_session_SUB__2_UNCLEAN_UNCLEAN_2SUBs_client_reSUBSCRIBES(xift):
    ''' see xi_ftest_clean_session_helpers.py for the matrix codes below '''
    clean_session_flag_queue = [0, 0]
    client_on_connect_action_queue = [12, 0]
    broker_on_subscribe_action_queue = [1, 0, 2, 1, 1, 1]
    client_on_subscribe_finish_action_queue = [0, 1]

    helpers.generator_test_case_setup(xift, clean_session_flag_queue,
                                      client_on_connect_action_queue, [], [],
                                      broker_on_subscribe_action_queue,
                                      client_on_subscribe_finish_action_queue)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 0)],
                                        0),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 1)],
                                        0),
        call.broker.on_client_disconnect(ANY, ANY, ANY),
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 0)],
                                        1),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 1)],
                                        1),
        call.broker.on_client_disconnect(ANY, ANY, ANY)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish([0]),
        call.client.on_subscribe_finish([1]),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_connect_connectionRefused_conClbCalledWithProperConnackError(
        xift, mqtt_connect_setup):
    """
        Tests the correct behaviour whenever server sends refuse in response to
        CONNECT msg

        Test scenario:
            Every connect attempt will be treated same way, server will send
            CONNACK with one of possible connack error codes

        Expectation:
            Client should invoke connection finished callback with an apropriate
            error state set
    """

    # broker on connection just say that the credentials are wrong
    def broker_on_client_connect(userdata, connect_options):
        xift.broker.send_connack(mqtt_connect_setup.server_connack)
        #xift.broker.trigger_shutdown()

    # client when connection finished just stops
    def client_on_connect_finish(connection_res):
        xift.broker.trigger_shutdown()
        xift.client_sut.stop()

    # brokers side effects
    xift.broker.on_client_connect.side_effect = broker_on_client_connect
    xift.broker.on_client_disconnect.side_effect = None

    # client side effects
    xift.client_sut.on_connect_finish.side_effect = client_on_connect_finish

    # run
    act(xift)

    # expectations
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_disconnect(ANY, ANY, 1)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(
            mqtt_connect_setup.client_on_connect_finish)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
Exemplo n.º 11
0
def test_clientSidePublish_messageArrivesAtBroker(xift):
    #Arrange
    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: \
                          xift.client_sut.publish_binary(TestEssentials.topic, TestEssentials.binary_payload, 1)
    xift.client_sut.on_publish_finish.side_effect = lambda request_id: xift.client_sut.disconnect(
    )
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                  xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                  xift.broker.trigger_shutdown()

    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback(msg_id, topics_and_qos)
    xift.broker.on_message.side_effect = lambda a, b, mqtt_message: \
                                          xift.broker.send_puback(mqtt_message.mid)

    #Act
    act(xift)

    #Assert
    class MessageMatcher(mqtt_messages.MQTTMessage):
        def __init__(self):
            super(MessageMatcher, self).__init__()

        def __eq__(self, other):
            return TestEssentials.binary_payload == other.payload and 1 == other.qos

    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_message(ANY, ANY, MessageMatcher()),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_publish_finish(ANY),
        call.client.on_disconnect(ANY)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_connect_connectionTimeout_conClbCalledWithTimeoutState(xift):
    """
        Tests if the connection operation is timed out properly

        Test scenario:
            Make the server to receive the CONNECT msg from the client
            but don't send the CONNACK response

        Expectations:
            Client should close the connection and invoke the on_connect_finish
            callback connection using timeout error state within
            apropriate amount of time defined via the connection settings.
    """

    xift.client_sut.on_connect_finish.side_effect = \
        lambda connect_res: xift.client_sut.stop()

    # Remove side effect so that it won't raise exception on usage.
    xift.client_sut.on_disconnect.side_effect = None

    xift.broker.on_client_connect.side_effect = None
    xift.broker.on_client_subscribe.side_effect = None
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                    xift.broker.trigger_shutdown()

    # Set the connection timeout based on the actual test value
    TestEssentials.connection_timeout = 2

    # Sanity checks
    assert TestEssentials.connection_timeout > 0
    assert TestEssentials.test_timeout > TestEssentials.connection_timeout

    # Act
    act(xift)

    # Assert parameters
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_disconnect(ANY, ANY, 1)
    ]
    expected_calls_client = [
        call.client.on_connect_finish(XiClientErrorCodes.TIMEOUT)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
Exemplo n.º 13
0
def test_tls_connect_successfully(xift):
    # Arrange
    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: xift.client_sut.disconnect(
    )
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )

    def validate_connection(userdata, connect_options):
        def assert_connect_options():
            assert connect_options.client_id.decode(
                "utf-8") == xift.connect_options.username
            assert mqtt_messages.CLEAN_SESSION_FLAG \
                | mqtt_messages.USERNAME_FLAG \
                | mqtt_messages.PASSWORD_FLAG == connect_options.connect_flags

        xift._task_queue.put(assert_connect_options)

        xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    xift.broker.on_client_connect.side_effect = validate_connection
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                xift.broker.trigger_shutdown()
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback(msg_id, topics_and_qos)

    xift.connect_options.connect_flags = xift.connect_options.connect_flags | mqtt_messages.CLEAN_SESSION_FLAG

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(ANY)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_disconnect_brokerClosesConnectionAfterConnectFinished_conClbCalledWithProperConnackError(xift):
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                       xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                         xift.broker.send_suback(msg_id, topics_and_qos)
    xift.broker.on_client_disconnect.side_effect = None


    xift.client_sut.on_connect_finish.side_effect = lambda result: \
                                               xift.broker.trigger_shutdown()
    xift.client_sut.on_disconnect.side_effect = lambda result: \
                                                       xift.client_sut.stop()

    # Act
    act(xift)

    # Assert
    expected_calls_client = [ call.client.on_disconnect(XiClientErrorCodes.CONNECTION_RESET_BY_PEER) ]
    assert expected_calls_client == xift.mock_call_history_client.method_calls[-1:]
Exemplo n.º 15
0
def connect_common(xift, username, password, connect_flags_expected):
    # Arrange
    xift.connect_options.username = username
    xift.connect_options.password = password

    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: xift.client_sut.disconnect()
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop()

    def validate_connection(userdata, connect_options):

        # 128   USERNAME_FLAG = 0x80
        # 64    PASSWORD_FLAG = 0x40
        # 32    WILL_RETAIN_FLAG = 0x20
        # 24    WILL_QOS_FLAG = 0x18
        # 4     WILL_FLAG = 0x04
        # 2     CLEAN_SESSION_FLAG = 0x02
        def assert_connect_options():
            assert connect_options.connect_flags == connect_flags_expected
            assert username == xift.connect_options.username
            assert password == xift.connect_options.password

        xift._task_queue.put(assert_connect_options)

        xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    xift.broker.on_client_connect.side_effect = validate_connection
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
        xift.broker.trigger_shutdown()
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
        xift.broker.send_suback(msg_id, topics_and_qos)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [ call.broker.on_client_connect(ANY, ANY) ]
    expected_calls_client = [ call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED) ]
    xift.mock_call_history_broker.assert_has_calls(expected_calls_broker)
    xift.mock_call_history_client.assert_has_calls(expected_calls_client)

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls[:1]
    assert expected_calls_client == xift.mock_call_history_client.method_calls[:1]
Exemplo n.º 16
0
def test_device_status_data_publish_on_boot(xift):
    if xift.sut_platform == XiClientPlatform.C:
        pytest.xfail("feature can be activated only for python clients")

    # Arrange
    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: xift.client_sut.disconnect(
    )
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )
    xift.client_sut.on_publish_finish.side_effect = None

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                xift.broker.trigger_shutdown()
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback(msg_id, topics_and_qos)

    xift.broker.on_message.side_effect = None  # no need to puback for now

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_message(ANY, ANY,
                               BasicMessageMatcher("device-status", 0, None)),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    expected_calls_client = [
        call.client.on_publish_finish(ANY),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(ANY)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_disconnect_brokerClosesConnectionAfterSubscribeArrives_disconnectClbWithProperConnackError(xift):

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                       xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
        xift.broker.trigger_shutdown()
    xift.broker.on_client_disconnect.side_effect = None

    xift.client_sut.on_connect_finish.side_effect = None

    # change side effect to None as soon as control topic subscription is part of connection process of libxively
    xift.client_sut.on_disconnect.side_effect = lambda result: \
                                               xift.client_sut.stop()

    # Act
    act(xift)

    # Assert
    expected_calls_client = [ call.client.on_connect_finish(XiClientErrorCodes.SUCCESS)
                            , call.client.on_disconnect(XiClientErrorCodes.CONNECTION_RESET_BY_PEER) ]
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_clean_session_PUB__2_UNCLEAN_UNCLEAN__client_redelivers_PUBLISH(xift):

    clean_session_flag_queue = [0, 0]
    client_on_connect_action_queue = [1, 0]
    broker_on_message_action_queue = [2, 1]

    helpers.generator_test_case_setup(xift, clean_session_flag_queue,
                                      client_on_connect_action_queue,
                                      broker_on_message_action_queue)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(TestEssentials.topic, 1, b'tm0')),
        call.broker.on_client_disconnect(ANY, ANY, ANY),
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(TestEssentials.topic, 1, b'tm0', 1)),
        call.broker.on_client_disconnect(ANY, ANY, ANY)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_publish_finish(ANY),
        call.client.on_disconnect(XiClientErrorCodes.SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
def test_subscribe_subscribe_DisconnectAfterSuback_on_disconnectClbCalledSuccess(
        xift):
    """
        Tests the correct behaviour when client subscribes to a topic
        and the Broker disonnects the connection after the suback is sent.

        Test scenario:
            Client Attempts to Subscribe to a Topic, Broker disconects before suback.

        Expectation:
            Client should invoke disconnect callback.
    """
    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. on client subscription request, shutdown the broker.
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.topic_as_signed_chars, 1)], 0)
    ]

    # 1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                  xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    #   2. accept the subscriptions
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback( msg_id, topics_and_qos )

    ###
    # client flow
    #  1. connect (automagically through act())
    #  1a. hidden, subscribe to control topic.
    #  2. on connect response, subscribe to topic
    #  3. on disconnect callback invoked, cleanup and shutdown.
    #  4. on disconnect callback invoked, cleanup and shutdown.
    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish([ANY]),
        call.client.on_disconnect(ANY)
    ]

    # 2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: \
                          xift.client_sut.subscribe([[TestEssentials.topic, 1]])

    #  3. client suback, disconnect
    xift.client_sut.on_subscribe_finish.side_effect = lambda granted_access_list: xift.broker.trigger_shutdown(
    )

    #  4. on disconnect callback invoked, cleanup and shutdown.
    def client_on_disconnect(return_code):
        xift.client_sut.stop()

    xift.client_sut.on_disconnect.side_effect = client_on_disconnect

    ##
    #Act
    act(xift)

    ##
    #Assert
    assert client_flow == xift.mock_call_history_client.method_calls
    assert broker_flow == xift.mock_call_history_broker.method_calls
def subscribeAtQoS_BrokerPublishMessageAtQoS_Runner(xift, subscribe_qos,
                                                    publish_qos):
    """
        Tests the correct behaviour when client subscribes to a topic at
        variable QoS levels and Broker Publishes to the topic at variable QoS levels.

        Test ensures that the various QoS levels reach the broker correctly
        and are correctly provided to the callbacks to the client application
    """
    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. accept the standard topic subscription, check for 'subscribe_qos'
    #   4. Cleanup on Disconnect
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        #   2. accept the control topic topic subscription
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        #   3. accept the standard topic subscription, check for 'subscribe_qos'
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.topic_as_signed_chars, subscribe_qos)],
            0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    # 1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                  xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    #   2. accept the control topic topic subscription
    #   3. accept the standard topic subscription
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback( msg_id, topics_and_qos )

    #   4. Cleanup on Disconnect
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                  xift.broker.trigger_shutdown()

    ###
    # client flow
    #  1. connect (automagically through act())
    #  1a. hidden, subscribe to control topic.
    #  2. on connect response, subscribe to topic
    #  3. subscription callback invoked, broker to publish to topic client subscribed to.
    #  4. on message callback, validate message, shutdown connection
    #  5. on shutdown callback, stop.

    # Validates that the message parameters are what we expect to recieve on the client.
    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish([ANY]),
        #  4. on message callback, validate message,
        call.client.on_message_received(
            ANY,
            BasicMessageMatcher(TestEssentials.topic, publish_qos,
                                TestEssentials.payload_as_bytes)),
        call.client.on_disconnect(ANY)
    ]

    #2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = lambda connect_res: \
                        xift.client_sut.subscribe([[TestEssentials.topic, subscribe_qos]])

    #  3. subscription callback invoked, broker publish to topic client subscribed to.
    xift.client_sut.on_subscribe_finish.side_effect = lambda granted_access_list: \
                        xift.broker.publish( TestEssentials.topic, TestEssentials.payload_as_string, publish_qos )

    #  4. on message callback, shutdown connection
    xift.client_sut.on_message_received.side_effect = lambda topic, message: \
                        xift.client_sut.disconnect()

    #  5. on shutdown callback, stop.
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )

    ##
    #Act
    act(xift)

    ##
    #Assert
    assert client_flow == xift.mock_call_history_client.method_calls
    assert broker_flow == xift.mock_call_history_broker.method_calls
def test_subcribe_subackFailure_conClbCalledWithProperSubackError(xift):
    """
        Tests the correct behaviour when server sends refuse in response to
        SUBSCRIBE request

        Test scenario:
            Client Attempts to Subscribe to a Topic, Server sends a SUBACK with error code 0x80.

        Expectation:
            Client should invoke subscription callback with an apropriate
            error state set
    """

    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. deny any other subscription
    #   4. Cleanup on Disconnect
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    def broker_on_client_subscribe(userdata, msg_id, topics_and_qos, dup):
        subscribe_results = []
        for index, t in enumerate(topics_and_qos):
            subscribe_results.append([t[0], t[1]])
            if t[0] != TestEssentials.control_topic_name:
                subscribe_results[index] = [t[0], 0x80]
        xift.broker.send_suback(msg_id, subscribe_results)

    #   1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                    xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    #   2. accept the control topic topic subscription
    #   3. deny any other subscription
    xift.broker.on_client_subscribe.side_effect = broker_on_client_subscribe

    #   4. Cleanup on Disconnect
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                xift.broker.trigger_shutdown()

    ###
    # client flow
    #  1. connect (automagically through act())
    #  1a. hidden, subscribe to control topic.
    #  2. on connect response, subscribe to topic
    #  3. monitor subscription callback, check for error state
    #  4. on subscribe callback, shutdown connection
    #  5. on shutdown callback, stop.

    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish(
            [0x80]),  # 3. monitor subscription callback, check for error state
        call.client.on_disconnect(ANY)
    ]

    #  2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = lambda connect_response: \
                                                        xift.client_sut.subscribe([[TestEssentials.topic, 1]])

    #  4. on subscribe callback, shutdown connection
    xift.client_sut.on_subscribe_finish.side_effect = lambda granted_access_list: xift.client_sut.disconnect(
    )

    #  5. on shutdown callback, stop.
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )

    ###
    # Act
    act(xift)

    ###
    # Assert
    assert broker_flow == xift.mock_call_history_broker.method_calls
    assert client_flow == xift.mock_call_history_client.method_calls
def standard_publish_flow(xift, topic, payload, expected_payload, is_string,
                          qos_level):
    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. test to see if the message arrived properly formatted via Mesage Matcher
    #   4. send puback
    #   5. cleanup on client disconnect
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_message(
            ANY, ANY, BasicMessageMatcher(topic, qos_level, expected_payload)),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    #   1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                        xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    #  2. accept the control topic topic subscription
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                        xift.broker.send_suback( msg_id, topics_and_qos )

    #  4. send puback if qos1 or above
    def broker_on_message(a, b, mqtt_message):
        if qos_level == 0:
            pass
        else:
            xift.broker.send_puback(mqtt_message.mid)

    xift.broker.on_message.side_effect = broker_on_message

    #   5. cleanup on client disconnect
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                      xift.broker.trigger_shutdown()

    ###
    # client flow
    #  1. connect (automagically through act())
    #   1a. hidden, subscribe to control topic.
    #  2. on connect response, publish to topic
    #  3. publish complete callback is called, shutdown.
    #  4. on shutdown callback, stop.
    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_publish_finish(ANY),
        call.client.on_disconnect(ANY)
    ]

    def connect_finish(connect_response):
        if is_string == True:
            xift.client_sut.publish_string(topic, payload, qos_level)
        else:
            xift.client_sut.publish_binary(topic, payload, qos_level)

    #  2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = connect_finish

    #  3. publish complete callback is called, shutdown.
    xift.client_sut.on_publish_finish.side_effect = lambda return_code: \
                                                        xift.client_sut.disconnect()

    #  4. on shutdown callback, stop.
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )

    ###
    # Act
    act(xift)

    ###
    # Assert
    assert broker_flow == xift.mock_call_history_broker.method_calls
    assert client_flow == xift.mock_call_history_client.method_calls
def publish_with_broker_disconnect_before_puback(xift, qos_level):
    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. reject publish on test topic
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_message(
            ANY, ANY,
            BasicMessageMatcher(TestEssentials.topic, qos_level,
                                TestEssentials.payload_as_bytes))
    ]

    #   1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    #  2. accept the control topic topic subscription
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                     xift.broker.send_suback( msg_id, topics_and_qos )

    # 3. reject publish on test topic
    xift.broker.on_message.side_effect = lambda a, bb, mqtt_message: \
                                            xift.broker.trigger_shutdown()

    ###
    # client flow
    #  1. connect (automagically through act())
    #  1a. hidden, subscribe to control topic.
    #  2. on connect response, publish to topic
    #  3. on shutdown callback, stop.
    if qos_level == 0:
        client_flow = [
            call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
            call.client.on_publish_finish(ANY),
            call.client.on_disconnect(ANY)
        ]
    else:
        client_flow = [
            call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
            call.client.on_disconnect(ANY)
        ]

    #  2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = lambda connect_response: \
                        xift.client_sut.publish_string(TestEssentials.topic, TestEssentials.payload_as_string, qos_level )

    xift.client_sut.on_publish_finish.side_effect = None

    #  3. on shutdown callback, stop.
    xift.client_sut.on_disconnect.side_effect = lambda return_code: \
                                                    xift.client_sut.stop()

    ###
    # Act
    act(xift)

    ###
    # Assert
    assert broker_flow == xift.mock_call_history_broker.method_calls
    assert client_flow == xift.mock_call_history_client.method_calls
def test_publish_PublishQoS1_DisconnectAfterPuback(xift):
    """
        Tests the correct behaviour when client publishes to a topic
            and gets disconnected after QoS 1 Puback.

        Test scenario:
            Client Attempts to Publish to a Topic, Server disconnects
            after puback.

        Expectation:
            Xively Client should have its disconnected callback
            invoked
    """
    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. send puback on message
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_message(
            ANY,
            ANY,
            BasicMessageMatcher(
                TestEssentials.topic,
                1,  #qos_level
                TestEssentials.payload_as_bytes))
    ]

    #   1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    #  2. accept the control topic topic subscription
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                xift.broker.send_suback( msg_id, topics_and_qos )

    #   3. send puback on message
    xift.broker.on_message.side_effect = lambda a, b, mqtt_message: \
                                xift.broker.send_puback(mqtt_message.mid)

    ###
    # client flow
    #  1. connect (automagically through act())
    #  1a. hidden, subscribe to control topic.
    #  2. on connect response, publish to topic
    #  3. on puback, have broker trigger shudown.
    #  3. on shutdown callback, stop.
    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_publish_finish(ANY),
        call.client.on_disconnect(ANY)
    ]

    #  2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = lambda connect_response: \
                    xift.client_sut.publish_string(TestEssentials.topic, TestEssentials.payload_as_string, 1 )

    xift.client_sut.on_publish_finish.side_effect = lambda return_code: \
                                                    xift.broker.trigger_shutdown()

    #  3. on shutdown callback, stop.
    xift.client_sut.on_disconnect.side_effect = lambda return_code: \
                                                    xift.client_sut.stop()

    ###
    # Act
    act(xift)

    ###
    # Assert
    assert broker_flow == xift.mock_call_history_broker.method_calls
    assert client_flow == xift.mock_call_history_client.method_calls
def off_test_ftest_lecture_threading_1(xift):

    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    def broker_on_client_connect(userdata, connect_options):
        print("*** [ broker ] [ " + threading.current_thread().getName() +
              " ] broker_on_client_connect")
        xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    xift.broker.on_client_connect.side_effect = broker_on_client_connect

    def broker_on_client_subscribe(userdata, msg_id, topics_and_qos):
        print("*** [ broker ] [ " + threading.current_thread().getName() +
              " ] broker_on_client_subscribe")
        xift.broker.send_suback(msg_id, topics_and_qos)

    xift.broker.on_client_subscribe.side_effect = broker_on_client_subscribe

    def broker_on_client_disconnect(br, userdata, rc):
        print("*** [ broker ] [ " + threading.current_thread().getName() +
              " ] broker_on_client_disconnect")
        xift.broker.trigger_shutdown()

    xift.broker.on_client_disconnect.side_effect = broker_on_client_disconnect

    xift.client_sut._exception_queue = xift._task_queue

    def client_on_connect_finish(connect_res):
        print("*** [ client ] [ " + threading.current_thread().getName() +
              " ] client_on_connect_finish")
        xift.client_sut.subscribe([[TestEssentials.topic, 1]])

    xift.client_sut.on_connect_finish.side_effect = client_on_connect_finish

    def client_on_subscribe_finish(granted_access_list):
        print("*** [ client ] [ " + threading.current_thread().getName() +
              " ] client_on_subscribe_finish")
        xift.client_sut.disconnect()

    xift.client_sut.on_subscribe_finish.side_effect = client_on_subscribe_finish

    def client_on_disconnect(return_code):
        print("*** [ client ] [ " + threading.current_thread().getName() +
              " ] client_on_disconnect")
        xift.client_sut.stop()

        def assert_on_return_code():
            assert return_code == 1

        xift._task_queue.put(assert_on_return_code)

    xift.client_sut.on_disconnect.side_effect = client_on_disconnect

    ###
    # Act
    print("\n")
    print("*** [ act    ] [ " + threading.current_thread().getName() +
          " ] act")
    act(xift)

    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish(ANY),
        call.client.on_disconnect(0)
    ]

    ###
    # Assert
    print("*** [ assert ] [ " + threading.current_thread().getName() +
          " ] asserting on main thread")
    assert broker_flow == xift.mock_call_history_broker.method_calls
    assert client_flow == xift.mock_call_history_client.method_calls
def test_subscribe_subscribeIncomingPublishQoS0_subscribeClbCalledSuccess(
        xift):
    """
        Tests the correct behaviour when client subscribes to a topic and
        an incoming message arrives on the topic.

        Test scenario:
            Client Attempts to Subscribe to a Topic, Server sends a message
            on topic after SUBACK

        Expectation:
            Client should invoke subscription callback
    """

    ###
    # broker flow
    #   1. accept connection, send connack
    #   2. accept the control topic topic subscription
    #   3. accept the standard topic subscription, check for QoS 0
    #   4. Cleanup on Disconnect
    broker_flow = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(ANY, ANY, ANY, 0),
        #   3. check for QoS 0
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.topic_as_signed_chars, 0)], 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    #   1. accept connection, send connack
    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                    xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)

    #   2. accept the control topic topic subscription
    #   3. accept the standard topic subscription,
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback( msg_id, topics_and_qos )

    #   4. Cleanup on Disconnect
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: \
                                                xift.broker.trigger_shutdown()

    ###
    # client flow
    #  1. connect (automagically through act())
    #  1a. hidden, subscribe to control topic.
    #  2. on connect response, subscribe to topic
    #  3. subscription callback invoked, broker to publish to topic client subscribed to.
    #  4. on message callback, validate message, shutdown connection
    #  5. on shutdown callback, stop.

    # Validates that the message parameters are what we expect to recieve on the client.
    client_flow = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish(
            [ANY]),  # 3. subscription callback invoked
        call.client.on_message_received(
            ANY,  # 4. on message callback validate message
            BasicMessageMatcher(
                TestEssentials.topic,
                0,  #qos_level
                TestEssentials.payload_as_bytes)),
        call.client.on_disconnect(ANY)
    ]

    #  2. on connect response, subscribe to topic
    xift.client_sut.on_connect_finish.side_effect = lambda connect_response: \
                                                        xift.client_sut.subscribe([[TestEssentials.topic, 0]])

    #  3. subscription callback invoked, broker to publish to topic client subscribed to.
    xift.client_sut.on_subscribe_finish.side_effect = lambda granted_access_list: \
                                                        xift.broker.publish(TestEssentials.topic, TestEssentials.payload_as_string)

    #  4. on message callback, ..., shutdown connection
    xift.client_sut.on_message_received.side_effect = lambda topic, message: \
                                                        xift.client_sut.disconnect()

    #  5. on shutdown callback, stop.
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )

    ###
    # Act
    act(xift)

    ###
    # Assert
    assert broker_flow == xift.mock_call_history_broker.method_calls
    assert client_flow == xift.mock_call_history_client.method_calls
Exemplo n.º 27
0
def test_receive_5_subscribed_messages(xift):
    # Arrange
    def deliver_5(userdata, msg_id, topics_and_qos, dup):
        xift.broker.send_suback(msg_id, topics_and_qos)
        if [(TestEssentials.topic_as_bytes, 0)] == topics_and_qos:
            # Deliver 5 messages to the client
            for i in range(5):
                xift.broker.publish(TestEssentials.topic,
                                    TestEssentials.payload_as_string)

    def collect_5_and_exit():
        counter = Counter()

        def collect_all(topic, message):
            counter.inc()
            if counter.is_at(5):
                xift.client_sut.disconnect()

        return collect_all

    xift.client_sut.on_connect_finish.side_effect = lambda connect_response: \
                                                        xift.client_sut.subscribe([[TestEssentials.topic, 0]])
    xift.client_sut.on_disconnect.side_effect = lambda return_code: xift.client_sut.stop(
    )
    xift.client_sut.on_subscribe_finish.side_effect = None
    xift.client_sut.on_message_received.side_effect = collect_5_and_exit()

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                    xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_subscribe.side_effect = deliver_5
    xift.broker.on_client_disconnect.side_effect = lambda br, userdata, rc: xift.broker.trigger_shutdown(
    )

    # Act
    act(xift)

    # Assert
    class MessageMatcher(mqtt_messages.MQTTMessage):
        def __init__(self):
            super(MessageMatcher, self).__init__()

        def __eq__(self, other):
            return TestEssentials.payload_as_bytes == other.payload and 0 == other.qos

    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_subscribe(ANY, ANY,
                                        [(TestEssentials.topic_as_bytes, 0)],
                                        0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_subscribe_finish([0]),
        # 5 times
        call.client.on_message_received(TestEssentials.topic,
                                        MessageMatcher()),
        call.client.on_message_received(TestEssentials.topic,
                                        MessageMatcher()),
        call.client.on_message_received(TestEssentials.topic,
                                        MessageMatcher()),
        call.client.on_message_received(TestEssentials.topic,
                                        MessageMatcher()),
        call.client.on_message_received(TestEssentials.topic,
                                        MessageMatcher()),
        call.client.on_disconnect(MQTT_ERR_SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
Exemplo n.º 28
0
def test_reconnect_clientDisconnectsAndReconnects3Times_3SuccessfulConnect(
        xift):
    # Arrange

    def on_disconnect_connect_twice_then_stop():
        counter = Counter()

        def on_disconnect_connect_twice_then_stop_impl(return_code):
            counter.inc()
            if counter.is_at(3):
                xift.client_sut.stop()
            else:
                xift.client_sut.connect(xift.broker.bind_address,
                                        xift.connect_options,
                                        TestEssentials.connection_timeout)

        return on_disconnect_connect_twice_then_stop_impl

    xift.client_sut.on_disconnect.side_effect = on_disconnect_connect_twice_then_stop(
    )
    xift.client_sut.on_connect_finish.side_effect = lambda connect_result: \
                                                           xift.client_sut.disconnect()

    def on_client_disconnect_shutdown_after_third():
        counter = Counter()

        def on_third_call_shutdown(broker, userdata, result_code):
            counter.inc()
            if counter.is_at(3):
                xift.broker.trigger_shutdown()

        return on_third_call_shutdown

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                       xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_disconnect.side_effect = on_client_disconnect_shutdown_after_third(
    )
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                         xift.broker.send_suback(msg_id, topics_and_qos)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS),
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS),
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(MQTT_ERR_SUCCESS),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(MQTT_ERR_SUCCESS),
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_disconnect(MQTT_ERR_SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls
Exemplo n.º 29
0
def test_receive_5_unsubscribed_messages(xift):
    if xift.sut_platform == XiClientPlatform.C:
        pytest.xfail(
            "This test require XivelyC library to have handle for receiving unsubscribed messages"
        )

    # Arrange
    def deliver_5(result):
        for i in range(5):
            xift.broker.publish(TestEssentials.topic,
                                TestEssentials.payload_as_string)

    def collect_5_and_exit():
        counter = Counter()

        def collect_all(topic, message):
            counter.inc()
            # We can avoid using matchers by asserting here on the message.
            assert TestEssentials.topic == message.topic
            assert TestEssentials.payload_as_bytes == message.payload
            assert 0 == message.qos
            if counter.is_at(5):
                xift.client_sut.disconnect()

        return collect_all

    xift.client_sut.on_connect_finish.side_effect = deliver_5
    xift.client_sut.on_disconnect.side_effect = lambda result: xift.client_sut.stop(
    )
    xift.client_sut.on_message_received.side_effect = collect_5_and_exit()

    xift.broker.on_client_connect.side_effect = lambda userdata, connect_options: \
                                                    xift.broker.send_connack(mqtt_messages.CONNACK_ACCEPTED)
    xift.broker.on_client_disconnect.side_effect = lambda a, b, c: xift.broker.trigger_shutdown(
    )
    xift.broker.on_client_subscribe.side_effect = lambda userdata, msg_id, topics_and_qos, dup: \
                                                    xift.broker.send_suback(msg_id, topics_and_qos)

    # Act
    act(xift)

    # Assert
    expected_calls_broker = [
        call.broker.on_client_connect(ANY, ANY),
        call.broker.on_client_subscribe(
            ANY, ANY, [(TestEssentials.control_topic_name, 1)], 0),
        call.broker.on_client_disconnect(xift.broker, ANY, MQTT_ERR_SUCCESS)
    ]

    expected_calls_client = [
        call.client.on_connect_finish(mqtt_messages.CONNACK_ACCEPTED),
        call.client.on_message_received(ANY, ANY),
        call.client.on_message_received(ANY, ANY),
        call.client.on_message_received(ANY, ANY),
        call.client.on_message_received(ANY, ANY),
        call.client.on_message_received(ANY, ANY),
        call.client.on_disconnect(MQTT_ERR_SUCCESS)
    ]

    assert expected_calls_broker == xift.mock_call_history_broker.method_calls
    assert expected_calls_client == xift.mock_call_history_client.method_calls