Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions source/include/core_mqtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,16 @@ typedef struct MQTTContext
*/
MQTTEventCallback_t appCallback;

/**
* @brief Application-defined data pointer.
*
* The library never reads or modifies this field; it allows the
* application to access its own state from an #MQTTEventCallback_t
* callback through the pContext parameter. As #MQTT_Init clears the
* entire context, set this field only after calling #MQTT_Init.
*/
void * pUserData;

/**
* @brief Timestamp of the last packet sent by the library.
*/
Expand Down
82 changes: 82 additions & 0 deletions test/unit-test/core_mqtt_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,29 @@ static bool eventCallback2( MQTTContext_t * pContext,
return true;
}

/**
* @brief Value of pContext->pUserData recorded by eventCallbackUserData.
*/
static void * pUserDataSeenInCallback = NULL;

/**
* @brief Mocked MQTT event callback that records the application-defined
* pUserData pointer from the context, and otherwise behaves exactly like
* eventCallback2.
*/
static bool eventCallbackUserData( MQTTContext_t * pContext,
MQTTPacketInfo_t * pPacketInfo,
MQTTDeserializedInfo_t * pDeserializedInfo,
MQTTSuccessFailReasonCode_t * pReasonCode,
MQTTPropBuilder_t * pSendPropsBuffer,
MQTTPropBuilder_t * pGetPropsBuffer )
{
pUserDataSeenInCallback = pContext->pUserData;

return eventCallback2( pContext, pPacketInfo, pDeserializedInfo,
pReasonCode, pSendPropsBuffer, pGetPropsBuffer );
}

static bool eventCallback3( MQTTContext_t * pContext,
MQTTPacketInfo_t * pPacketInfo,
MQTTDeserializedInfo_t * pDeserializedInfo,
Expand Down Expand Up @@ -1811,6 +1834,65 @@ void test_MQTT_Init_Happy_Path( void )
TEST_ASSERT_EQUAL_MEMORY( &networkBuffer, &context.networkBuffer, sizeof( networkBuffer ) );
}

/**
* @brief Test that MQTT_Init clears pUserData and that the application can
* read it back from the event callback through the context pointer.
*/
void test_MQTT_Init_UserData_AccessibleInEventCallback( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingCallback[ 10 ];
uint8_t ackPropsBuf[ 500 ];
size_t ackPropsBufLength = sizeof( ackPropsBuf );
MQTTPublishInfo_t publishInfo = { 0 };
int userData = 0;

setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );

/* Set pUserData before MQTT_Init to verify that MQTT_Init clears it. */
context.pUserData = &userData;

MQTT_InitConnect_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallbackUserData, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
TEST_ASSERT_NULL( context.pUserData );

/* The application sets its data pointer after MQTT_Init. */
context.pUserData = &userData;

MQTTPropertyBuilder_Init_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingCallback, 10, ackPropsBuf, ackPropsBufLength );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );

MQTTPropBuilder_t ackPropsBuffer;
setupackPropsBuilder( &ackPropsBuffer );
context.ackPropsBuffer = ackPropsBuffer;

context.connectStatus = MQTTConnected;

modifyIncomingPacketStatus = MQTTSuccess;

/* Receive a QoS 1 PUBLISH so that the event callback is invoked. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectParams.incomingPublish = true;
publishInfo.qos = MQTTQoS1;
expectParams.pPubInfo = &publishInfo;
expectParams.willReasonCodeBeSet = true;
expectParams.willSendPropsBeSet = true;
pUserDataSeenInCallback = NULL;
expectProcessLoopCalls( &context, &expectParams );

TEST_ASSERT_EQUAL_PTR( &userData, pUserDataSeenInCallback );
}

/**
* @brief Test that any NULL parameter causes MQTT_Init to return MQTTBadParameter.
*/
Expand Down