1
0
mirror of https://github.com/FreeRTOS/coreMQTT synced 2025-05-13 21:59:40 +08:00
coreMQTT/test/unit-test/core_mqtt_utest.c
Dakshit Babbar 86a5750bb3
Changes for passing the Coverity Static Analysis (#314)
<!--- Title -->

Description
-----------
<!--- Describe your changes in detail. -->
Make required changes for passing the Coverity Static Analysis. Unit
tests are modified for the changes made.

Checklist:
----------
<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
- [x] I have tested my changes. No regression in existing tests.
- [x] I have modified and/or added unit-tests to cover the code changes
in this Pull Request.

Related Issue
-----------
<!-- If any, please provide issue ID. -->
By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.

---------

Co-authored-by: DakshitBabbar <ubuntu@ip-172-31-24-168.ap-south-1.compute.internal>
Co-authored-by: Dakshit Babbar <dakshba@amazon.com>
2025-02-24 14:55:47 +05:30

7468 lines
286 KiB
C

/*
* coreMQTT <DEVELOPMENT BRANCH>
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file core_mqtt_utest.c
* @brief Unit tests for functions in core_mqtt.h.
*/
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "unity.h"
/* Include paths for public enums, structures, and macros. */
#include "core_mqtt.h"
#include "mock_core_mqtt_serializer.h"
#include "mock_core_mqtt_state.h"
#include "core_mqtt_config_defaults.h"
/* Set network context to double pointer to buffer (uint8_t**). */
struct NetworkContext
{
uint8_t ** buffer;
};
/**
* @brief MQTT client identifier.
*/
#define MQTT_CLIENT_IDENTIFIER "testclient"
/**
* @brief A valid starting packet ID per MQTT spec. Start from 1.
*/
#define MQTT_FIRST_VALID_PACKET_ID ( 1 )
/**
* @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 3.1.1 spec.
*/
#define MQTT_PACKET_PINGREQ_SIZE ( 2U )
/**
* @brief A packet type not handled by MQTT_ProcessLoop.
*/
#define MQTT_PACKET_TYPE_INVALID ( 0U )
/**
* @brief Number of milliseconds in a second.
*/
#define MQTT_ONE_SECOND_TO_MS ( 1000U )
/**
* @brief Length of the MQTT network buffer.
*/
#define MQTT_TEST_BUFFER_LENGTH ( 128 )
/**
* @brief Sample keep-alive interval that should be greater than 0.
*/
#define MQTT_SAMPLE_KEEPALIVE_INTERVAL_S ( 1U )
/**
* @brief Length of time spent for single test case with
* multiple iterations spent in the process loop for coverage.
*/
#define MQTT_SAMPLE_PROCESS_LOOP_TIMEOUT_MS ( 1U )
/**
* @brief Zero timeout in the process loop implies one iteration.
*/
#define MQTT_NO_TIMEOUT_MS ( 0U )
/**
* @brief Sample length of remaining serialized data.
*/
#define MQTT_SAMPLE_REMAINING_LENGTH ( 64 )
/**
* @brief Subtract this value from max value of global entry time
* for the timer overflow test.
*/
#define MQTT_OVERFLOW_OFFSET ( 3 )
/**
* @brief The number of times the "getTime()" function is called
* within a single iteration of the #MQTT_ProcessLoop.
*
* This constant is used for the timer overflow test which checks
* that the API can support normal behavior even if the timer
* overflows.
*
* @note Currently, there are 6 calls within a single iteration.
* This can change when the implementation changes which would be
* caught through unit test failure.
*/
#define MQTT_TIMER_CALLS_PER_ITERATION ( 6 )
/**
* @brief Timeout for the timer overflow test.
*/
#define MQTT_TIMER_OVERFLOW_TIMEOUT_MS ( 10 )
/**
* @brief A sample network context that we set to NULL.
*/
#define MQTT_SAMPLE_NETWORK_CONTEXT ( NULL )
/**
* @brief Sample topic filter to subscribe to.
*/
#define MQTT_SAMPLE_TOPIC_FILTER "iot"
/**
* @brief Length of sample topic filter.
*/
#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH ( sizeof( MQTT_SAMPLE_TOPIC_FILTER ) - 1 )
/**
* @brief Sample topic filter to subscribe to.
*/
#define MQTT_SAMPLE_TOPIC_FILTER1 "TopicFilter2"
/**
* @brief Length of sample topic filter.
*/
#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH1 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER1 ) - 1 )
/**
* @brief Sample topic filter to subscribe to.
*/
#define MQTT_SAMPLE_TOPIC_FILTER2 "SomeTopic"
/**
* @brief Length of sample topic filter.
*/
#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH2 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER2 ) - 1 )
/**
* @brief Sample topic filter to subscribe to.
*/
#define MQTT_SAMPLE_TOPIC_FILTER3 "iotTopicFilter"
/**
* @brief Length of sample topic filter.
*/
#define MQTT_SAMPLE_TOPIC_FILTER_LENGTH3 ( sizeof( MQTT_SAMPLE_TOPIC_FILTER3 ) - 1 )
/**
* @brief Return values of mocked calls in MQTT_ProcessLoop(). Used by
* `expectProcessLoopCalls`
*/
typedef struct ProcessLoopReturns
{
MQTTStatus_t deserializeStatus; /**< @brief Status after deserializing incoming packet. */
MQTTPublishState_t stateAfterDeserialize; /**< @brief Publish state after deserializing incoming packet. */
MQTTStatus_t updateStateStatus; /**< @brief Status after updating publish state. */
MQTTStatus_t serializeStatus; /**< @brief Status after serializing a publish ack to send. */
MQTTPublishState_t stateAfterSerialize; /**< @brief Publish state after serializing an ack to send. */
MQTTStatus_t processLoopStatus; /**< @brief Return value of the process loop. */
bool incomingPublish; /**< @brief Whether the incoming packet is a publish. */
MQTTPublishInfo_t * pPubInfo; /**< @brief Publish information to be returned by the deserializer. */
uint32_t timeoutMs; /**< @brief The timeout value to call MQTT_ProcessLoop API with. */
} ProcessLoopReturns_t;
/**
* @brief An opaque structure provided by the library to the #MQTTStorePacketForRetransmit function when using #MQTTStorePacketForRetransmit.
*/
struct MQTTVec
{
TransportOutVector_t * pVector; /**< Pointer to transport vector. USER SHOULD NOT ACCESS THIS DIRECTLY - IT IS AN INTERNAL DETAIL AND CAN CHANGE. */
size_t vectorLen; /**< Length of the transport vector. USER SHOULD NOT ACCESS THIS DIRECTLY - IT IS AN INTERNAL DETAIL AND CAN CHANGE. */
};
/**
* @brief The packet type to be received by the process loop.
* IMPORTANT: Make sure this is set before calling expectProcessLoopCalls(...).
*/
static uint8_t currentPacketType = MQTT_PACKET_TYPE_INVALID;
/**
* @brief The return value of modifyIncomingPacket(...) CMock callback that
* replaces a call to MQTT_GetIncomingPacketTypeAndLength.
* IMPORTANT: Make sure this is set before calling expectProcessLoopCalls(...).
*/
static MQTTStatus_t modifyIncomingPacketStatus = MQTTSuccess;
/**
* @brief Time at the beginning of each test. Note that this is not updated with
* a real clock. Instead, we simply increment this variable.
*/
static uint32_t globalEntryTime = 0;
/**
* @brief A static buffer used by the MQTT library for storing packet data.
*/
static uint8_t mqttBuffer[ MQTT_TEST_BUFFER_LENGTH ] = { 0 };
/**
* @brief A static buffer used by the MQTT library for storing publishes for retransmiting purpose.
*/
static uint8_t * publishCopyBuffer = NULL;
/**
* @brief Size of the publishCopyBuffer array
*/
static size_t publishCopyBufferSize = 0;
/**
* @brief A flag to indicate whether event callback is called from
* MQTT_ProcessLoop.
*/
static bool isEventCallbackInvoked = false;
static bool receiveOnce = false;
static const uint8_t SubscribeHeader[] =
{
MQTT_PACKET_TYPE_SUBSCRIBE, /* Subscribe header. */
0x10, 0x10, /* Packet Length. */
( MQTT_FIRST_VALID_PACKET_ID >> 8 ),
( ( MQTT_FIRST_VALID_PACKET_ID ) & 0x00ffU ) /* Packet ID. */
};
static const size_t SubscribeHeaderLength = 5U;
static const uint8_t UnsubscribeHeader[] =
{
MQTT_PACKET_TYPE_UNSUBSCRIBE, /* Subscribe header. */
0x12, 0x15, /* Packet Length. */
( MQTT_FIRST_VALID_PACKET_ID >> 8 ),
( ( MQTT_FIRST_VALID_PACKET_ID ) & 0x00ffU ) /* Packet ID. */
};
static const size_t UnsubscribeHeaderLength = 5U;
/* ============================ UNITY FIXTURES ============================ */
/* Called before each test method. */
void setUp()
{
memset( mqttBuffer, 0x0, sizeof( mqttBuffer ) );
MQTT_State_strerror_IgnoreAndReturn( "DUMMY_MQTT_STATE" );
globalEntryTime = 0;
}
/* Called after each test method. */
void tearDown()
{
}
/* Called at the beginning of the whole suite. */
void suiteSetUp()
{
receiveOnce = 0;
}
/* Called at the end of the whole suite. */
int suiteTearDown( int numFailures )
{
return numFailures;
}
/* ========================================================================== */
/**
* @brief Mock successful transport send, and write data into buffer for
* verification.
*/
static int32_t mockSend( NetworkContext_t * pNetworkContext,
const void * pMessage,
size_t bytesToSend )
{
const uint8_t * buffer = ( const uint8_t * ) pMessage;
/* Treat network context as pointer to buffer for mocking. */
uint8_t * mockNetwork = *( pNetworkContext->buffer );
size_t bytesSent = 0;
while( bytesSent++ < bytesToSend )
{
/* Write single byte and advance buffer. */
*mockNetwork++ = *buffer++;
}
/* Move stream by bytes sent. */
*( pNetworkContext->buffer ) = mockNetwork;
return bytesToSend;
}
/**
* @brief Initialize pNetworkBuffer using static buffer.
*
* @param[in] pNetworkBuffer Network buffer provided for the context.
*/
static void setupNetworkBuffer( MQTTFixedBuffer_t * const pNetworkBuffer )
{
pNetworkBuffer->pBuffer = mqttBuffer;
pNetworkBuffer->size = MQTT_TEST_BUFFER_LENGTH;
}
/**
* @brief Mocked MQTT event callback.
*
* @param[in] pContext MQTT context pointer.
* @param[in] pPacketInfo Packet Info pointer for the incoming packet.
* @param[in] pDeserializedInfo Deserialized information from the incoming packet.
*/
static void eventCallback( MQTTContext_t * pContext,
MQTTPacketInfo_t * pPacketInfo,
MQTTDeserializedInfo_t * pDeserializedInfo )
{
( void ) pContext;
( void ) pPacketInfo;
( void ) pDeserializedInfo;
/* Update the global state to indicate that event callback is invoked. */
isEventCallbackInvoked = true;
}
/**
* @brief A mocked timer query function that increments on every call. This
* guarantees that only a single iteration runs in the ProcessLoop for ease
* of testing.
*/
static uint32_t getTime( void )
{
return globalEntryTime++;
}
static int32_t getTimeMockCallLimit = -1;
/**
* @brief A mocked timer query function that increments on every call. This
* guarantees that only a single iteration runs in the ProcessLoop for ease
* of testing. Additionally, this tests whether the number of calls to this
* function have exceeded than the set limit and asserts.
*/
static uint32_t getTimeMock( void )
{
TEST_ASSERT_GREATER_THAN_INT32( -1, getTimeMockCallLimit-- );
return globalEntryTime++;
}
static int32_t getTimeMockBigTimeStepCallLimit = -1;
/**
* @brief A mocked timer query function that increments by MQTT_SEND_TIMEOUT_MS
* to simulate the time consumed by a long running high priority task on every
* call. Additionally, this tests whether the number of calls to this function
* have exceeded than the set limit and asserts.
*/
static uint32_t getTimeMockBigTimeStep( void )
{
TEST_ASSERT_GREATER_THAN_INT32( -1, getTimeMockBigTimeStepCallLimit-- );
globalEntryTime += MQTT_SEND_TIMEOUT_MS;
return globalEntryTime;
}
/**
* @brief A mocked timer function that could be used on a device with no system
* time.
*/
static uint32_t getTimeDummy( void )
{
return 0;
}
/**
* @brief Mocked successful transport writev.
*
* @param[in] tcpSocket TCP socket.
* @param[in] pMessage vectors to send
* @param[in] bytesToWrite number of vectors
*
* @return Number of bytes sent; negative value on error;
* 0 for timeout or 0 bytes sent.
*/
static int32_t transportWritevSuccess( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVectorIterator,
size_t vectorsToBeSent )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
int32_t bytesToWrite = 0;
size_t i;
for( i = 0; i < vectorsToBeSent; ++i )
{
bytesToWrite += pIoVectorIterator->iov_len;
pIoVectorIterator++;
}
return bytesToWrite;
}
/**
* @brief Mocked successful publish store function.
*
* @param[in] pContext initialised mqtt context.
* @param[in] packetId packet id
* @param[in] pIoVec array of transportout vectors
* @param[in] ioVecCount number of vectors in the array
*
* @return true if store is successful else false
*/
bool publishStoreCallbackSuccess( struct MQTTContext * pContext,
uint16_t packetId,
MQTTVec_t * pMqttVec )
{
( void ) pContext;
( void ) packetId;
( void ) pMqttVec;
return true;
}
/**
* @brief Mocked failed publish store function.
*
* @param[in] pContext initialised mqtt context.
* @param[in] packetId packet id
* @param[in] pIoVec array of transportout vectors
* @param[in] ioVecCount number of vectors in the array
*
* @return true if store is successful else false
*/
bool publishStoreCallbackFailed( struct MQTTContext * pContext,
uint16_t packetId,
MQTTVec_t * pMqttVec )
{
( void ) pContext;
( void ) packetId;
( void ) pMqttVec;
return false;
}
/**
* @brief Mocked successful publish retrieve function.
*
* @param[in] pContext initialised mqtt context.
* @param[in] packetId packet id
* @param[in] pIoVec array of transportout vectors
* @param[in] ioVecCount number of vectors in the array
*
* @return true if retrieve is successful else false
*/
bool publishRetrieveCallbackSuccess( struct MQTTContext * pContext,
uint16_t packetId,
uint8_t ** pPacket,
size_t * pPacketSize )
{
( void ) pContext;
( void ) packetId;
*pPacket = publishCopyBuffer;
*pPacketSize = publishCopyBufferSize;
return true;
}
/**
* @brief Mocked publish retrieve function. Succeeds once then fails
*
* @param[in] pContext initialised mqtt context.
* @param[in] packetId packet id
* @param[in] pIoVec array of transportout vectors
* @param[in] ioVecCount number of vectors in the array
*
* @return true if retrieve is successful else false
*/
bool publishRetrieveCallbackSuccessThenFail( struct MQTTContext * pContext,
uint16_t packetId,
uint8_t ** pPacket,
size_t * pPacketSize )
{
( void ) pContext;
( void ) packetId;
bool ret = true;
static int count = 0;
*pPacket = publishCopyBuffer;
*pPacketSize = publishCopyBufferSize;
if( count != 0 )
{
count = 0;
ret = false;
}
count++;
return ret;
}
/**
* @brief Mocked failed publish retrieve function.
*
* @param[in] pContext initialised mqtt context.
* @param[in] packetId packet id
* @param[in] pIoVec array of transportout vectors
* @param[in] ioVecCount number of vectors in the array
*
* @return true if retrieve is successful else false
*/
bool publishRetrieveCallbackFailed( struct MQTTContext * pContext,
uint16_t packetId,
uint8_t ** pPacket,
size_t * pPacketSize )
{
( void ) pContext;
( void ) packetId;
( void ) pPacket;
( void ) pPacketSize;
return false;
}
/**
* @brief Mocked publish clear function.
*
* @param[in] pContext initialised mqtt context.
* @param[in] packetId packet id
*
* @return true if clear is successful else false
*/
void publishClearCallback( struct MQTTContext * pContext,
uint16_t packetId )
{
( void ) pContext;
( void ) packetId;
}
static void verifyEncodedTopicString( TransportOutVector_t * pIoVectorIterator,
char * pTopicFilter,
size_t topicFilterLength,
MQTTQoS_t topicQos,
int32_t * pBytesToWrite )
{
/* Encoded topic length. */
uint8_t serializedLength[ 2 ];
const uint8_t * buffer;
size_t length;
serializedLength[ 0 ] = ( uint8_t ) ( topicFilterLength >> 8 );
serializedLength[ 1 ] = ( uint8_t ) ( topicFilterLength & 0x00ffU );
buffer = pIoVectorIterator[ 0 ].iov_base;
length = pIoVectorIterator[ 0 ].iov_len;
TEST_ASSERT_EQUAL( 2U, length );
TEST_ASSERT_EQUAL_UINT8_ARRAY( serializedLength, buffer, 2U );
( *pBytesToWrite ) += length;
buffer = pIoVectorIterator[ 1 ].iov_base;
length = pIoVectorIterator[ 1 ].iov_len;
/* Encoded topic string. */
TEST_ASSERT_EQUAL( topicFilterLength, length );
TEST_ASSERT_EQUAL_UINT8_ARRAY( pTopicFilter, buffer, topicFilterLength );
( *pBytesToWrite ) += length;
buffer = pIoVectorIterator[ 2 ].iov_base;
length = pIoVectorIterator[ 2 ].iov_len;
/* Encoded QoS. */
TEST_ASSERT_EQUAL( 1U, length );
TEST_ASSERT_EQUAL_UINT8( topicQos, *buffer );
( *pBytesToWrite ) += length;
}
static void verifyEncodedTopicStringUnsubscribe( TransportOutVector_t * pIoVectorIterator,
char * pTopicFilter,
size_t topicFilterLength,
int32_t * pBytesToWrite )
{
/* Encoded topic length. */
uint8_t serializedLength[ 2 ];
const uint8_t * buffer;
size_t length;
serializedLength[ 0 ] = ( uint8_t ) ( topicFilterLength >> 8 );
serializedLength[ 1 ] = ( uint8_t ) ( topicFilterLength & 0x00ffU );
buffer = pIoVectorIterator[ 0 ].iov_base;
length = pIoVectorIterator[ 0 ].iov_len;
TEST_ASSERT_EQUAL( 2U, length );
TEST_ASSERT_EQUAL_UINT8_ARRAY( serializedLength, buffer, 2U );
( *pBytesToWrite ) += length;
buffer = pIoVectorIterator[ 1 ].iov_base;
length = pIoVectorIterator[ 1 ].iov_len;
/* Encoded topic string. */
TEST_ASSERT_EQUAL( topicFilterLength, length );
TEST_ASSERT_EQUAL_UINT8_ARRAY( pTopicFilter, buffer, topicFilterLength );
( *pBytesToWrite ) += length;
}
/**
* @brief Mocked transport writev to verify correct subscription
* packet.
*
* @param[in] tcpSocket TCP socket.
* @param[in] pMessage vectors to send
* @param[in] bytesToWrite number of vectors
*
* @return Number of bytes sent; negative value on error;
* 0 for timeout or 0 bytes sent.
*/
static int32_t transportWritevSubscribeSuccess( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVectorIterator,
size_t vectorsToBeSent )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
int32_t bytesToWrite = 0;
static int writeCount = 0;
const uint8_t * buffer;
size_t length;
/* The header. */
if( writeCount == 0 )
{
TEST_ASSERT_EQUAL( 4, vectorsToBeSent );
buffer = pIoVectorIterator->iov_base;
length = pIoVectorIterator->iov_len;
TEST_ASSERT_EQUAL( length, SubscribeHeaderLength );
TEST_ASSERT_EQUAL_UINT8_ARRAY( ( uint8_t * ) SubscribeHeader, buffer, SubscribeHeaderLength );
bytesToWrite += length;
pIoVectorIterator++;
/* First topic filter. */
verifyEncodedTopicString( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
MQTTQoS1,
&bytesToWrite );
writeCount++;
pIoVectorIterator += 4;
}
else if( writeCount == 1 )
{
TEST_ASSERT_EQUAL( 6, vectorsToBeSent );
/* Second topic filter. */
verifyEncodedTopicString( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER1,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH1,
MQTTQoS2,
&bytesToWrite );
pIoVectorIterator += 3;
/* Third topic filter. */
verifyEncodedTopicString( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER2,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH2,
MQTTQoS0,
&bytesToWrite );
writeCount++;
}
else if( writeCount == 2 )
{
TEST_ASSERT_EQUAL( 3, vectorsToBeSent );
/* Fourth topic filter. */
verifyEncodedTopicString( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER3,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH3,
MQTTQoS1,
&bytesToWrite );
writeCount++;
}
else
{
bytesToWrite = -1;
}
return bytesToWrite;
}
/**
* @brief Mocked transport writev to verify correct subscription
* packet.
*
* @param[in] tcpSocket TCP socket.
* @param[in] pMessage vectors to send
* @param[in] bytesToWrite number of vectors
*
* @return Number of bytes sent; negative value on error;
* 0 for timeout or 0 bytes sent.
*/
static int32_t transportWritevUnsubscribeSuccess( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVectorIterator,
size_t vectorsToBeSent )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
int32_t bytesToWrite = 0;
static int writeCount = 0;
const uint8_t * buffer;
size_t length;
/* The header. */
if( writeCount == 0 )
{
TEST_ASSERT_EQUAL( 5, vectorsToBeSent );
buffer = pIoVectorIterator->iov_base;
length = pIoVectorIterator->iov_len;
TEST_ASSERT_EQUAL( length, UnsubscribeHeaderLength );
TEST_ASSERT_EQUAL_UINT8_ARRAY( ( uint8_t * ) UnsubscribeHeader, buffer, UnsubscribeHeaderLength );
bytesToWrite += length;
pIoVectorIterator++;
/* First topic filter. */
verifyEncodedTopicStringUnsubscribe( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
&bytesToWrite );
pIoVectorIterator += 2;
/* Second topic filter. */
verifyEncodedTopicStringUnsubscribe( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER1,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH1,
&bytesToWrite );
writeCount++;
}
else if( writeCount == 1 )
{
TEST_ASSERT_EQUAL( 4, vectorsToBeSent );
/* Third topic filter. */
verifyEncodedTopicStringUnsubscribe( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER2,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH2,
&bytesToWrite );
pIoVectorIterator += 2;
/* Fourth topic filter. */
verifyEncodedTopicStringUnsubscribe( pIoVectorIterator,
MQTT_SAMPLE_TOPIC_FILTER3,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH3,
&bytesToWrite );
writeCount++;
}
else
{
bytesToWrite = -1;
}
return bytesToWrite;
}
/**
* @brief Mocked failed transport writev.
*
* @param[in] tcpSocket TCP socket.
* @param[in] pMessage vectors to send
* @param[in] bytesToWrite number of vectors
*
* @return Number of bytes sent; negative value on error;
* 0 for timeout or 0 bytes sent.
*/
static int32_t transportWritevFail( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVectorIterator,
size_t vectorsToBeSent )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
int32_t bytesToWrite = 0;
size_t i;
for( i = 0; i < vectorsToBeSent; ++i )
{
bytesToWrite += pIoVectorIterator->iov_len;
pIoVectorIterator++;
}
return bytesToWrite + 3;
}
static int32_t transportWritevError( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVectorIterator,
size_t vectorsToBeSent )
{
( void ) vectorsToBeSent;
( void ) pIoVectorIterator;
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
return -1;
}
/**
* @brief Mocked successful transport send.
*
* @param[in] tcpSocket TCP socket.
* @param[in] pMessage Data to send.
* @param[in] bytesToWrite Length of data to send.
*
* @return Number of bytes sent; negative value on error;
* 0 for timeout or 0 bytes sent.
*/
static int32_t transportSendSuccess( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToWrite )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
( void ) pBuffer;
return bytesToWrite;
}
/**
* @brief Mocked failed transport send.
*/
static int32_t transportSendFailure( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToWrite )
{
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToWrite;
return -1;
}
/**
* @brief Mocked transport send that always returns 0 bytes sent.
*/
static int32_t transportSendNoBytes( NetworkContext_t * pNetworkContext,
const void * pBuffer,
size_t bytesToWrite )
{
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToWrite;
return 0;
}
/**
* @brief Mocked transport send that succeeds then fails.
*/
static int32_t transportSendSucceedThenFail( NetworkContext_t * pNetworkContext,
const void * pMessage,
size_t bytesToSend )
{
int32_t retVal = bytesToSend;
static int counter = 0;
( void ) pNetworkContext;
( void ) pMessage;
if( counter++ )
{
retVal = -1;
counter = 0;
}
return retVal;
}
/**
* @brief Mocked transport send that succeeds when sending connect then fails after that.
*/
static int32_t transportSendSucceedThenFailAfterConnect( NetworkContext_t * pNetworkContext,
const void * pMessage,
size_t bytesToSend )
{
int32_t retVal = bytesToSend;
static int counter = 0;
( void ) pNetworkContext;
( void ) pMessage;
counter++;
if( counter == 3 )
{
retVal = -1;
counter = 0;
}
return retVal;
}
/**
* @brief Mocked transport send that only sends half of the bytes.
*/
static int32_t transportWritevPartialByte( NetworkContext_t * pNetworkContext,
TransportOutVector_t * pIoVectorIterator,
size_t vectorsToBeSent )
{
int32_t bytesToWrite = 0;
size_t i;
( void ) pNetworkContext;
for( i = 0; i < vectorsToBeSent; ++i )
{
bytesToWrite += pIoVectorIterator->iov_len;
pIoVectorIterator++;
}
if( bytesToWrite > 1 )
{
bytesToWrite /= 2;
}
return bytesToWrite;
}
/**
* @brief Mocked successful transport read.
*
* @param[in] tcpSocket TCP socket.
* @param[out] pBuffer Buffer for receiving data.
* @param[in] bytesToRead Size of pBuffer.
*
* @return Number of bytes received; negative value on error.
*/
static int32_t transportRecvSuccess( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRead )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
( void ) pBuffer;
return bytesToRead;
}
static int32_t transportRecvOneSuccessOneFail( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRead )
{
TEST_ASSERT_EQUAL( MQTT_SAMPLE_NETWORK_CONTEXT, pNetworkContext );
( void ) pBuffer;
if( receiveOnce == false )
{
receiveOnce = true;
return bytesToRead;
}
else
{
return -1;
}
}
/**
* @brief Mocked failed transport read.
*/
static int32_t transportRecvFailure( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRead )
{
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToRead;
return -1;
}
/**
* @brief Mocked transport reading one byte at a time.
*/
static int32_t transportRecvOneByte( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRead )
{
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToRead;
return 1;
}
/**
* @brief Mocked transport returning zero bytes to simulate reception
* of no data over network.
*/
static int32_t transportRecvNoData( NetworkContext_t * pNetworkContext,
void * pBuffer,
size_t bytesToRead )
{
( void ) pNetworkContext;
( void ) pBuffer;
( void ) bytesToRead;
return 0;
}
/**
* @brief Initialize the transport interface with the mocked functions for
* send and receive.
*
* @brief param[in] pTransport The transport interface to use with the context.
*/
static void setupTransportInterface( TransportInterface_t * pTransport )
{
pTransport->pNetworkContext = MQTT_SAMPLE_NETWORK_CONTEXT;
pTransport->send = transportSendSuccess;
pTransport->recv = transportRecvSuccess;
pTransport->writev = transportWritevSuccess;
}
/**
* @brief Initialize pSubscribeInfo using test-defined macros.
*
* @param[in] pSubscribeInfo Pointer to MQTT subscription info.
*/
static void setupSubscriptionInfo( MQTTSubscribeInfo_t * pSubscribeInfo )
{
pSubscribeInfo->qos = MQTTQoS1;
pSubscribeInfo->pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
pSubscribeInfo->topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
}
/**
* @brief Zero out a #ProcessLoopReturns_t.
*
* @param[in] pExpectParams Pointer to struct to reset.
*/
static void resetProcessLoopParams( ProcessLoopReturns_t * pExpectParams )
{
pExpectParams->deserializeStatus = MQTTSuccess;
pExpectParams->stateAfterDeserialize = MQTTStateNull;
pExpectParams->updateStateStatus = MQTTSuccess;
pExpectParams->serializeStatus = MQTTSuccess;
pExpectParams->stateAfterSerialize = MQTTStateNull;
pExpectParams->processLoopStatus = MQTTSuccess;
pExpectParams->incomingPublish = false;
pExpectParams->pPubInfo = NULL;
pExpectParams->timeoutMs = MQTT_NO_TIMEOUT_MS;
}
/**
* @brief create default context
*
* @param[out] context to initialize
*/
static void setUPContext( MQTTContext_t * mqttContext )
{
MQTTStatus_t mqttStatus;
static TransportInterface_t transport = { 0 };
static MQTTFixedBuffer_t networkBuffer = { 0 };
static MQTTPubAckInfo_t incomingRecords[ 10 ] = { 0 };
static MQTTPubAckInfo_t outgoingRecords[ 10 ] = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( mqttContext, 0x0, sizeof( MQTTContext_t ) );
mqttStatus = MQTT_Init( mqttContext,
&transport,
getTime,
eventCallback,
&networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( mqttContext,
outgoingRecords,
10,
incomingRecords,
10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This helper function is used to expect any calls from the process loop
* to mocked functions belonging to an external header file. Its parameters
* are used to provide return values for these mocked functions.
*/
static void expectProcessLoopCalls( MQTTContext_t * const pContext,
ProcessLoopReturns_t * pExpectParams )
{
MQTTStatus_t mqttStatus = MQTTSuccess;
MQTTPacketInfo_t incomingPacket = { 0 };
size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
bool expectMoreCalls = true;
/* Copy values passed in the parameter struct. */
MQTTStatus_t deserializeStatus = pExpectParams->deserializeStatus;
MQTTPublishState_t stateAfterDeserialize = pExpectParams->stateAfterDeserialize;
MQTTStatus_t updateStateStatus = pExpectParams->updateStateStatus;
MQTTStatus_t serializeStatus = pExpectParams->serializeStatus;
MQTTPublishState_t stateAfterSerialize = pExpectParams->stateAfterSerialize;
MQTTStatus_t processLoopStatus = pExpectParams->processLoopStatus;
bool incomingPublish = pExpectParams->incomingPublish;
MQTTPublishInfo_t * pPubInfo = pExpectParams->pPubInfo;
uint32_t packetTxTimeoutMs = 0U;
/* Modify incoming packet depending on type to be tested. */
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* More calls are expected only with the following packet types. */
if( ( currentPacketType != MQTT_PACKET_TYPE_PUBLISH ) &&
( currentPacketType != MQTT_PACKET_TYPE_PUBACK ) &&
( currentPacketType != MQTT_PACKET_TYPE_PUBREC ) &&
( currentPacketType != MQTT_PACKET_TYPE_PUBREL ) &&
( currentPacketType != MQTT_PACKET_TYPE_PUBCOMP ) &&
( currentPacketType != MQTT_PACKET_TYPE_PINGRESP ) &&
( currentPacketType != MQTT_PACKET_TYPE_SUBACK ) &&
( currentPacketType != MQTT_PACKET_TYPE_UNSUBACK ) )
{
expectMoreCalls = false;
}
/* When no data is available, the process loop tries to send a PINGREQ. */
if( modifyIncomingPacketStatus == MQTTNoDataAvailable )
{
packetTxTimeoutMs = 1000U * ( uint32_t ) pContext->keepAliveIntervalSec;
if( PACKET_TX_TIMEOUT_MS < packetTxTimeoutMs )
{
packetTxTimeoutMs = PACKET_TX_TIMEOUT_MS;
}
if( pContext->waitingForPingResp == false )
{
if( ( ( packetTxTimeoutMs != 0U ) &&
( ( globalEntryTime - pContext->lastPacketTxTime ) >= packetTxTimeoutMs ) ) ||
( ( PACKET_RX_TIMEOUT_MS != 0U ) &&
( ( globalEntryTime - pContext->lastPacketRxTime ) >= PACKET_RX_TIMEOUT_MS ) ) )
{
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Replace pointer parameter being passed to the method. */
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( serializeStatus );
}
}
expectMoreCalls = false;
}
/* Deserialize based on the packet type (PUB or ACK) being received. */
if( expectMoreCalls )
{
if( incomingPublish )
{
MQTT_DeserializePublish_ExpectAnyArgsAndReturn( deserializeStatus );
if( pPubInfo != NULL )
{
MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( pPubInfo );
}
}
else
{
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( deserializeStatus );
}
if( ( deserializeStatus != MQTTSuccess ) ||
( currentPacketType == MQTT_PACKET_TYPE_PINGRESP ) ||
( currentPacketType == MQTT_PACKET_TYPE_SUBACK ) ||
( currentPacketType == MQTT_PACKET_TYPE_UNSUBACK ) )
{
expectMoreCalls = false;
}
}
/* Update state based on the packet type (PUB or ACK) being received. */
if( expectMoreCalls )
{
if( incomingPublish )
{
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( updateStateStatus );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &stateAfterDeserialize );
}
else
{
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( updateStateStatus );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterDeserialize );
}
if( stateAfterDeserialize == MQTTPublishDone )
{
expectMoreCalls = false;
}
else
{
switch( updateStateStatus )
{
case MQTTSuccess:
expectMoreCalls = true;
break;
case MQTTStateCollision:
/* Execution will continue regardless of the dup flag. */
expectMoreCalls = true;
MQTT_CalculateStatePublish_ExpectAnyArgsAndReturn( stateAfterDeserialize );
break;
default:
expectMoreCalls = false;
}
}
}
/* Serialize the packet to be sent in response to the received packet. */
if( expectMoreCalls )
{
MQTT_SerializeAck_ExpectAnyArgsAndReturn( serializeStatus );
if( serializeStatus != MQTTSuccess )
{
expectMoreCalls = false;
}
}
if( expectMoreCalls && ( pContext->connectStatus != MQTTConnected ) )
{
expectMoreCalls = false;
}
/* Update the state based on the sent packet. */
if( expectMoreCalls )
{
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( ( stateAfterSerialize == MQTTStateNull ) ?
MQTTIllegalState : MQTTSuccess );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &stateAfterSerialize );
}
/* Expect the above calls when running MQTT_ProcessLoop. */
mqttStatus = MQTT_ProcessLoop( pContext );
TEST_ASSERT_EQUAL( processLoopStatus, mqttStatus );
/* Any final assertions to end the test. */
if( mqttStatus == MQTTSuccess )
{
if( currentPacketType == MQTT_PACKET_TYPE_PUBLISH )
{
TEST_ASSERT_TRUE( pContext->controlPacketSent );
}
if( currentPacketType == MQTT_PACKET_TYPE_PINGRESP )
{
TEST_ASSERT_FALSE( pContext->waitingForPingResp );
}
}
}
/* ========================================================================== */
/**
* @brief Test that MQTT_Init is able to update the context object correctly.
*/
void test_MQTT_Init_Happy_Path( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
TEST_ASSERT_EQUAL( MQTTNotConnected, context.connectStatus );
TEST_ASSERT_EQUAL( MQTT_FIRST_VALID_PACKET_ID, context.nextPacketId );
TEST_ASSERT_EQUAL_PTR( getTime, context.getTime );
TEST_ASSERT_EQUAL_PTR( eventCallback, context.appCallback );
/* These Unity assertions take pointers and compare their contents. */
TEST_ASSERT_EQUAL_MEMORY( &transport, &context.transportInterface, sizeof( transport ) );
TEST_ASSERT_EQUAL_MEMORY( &networkBuffer, &context.networkBuffer, sizeof( networkBuffer ) );
}
/**
* @brief Test that any NULL parameter causes MQTT_Init to return MQTTBadParameter.
*/
void test_MQTT_Init_Invalid_Params( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
/* Check that MQTTBadParameter is returned if any NULL parameters are passed. */
mqttStatus = MQTT_Init( NULL, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
mqttStatus = MQTT_Init( &context, NULL, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Test if NULL is passed for any of the function pointers. */
mqttStatus = MQTT_Init( &context, &transport, NULL, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
mqttStatus = MQTT_Init( &context, &transport, getTime, NULL, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
transport.recv = NULL;
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
transport.recv = transportRecvSuccess;
transport.send = NULL;
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
/**
* @brief Test that NULL parameter causes MQTT_CheckConnectStatus to return MQTTBadParameter.
*/
void test_MQTT_CheckConnectStatus_invalid_params( void )
{
MQTTStatus_t mqttStatus = { 0 };
mqttStatus = MQTT_CheckConnectStatus( NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/**
* @brief Test that MQTT_CheckConnectStatus returns correct status corresponding to the connection status.
*/
void test_MQTT_CheckConnectStatus_return_correct_status( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
context.connectStatus = MQTTConnected;
mqttStatus = MQTT_CheckConnectStatus( &context );
TEST_ASSERT_EQUAL( MQTTStatusConnected, mqttStatus );
context.connectStatus = MQTTNotConnected;
mqttStatus = MQTT_CheckConnectStatus( &context );
TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
context.connectStatus = MQTTDisconnectPending;
mqttStatus = MQTT_CheckConnectStatus( &context );
TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
}
/* ========================================================================== */
/**
* @brief Test that any NULL parameter causes MQTT_InitRetransmits to return MQTTBadParameter.
*/
void test_MQTT_InitRetransmits_Invalid_Params( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
/* Check that MQTTBadParameter is returned if any NULL parameters are passed. */
mqttStatus = MQTT_InitRetransmits( NULL, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
mqttStatus = MQTT_InitRetransmits( &context, NULL,
publishRetrieveCallbackSuccess,
publishClearCallback );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
mqttStatus = MQTT_InitRetransmits( &context, publishStoreCallbackSuccess,
NULL,
publishClearCallback );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
mqttStatus = MQTT_InitRetransmits( &context, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
static uint8_t * MQTT_SerializeConnectFixedHeader_cb( uint8_t * pIndex,
const MQTTConnectInfo_t * pConnectInfo,
const MQTTPublishInfo_t * pWillInfo,
size_t remainingLength,
int numcallbacks )
{
( void ) pConnectInfo;
( void ) pWillInfo;
( void ) remainingLength;
( void ) numcallbacks;
return pIndex;
}
/**
* @brief Test MQTT_Connect, when the status is already MQTTConnected.
*/
void test_MQTT_Connect_sendConnect_already_connected( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* set MQTT Connection status as connected*/
mqttContext.connectStatus = MQTTConnected;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTStatusConnected, status );
}
/**
* @brief Test MQTT_Connect, when the status is MQTTDisconnectPending.
*/
void test_MQTT_Connect_sendConnect_disconnect_pending( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* set MQTT Connection status as connected*/
mqttContext.connectStatus = MQTTDisconnectPending;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTStatusDisconnectPending, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect_writev_error( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
setupTransportInterface( &transport );
transport.writev = transportWritevError;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test network send failure from timeout in calling transport send. */
mqttContext.transportInterface.send = transportSendNoBytes; /* Use mock send that always returns zero bytes. */
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect1( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test network send failure from timeout in calling transport send. */
mqttContext.transportInterface.send = transportSendNoBytes; /* Use mock send that always returns zero bytes. */
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_WillInfoWrong( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0, sizeof( MQTTPublishInfo_t ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test network send failure from timeout in calling transport send. */
mqttContext.transportInterface.send = transportSendNoBytes; /* Use mock send that always returns zero bytes. */
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect2( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
/* Choose 10 bytes variable header + 1 byte payload for the remaining
* length of the CONNECT. The packet size needs to be nonzero for this test
* as that is the amount of bytes used in the call to send the packet. */
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
mqttContext.transportInterface.writev = NULL;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_ProperWIllInfo( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0, sizeof( MQTTPublishInfo_t ) );
willInfo.pTopicName = "MQTTTopic";
willInfo.topicNameLength = strlen( willInfo.pTopicName );
willInfo.pPayload = "MQTTPayload";
willInfo.payloadLength = strlen( willInfo.pPayload );
connectInfo.pUserName = "MQTTUser";
connectInfo.userNameLength = strlen( connectInfo.pUserName );
connectInfo.pPassword = "NotSafePassword";
connectInfo.passwordLength = strlen( connectInfo.pPassword );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
/* Choose 10 bytes variable header + 1 byte payload for the remaining
* length of the CONNECT. The packet size needs to be nonzero for this test
* as that is the amount of bytes used in the call to send the packet. */
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test MQTT_Connect, with no payload in will message.
*/
void test_MQTT_Connect_ProperWIllInfoWithNoPayload( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0, sizeof( MQTTPublishInfo_t ) );
willInfo.pTopicName = "MQTTTopic";
willInfo.topicNameLength = strlen( willInfo.pTopicName );
connectInfo.pUserName = "MQTTUser";
connectInfo.userNameLength = strlen( connectInfo.pUserName );
connectInfo.pPassword = "NotSafePassword";
connectInfo.passwordLength = strlen( connectInfo.pPassword );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
/* Choose 10 bytes variable header + 1 byte payload for the remaining
* length of the CONNECT. The packet size needs to be nonzero for this test
* as that is the amount of bytes used in the call to send the packet. */
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test MQTT_Connect, with payload in will message but the length is
* zero.
*/
void test_MQTT_Connect_ProperWIllInfoWithPayloadButZeroLength( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
MQTTPublishInfo_t willInfo;
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0, sizeof( MQTTPublishInfo_t ) );
willInfo.pTopicName = "MQTTTopic";
willInfo.topicNameLength = strlen( willInfo.pTopicName );
willInfo.pPayload = "Payload";
willInfo.payloadLength = 0;
connectInfo.pUserName = "MQTTUser";
connectInfo.userNameLength = strlen( connectInfo.pUserName );
connectInfo.pPassword = "NotSafePassword";
connectInfo.passwordLength = strlen( connectInfo.pPassword );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Transport send failed when sending CONNECT. */
/* Choose 10 bytes variable header + 1 byte payload for the remaining
* length of the CONNECT. The packet size needs to be nonzero for this test
* as that is the amount of bytes used in the call to send the packet. */
packetSize = 13;
remainingLength = 11;
mqttContext.transportInterface.send = transportSendFailure;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreArg_pPacketSize();
MQTT_GetConnectPacketSize_IgnoreArg_pRemainingLength();
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect3( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Empty connect info fails. */
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
memset( &connectInfo, 0x0, sizeof( connectInfo ) );
status = MQTT_Connect( &mqttContext,
&connectInfo,
NULL,
timeout,
&sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect4( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Check parameters */
status = MQTT_Connect( NULL, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
status = MQTT_Connect( &mqttContext, NULL, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect5( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t remainingLength;
size_t packetSize;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Send the CONNECT successfully. This provides branch coverage for sendPacket. */
mqttContext.transportInterface.send = transportSendSuccess;
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetConnectPacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
/* We know the send was successful if MQTT_GetIncomingPacketTypeAndLength()
* is called. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTRecvFailed );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
}
/**
* @brief Test MQTT_Connect, except for receiving the CONNACK.
*/
void test_MQTT_Connect_sendConnect6( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
connectInfo.pClientIdentifier = MQTT_CLIENT_IDENTIFIER;
connectInfo.clientIdentifierLength = sizeof( MQTT_CLIENT_IDENTIFIER ) - 1;
MQTT_GetConnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( 2 );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
}
/**
* @brief Test CONNACK reception in MQTT_Connect.
*/
void test_MQTT_Connect_receiveConnack( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 0;
bool sessionPresent, sessionPresentExpected;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.recv = transportRecvFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Everything before receiving the CONNACK should succeed. */
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Nothing received from transport interface. Set timeout to 2 for branch coverage. */
timeout = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTNoDataAvailable, status );
/* Did not receive a CONNACK. */
incomingPacket.type = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.remainingLength = 0;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
/* Transport receive failure when receiving rest of packet. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
timeout = 2;
mqttContext.transportInterface.recv = transportRecvFailure;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Bad response when deserializing CONNACK. */
mqttContext.transportInterface.recv = transportRecvSuccess;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
/* Test case when broker sends session present flag in response to a
* clean session connection request. */
mqttContext.transportInterface.recv = transportRecvSuccess;
connectInfo.cleanSession = true;
sessionPresentExpected = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
}
/**
* @brief Test CONNACK reception in MQTT_Connect.
*/
void test_MQTT_Connect_receiveConnack_retries( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
/* Same set of tests with retries. MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT is 2*/
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.recv = transportRecvFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Everything before receiving the CONNACK should succeed. */
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
/* Test with retries. MQTT_MAX_CONNACK_RECEIVE_RETRY_COUNT is 2.
* Nothing received from transport interface. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
/* 2 retries. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTNoDataAvailable, status );
/* Did not receive a CONNACK. */
incomingPacket.type = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.remainingLength = 0;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
/* Transport receive failure when receiving rest of packet. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Bad response when deserializing CONNACK. */
mqttContext.transportInterface.recv = transportRecvSuccess;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTBadResponse );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadResponse, status );
}
/**
* @brief Test error cases for MQTT_Connect when a timeout occurs or the packet
* needs to be discarded in MQTT_Connect.
*/
void test_MQTT_Connect_partial_receive( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 0;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.recv = transportRecvNoData;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Everything before receiving the CONNACK should succeed. */
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
/* Timeout in receiving entire packet, for branch coverage. This is due to the fact that the mocked
* receive function always returns 0 bytes read. */
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Update to use mock receive function that receives one byte at a time for the
* rest of the test. */
mqttContext.transportInterface.recv = transportRecvOneByte;
timeout = 10;
/* Not enough space for packet, discard it. */
mqttContext.networkBuffer.size = 2;
incomingPacket.remainingLength = 3;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTNoDataAvailable, status );
/* Discard packet, no timeout provided. This should fail since multiple
* iterations of the discard loop are required to discard the packet, but only
* one will run. */
mqttContext.transportInterface.recv = transportRecvSuccess;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Timeout while discarding packet. */
/* (Mocked) read only one byte at a time to ensure timeout will occur. */
mqttContext.transportInterface.recv = transportRecvOneByte;
incomingPacket.remainingLength = 20;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
/* Receive failure while discarding packet. */
mqttContext.transportInterface.recv = transportRecvFailure;
/* Test with dummy get time function to make sure there are no infinite loops. */
mqttContext.getTime = getTimeDummy;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, MQTT_NO_TIMEOUT_MS, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTRecvFailed, status );
}
/**
* @brief Test resend of pending acks in MQTT_Connect.
*/
void test_MQTT_Connect_resendPendingAcks( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent, sessionPresentResult;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
uint16_t packetIdentifier = 1;
MQTTPublishState_t pubRelState = MQTTPubRelSend;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
/* Test 1. No packets to resend reestablishing a session. */
/* successful receive CONNACK packet. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Return with a session present flag. */
sessionPresent = true;
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* No packets to resend. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_TRUE( sessionPresentResult );
/* Test 2. One packet found in ack pending state, but Sending ack failed. */
sessionPresentResult = false;
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack failure. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTBadParameter );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
/* Test 3. One packet found in ack pending state, but Transport Send failed. */
sessionPresentResult = false;
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
mqttContext.transportInterface.send = transportSendFailure;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
mqttContext.transportInterface.send = transportSendSuccess;
/* Test 4. One packet found in ack pending state, Sent
* PUBREL successfully. */
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack successful. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Query for any remaining packets pending to ack. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
/* Test 5. Three packets found in ack pending state. Sent PUBREL successfully
* for first and failed for second and no attempt for third. */
mqttContext.keepAliveIntervalSec = 0;
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* First packet. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack successful. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Second packet. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier + 1 );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack failed. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTBadParameter );
/* Query for any remaining packets pending to ack. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier + 2 );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
/* Test 6. Two packets found in ack pending state. Sent PUBREL successfully
* for first and failed for second. */
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* First packet. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack successful. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Second packet. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( packetIdentifier + 1 );
MQTT_PubrelToResend_ReturnThruPtr_pState( &pubRelState );
/* Serialize Ack successful. */
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Query for any remaining packets pending to ack. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_ID_INVALID );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
}
/**
* @brief Test resend of publshes in MQTT_Connect.
*/
void test_MQTT_Connect_resendUnAckedPublishes( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent, sessionPresentResult;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
/* Test 1. Connecting with a clean session. Clear all callback successfully executes */
/* successful receive CONNACK packet. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Return with a session present flag. */
sessionPresent = false;
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( 1 );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_FALSE( sessionPresentResult );
}
void test_MQTT_Connect_resendUnAckedPublishes2( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent, sessionPresentResult;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
mqttContext.clearFunction = publishClearCallback;
/* Test 3. No publishes to resend reestablishing a session. */
/* successful receive CONNACK packet. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Return with a session present flag. */
sessionPresent = true;
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
/* No acks to resend. */
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
/* No publishes to resend. */
MQTT_PublishToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_TRUE( sessionPresentResult );
}
void test_MQTT_Connect_resendUnAckedPublishes3( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent, sessionPresentResult;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
uint16_t packetIdentifier = 1;
/* MQTTPublishState_t pubRelState = MQTTPubRelSend; */
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
/* MQTTPublishState_t expectedState = { 0 }; */
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
/* Test 4. One publish packet found to resend, but retrieve failed. */
sessionPresentResult = false;
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
sessionPresent = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
mqttContext.retrieveFunction = publishRetrieveCallbackFailed;
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTPublishRetrieveFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
}
void test_MQTT_Connect_resendUnAckedPublishes4( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent, sessionPresentResult;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
uint16_t packetIdentifier = 1;
/* MQTTPublishState_t pubRelState = MQTTPubRelSend; */
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
/* MQTTPublishState_t expectedState = { 0 }; */
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
mqttContext.retrieveFunction = publishRetrieveCallbackSuccess;
/* Test 5. One publish packet found to resend, but Transport Send failed. */
sessionPresentResult = false;
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
mqttContext.transportInterface.writev = NULL;
mqttContext.transportInterface.send = transportSendSucceedThenFailAfterConnect;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
sessionPresent = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresentResult );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
TEST_ASSERT_TRUE( sessionPresentResult );
}
void test_MQTT_Connect_resendUnAckedPublishes5( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
uint16_t packetIdentifier = 1;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &connectInfo, 0x00, sizeof( connectInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
mqttContext.transportInterface.send = transportSendSuccess;
/* Test 6. One publish packet found to resend, Sent successfully. */
mqttContext.connectStatus = MQTTNotConnected;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
sessionPresent = true;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
MQTT_PublishToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
/* Query for any remaining packets pending to ack. */
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
}
void test_MQTT_Connect_resendUnAckedPublishes6( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
uint16_t packetIdentifier = 1;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
uint8_t * localPublishCopyBuffer = ( uint8_t * ) "Hello world!";
publishCopyBuffer = localPublishCopyBuffer;
publishCopyBufferSize = sizeof( "Hello world!" );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccessThenFail,
publishClearCallback );
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
/* Test 7. Two publish packets found to resend. Sent successfully
* for first and failed for second. */
mqttContext.keepAliveIntervalSec = 0;
mqttContext.connectStatus = MQTTNotConnected;
sessionPresent = true;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresent );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
/* First packet. */
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier );
/* Second packet. */
MQTT_PublishToResend_ExpectAnyArgsAndReturn( packetIdentifier + 1 );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTPublishRetrieveFailed, status );
TEST_ASSERT_EQUAL_INT( MQTTDisconnectPending, mqttContext.connectStatus );
}
/**
* @brief Test success case for MQTT_Connect().
*/
#define MQTT_STATE_ARRAY_MAX_COUNT 1
void test_MQTT_Connect_happy_path1()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
bool sessionPresent;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* CONNACK receive with timeoutMs=0. Retry logic will be used. */
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
sessionPresent = false;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_FALSE( mqttContext.waitingForPingResp );
}
/**
* @brief Test success case for MQTT_Connect().
*/
void test_MQTT_Connect_happy_path2()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent = false;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
connectInfo.keepAliveSeconds = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
/* Success. */
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
}
/**
* @brief Test success case for MQTT_Connect().
*/
void test_MQTT_Connect_happy_path3()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
MQTTPublishInfo_t willInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent = false;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &willInfo, 0x0, sizeof( MQTTPublishInfo_t ) );
memset( &connectInfo, 0x0, sizeof( MQTTConnectInfo_t ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* With non-NULL Will. */
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
willInfo.pTopicName = "test";
willInfo.topicNameLength = 4;
willInfo.pPayload = "Payload";
willInfo.payloadLength = 7;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, &willInfo, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
}
/**
* @brief Test success case for MQTT_Connect().
*/
void test_MQTT_Connect_happy_path4()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent;
bool sessionPresentExpected;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPubAckInfo_t incomingRecords[ 10 ] = { 0 };
MQTTPubAckInfo_t outgoingRecords[ 10 ] = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
outgoingRecords, 10,
incomingRecords, 10 );
/* Request to establish a clean session. */
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
connectInfo.cleanSession = true;
sessionPresentExpected = false;
/* Populate some state records to make sure they are cleared since a clean session
* will be established. */
mqttContext.outgoingPublishRecords[ 0 ].packetId = 1;
mqttContext.outgoingPublishRecords[ 0 ].qos = MQTTQoS2;
mqttContext.outgoingPublishRecords[ 0 ].publishState = MQTTPublishSend;
mqttContext.incomingPublishRecords[ MQTT_STATE_ARRAY_MAX_COUNT - 1 ].packetId = 1;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
/* Set ping response flag to true to ensure it will be cleared. */
mqttContext.waitingForPingResp = true;
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_FALSE( mqttContext.waitingForPingResp );
TEST_ASSERT_FALSE( sessionPresent );
/* Test old records were cleared. */
TEST_ASSERT_EQUAL_MEMORY( &outgoingRecords,
mqttContext.outgoingPublishRecords,
sizeof( outgoingRecords ) );
TEST_ASSERT_EQUAL_MEMORY( &incomingRecords,
mqttContext.incomingPublishRecords,
sizeof( incomingRecords ) );
}
/**
* @brief Test success case for MQTT_Connect().
*/
void test_MQTT_Connect_happy_path5()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
uint32_t timeout = 2;
bool sessionPresent, sessionPresentExpected;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Request to establish a session if present and session present is received
* from broker. */
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
mqttContext.waitingForPingResp = true;
connectInfo.cleanSession = false;
sessionPresentExpected = true;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
MQTT_SerializeConnect_IgnoreAndReturn( MQTTSuccess );
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializeAck_ReturnThruPtr_pSessionPresent( &sessionPresentExpected );
MQTT_PubrelToResend_ExpectAnyArgsAndReturn( MQTT_PACKET_TYPE_INVALID );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, timeout, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_TRUE( sessionPresent );
TEST_ASSERT_FALSE( mqttContext.waitingForPingResp );
}
/**
* @brief Test success case for MQTT_Connect().
*/
void test_MQTT_Connect_happy_path6()
{
MQTTContext_t mqttContext = { 0 };
MQTTConnectInfo_t connectInfo = { 0 };
bool sessionPresent = false;
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* CONNACK receive with timeoutMs=0. Retry logic will be used.
* #MQTTNoDataAvailable for first #MQTT_GetIncomingPacketTypeAndLength
* and success in the second time. */
mqttContext.connectStatus = MQTTNotConnected;
mqttContext.keepAliveIntervalSec = 0;
incomingPacket.type = MQTT_PACKET_TYPE_CONNACK;
incomingPacket.remainingLength = 2;
MQTT_GetConnectPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializeConnectFixedHeader_Stub( MQTT_SerializeConnectFixedHeader_cb );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_GetIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_IgnoreAndReturn( MQTTSuccess );
status = MQTT_Connect( &mqttContext, &connectInfo, NULL, 0U, &sessionPresent );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_INT( MQTTConnected, mqttContext.connectStatus );
TEST_ASSERT_EQUAL_INT( connectInfo.keepAliveSeconds, mqttContext.keepAliveIntervalSec );
TEST_ASSERT_FALSE( mqttContext.waitingForPingResp );
}
/* ========================================================================== */
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Verify parameters. */
status = MQTT_Publish( NULL, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish2( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
status = MQTT_Publish( &mqttContext, NULL, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish3( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
publishInfo.qos = MQTTQoS1;
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish4( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
publishInfo.payloadLength = 1;
publishInfo.pPayload = NULL;
status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish5( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Bad Parameter when getting packet size. */
publishInfo.qos = MQTTQoS0;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish6( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTNoMemory );
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTNoMemory, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_Storing_Publish_Success( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
MQTTPublishState_t expectedState = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
expectedState = MQTTPublishSend;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectedState );
mqttContext.transportInterface.send = transportSendSuccess;
status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_Storing_Publish_Success_For_Duplicate_Publish( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
MQTTPublishState_t expectedState = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
publishInfo.dup = true;
expectedState = MQTTPublishSend;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectedState );
mqttContext.transportInterface.send = transportSendSuccess;
status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_Storing_Publish_Failed( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackFailed,
publishRetrieveCallbackSuccess,
publishClearCallback );
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttContext.transportInterface.send = transportSendSuccess;
status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
TEST_ASSERT_EQUAL_INT( MQTTPublishStoreFailed, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_Storing_Publish_Failed_Due_To_Dup_Flag_Not_Set( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
MQTT_InitRetransmits( &mqttContext, publishStoreCallbackFailed,
publishRetrieveCallbackSuccess,
publishClearCallback );
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateDuplicatePublishFlag_ExpectAnyArgsAndReturn( MQTTBadParameter );
mqttContext.transportInterface.send = transportSendSuccess;
status = MQTT_Publish( &mqttContext, &publishInfo, 1 );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_DuplicatePublish( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t outgoingPublishRecord[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttContext.outgoingPublishRecordMaxCount = 10;
mqttContext.outgoingPublishRecords = outgoingPublishRecord;
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
publishInfo.dup = true;
publishInfo.pPayload = "TestPublish";
publishInfo.payloadLength = strlen( publishInfo.pPayload );
publishInfo.pTopicName = "TestTopic";
publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended when the connection status is anything but MQTTConnected.
*/
void test_MQTT_Publish_not_connected( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Test 1 connection status is MQTTNotConnected */
mqttContext.connectStatus = MQTTNotConnected;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
TEST_ASSERT_EQUAL_INT( MQTTStatusNotConnected, status );
/* Test 2 connection status is MQTTDisconnectPending */
mqttContext.connectStatus = MQTTDisconnectPending;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
TEST_ASSERT_EQUAL_INT( MQTTStatusDisconnectPending, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_DuplicatePublish_UpdateFailed( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t outgoingPublishRecord[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSendFailed );
mqttContext.outgoingPublishRecordMaxCount = 10;
mqttContext.outgoingPublishRecords = outgoingPublishRecord;
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
publishInfo.dup = true;
publishInfo.pPayload = "TestPublish";
publishInfo.payloadLength = strlen( publishInfo.pPayload );
publishInfo.pTopicName = "TestTopic";
publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish_WriteVSendsPartialBytes( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t outgoingPublishRecord[ 10 ];
size_t headerLen = 5;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.writev = transportWritevPartialByte;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Always return success from now on. */
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ReturnThruPtr_headerSize( &headerLen );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttContext.outgoingPublishRecordMaxCount = 10;
mqttContext.outgoingPublishRecords = outgoingPublishRecord;
mqttContext.connectStatus = MQTTConnected;
publishInfo.qos = MQTTQoS1;
publishInfo.dup = false;
publishInfo.pPayload = "TestPublish";
publishInfo.payloadLength = strlen( publishInfo.pPayload );
publishInfo.pTopicName = "TestTopic";
publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
status = MQTT_Publish( &mqttContext, &publishInfo, 10 );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish7( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.writev = transportWritevFail;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttContext.connectStatus = MQTTConnected;
/* We need sendPacket to be called with at least 1 byte to send, so that
* it can return failure. This argument is the output of serializing the
* publish header. */
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish8( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.writev = transportWritevFail;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* We want to test the first call to sendPacket within sendPublish succeeding,
* and the second one failing. */
mqttContext.transportInterface.send = transportSendSucceedThenFail;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish9( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttContext.transportInterface.send = transportSendSuccess;
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish10( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Test that sending a publish without a payload succeeds. */
publishInfo.pPayload = NULL;
publishInfo.payloadLength = 0;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish11( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Restore the test payload and length. */
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
/* Now for non zero QoS, which uses state engine. */
publishInfo.qos = MQTTQoS2;
status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish12( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPublishState_t expectedState = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
publishInfo.qos = MQTTQoS1;
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
mqttContext.outgoingPublishRecords[ 0 ].packetId = 1;
mqttContext.outgoingPublishRecords[ 0 ].qos = MQTTQoS2;
mqttContext.outgoingPublishRecords[ 0 ].publishState = MQTTPublishSend;
mqttContext.outgoingPublishRecords->packetId = 1;
mqttContext.outgoingPublishRecords->qos = MQTTQoS2;
mqttContext.connectStatus = MQTTConnected;
expectedState = MQTTPublishSend;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &expectedState );
status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish13( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
MQTT_InitStatefulQoS( &mqttContext,
&outgoingRecords, 4,
&incomingRecords, 4 );
publishInfo.qos = MQTTQoS1;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Duplicate publish. dup flag is not marked by application. */
MQTT_ReserveState_ExpectAnyArgsAndReturn( MQTTStateCollision );
status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTStateCollision, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish14( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Duplicate publish. dup flag is marked by application. */
publishInfo.dup = true;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that MQTT_Publish works as intended.
*/
void test_MQTT_Publish15( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
const uint16_t PACKET_ID = 1;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.writev = transportWritevSuccess;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
memset( &publishInfo, 0x0, sizeof( publishInfo ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Duplicate publish. dup flag is marked by application.
* State record is not present. */
publishInfo.dup = true;
MQTT_GetPublishPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Publish( &mqttContext, &publishInfo, PACKET_ID );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
}
/**
* @brief Test that verifies that the MQTT_Publish API detects a timeout
* and returns failure when the transport send function is unable to send any data
* over the network.
*/
void test_MQTT_Publish_Send_Timeout( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t status;
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
/* Set the transport send function to the mock that always returns zero
* bytes for the test. */
transport.send = transportSendNoBytes;
/* Initialize the MQTT context. */
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Setup for making sure that the test results in calling sendPacket function
* where calls to transport send function are made (repeatedly to send packet
* over the network).*/
memset( &publishInfo, 0, sizeof( MQTTPublishInfo_t ) );
publishInfo.pPayload = "Test";
publishInfo.payloadLength = 4;
MQTT_GetPublishPacketSize_IgnoreAndReturn( MQTTSuccess );
MQTT_SerializePublishHeaderWithoutTopic_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Call the API function under test and expect that it detects a timeout in sending
* MQTT packet over the network. */
status = MQTT_Publish( &mqttContext, &publishInfo, 0 );
TEST_ASSERT_EQUAL_INT( MQTTSendFailed, status );
}
/* ========================================================================== */
/**
* @brief Test that MQTT_Disconnect works as intended when the connection is already disconnected.
*/
void test_MQTT_Disconnect_already_disconnected( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t disconnectSize = 2;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTNotConnected;
/* Send failure with network error. */
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Disconnect( &mqttContext );
TEST_ASSERT_EQUAL( MQTTStatusNotConnected, status );
}
/**
* @brief Test that MQTT_Disconnect works as intended.
*/
void test_MQTT_Disconnect1( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
uint8_t buffer[ 10 ];
uint8_t * bufPtr = buffer;
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
networkContext.buffer = &bufPtr;
transport.pNetworkContext = &networkContext;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Verify parameters. */
status = MQTT_Disconnect( NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/**
* @brief Test that MQTT_Disconnect works as intended.
*/
void test_MQTT_Disconnect2( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
uint8_t buffer[ 10 ];
uint8_t * bufPtr = buffer;
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t disconnectSize = 2;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
networkContext.buffer = &bufPtr;
transport.pNetworkContext = &networkContext;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Send failure with network error. */
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Disconnect( &mqttContext );
TEST_ASSERT_EQUAL( MQTTSendFailed, status );
TEST_ASSERT_EQUAL( MQTTNotConnected, mqttContext.connectStatus );
}
/**
* @brief Test that MQTT_Disconnect works as intended.
*/
void test_MQTT_Disconnect3( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
uint8_t buffer[ 10 ];
uint8_t * bufPtr = buffer;
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t disconnectSize = 2;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
networkContext.buffer = &bufPtr;
transport.pNetworkContext = &networkContext;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Send failure with timeout in calling transport send. */
transport.send = transportSendNoBytes;
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
status = MQTT_Disconnect( &mqttContext );
TEST_ASSERT_EQUAL( MQTTSendFailed, status );
}
MQTTStatus_t MQTT_SerializeDisconnect_stub( const MQTTFixedBuffer_t * pFixedBuffer,
int numcalls )
{
( void ) numcalls;
pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
pFixedBuffer->pBuffer[ 1 ] = 0;
return MQTTSuccess;
}
/**
* @brief Test that MQTT_Disconnect works as intended.
*/
void test_MQTT_Disconnect4( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
uint8_t buffer[ 10 ];
uint8_t * bufPtr = buffer;
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t disconnectSize = 2;
/* Fill the buffer with garbage data. */
memset( mqttBuffer, 0xAB, MQTT_TEST_BUFFER_LENGTH );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
networkContext.buffer = &bufPtr;
transport.pNetworkContext = &networkContext;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
transport.writev = NULL;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTConnected;
/* Successful send. */
mqttContext.transportInterface.send = mockSend;
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializeDisconnect_Stub( MQTT_SerializeDisconnect_stub );
/* Write a disconnect packet into the buffer. */
mqttBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
status = MQTT_Disconnect( &mqttContext );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_EQUAL( MQTTNotConnected, mqttContext.connectStatus );
/* At disconnect, the buffer is cleared of any pending packets. */
TEST_ASSERT_EACH_EQUAL_UINT8( 0, mqttBuffer, MQTT_TEST_BUFFER_LENGTH );
}
/**
* @brief Test that MQTT_Disconnect works as intended when status is disconnect pending.
*/
void test_MQTT_Disconnect4_status_disconnect_pending( void )
{
MQTTContext_t mqttContext = { 0 };
MQTTStatus_t status;
uint8_t buffer[ 10 ];
uint8_t * bufPtr = buffer;
NetworkContext_t networkContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t disconnectSize = 2;
/* Fill the buffer with garbage data. */
memset( mqttBuffer, 0xAB, MQTT_TEST_BUFFER_LENGTH );
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
networkContext.buffer = &bufPtr;
transport.pNetworkContext = &networkContext;
transport.recv = transportRecvSuccess;
transport.send = transportSendFailure;
transport.writev = NULL;
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
mqttContext.connectStatus = MQTTDisconnectPending;
/* Successful send. */
mqttContext.transportInterface.send = mockSend;
MQTT_GetDisconnectPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetDisconnectPacketSize_ReturnThruPtr_pPacketSize( &disconnectSize );
MQTT_SerializeDisconnect_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializeDisconnect_Stub( MQTT_SerializeDisconnect_stub );
/* Write a disconnect packet into the buffer. */
mqttBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
status = MQTT_Disconnect( &mqttContext );
TEST_ASSERT_EQUAL( MQTTSuccess, status );
TEST_ASSERT_EQUAL( MQTTNotConnected, mqttContext.connectStatus );
/* At disconnect, the buffer is cleared of any pending packets. */
TEST_ASSERT_EACH_EQUAL_UINT8( 0, mqttBuffer, MQTT_TEST_BUFFER_LENGTH );
}
/* ========================================================================== */
/**
* @brief Test that MQTT_GetPacketId works as intended.
*/
void test_MQTT_GetPacketId( void )
{
MQTTContext_t mqttContext = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
uint16_t packetId;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
memset( &mqttContext, 0x0, sizeof( mqttContext ) );
MQTT_Init( &mqttContext, &transport, getTime, eventCallback, &networkBuffer );
/* Verify parameters. */
packetId = MQTT_GetPacketId( NULL );
TEST_ASSERT_EQUAL_INT( 0, packetId );
packetId = MQTT_GetPacketId( &mqttContext );
TEST_ASSERT_EQUAL_INT( 1, packetId );
TEST_ASSERT_EQUAL_INT( 2, mqttContext.nextPacketId );
mqttContext.nextPacketId = UINT16_MAX;
packetId = MQTT_GetPacketId( &mqttContext );
TEST_ASSERT_EQUAL_INT( UINT16_MAX, packetId );
TEST_ASSERT_EQUAL_INT( 1, mqttContext.nextPacketId );
}
/* ========================================================================== */
/**
* @brief Test that NULL pContext causes MQTT_ProcessLoop to return MQTTBadParameter.
*/
void test_MQTT_ProcessLoop_Invalid_Params( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus = MQTT_ProcessLoop( NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
setupTransportInterface( &transport );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Get time function cannot be NULL. */
context.getTime = NULL;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Restore the time function for the next test. */
context.getTime = getTime;
/* The fixed network buffer cannot be NULL. */
context.networkBuffer.pBuffer = NULL;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
void test_MQTT_ProcessLoop_discardPacket( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTStatus_t mqttStatus;
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.networkBuffer.size = 20;
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_ProcessLoop_IncomingBufferNotInit( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* First byte shows that it is a publish type packet. */
mqttBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
/* Length of the packet. */
mqttBuffer[ 1 ] = 20;
incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Assume QoS = 1. */
publishInfo.qos = MQTTQoS1;
MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTRecvFailed, mqttStatus );
}
void test_MQTT_ProcessLoop_IncomingBufferNotInitQoS0( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
isEventCallbackInvoked = false;
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* First byte shows that it is a publish type packet. */
mqttBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBLISH;
/* Length of the packet. */
mqttBuffer[ 1 ] = 20;
incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Assume QoS = 1. */
publishInfo.qos = MQTTQoS0;
MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_DeserializePublish_ReturnThruPtr_pPublishInfo( &publishInfo );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
TEST_ASSERT_EQUAL( true, isEventCallbackInvoked );
}
void test_MQTT_ProcessLoop_HandleKeepAlive( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* Set this value such that the library will be forced to send keep alive. */
context.waitingForPingResp = true;
/* Update the time so that there is timeout. */
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_ProcessLoop_HandleKeepAlive1( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Set this value such that the library will be forced to send keep alive. */
context.waitingForPingResp = false;
context.keepAliveIntervalSec = 1;
/* Update the time so that there is timeout. */
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_ProcessLoop_HandleKeepAlive2( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
/* Set this value such that the library will be forced to send keep alive. */
context.waitingForPingResp = false;
context.keepAliveIntervalSec = 1;
/* Update the time so that timeout does not occur and the ping is not sent. */
globalEntryTime = 0;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_ProcessLoop_RecvFailed( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
setupTransportInterface( &transport );
transport.recv = transportRecvFailure;
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
context.connectStatus = MQTTConnected;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTRecvFailed, mqttStatus );
}
void test_MQTT_ProcessLoop_RecvFailed_disconnected( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTStatus_t mqttStatus;
setupTransportInterface( &transport );
transport.recv = transportRecvFailure;
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTRecvFailed, mqttStatus );
}
void test_MQTT_ReceiveLoop_KeepAliveACK( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTStatus_t mqttStatus;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.networkBuffer.size = MQTT_TEST_BUFFER_LENGTH;
incomingPacket.type = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_ProcessLoop_discardPacket_second_recv_fail( void )
{
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTStatus_t mqttStatus;
setupTransportInterface( &transport );
transport.recv = transportRecvOneSuccessOneFail;
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
context.networkBuffer.size = 20;
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTRecvFailed, mqttStatus );
}
/**
* @brief This test case covers one call to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingCallback[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingCallback, 10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Assume QoS = 1 so that a PUBACK will be sent after receiving PUBLISH.
* That is, expectProcessLoopCalls will take on the following parameters:
* incomingPublish=true and stateAfterDeserialize=MQTTPubAckSend. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
/* Set expected return values during the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectParams.incomingPublish = true;
expectProcessLoopCalls( &context, &expectParams );
}
/**
* @brief This test case covers one call to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Assume QoS = 2 so that a PUBREC will be sent after receiving PUBLISH.
* That is, expectProcessLoopCalls will take on the following parameters:
* incomingPublish=true and stateAfterDeserialize=MQTTPubRecSend. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
/* Set expected return values during the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRecSend;
expectParams.stateAfterSerialize = MQTTPubRelPending;
expectParams.incomingPublish = true;
expectProcessLoopCalls( &context, &expectParams );
}
/**
* @brief This test case covers one call to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path3( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPublishInfo_t pubInfo = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context,
&transport,
getTime,
eventCallback,
&networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Duplicate QoS1 publish received.
* expectProcessLoopCalls will take on the following parameters:
* incomingPublish=true, stateAfterDeserialize=MQTTPubAckSend,
* updateStateStatus=MQTTStateCollision and pPubInfo is passed with
* dup flag set. The event callback should not be invoked. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
pubInfo.dup = true;
pubInfo.qos = MQTTQoS1;
isEventCallbackInvoked = false;
/* Set expected return values during the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.updateStateStatus = MQTTStateCollision;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectParams.deserializeStatus = MQTTSuccess;
expectParams.incomingPublish = true;
expectParams.pPubInfo = &pubInfo;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_FALSE( isEventCallbackInvoked );
}
/**
* @brief This test case covers one call to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path4( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Duplicate QoS2 publish received.
* expectProcessLoopCalls will take on the following parameters:
* incomingPublish=true, stateAfterDeserialize=MQTTPubRecSend,
* updateStateStatus=MQTTStateCollision and pPubInfo is passed with
* dup flag set. The event callback should not be invoked. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
isEventCallbackInvoked = false;
/* Only changes are for QoS 2, no need to reset. */
expectParams.stateAfterDeserialize = MQTTPubRecSend;
expectParams.stateAfterSerialize = MQTTPubRelPending;
expectParams.incomingPublish = true;
expectParams.updateStateStatus = MQTTStateCollision;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_FALSE( isEventCallbackInvoked );
}
/**
* @brief This test case covers one call to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path5( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* A publish is received when already a state record exists, but dup
* flag is not set. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
isEventCallbackInvoked = false;
expectParams.incomingPublish = true;
expectParams.updateStateStatus = MQTTStateCollision;
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
/* No loop statuses have changed from before. */
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_FALSE( isEventCallbackInvoked );
}
/**
* @brief This test case covers one call to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Happy_Path6( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t pIncomingPublish[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, pIncomingPublish, 10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Duplicate QoS2 publish received with no collision.
* expectProcessLoopCalls will take on the following parameters:
* incomingPublish=true, stateAfterDeserialize=MQTTPubRecSend,
* updateStateStatus=MQTTSuccess and pPubInfo is passed with
* dup flag set. The event callback should be invoked. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
isEventCallbackInvoked = false;
expectParams.incomingPublish = true;
/* The only expect parameter to change is the update status. */
expectParams.updateStateStatus = MQTTSuccess;
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_TRUE( isEventCallbackInvoked );
}
/**
* @brief This test case covers all calls to the private method,
* handleIncomingPublish(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleIncomingPublish_Error_Paths( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPublishInfo_t publishInfo = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
modifyIncomingPacketStatus = MQTTSuccess;
/* Verify that an error is propagated when deserialization fails by returning
* MQTTBadResponse. Any parameters beyond that are actually irrelevant
* because they are only used as return values for non-expected calls. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
/* Set expected return values during the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTBadResponse;
expectParams.updateStateStatus = MQTTIllegalState;
expectParams.serializeStatus = MQTTBadResponse;
expectParams.processLoopStatus = MQTTBadResponse;
expectParams.incomingPublish = true;
expectProcessLoopCalls( &context, &expectParams );
/* A publish is received and dup flag is set, but state update failed. */
publishInfo.dup = true;
publishInfo.qos = MQTTQoS2;
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
isEventCallbackInvoked = false;
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.updateStateStatus = MQTTIllegalState;
expectParams.processLoopStatus = MQTTIllegalState;
expectParams.incomingPublish = true;
expectParams.pPubInfo = &publishInfo;
/* The other loop parameter fields are irrelevant. */
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_FALSE( isEventCallbackInvoked );
}
/**
* @brief This test checks that the ProcessLoop API function is able to
* support receiving an entire incoming MQTT packet over the network when
* the transport recv function only reads less than requested bytes at a
* time, and the timeout passed to the API is "0ms".
*/
void test_MQTT_ProcessLoop_Zero_Duration_And_Partial_Network_Read( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupNetworkBuffer( &networkBuffer );
transport.send = transportSendSuccess;
/* Set the transport recv function for the test to the mock function that represents
* partial read of data from network (i.e. less than requested number of bytes)
* at a time. */
transport.recv = transportRecvOneByte;
/* Initialize the context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Set flag required for configuring behavior of expectProcessLoopCalls()
* helper function. */
modifyIncomingPacketStatus = MQTTNoDataAvailable;
/* Test the ProcessLoop() call with zero duration timeout to verify that it
* will be able to support reading the packet over network over multiple calls to
* the transport receive function. */
expectParams.timeoutMs = MQTT_NO_TIMEOUT_MS;
/* Test with an incoming PUBLISH packet whose payload is read only one byte
* per call to the transport recv function. */
currentPacketType = MQTT_PACKET_TYPE_PUBLISH;
/* Set expected return values during the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubAckSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectParams.incomingPublish = true;
expectParams.processLoopStatus = MQTTNeedMoreBytes;
expectParams.updateStateStatus = MQTTNeedMoreBytes;
expectProcessLoopCalls( &context, &expectParams );
}
/**
* @brief This test case covers all calls to the private method,
* handleIncomingAck(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingAck_Happy_Paths( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Mock the receiving of a PUBACK packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPublishDone;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a PUBREC packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.stateAfterSerialize = MQTTPubCompPending;
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a PUBREL packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBREL;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubCompSend;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
/* Duplicate PUBREL, but no record exists. */
currentPacketType = MQTT_PACKET_TYPE_PUBREL;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTStateNull;
expectParams.updateStateStatus = MQTTBadParameter;
expectParams.processLoopStatus = MQTTBadParameter;
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a PUBCOMP packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBCOMP;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPublishDone;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a PINGRESP packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PINGRESP;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a SUBACK packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_SUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectProcessLoopCalls( &context, &expectParams );
/* Verify that process loop is still successful when SUBACK indicates a
* server refusal. */
currentPacketType = MQTT_PACKET_TYPE_SUBACK;
isEventCallbackInvoked = false;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTServerRefused;
expectProcessLoopCalls( &context, &expectParams );
TEST_ASSERT_TRUE( isEventCallbackInvoked );
/* Mock the receiving of an UNSUBACK packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_UNSUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectProcessLoopCalls( &context, &expectParams );
}
/**
* @brief This test case covers all calls to the private method,
* handleIncomingAck(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleIncomingAck_Clear_Publish_Copies( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitRetransmits( &context, publishStoreCallbackSuccess,
publishRetrieveCallbackSuccess,
publishClearCallback );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Mock the receiving of a PUBACK packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPublishDone;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a PUBREC packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.stateAfterSerialize = MQTTPubCompPending;
expectProcessLoopCalls( &context, &expectParams );
context.clearFunction = publishClearCallback;
/* Mock the receiving of a PUBACK packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPublishDone;
expectParams.stateAfterSerialize = MQTTPublishDone;
expectProcessLoopCalls( &context, &expectParams );
/* Mock the receiving of a PUBREC packet type and expect the appropriate
* calls made from the process loop. */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.stateAfterSerialize = MQTTPubCompPending;
expectProcessLoopCalls( &context, &expectParams );
}
/**
* @brief This test case covers all calls to the private method,
* handleIncomingAck(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleIncomingAck_Error_Paths( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
modifyIncomingPacketStatus = MQTTSuccess;
/* Verify that MQTTBadResponse is propagated when deserialization fails upon
* receiving an unknown packet type. */
currentPacketType = MQTT_PACKET_TYPE_INVALID;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTBadResponse;
expectParams.processLoopStatus = MQTTBadResponse;
expectProcessLoopCalls( &context, &expectParams );
/* Verify that MQTTSendFailed is propagated when receiving a PUBREC
* then failing when serializing a PUBREL to send in response. */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.serializeStatus = MQTTNoMemory;
expectParams.stateAfterSerialize = MQTTStateNull;
expectParams.processLoopStatus = MQTTNoMemory;
expectProcessLoopCalls( &context, &expectParams );
/* Verify that MQTTStatusNotConnected propagated when receiving a any ACK,
* here PUBREC but thr connection status is MQTTNotConnected. */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.stateAfterSerialize = MQTTPubCompPending;
expectParams.serializeStatus = MQTTSuccess;
expectParams.processLoopStatus = MQTTStatusNotConnected;
context.connectStatus = MQTTNotConnected;
expectProcessLoopCalls( &context, &expectParams );
context.connectStatus = MQTTConnected;
/* Verify that MQTTStatusNotConnected propagated when receiving a any ACK,
* here PUBREC but thr connection status is MQTTNotConnected. */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.stateAfterSerialize = MQTTPubCompPending;
expectParams.serializeStatus = MQTTSuccess;
expectParams.processLoopStatus = MQTTStatusDisconnectPending;
context.connectStatus = MQTTDisconnectPending;
expectProcessLoopCalls( &context, &expectParams );
context.connectStatus = MQTTConnected;
/* Verify that MQTTBadResponse is propagated when deserialization fails upon
* receiving a PUBACK. */
currentPacketType = MQTT_PACKET_TYPE_PUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTBadResponse;
expectParams.stateAfterDeserialize = MQTTStateNull;
expectParams.processLoopStatus = MQTTBadResponse;
/* The other loop parameter fields are irrelevant. */
expectProcessLoopCalls( &context, &expectParams );
/* Verify that MQTTBadResponse is propagated when deserialization fails upon
* receiving a PINGRESP. */
currentPacketType = MQTT_PACKET_TYPE_PINGRESP;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTBadResponse;
expectParams.stateAfterDeserialize = MQTTStateNull;
expectParams.processLoopStatus = MQTTBadResponse;
/* The other loop parameter fields are irrelevant. */
expectProcessLoopCalls( &context, &expectParams );
/* Verify that MQTTBadResponse is propagated when deserialization fails upon
* receiving a SUBACK. */
currentPacketType = MQTT_PACKET_TYPE_SUBACK;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.deserializeStatus = MQTTBadResponse;
expectParams.processLoopStatus = MQTTBadResponse;
/* The other loop parameter fields are irrelevant. */
expectProcessLoopCalls( &context, &expectParams );
/* Verify that MQTTIllegalState is returned if MQTT_UpdateStateAck(...)
* provides an unknown state such as MQTTStateNull to sendPublishAcks(...). */
currentPacketType = MQTT_PACKET_TYPE_PUBREC;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.stateAfterDeserialize = MQTTPubRelSend;
expectParams.stateAfterSerialize = MQTTStateNull;
expectParams.processLoopStatus = MQTTIllegalState;
expectProcessLoopCalls( &context, &expectParams );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
resetProcessLoopParams( &expectParams );
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
context.waitingForPingResp = false;
context.keepAliveIntervalSec = 0;
expectParams.incomingPublish = false;
expectParams.updateStateStatus = MQTTSuccess;
expectParams.processLoopStatus = MQTTSuccess;
expectParams.stateAfterDeserialize = MQTTPubRelSend;
/* Set expected return values in the loop. All success. */
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
resetProcessLoopParams( &expectParams );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Coverage for the branch path where keep alive interval is greater than 0,
* and the interval has not expired. PINGREQ should not be sent. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.keepAliveIntervalSec = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
context.lastPacketTxTime = getTime();
/* Set expected return values in the loop. All success. */
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths3( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
resetProcessLoopParams( &expectParams );
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Coverage for the branch path where PINGRESP timeout interval hasn't expired. */
context.waitingForPingResp = true;
context.keepAliveIntervalSec = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
context.lastPacketTxTime = MQTT_ONE_SECOND_TO_MS;
context.pingReqSendTimeMs = MQTT_ONE_SECOND_TO_MS;
/* Set expected return values in the loop. All success. */
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning successfully.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Happy_Paths4( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
resetProcessLoopParams( &expectParams );
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_ONE_SECOND_TO_MS;
/* Coverage for the branch path where keep alive interval is 0. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.waitingForPingResp = false;
context.keepAliveIntervalSec = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
context.lastPacketTxTime = 0;
/* Set expected return values in the loop. All success. */
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( expectParams.updateStateStatus );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &expectParams.stateAfterDeserialize );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths1( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
transport.writev = transportWritevSuccess;
transport.recv = transportRecvNoData;
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.keepAliveIntervalSec = MQTT_SAMPLE_KEEPALIVE_INTERVAL_S;
context.lastPacketTxTime = 0;
context.lastPacketRxTime = 0;
context.pingReqSendTimeMs = 0;
context.waitingForPingResp = true;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.processLoopStatus = MQTTKeepAliveTimeout;
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTKeepAliveTimeout, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths2( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.keepAliveIntervalSec = PACKET_TX_TIMEOUT_MS + 1;
context.lastPacketTxTime = 0;
context.lastPacketRxTime = 0;
context.pingReqSendTimeMs = 0;
context.waitingForPingResp = false;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
expectParams.processLoopStatus = MQTTKeepAliveTimeout;
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
currentPacketType = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNoDataAvailable );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths3( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
transport.recv = transportRecvNoData;
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
globalEntryTime = PACKET_RX_TIMEOUT_MS + 1;
context.keepAliveIntervalSec = 0;
context.lastPacketTxTime = 0;
context.lastPacketRxTime = 0;
context.pingReqSendTimeMs = 0;
context.waitingForPingResp = false;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths4( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
globalEntryTime = PACKET_RX_TIMEOUT_MS + 1;
context.keepAliveIntervalSec = ( PACKET_TX_TIMEOUT_MS / 1000 ) + 1U;
context.lastPacketTxTime = 0;
context.lastPacketRxTime = 0;
context.pingReqSendTimeMs = 0;
context.waitingForPingResp = false;
/* Set the index to non-zero value to show that there is some data in the buffer
* to be processed. */
context.index = 12;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
currentPacketType = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNeedMoreBytes );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTNeedMoreBytes, mqttStatus );
}
/**
* @brief This test case covers all calls to the private method,
* handleKeepAlive(...),
* that result in the process loop returning an error.
*/
void test_MQTT_ProcessLoop_handleKeepAlive_Error_Paths5( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
ProcessLoopReturns_t expectParams = { 0 };
setupTransportInterface( &transport );
transport.recv = transportRecvNoData;
setupNetworkBuffer( &networkBuffer );
modifyIncomingPacketStatus = MQTTNoDataAvailable;
globalEntryTime = MQTT_PINGRESP_TIMEOUT_MS + 1;
/* Coverage for the branch path where PINGRESP timeout interval has expired. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
globalEntryTime = PACKET_RX_TIMEOUT_MS - 1U;
context.keepAliveIntervalSec = ( PACKET_TX_TIMEOUT_MS / 1000 ) + 1U;
context.lastPacketTxTime = 0;
context.lastPacketRxTime = 0;
context.pingReqSendTimeMs = 0;
context.waitingForPingResp = false;
/* Set the index to non-zero value to show that there is some data in the buffer
* to be processed. */
context.index = 12;
/* Set expected return values in the loop. */
resetProcessLoopParams( &expectParams );
MQTTPacketInfo_t incomingPacket = { 0 };
/* Modify incoming packet depending on type to be tested. */
currentPacketType = MQTT_PACKET_TYPE_PINGRESP;
incomingPacket.type = currentPacketType;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
incomingPacket.headerLength = MQTT_SAMPLE_REMAINING_LENGTH;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTNeedMoreBytes );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTNeedMoreBytes, mqttStatus );
}
/**
* @brief This test mocks a failing transport receive and runs multiple
* iterations of the process loop, resulting in returning MQTTRecvFailed.
*/
void test_MQTT_ProcessLoop_Receive_Failed( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
setupNetworkBuffer( &networkBuffer );
setupTransportInterface( &transport );
transport.writev = transportWritevFail;
mqttStatus = MQTT_Init( &context, &transport,
getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
incomingPacket.type = MQTT_PACKET_TYPE_PUBCOMP;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
MQTT_DeserializeAck_ExpectAnyArgsAndReturn( MQTTRecvFailed );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTRecvFailed, mqttStatus );
}
/**
* @brief Set the initial entry time close to the maximum value, causing
* an overflow. This test then checks that the process loop still runs for the
* expected number of iterations in spite of this.
*/
void test_MQTT_ProcessLoop_Timer_Overflow( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTPacketInfo_t incomingPacket = { 0 };
MQTTPublishState_t publishState = MQTTPubAckSend;
MQTTPublishState_t ackState = MQTTPublishDone;
MQTTPubAckInfo_t incomingPublishRecords[ 10 ];
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
incomingPacket.type = MQTT_PACKET_TYPE_PUBLISH;
incomingPacket.remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
globalEntryTime = UINT32_MAX - MQTT_OVERFLOW_OFFSET;
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context, NULL, 0, incomingPublishRecords, 10 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_ProcessIncomingPacketTypeAndLength_ReturnThruPtr_pIncomingPacket( &incomingPacket );
/* Assume QoS = 1 so that a PUBACK will be sent after receiving PUBLISH. */
MQTT_DeserializePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStatePublish_ReturnThruPtr_pNewState( &publishState );
MQTT_SerializeAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_UpdateStateAck_ReturnThruPtr_pNewState( &ackState );
mqttStatus = MQTT_ProcessLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/* ========================================================================== */
/**
* @brief Test that MQTT_ReceiveLoop() works as intended. Since the only difference
* between this and the process loop is keep alive, we only need to test the
* differences for coverage.
*/
void test_MQTT_ReceiveLoop( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Verify that a NULL Context returns an error. */
mqttStatus = MQTT_ReceiveLoop( NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Verify that a NULL time function returns an error. */
context.getTime = NULL;
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
context.getTime = getTime;
/* Verify that a null fixed network buffer returns an error. */
context.networkBuffer.pBuffer = NULL;
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
setupNetworkBuffer( &( context.networkBuffer ) );
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTBadResponse );
/* Error case, for branch coverage. */
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTBadResponse, mqttStatus );
/* This will cover the case when there is data available in the buffer to be processed but
* no additional bytes have been received by the transport interface. */
context.transportInterface.recv = transportRecvNoData;
MQTT_ProcessIncomingPacketTypeAndLength_ExpectAnyArgsAndReturn( MQTTBadResponse );
/* Error case, for branch coverage. */
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTBadResponse, mqttStatus );
/* Reset the index to clear the buffer of any remaining data. */
context.index = 0;
/* Keep Alive should not trigger.*/
context.keepAliveIntervalSec = 1;
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
TEST_ASSERT_FALSE( context.controlPacketSent );
/* Test with a dummy getTime to ensure there's no infinite loops. */
context.getTime = getTimeDummy;
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.getTime = getTime;
/* Receive a PINGRESP. */
mqttStatus = MQTT_ReceiveLoop( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/* ========================================================================== */
/**
* @brief This test case verifies that MQTT_Subscribe returns MQTTBadParameter
* with an invalid parameter. This test case also gives us coverage over
* the private method, validateSubscribeUnsubscribeParams(...).
*/
void test_MQTT_Subscribe_invalid_params( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
/* Call subscribe with a NULL context. */
mqttStatus = MQTT_Subscribe( NULL, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Call subscribe with a NULL subscription list. */
mqttStatus = MQTT_Subscribe( &context, NULL, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Call subscribe with 0 subscriptions. */
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 0, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Packet ID cannot be 0 per MQTT 3.1.1 spec. */
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, 0 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Incoming publish records NULL but QoS > 0. */
subscribeInfo.qos = MQTTQoS1;
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, 10 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
static uint8_t * MQTT_SerializeSubscribedHeader_cb( size_t remainingLength,
uint8_t * pIndex,
uint16_t packetId,
int numcallbacks )
{
( void ) remainingLength;
( void ) pIndex;
( void ) packetId;
( void ) numcallbacks;
return pIndex;
}
static uint8_t * MQTT_SerializeSubscribedHeader_cb1( size_t remainingLength,
uint8_t * pIndex,
uint16_t packetId,
int numcallbacks )
{
( void ) remainingLength;
( void ) pIndex;
( void ) packetId;
( void ) numcallbacks;
return pIndex + 5;
}
static uint8_t * MQTT_SerializeSubscribedHeader_cb2( size_t remainingLength,
uint8_t * pIndex,
uint16_t packetId,
int numcallbacks )
{
( void ) remainingLength;
( void ) pIndex;
( void ) packetId;
( void ) numcallbacks;
memcpy( pIndex, SubscribeHeader, SubscribeHeaderLength );
return pIndex + SubscribeHeaderLength;
}
static uint8_t * MQTT_SerializeUnsubscribedHeader_cb2( size_t remainingLength,
uint8_t * pIndex,
uint16_t packetId,
int numcallbacks )
{
( void ) remainingLength;
( void ) pIndex;
( void ) packetId;
( void ) numcallbacks;
memcpy( pIndex, UnsubscribeHeader, UnsubscribeHeaderLength );
return pIndex + UnsubscribeHeaderLength;
}
/**
* @brief This test case verifies that MQTT_Subscribe returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_Subscribe_happy_path( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe does not return success if the connect status
* is anythin but MQTTConnected.
*/
void test_MQTT_Subscribe_happy_path_not_connected( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Test 1 connect status is MQTTNotConnected */
context.connectStatus = MQTTNotConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
/* Test 2 connect status is MQTTDisconnectPending*/
context.connectStatus = MQTTDisconnectPending;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_Subscribe_happy_path1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo[ 2 ];
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo[ 0 ] );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_Subscribe_happy_path2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo[ 2 ];
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo[ 0 ] );
setupSubscriptionInfo( &subscribeInfo[ 1 ] );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb1 );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 2, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_Subscribe_MultipleSubscriptions( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo[ 5 ];
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
TEST_ASSERT_EQUAL_MESSAGE( 6U, MQTT_SUB_UNSUB_MAX_VECTORS,
"This test is configured to work with MQTT_SUB_UNSUB_MAX_VECTORS defined as 6." );
setupTransportInterface( &transport );
transport.writev = transportWritevSubscribeSuccess;
setupNetworkBuffer( &networkBuffer );
subscribeInfo[ 0 ].qos = MQTTQoS1;
subscribeInfo[ 0 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
subscribeInfo[ 0 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
subscribeInfo[ 1 ].qos = MQTTQoS2;
subscribeInfo[ 1 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER1;
subscribeInfo[ 1 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH1;
subscribeInfo[ 2 ].qos = MQTTQoS0;
subscribeInfo[ 2 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER2;
subscribeInfo[ 2 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH2;
subscribeInfo[ 3 ].qos = MQTTQoS1;
subscribeInfo[ 3 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER3;
subscribeInfo[ 3 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH3;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb2 );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, subscribeInfo, 4, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
void test_MQTT_Subscribe_error_paths1( void )
{
MQTTStatus_t mqttStatus = { 0 };
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
/* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
setupTransportInterface( &transport );
transport.send = transportSendFailure;
transport.writev = transportWritevFail;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSendFailed is propagated when transport interface returns an error. */
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
void test_MQTT_Subscribe_error_paths2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
/* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
setupTransportInterface( &transport );
transport.writev = NULL;
/* Case when there is timeout in sending data through transport send. */
transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface fails to send and the connection status is converted to
* MQTTDisconnectPending
*/
void test_MQTT_Subscribe_error_paths_with_transport_failure( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
/* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
setupTransportInterface( &transport );
transport.writev = NULL;
transport.send = transportSendFailure;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
TEST_ASSERT_EQUAL( MQTTDisconnectPending, context.connectStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface send fails and timer overflows.
*/
void test_MQTT_Subscribe_error_paths_timerOverflowCheck( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
globalEntryTime = UINT32_MAX - 2U;
/* The timer function can be called a maximum of these many times
* (which is way less than UINT32_MAX). This ensures that if overflow
* check is not correct, then the timer mock call will fail and assert. */
getTimeMockCallLimit = MQTT_SEND_TIMEOUT_MS + 1;
/* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
setupTransportInterface( &transport );
transport.writev = NULL;
/* Case when there is timeout in sending data through transport send. */
transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTimeMock, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
TEST_ASSERT_EQUAL( -1, getTimeMockCallLimit );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns MQTTSendFailed
* if transport interface send fails and timer overflows.
*/
void test_MQTT_Subscribe_error_paths_timerOverflowCheck1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
globalEntryTime = UINT32_MAX - MQTT_SEND_TIMEOUT_MS + 1;
/* The timer function can be called a exactly 2 times. First when setting
* the initial time, next time when checking for timeout.
*/
getTimeMockBigTimeStepCallLimit = 2;
/* Verify that an error is propagated when transport interface returns an error. */
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
setupTransportInterface( &transport );
transport.writev = NULL;
/* Case when there is timeout in sending data through transport send. */
transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTimeMockBigTimeStep, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_GetSubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetSubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeSubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
mqttStatus = MQTT_Subscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
TEST_ASSERT_EQUAL( -1, getTimeMockBigTimeStepCallLimit );
}
/* ========================================================================== */
/**
* @brief This test case verifies that MQTT_Unsubscribe returns MQTTBadParameter
* with an invalid parameter. This test case also gives us coverage over
* the private method, validateSubscribeUnsubscribeParams(...).
*/
void test_MQTT_Unsubscribe_invalid_params( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
/* Call subscribe with a NULL context. */
mqttStatus = MQTT_Unsubscribe( NULL, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Call subscribe with a NULL subscription list. */
mqttStatus = MQTT_Unsubscribe( &context, NULL, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Call subscribe with 0 subscriptions. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 0, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
/* Packet ID cannot be 0 per MQTT 3.1.1 spec. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, 0 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
static uint8_t * MQTT_SerializeUnsubscribeHeader_cb( size_t remainingLength,
uint8_t * pIndex,
uint16_t packetId,
int numcallbacks )
{
( void ) remainingLength;
( void ) pIndex;
( void ) packetId;
( void ) numcallbacks;
return pIndex;
}
/**
* @brief This test case verifies that MQTT_Unsubscribe returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_Unsubscribe_happy_path( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribeHeader_cb );
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
/* Expect the above calls when running MQTT_Unsubscribe. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Unsubscribe does not return success
* when the connection status is anything but MQTTConnected
*/
void test_MQTT_Unsubscribe_not_connected( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Test 1 Connection status is MQTTNotConnected*/
context.connectStatus = MQTTNotConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
/* Expect the above calls when running MQTT_Unsubscribe. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
/* Test 2 Connection status is MQTTDisconnectPending*/
context.connectStatus = MQTTDisconnectPending;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
/* Expect the above calls when running MQTT_Unsubscribe. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_Unsubscribe_happy_path1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo[ 2 ];
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo[ 0 ] );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Subscribe returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_unsubscribe_happy_path2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo[ 3 ];
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo[ 0 ] );
setupSubscriptionInfo( &subscribeInfo[ 1 ] );
setupSubscriptionInfo( &subscribeInfo[ 2 ] );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeSubscribedHeader_cb1 );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 3, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
void test_MQTT_Unsubscribe_MultipleSubscriptions( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo[ 5 ];
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
MQTTPubAckInfo_t incomingRecords = { 0 };
MQTTPubAckInfo_t outgoingRecords = { 0 };
TEST_ASSERT_EQUAL_MESSAGE( 6U, MQTT_SUB_UNSUB_MAX_VECTORS,
"This test is configured to work with MQTT_SUB_UNSUB_MAX_VECTORS defined as 6." );
setupTransportInterface( &transport );
transport.writev = transportWritevUnsubscribeSuccess;
setupNetworkBuffer( &networkBuffer );
subscribeInfo[ 0 ].qos = MQTTQoS1;
subscribeInfo[ 0 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER;
subscribeInfo[ 0 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH;
subscribeInfo[ 1 ].qos = MQTTQoS2;
subscribeInfo[ 1 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER1;
subscribeInfo[ 1 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH1;
subscribeInfo[ 2 ].qos = MQTTQoS0;
subscribeInfo[ 2 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER2;
subscribeInfo[ 2 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH2;
subscribeInfo[ 3 ].qos = MQTTQoS1;
subscribeInfo[ 3 ].pTopicFilter = MQTT_SAMPLE_TOPIC_FILTER3;
subscribeInfo[ 3 ].topicFilterLength = MQTT_SAMPLE_TOPIC_FILTER_LENGTH3;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
mqttStatus = MQTT_InitStatefulQoS( &context,
&outgoingRecords, 4,
&incomingRecords, 4 );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned with the following mocks. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribedHeader_cb2 );
/* Expect the above calls when running MQTT_Subscribe. */
mqttStatus = MQTT_Unsubscribe( &context, subscribeInfo, 4, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Unsubscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
void test_MQTT_Unsubscribe_error_path1( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
/* Verify that an error is propagated when transport interface returns an error. */
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
transport.send = transportSendFailure;
transport.recv = transportRecvFailure;
transport.writev = transportWritevFail;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribeHeader_cb );
/* Verify MQTTSendFailed is propagated when transport interface returns an error. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
/* Expect the above calls when running MQTT_Unsubscribe. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
/* Case when there is timeout in sending data through transport send. */
}
/**
* @brief This test case verifies that MQTT_Unsubscribe returns MQTTSendFailed
* if transport interface send returns an error.
*/
void test_MQTT_Unsubscribe_error_path2( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
MQTTSubscribeInfo_t subscribeInfo = { 0 };
size_t remainingLength = MQTT_SAMPLE_REMAINING_LENGTH;
size_t packetSize = MQTT_SAMPLE_REMAINING_LENGTH;
setupNetworkBuffer( &networkBuffer );
setupSubscriptionInfo( &subscribeInfo );
subscribeInfo.qos = MQTTQoS0;
/* Verify that an error is propagated when transport interface returns an error. */
setupTransportInterface( &transport );
transport.send = transportSendFailure;
transport.recv = transportRecvFailure;
transport.writev = transportWritevFail;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_SerializeUnsubscribeHeader_Stub( MQTT_SerializeUnsubscribeHeader_cb );
transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
MQTT_GetUnsubscribePacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pPacketSize( &packetSize );
MQTT_GetUnsubscribePacketSize_ReturnThruPtr_pRemainingLength( &remainingLength );
/* Expect the above calls when running MQTT_Unsubscribe. */
mqttStatus = MQTT_Unsubscribe( &context, &subscribeInfo, 1, MQTT_FIRST_VALID_PACKET_ID );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
}
/* ========================================================================== */
/**
* @brief This test case verifies that MQTT_Ping returns MQTTBadParameter
* with context parameter is NULL.
*/
void test_MQTT_Ping_invalid_params( void )
{
MQTTStatus_t mqttStatus;
/* Call ping with a NULL context. */
mqttStatus = MQTT_Ping( NULL );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Ping returns successfully
* when valid parameters are passed and all bytes are sent.
*/
void test_MQTT_Ping_happy_path( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSuccess is returned. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Expect the above calls when running MQTT_Ping. */
mqttStatus = MQTT_Ping( &context );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
TEST_ASSERT_EQUAL( context.lastPacketTxTime, context.pingReqSendTimeMs );
TEST_ASSERT_TRUE( context.waitingForPingResp );
}
/**
* @brief This test case verifies that MQTT_Ping does not returns success
* if the connection status is anything but MQTTConnect.
*/
void test_MQTT_Ping_not_connected( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
/* Test 1 when the connection status is MQTTNotConnected*/
context.connectStatus = MQTTNotConnected;
/* Verify MQTTSuccess is returned. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Expect the above calls when running MQTT_Ping. */
mqttStatus = MQTT_Ping( &context );
TEST_ASSERT_EQUAL( MQTTStatusNotConnected, mqttStatus );
/* Test 2 when the connection status is MQTTDisconnectPending*/
context.connectStatus = MQTTDisconnectPending;
/* Verify MQTTSuccess is returned. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Expect the above calls when running MQTT_Ping. */
mqttStatus = MQTT_Ping( &context );
TEST_ASSERT_EQUAL( MQTTStatusDisconnectPending, mqttStatus );
}
/**
* @brief This test case verifies that MQTT_Ping returns MQTTSendFailed
* if transport interface send returns an error.
*/
void test_MQTT_Ping_error_path( void )
{
MQTTStatus_t mqttStatus;
MQTTContext_t context = { 0 };
TransportInterface_t transport = { 0 };
MQTTFixedBuffer_t networkBuffer = { 0 };
size_t pingreqSize = MQTT_PACKET_PINGREQ_SIZE;
setupTransportInterface( &transport );
setupNetworkBuffer( &networkBuffer );
/* Test a network error is returned from sending the PING packet over the
* transport send . */
transport.send = transportSendFailure;
transport.recv = transportRecvFailure;
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTSendFailed is propagated when transport interface returns an error. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Expect the above calls when running MQTT_Ping. */
mqttStatus = MQTT_Ping( &context );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
/* Case when there is timeout in sending data through transport send. */
transport.recv = transportRecvSuccess;
transport.send = transportSendNoBytes; /* Use the mock function that returns zero bytes sent. */
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTSuccess );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
MQTT_SerializePingreq_ExpectAnyArgsAndReturn( MQTTSuccess );
/* Verify that the API returns failure. */
mqttStatus = MQTT_Ping( &context );
TEST_ASSERT_EQUAL( MQTTSendFailed, mqttStatus );
/* Initialize context. */
mqttStatus = MQTT_Init( &context, &transport, getTime, eventCallback, &networkBuffer );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
context.connectStatus = MQTTConnected;
/* Verify MQTTBadParameter is propagated when getting PINGREQ packet size fails. */
MQTT_GetPingreqPacketSize_ExpectAnyArgsAndReturn( MQTTBadParameter );
MQTT_GetPingreqPacketSize_ReturnThruPtr_pPacketSize( &pingreqSize );
/* Expect the above calls when running MQTT_Ping. */
mqttStatus = MQTT_Ping( &context );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
/**
* @brief Test MQTT_MatchTopic for invalid input parameters.
*/
void test_MQTT_MatchTopic_InvalidInput( void )
{
bool matchResult = false;
/* NULL topic name. */
TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( NULL,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid topic name length. */
TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
0u,
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* NULL topic filter. */
TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
NULL,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid topic filter length. */
TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
MQTT_SAMPLE_TOPIC_FILTER,
0u,
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid output parameter. */
TEST_ASSERT_EQUAL( MQTTBadParameter, MQTT_MatchTopic( MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
NULL ) );
}
/**
* @brief Verifies that MQTT_MatchTopic is able to determine an exact match between the
* topic name and topic filter.
*/
void test_MQTT_MatchTopic_ExactMatch( void )
{
const char * pTopicFilter = NULL;
const char * pTopicName = NULL;
bool matchResult = false;
/* Test for topic filter and topic name having exact match. */
pTopicName = "/test/match";
pTopicFilter = "/test/match";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test for exact match when topic name and filter start with '$' .*/
pTopicName = "$///";
pTopicFilter = "$///";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test for no match (with no wildcard in the topic filter). */
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
MQTT_SAMPLE_TOPIC_FILTER,
MQTT_SAMPLE_TOPIC_FILTER_LENGTH,
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Edge case tests (for branch coverage) to match at end with no wildcards. */
pTopicName = "/test/match/";
pTopicFilter = "/test/match/a";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
pTopicName = "a";
pTopicFilter = "a/";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Edge case test (for branch coverage) when topic name has more levels
* than topic filter. */
pTopicName = "test/match";
pTopicFilter = "test";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
}
/**
* @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification of all
* cases of matching topic filters that contain the single-level '+' wildcard.
*/
void test_MQTT_MatchTopic_Wildcard_SingleLevel_Match_Cases( void )
{
const char * pTopicName = NULL;
const char * pTopicFilter = NULL;
bool matchResult = false;
/* Nominal case of topic filter ending with '+' .*/
pTopicName = "/test/match/level1";
pTopicFilter = "/test/match/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test for match with a topic name starting with '$' .*/
pTopicName = "$test/match/level1";
pTopicFilter = "$test/match/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test with '+' as the topic filter. */
pTopicName = "test";
pTopicFilter = "+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test that '+' in topic filter matches topic name containing consecutive
* level separators, "//" in the corresponding level. */
pTopicName = "/test//level1";
pTopicFilter = "/test/+/level1";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test with multiple placements of wildcard in topic filter. */
pTopicName = "/test/match/level1";
pTopicFilter = "/+/match/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
pTopicName = "/test/match/level1";
pTopicFilter = "+/+/+/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
pTopicName = "/test///level1";
pTopicFilter = "/test/+/+/level1";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test that match fails when topic name has more levels than topic filter. */
pTopicName = "/test/match/level1/level2";
pTopicFilter = "/test/match/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
pTopicName = "/";
pTopicFilter = "+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Edge case where filter ending with '/+' matches topic ending with '/'. */
pTopicName = "/test/match/";
pTopicFilter = "/test/match/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
}
/**
* @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification for
* cases of where topic filter containing '+' wildcard do not match topic name.
*/
void test_MQTT_MatchTopic_Wildcard_SingleLevel_No_Match_Cases( void )
{
const char * pTopicName = NULL;
const char * pTopicFilter = NULL;
bool matchResult = false;
/* Edge case where filter ending with '/+' should not match a topic ending with
* at parent level. */
pTopicName = "/test/match";
pTopicFilter = "/test/match/+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Edge case where topic filter starts with '+' and topic name starts with '$'. */
pTopicName = "$/test/match";
pTopicFilter = "+/test/match";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Topic name matches all characters with topic filter, but topic filter is invalid. */
pTopicName = "test/match/level";
pTopicFilter = "test/match/level+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid topic filter where non-starting '+' is not placed after '/'.*/
pTopicName = "test/match/level1";
pTopicFilter = "test/match/level+";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid topic filter where intermediate '+' is not followed by '/'.*/
pTopicName = "test/match/level";
pTopicFilter = "test/+?level";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
}
/**
* @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification of all
* cases of matching topic filters that contain the multi-level '#' wildcard.
*/
void test_MQTT_MatchTopic_Wildcard_MultiLevel_Match_Cases( void )
{
const char * pTopicName = NULL;
const char * pTopicFilter = NULL;
bool matchResult = false;
/* Match topic filter ending with '#' with a single level .*/
pTopicName = "/test/match/level1";
pTopicFilter = "/test/match/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Match topic filter ending with '#' with multiple levels in topic name.*/
pTopicName = "/test/match/level1/level2/level3";
pTopicFilter = "/test/match/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
pTopicName = "/test/match/level1/level2/level3";
pTopicFilter = "/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Match when topic filter is "#" */
pTopicName = "test/match/level";
pTopicFilter = "#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test for match with a topic name starting with '$' .*/
pTopicName = "$test/match/level1";
pTopicFilter = "$test/match/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Match '#' with topic name ending at the parent level. */
pTopicName = "/test/match";
pTopicFilter = "/test/match/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Edge case where filter ending with '/#' matches topic ending with '/'. */
pTopicName = "/test/match/";
pTopicFilter = "/test/match/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
/* Test for topic filters containing both '+' and '#' wildcard characters. */
pTopicName = "/test/match";
pTopicFilter = "+/test/match/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
pTopicName = "/test/match/level";
pTopicFilter = "+/+/+/#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( true, matchResult );
}
/**
* @brief Verifies that MQTT_MatchTopic meets the MQTT 3.1.1 specification for
* cases of where topic filter containing '#' wildcard do not match topic name.
*/
void test_MQTT_MatchTopic_Wildcard_MultiLevel_No_Match_Cases( void )
{
const char * pTopicName = NULL;
const char * pTopicFilter = NULL;
bool matchResult = false;
/* Edge case where topic filter starts with '#' and topic name starts with '$'. */
pTopicName = "$/test/match";
pTopicFilter = "#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid topic filter where non-starting '#' is not placed after '/'.*/
pTopicName = "test/match/level1";
pTopicFilter = "test/match/level#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Topic name matches all characters with topic filter, but topic filter is invalid. */
pTopicName = "test/match/level";
pTopicFilter = "test/match/level?#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
pTopicName = "test/match/level";
pTopicFilter = "test/match/level#";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
/* Invalid topic filters that contain '#' at a non-ending position .*/
pTopicName = "test/match/level1/level2";
pTopicFilter = "test/match/#/level2";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
pTopicName = "test/match/level2";
pTopicFilter = "#/match/level2";
TEST_ASSERT_EQUAL( MQTTSuccess, MQTT_MatchTopic( pTopicName,
strlen( pTopicName ),
pTopicFilter,
strlen( pTopicFilter ),
&matchResult ) );
TEST_ASSERT_EQUAL( false, matchResult );
}
/* ========================================================================== */
/**
* @brief Tests that MQTT_GetSubAckStatusCodes works as expected in parsing the
* payload information of a SUBACK packet.
*/
void test_MQTT_GetSubAckStatusCodes( void )
{
MQTTPacketInfo_t mqttPacketInfo = { 0 };
size_t payloadSize;
uint8_t * pPayloadStart;
MQTTStatus_t status = MQTTSuccess;
uint8_t buffer[ 10 ] = { 0 };
buffer[ 0 ] = 0;
buffer[ 1 ] = 1;
buffer[ 2 ] = 0x00;
buffer[ 3 ] = 0x01;
buffer[ 4 ] = 0x02;
buffer[ 5 ] = 0x80;
/* Process a valid SUBACK packet containing whole range of server response codes. */
mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
mqttPacketInfo.pRemainingData = buffer;
mqttPacketInfo.remainingLength = 6;
status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
TEST_ASSERT_EQUAL_INT( MQTTSuccess, status );
TEST_ASSERT_EQUAL_PTR( &buffer[ 2 ], pPayloadStart );
TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos0, pPayloadStart[ 0 ] );
TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos1, pPayloadStart[ 1 ] );
TEST_ASSERT_EQUAL_INT( MQTTSubAckSuccessQos2, pPayloadStart[ 2 ] );
TEST_ASSERT_EQUAL_INT( MQTTSubAckFailure, pPayloadStart[ 3 ] );
TEST_ASSERT_EQUAL_INT( 4, payloadSize );
/* Packet is NULL. */
status = MQTT_GetSubAckStatusCodes( NULL, &pPayloadStart, &payloadSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* Output parameter, pPayloadStart, is NULL. */
status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, NULL, &payloadSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* Output parameter, pPayloadSize, is NULL. */
status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, NULL );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* Remaining Data is NULL. */
mqttPacketInfo.pRemainingData = NULL;
status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* non-SUBACK packet type. */
mqttPacketInfo.type = MQTT_PACKET_TYPE_CONNACK;
mqttPacketInfo.pRemainingData = buffer;
status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
/* Invalid remaining length value in packet. */
mqttPacketInfo.remainingLength = 0;
mqttPacketInfo.type = MQTT_PACKET_TYPE_SUBACK;
status = MQTT_GetSubAckStatusCodes( &mqttPacketInfo, &pPayloadStart, &payloadSize );
TEST_ASSERT_EQUAL_INT( MQTTBadParameter, status );
}
/* ========================================================================== */
/**
* @brief Test MQTT_Status_strerror returns correct strings.
*/
void test_MQTT_Status_strerror( void )
{
MQTTStatus_t status;
const char * str = NULL;
status = MQTTSuccess;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTSuccess", str );
status = MQTTBadParameter;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTBadParameter", str );
status = MQTTNoMemory;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTNoMemory", str );
status = MQTTSendFailed;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTSendFailed", str );
status = MQTTRecvFailed;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTRecvFailed", str );
status = MQTTBadResponse;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTBadResponse", str );
status = MQTTServerRefused;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTServerRefused", str );
status = MQTTNoDataAvailable;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTNoDataAvailable", str );
status = MQTTIllegalState;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTIllegalState", str );
status = MQTTStateCollision;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTStateCollision", str );
status = MQTTKeepAliveTimeout;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTKeepAliveTimeout", str );
status = MQTTNeedMoreBytes;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTNeedMoreBytes", str );
status = MQTTStatusConnected;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTStatusConnected", str );
status = MQTTStatusNotConnected;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTStatusNotConnected", str );
status = MQTTStatusDisconnectPending;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTStatusDisconnectPending", str );
status = MQTTPublishStoreFailed;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTPublishStoreFailed", str );
status = MQTTPublishRetrieveFailed;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "MQTTPublishRetrieveFailed", str );
status = MQTTPublishRetrieveFailed + 1;
str = MQTT_Status_strerror( status );
TEST_ASSERT_EQUAL_STRING( "Invalid MQTT Status code", str );
}
/* ========================================================================== */
void test_MQTT_GetPacketId_NULL_Context( void )
{
uint16_t packetId = 0U;
packetId = MQTT_GetPacketId( NULL );
TEST_ASSERT_EQUAL( 0, packetId );
}
/* ========================================================================== */
void test_MQTT_GetPacketId_happy_path( void )
{
uint16_t packetId = 0U;
MQTTContext_t mqttContext = { 0 };
mqttContext.nextPacketId = 5;
packetId = MQTT_GetPacketId( &mqttContext );
TEST_ASSERT_EQUAL( 5, packetId );
TEST_ASSERT_EQUAL( 6, mqttContext.nextPacketId );
}
/* ========================================================================== */
void test_MQTT_GetPacketId_happy_path_uint16_max( void )
{
uint16_t packetId = 0U;
MQTTContext_t mqttContext = { 0 };
mqttContext.nextPacketId = UINT16_MAX;
packetId = MQTT_GetPacketId( &mqttContext );
TEST_ASSERT_EQUAL( UINT16_MAX, packetId );
TEST_ASSERT_EQUAL( 1, mqttContext.nextPacketId );
}
/* ========================================================================== */
void test_MQTT_CancelCallback_null_context( void )
{
uint16_t packetId = 0U;
MQTTStatus_t mqttStatus;
mqttStatus = MQTT_CancelCallback( NULL, packetId );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_CancelCallback_null_outgoingPublishRecords( void )
{
uint16_t packetId = 0U;
MQTTStatus_t mqttStatus;
MQTTContext_t mqttContext = { 0 };
mqttContext.outgoingPublishRecords = NULL;
mqttStatus = MQTT_CancelCallback( &mqttContext, packetId );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_CancelCallback_happy_path( void )
{
uint16_t packetId = 0U;
MQTTStatus_t mqttStatus;
MQTTContext_t mqttContext = { 0 };
mqttContext.outgoingPublishRecords = NULL;
setUPContext( &mqttContext );
MQTT_RemoveStateRecord_ExpectAndReturn( &mqttContext, packetId, MQTTSuccess );
mqttStatus = MQTT_CancelCallback( &mqttContext, packetId );
TEST_ASSERT_EQUAL( MQTTSuccess, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_InitStatefulQoS_fail_null_context( void )
{
MQTTStatus_t mqttStatus;
MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
mqttStatus = MQTT_InitStatefulQoS( NULL,
pOutgoingPublishRecords,
10,
pIncomingPublishRecords,
10 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_InitStatefulQoS_zero_outgoing_size( void )
{
MQTTStatus_t mqttStatus;
MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
MQTTContext_t mqttContext = { 0 };
mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
pOutgoingPublishRecords,
0,
pIncomingPublishRecords,
10 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_InitStatefulQoS_zero_incoming_size( void )
{
MQTTStatus_t mqttStatus;
MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
MQTTContext_t mqttContext = { 0 };
mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
pOutgoingPublishRecords,
10,
pIncomingPublishRecords,
0 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_InitStatefulQoS_callback_is_null( void )
{
MQTTStatus_t mqttStatus;
MQTTPubAckInfo_t pOutgoingPublishRecords[ 10 ] = { 0 };
MQTTPubAckInfo_t pIncomingPublishRecords[ 10 ] = { 0 };
MQTTContext_t mqttContext = { 0 };
mqttContext.appCallback = NULL;
mqttStatus = MQTT_InitStatefulQoS( &mqttContext,
pOutgoingPublishRecords,
10,
pIncomingPublishRecords,
10 );
TEST_ASSERT_EQUAL( MQTTBadParameter, mqttStatus );
}
/* ========================================================================== */
void test_MQTT_GetBytesInMQTTVec( void )
{
TransportOutVector_t pTransportArray[ 10 ] =
{
{ .iov_base = NULL, .iov_len = 1 },
{ .iov_base = NULL, .iov_len = 2 },
{ .iov_base = NULL, .iov_len = 3 },
{ .iov_base = NULL, .iov_len = 4 },
{ .iov_base = NULL, .iov_len = 5 },
{ .iov_base = NULL, .iov_len = 6 },
{ .iov_base = NULL, .iov_len = 7 },
{ .iov_base = NULL, .iov_len = 8 },
{ .iov_base = NULL, .iov_len = 9 },
{ .iov_base = NULL, .iov_len = 10 },
};
MQTTVec_t mqttVec;
mqttVec.pVector = pTransportArray;
mqttVec.vectorLen = 10;
size_t ret = MQTT_GetBytesInMQTTVec( &mqttVec );
TEST_ASSERT_EQUAL( 55, ret );
}
/* ========================================================================== */
void test_MQTT_SerializeMQTTVec( void )
{
TransportOutVector_t pTransportArray[ 6 ] =
{
{ .iov_base = "This ", .iov_len = strlen( "This " ) },
{ .iov_base = "is ", .iov_len = strlen( "is " ) },
{ .iov_base = "a ", .iov_len = strlen( "a " ) },
{ .iov_base = "coreMQTT ", .iov_len = strlen( "coreMQTT " ) },
{ .iov_base = "unit-test ", .iov_len = strlen( "unit-test " ) },
{ .iov_base = "string.", .iov_len = strlen( "string." ) }
};
uint8_t array[ 50 ] = { 0 };
MQTTVec_t mqttVec;
mqttVec.pVector = pTransportArray;
mqttVec.vectorLen = 6;
MQTT_SerializeMQTTVec( array, &mqttVec );
TEST_ASSERT_EQUAL_MEMORY( "This is a coreMQTT unit-test string.", array, strlen( "This is a coreMQTT unit-test string." ) );
TEST_ASSERT_EQUAL_MEMORY( "\0\0\0\0\0\0\0\0\0\0\0\0\0", &array[ 37 ], 13 );
}