From 0cd2cd90241cd32207d634be8a7d5f4d16570bd9 Mon Sep 17 00:00:00 2001 From: Jelani Date: Wed, 9 Aug 2017 16:47:17 -0700 Subject: [PATCH] Add callback function for Disconnect --- .../mqtt_client_requirements.md | 157 ++++++++++++------ inc/azure_umqtt_c/mqtt_client.h | 3 +- .../mqtt_client_sample/mqtt_client_sample.c | 2 +- src/mqtt_client.c | 54 +++--- tests/mqtt_client_ut/mqtt_client_ut.c | 91 +++++----- 5 files changed, 185 insertions(+), 122 deletions(-) diff --git a/devdoc/requirement_docs/mqtt_client_requirements.md b/devdoc/requirement_docs/mqtt_client_requirements.md index 047b90f..923a2c0 100644 --- a/devdoc/requirement_docs/mqtt_client_requirements.md +++ b/devdoc/requirement_docs/mqtt_client_requirements.md @@ -1,10 +1,10 @@ # Mqtt_Client Requirements -##Overview +## Overview Mqtt_Client is the library that encapsulates the [MQTT Protocol](http://mqtt.org/documentation) -##Exposed API +## Exposed API ```C typedef struct MQTT_CLIENT_DATA_INSTANCE_TAG* MQTT_CLIENT_HANDLE; @@ -40,7 +40,7 @@ extern MQTT_CLIENT_HANDLE mqtt_client_init(ON_MQTT_MESSAGE_RECV_CALLBACK msgRecv extern void mqtt_client_deinit(MQTT_CLIENT_HANDLE handle); extern int mqtt_client_connect(MQTT_CLIENT_HANDLE handle, XIO_HANDLE ioHandle, MQTT_CLIENT_OPTIONS* mqttOptions); -extern void mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle); +extern void mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle, ON_MQTT_DISCONNECTED_CALLBACK callback, void* ctx); extern int mqtt_client_subscribe(MQTT_CLIENT_HANDLE handle, uint8_t packetId, SUBSCRIBE_PAYLOAD* payloadList, size_t payloadCount); extern int mqtt_client_unsubscribe(MQTT_CLIENT_HANDLE handle, uint8_t packetId, const char** unsubscribeTopic, size_t payloadCount); @@ -50,89 +50,138 @@ extern int mqtt_client_publish(MQTT_CLIENT_HANDLE handle, MQTT_MESSAGE_HANDLE ms extern void mqtt_client_dowork(MQTT_CLIENT_HANDLE handle); ``` -##mqtt_client_init -``` +## mqtt_client_init + +```C extern MQTT_CLIENT_HANDLE mqtt_client_init(ON_MQTT_MESSAGE_RECV_CALLBACK msgRecv, ON_MQTT_OPERATION_CALLBACK opCallback, void* callbackCtx, ON_MQTT_ERROR_CALLBACK onErrorCallBack, void* errorCBCtx) ``` + **SRS_MQTT_CLIENT_07_001: [**If the parameters ON_MQTT_MESSAGE_RECV_CALLBACK is NULL then mqttclient_init shall return NULL.**]** -**SRS_MQTT_CLIENT_07_002: [**If any failure is encountered then mqttclient_init shall return NULL.**]** + +**SRS_MQTT_CLIENT_07_002: [**If any failure is encountered then mqttclient_init shall return NULL.**]** + **SRS_MQTT_CLIENT_07_003: [**mqttclient_init shall allocate MQTTCLIENT_DATA_INSTANCE and return the MQTTCLIENT_HANDLE on success.**]** -##mqtt_client_deinit -``` +## mqtt_client_deinit + +```C extern void mqtt_client_deinit(MQTT_CLIENT_HANDLE handle); ``` -**SRS_MQTT_CLIENT_07_004: [**If the parameter handle is NULL then function mqtt_client_deinit shall do nothing.**]** -**SRS_MQTT_CLIENT_07_005: [**mqtt_client_deinit shall deallocate all memory allocated in this unit.**]** - -##mqtt_client_connect -``` + +**SRS_MQTT_CLIENT_07_004: [**If the parameter handle is NULL then function mqtt_client_deinit shall do nothing.**]** + +**SRS_MQTT_CLIENT_07_005: [**mqtt_client_deinit shall deallocate all memory allocated in this unit.**]** + +## mqtt_client_connect + +```C extern int mqtt_client_connect(MQTT_CLIENT_HANDLE handle, XIO_HANDLE ioHandle, MQTT_CLIENT_OPTIONS* mqttOptions); ``` -**SRS_MQTT_CLIENT_07_006: [**If any of the parameters handle, ioHandle, or mqttOptions are NULL then mqtt_client_connect shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_007: [**If any failure is encountered then mqtt_client_connect shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_008: [**mqtt_client_connect shall open the XIO_HANDLE by calling into the xio_open interface.**]** -**SRS_MQTT_CLIENT_07_009: [**On success mqtt_client_connect shall send the MQTT CONNECT packet to the endpoint.**]** -**SRS_MQTT_CLIENT_07_036: [** If an error is encountered by the ioHandle the mqtt_client shall call xio_close. **]** -##mqtt_client_disconnect -``` -extern int mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle); -``` -**SRS_MQTT_CLIENT_07_010: [**If the parameters handle is NULL then mqtt_client_disconnect shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_011: [**If any failure is encountered then mqtt_client_disconnect shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_012: [**On success mqtt_client_disconnect shall send the MQTT DISCONNECT packet to the endpoint.**]** +**SRS_MQTT_CLIENT_07_006: [**If any of the parameters handle, ioHandle, or mqttOptions are NULL then mqtt_client_connect shall return a non-zero value.**]** -##mqttclient_subscribe +**SRS_MQTT_CLIENT_07_007: [**If any failure is encountered then mqtt_client_connect shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_008: [**mqtt_client_connect shall open the XIO_HANDLE by calling into the xio_open interface.**]** + +**SRS_MQTT_CLIENT_07_009: [**On success mqtt_client_connect shall send the MQTT CONNECT packet to the endpoint.**]** + +**SRS_MQTT_CLIENT_07_036: [** If an error is encountered by the ioHandle the mqtt_client shall call xio_close. **]** + +## mqtt_client_disconnect + +```C +extern int mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle, ON_MQTT_DISCONNECTED_CALLBACK callback, void* ctx); ``` + +**SRS_MQTT_CLIENT_07_010: [**If the parameters handle is NULL then mqtt_client_disconnect shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_011: [**If any failure is encountered then mqtt_client_disconnect shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_012: [**On success mqtt_client_disconnect shall send the MQTT DISCONNECT packet to the endpoint.**]** + +**SRS_MQTT_CLIENT_07_037: [** if callback is not NULL callback shall be called once the mqtt connection has been disconnected **]** + +## mqtt_client_subscribe + +```C int mqtt_client_subscribe(MQTT_CLIENT_HANDLE handle, uint8_t packetId, SUBSCRIBE_PAYLOAD* payloadList, size_t payloadCount); ``` -**SRS_MQTT_CLIENT_07_013: [**If any of the parameters handle, subscribeList is NULL or count is 0 then mqtt_client_subscribe shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_014: [**If any failure is encountered then mqtt_client_subscribe shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_015: [**On success mqtt_client_subscribe shall send the MQTT SUBCRIBE packet to the endpoint.**]** -##mqtt_client_unsubscribe -``` +**SRS_MQTT_CLIENT_07_013: [**If any of the parameters handle, subscribeList is NULL or count is 0 then mqtt_client_subscribe shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_014: [**If any failure is encountered then mqtt_client_subscribe shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_015: [**On success mqtt_client_subscribe shall send the MQTT SUBCRIBE packet to the endpoint.**]** + +## mqtt_client_unsubscribe + +```C extern int mqtt_client_unsubscribe(MQTT_CLIENT_HANDLE handle, uint8_t packetId, const char** unsubscribeList, size_t count); ``` -**SRS_MQTT_CLIENT_07_016: [**If any of the parameters handle, unsubscribeList is NULL or count is 0 then mqtt_client_unsubscribe shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_017: [**If any failure is encountered then mqtt_client_unsubscribe shall return a non-zero value.**]** -**SRS_MQTT_CLIENT_07_018: [**On success mqtt_client_unsubscribe shall send the MQTT SUBCRIBE packet to the endpoint.**]** -##mqtt_client_publish -``` +**SRS_MQTT_CLIENT_07_016: [**If any of the parameters handle, unsubscribeList is NULL or count is 0 then mqtt_client_unsubscribe shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_017: [**If any failure is encountered then mqtt_client_unsubscribe shall return a non-zero value.**]** + +**SRS_MQTT_CLIENT_07_018: [**On success mqtt_client_unsubscribe shall send the MQTT SUBCRIBE packet to the endpoint.**]** + +## mqtt_client_publish + +```C extern int mqtt_client_publish(MQTT_CLIENT_HANDLE handle, MQTT_MESSAGE_HANDLE msgHandle); ``` + **SRS_MQTT_CLIENT_07_019: [**If one of the parameters handle or msgHandle is NULL then mqtt_client_publish shall return a non-zero value.**]** + **SRS_MQTT_CLIENT_07_020: [**If any failure is encountered then mqtt_client_publish shall return a non-zero value.**]** + **SRS_MQTT_CLIENT_07_021: [**mqtt_client_publish shall get the message information from the MQTT_MESSAGE_HANDLE.**]** + **SRS_MQTT_CLIENT_07_022: [**On success mqtt_client_publish shall send the MQTT SUBCRIBE packet to the endpoint.**]** -##mqtt_client_dowork -``` +## mqtt_client_dowork + +```C extern void mqtt_client_dowork(MQTT_CLIENT_HANDLE handle); ``` -**SRS_MQTT_CLIENT_07_023: [**If the parameter handle is NULL then mqtt_client_dowork shall do nothing.**]** -**SRS_MQTT_CLIENT_18_001: [**If the client is disconnected, mqtt_client_dowork shall do nothing.**]** -**SRS_MQTT_CLIENT_07_024: [**mqtt_client_dowork shall call the xio_dowork function to complete operations.**]** -**SRS_MQTT_CLIENT_07_025: [**mqtt_client_dowork shall retrieve the the last packet send value and ...**]** -**SRS_MQTT_CLIENT_07_026: [**If keepAliveInternal is > 0 and the send time is greater than the MQTT KeepAliveInterval then it shall construct an MQTT PINGREQ packet.**]** + +**SRS_MQTT_CLIENT_07_023: [**If the parameter handle is NULL then mqtt_client_dowork shall do nothing.**]** + +**SRS_MQTT_CLIENT_18_001: [**If the client is disconnected, mqtt_client_dowork shall do nothing.**]** + +**SRS_MQTT_CLIENT_07_024: [**mqtt_client_dowork shall call the xio_dowork function to complete operations.**]** + +**SRS_MQTT_CLIENT_07_025: [**mqtt_client_dowork shall retrieve the the last packet send value and ...**]** + +**SRS_MQTT_CLIENT_07_026: [**If keepAliveInternal is > 0 and the send time is greater than the MQTT KeepAliveInterval then it shall construct an MQTT PINGREQ packet.**]** + **SRS_MQTT_CLIENT_07_035: [**If the timeSincePing has expired past the maxPingRespTime then mqtt_client_dowork shall call the Error Callback function with the message MQTT_CLIENT_NO_PING_RESPONSE**]** -##ON_MQTT_OPERATION_CALLBACK -``` +## ON_MQTT_OPERATION_CALLBACK + +```C typedef void(*ON_MQTT_OPERATION_CALLBACK)(MQTT_CLIENT_ACTION_RESULT actionResult, const void* msgInfo, void* callbackCtx); ``` -**SRS_MQTT_CLIENT_07_027: [**The callbackCtx parameter shall be an unmodified pointer that was passed to the mqtt_client_init function.**]** -**SRS_MQTT_CLIENT_07_028: [**If the actionResult parameter is of type CONNECT_ACK then the msgInfo value shall be a CONNECT_ACK* structure.**]** -**SRS_MQTT_CLIENT_07_029: [**If the actionResult parameter are of types PUBACK_TYPE, PUBREC_TYPE, PUBREL_TYPE or PUBCOMP_TYPE then the msgInfo value shall be a PUBLISH_ACK* structure.**]** -**SRS_MQTT_CLIENT_07_030: [**If the actionResult parameter is of type SUBACK_TYPE then the msgInfo value shall be a SUBSCRIBE_ACK* structure.**]** -**SRS_MQTT_CLIENT_07_031: [**If the actionResult parameter is of type UNSUBACK_TYPE then the msgInfo value shall be a UNSUBSCRIBE_ACK* structure.**]** + +**SRS_MQTT_CLIENT_07_027: [**The callbackCtx parameter shall be an unmodified pointer that was passed to the mqtt_client_init function.**]** + +**SRS_MQTT_CLIENT_07_028: [**If the actionResult parameter is of type CONNECT_ACK then the msgInfo value shall be a CONNECT_ACK* structure.**]** + +**SRS_MQTT_CLIENT_07_029: [**If the actionResult parameter are of types PUBACK_TYPE, PUBREC_TYPE, PUBREL_TYPE or PUBCOMP_TYPE then the msgInfo value shall be a PUBLISH_ACK* structure.**]** + +**SRS_MQTT_CLIENT_07_030: [**If the actionResult parameter is of type SUBACK_TYPE then the msgInfo value shall be a SUBSCRIBE_ACK* structure.**]** + +**SRS_MQTT_CLIENT_07_031: [**If the actionResult parameter is of type UNSUBACK_TYPE then the msgInfo value shall be a UNSUBSCRIBE_ACK* structure.**]** + **SRS_MQTT_CLIENT_07_032: [**If the actionResult parameter is of type MQTT_CLIENT_ON_DISCONNECT the the msgInfo value shall be NULL.**]** -##ON_MQTT_MESSAGE_RECV_CALLBACK -``` +## ON_MQTT_MESSAGE_RECV_CALLBACK + +```C typedef void(*ON_MQTT_MESSAGE_RECV_CALLBACK)(MQTT_MESSAGE_HANDLE msgHandle, void* callbackCtx); ``` -**SRS_MQTT_CLIENT_07_033: [**The callbackCtx parameter shall be an unmodified pointer that was passed to the mqtt_client_init function.**]** -**SRS_MQTT_CLIENT_07_034: [**The msgHandle shall be the message that was sent from the MQTT endpoint to the client.**]** + +**SRS_MQTT_CLIENT_07_033: [**The callbackCtx parameter shall be an unmodified pointer that was passed to the mqtt_client_init function.**]** + +**SRS_MQTT_CLIENT_07_034: [**The msgHandle shall be the message that was sent from the MQTT endpoint to the client.**]** diff --git a/inc/azure_umqtt_c/mqtt_client.h b/inc/azure_umqtt_c/mqtt_client.h index ff3d0b9..4b24b5e 100644 --- a/inc/azure_umqtt_c/mqtt_client.h +++ b/inc/azure_umqtt_c/mqtt_client.h @@ -45,12 +45,13 @@ DEFINE_ENUM(MQTT_CLIENT_EVENT_ERROR, MQTT_CLIENT_EVENT_ERROR_VALUES); typedef void(*ON_MQTT_OPERATION_CALLBACK)(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_RESULT actionResult, const void* msgInfo, void* callbackCtx); typedef void(*ON_MQTT_ERROR_CALLBACK)(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_ERROR error, void* callbackCtx); typedef void(*ON_MQTT_MESSAGE_RECV_CALLBACK)(MQTT_MESSAGE_HANDLE msgHandle, void* callbackCtx); +typedef void(*ON_MQTT_DISCONNECTED_CALLBACK)(void* callbackCtx); MOCKABLE_FUNCTION(, MQTT_CLIENT_HANDLE, mqtt_client_init, ON_MQTT_MESSAGE_RECV_CALLBACK, msgRecv, ON_MQTT_OPERATION_CALLBACK, opCallback, void*, opCallbackCtx, ON_MQTT_ERROR_CALLBACK, onErrorCallBack, void*, errorCBCtx); MOCKABLE_FUNCTION(, void, mqtt_client_deinit, MQTT_CLIENT_HANDLE, handle); MOCKABLE_FUNCTION(, int, mqtt_client_connect, MQTT_CLIENT_HANDLE, handle, XIO_HANDLE, xioHandle, MQTT_CLIENT_OPTIONS*, mqttOptions); -MOCKABLE_FUNCTION(, int, mqtt_client_disconnect, MQTT_CLIENT_HANDLE, handle); +MOCKABLE_FUNCTION(, int, mqtt_client_disconnect, MQTT_CLIENT_HANDLE, handle, ON_MQTT_DISCONNECTED_CALLBACK, callback, void*, ctx); MOCKABLE_FUNCTION(, int, mqtt_client_subscribe, MQTT_CLIENT_HANDLE, handle, uint16_t, packetId, SUBSCRIBE_PAYLOAD*, subscribeList, size_t, count); MOCKABLE_FUNCTION(, int, mqtt_client_unsubscribe, MQTT_CLIENT_HANDLE, handle, uint16_t, packetId, const char**, unsubscribeList, size_t, count); diff --git a/samples/mqtt_client_sample/mqtt_client_sample.c b/samples/mqtt_client_sample/mqtt_client_sample.c index 9ff1b3b..b93b2a6 100644 --- a/samples/mqtt_client_sample/mqtt_client_sample.c +++ b/samples/mqtt_client_sample/mqtt_client_sample.c @@ -121,7 +121,7 @@ static void OnOperationComplete(MQTT_CLIENT_HANDLE handle, MQTT_CLIENT_EVENT_RES case MQTT_CLIENT_ON_PUBLISH_COMP: { // Done so send disconnect - mqtt_client_disconnect(handle); + mqtt_client_disconnect(handle, NULL, NULL); break; } case MQTT_CLIENT_ON_DISCONNECT: diff --git a/src/mqtt_client.c b/src/mqtt_client.c index 5d8681f..8b6f0f5 100644 --- a/src/mqtt_client.c +++ b/src/mqtt_client.c @@ -44,6 +44,8 @@ typedef struct MQTT_CLIENT_TAG void* ctx; ON_MQTT_ERROR_CALLBACK fnOnErrorCallBack; void* errorCBCtx; + ON_MQTT_DISCONNECTED_CALLBACK disconnect_cb; + void* disconnect_ctx; QOS_VALUE qosValue; uint16_t keepAliveInterval; MQTT_CLIENT_OPTIONS mqttOptions; @@ -57,24 +59,31 @@ typedef struct MQTT_CLIENT_TAG static void on_connection_closed(void* context) { - size_t* close_complete = (size_t*)context; - *close_complete = 1; + MQTT_CLIENT* mqtt_client = (MQTT_CLIENT*)context; + if (mqtt_client != NULL) + { + mqtt_client->socketConnected = false; + mqtt_client->clientConnected = false; + if (mqtt_client->disconnect_cb) + { + mqtt_client->disconnect_cb(mqtt_client->disconnect_ctx); + } + } } static void close_connection(MQTT_CLIENT* mqtt_client) { - size_t close_complete = 0; - (void)xio_close(mqtt_client->xioHandle, on_connection_closed, &close_complete); - - size_t counter = 0; - do + (void)xio_close(mqtt_client->xioHandle, on_connection_closed, mqtt_client); + if (mqtt_client->disconnect_cb == NULL) { - xio_dowork(mqtt_client->xioHandle); - counter++; - ThreadAPI_Sleep(10); - } while (close_complete == 0 && counter < MAX_CLOSE_RETRIES); - mqtt_client->socketConnected = false; - mqtt_client->clientConnected = false; + size_t counter = 0; + do + { + xio_dowork(mqtt_client->xioHandle); + counter++; + ThreadAPI_Sleep(2); + } while (mqtt_client->clientConnected && counter < MAX_CLOSE_RETRIES); + } } static void set_error_callback(MQTT_CLIENT* mqtt_client, MQTT_CLIENT_EVENT_ERROR error_type) @@ -876,28 +885,16 @@ MQTT_CLIENT_HANDLE mqtt_client_init(ON_MQTT_MESSAGE_RECV_CALLBACK msgRecv, ON_MQ } else { + memset(result, 0, sizeof(MQTT_CLIENT)); /*Codes_SRS_MQTT_CLIENT_07_003: [mqttclient_init shall allocate MQTTCLIENT_DATA_INSTANCE and return the MQTTCLIENT_HANDLE on success.]*/ - result->xioHandle = NULL; result->packetState = UNKNOWN_TYPE; - result->packetSendTimeMs = 0; result->fnOperationCallback = opCallback; result->ctx = opCallbackCtx; result->fnMessageRecv = msgRecv; result->fnOnErrorCallBack = onErrorCallBack; result->errorCBCtx = errorCBCtx; result->qosValue = DELIVER_AT_MOST_ONCE; - result->keepAliveInterval = 0; result->packetTickCntr = tickcounter_create(); - result->mqttOptions.clientId = NULL; - result->mqttOptions.willTopic = NULL; - result->mqttOptions.willMessage = NULL; - result->mqttOptions.username = NULL; - result->mqttOptions.password = NULL; - result->socketConnected = false; - result->clientConnected = false; - result->logTrace = false; - result->rawBytesTrace = false; - result->timeSincePing = 0; result->maxPingRespTime = DEFAULT_MAX_PING_RESPONSE_TIME; if (result->packetTickCntr == NULL) { @@ -1145,7 +1142,7 @@ int mqtt_client_unsubscribe(MQTT_CLIENT_HANDLE handle, uint16_t packetId, const return result; } -int mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle) +int mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle, ON_MQTT_DISCONNECTED_CALLBACK callback, void* ctx) { int result; MQTT_CLIENT* mqtt_client = (MQTT_CLIENT*)handle; @@ -1166,6 +1163,9 @@ int mqtt_client_disconnect(MQTT_CLIENT_HANDLE handle) } else { + /* Codes_SRS_MQTT_CLIENT_07_037: [ if callback is not NULL callback shall be called once the mqtt connection has been disconnected ] */ + mqtt_client->disconnect_cb = callback; + mqtt_client->disconnect_ctx = ctx; mqtt_client->packetState = DISCONNECT_TYPE; size_t size = BUFFER_length(disconnectPacket); diff --git a/tests/mqtt_client_ut/mqtt_client_ut.c b/tests/mqtt_client_ut/mqtt_client_ut.c index 8b2c712..40020d9 100644 --- a/tests/mqtt_client_ut/mqtt_client_ut.c +++ b/tests/mqtt_client_ut/mqtt_client_ut.c @@ -50,8 +50,10 @@ static void my_gballoc_free(void* ptr) #include "azure_umqtt_c/mqttconst.h" #define ENABLE_MOCKS +#include "azure_c_shared_utility/umock_c_prod.h" MOCKABLE_FUNCTION(, void, on_mqtt_operation_callback, MQTT_CLIENT_HANDLE, handle, MQTT_CLIENT_EVENT_RESULT, actionResult, const void*, msgInfo, void*, callbackCtx); +MOCKABLE_FUNCTION(, void, on_mqtt_disconnected_callback, void*, callback_ctx); #undef ENABLE_MOCKS @@ -114,6 +116,8 @@ typedef struct TEST_COMPLETE_DATA_INSTANCE_TAG TEST_MUTEX_HANDLE test_serialize_mutex; #define TEST_CONTEXT ((const void*)0x4242) +#define MAX_CLOSE_RETRIES 10 +#define CLOSE_SLEEP_VALUE 2 #ifdef __cplusplus extern "C" { @@ -1009,11 +1013,9 @@ TEST_FUNCTION(mqtt_client_on_bytes_received_bytesReceived_fail_succeeds) STRICT_EXPECTED_CALL(xio_close(TEST_IO_HANDLE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) - { - STRICT_EXPECTED_CALL(xio_dowork(TEST_IO_HANDLE)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); - } + + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); // act g_bytesRecv(g_bytesRecvCtx, TEST_BUFFER_U_CHAR, 1); @@ -1039,11 +1041,9 @@ TEST_FUNCTION(mqtt_client_connect_multiple_completes_one_connect_succeeds) STRICT_EXPECTED_CALL(xio_close(TEST_IO_HANDLE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) - { - STRICT_EXPECTED_CALL(xio_dowork(TEST_IO_HANDLE)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); - } + + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); // act int result = mqtt_client_connect(mqttHandle, TEST_IO_HANDLE, &mqttOptions); @@ -1078,11 +1078,9 @@ TEST_FUNCTION(mqtt_client_connect_completes_IO_OPEN_ERROR_succeeds) STRICT_EXPECTED_CALL(xio_close(TEST_IO_HANDLE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) - { - STRICT_EXPECTED_CALL(xio_dowork(TEST_IO_HANDLE)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); - } + + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); // act ASSERT_IS_NOT_NULL(g_openComplete); @@ -1112,11 +1110,9 @@ TEST_FUNCTION(mqtt_client_ioerror_succeeds) STRICT_EXPECTED_CALL(xio_close(TEST_IO_HANDLE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) - { - STRICT_EXPECTED_CALL(xio_dowork(TEST_IO_HANDLE)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); - } + + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); // act g_ioError(g_ioErrorCtx); @@ -1561,7 +1557,7 @@ TEST_FUNCTION(mqtt_client_disconnect_handle_NULL_fail) // arrange // act - int result = mqtt_client_disconnect(NULL); + int result = mqtt_client_disconnect(NULL, NULL, NULL); // assert ASSERT_ARE_NOT_EQUAL(int, 0, result); @@ -1600,7 +1596,7 @@ TEST_FUNCTION(mqtt_client_disconnect_fail) char tmp_msg[64]; sprintf(tmp_msg, "mqtt_client_disconnect failure in test %zu/%zu", index, count); - int result = mqtt_client_disconnect(mqttHandle); + int result = mqtt_client_disconnect(mqttHandle, NULL, NULL); // assert ASSERT_ARE_NOT_EQUAL_WITH_MSG(int, 0, result, tmp_msg); @@ -1622,7 +1618,29 @@ TEST_FUNCTION(mqtt_client_disconnect_succeeds) setup_mqtt_client_disconnect_mocks(&mqttOptions); // act - int result = mqtt_client_disconnect(mqttHandle); + int result = mqtt_client_disconnect(mqttHandle, NULL, NULL); + + // assert + ASSERT_ARE_EQUAL(int, 0, result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + // cleanup + mqtt_client_deinit(mqttHandle); +} + +/* Tests_SRS_MQTT_CLIENT_07_037: [ if callback is not NULL callback shall be called once the mqtt connection has been disconnected ] */ +TEST_FUNCTION(mqtt_client_disconnect_callback_succeeds) +{ + // arrange + MQTT_CLIENT_OPTIONS mqttOptions = { 0 }; + + MQTT_CLIENT_HANDLE mqttHandle = mqtt_client_init(TestRecvCallback, TestOpCallback, NULL, TestErrorCallback, NULL); + umock_c_reset_all_calls(); + + setup_mqtt_client_disconnect_mocks(&mqttOptions); + + // act + int result = mqtt_client_disconnect(mqttHandle, on_mqtt_disconnected_callback, NULL); // assert ASSERT_ARE_EQUAL(int, 0, result); @@ -1636,7 +1654,7 @@ TEST_FUNCTION(mqtt_client_disconnect_send_complete_SEND_OK_succeeds) { // arrange MQTT_CLIENT_HANDLE mqttHandle = mqtt_client_init(TestRecvCallback, TestOpCallback, NULL, TestErrorCallback, NULL); - (void)mqtt_client_disconnect(mqttHandle); + (void)mqtt_client_disconnect(mqttHandle, NULL, NULL); umock_c_reset_all_calls(); EXPECTED_CALL(xio_close(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_NUM_ARG)); @@ -1656,7 +1674,7 @@ TEST_FUNCTION(mqtt_client_disconnect_send_complete_SEND_ERROR_succeeds) { // arrange MQTT_CLIENT_HANDLE mqttHandle = mqtt_client_init(TestRecvCallback, TestOpCallback, NULL, TestErrorCallback, NULL); - (void)mqtt_client_disconnect(mqttHandle); + (void)mqtt_client_disconnect(mqttHandle, NULL, NULL); umock_c_reset_all_calls(); // act @@ -1756,10 +1774,10 @@ TEST_FUNCTION(mqtt_client_dowork_ping_No_ping_response_succeeds) STRICT_EXPECTED_CALL(xio_close(TEST_IO_HANDLE, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) + for (size_t index = 0; index < MAX_CLOSE_RETRIES; index++) { - STRICT_EXPECTED_CALL(xio_dowork(TEST_IO_HANDLE)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); } // act @@ -1903,7 +1921,7 @@ TEST_FUNCTION(mqtt_client_dowork_does_nothing_if_disconnected) g_openComplete(g_onCompleteCtx, IO_OPEN_OK); g_packetComplete(mqttHandle, CONNACK_TYPE, 0, connack_handle); - mqtt_client_disconnect(mqttHandle); + mqtt_client_disconnect(mqttHandle, NULL, NULL); umock_c_reset_all_calls(); @@ -2284,11 +2302,8 @@ TEST_FUNCTION(mqtt_client_recvCompleteCallback_PUBLISH_RECEIVE_fails) STRICT_EXPECTED_CALL(xio_close(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) - { - STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); - } + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); // act g_mqtt_codec_publish_func_fail = true; @@ -2363,11 +2378,9 @@ TEST_FUNCTION(mqtt_client_recvCompleteCallback_PUBLISH_RELEASE_fails) STRICT_EXPECTED_CALL(xio_close(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .IgnoreArgument_on_io_close_complete() .IgnoreArgument_callback_context(); - for (size_t index = 0; index < 10; index++) - { - STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); - STRICT_EXPECTED_CALL(ThreadAPI_Sleep(10)); - } + + STRICT_EXPECTED_CALL(xio_dowork(IGNORED_PTR_ARG)); + STRICT_EXPECTED_CALL(ThreadAPI_Sleep(CLOSE_SLEEP_VALUE)); // act g_mqtt_codec_publish_func_fail = true;