diff --git a/README.md b/README.md index 8822f11..98e2b66 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## backOffAlgorithm Library +## backoffAlgorithm Library This repository contains the backoffAlgorithm library, a utility library to calculate backoff period for network operation retries (like failed network connection with server) using an exponential backoff with jitter algorithm. The backoffAlgorithm library is distributed under the [MIT Open Source License](LICENSE). @@ -22,6 +22,7 @@ The example below shows how to use the backoffAlgorithm library to retry a DNS r #include #include #include +#include /* The maximum number of retries for the example code. */ #define RETRY_MAX_ATTEMPTS ( 5U ) @@ -32,28 +33,6 @@ The example below shows how to use the backoffAlgorithm library to retry a DNS r /* The base back-off delay (in milliseconds) for retry configuration in the example. */ #define RETRY_BACKOFF_BASE_MS ( 500U ) -/** - * A random number generator to provide to the backoffAlgorithm - * library. - * - * This function is used in the exponential backoff with jitter algorithm - * to calculate the backoff value for the next retry attempt. - * - * It is recommended to either use a True Random Number Generator (TRNG) for - * calculation of unique back-off values in devices so that collision between - * devices attempting retries at the same intervals can be avoided. - * - * For the simplicity of the code example, this function is a pseudo - * random number generator. - * - * @return The generated random number. This example function ALWAYS succeeds - * in generating a random number. - */ -static int32_t pseudoRng() -{ - return( rand() % ( INT32_MAX ) ); -} - int main() { /* Variables used in this example. */ @@ -65,6 +44,7 @@ int main() int32_t dnsStatus = -1; struct addrinfo hints; struct addrinfo ** pListHead; + struct timespec tp; /* Add hints to retrieve only TCP sockets in getaddrinfo. */ ( void ) memset( &hints, 0, sizeof( hints ) ); @@ -77,10 +57,19 @@ int main() /* Initialize reconnect attempts and interval. */ BackoffAlgorithm_InitializeParams( &retryParams, - RETRY_BACKOFF_BASE_MS, - RETRY_MAX_BACKOFF_DELAY_MS, - RETRY_MAX_ATTEMPTS, - pseudoRng ); + RETRY_BACKOFF_BASE_MS, + RETRY_MAX_BACKOFF_DELAY_MS, + RETRY_MAX_ATTEMPTS ); + + + /* Seed the pseudo random number generator used in this example (with call to + * rand() function provided by ISO C standard library) for use in backoff period + * calculation when retrying failed DNS resolution. */ + + /* Get current time to seed pseudo random number generator. */ + ( void ) clock_gettime( CLOCK_REALTIME, &tp ); + /* Seed pseudo random number generator with seconds. */ + srand( tp.tv_sec ); do { @@ -90,8 +79,14 @@ int main() /* Retry if DNS resolution query failed. */ if( dnsStatus != 0 ) { - /* Get back-off value (in milliseconds) for the next retry. */ - retryStatus = BackoffAlgorithm_GetNextBackoff( &retryParams, &nextRetryBackOff ); + /* Generate a random number and get back-off value (in milliseconds) for the next retry. + * Note: It is recommended to use a random number generator that is seeded with + * device-specific entropy source so that backoff calculation in devices is different + * and possibility of network collision between devices attempting retries can be avoided. + * + * For the simplicity of the code example, the pseudo random number generator, rand() function + * is used. */ + retryStatus = BackoffAlgorithm_GetNextBackoff( &retryParams, rand(), &nextRetryBackOff ); } } while( ( dnsStatus != 0 ) && ( retryStatus != BackoffAlgorithmRetriesExhausted ) ); diff --git a/docs/doxygen/pages.dox b/docs/doxygen/pages.dox index 3d15406..b928771 100644 --- a/docs/doxygen/pages.dox +++ b/docs/doxygen/pages.dox @@ -36,7 +36,7 @@ For a reference example of using the library, refer to the related README sectio - + @@ -46,9 +46,9 @@ For a reference example of using the library, refer to the related README sectio - - - + + +
Code size of backoffAlgorithm library files (sizes generated with [GCC for ARM Cortex-M toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update))
Code size (in bytes) of backoffAlgorithm library files (sizes generated with [GCC for ARM Cortex-M toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads/9-2020-q2-update))
File
backoff_algorithm.c0.6K0.2K0.2K678140136
@@ -61,13 +61,12 @@ All functions in the backoffAlgorithm library operate only on the buffer provide local variables on the stack.

-

Random Number Generator

+

Random Number Generation

-The library requires a platform-specific random number generator for the "jitter" -part of the algorithm when generating the next backoff value. To avoid calculation -of the same random numbers across your fleet of devices attempting retry of network -operations, it is RECOMMENDED to provide a random number generator that is seeded with -an entropy source unique to the device. +The library takes a random number each time it calculates the backoff period value for the +retry attempt. To avoid calculation of the same random numbers across your fleet of devices +attempting retry of network operations, it is RECOMMENDED to generate the random number with +a random number generator that is seeded with an entropy source unique to the device.

Compliance & Coverage

diff --git a/lexicon.txt b/lexicon.txt index 292e85a..dfd4203 100644 --- a/lexicon.txt +++ b/lexicon.txt @@ -2,7 +2,11 @@ api apis aws backoff +backoff backoffalgorithm +backoffalgorithmretriesexhausted +backoffalgorithmrngfailure +backoffalgorithmsuccess backoffbase br com @@ -13,6 +17,7 @@ getaddrinfo https ifndef inc +ingroup iot longjmp maxattempts @@ -21,20 +26,17 @@ min mockrng noninfringement param +pcontext pnextbackoff pretrycontext pretryparams prng -backoffalgorithmretriesexhausted -backoffalgorithmrngfailure -backoffalgorithmsuccess +randomvalue rng sdk shouldn stderr sublicense tcp -utils -ingroup -backoff -pcontext \ No newline at end of file +trng +utils \ No newline at end of file diff --git a/source/backoff_algorithm.c b/source/backoff_algorithm.c index 6d1132c..db66ad8 100644 --- a/source/backoff_algorithm.c +++ b/source/backoff_algorithm.c @@ -36,10 +36,10 @@ /*-----------------------------------------------------------*/ BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContext_t * pRetryContext, + uint32_t randomValue, uint16_t * pNextBackOff ) { BackoffAlgorithmStatus_t status = BackoffAlgorithmSuccess; - int32_t randomVal = 0; assert( pRetryContext != NULL ); assert( pNextBackOff != NULL ); @@ -48,34 +48,24 @@ BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContex if( ( pRetryContext->attemptsDone < pRetryContext->maxRetryAttempts ) || ( pRetryContext->maxRetryAttempts == BACKOFF_ALGORITHM_RETRY_FOREVER ) ) { - /* Generate a random number. */ - randomVal = pRetryContext->pRng(); + /* The next backoff value is a random value between 0 and the maximum jitter value + * for the retry attempt. */ - if( randomVal < 0 ) + /* Choose a random value for back-off time between 0 and the max jitter value. */ + *pNextBackOff = ( uint16_t ) ( randomValue % ( pRetryContext->nextJitterMax + 1U ) ); + + /* Increment the retry attempt. */ + pRetryContext->attemptsDone++; + + /* Double the max jitter value for the next retry attempt, only + * if the new value will be less than the max backoff time value. */ + if( pRetryContext->nextJitterMax < ( pRetryContext->maxBackoffDelay / 2U ) ) { - status = BackoffAlgorithmRngFailure; + pRetryContext->nextJitterMax += pRetryContext->nextJitterMax; } else { - /* The next backoff value is a random value between 0 and the maximum jitter value - * for the retry attempt. */ - - /* Choose a random value for back-off time between 0 and the max jitter value. */ - *pNextBackOff = ( uint16_t ) ( randomVal % ( pRetryContext->nextJitterMax + 1U ) ); - - /* Increment the retry attempt. */ - pRetryContext->attemptsDone++; - - /* Double the max jitter value for the next retry attempt, only - * if the new value will be less than the max backoff time value. */ - if( pRetryContext->nextJitterMax < ( pRetryContext->maxBackOffDelay / 2U ) ) - { - pRetryContext->nextJitterMax += pRetryContext->nextJitterMax; - } - else - { - pRetryContext->nextJitterMax = pRetryContext->maxBackOffDelay; - } + pRetryContext->nextJitterMax = pRetryContext->maxBackoffDelay; } } else @@ -94,17 +84,15 @@ BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContex void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext, uint16_t backOffBase, uint16_t maxBackOff, - uint32_t maxAttempts, - BackoffAlgorithm_RNG_t pRng ) + uint32_t maxAttempts ) { assert( pContext != NULL ); /* Initialize the context with parameters used in calculating the backoff * value for the next retry attempt. */ pContext->nextJitterMax = backOffBase; - pContext->maxBackOffDelay = maxBackOff; + pContext->maxBackoffDelay = maxBackOff; pContext->maxRetryAttempts = maxAttempts; - pContext->pRng = pRng; /* The total number of retry attempts is zero at initialization. */ pContext->attemptsDone = 0; diff --git a/source/include/backoff_algorithm.h b/source/include/backoff_algorithm.h index c15a22c..6dab41e 100644 --- a/source/include/backoff_algorithm.h +++ b/source/include/backoff_algorithm.h @@ -42,20 +42,6 @@ */ #define BACKOFF_ALGORITHM_RETRY_FOREVER 0 -/** - * @brief Interface for a random number generator. - * The user should supply the platform-specific random number generator to the - * library through the @ref BackoffAlgorithm_InitializeParams API function. - * - * @note It is recommended that a true random number generator is supplied - * to the library. The random number generator should be seeded with an entropy - * source in the system. - * - * @return The random number if successful; otherwise a negative value to indicate - * failure. - */ -typedef int32_t ( * BackoffAlgorithm_RNG_t )(); - /** * @ingroup backoff_algorithm_enum_types * @brief Status for @ref BackoffAlgorithm_GetNextBackoff. @@ -63,7 +49,6 @@ typedef int32_t ( * BackoffAlgorithm_RNG_t )(); typedef enum BackoffAlgorithmStatus { BackoffAlgorithmSuccess = 0, /**< @brief The function successfully calculated the next back-off value. */ - BackoffAlgorithmRngFailure = 1, /**< @brief The function encountered failure in generating random number. */ BackoffAlgorithmRetriesExhausted /**< @brief The function exhausted all retry attempts. */ } BackoffAlgorithmStatus_t; @@ -77,7 +62,7 @@ typedef struct BackoffAlgorithmContext /** * @brief The maximum backoff delay (in milliseconds) between consecutive retry attempts. */ - uint16_t maxBackOffDelay; + uint16_t maxBackoffDelay; /** * @brief The total number of retry attempts completed. @@ -94,12 +79,6 @@ typedef struct BackoffAlgorithmContext * @brief The maximum number of retry attempts. */ uint32_t maxRetryAttempts; - - /** - * @brief The random number generator function used for calculating the - * backoff value for the next retry attempt. - */ - BackoffAlgorithm_RNG_t pRng; } BackoffAlgorithmContext_t; /** @@ -115,15 +94,12 @@ typedef struct BackoffAlgorithmContext * use in the exponential backoff and jitter model. * @param[in] maxAttempts The maximum number of retry attempts. Set the value to * #BACKOFF_ALGORITHM_RETRY_FOREVER to retry for ever. - * @param[in] pRng The platform-specific function to use for random number generation. - * The random number generator should be seeded before calling this function. */ /* @[define_backoffalgorithm_initializeparams] */ void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext, uint16_t backOffBase, uint16_t maxBackOff, - uint32_t maxAttempts, - BackoffAlgorithm_RNG_t pRng ); + uint32_t maxAttempts ); /* @[define_backoffalgorithm_initializeparams] */ /** @@ -135,15 +111,22 @@ void BackoffAlgorithm_InitializeParams( BackoffAlgorithmContext_t * pContext, * * @param[in, out] pRetryContext Structure containing parameters for the next backoff * value calculation. + * @param[in] randomValue The random value to use for calculation of the backoff period. + * The random value should be in the range of [0, UINT32_MAX]. * @param[out] pNextBackOff This will be populated with the backoff value (in milliseconds) * for the next retry attempt. The value does not exceed the maximum backoff delay * configured in the context. * - * @return #BackoffAlgorithmSuccess after a successful sleep, #BackoffAlgorithmRngFailure for a failure - * in random number generation, #BackoffAlgorithmRetriesExhausted when all attempts are exhausted. + * @note For generating a random number, it is recommended to use a Random Number Generator + * that is seeded with a device-specific entropy source so that possibility of collisions + * between multiple devices retrying the network operations can be mitigated. + * + * @return #BackoffAlgorithmSuccess after a successful sleep; + * #BackoffAlgorithmRetriesExhausted when all attempts are exhausted. */ /* @[define_backoffalgorithm_getnextbackoff] */ BackoffAlgorithmStatus_t BackoffAlgorithm_GetNextBackoff( BackoffAlgorithmContext_t * pRetryContext, + uint32_t randomValue, uint16_t * pNextBackOff ); /* @[define_backoffalgorithm_getnextbackoff] */ diff --git a/test/unit-test/backoff_algorithm_utest.c b/test/unit-test/backoff_algorithm_utest.c index 71f94bc..26fdc36 100644 --- a/test/unit-test/backoff_algorithm_utest.c +++ b/test/unit-test/backoff_algorithm_utest.c @@ -33,9 +33,6 @@ /* Backoff Algorithm library include */ #include "backoff_algorithm.h" -/* Return value of mockRng. */ -static int32_t randomValToReturn; - #define TEST_BACKOFF_BASE_VALUE ( 1000 ) #define TEST_BACKOFF_MAX_VALUE ( 10000 ) #define TEST_MAX_ATTEMPTS ( 5 ) @@ -43,35 +40,27 @@ static int32_t randomValToReturn; static BackoffAlgorithmContext_t retryParams; /* Return value of #BackoffAlgorithm_GetNextBackoff. */ static BackoffAlgorithmStatus_t BackoffAlgorithmStatus; -static uint16_t nextBackOff; - -/** - * @brief A mock random number generator. - */ -static int32_t mockRng() -{ - return randomValToReturn; -} +static uint16_t nextBackoff; +static uint32_t testRandomVal; /* ============================ UNITY FIXTURES ============================ */ /* Called before each test method. */ void setUp() { - /* Initialize context with random number generator that succeeds. */ + /* Initialize context. */ BackoffAlgorithm_InitializeParams( &retryParams, TEST_BACKOFF_BASE_VALUE, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); } /* Called after each test method. */ void tearDown() { - randomValToReturn = 0; + testRandomVal = 0; BackoffAlgorithmStatus = BackoffAlgorithmSuccess; - nextBackOff = 0; + nextBackoff = 0; } /* Called at the beginning of the whole suite. */ @@ -93,15 +82,13 @@ int suiteTearDown( int numFailures ) static void verifyContextData( BackoffAlgorithmContext_t * pContext, uint32_t expectedAttemptsDone, uint16_t expectedNextJitterMax, - uint16_t expectedMaxBackOff, - uint32_t expectedMaxAttempts, - BackoffAlgorithm_RNG_t pExpectedRng ) + uint16_t expectedMaxBackoff, + uint32_t expectedMaxAttempts ) { TEST_ASSERT_EQUAL( expectedNextJitterMax, pContext->nextJitterMax ); TEST_ASSERT_EQUAL( expectedAttemptsDone, pContext->attemptsDone ); TEST_ASSERT_EQUAL( expectedMaxAttempts, pContext->maxRetryAttempts ); - TEST_ASSERT_EQUAL( expectedMaxBackOff, pContext->maxBackOffDelay ); - TEST_ASSERT_EQUAL_PTR( pExpectedRng, pContext->pRng ); + TEST_ASSERT_EQUAL( expectedMaxBackoff, pContext->maxBackoffDelay ); } /** @@ -113,8 +100,7 @@ void test_BackoffAlgorithm_InitializeParams_Invalid_Context( void ) catch_assert( BackoffAlgorithm_InitializeParams( NULL /* Invalid context */, TEST_BACKOFF_BASE_VALUE, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ) ); + TEST_MAX_ATTEMPTS ) ); } /** @@ -126,53 +112,12 @@ void test_BackoffAlgorithm_InitializeParams_Sets_Jitter_Correctly( void ) BackoffAlgorithm_InitializeParams( &retryParams, TEST_BACKOFF_BASE_VALUE, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); verifyContextData( &retryParams, 0, TEST_BACKOFF_BASE_VALUE, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); -} - -/** - * @brief Test that #BackoffAlgorithm_GetNextBackoff returns the expected failure - * and does not update the context data when the random number generator fails. - */ -void test_BackoffAlgorithm_GetNextBackoff_Rng_Failure( void ) -{ - int32_t testNegativeVal[] = { -1, -10 }; - uint iter = 0; - - /* Initialize context with random number generator that fails. */ - BackoffAlgorithm_InitializeParams( &retryParams, - TEST_BACKOFF_BASE_VALUE, - TEST_BACKOFF_MAX_VALUE, - BACKOFF_ALGORITHM_RETRY_FOREVER, - mockRng ); - - /* Test the #BackoffAlgorithm_GetNextBackoff API with the 2 negative values - * from the mock random number generator. */ - - for( ; iter < sizeof( testNegativeVal ) / sizeof( int32_t ); iter++ ) - { - /* Set the random value generated to be negative. */ - randomValToReturn = testNegativeVal[ iter ]; - - /* Make sure that the API function returns RNG failure.*/ - TEST_ASSERT_EQUAL( BackoffAlgorithmRngFailure, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); - - /* Make sure that the context data has not changed as the call to - * BackoffAlgorithm_GetNextBackoff failed. */ - verifyContextData( &retryParams, - 0, - TEST_BACKOFF_BASE_VALUE, - TEST_BACKOFF_MAX_VALUE, - BACKOFF_ALGORITHM_RETRY_FOREVER, - mockRng ); - } + TEST_MAX_ATTEMPTS ); } /** @@ -188,17 +133,17 @@ void test_BackoffAlgorithm_GetNextBackoff_Success_RandVal_Less_Than_Jitter_Max( int iter = 1; uint16_t expectedAttemptsDone = 0; uint16_t expectedNextJitterMax = TEST_BACKOFF_BASE_VALUE; - uint16_t expectedNextBackOff = 0; + uint16_t expectedNextBackoff = 0; for( ; iter < 2; iter++ ) { - /* Set the random value to be generated as a value lower than + /* Set the random value as a value lower than * the jitter max value for the next retry attempt. */ - randomValToReturn = retryParams.nextJitterMax / 2; + testRandomVal = retryParams.nextJitterMax / 2; /* As the random value is less than the max jitter value, the expected * next backoff value should remain the same as the random value. */ - expectedNextBackOff = randomValToReturn; + expectedNextBackoff = testRandomVal; /* The jitter max value should double with the above call for use in next call. */ expectedNextJitterMax *= 2; @@ -210,16 +155,15 @@ void test_BackoffAlgorithm_GetNextBackoff_Success_RandVal_Less_Than_Jitter_Max( /* Call the BackoffAlgorithm_GetNextBackoff API a couple times. */ TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); - TEST_ASSERT_EQUAL( expectedNextBackOff, nextBackOff ); + BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); + TEST_ASSERT_EQUAL( expectedNextBackoff, nextBackoff ); /* Verify that the context data for expected data after the API call. */ verifyContextData( &retryParams, expectedAttemptsDone, expectedNextJitterMax, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); } } @@ -239,9 +183,9 @@ void test_BackoffAlgorithm_GetNextBackoff_Success_RandVal_More_Than_Jitter_Max( for( ; iter < 2; iter++ ) { - /* Set the random value to be generated as a value greater than + /* Set the random value as a value greater than * the jitter max value for the next retry attempt. */ - randomValToReturn = retryParams.nextJitterMax + 1; + testRandomVal = retryParams.nextJitterMax + 1; /* The jitter max value should double with the above call for use in next call. */ expectedNextJitterMax *= 2; @@ -253,20 +197,19 @@ void test_BackoffAlgorithm_GetNextBackoff_Success_RandVal_More_Than_Jitter_Max( /* As the random value is greater than the jitter max value, the expected * next backoff value should be truncated to a value within the jitter window * for the retry attempt. */ - uint16_t expectedNextBackOff = ( randomValToReturn % ( retryParams.nextJitterMax + 1U ) ); + uint16_t expectedNextBackoff = ( testRandomVal % ( retryParams.nextJitterMax + 1U ) ); /* Call the BackoffAlgorithm_GetNextBackoff API a couple times. */ TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); - TEST_ASSERT_EQUAL( expectedNextBackOff, nextBackOff ); + BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); + TEST_ASSERT_EQUAL( expectedNextBackoff, nextBackoff ); /* Verify that the context data for expected data after the API call. */ verifyContextData( &retryParams, expectedAttemptsDone, expectedNextJitterMax, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); } } @@ -282,9 +225,9 @@ void test_BackoffAlgorithm_GetNextBackoff_Attempts_Exhausted() /* Call the BackoffAlgorithm_GetNextBackoff API. */ TEST_ASSERT_EQUAL( BackoffAlgorithmRetriesExhausted, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); + BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); /* Make sure that the value of the output parameter has not changed. */ - TEST_ASSERT_EQUAL( 0, nextBackOff ); + TEST_ASSERT_EQUAL( 0, nextBackoff ); /* Make sure that the context data has not changed as the call to * BackoffAlgorithm_GetNextBackoff failed. */ @@ -292,15 +235,14 @@ void test_BackoffAlgorithm_GetNextBackoff_Attempts_Exhausted() TEST_MAX_ATTEMPTS /* Number of attempts shouldn't change */, TEST_BACKOFF_BASE_VALUE, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); } /** - * @brief Test that the value of the next max jitter has a lower bound that will - * then be capped at some max threshold. + * @brief Tests that the #BackoffAlgorithm_GetNextBackoff API does not calculate a backoff period + * beyond the configured maximum backoff period. */ -void test_BackoffAlgorithm_GetNextBackoff_Returns_Cap_BackOff( void ) +void test_BackoffAlgorithm_GetNextBackoff_Returns_Cap_Backoff( void ) { /* Initialize to 0 attempts, so the max value of next jitter will increase. */ retryParams.attemptsDone = 0U; @@ -310,17 +252,17 @@ void test_BackoffAlgorithm_GetNextBackoff_Returns_Cap_BackOff( void ) * the configured maximum backoff value. */ retryParams.nextJitterMax = ( TEST_BACKOFF_MAX_VALUE / 2U ) + 1; - /* Set the random value to be generated equal to the current jitter max value. + /* Set the random value equal to the current jitter max value. * Thus, the BackoffAlgorithm_GetNextBackoff API should return the random value as * the next back-off value. */ - randomValToReturn = retryParams.nextJitterMax; - uint16_t expectedBackOffVal = randomValToReturn; + testRandomVal = retryParams.nextJitterMax; + uint16_t expectedBackoffVal = testRandomVal; /* Call the BackoffAlgorithm_GetNextBackoff API. */ TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); + BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); /* Make sure that the expected value is returned for the next backoff. */ - TEST_ASSERT_EQUAL( expectedBackOffVal, nextBackOff ); + TEST_ASSERT_EQUAL( expectedBackoffVal, nextBackoff ); /* Verify that the next jitter max value has been set to the cap back-off value * configured in the context. */ @@ -328,44 +270,50 @@ void test_BackoffAlgorithm_GetNextBackoff_Returns_Cap_BackOff( void ) 1, TEST_BACKOFF_MAX_VALUE /* New jitter max */, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); - /* Now, set the random value to be generated as the maximum back-off value to + /* Now, set the random value as the maximum back-off value to * expect that the next back-off value returned by the API is the maximum * back-off value.*/ - randomValToReturn = TEST_BACKOFF_MAX_VALUE; + testRandomVal = TEST_BACKOFF_MAX_VALUE; /* Call BackoffAlgorithm_GetNextBackoff API again to verify that it now returns the * cap value as the next back-off value. */ TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); + BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); /* Make sure that the capped backoff value is returned as the next backoff value . */ - TEST_ASSERT_EQUAL( TEST_BACKOFF_MAX_VALUE, nextBackOff ); + TEST_ASSERT_EQUAL( TEST_BACKOFF_MAX_VALUE, nextBackoff ); /* Verify that the context data for expected data after the API call. */ verifyContextData( &retryParams, 2, TEST_BACKOFF_MAX_VALUE /* jitter max remains unchanged */, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + TEST_MAX_ATTEMPTS ); } /** - * @brief Test that the value of the next max jitter has a lower bound that will - * then be capped at some max threshold. + * @brief Tests the #BackoffAlgorithm_GetNextBackoff API when the next jitter max value + * is one lower than half of the maximum backoff value. This tests that the API does not + * update the next jitter max to the maximum backoff value in this case. */ -void test_BackoffAlgorithm_GetNextBackoff_Returns_Rand_Val( void ) +void test_BackoffAlgorithm_GetNextBackoff_NextJitterMax_Below_Cap_Backoff( void ) { + /* Initialize context. + * Use the configuration constant of retrying forever to achieve branch coverage in tests + * for the configuration. */ + BackoffAlgorithm_InitializeParams( &retryParams, + TEST_BACKOFF_BASE_VALUE, + TEST_BACKOFF_MAX_VALUE, + BACKOFF_ALGORITHM_RETRY_FOREVER ); + /* Initialize to 0 attempts, so the max value of next jitter will increase. */ retryParams.attemptsDone = 0U; - /* Set the returned random value to zero to test that the - * BackoffAlgorithm_GetNextBackoff API will return zero as the - * next back-off value.*/ - randomValToReturn = 0; + /* Set the random value to zero to test that the BackoffAlgorithm_GetNextBackoff + * API will return zero as the next back-off value.*/ + testRandomVal = 0; /* Update the next jitter max value to one less than half of max backoff * to make sure that the BackoffAlgorithm_GetNextBackoff API does not update it @@ -374,17 +322,16 @@ void test_BackoffAlgorithm_GetNextBackoff_Returns_Rand_Val( void ) /* Call the BackoffAlgorithm_GetNextBackoff API. */ TEST_ASSERT_EQUAL( BackoffAlgorithmSuccess, - BackoffAlgorithm_GetNextBackoff( &retryParams, &nextBackOff ) ); + BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, &nextBackoff ) ); /* Make sure that zero is returned as the next backoff value . */ - TEST_ASSERT_EQUAL( 0, nextBackOff ); + TEST_ASSERT_EQUAL( 0, nextBackoff ); /* Verify that the context data for expected data after the API call. */ verifyContextData( &retryParams, 1, TEST_BACKOFF_MAX_VALUE - 2U /* next jitter max value */, TEST_BACKOFF_MAX_VALUE, - TEST_MAX_ATTEMPTS, - mockRng ); + BACKOFF_ALGORITHM_RETRY_FOREVER ); } /** @@ -394,8 +341,8 @@ void test_BackoffAlgorithm_GetNextBackoff_Returns_Rand_Val( void ) void test_BackoffAlgorithm_GetNextBackoff_Invalid_Params() { /* Invalid context. */ - catch_assert( BackoffAlgorithm_GetNextBackoff( NULL, &nextBackOff ) ); + catch_assert( BackoffAlgorithm_GetNextBackoff( NULL, testRandomVal, &nextBackoff ) ); /* Invalid output parameter for next back-off. */ - catch_assert( BackoffAlgorithm_GetNextBackoff( &retryParams, NULL ) ); + catch_assert( BackoffAlgorithm_GetNextBackoff( &retryParams, testRandomVal, NULL ) ); }