Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more unit tests for coverage #175

Merged
merged 7 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ jobs:
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
with:
coverage-file: ./build/coverage.info
branch-coverage-min: 100
line-coverage-min: 100

complexity:
runs-on: ubuntu-latest
Expand Down
153 changes: 139 additions & 14 deletions test/unit-test/core_http_send_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@

/* HTTP OK Status-Line. */
#define HTTP_STATUS_LINE_OK "HTTP/1.1 200 OK\r\n"
#define HTTP_STATUS_LINE_NO_REASON_PHRASE "HTTP/1.1 200\r\n"
#define HTTP_STATUS_CODE_OK 200

/* Various header lines for test response templates. */
Expand Down Expand Up @@ -103,11 +104,26 @@
HTTP_TEST_VARY_HEADER_LINE \
HTTP_TEST_P3P_HEADER_LINE \
HTTP_TEST_XSERVER_HEADER_LINE HTTP_HEADER_LINE_SEPARATOR
#define HTTP_TEST_RESPONSE_HEAD_LENGTH ( sizeof( HTTP_TEST_RESPONSE_HEAD ) - 1U )
#define HTTP_TEST_RESPONSE_HEAD_HEADER_COUNT 7
#define HTTP_TEST_RESPONSE_HEAD_CONTENT_LENGTH 43
#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_FIELD_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_FIELD ) - 2U )
#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_VALUE_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_VALUE ) - 2U )
#define HTTP_TEST_RESPONSE_HEAD_LENGTH ( sizeof( HTTP_TEST_RESPONSE_HEAD ) - 1U )
#define HTTP_TEST_RESPONSE_HEAD_HEADER_COUNT 7
#define HTTP_TEST_RESPONSE_HEAD_CONTENT_LENGTH 43
#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_FIELD_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_FIELD ) - 2U )
#define HTTP_TEST_RESPONSE_HEAD_PARTIAL_HEADER_VALUE_LENGTH ( sizeof( HTTP_STATUS_LINE_OK ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_VALUE ) - 2U )

#define HTTP_TEST_RESPONSE_HEAD_2 \
HTTP_STATUS_LINE_NO_REASON_PHRASE \
HTTP_TEST_CONTENT_LENGTH_HEADER_LINE \
HTTP_TEST_CONNECTION_CLOSE_HEADER_LINE \
HTTP_TEST_DATE_HEADER_LINE \
HTTP_TEST_ETAG_HEADER_LINE \
HTTP_TEST_VARY_HEADER_LINE \
HTTP_TEST_P3P_HEADER_LINE \
HTTP_TEST_XSERVER_HEADER_LINE HTTP_HEADER_LINE_SEPARATOR
#define HTTP_TEST_RESPONSE_HEAD_2_LENGTH ( sizeof( HTTP_TEST_RESPONSE_HEAD_2 ) - 1U )
#define HTTP_TEST_RESPONSE_HEAD_2_HEADER_COUNT 7
#define HTTP_TEST_RESPONSE_HEAD_2_CONTENT_LENGTH 43
#define HTTP_TEST_RESPONSE_HEAD_2_PARTIAL_HEADER_FIELD_LENGTH ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_FIELD ) - 2U )
#define HTTP_TEST_RESPONSE_HEAD_2_PARTIAL_HEADER_VALUE_LENGTH ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) + sizeof( HTTP_TEST_CONTENT_LENGTH_PARTIAL_HEADER_VALUE ) - 2U )

/* Template HTTP PUT response. This has no body. */
#define HTTP_TEST_RESPONSE_PUT \
Expand Down Expand Up @@ -235,6 +251,9 @@ static HTTPRequestHeaders_t requestHeaders = { 0 };
/* Header parsing callback shared among the tests. */
static HTTPClient_ResponseHeaderParsingCallback_t headerParsingCallback = { 0 };

/* Flag to indicate this callback is called. */
static int statusCompleteCallbackFlag = 0;

/* A mocked timer query function that increments on every call. */
static uint32_t getTestTime( void )
{
Expand Down Expand Up @@ -432,6 +451,7 @@ static void helper_parse_status_line( const char ** pNext,
const llhttp_settings_t * pSettings )
{
const char * pReasonPhraseStart = NULL;
const char * pNextLineStart = NULL;
size_t reasonPhraseStartLen = 0;

/* For purposes of unit testing the response is well formed in the non-error
Expand All @@ -440,17 +460,36 @@ static void helper_parse_status_line( const char ** pNext,
* always string literals. strchr() should not be used in application code. */
*pNext = strchr( *pNext, SPACE_CHARACTER ); /* Get the space before the status-code. */
*pNext += SPACE_CHARACTER_LEN;
*pNext = strchr( *pNext, SPACE_CHARACTER ); /* Get the space before the reason-phrase. */
*pNext += SPACE_CHARACTER_LEN;
pReasonPhraseStart = *pNext;
*pNext = strstr( *pNext, HTTP_HEADER_LINE_SEPARATOR );
reasonPhraseStartLen = ( size_t ) ( *pNext - pReasonPhraseStart );
/* pNext points to the status code now. */

pReasonPhraseStart = strchr( *pNext, SPACE_CHARACTER );
pReasonPhraseStart = &( pReasonPhraseStart[ SPACE_CHARACTER_LEN ] );

pNextLineStart = strstr( *pNext, HTTP_HEADER_LINE_SEPARATOR );
pNextLineStart = &( pNextLineStart[ HTTP_HEADER_LINE_SEPARATOR_LEN ] );

pParser->status_code = 200;
pSettings->on_status( pParser,
pReasonPhraseStart,
reasonPhraseStartLen );

*pNext += HTTP_HEADER_LINE_SEPARATOR_LEN;
/* Check if the reason phrase exist in the header and call the corresponding callback.
* Reason phrase "OK" exists in the response "HTTP/1.1 200 OK\r\n". The callback
* on_status is called.
* Reason phrase doesn't exist in the response "HTTP/1.1 200\r\n". The callback
* on_status_complete is called. */
if( pNextLineStart > pReasonPhraseStart )
{
reasonPhraseStartLen = ( size_t ) ( pNextLineStart - pReasonPhraseStart );
reasonPhraseStartLen = reasonPhraseStartLen - HTTP_HEADER_LINE_SEPARATOR_LEN;
pSettings->on_status( pParser,
pReasonPhraseStart,
reasonPhraseStartLen );
*pNext = pNextLineStart;
}
else
{
statusCompleteCallbackFlag = 1;
pSettings->on_status_complete( pParser );
*pNext = pNextLineStart;
}
}

/* Mock helper that parses all of the headers starting from pNext. */
Expand Down Expand Up @@ -805,6 +844,7 @@ void setUp( void )
response.pBuffer = httpBuffer;
response.bufferLen = sizeof( httpBuffer );
response.pHeaderParsingCallback = &headerParsingCallback;
statusCompleteCallbackFlag = 0;

/* Ignore third-party init functions that return void. */
llhttp_init_Ignore();
Expand Down Expand Up @@ -846,6 +886,72 @@ void test_HTTPClient_Send_HEAD_request_parse_whole_response( void )

/*-----------------------------------------------------------*/

/* Test successfully parsing a response to a HEAD request. The full response
* message is present in the response buffer on the first network read. */
void test_HTTPClient_Send_HEAD_request_no_parse_body( void )
{
HTTPStatus_t returnStatus = HTTPSuccess;

llhttp_execute_Stub( llhttp_execute_whole_response );

response.respOptionFlags |= HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG;

returnStatus = HTTPClient_Send( &transportInterface,
&requestHeaders,
NULL,
0,
&response,
0 );
TEST_ASSERT_EQUAL( HTTPSuccess, returnStatus );
TEST_ASSERT_EQUAL( NULL, response.pBody );
TEST_ASSERT_EQUAL( 0U, response.bodyLen );
TEST_ASSERT_EQUAL( response.pBuffer + ( sizeof( HTTP_STATUS_LINE_OK ) - 1U ), response.pHeaders );
TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_LENGTH - ( sizeof( HTTP_STATUS_LINE_OK ) - 1U ) - HTTP_HEADER_END_INDICATOR_LEN,
response.headersLen );
TEST_ASSERT_EQUAL( HTTP_STATUS_CODE_OK, response.statusCode );
TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_CONTENT_LENGTH, response.contentLength );
TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_HEADER_COUNT, response.headerCount );
TEST_ASSERT_BITS_HIGH( HTTP_RESPONSE_CONNECTION_CLOSE_FLAG, response.respFlags );
TEST_ASSERT_BITS_LOW( HTTP_RESPONSE_CONNECTION_KEEP_ALIVE_FLAG, response.respFlags );
}

/*-----------------------------------------------------------*/

/* Test successfully parsing a response to a HEAD request. The full response
* message is present in the response buffer on the first network read. The response
* contains a status code but without a reason string. The on_status_complete is called
* in this case. */
void test_HTTPClient_Send_HEAD_request_parse_whole_response_no_reason_string( void )
{
HTTPStatus_t returnStatus = HTTPSuccess;

pNetworkData = ( uint8_t * ) HTTP_TEST_RESPONSE_HEAD_2;
networkDataLen = HTTP_TEST_RESPONSE_HEAD_2_LENGTH;

llhttp_execute_Stub( llhttp_execute_whole_response );

returnStatus = HTTPClient_Send( &transportInterface,
&requestHeaders,
NULL,
0,
&response,
0 );
TEST_ASSERT_EQUAL( HTTPSuccess, returnStatus );
TEST_ASSERT_EQUAL( NULL, response.pBody );
TEST_ASSERT_EQUAL( 0U, response.bodyLen );
TEST_ASSERT_EQUAL( response.pBuffer + ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) - 1U ), response.pHeaders );
TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_2_LENGTH - ( sizeof( HTTP_STATUS_LINE_NO_REASON_PHRASE ) - 1U ) - HTTP_HEADER_END_INDICATOR_LEN,
response.headersLen );
TEST_ASSERT_EQUAL( HTTP_STATUS_CODE_OK, response.statusCode );
TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_2_CONTENT_LENGTH, response.contentLength );
TEST_ASSERT_EQUAL( HTTP_TEST_RESPONSE_HEAD_2_HEADER_COUNT, response.headerCount );
TEST_ASSERT_BITS_HIGH( HTTP_RESPONSE_CONNECTION_CLOSE_FLAG, response.respFlags );
TEST_ASSERT_BITS_LOW( HTTP_RESPONSE_CONNECTION_KEEP_ALIVE_FLAG, response.respFlags );
TEST_ASSERT_EQUAL( 1, statusCompleteCallbackFlag );
}

/*-----------------------------------------------------------*/

/* Test successfully parsing a response to a PUT request. The full response
* message is present in the response buffer on the first network read. */
void test_HTTPClient_Send_PUT_request_parse_whole_response( void )
Expand Down Expand Up @@ -1757,6 +1863,25 @@ void test_HTTPClient_Send_parsing_errors( void )
0 );
TEST_ASSERT_EQUAL( HTTPSecurityAlertInvalidContentLength, returnStatus );

httpParsingErrno = HPE_PAUSED;
returnStatus = HTTPClient_Send( &transportInterface,
&requestHeaders,
NULL,
0,
&response,
0 );
TEST_ASSERT_EQUAL( HTTPParserPaused, returnStatus );

httpParsingErrno = HPE_PAUSED;
response.respOptionFlags |= HTTP_RESPONSE_DO_NOT_PARSE_BODY_FLAG;
returnStatus = HTTPClient_Send( &transportInterface,
&requestHeaders,
NULL,
0,
&response,
0 );
TEST_ASSERT_EQUAL( HTTPNoResponse, returnStatus );

/* Use -1 to indicate an unknown error. */
httpParsingErrno = -1;
returnStatus = HTTPClient_Send( &transportInterface,
Expand Down
50 changes: 50 additions & 0 deletions test/unit-test/core_http_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ typedef struct _headers
"%s: %s\r\n" \
"%s: %s\r\n\r\n"

#define HTTP_TEST_HEADER_NO_USER_AGENT_FORMAT \
"%s %s %s\r\n" \
"%s: %s\r\n\r\n"

#define HTTP_TEST_EXTRA_HEADER_FORMAT \
"%s %s %s\r\n" \
"%s: %s\r\n" \
Expand All @@ -94,6 +98,19 @@ typedef struct _headers
HTTP_TEST_HOST_VALUE_LEN + HTTP_HEADER_LINE_SEPARATOR_LEN + \
HTTP_HEADER_LINE_SEPARATOR_LEN )

/* Length of the following template HTTP header.
* <HTTP_METHOD_GET> <HTTP_TEST_REQUEST_PATH> <HTTP_PROTOCOL_VERSION> \r\n
* <HTTP_HOST_FIELD>: <HTTP_TEST_HOST_VALUE> \r\n
* \r\n
* This is used to initialize the expectedHeader string. */
#define HTTP_TEST_PREFIX_HEADER_NO_USER_AGENT_LEN \
( HTTP_METHOD_GET_LEN + SPACE_CHARACTER_LEN + \
HTTP_TEST_REQUEST_PATH_LEN + SPACE_CHARACTER_LEN + \
HTTP_PROTOCOL_VERSION_LEN + HTTP_HEADER_LINE_SEPARATOR_LEN + \
HTTP_HOST_FIELD_LEN + HTTP_HEADER_FIELD_SEPARATOR_LEN + \
HTTP_TEST_HOST_VALUE_LEN + HTTP_HEADER_LINE_SEPARATOR_LEN + \
HTTP_HEADER_LINE_SEPARATOR_LEN )

/* Add 1 because snprintf(...) writes a null byte at the end. */
#define HTTP_TEST_INITIALIZED_HEADER_BUFFER_LEN \
( HTTP_TEST_PREFIX_HEADER_LEN + 1 )
Expand Down Expand Up @@ -472,6 +489,39 @@ void test_Http_InitializeRequestHeaders_Happy_Path()
expectedHeaders.dataLen );
}

/**
* @brief Test happy path with HTTP_REQUEST_NO_USER_AGENT_FLAG.
*/
void test_Http_InitializeRequestHeaders_no_user_agent_flag()
{
HTTPStatus_t httpStatus = HTTPSuccess;
HTTPRequestHeaders_t requestHeaders = { 0 };
HTTPRequestInfo_t requestInfo = { 0 };
int numBytes = 0;

setupRequestInfo( &requestInfo );
requestInfo.reqFlags |= HTTP_REQUEST_NO_USER_AGENT_FLAG;

expectedHeaders.dataLen = HTTP_TEST_PREFIX_HEADER_NO_USER_AGENT_LEN;
setupBuffer( &requestHeaders );

/* Happy Path testing. */
numBytes = snprintf( ( char * ) expectedHeaders.buffer, sizeof( expectedHeaders.buffer ),
HTTP_TEST_HEADER_NO_USER_AGENT_FORMAT,
HTTP_METHOD_GET, HTTP_TEST_REQUEST_PATH,
HTTP_PROTOCOL_VERSION,
HTTP_HOST_FIELD, HTTP_TEST_HOST_VALUE );
/* Make sure that the entire pre-existing data was printed to the buffer. */
TEST_ASSERT_GREATER_THAN( 0, numBytes );
TEST_ASSERT_LESS_THAN( sizeof( expectedHeaders.buffer ), ( size_t ) numBytes );

httpStatus = HTTPClient_InitializeRequestHeaders( &requestHeaders, &requestInfo );
TEST_ASSERT_EQUAL( HTTPSuccess, httpStatus );
TEST_ASSERT_EQUAL( expectedHeaders.dataLen, requestHeaders.headersLen );
TEST_ASSERT_EQUAL_MEMORY( expectedHeaders.buffer, requestHeaders.pBuffer,
expectedHeaders.dataLen );
}

/**
* @brief Test NULL parameters, following order of else-if blocks in the HTTP library.
*/
Expand Down
Loading