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
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
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))
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]
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
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
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:]
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]
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
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
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
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