diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 533c43c63..6fc8ddb73 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -94,4 +94,21 @@ jobs: run: | lcov --capture --rc lcov_branch_coverage=1 --directory build --output-file coverage_test.info lcov --rc lcov_branch_coverage=1 --add-tracefile coverage_base.info --add-tracefile coverage_test.info --output-file coverage_total.info - genhtml coverage_total.info --branch-coverage --output-directory lcov + genhtml coverage_total.info --branch-coverage --output-directory lcov | tee lcov_out.txt + + - name: Confirm Minimum Coverage + run: | + missed_branches=76 + missed_lines=33 + branch_nums=$(grep -A 3 "Overall coverage rate" lcov_out.txt | grep branches | grep -oP "[0-9]+[0-9]*") + line_nums=$(grep -A 3 "Overall coverage rate" lcov_out.txt | grep lines | grep -oP "[0-9]+[0-9]*") + + branch_diff=$(echo $branch_nums | awk '{ print $4 - $3 }') + line_diff=$(echo $line_nums | awk '{ print $4 - $3 }') + if [ $branch_diff -gt $missed_branches ] || [ $line_diff -gt $missed_lines ] + then + grep -A 3 "Overall coverage rate" lcov_out.txt + echo "$branch_diff branches missed, $missed_branches allowed" + echo "$line_diff lines missed, $missed_lines allowed" + exit -1 + fi diff --git a/README.md b/README.md index ca8fc797a..493e59599 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,16 @@ The detailed cFE user's guide can be viewed at and + ### Development Build: v6.8.0-rc1+dev980 - Add SB API test cases diff --git a/docs/cFE Application Developers Guide.md b/docs/cFE Application Developers Guide.md index 565284f5d..5bad81eab 100644 --- a/docs/cFE Application Developers Guide.md +++ b/docs/cFE Application Developers Guide.md @@ -302,21 +302,130 @@ a variation on this standard. ## 2.1 Directory Tree -The following diagrams show the standard development and build directory +The following shows the standard development and build directory tree or mission tree as it is often referred to. The purpose of each directory is described as a note under each folder. - -![](.//media/cFE_Application_Developers_Guide_image4.png) - -![](.//media/cFE_Application_Developers_Guide_image5.png) - -![](.//media/cFE_Application_Developers_Guide_image6.png) - +``` +-- missionxyz + |-- cfe + | |-- Contains a copy of the cFE component + |-- osal + | |-- Contains a copy of the OSAL component + |-- psp + | |-- Contains the Platform Suport Package (PSP) library + | |-- Can customize PSP implementation for each CPU and OS that the project needs + |-- build + | |-- The flight software is all configured and built under this directory + | |-- All mission and platform configuration files are placed here + |-- apps + | |-- Contains application source code. + | |-- Application source code may be shared amoung multiple build CPUs + |-- libs + | |-- Contains Core Flight System (cFS) Sample Library (sample_lib) + |-- tools + | |-- Contains Core Flight System (cFS) tools +``` +Module descriptions are provided in the table below. +``` +-- missionxyz/cfe + |-- cmake + | |-- sample_defs + | | |-- Example target definitions folder (used for building the open source cFS bundle) + | |-- target + | | |-- Templates and generic helper software used/included by the build toolchain + |-- docs + |-- modules + | |-- cfe_assert + | |-- cfe_testcase + | |-- cfe_testrunner + | |-- core_api + | |-- core_private + | |-- es + | |-- evs + | |-- fs + | |-- msg + | |-- resourceid + | |-- sb + | |-- sbr + | |-- tbl + | |-- time +``` +``` +-- missionxyz/build + |-- CMakeFiles + | |-- Cmake fore cfe core build and all apps + |-- cpu1 + | |-- Contains start up script "cfe_es_startup.scr" + | |-- Where build.o and executable files, etc. are placed + |-- cpuN + |-- docs + |-- exe + |-- inc + | |-- Where the cpu1 platform configuration include files go + |-- src + |-- tools +``` +``` +-- missionxyz/build/cpu1 + |-- default_cpu1 + | |-- CMakeFiles + | | | Cmake fore cfe core build and all apps + | |-- apps + | | |-- Where application makefiles go + | | |-- One directory per application + | |-- core_api + | |-- core_private + | |-- cpu1 + | | |-- Contains start up script "cfe_es_startup.scr" + | | |-- Where build.o and executable files, etc. are placed + | |-- es + | |-- evs + | |-- fs + | |-- inc + | | |-- Where the cpu1 platform configuration include files go + | |-- msg + | |-- osal + | |-- psp + | |-- resourceid + | |-- sb + | |-- sbr + | |-- tbl + | |-- time +``` +``` +-- missionxyz/apps + |-- ci_lab + |-- sample_app + |-- sch_lab + |-- to_lab +``` +``` +-- missionxyz/tools + |-- cFS-GroundSystem + |-- elf2cfetbl + |-- tblCRCTool +``` +``` +-- missionxyz/cf/modules/es + |-- eds + |-- fsw + | | Software tree + | |-- inc + | |-- src + | | |-- Application source code and private header files + | | |-- The build system is flexible enough to have multiple subdirectories under/src when building code + | | |-- For appls with ~ 10 files, keep it simple with just a "src" directory + |-- ut-coverage + | | Test tree +``` Each cFE core component is itself a modular entity, all of which work together to form the complete cFE core executive. These modules are all contained under the `modules` subdirectory: | **Directory** | **Content** | |:------------------------|:------------------------------------------------------------------------------------------------------------------ | +| `modules/cfe_assert/` | A CFE-compatible library wrapping the basic UT assert library. This is the same library that all other unit tests use, but configured to be dynamically loaded into the CFE environment, and using CFE syslog for its output. This must be the first library loaded for any functional test. | +| `modules/cfe_testcase/` | A CFE-compatible library implementing test cases for CFE core apps. This must be loaded after cfe_assert. | +| `modules/cfe_testrunner/` | A CFE application that actually executes the tests. This is a very simple app that waits for CFE startup to complete, then executes all registered test cases. It also must be loaded after cfe_assert. | | `modules/core_api/` | Contains the public interface definition of the complete CFE core - public API/headers only, no implementation | | `modules/core_private/` | Contains the inter-module interface definition of the CFE core - internal API/headers only, no implementation | | `modules/es/` | Implementation of the Executive Services (ES) core module - provides app and task management | @@ -342,15 +451,7 @@ Each module directory is in turn divided into subdirectories as follows: | _module_`/ut-coverage/` | Coverage tests to provide line/branch testing (correlates with internal implementation in `fsw/src`) | | _module_`/eds/` | Command & Telemetry interface description as a CCSDS book 876.0 Electronic Data Sheet | -![](.//media/cFE_Application_Developers_Guide_image7.png) - -![](.//media/cFE_Application_Developers_Guide_image8.png) - -![](.//media/cFE_Application_Developers_Guide_image9.png) -![](.//media/cFE_Application_Developers_Guide_image10.png) - -![](.//media/cFE_Application_Developers_Guide_image11.png) ## 2.2 Header Files @@ -1389,29 +1490,35 @@ with timeout as well. ### 6.1.1 Software Bus Messages -A Software Bus Message (SB Message) is a collection of data treated as a -single entity. The format and the definition of the content is uniquely -identified with a 16 bit Message ID. The Message ID is used to identify -what the data is and who would like to receive it. Applications create -SB Messages by allocating sufficient memory, calling the SB API to -initialize the contents of the SB Message and then storing any -appropriate data into the structure. - -The Message API hides the details of the message structure, -providing routines such as CFE_MSG_GetMsgTime and CFE_MSG_SetMsgTime -in order to get and set a message time. The current version of the cFE -supports only CCSDS, however, the implementation of the message -structure can be changed without affecting cFS Applications. - -See the implementation documentation for specific formats, -fields, and bit values. The message ID (MsgId) is an abstract -concept that is implementation depended, used for routing messages -on the Software Bus. Depending on the implementation, different -ranges and values are supported, and the values effect the message -header differently. +A Software Bus Message is a collection of data treated as a single entity. +Messages are identified and routed on the Software Bus using an abstracted +Message ID. Applications create SB Messages by allocating sufficient memory, +initializing the message contents and filling in user data. -If you are using the default, MsgID maps directly to the CCSDS Stream ID. -When using the default, for commands use 0x18xx and telemetry use 0x08xx +The Message API abstracts the details of the message header, +and most importantly the Message ID. The current version of the cFE +supports only CCSDS, however, the implementation of the message +structure can be changed without affecting the rest of cFS as long +as the APIs meet the required behavior identified in the related +documentation. + +See the message module implementation documentation for specific formats, +fields, and bit values. The message module provides a selection of two +different implementations for Message ID (MISSION_MSG_V1 and MISSION_MSG_V2), +which use different header information to interpret the Message ID. +Applications and cFE services should always use the message module APIs +for getting or setting information in the message headers to support +portability between formats. Message ID should always be treated as opaque, +although they do need to be defined for applications to subscribe to messages. +Message ID definition is typically managed by external database management +systems and MUST match the implementation selected. + +If you are using the default (MISSION_MSG_V1), MsgID maps directly to the CCSDS Stream ID. +It is important enough to repeat, applications should NOT directly interpret +the Message ID value since for different implementations the bits may have +different meanings. For example, default Message ID values for commands are of +the format 0x18xx and telemetry is 0x08xx, whereas for MISSION_MSG_V2 +those bits have different meaning. ### 6.1.2 Pipes @@ -1458,6 +1565,21 @@ performs the operations necessary to transfer the SB Message to the target pipe(s). Applications call the SB API to request specified SB Message IDs to be routed to their previously created pipes. +Note there are two routing implementations provide by the +Software Bus Routing (SBR) module. If the MISSION_MSGMAP_IMPLEMENTATION +is unset (the default) or set to DIRECT, a message map of size +CFE_PLATFORM_SB_HIGHEST_VALID_MSGID is used to relate Message ID to routes. +If set to HASH, a message map of size (4 * CFE_PLATFORM_SB_MAX_MSG_IDS) +is used and a hash is performed on Message IDs to relate to routes. Note +the impact on memory footprint can be significant, since +CFE_PLATFORM_SB_HIGHEST_VALID_MSGID is the maximum number of possible +Message IDs, whereas CFE_PLATFORM_SB_MAX_MSG_IDS is the maximum number of +routes supported (**used** Message IDs). Hash collisions are reported +during subscription and can be avoided by predetermining Message +IDs that won't collide. Note advanced users can replace SBR with a custom +routing implementation (possibly sorting or a smart hash) to adapt to unique +mission requirements/constraints. + #### 6.1.3.1 Sending Applications Any software application is capable of sending SB Messages. However, @@ -1579,7 +1701,7 @@ FILE: sample_msgids.h ... /* Define Message IDs */ -#define SAMPLE_CMDID_1 (0x0123) +#define SAMPLE_CMDID_1 (0x0123) /* CAUTION!!! This value depends on selected implementation */ ... ``` ```c @@ -1739,15 +1861,14 @@ for the Developer to have used the CFE_MSG_CommandHeader_t macro instead. The CFE_MSG_Init API call formats the Message Header -appropriately with the given SB Message ID, size and, in this case, -clears the data portion of the SB Message (CFE_SB_CLEAR_DATA). -Another option for the fourth parameter is CFE_SB_NO_CLEAR which -would have retained the contents of the data structure and only updated -the SB Message Header. +appropriately with the given Message ID, size and clears the rest +of the message. Note this call is implementation dependent, in that +bits in the Message ID may have additional meaning and may impact +actual header fields in different ways. -NOTE: SB Message IDs are defined in a separate header file from the rest +NOTE: Message IDs are defined in a separate header file from the rest of the Application's interface. This makes it much simpler to port the -Application to another mission where SB Message IDs may need to be +Application to another mission where Message IDs may need to be renumbered. ### 6.5.1 Message Header Types @@ -1799,7 +1920,7 @@ functions are only applicable to a specific header type. Additional information on modifying specific header types is provided in the following subsections. -| **SB Message Header Field** | **API for Modifying the Header Field** | +| **Message Header Field** | **API for Modifying the Header Field** | | ---------------------------:| --------------------------------------:| | Message ID | CFE_MSG_SetMsgId | | Total Message Length | CFE_MSG_SetSize | @@ -1845,7 +1966,7 @@ Applications are portable to future missions. The following table identifies the fields of the Message Header and the appropriate API for extracting that field from the header: -| **SB Message Header Field** | **API for Reading the Header Field** | +| **Message Header Field** | **API for Reading the Header Field** | |:----------------------------|:-------------------------------------| | Message ID | CFE_MSG_GetMsgId | | Message Time | CFE_MSG_GetTime | @@ -1896,7 +2017,7 @@ SAMPLE_AppData_t SAMPLE_AppData; /* Instantiate Task Data */ ## 6.7 Receiving Software Bus Messages -To receive a SB Message, an application calls CFE_SB_ReceiveBuffer. Since most +To receive a Message, an application calls CFE_SB_ReceiveBuffer. Since most applications are message-driven, this typically occurs in an application's main execution loop. An example of this is shown below. @@ -1938,7 +2059,7 @@ FILE: sample_app.c ``` In the above example, the Application will pend on the -SAMPLE_AppData.CmdPipe until an SB Message arrives. A pointer to the next SB +SAMPLE_AppData.CmdPipe until a Message arrives. A pointer to the next SB message in the Pipe will be returned in SBBufPtr. Alternatively, the Application could have chosen to pend with a timeout (by @@ -1946,12 +2067,12 @@ providing a numerical argument in place of CFE_SB_PEND_FOREVER) or to quickly poll the pipe to check for a message (by using CFE_SB_POLL in place of CFE_SB_PEND_FOREVER). -If a SB Message fails to arrive within the specified timeout period, the +If a Message fails to arrive within the specified timeout period, the cFE will return the CFE_SB_TIME_OUT status code. If the Pipe does not have any data present when the CFE_SB_ReceiveBuffer API is called, the cFE will return a CFE_SB_NO_MESSAGE status code. -After a message is received, the SB Message Header accessor functions (as +After a message is received, the Message Header accessor functions (as described in Section 6.5.3) should be used to identify the message so that the application can react to it appropriately. @@ -1980,7 +2101,7 @@ assume the SB Buffer pointer is accessible once the buffer has been sent. If an Application has called the `CFE_SB_AllocateMessageBuffer` API call and -then later determines that it is not going to send the SB Message, it +then later determines that it is not going to send the Message, it shall free the allocated buffer by calling the `CFE_SB_ReleaseMessageBuffer` API. @@ -1990,7 +2111,7 @@ An example of the "Zero Copy" protocol is shown below: FILE: app_msgids.h ... -#define SAMPLE_BIG_TLM_MID (0x0231) /* Define SB Message ID for SAMPLE’s Big Pkt */ +#define SAMPLE_BIG_TLM_MID (0x0231) /* Define Message ID for SAMPLE’s Big Pkt */ ... FILE: sample_app.h @@ -2033,7 +2154,7 @@ SAMPLE_AppData_t SAMPLE_AppData; /* Instantiate Task Data */ { ... /* - ** Get a SB Message block of memory and initialize it + ** Get a Message block of memory and initialize it */ SAMPLE_AppData.BigPktBuf = (SAMPLE_BigPkt_Buffer_t *)CFE_SB_AllocateMessageBuffer(sizeof(SAMPLE_BigPkt_t)); @@ -2045,7 +2166,7 @@ SAMPLE_AppData_t SAMPLE_AppData; /* Instantiate Task Data */ */ /* - ** Send SB Message after time tagging it with current time + ** Send Message after time tagging it with current time */ CFE_SB_TimeStampMsg(&SAMPLE_AppData.BigPktBuf->Pkt.TlmHeader.Msg); CFE_SB_TransmitBuffer(SAMPLE_AppData.BigPktBuf, BufferHandle, true); @@ -2062,7 +2183,7 @@ The following are recommended "best practices" for applications using SB. 2. Pipe depth and message limits are dependent on the entire software system. Consider both the receiving application and any sending application(s) when choosing those limits. -3. Applications shall always use AB API functions to read or manipulate the SB +3. Applications shall always use API functions to read or manipulate the Message Header. 4. Applications should maintain a command counter and a command error counter in housekeeping telemetry. diff --git a/docs/media/cFE_Application_Developers_Guide_image10.png b/docs/media/cFE_Application_Developers_Guide_image10.png deleted file mode 100644 index 479dc6537..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image10.png and /dev/null differ diff --git a/docs/media/cFE_Application_Developers_Guide_image11.png b/docs/media/cFE_Application_Developers_Guide_image11.png deleted file mode 100644 index 3d4a73c2a..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image11.png and /dev/null differ diff --git a/docs/media/cFE_Application_Developers_Guide_image5.png b/docs/media/cFE_Application_Developers_Guide_image5.png deleted file mode 100644 index 96a45ac12..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image5.png and /dev/null differ diff --git a/docs/media/cFE_Application_Developers_Guide_image6.png b/docs/media/cFE_Application_Developers_Guide_image6.png deleted file mode 100644 index 066b644bf..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image6.png and /dev/null differ diff --git a/docs/media/cFE_Application_Developers_Guide_image7.png b/docs/media/cFE_Application_Developers_Guide_image7.png deleted file mode 100644 index ffeec30ad..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image7.png and /dev/null differ diff --git a/docs/media/cFE_Application_Developers_Guide_image8.png b/docs/media/cFE_Application_Developers_Guide_image8.png deleted file mode 100644 index 5603662ce..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image8.png and /dev/null differ diff --git a/docs/media/cFE_Application_Developers_Guide_image9.png b/docs/media/cFE_Application_Developers_Guide_image9.png deleted file mode 100644 index 96832ebf4..000000000 Binary files a/docs/media/cFE_Application_Developers_Guide_image9.png and /dev/null differ diff --git a/modules/cfe_testcase/src/msg_api_test.c b/modules/cfe_testcase/src/msg_api_test.c index 0690ef07a..e9ade9d69 100644 --- a/modules/cfe_testcase/src/msg_api_test.c +++ b/modules/cfe_testcase/src/msg_api_test.c @@ -184,6 +184,7 @@ void TestMsgHeaderSecondaryApi(void) CFE_TIME_SysTime_t msgTime; bool isValid = true; CFE_TIME_SysTime_t currentTime = {1000, 0xFFFF0000}; + CFE_Status_t status; memset(&cmd, 0, sizeof(cmd)); memset(&cmdTlm, 0xFF, sizeof(cmdTlm)); @@ -203,17 +204,25 @@ void TestMsgHeaderSecondaryApi(void) UtAssert_INT32_EQ(CFE_MSG_SetType(&cmd2.Msg, CFE_MSG_Type_Cmd), CFE_SUCCESS); /* test generate-checksum */ - UtAssert_INT32_EQ(CFE_MSG_GenerateChecksum(NULL), CFE_MSG_BAD_ARGUMENT); - UtAssert_INT32_EQ(CFE_MSG_GenerateChecksum(&cmdTlm.Msg), CFE_MSG_WRONG_MSG_TYPE); - UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmdTlm.Msg, &isValid), CFE_MSG_WRONG_MSG_TYPE); - UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(NULL, &isValid), CFE_MSG_BAD_ARGUMENT); - UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmdTlm.Msg, NULL), CFE_MSG_BAD_ARGUMENT); - - UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmd.Msg, &isValid), CFE_SUCCESS); - UtAssert_True(!isValid, "Checksum isValid (%d) = false", isValid); - UtAssert_INT32_EQ(CFE_MSG_GenerateChecksum(&cmd.Msg), CFE_SUCCESS); - UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmd.Msg, &isValid), CFE_SUCCESS); - UtAssert_True(isValid, "Checksum isValid (%d) = true", isValid); + status = CFE_MSG_GenerateChecksum(NULL); + if (status == CFE_MSG_NOT_IMPLEMENTED) + { + UtAssert_NA("CFE_MSG_GenerateChecksum not implemented"); + } + else + { + UtAssert_INT32_EQ(CFE_MSG_GenerateChecksum(NULL), CFE_MSG_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_MSG_GenerateChecksum(&cmdTlm.Msg), CFE_MSG_WRONG_MSG_TYPE); + UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmdTlm.Msg, &isValid), CFE_MSG_WRONG_MSG_TYPE); + UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(NULL, &isValid), CFE_MSG_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmdTlm.Msg, NULL), CFE_MSG_BAD_ARGUMENT); + + UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmd.Msg, &isValid), CFE_SUCCESS); + UtAssert_True(!isValid, "Checksum isValid (%d) = false", isValid); + UtAssert_INT32_EQ(CFE_MSG_GenerateChecksum(&cmd.Msg), CFE_SUCCESS); + UtAssert_INT32_EQ(CFE_MSG_ValidateChecksum(&cmd.Msg, &isValid), CFE_SUCCESS); + UtAssert_True(isValid, "Checksum isValid (%d) = true", isValid); + } /* test get/set-fcn-code */ UtAssert_INT32_EQ(CFE_MSG_SetFcnCode(NULL, 4), CFE_MSG_BAD_ARGUMENT); @@ -232,10 +241,20 @@ void TestMsgHeaderSecondaryApi(void) UtAssert_INT32_EQ(CFE_MSG_GetMsgTime(NULL, &msgTime), CFE_MSG_BAD_ARGUMENT); UtAssert_INT32_EQ(CFE_MSG_GetMsgTime(&cmd.Msg, NULL), CFE_MSG_BAD_ARGUMENT); - UtAssert_INT32_EQ(CFE_MSG_GetMsgTime(&cmd2.Msg, &msgTime), CFE_MSG_WRONG_MSG_TYPE); + + CFE_Assert_STATUS_STORE(CFE_MSG_GetMsgTime(&cmd2.Msg, &msgTime)); + if (!CFE_Assert_STATUS_MAY_BE(CFE_SUCCESS)) + { + CFE_Assert_STATUS_MUST_BE(CFE_MSG_WRONG_MSG_TYPE); + } UtAssert_INT32_EQ(CFE_MSG_SetMsgTime(NULL, currentTime), CFE_MSG_BAD_ARGUMENT); - UtAssert_INT32_EQ(CFE_MSG_SetMsgTime(&cmd2.Msg, currentTime), CFE_MSG_WRONG_MSG_TYPE); + + CFE_Assert_STATUS_STORE(CFE_MSG_SetMsgTime(&cmd2.Msg, currentTime)); + if (!CFE_Assert_STATUS_MAY_BE(CFE_SUCCESS)) + { + CFE_Assert_STATUS_MUST_BE(CFE_MSG_WRONG_MSG_TYPE); + } UtAssert_INT32_EQ(CFE_MSG_SetMsgTime(&cmd.Msg, currentTime), CFE_SUCCESS); UtAssert_INT32_EQ(CFE_MSG_GetMsgTime(&cmd.Msg, &msgTime), CFE_SUCCESS); diff --git a/modules/cfe_testcase/src/sb_sendrecv_test.c b/modules/cfe_testcase/src/sb_sendrecv_test.c index 2113c9f2d..2f2bb4457 100644 --- a/modules/cfe_testcase/src/sb_sendrecv_test.c +++ b/modules/cfe_testcase/src/sb_sendrecv_test.c @@ -122,7 +122,12 @@ void TestBasicTransmitRecv(void) /* Attempt to send a msg which does not have a valid msgid */ memset(&CFE_FT_BigMsg, 0xFF, sizeof(CFE_FT_BigMsg)); CFE_MSG_SetSize(&CFE_FT_BigMsg.Hdr, sizeof(CFE_MSG_Message_t) + 4); - UtAssert_INT32_EQ(CFE_SB_TransmitMsg(&CFE_FT_BigMsg.Hdr, true), CFE_SB_BAD_ARGUMENT); + + CFE_Assert_STATUS_STORE(CFE_SB_TransmitMsg(&CFE_FT_BigMsg.Hdr, true)); + if (!CFE_Assert_STATUS_MAY_BE(CFE_SUCCESS)) + { + CFE_Assert_STATUS_MUST_BE(CFE_SB_BAD_ARGUMENT); + } /* Attempt to send a msg which is too big */ CFE_MSG_SetSize(&CFE_FT_BigMsg.Hdr, sizeof(CFE_FT_BigMsg)); diff --git a/modules/core_api/fsw/inc/cfe_version.h b/modules/core_api/fsw/inc/cfe_version.h index 6e6100cad..6c6b666f0 100644 --- a/modules/core_api/fsw/inc/cfe_version.h +++ b/modules/core_api/fsw/inc/cfe_version.h @@ -28,7 +28,7 @@ #define CFE_VERSION_H /* Development Build Macro Definitions */ -#define CFE_BUILD_NUMBER 980 /**< @brief Development: Number of development commits since baseline */ +#define CFE_BUILD_NUMBER 994 /**< @brief Development: Number of development commits since baseline */ #define CFE_BUILD_BASELINE "v6.8.0-rc1" /**< @brief Development: Reference git tag for build number */ /* Version Macro Definitions updated for official releases only */ diff --git a/modules/core_private/ut-stubs/inc/ut_osprintf_stubs.h b/modules/core_private/ut-stubs/inc/ut_osprintf_stubs.h index 6641ad843..d9c40946e 100644 --- a/modules/core_private/ut-stubs/inc/ut_osprintf_stubs.h +++ b/modules/core_private/ut-stubs/inc/ut_osprintf_stubs.h @@ -105,5 +105,6 @@ #define UT_OSP_PUTPOOL_BAD_HANDLE 77 #define UT_OSP_FORMAT_VOLATILE 78 #define UT_OSP_RELOAD_NO_FILE 79 +#define UT_OSP_EXTERNAL_APP_EXIT 80 #endif /* UT_OSPRINTF_STUBS_H */ diff --git a/modules/core_private/ut-stubs/src/ut_osprintf_stubs.c b/modules/core_private/ut-stubs/src/ut_osprintf_stubs.c index ddb5bfcd6..d7a08252f 100644 --- a/modules/core_private/ut-stubs/src/ut_osprintf_stubs.c +++ b/modules/core_private/ut-stubs/src/ut_osprintf_stubs.c @@ -110,4 +110,5 @@ const char *UT_OSP_MESSAGES[] = { [UT_OSP_PUTPOOL_BAD_HANDLE] = "%s: Err:Invalid Memory Handle (0x%08lX).\n", [UT_OSP_FORMAT_VOLATILE] = "%s: Formatting Volatile(RAM) Volume.\n", [UT_OSP_RELOAD_NO_FILE] = "%s: Cannot Reload Application %s, File %s does not exist.\n", + [UT_OSP_EXTERNAL_APP_EXIT] = "%s: Application %s called CFE_ES_ExitApp\n", }; diff --git a/modules/es/ut-coverage/es_UT.c b/modules/es/ut-coverage/es_UT.c index cf315f6d5..ad7e33e01 100644 --- a/modules/es/ut-coverage/es_UT.c +++ b/modules/es/ut-coverage/es_UT.c @@ -39,6 +39,7 @@ ** Includes */ #include "es_UT.h" +#include "target_config.h" #define ES_UT_CDS_BLOCK_SIZE 16 @@ -207,6 +208,25 @@ void ES_UT_TaskFunction(void) UT_DEFAULT_IMPL(ES_UT_TaskFunction); } +/* Local function to test CFE_ES_SysLog_vsnprintf */ +void ES_UT_SysLog_snprintf(char *Buffer, size_t BufferSize, const char *SpecStringPtr, ...) +{ + va_list ap; + + va_start(ap, SpecStringPtr); + CFE_ES_SysLog_vsnprintf(Buffer, BufferSize, SpecStringPtr, ap); + va_end(ap); +} + +void ES_UT_FillBuffer(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + char * PrintBuffer = UT_Hook_GetArgValueByName(Context, "PrintBuffer", char *); + uint32 Size = *((uint32 *)UserObj); + + memset(PrintBuffer, ' ', Size - 1); + PrintBuffer[Size - 1] = 0; +} + /* * Helper function to assemble basic bits of info into the "CFE_ES_ModuleLoadParams_t" struct */ @@ -401,6 +421,18 @@ int32 ES_UT_CDSPoolCommit(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset, con return CFE_PSP_WriteToCDS(BdPtr, Offset, sizeof(*BdPtr)); } +/* Commit failure routine for pool coverage testing */ +int32 ES_UT_PoolCommitFail(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset, const CFE_ES_GenPoolBD_t *BdPtr) +{ + return CFE_ES_CDS_ACCESS_ERROR; +} + +/* Retrieve failure routine for pool coverage testing */ +int32 ES_UT_PoolRetrieveFail(CFE_ES_GenPoolRecord_t *PoolRecPtr, size_t Offset, CFE_ES_GenPoolBD_t **BdPtr) +{ + return CFE_ES_CDS_ACCESS_ERROR; +} + void ES_UT_SetupMemPoolId(CFE_ES_MemPoolRecord_t **OutPoolRecPtr) { CFE_ResourceId_t UtPoolID; @@ -876,6 +908,22 @@ void TestStartupErrorPaths(void) CFE_ES_InitializeFileSystems(CFE_PSP_RST_TYPE_PROCESSOR); CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_DETERMINE_BLOCKS]); + /* File system init with free space (no reformat) */ + ES_ResetUnitTest(); + StatBuf.blocks_free = StatBuf.total_blocks; + UT_SetDataBuffer(UT_KEY(OS_FileSysStatVolume), &StatBuf, sizeof(StatBuf), false); + CFE_ES_InitializeFileSystems(CFE_PSP_RST_TYPE_PROCESSOR); + UtAssert_STUB_COUNT(OS_unmount, 0); + StatBuf.blocks_free = CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS / 100; + + /* File system init with no blocks */ + ES_ResetUnitTest(); + StatBuf.total_blocks = 0; + UT_SetDataBuffer(UT_KEY(OS_FileSysStatVolume), &StatBuf, sizeof(StatBuf), false); + CFE_ES_InitializeFileSystems(CFE_PSP_RST_TYPE_PROCESSOR); + UtAssert_STUB_COUNT(CFE_PSP_Panic, 1); + StatBuf.total_blocks = CFE_PLATFORM_ES_RAM_DISK_NUM_SECTORS; + /* Test reading the object table where a record used error occurs */ ES_ResetUnitTest(); TaskRecPtr = CFE_ES_Global.TaskTable; @@ -967,7 +1015,7 @@ void TestStartupErrorPaths(void) /* Test application sync delay where the operation times out */ ES_ResetUnitTest(); /* This prep is necessary so GetAppId works */ - ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppType_CORE, NULL, &AppRecPtr, NULL); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_EARLY_INIT, NULL, &AppRecPtr, NULL); CFE_ES_Global.SystemState = CFE_ES_SystemState_CORE_READY; UtAssert_INT32_EQ( CFE_ES_WaitForSystemState(CFE_ES_SystemState_OPERATIONAL, CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC), @@ -978,7 +1026,7 @@ void TestStartupErrorPaths(void) */ ES_ResetUnitTest(); /* This prep is necessary so GetAppId works */ - ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppType_CORE, NULL, &AppRecPtr, NULL); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_EARLY_INIT, NULL, &AppRecPtr, NULL); CFE_ES_Global.SystemState = CFE_ES_SystemState_CORE_READY; UtAssert_INT32_EQ( CFE_ES_WaitForSystemState(CFE_ES_SystemState_SHUTDOWN, CFE_PLATFORM_ES_STARTUP_SCRIPT_TIMEOUT_MSEC), @@ -990,7 +1038,7 @@ void TestStartupErrorPaths(void) */ ES_ResetUnitTest(); /* This prep is necessary so GetAppId works */ - ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppType_CORE, NULL, &AppRecPtr, NULL); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_EARLY_INIT, NULL, &AppRecPtr, NULL); CFE_ES_Global.SystemState = CFE_ES_SystemState_CORE_READY; UtAssert_INT32_EQ( @@ -1001,9 +1049,78 @@ void TestStartupErrorPaths(void) /* Test success */ ES_ResetUnitTest(); /* This prep is necessary so GetAppId works */ - ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppType_CORE, NULL, &AppRecPtr, NULL); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_EARLY_INIT, NULL, &AppRecPtr, NULL); CFE_ES_Global.SystemState = CFE_ES_SystemState_CORE_READY; CFE_UtAssert_SUCCESS(CFE_ES_WaitForSystemState(CFE_ES_SystemState_CORE_READY, 0)); + + /* Core app wait for operational, already running */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_EARLY_INIT, NULL, &AppRecPtr, NULL); + CFE_ES_Global.SystemState = CFE_ES_SystemState_EARLY_INIT; + CFE_UtAssert_SUCCESS(CFE_ES_WaitForSystemState(CFE_ES_SystemState_EARLY_INIT, 0)); +} + +static void ES_UT_UnusedAppTask(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + CFE_ES_TaskId_t TaskId = *((CFE_ES_TaskId_t *)UserObj); + CFE_ES_TaskRecord_t *UtTaskRecPtr; + CFE_ES_AppRecord_t * UtAppRecPtr; + + UtTaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId); + UtAppRecPtr = CFE_ES_LocateAppRecordByID(UtTaskRecPtr->AppId); + + /* Set the records back to there "used" values */ + UtTaskRecPtr->TaskId = CFE_ES_TASKID_UNDEFINED; + UtAppRecPtr->AppId = CFE_ES_APPID_UNDEFINED; +} + +static void ES_UT_UsedAppTask(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + CFE_ES_TaskId_t TaskId = *((CFE_ES_TaskId_t *)UserObj); + CFE_ES_TaskRecord_t *UtTaskRecPtr; + CFE_ES_AppRecord_t * UtAppRecPtr; + + UtTaskRecPtr = CFE_ES_LocateTaskRecordByID(TaskId); + UtAppRecPtr = CFE_ES_LocateAppRecordByID(UtTaskRecPtr->AppId); + + /* Set the records back to there "used" values */ + UtTaskRecPtr->TaskId = TaskId; + UtAppRecPtr->AppId = UtTaskRecPtr->AppId; +} + +static void ES_UT_SetPerfIdle(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + CFE_ES_Global.ResetDataPtr->Perf.MetaData.State = CFE_ES_PERF_IDLE; +} + +static void ES_UT_ForEachObjectIncrease(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + + OS_ArgCallback_t callback_ptr = UT_Hook_GetArgValueByName(Context, "callback_ptr", OS_ArgCallback_t); + void * callback_arg = UT_Hook_GetArgValueByName(Context, "callback_arg", void *); + int * count = (int *)UserObj; + int i; + osal_id_t id; + + /* Increasing number of objects per call */ + for (i = 0; i < *count; i++) + { + OS_OpenCreate(&id, NULL, 0, 0); + (*callback_ptr)(id, callback_arg); + } + (*count)++; +} + +static void ES_UT_ForEachObjectFail(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + + OS_ArgCallback_t callback_ptr = UT_Hook_GetArgValueByName(Context, "callback_ptr", OS_ArgCallback_t); + void * callback_arg = UT_Hook_GetArgValueByName(Context, "callback_arg", void *); + osal_id_t id; + + OS_OpenCreate(&id, NULL, 0, 0); + UT_SetDeferredRetcode(UT_KEY(OS_close), 1, -1); + (*callback_ptr)(id, callback_arg); } void TestApps(void) @@ -1014,9 +1131,11 @@ void TestApps(void) CFE_ES_TaskId_t TaskId; CFE_ES_TaskRecord_t * UtTaskRecPtr; CFE_ES_AppRecord_t * UtAppRecPtr; + CFE_ES_AppRecord_t * UtAppRecPtr1; CFE_ES_MemPoolRecord_t *UtPoolRecPtr; char NameBuffer[OS_MAX_API_NAME + 5]; CFE_ES_AppStartParams_t StartParams; + int ObjCount; UtPrintf("Begin Test Apps"); @@ -1079,6 +1198,12 @@ void TestApps(void) CFE_ES_StartApplications(CFE_PSP_RST_TYPE_PROCESSOR, "ut_startup"); CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_CANNOT_OPEN_ES_APP_STARTUP]); + /* Test with failing parse of filenames */ + ES_ResetUnitTest(); + UT_SetDefaultReturnValue(UT_KEY(CFE_FS_ParseInputFileName), -1); + CFE_ES_StartApplications(CFE_PSP_RST_TYPE_PROCESSOR, "ut_startup"); + UtAssert_STUB_COUNT(OS_OpenCreate, 0); + /* Test successfully starting an application */ ES_ResetUnitTest(); UT_SetReadBuffer(StartupScript, NumBytes); @@ -1110,9 +1235,10 @@ void TestApps(void) /* Verify requirement to report error */ CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_APP_CREATE]); - /* Test application creation with NULL parameters */ + /* Test application creation with NULL pointers */ ES_ResetUnitTest(); UtAssert_INT32_EQ(CFE_ES_AppCreate(&AppId, "AppName", NULL), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_AppCreate(&AppId, NULL, &StartParams), CFE_ES_BAD_ARGUMENT); /* Test application creation with name too long */ memset(NameBuffer, 'x', sizeof(NameBuffer) - 1); @@ -1149,6 +1275,7 @@ void TestApps(void) CFE_ES_Global.AppTable[2].AppId = CFE_ES_APPID_UNDEFINED; UtAssert_BOOL_TRUE(CFE_ES_CheckAppIdSlotUsed(ES_UT_MakeAppIdForIndex(1))); UtAssert_BOOL_FALSE(CFE_ES_CheckAppIdSlotUsed(ES_UT_MakeAppIdForIndex(2))); + UtAssert_BOOL_TRUE(CFE_ES_CheckAppIdSlotUsed(CFE_RESOURCEID_UNDEFINED)); /* Test application loading and creation where the entry point symbol * cannot be found @@ -1187,7 +1314,7 @@ void TestApps(void) UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; UtAppRecPtr->ControlReq.AppTimerMsec = 0; memset(&CFE_ES_Global.BackgroundAppScanState, 0, sizeof(CFE_ES_Global.BackgroundAppScanState)); - CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState); + UtAssert_BOOL_TRUE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 0); CFE_UtAssert_EVENTSENT(CFE_ES_PCR_ERR2_EID); @@ -1198,7 +1325,7 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_WAITING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; UtAppRecPtr->ControlReq.AppTimerMsec = 5000; - CFE_ES_RunAppTableScan(1000, &CFE_ES_Global.BackgroundAppScanState); + UtAssert_BOOL_TRUE(CFE_ES_RunAppTableScan(1000, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 4000); UtAssert_UINT32_EQ(UtAppRecPtr->ControlReq.AppControlRequest, CFE_ES_RunStatus_APP_EXIT); @@ -1209,7 +1336,7 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_STOPPED, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; UtAppRecPtr->ControlReq.AppTimerMsec = 0; - CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState); + UtAssert_BOOL_TRUE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 0); CFE_UtAssert_EVENTSENT(CFE_ES_PCR_ERR2_EID); @@ -1220,7 +1347,7 @@ void TestApps(void) ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; UtAppRecPtr->ControlReq.AppTimerMsec = 0; - CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState); + UtAssert_BOOL_FALSE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, CFE_PLATFORM_ES_APP_KILL_TIMEOUT * CFE_PLATFORM_ES_APP_SCAN_RATE); @@ -1229,8 +1356,9 @@ void TestApps(void) */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_EARLY_INIT, NULL, &UtAppRecPtr, NULL); - UtAppRecPtr->ControlReq.AppTimerMsec = 5000; - CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState); + UtAppRecPtr->ControlReq.AppTimerMsec = 5000; + CFE_ES_Global.BackgroundAppScanState.PendingAppStateChanges = 1; + UtAssert_BOOL_FALSE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 5000); CFE_UtAssert_EVENTCOUNT(0); @@ -1382,12 +1510,29 @@ void TestApps(void) UtAssert_VOIDCALL(CFE_ES_ProcessControlRequest(AppId)); CFE_UtAssert_EVENTSENT(CFE_ES_PCR_ERR1_EID); + /* Control action with mismatched ID */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); + UtAppRecPtr->AppId = CFE_ES_APPID_UNDEFINED; + UtAssert_VOIDCALL(CFE_ES_ProcessControlRequest(AppId)); + CFE_UtAssert_EVENTSENT(CFE_ES_PCR_ERR2_EID); + /* Test populating the application information structure with data */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_UtAssert_SUCCESS(CFE_ES_GetAppInfo(&AppInfo, AppId)); + /* Two main/child pairs, assert count of child tasks */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); + AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); + ES_UT_SetupChildTaskId(UtAppRecPtr, NULL, NULL); + ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr1, NULL); + ES_UT_SetupChildTaskId(UtAppRecPtr1, NULL, NULL); + CFE_UtAssert_SUCCESS(CFE_ES_GetAppInfo(&AppInfo, AppId)); + UtAssert_UINT32_EQ(AppInfo.NumOfChildTasks, 1); + /* Test populating the application information structure with data using * a null application information pointer */ @@ -1552,6 +1697,13 @@ void TestApps(void) UT_SetDefaultReturnValue(UT_KEY(OS_TaskDelete), OS_ERROR); UtAssert_INT32_EQ(CFE_ES_CleanupTaskResources(TaskId), CFE_ES_TASK_DELETE_ERR); + /* Clean up resources where task self exited */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, NULL, &UtTaskRecPtr); + TaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); + UT_SetDefaultReturnValue(UT_KEY(OS_TaskDelete), OS_ERR_INVALID_ID); + CFE_UtAssert_SUCCESS(CFE_ES_CleanupTaskResources(TaskId)); + /* Test successfully cleaning up the OS resources for a task */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, NULL, &UtTaskRecPtr); @@ -1559,6 +1711,21 @@ void TestApps(void) UT_SetDeferredRetcode(UT_KEY(OS_TimerGetInfo), 1, OS_ERROR); CFE_UtAssert_SUCCESS(CFE_ES_CleanupTaskResources(TaskId)); + /* Override OS_ForEachObject to provide increasing number of objects */ + ES_ResetUnitTest(); + ObjCount = 1; + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, NULL, &UtTaskRecPtr); + TaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); + UT_SetHandlerFunction(UT_KEY(OS_ForEachObject), ES_UT_ForEachObjectIncrease, &ObjCount); + UtAssert_INT32_EQ(CFE_ES_CleanupTaskResources(TaskId), CFE_ES_APP_CLEANUP_ERR); + + /* Override OS_ForEachObject to get zero deleted (but nonzero objects )*/ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, NULL, &UtTaskRecPtr); + TaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); + UT_SetHandlerFunction(UT_KEY(OS_ForEachObject), ES_UT_ForEachObjectFail, NULL); + UtAssert_INT32_EQ(CFE_ES_CleanupTaskResources(TaskId), CFE_ES_APP_CLEANUP_ERR); + /* Test parsing the startup script for a cFE application and a restart * application exception action */ @@ -1585,7 +1752,7 @@ void TestApps(void) ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_WAITING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppTimerMsec = 0; - CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState); + UtAssert_BOOL_FALSE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 0); CFE_UtAssert_EVENTCOUNT(0); @@ -1595,7 +1762,16 @@ void TestApps(void) ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); UtAppRecPtr->ControlReq.AppTimerMsec = 0; - CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState); + UtAssert_BOOL_FALSE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); + UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 0); + CFE_UtAssert_EVENTCOUNT(0); + + /* Scan where command counter changed */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); + UtAppRecPtr->ControlReq.AppTimerMsec = 0; + CFE_ES_Global.BackgroundAppScanState.LastScanCommandCount = CFE_ES_Global.TaskData.CommandCounter + 1; + UtAssert_BOOL_FALSE(CFE_ES_RunAppTableScan(0, &CFE_ES_Global.BackgroundAppScanState)); UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppTimerMsec, 0); CFE_UtAssert_EVENTCOUNT(0); @@ -1617,17 +1793,19 @@ void TestApps(void) UtAssert_BOOL_FALSE(CFE_ES_MemPoolRecordIsUsed(UtPoolRecPtr)); /* Test deleting an application and cleaning up its resources where the - * main task and child task need to be swapped + * main task and child task need to be swapped and there is a mempool not owned by the app */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr1, NULL); ES_UT_SetupMemPoolId(&UtPoolRecPtr); - UtPoolRecPtr->OwnerAppID = CFE_ES_AppRecordGetID(UtAppRecPtr); + UtPoolRecPtr->OwnerAppID = CFE_ES_AppRecordGetID(UtAppRecPtr1); ES_UT_SetupChildTaskId(UtAppRecPtr, NULL, &UtTaskRecPtr); AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); /* Set MainTask to Child task's ID. Cleanup code will swap the order. */ UtAppRecPtr->MainTaskId = UtTaskRecPtr->TaskId; CFE_UtAssert_SUCCESS(CFE_ES_CleanUpApp(AppId)); + UtAssert_BOOL_TRUE(CFE_ES_MemPoolRecordIsUsed(UtPoolRecPtr)); /* Test deleting an application and cleaning up its resources where the * memory pool deletion fails @@ -1708,6 +1886,17 @@ void TestApps(void) UT_SetDeferredRetcode(UT_KEY(OS_TimerGetInfo), 1, OS_ERROR); UT_SetDeferredRetcode(UT_KEY(OS_FDGetInfo), 1, OS_ERROR); CFE_UtAssert_SUCCESS(CFE_ES_CleanupTaskResources(TaskId)); + + /* Corrupt the App/Task records as part of cleanup for branch coverage */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); + AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); + TaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); + /* Register the handler to set records back to used */ + UT_SetHandlerFunction(UT_KEY(CFE_SB_CleanUpApp), ES_UT_UsedAppTask, &TaskId); + CFE_UtAssert_SUCCESS(CFE_ES_CleanUpApp(AppId)); + UtAssert_BOOL_TRUE(CFE_ES_TaskRecordIsUsed(UtTaskRecPtr)); + UtAssert_BOOL_TRUE(CFE_ES_AppRecordIsUsed(UtAppRecPtr)); } void TestResourceID(void) @@ -1745,6 +1934,7 @@ void TestLibs(void) char LongLibraryName[sizeof(UtLibRecPtr->LibName) + 1]; CFE_ES_LibId_t Id; CFE_ES_ModuleLoadParams_t LoadParams; + CFE_ES_AppInfo_t LibInfo; /* Test shared library loading and initialization where the initialization * routine returns an error @@ -1777,6 +1967,10 @@ void TestLibs(void) UtAssert_INT32_EQ(CFE_ES_LoadLibrary(&Id, "TST_LIB", &LoadParams), CFE_ES_ERR_DUPLICATE_NAME); CFE_UtAssert_RESOURCEID_EQ(Id, CFE_ES_LibRecordGetID(UtLibRecPtr)); + /* Add an app and exercise name conflict */ + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_EARLY_INIT, "Conflict", NULL, NULL); + UtAssert_INT32_EQ(CFE_ES_LoadLibrary(&Id, "Conflict", &LoadParams), CFE_ES_ERR_DUPLICATE_NAME); + /* Test shared library loading and initialization where the library * fails to load */ @@ -1833,6 +2027,8 @@ void TestLibs(void) CFE_ES_Global.LibTable[2].LibId = CFE_ES_LIBID_UNDEFINED; UtAssert_BOOL_TRUE(CFE_ES_CheckLibIdSlotUsed(ES_UT_MakeLibIdForIndex(1))); UtAssert_BOOL_FALSE(CFE_ES_CheckLibIdSlotUsed(ES_UT_MakeLibIdForIndex(2))); + UtAssert_BOOL_TRUE(CFE_ES_CheckLibIdSlotUsed(CFE_RESOURCEID_UNDEFINED)); + /* * Test public Name+ID query/lookup API */ @@ -1846,7 +2042,13 @@ void TestLibs(void) UtAssert_INT32_EQ(CFE_ES_GetLibName(LongLibraryName, CFE_ES_LIBID_UNDEFINED, sizeof(LongLibraryName)), CFE_ES_ERR_RESOURCEID_NOT_VALID); UtAssert_INT32_EQ(CFE_ES_GetLibName(NULL, Id, sizeof(LongLibraryName)), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetLibName(LongLibraryName, Id, 0), CFE_ES_BAD_ARGUMENT); UtAssert_INT32_EQ(CFE_ES_GetLibIDByName(&Id, NULL), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetLibIDByName(NULL, "NotNULL"), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetLibInfo(NULL, Id), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetLibInfo(&LibInfo, CFE_ES_LIBID_UNDEFINED), CFE_ES_ERR_RESOURCEID_NOT_VALID); + CFE_UtAssert_SUCCESS(CFE_ES_GetLibInfo(&LibInfo, Id)); + UtAssert_INT32_EQ(CFE_ES_GetModuleInfo(NULL, CFE_RESOURCEID_UNDEFINED), CFE_ES_ERR_RESOURCEID_NOT_VALID); } void TestERLog(void) @@ -1857,7 +2059,7 @@ void TestERLog(void) UtPrintf("Begin Test Exception and Reset Log"); - /* Test initial rolling over log entry, + /* Test invalid log index, * null description, * and non-null context with small size */ @@ -1869,6 +2071,18 @@ void TestERLog(void) sizeof(CFE_ES_Global.ResetDataPtr->ERLog[0].BaseInfo.Description), "No Description String Given.", SIZE_MAX); + /* Test rollover log index, + * null description, + * and non-null context with small size + */ + ES_ResetUnitTest(); + CFE_ES_Global.ResetDataPtr->ERLogIndex = CFE_PLATFORM_ES_ER_LOG_ENTRIES - 1; + CFE_UtAssert_SUCCESS(CFE_ES_WriteToERLog(CFE_ES_LogEntryType_CORE, CFE_PSP_RST_TYPE_POWERON, 1, NULL)); + UtAssert_UINT32_EQ(CFE_ES_Global.ResetDataPtr->ERLogIndex, 0); + UtAssert_STRINGBUF_EQ(CFE_ES_Global.ResetDataPtr->ERLog[0].BaseInfo.Description, + sizeof(CFE_ES_Global.ResetDataPtr->ERLog[0].BaseInfo.Description), + "No Description String Given.", SIZE_MAX); + /* Test non-rolling over log entry, * null description, * and null context @@ -1944,8 +2158,9 @@ void TestGenericPool(void) * so that the implementation will sort them. */ 16, 56, 60, 40, 44, 48, 64, 128, 20, 24, 28, 12, 52, 32, 4, 8, 36}; - uint16 i; - uint32 ExpectedCount; + uint16 i; + uint32 ExpectedCount; + CFE_ES_GenPoolBD_t *BdPtr; ES_ResetUnitTest(); @@ -1998,9 +2213,16 @@ void TestGenericPool(void) UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, 1000), CFE_ES_ERR_MEM_BLOCK_SIZE); /* Call stats functions for coverage (no return code) */ - CFE_ES_GenPoolGetUsage(&Pool1, &FreeSize, &TotalSize); - CFE_ES_GenPoolGetCounts(&Pool1, &NumBlocks, &CountBuf, &ErrBuf); - CFE_ES_GenPoolGetBucketUsage(&Pool1, 1, &BlockStats); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetUsage(&Pool1, &FreeSize, &TotalSize)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetUsage(&Pool1, NULL, &TotalSize)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetUsage(&Pool1, &FreeSize, NULL)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetCounts(&Pool1, &NumBlocks, &CountBuf, &ErrBuf)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetCounts(&Pool1, &NumBlocks, &CountBuf, NULL)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetCounts(&Pool1, &NumBlocks, NULL, &ErrBuf)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetCounts(&Pool1, NULL, &CountBuf, &ErrBuf)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetBucketUsage(&Pool1, 1, &BlockStats)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetBucketUsage(&Pool1, 1, NULL)); + UtAssert_VOIDCALL(CFE_ES_GenPoolGetBucketUsage(&Pool1, Pool1.NumBuckets + 1, &BlockStats)); /* Check various outputs to ensure correctness */ CFE_UtAssert_MEMOFFSET_EQ(TotalSize, OffsetEnd); @@ -2087,7 +2309,7 @@ void TestGenericPool(void) * because its now fragmented. */ UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset2, 12), CFE_ES_ERR_MEM_BLOCK_SIZE); - /* Put the buffer, then corrupt the memory and try to recycle */ + /* Put the buffer, then corrupt the buffer descriptor and try to recycle */ CFE_UtAssert_SUCCESS(CFE_ES_GenPoolPutBlock(&Pool2, &BlockSize, Offset3)); memset(UT_MemPoolIndirectBuffer.Data, 0xee, sizeof(UT_MemPoolIndirectBuffer.Data)); UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool2, &Offset3, 56), CFE_ES_ERR_MEM_BLOCK_SIZE); @@ -2124,8 +2346,107 @@ void TestGenericPool(void) UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, 0), CFE_ES_BUFFER_NOT_IN_POOL); UtAssert_BOOL_TRUE(CFE_ES_GenPoolValidateState(&Pool1)); - Pool1.TailPosition = 0xFFFFFF; + Pool1.NumBuckets = CFE_PLATFORM_ES_POOL_MAX_BUCKETS + 1; UtAssert_BOOL_FALSE(CFE_ES_GenPoolValidateState(&Pool1)); + + Pool1.NumBuckets = 0; + UtAssert_BOOL_FALSE(CFE_ES_GenPoolValidateState(&Pool1)); + Pool1.NumBuckets = CFE_PLATFORM_ES_POOL_MAX_BUCKETS; + + Pool1.TailPosition = Pool1.PoolMaxOffset + 1; + UtAssert_BOOL_FALSE(CFE_ES_GenPoolValidateState(&Pool1)); + Pool1.TailPosition = Pool1.PoolMaxOffset; + + Pool1.PoolTotalSize = 0; + UtAssert_BOOL_FALSE(CFE_ES_GenPoolValidateState(&Pool1)); + + /* Recycle pool bad firstoffset, note creating new will still pass */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, ES_UT_PoolDirectCommit)); + CFE_UtAssert_SETUP(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + CFE_UtAssert_SETUP(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset1)); + Pool1.Buckets[0].FirstOffset = 0; + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + + /* Recycle pool buf with bad allocation info */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, ES_UT_PoolDirectCommit)); + CFE_UtAssert_SETUP(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + CFE_UtAssert_SETUP(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset1)); + CFE_UtAssert_SETUP(ES_UT_PoolDirectRetrieve(&Pool1, Offset1 - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE, &BdPtr)); + BdPtr->Allocated = 0; + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + + /* Retrieve failures, need to manually set up buffer for recycle */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolRetrieveFail, ES_UT_PoolDirectCommit)); + Pool1.Buckets[0].FirstOffset = 2; + Pool1.Buckets[0].ReleaseCount = Pool1.Buckets[0].RecycleCount + 1; + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize), CFE_ES_CDS_ACCESS_ERROR); + + /* Commit failures */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, ES_UT_PoolCommitFail)); + Pool1.Buckets[0].FirstOffset = CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE; + Pool1.Buckets[0].ReleaseCount = Pool1.Buckets[0].RecycleCount + 1; + CFE_UtAssert_SETUP(ES_UT_PoolDirectRetrieve(&Pool1, 0, &BdPtr)); + BdPtr->CheckBits = CFE_ES_CHECK_PATTERN; + BdPtr->Allocated = Pool1.NumBuckets + CFE_ES_MEMORY_DEALLOCATED; + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize), CFE_ES_CDS_ACCESS_ERROR); + + /* Branch coverage for zero block sizes case */ + UtAssert_ZERO(CFE_ES_GenPoolCalcMinSize(0, NULL, 0)); + + /* Branch coverage of error cases for getting block sizes */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, ES_UT_PoolDirectCommit)); + CFE_UtAssert_SETUP(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + CFE_UtAssert_SETUP(ES_UT_PoolDirectRetrieve(&Pool1, Offset1 - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE, &BdPtr)); + + BdPtr->ActualSize = Pool1.Buckets[0].BlockSize + 1; + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlockSize(&Pool1, &BlockSize, Offset1), CFE_ES_POOL_BLOCK_INVALID); + + BdPtr->ActualSize = 0; + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlockSize(&Pool1, &BlockSize, Offset1), CFE_ES_POOL_BLOCK_INVALID); + + UtAssert_INT32_EQ(CFE_ES_GenPoolGetBlockSize(&Pool1, NULL, 0), CFE_ES_BUFFER_NOT_IN_POOL); + + /* Put pool block with bad allocation info */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, ES_UT_PoolDirectCommit)); + CFE_UtAssert_SETUP(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + CFE_UtAssert_SETUP(ES_UT_PoolDirectRetrieve(&Pool1, Offset1 - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE, &BdPtr)); + BdPtr->CheckBits = ~CFE_ES_CHECK_PATTERN; + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset1), CFE_ES_POOL_BLOCK_INVALID); + BdPtr->CheckBits = CFE_ES_CHECK_PATTERN; + BdPtr->ActualSize = 0; + UtAssert_INT32_EQ(CFE_ES_GenPoolPutBlock(&Pool1, &BlockSize, Offset1), CFE_ES_POOL_BLOCK_INVALID); + + /* Rebuild generic pool actual size error cases */ + ES_ResetUnitTest(); + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolInitialize(&Pool1, 0, sizeof(UT_MemPoolIndirectBuffer.Data), 32, + CFE_PLATFORM_ES_POOL_MAX_BUCKETS, UT_POOL_BLOCK_SIZES, + ES_UT_PoolDirectRetrieve, ES_UT_PoolDirectCommit)); + /* Create an entry */ + CFE_UtAssert_SETUP(CFE_ES_GenPoolGetBlock(&Pool1, &Offset1, Pool1.Buckets[0].BlockSize)); + CFE_UtAssert_SETUP(ES_UT_PoolDirectRetrieve(&Pool1, Offset1 - CFE_ES_GENERIC_POOL_DESCRIPTOR_SIZE, &BdPtr)); + /* Corrupt the entry */ + BdPtr->ActualSize = Pool1.Buckets[0].BlockSize + 1; + /* Reset the structure so it will rebuild */ + Pool1.TailPosition = 0; + CFE_UtAssert_SUCCESS(CFE_ES_GenPoolRebuild(&Pool1)); } void TestTask(void) @@ -2156,10 +2477,14 @@ void TestTask(void) CFE_ES_QueryAllTasksCmd_t QueryAllTasksCmd; } CmdBuf; CFE_ES_AppRecord_t * UtAppRecPtr; + CFE_ES_AppRecord_t * UtAppRecPtr1; CFE_ES_TaskRecord_t * UtTaskRecPtr; CFE_ES_CDS_RegRec_t * UtCDSRegRecPtr; CFE_ES_MemPoolRecord_t *UtPoolRecPtr; CFE_SB_MsgId_t MsgId = CFE_SB_INVALID_MSG_ID; + CFE_ES_TaskId_t TaskId; + uint32 Idx; + uint32 Idx1; UtPrintf("Begin Test Task"); @@ -2481,6 +2806,16 @@ void TestTask(void) UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.ReloadAppCmd), UT_TPID_CFE_ES_CMD_RELOAD_APP_CC); CFE_UtAssert_EVENTSENT(CFE_ES_RELOAD_APP_DBG_EID); + /* Test app reload with filename parse error */ + ES_ResetUnitTest(); + memset(&CmdBuf, 0, sizeof(CmdBuf)); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, "CFE_ES", NULL, NULL); + strncpy(CmdBuf.ReloadAppCmd.Payload.Application, "CFE_ES", sizeof(CmdBuf.ReloadAppCmd.Payload.Application) - 1); + CmdBuf.ReloadAppCmd.Payload.Application[sizeof(CmdBuf.ReloadAppCmd.Payload.Application) - 1] = '\0'; + UT_SetDeferredRetcode(UT_KEY(CFE_FS_ParseInputFileNameEx), 1, CFE_FS_INVALID_PATH); + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.ReloadAppCmd), UT_TPID_CFE_ES_CMD_RELOAD_APP_CC); + CFE_UtAssert_EVENTSENT(CFE_ES_RELOAD_APP_ERR1_EID); + /* Test app reload with missing file */ ES_ResetUnitTest(); memset(&CmdBuf, 0, sizeof(CmdBuf)); @@ -2609,6 +2944,17 @@ void TestTask(void) UT_TPID_CFE_ES_CMD_QUERY_ALL_TASKS_CC); CFE_UtAssert_EVENTSENT(CFE_ES_TASKINFO_EID); + /* Test write of all task data with a task that becomes unused after first scan */ + ES_ResetUnitTest(); + memset(&CmdBuf, 0, sizeof(CmdBuf)); + ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_RUNNING, "CFE_ES", NULL, &UtTaskRecPtr); + TaskId = CFE_ES_TaskRecordGetID(UtTaskRecPtr); + UT_SetHandlerFunction(UT_KEY(CFE_FS_InitHeader), ES_UT_UnusedAppTask, &TaskId); + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.QueryAllTasksCmd), + UT_TPID_CFE_ES_CMD_QUERY_ALL_TASKS_CC); + CFE_UtAssert_EVENTSENT(CFE_ES_TASKINFO_EID); + /* TODO */ + /* Test write of all task data to a file with file name validation failure */ ES_ResetUnitTest(); memset(&CmdBuf, 0, sizeof(CmdBuf)); @@ -2650,7 +2996,7 @@ void TestTask(void) UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.ClearSysLogCmd), UT_TPID_CFE_ES_CMD_CLEAR_SYSLOG_CC); CFE_UtAssert_EVENTSENT(CFE_ES_SYSLOG1_INF_EID); - /* Test successful overwriting of the system log using discard mode */ + /* Test successful overwriting of the system log using overwrite mode */ ES_ResetUnitTest(); memset(&CmdBuf, 0, sizeof(CmdBuf)); CmdBuf.OverwriteSysLogCmd.Payload.Mode = CFE_ES_LogMode_OVERWRITE; @@ -2658,6 +3004,14 @@ void TestTask(void) UT_TPID_CFE_ES_CMD_OVER_WRITE_SYSLOG_CC); CFE_UtAssert_EVENTSENT(CFE_ES_SYSLOGMODE_EID); + /* Test successful overwriting of the system log using discard mode */ + ES_ResetUnitTest(); + memset(&CmdBuf, 0, sizeof(CmdBuf)); + CmdBuf.OverwriteSysLogCmd.Payload.Mode = CFE_ES_LogMode_DISCARD; + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.OverwriteSysLogCmd), + UT_TPID_CFE_ES_CMD_OVER_WRITE_SYSLOG_CC); + CFE_UtAssert_EVENTSENT(CFE_ES_SYSLOGMODE_EID); + /* Test overwriting the system log using an invalid mode */ ES_ResetUnitTest(); memset(&CmdBuf, 0, sizeof(CmdBuf)); @@ -2783,6 +3137,53 @@ void TestTask(void) UtAssert_INT32_EQ(UtAppRecPtr->ControlReq.AppControlRequest, CFE_ES_RunStatus_SYS_RESTART); UtAssert_STUB_COUNT(CFE_PSP_Restart, 0); + /* app restart without the restart app exception action should do system restart */ + ES_ResetUnitTest(); + UT_SetDefaultReturnValue(UT_KEY(CFE_PSP_Exception_GetCount), 1); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); + UT_ContextTask = CFE_ES_TaskId_ToOSAL(CFE_ES_TaskRecordGetID(UtTaskRecPtr)); + UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_GetSummary), &UT_ContextTask, sizeof(UT_ContextTask), false); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + UtAppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_PROC_RESTART; + CFE_ES_RunExceptionScan(0, NULL); + UtAssert_STUB_COUNT(CFE_PSP_Restart, 1); + + /* app out of sync restart with restart app request should do system restart */ + ES_ResetUnitTest(); + UT_SetDefaultReturnValue(UT_KEY(CFE_PSP_Exception_GetCount), 1); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr1, NULL); + UT_ContextTask = CFE_ES_TaskId_ToOSAL(CFE_ES_TaskRecordGetID(UtTaskRecPtr)); + UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_GetSummary), &UT_ContextTask, sizeof(UT_ContextTask), false); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + UtAppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_RESTART_APP; + CFE_UtAssert_SETUP(CFE_ES_AppID_ToIndex(UtAppRecPtr->AppId, &Idx)); + CFE_UtAssert_SETUP(CFE_ES_AppID_ToIndex(UtAppRecPtr1->AppId, &Idx1)); + + /* Match on the first conversion, corrupt for the second */ + UT_SetDataBuffer(UT_KEY(CFE_ResourceId_ToIndex), &Idx, sizeof(Idx1), false); + UT_SetDataBuffer(UT_KEY(CFE_ResourceId_ToIndex), &Idx1, sizeof(Idx), false); + UtAppRecPtr1->StartParams.ExceptionAction = CFE_ES_ExceptionAction_RESTART_APP; + CFE_ES_RunExceptionScan(0, NULL); + UtAssert_STUB_COUNT(CFE_PSP_Restart, 1); + + /* CFE_ES_GetTaskInfo failure */ + ES_ResetUnitTest(); + UT_SetDefaultReturnValue(UT_KEY(CFE_PSP_Exception_GetCount), 1); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr1, NULL); + UT_ContextTask = CFE_ES_TaskId_ToOSAL(CFE_ES_TaskRecordGetID(UtTaskRecPtr)); + UT_SetDataBuffer(UT_KEY(CFE_PSP_Exception_GetSummary), &UT_ContextTask, sizeof(UT_ContextTask), false); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + UtAppRecPtr->StartParams.ExceptionAction = CFE_ES_ExceptionAction_RESTART_APP; + CFE_UtAssert_SETUP(CFE_ES_AppID_ToIndex(UtAppRecPtr->AppId, &Idx)); + CFE_UtAssert_SETUP(CFE_ES_AppID_ToIndex(UtAppRecPtr1->AppId, &Idx1)); + + /* Corrupt first index */ + UT_SetDataBuffer(UT_KEY(CFE_ResourceId_ToIndex), &Idx1, sizeof(Idx), false); + UtAppRecPtr1->StartParams.ExceptionAction = CFE_ES_ExceptionAction_RESTART_APP; + CFE_ES_RunExceptionScan(0, NULL); + /* repeat, but for a CORE app, which cannot be restarted */ ES_ResetUnitTest(); UT_SetDefaultReturnValue(UT_KEY(CFE_PSP_Exception_GetCount), 1); @@ -3086,6 +3487,11 @@ void TestTask(void) UT_TPID_CFE_ES_CMD_DUMP_CDS_REGISTRY_CC); CFE_UtAssert_EVENTSENT(CFE_ES_CDS_REG_DUMP_INF_EID); + /* Dump CDS command with invalid length */ + ES_ResetUnitTest(); + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, 0, UT_TPID_CFE_ES_CMD_DUMP_CDS_REGISTRY_CC); + CFE_UtAssert_EVENTSENT(CFE_ES_LEN_ERR_EID); + /* Test error when sending Build Info event */ ES_ResetUnitTest(); UT_SetDeferredRetcode(UT_KEY(CFE_EVS_SendEvent), 1, CFE_EVS_INVALID_PARAMETER); @@ -3185,6 +3591,12 @@ void TestPerf(void) UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.PerfStartCmd), UT_TPID_CFE_ES_CMD_START_PERF_DATA_CC); CFE_UtAssert_EVENTSENT(CFE_ES_PERF_STARTCMD_ERR_EID); + /* Check again with pending state not idle */ + CFE_ES_Global.BackgroundPerfDumpState.CurrentState = CFE_ES_PerfDumpState_IDLE; + CFE_ES_Global.BackgroundPerfDumpState.PendingState = CFE_ES_PerfDumpState_INIT; + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.PerfStartCmd), UT_TPID_CFE_ES_CMD_START_PERF_DATA_CC); + CFE_UtAssert_EVENTSENT(CFE_ES_PERF_STARTCMD_ERR_EID); + /* Test performance data collection by sending another valid * start command */ @@ -3227,6 +3639,12 @@ void TestPerf(void) UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.PerfStopCmd), UT_TPID_CFE_ES_CMD_STOP_PERF_DATA_CC); CFE_UtAssert_EVENTSENT(CFE_ES_PERF_STOPCMD_ERR2_EID); + /* Repeat with pending state not IDLE */ + CFE_ES_Global.BackgroundPerfDumpState.CurrentState = CFE_ES_PerfDumpState_IDLE; + CFE_ES_Global.BackgroundPerfDumpState.PendingState = CFE_ES_PerfDumpState_INIT; + UT_CallTaskPipe(CFE_ES_TaskPipe, &CmdBuf.Msg, sizeof(CmdBuf.PerfStopCmd), UT_TPID_CFE_ES_CMD_STOP_PERF_DATA_CC); + CFE_UtAssert_EVENTSENT(CFE_ES_PERF_STOPCMD_ERR2_EID); + /* Test performance filter mask command with out of range filter mask value */ ES_ResetUnitTest(); @@ -3315,6 +3733,12 @@ void TestPerf(void) UtAssert_UINT32_EQ(Perf->MetaData.Mode, CFE_ES_PERF_TRIGGER_END); UtAssert_UINT32_EQ(Perf->MetaData.State, CFE_ES_PERF_IDLE); + /* Test addition where state goes to idle after first check */ + ES_ResetUnitTest(); + Perf->MetaData.State = CFE_ES_PERF_TRIGGERED; + UT_SetHandlerFunction(UT_KEY(OS_MutSemTake), ES_UT_SetPerfIdle, NULL); + CFE_ES_PerfLogAdd(1, 0); + /* Test addition of a new entry to the performance log with an invalid * marker after an invalid marker has already been reported */ @@ -3456,6 +3880,22 @@ void TestPerf(void) /* should have written 4 entries to the log */ UtAssert_UINT32_EQ(CFE_ES_Global.BackgroundPerfDumpState.FileSize, sizeof(CFE_ES_PerfDataEntry_t) * 4); + /* Cover close file branch with undefined file descriptor */ + ES_ResetUnitTest(); + memset(&CFE_ES_Global.BackgroundPerfDumpState, 0, sizeof(CFE_ES_Global.BackgroundPerfDumpState)); + CFE_ES_Global.BackgroundPerfDumpState.FileDesc = OS_OBJECT_ID_UNDEFINED; + CFE_ES_Global.BackgroundPerfDumpState.CurrentState = CFE_ES_PerfDumpState_IDLE; + CFE_ES_Global.BackgroundPerfDumpState.PendingState = CFE_ES_PerfDumpState_CLOSE_FILE; + CFE_ES_RunPerfLogDump(1000, &CFE_ES_Global.BackgroundPerfDumpState); + + /* Cover default current state switch branch with nonzero statecounter */ + ES_ResetUnitTest(); + memset(&CFE_ES_Global.BackgroundPerfDumpState, 0, sizeof(CFE_ES_Global.BackgroundPerfDumpState)); + CFE_ES_Global.BackgroundPerfDumpState.StateCounter = 1; + CFE_ES_Global.BackgroundPerfDumpState.CurrentState = CFE_ES_PerfDumpState_INIT; + CFE_ES_Global.BackgroundPerfDumpState.PendingState = CFE_ES_PerfDumpState_INIT; + CFE_ES_RunPerfLogDump(1000, &CFE_ES_Global.BackgroundPerfDumpState); + /* Confirm that the "CFE_ES_GetPerfLogDumpRemaining" function works. * This requires that the state is not idle, in order to get nonzero results. */ @@ -3476,6 +3916,8 @@ void TestAPI(void) { osal_id_t TestObjId; char AppName[OS_MAX_API_NAME + 12]; + char SysLogBuf[CFE_TIME_PRINTED_STRING_SIZE + 20]; + uint32 SysLogBufSize; uint32 StackBuf[8]; uint8 Data[12]; uint32 ResetType; @@ -3489,6 +3931,9 @@ void TestAPI(void) UtPrintf("Begin Test API"); + /* Coverage for processing async event */ + UtAssert_VOIDCALL(CFE_ES_ProcessAsyncEvent()); + /* Test resetting the cFE with a processor reset */ ES_ResetUnitTest(); ResetType = CFE_PSP_RST_TYPE_PROCESSOR; @@ -3523,6 +3968,7 @@ void TestAPI(void) /* Test restarting an app with an ID out of range (high) */ ES_ResetUnitTest(); + UT_SetDeferredRetcode(UT_KEY(CFE_ResourceId_ToIndex), 1, -1); AppId = CFE_ES_APPID_C(ES_UT_MakeAppIdForIndex(99999)); UtAssert_INT32_EQ(CFE_ES_RestartApp(AppId), CFE_ES_ERR_RESOURCEID_NOT_VALID); @@ -3600,17 +4046,22 @@ void TestAPI(void) CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_CORE_APP_EXIT]); UtAssert_UINT32_EQ(UtAppRecPtr->ControlReq.AppControlRequest, CFE_ES_RunStatus_APP_ERROR); + /* Exit app with undefined exit status and not a core app */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_STOPPED, "UT", &UtAppRecPtr, NULL); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + CFE_ES_ExitApp(CFE_ES_RunStatus_UNDEFINED); + CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_CORE_APP_EXIT]); + UtAssert_UINT32_EQ(UtAppRecPtr->ControlReq.AppControlRequest, CFE_ES_RunStatus_APP_ERROR); + #if 0 - /* Can't cover this path since it contains a while(1) (i.e., - * infinite) loop - */ - OS_TaskCreate(&TestObjId, "UT", NULL, NULL, 0, 0, 0); - Id = ES_UT_OSALID_TO_ARRAYIDX(TestObjId); - CFE_ES_TaskRecordSetUsed(TaskRecPtr); - TaskRecPtr->AppId = Id; - AppRecPtr->Type = CFE_ES_AppType_EXTERNAL; - AppRecPtr->AppState = CFE_ES_AppState_RUNNING; - CFE_ES_ExitApp(CFE_ES_RunStatus_CORE_APP_RUNTIME_ERROR); + /* Can't cover EXTERNAL CFE_ES_ExitApp since it contains a while(1) (infinte loop) */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_STOPPED, "UT", &UtAppRecPtr, NULL); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; + CFE_ES_ExitApp(CFE_ES_RunStatus_APP_EXIT); + CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_EXTERNAL_APP_EXIT]); + UtAssert_UINT32_EQ(UtAppRecPtr->ControlReq.AppControlRequest, CFE_ES_RunStatus_APP_EXIT); #endif /* Test successful run loop app run request */ @@ -3652,8 +4103,8 @@ void TestAPI(void) /* Test run loop with a NULL run status */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); - UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_RUN; - UtAssert_BOOL_TRUE(CFE_ES_RunLoop(NULL)); + UtAppRecPtr->ControlReq.AppControlRequest = CFE_ES_RunStatus_APP_EXIT; + UtAssert_BOOL_FALSE(CFE_ES_RunLoop(NULL)); /* Test run loop with startup sync code */ ES_ResetUnitTest(); @@ -3663,12 +4114,20 @@ void TestAPI(void) UtAssert_BOOL_TRUE(CFE_ES_RunLoop(&RunStatus)); UtAssert_UINT32_EQ(UtAppRecPtr->AppState, CFE_ES_AppState_RUNNING); + /* Hit NULL TaskRecPtr case */ + ES_ResetUnitTest(); + UT_SetDeferredRetcode(UT_KEY(OS_ObjectIdToArrayIndex), 1, OS_ERROR); + UtAssert_VOIDCALL(CFE_ES_IncrementTaskCounter()); + /* Test getting the cFE application and task ID by context */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, "UT", NULL, NULL); CFE_UtAssert_SUCCESS(CFE_ES_GetAppID(&AppId)); CFE_UtAssert_SUCCESS(CFE_ES_GetTaskID(&TaskId)); + /* Convert task ID to index with NULL index */ + UtAssert_INT32_EQ(CFE_ES_TaskID_ToIndex(TaskId, NULL), CFE_ES_BAD_ARGUMENT); + /* Test CFE_ES_GetAppID error with null pointer parameter */ ES_ResetUnitTest(); UtAssert_INT32_EQ(CFE_ES_GetAppID(NULL), CFE_ES_BAD_ARGUMENT); @@ -3699,6 +4158,10 @@ void TestAPI(void) AppId = CFE_ES_AppRecordGetID(UtAppRecPtr); CFE_UtAssert_SUCCESS(CFE_ES_GetAppName(AppName, AppId, sizeof(AppName))); + /* Bad arguement calls */ + UtAssert_INT32_EQ(CFE_ES_GetAppName(NULL, AppId, sizeof(AppName)), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetAppName(AppName, AppId, 0), CFE_ES_BAD_ARGUMENT); + /* Test getting task information using the task ID - NULL buffer */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, &UtTaskRecPtr); @@ -3805,6 +4268,14 @@ void TestAPI(void) CFE_ES_TaskEntryPoint(); UtAssert_STUB_COUNT(ES_UT_TaskFunction, 1); + /* Case where not fully set up */ + UtTaskRecPtr->AppId = CFE_ES_APPID_UNDEFINED; + CFE_ES_TaskEntryPoint(); + UtAssert_STUB_COUNT(ES_UT_TaskFunction, 1); + + /* NULL pointer protection logic coverage */ + UtAssert_INT32_EQ(CFE_ES_GetTaskFunction(NULL), CFE_ES_ERR_APP_REGISTER); + /* Test deleting a child task when task is not active/valid */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, "UT", NULL, &UtTaskRecPtr); @@ -3867,6 +4338,15 @@ void TestAPI(void) /* Verify requirement to report error */ CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_CANNOT_CALL_APP_MAIN]); + /* Test with mismatched AppId */ + ES_ResetUnitTest(); + ES_UT_SetupSingleAppId(CFE_ES_AppType_EXTERNAL, CFE_ES_AppState_RUNNING, NULL, &UtAppRecPtr, NULL); + ES_UT_SetupChildTaskId(UtAppRecPtr, NULL, &UtTaskRecPtr); + TestObjId = CFE_ES_TaskId_ToOSAL(CFE_ES_TaskRecordGetID(UtTaskRecPtr)); /* Set context to that of child */ + UtAppRecPtr->AppId = CFE_ES_APPID_UNDEFINED; + CFE_ES_ExitChildTask(); + CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_CANNOT_CALL_APP_MAIN]); + /* Test exiting a child task with an error retrieving the app ID */ ES_ResetUnitTest(); CFE_ES_ExitChildTask(); @@ -3897,12 +4377,6 @@ void TestAPI(void) ES_ResetUnitTest(); UtAssert_UINT32_EQ(CFE_ES_CalculateCRC(&Data, 12, 345353, CFE_MISSION_ES_CRC_16), 2688); - /* - * CRC memory read failure test case removed in #322 - - * deprecated CFE_PSP_MemRead8, now the FSW code does a direct read - * which has no failure path. - */ - /* Test calculating a CRC on a range of memory using CRC type 32 * NOTE: This capability is not currently implemented in cFE */ @@ -3914,6 +4388,11 @@ void TestAPI(void) ES_ResetUnitTest(); UtAssert_UINT32_EQ(CFE_ES_CalculateCRC(&Data, 12, 345353, -1), 0); + /* Test NULL and zero size */ + ES_ResetUnitTest(); + UtAssert_UINT32_EQ(CFE_ES_CalculateCRC(NULL, 12, 345353, CFE_MISSION_ES_CRC_16), 345353); + UtAssert_UINT32_EQ(CFE_ES_CalculateCRC(&Data, 0, 345353, CFE_MISSION_ES_CRC_16), 345353); + /* Test shared mutex take with a take error */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_RUNNING, "UT", NULL, NULL); @@ -3960,13 +4439,6 @@ void TestAPI(void) */ UtAssert_VOIDCALL(CFE_ES_WaitForStartupSync(99)); - /* Test adding a time-stamped message to the system log using an invalid - * log mode - * - * TEST CASE REMOVED as the invalid log mode follow the same path as Discard, - * this test case added nothing new - */ - /* Test successfully adding a time-stamped message to the system log that * causes the log index to be reset */ @@ -3986,6 +4458,27 @@ void TestAPI(void) CFE_UtAssert_SUCCESS(CFE_ES_WriteToSysLog("SysLogText")); UtAssert_UINT32_LTEQ(CFE_ES_Global.ResetDataPtr->SystemLogWriteIdx, CFE_PLATFORM_ES_SYSTEM_LOG_SIZE - 1); + /* Test NULL spec string */ + ES_ResetUnitTest(); + UtAssert_INT32_EQ(CFE_ES_WriteToSysLog(NULL), CFE_ES_BAD_ARGUMENT); + + /* Invalid buffer size to CFE_ES_SysLog_vsnprintf */ + ES_ResetUnitTest(); + memset(SysLogBuf, 0, sizeof(SysLogBuf)); + UtAssert_VOIDCALL(ES_UT_SysLog_snprintf(SysLogBuf, 0, "b")); + UtAssert_ZERO(strlen(SysLogBuf)); + + /* Fill buffer with time call for branch coverage */ + ES_ResetUnitTest(); + memset(SysLogBuf, 0, sizeof(SysLogBuf)); + SysLogBufSize = sizeof(SysLogBuf); + UT_SetHandlerFunction(UT_KEY(CFE_TIME_Print), ES_UT_FillBuffer, &SysLogBufSize); + UtAssert_VOIDCALL(ES_UT_SysLog_snprintf(SysLogBuf, sizeof(SysLogBuf), "b")); + + /* Force a vsnprintf failure */ + ES_ResetUnitTest(); + UtAssert_VOIDCALL(ES_UT_SysLog_snprintf(SysLogBuf, sizeof(SysLogBuf), NULL)); + /* Test run loop with an application error status */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_RUNNING, "UT", &UtAppRecPtr, NULL); @@ -4003,19 +4496,27 @@ void TestAPI(void) UtAssert_INT32_EQ(CFE_ES_GetTaskName(AppName, CFE_ES_TASKID_UNDEFINED, sizeof(AppName)), CFE_ES_ERR_RESOURCEID_NOT_VALID); UtAssert_INT32_EQ(CFE_ES_GetTaskName(NULL, TaskId, sizeof(AppName)), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetTaskName(AppName, TaskId, 0), CFE_ES_BAD_ARGUMENT); CFE_UtAssert_SUCCESS(CFE_ES_GetTaskName(AppName, TaskId, sizeof(AppName))); UT_SetDeferredRetcode(UT_KEY(OS_GetResourceName), 1, OS_ERROR); UtAssert_INT32_EQ(CFE_ES_GetTaskName(AppName, TaskId, sizeof(AppName)), CFE_ES_ERR_RESOURCEID_NOT_VALID); + UtAssert_INT32_EQ(CFE_ES_GetTaskID(NULL), CFE_ES_BAD_ARGUMENT); UtAssert_INT32_EQ(CFE_ES_GetTaskIDByName(&TaskId, NULL), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetTaskIDByName(NULL, "NotNULL"), CFE_ES_BAD_ARGUMENT); CFE_UtAssert_SUCCESS(CFE_ES_GetTaskIDByName(&TaskId, AppName)); UT_SetDeferredRetcode(UT_KEY(OS_TaskGetIdByName), 1, OS_ERROR); UtAssert_INT32_EQ(CFE_ES_GetTaskIDByName(&TaskId, "Nonexistent"), CFE_ES_ERR_NAME_NOT_FOUND); + + /* Hit error case for NULL TaskRecPtr */ + ES_ResetUnitTest(); + UT_SetDeferredRetcode(UT_KEY(OS_TaskGetId), 1, OS_OBJECT_ID_UNDEFINED); + UtAssert_INT32_EQ(CFE_ES_GetTaskID(&TaskId), CFE_ES_ERR_RESOURCEID_NOT_VALID); } void TestGenericCounterAPI(void) { - char CounterName[11]; + char CounterName[OS_MAX_API_NAME + 1]; CFE_ES_CounterId_t CounterId; CFE_ES_CounterId_t CounterId2; uint32 CounterCount; @@ -4051,6 +4552,7 @@ void TestGenericCounterAPI(void) CFE_ES_Global.CounterTable[2].CounterId = CFE_ES_COUNTERID_UNDEFINED; UtAssert_BOOL_TRUE(CFE_ES_CheckCounterIdSlotUsed(ES_UT_MakeCounterIdForIndex(1))); UtAssert_BOOL_FALSE(CFE_ES_CheckCounterIdSlotUsed(ES_UT_MakeCounterIdForIndex(2))); + UtAssert_BOOL_TRUE(CFE_ES_CheckCounterIdSlotUsed(CFE_RESOURCEID_UNDEFINED)); /* Test getting a registered generic counter that doesn't exist */ UtAssert_INT32_EQ(CFE_ES_GetGenCounterIDByName(&CounterId, "Counter999"), CFE_ES_ERR_NAME_NOT_FOUND); @@ -4091,15 +4593,23 @@ void TestGenericCounterAPI(void) CFE_ES_GetGenCount(CounterId, &CounterCount); UtAssert_INT32_EQ(CounterCount, 5); + /* Test getting a generic (valid) counter where the count is null */ + UtAssert_INT32_EQ(CFE_ES_GetGenCount(CounterId, NULL), CFE_ES_BAD_ARGUMENT); + /* Test registering a generic counter with a null counter ID pointer */ ES_ResetUnitTest(); UtAssert_INT32_EQ(CFE_ES_RegisterGenCounter(NULL, "Counter1"), CFE_ES_BAD_ARGUMENT); /* Test registering a generic counter with a null counter name */ ES_ResetUnitTest(); - UtAssert_INT32_EQ(CFE_ES_RegisterGenCounter(&CounterId, NULL), CFE_ES_BAD_ARGUMENT); + /* Register a generic counter with a name that is too long */ + ES_ResetUnitTest(); + memset(CounterName, 'a', sizeof(CounterName) - 1); + CounterName[sizeof(CounterName) - 1] = 0; + UtAssert_INT32_EQ(CFE_ES_RegisterGenCounter(&CounterId, CounterName), CFE_ES_BAD_ARGUMENT); + /* Test incrementing a generic counter where the record is not in use */ ES_ResetUnitTest(); UtAssert_INT32_EQ(CFE_ES_IncrementGenCounter(CounterId), CFE_ES_BAD_ARGUMENT); @@ -4112,9 +4622,9 @@ void TestGenericCounterAPI(void) ES_ResetUnitTest(); UtAssert_INT32_EQ(CFE_ES_GetGenCount(CounterId, &CounterCount), CFE_ES_BAD_ARGUMENT); - /* Test getting a generic counter where the count is null */ + /* Test deleting a generic counter where the record is not in use */ ES_ResetUnitTest(); - UtAssert_INT32_EQ(CFE_ES_GetGenCount(CounterId, NULL), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_DeleteGenCounter(CounterId), CFE_ES_BAD_ARGUMENT); /* Test getting a registered generic counter ID using a null counter * pointer @@ -4134,6 +4644,7 @@ void TestGenericCounterAPI(void) UtAssert_INT32_EQ(CFE_ES_GetGenCounterName(CounterName, CFE_ES_COUNTERID_UNDEFINED, sizeof(CounterName)), CFE_ES_ERR_RESOURCEID_NOT_VALID); UtAssert_INT32_EQ(CFE_ES_GetGenCounterName(NULL, CounterId, sizeof(CounterName)), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetGenCounterName(CounterName, CounterId, 0), CFE_ES_BAD_ARGUMENT); UtAssert_INT32_EQ(CFE_ES_GetGenCounterIDByName(&CounterId, NULL), CFE_ES_BAD_ARGUMENT); } @@ -4168,9 +4679,19 @@ void TestCDS() /* Test the CDS Cache Fetch/Flush/Load routine error cases */ ES_ResetUnitTest(); UtAssert_INT32_EQ(CFE_ES_CDS_CacheFetch(&CFE_ES_Global.CDSVars.Cache, 4, 0), CFE_ES_CDS_INVALID_SIZE); + UtAssert_INT32_EQ( + CFE_ES_CDS_CacheFetch(&CFE_ES_Global.CDSVars.Cache, 4, sizeof(CFE_ES_Global.CDSVars.Cache.Data) + 1), + CFE_ES_CDS_INVALID_SIZE); + UtAssert_INT32_EQ(CFE_ES_CDS_CacheFlush(&CFE_ES_Global.CDSVars.Cache), CFE_ES_CDS_INVALID_SIZE); + + /* Size too big */ + CFE_ES_Global.CDSVars.Cache.Size = sizeof(CFE_ES_Global.CDSVars.Cache.Data) + 1; UtAssert_INT32_EQ(CFE_ES_CDS_CacheFlush(&CFE_ES_Global.CDSVars.Cache), CFE_ES_CDS_INVALID_SIZE); UtAssert_INT32_EQ(CFE_ES_CDS_CachePreload(&CFE_ES_Global.CDSVars.Cache, NULL, 4, 0), CFE_ES_CDS_INVALID_SIZE); + UtAssert_INT32_EQ( + CFE_ES_CDS_CachePreload(&CFE_ES_Global.CDSVars.Cache, NULL, 4, sizeof(CFE_ES_Global.CDSVars.Cache.Data) + 1), + CFE_ES_CDS_INVALID_SIZE); TempSize = 5; CFE_UtAssert_SUCCESS(CFE_ES_CDS_CachePreload(&CFE_ES_Global.CDSVars.Cache, &TempSize, 4, 4)); @@ -4209,6 +4730,10 @@ void TestCDS() /* No reset here -- just attempt to register the same name again */ CFE_UtAssert_SUCCESS(CFE_ES_RegisterCDS(&CDSHandle, 6, "Name")); + /* Register a new size with a read CDS failure */ + UT_SetDeferredRetcode(UT_KEY(CFE_PSP_ReadFromCDS), 1, OS_ERROR); + UtAssert_INT32_EQ(CFE_ES_RegisterCDS(&CDSHandle, 8, "Name"), CFE_ES_CDS_ACCESS_ERROR); + /* Test CDS registering using a null name */ UtAssert_INT32_EQ(CFE_ES_RegisterCDS(&CDSHandle, 4, ""), CFE_ES_CDS_INVALID_NAME); @@ -4234,6 +4759,7 @@ void TestCDS() CFE_ES_Global.CDSVars.Registry[2].BlockID = CFE_ES_CDS_BAD_HANDLE; UtAssert_BOOL_TRUE(CFE_ES_CheckCDSHandleSlotUsed(ES_UT_MakeCDSIdForIndex(1))); UtAssert_BOOL_FALSE(CFE_ES_CheckCDSHandleSlotUsed(ES_UT_MakeCDSIdForIndex(2))); + UtAssert_BOOL_TRUE(CFE_ES_CheckCDSHandleSlotUsed(CFE_RESOURCEID_UNDEFINED)); /* Test CDS registering using a bad app ID */ ES_ResetUnitTest(); @@ -4253,9 +4779,15 @@ void TestCDS() CDSHandle = CFE_ES_CDSBlockRecordGetID(UtCDSRegRecPtr); CFE_UtAssert_SUCCESS(CFE_ES_CopyToCDS(CDSHandle, &BlockData)); + /* Copy to CDS with NULL */ + UtAssert_INT32_EQ(CFE_ES_CopyToCDS(CDSHandle, NULL), CFE_ES_BAD_ARGUMENT); + /* Test successfully restoring from a CDS */ CFE_UtAssert_SUCCESS(CFE_ES_RestoreFromCDS(&BlockData, CDSHandle)); + /* Restore from CDS with NULL */ + UtAssert_INT32_EQ(CFE_ES_RestoreFromCDS(NULL, CDSHandle), CFE_ES_BAD_ARGUMENT); + /* Test CDS registering using a name longer than the maximum allowed */ ES_ResetUnitTest(); ES_UT_SetupSingleAppId(CFE_ES_AppType_CORE, CFE_ES_AppState_RUNNING, "UT", NULL, NULL); @@ -4416,6 +4948,13 @@ void TestCDS() UT_SetDeferredRetcode(UT_KEY(CFE_PSP_ReadFromCDS), 3, OS_ERROR); CFE_UtAssert_SUCCESS(CFE_ES_CDS_EarlyInit()); + /* Fail writing to CDS during CFE_ES_ClearCDS for branch coverage */ + ES_ResetUnitTest(); + UT_SetDeferredRetcode(UT_KEY(CFE_PSP_ReadFromCDS), 3, OS_ERROR); + UT_SetDeferredRetcode(UT_KEY(CFE_PSP_WriteToCDS), 1, OS_ERROR); + UtAssert_INT32_EQ(CFE_ES_CDS_EarlyInit(), CFE_ES_CDS_ACCESS_ERROR); + UtAssert_STUB_COUNT(CFE_PSP_WriteToCDS, 1); + /* Test CDS initialization where initializing the CDS registry fails */ ES_ResetUnitTest(); UT_SetDeferredRetcode(UT_KEY(CFE_PSP_WriteToCDS), 1, OS_ERROR); @@ -4446,7 +4985,14 @@ void TestCDS() UtAssert_INT32_EQ(CFE_ES_GetCDSBlockName(CDSName, CFE_ES_CDS_BAD_HANDLE, sizeof(CDSName)), CFE_ES_ERR_RESOURCEID_NOT_VALID); UtAssert_INT32_EQ(CFE_ES_GetCDSBlockName(NULL, CDSHandle, sizeof(CDSName)), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetCDSBlockName(CDSName, CDSHandle, 0), CFE_ES_BAD_ARGUMENT); UtAssert_INT32_EQ(CFE_ES_GetCDSBlockIDByName(&CDSHandle, NULL), CFE_ES_BAD_ARGUMENT); + UtAssert_INT32_EQ(CFE_ES_GetCDSBlockIDByName(NULL, "NotNULL"), CFE_ES_BAD_ARGUMENT); + + /* Try to get block with CDS unavailable */ + CFE_ES_Global.CDSIsAvailable = false; + UtAssert_INT32_EQ(CFE_ES_GetCDSBlockIDByName(&CDSHandle, "NotNULL"), CFE_ES_NOT_IMPLEMENTED); + UtAssert_INT32_EQ(CFE_ES_GetCDSBlockName(CDSName, CDSHandle, sizeof(CDSName)), CFE_ES_NOT_IMPLEMENTED); } /* End TestCDS */ @@ -4520,7 +5066,6 @@ void TestCDSMempool(void) --UtCdsRegRecPtr->BlockOffset; UtAssert_INT32_EQ(CFE_ES_CDSBlockWrite(BlockHandle, &Data), CFE_ES_POOL_BLOCK_INVALID); UtAssert_INT32_EQ(CFE_ES_CDSBlockRead(&Data, BlockHandle), CFE_ES_POOL_BLOCK_INVALID); - ++UtCdsRegRecPtr->BlockOffset; /* Corrupt/change the block size, should trigger invalid size error */ @@ -4556,6 +5101,15 @@ void TestCDSMempool(void) CdsPtr[UtCdsRegRecPtr->BlockOffset] ^= 0x02; /* Bit flip */ UtAssert_INT32_EQ(CFE_ES_CDSBlockRead(&Data, BlockHandle), CFE_ES_CDS_BLOCK_CRC_ERR); CdsPtr[UtCdsRegRecPtr->BlockOffset] ^= 0x02; /* Fix Bit */ + + /* Set up again with a CDS that is too small to get branch coverage */ + /* Test CDS block access */ + ES_ResetUnitTest(); + ES_UT_SetupCDSGlobal(ES_UT_CDS_SMALL_TEST_SIZE); + ES_UT_SetupSingleCDSRegistry("UT", sizeof(CFE_ES_CDS_BlockHeader_t) - 2, false, &UtCdsRegRecPtr); + BlockHandle = CFE_ES_CDSBlockRecordGetID(UtCdsRegRecPtr); + UtAssert_INT32_EQ(CFE_ES_CDSBlockWrite(BlockHandle, &Data), CFE_ES_CDS_INVALID_SIZE); + UtAssert_INT32_EQ(CFE_ES_CDSBlockRead(&Data, BlockHandle), CFE_ES_CDS_INVALID_SIZE); } void TestESMempool(void) @@ -4651,6 +5205,9 @@ void TestESMempool(void) */ UtAssert_INT32_EQ(CFE_ES_GetMemPoolStats(&Stats, CFE_ES_MEMHANDLE_UNDEFINED), CFE_ES_ERR_RESOURCEID_NOT_VALID); + /* NULL pointer protection */ + UtAssert_INT32_EQ(CFE_ES_GetMemPoolStats(NULL, PoolID2), CFE_ES_BAD_ARGUMENT); + /* Test successfully getting memory pool statistics */ CFE_UtAssert_SUCCESS(CFE_ES_GetMemPoolStats(&Stats, PoolID1)); @@ -4672,6 +5229,15 @@ void TestESMempool(void) UtAssert_INT32_EQ(CFE_ES_PutPoolBuf(PoolID2, CFE_ES_MEMPOOLBUF_C((cpuaddr)addressp2 - 40)), CFE_ES_BUFFER_NOT_IN_POOL); + /* Allocate a buffer, corrupt retrieve function and put to get path coverage */ + UtAssert_INT32_EQ(CFE_ES_GetPoolBuf(&addressp2, PoolID2, 256), 256); + PoolPtr->Pool.Retrieve = ES_UT_PoolRetrieveFail; + UtAssert_INT32_EQ(CFE_ES_PutPoolBuf(PoolID2, addressp2), CFE_ES_CDS_ACCESS_ERROR); + + /* Validate handle with a corrupt pool */ + PoolPtr->Pool.PoolTotalSize = 0; + UtAssert_BOOL_FALSE(CFE_ES_ValidateHandle(PoolID2)); + /* Test initializing a pre-allocated pool specifying a number of block * sizes greater than the maximum */ @@ -4701,6 +5267,8 @@ void TestESMempool(void) * Test to use default block sizes if none are given */ CFE_UtAssert_SUCCESS(CFE_ES_PoolCreateEx(&PoolID1, Buffer1, sizeof(Buffer1), 0, NULL, CFE_ES_USE_MUTEX)); + UtAssert_INT32_EQ(CFE_ES_PoolCreateEx(&PoolID1, Buffer1, sizeof(Buffer1), 1, NULL, CFE_ES_USE_MUTEX), + CFE_ES_BAD_ARGUMENT); /* * Test creating a memory pool after the limit reached (no slots) @@ -4716,6 +5284,7 @@ void TestESMempool(void) CFE_ES_Global.MemPoolTable[2].PoolID = CFE_ES_MEMHANDLE_UNDEFINED; UtAssert_BOOL_TRUE(CFE_ES_CheckMemPoolSlotUsed(ES_UT_MakePoolIdForIndex(1))); UtAssert_BOOL_FALSE(CFE_ES_CheckMemPoolSlotUsed(ES_UT_MakePoolIdForIndex(2))); + UtAssert_BOOL_TRUE(CFE_ES_CheckMemPoolSlotUsed(CFE_RESOURCEID_UNDEFINED)); /* * Test creating a memory pool with a semaphore error @@ -4869,8 +5438,12 @@ void TestESMempool(void) /* Verify requirement to report error */ CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_GETPOOL_BAD_HANDLE]); - /* Test getting the size of an existing pool buffer using a null handle */ + /* NULL protection */ + UtAssert_INT32_EQ(CFE_ES_GetPoolBuf(NULL, PoolID1, 256), CFE_ES_BAD_ARGUMENT); + + /* Test getting the size of an existing pool buffer using undefined handle, NULL buff */ UtAssert_INT32_EQ(CFE_ES_GetPoolBufInfo(CFE_ES_MEMHANDLE_UNDEFINED, addressp1), CFE_ES_ERR_RESOURCEID_NOT_VALID); + UtAssert_INT32_EQ(CFE_ES_GetPoolBufInfo(PoolID1, NULL), CFE_ES_BAD_ARGUMENT); /* Test initializing a pre-allocated pool specifying a small block size */ ES_ResetUnitTest(); @@ -4911,8 +5484,9 @@ void TestESMempool(void) UtAssert_INT32_EQ(CFE_ES_GetPoolBufInfo(PoolID1, CFE_ES_MEMPOOLBUF_C((cpuaddr)addressp1 + 400)), CFE_ES_BUFFER_NOT_IN_POOL); - /* Test getting the size of a pool buffer with an invalid memory handle */ + /* Test getting the size of a pool buffer with an invalid memory handle, NULL buffer */ UtAssert_INT32_EQ(CFE_ES_PutPoolBuf(CFE_ES_MEMHANDLE_UNDEFINED, addressp1), CFE_ES_ERR_RESOURCEID_NOT_VALID); + UtAssert_INT32_EQ(CFE_ES_PutPoolBuf(PoolID1, NULL), CFE_ES_BAD_ARGUMENT); } /* Tests to fill gaps in coverage in SysLog */ @@ -5024,8 +5598,9 @@ void TestBackground(void) memset(&CFE_ES_Global.BackgroundPerfDumpState, 0, sizeof(CFE_ES_Global.BackgroundPerfDumpState)); UT_SetDefaultReturnValue(UT_KEY(OS_write), -10); CFE_ES_Global.BackgroundPerfDumpState.CurrentState = CFE_ES_PerfDumpState_INIT; - UT_SetDeferredRetcode(UT_KEY(OS_BinSemTimedWait), 3, -4); - CFE_ES_BackgroundTask(); + UT_SetDeferredRetcode(UT_KEY(OS_BinSemTimedWait), 2, OS_SEM_TIMEOUT); + UT_SetDeferredRetcode(UT_KEY(OS_BinSemTimedWait), 1, -4); + UtAssert_VOIDCALL(CFE_ES_BackgroundTask()); CFE_UtAssert_PRINTF(UT_OSP_MESSAGES[UT_OSP_BACKGROUND_TAKE]); /* The number of jobs running should be 1 (perf log dump) */ diff --git a/modules/sb/ut-coverage/sb_UT.c b/modules/sb/ut-coverage/sb_UT.c index da88d7151..c42c5865d 100644 --- a/modules/sb/ut-coverage/sb_UT.c +++ b/modules/sb/ut-coverage/sb_UT.c @@ -695,9 +695,13 @@ void Test_SB_Cmds_RoutingInfoDataGetter(void) CFE_SB_MsgId_t MsgId4 = SB_UT_TLM_MID5; CFE_SB_MsgId_t MsgId5 = SB_UT_TLM_MID6; uint16 PipeDepth = 10; + uint16 i; void * LocalBuffer; size_t LocalBufSize; CFE_SB_BackgroundFileStateInfo_t State; + CFE_SB_PipeD_t * PipeDscPtr; + CFE_SB_DestinationD_t * DestPtr; + CFE_SB_DestinationD_t * DestPtrSave; /* Create some map info */ CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); @@ -715,7 +719,16 @@ void Test_SB_Cmds_RoutingInfoDataGetter(void) LocalBuffer = NULL; LocalBufSize = 0; - UtAssert_BOOL_FALSE(CFE_SB_WriteRouteInfoDataGetter(&State, 0, &LocalBuffer, &LocalBufSize)); + /* Loop through records including one unused */ + for (i = 0; i < 5; i++) + { + UtAssert_BOOL_FALSE(CFE_SB_WriteRouteInfoDataGetter(&State, i, &LocalBuffer, &LocalBufSize)); + UtAssert_NOT_NULL(LocalBuffer); + UtAssert_NONZERO(LocalBufSize); + } + + /* Last record should return TRUE but valid entries */ + UtAssert_BOOL_TRUE(CFE_SB_WriteRouteInfoDataGetter(&State, i, &LocalBuffer, &LocalBufSize)); UtAssert_NOT_NULL(LocalBuffer); UtAssert_NONZERO(LocalBufSize); @@ -723,6 +736,22 @@ void Test_SB_Cmds_RoutingInfoDataGetter(void) CFE_SB_WriteRouteInfoDataGetter(&State, CFE_PLATFORM_SB_MAX_MSG_IDS, &LocalBuffer, &LocalBufSize)); UtAssert_ZERO(LocalBufSize); + /* Hit max destination limit by corrupting head pointer, point to self (bug avoidance code) */ + DestPtr = CFE_SBR_GetDestListHeadPtr(CFE_SBR_ValueToRouteId(1)); + DestPtrSave = DestPtr->Next; + DestPtr->Next = DestPtr; + UtAssert_VOIDCALL(CFE_SB_CollectRouteInfo(CFE_SBR_ValueToRouteId(1), &State)); + DestPtr->Next = DestPtrSave; + + /* Hit invalid PipeId case by corrupting PipeId (bug avoidance code) */ + PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId1); + PipeDscPtr->PipeId = CFE_SB_INVALID_PIPE; + UtAssert_VOIDCALL(CFE_SB_CollectRouteInfo(CFE_SBR_ValueToRouteId(0), &State)); + PipeDscPtr->PipeId = PipeId1; + + /* Hit invalid MsgId for route by passing in invalid route (bug avoidance code) */ + UtAssert_VOIDCALL(CFE_SB_CollectRouteInfo(CFE_SBR_ValueToRouteId(CFE_PLATFORM_SB_MAX_MSG_IDS), &State)); + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId1)); CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId2)); CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId3)); @@ -1510,7 +1539,8 @@ void Test_SB_Cmds_SendPrevSubs(void) NumEvts += 1; } - CFE_UtAssert_SETUP(CFE_SB_SubscribeLocal(MsgId, PipeId2, MsgLim)); + /* Additional unique local route to hit while loop destptr == NULL branch */ + CFE_UtAssert_SETUP(CFE_SB_SubscribeLocal(CFE_SB_ValueToMsgId(i), PipeId2, MsgLim)); /* For 3 internal TransmitMsg calls */ MsgIdCmd = CFE_SB_ValueToMsgId(CFE_SB_ALLSUBS_TLM_MID); @@ -1531,7 +1561,7 @@ void Test_SB_Cmds_SendPrevSubs(void) CFE_SB_ProcessCmdPipePkt(&SendPrevSubs.SBBuf); - NumEvts += 8; /* +2 for the subscribe, +6 for the SEND_PREV_SUBS_CC */ + NumEvts += 7; /* +1 for the local subscribe, +6 for the SEND_PREV_SUBS_CC */ /* Event count is only exact if there were no collisions */ if (UT_EventIsInHistory(CFE_SB_HASHCOLLISION_EID)) @@ -1871,6 +1901,8 @@ void Test_CreatePipe_MaxPipes(void) CFE_SB_Global.PipeTbl[2].PipeId = CFE_SB_INVALID_PIPE; UtAssert_BOOL_TRUE(CFE_SB_CheckPipeDescSlotUsed(UT_SB_MakePipeIdForIndex(1))); UtAssert_BOOL_FALSE(CFE_SB_CheckPipeDescSlotUsed(UT_SB_MakePipeIdForIndex(2))); + UT_SetDeferredRetcode(UT_KEY(CFE_ResourceId_ToIndex), 1, -1); + UtAssert_BOOL_TRUE(CFE_SB_CheckPipeDescSlotUsed(UT_SB_MakePipeIdForIndex(1))); } /* end Test_CreatePipe_MaxPipes */ @@ -2505,6 +2537,9 @@ void Test_Subscribe_MaxMsgIdCount(void) CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId1, PipeDepth, "TestPipe1")); CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId2, PipeDepth, "TestPipe2")); + /* For code coverage set PeakMsgIdsInUse so it won't always increment */ + CFE_SB_Global.StatTlmMsg.Payload.PeakMsgIdsInUse = 1; + for (i = 0; i < CFE_PLATFORM_SB_MAX_MSG_IDS + 1; i++) { if (i < CFE_PLATFORM_SB_MAX_MSG_IDS) @@ -3317,9 +3352,18 @@ void Test_TransmitMsg_GetPoolBufErr(void) UtAssert_INT32_EQ(CFE_SB_TransmitMsg(&TlmPkt.Hdr.Msg, true), CFE_SB_BUF_ALOC_ERR); CFE_UtAssert_EVENTCOUNT(3); - CFE_UtAssert_EVENTSENT(CFE_SB_GET_BUF_ERR_EID); + /* Repeat buf descriptor allocation failed with event denied */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_SetDeferredRetcode(UT_KEY(CFE_ES_GetPoolBuf), 1, CFE_ES_ERR_MEM_BLOCK_SIZE); + UT_SetDeferredRetcode(UT_KEY(CFE_ES_TaskID_ToIndex), 1, -1); + UtAssert_INT32_EQ(CFE_SB_TransmitMsg(&TlmPkt.Hdr.Msg, true), CFE_SB_BUF_ALOC_ERR); + + /* Confirm no additional events sent */ + CFE_UtAssert_EVENTCOUNT(3); + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); } /* end Test_TransmitMsg_GetPoolBufErr */ @@ -3449,6 +3493,19 @@ void Test_TransmitBuffer_IncrementSeqCnt(void) CFE_UtAssert_EVENTSENT(CFE_SB_SUBSCRIPTION_RCVD_EID); + /* Test again with message validation failure */ + SendPtr = CFE_SB_AllocateMessageBuffer(sizeof(SB_UT_Test_Tlm_t)); + if (SendPtr == NULL) + { + UtAssert_Failed("Unexpected NULL pointer returned from ZeroCopyGetPtr"); + } + + MsgId = CFE_SB_INVALID_MSG_ID; + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + UtAssert_INT32_EQ(CFE_SB_TransmitBuffer(SendPtr, true), CFE_SB_BAD_ARGUMENT); + CFE_UtAssert_EVENTSENT(CFE_SB_SEND_INV_MSGID_EID); + CFE_UtAssert_SUCCESS(CFE_SB_ReleaseMessageBuffer(SendPtr)); + /* Test an unsuccessful zero copy send */ UtAssert_INT32_EQ(CFE_SB_TransmitBuffer(NULL, true), CFE_SB_BAD_ARGUMENT); @@ -3710,6 +3767,26 @@ static void SB_UT_PipeIdModifyHandler(void *UserObj, UT_EntryKey_t FuncKey, cons PipeDscPtr->PipeId = CFE_SB_INVALID_PIPE; } +/* Special handler to hit OS_QueueGet error casses */ +static void SB_UT_QueueGetHandler(void *UserObj, UT_EntryKey_t FuncKey, const UT_StubContext_t *Context) +{ + size_t **data = (size_t **)UT_Hook_GetArgValueByName(Context, "data", void *); + size_t * size_copied = UT_Hook_GetArgValueByName(Context, "size_copied", size_t *); + int32 status = OS_SUCCESS; + + *data = UserObj; + + if (*data == NULL) + { + *size_copied = sizeof(CFE_SB_BufferD_t *); + } + else + { + *size_copied = *((size_t *)UserObj); + } + UT_Stub_SetReturnValue(FuncKey, status); +} + /* ** Test receiving a message from the software bus with an invalid pipe ID */ @@ -3825,6 +3902,7 @@ void Test_ReceiveBuffer_PipeReadError(void) CFE_SB_Buffer_t *SBBufPtr; CFE_SB_PipeId_t PipeId; uint32 PipeDepth = 10; + size_t Data = 1; CFE_UtAssert_SETUP(CFE_SB_CreatePipe(&PipeId, PipeDepth, "RcvTestPipe")); UT_SetDeferredRetcode(UT_KEY(OS_QueueGet), 1, OS_ERROR); @@ -3834,6 +3912,13 @@ void Test_ReceiveBuffer_PipeReadError(void) CFE_UtAssert_EVENTSENT(CFE_SB_Q_RD_ERR_EID); + /* Set handler to exercise error conditions for OS_QueueGet */ + UT_SetHandlerFunction(UT_KEY(OS_QueueGet), SB_UT_QueueGetHandler, &Data); + UtAssert_INT32_EQ(CFE_SB_ReceiveBuffer(&SBBufPtr, PipeId, CFE_SB_PEND_FOREVER), CFE_SB_PIPE_RD_ERR); + UT_SetHandlerFunction(UT_KEY(OS_QueueGet), SB_UT_QueueGetHandler, NULL); + UtAssert_INT32_EQ(CFE_SB_ReceiveBuffer(&SBBufPtr, PipeId, CFE_SB_PEND_FOREVER), CFE_SB_PIPE_RD_ERR); + UT_SetHandlerFunction(UT_KEY(OS_QueueGet), NULL, NULL); + CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); } /* end Test_ReceiveBuffer_PipeReadError */ @@ -4198,6 +4283,7 @@ void Test_CFE_SB_ZeroCopyReleaseAppId(void) */ void Test_SB_SpecialCases(void) { + SB_UT_ADD_SUBTEST(Test_UseCount_Rollover_Prevention); SB_UT_ADD_SUBTEST(Test_OS_MutSem_ErrLogic); SB_UT_ADD_SUBTEST(Test_ReqToSendEvent_ErrLogic); SB_UT_ADD_SUBTEST(Test_PutDestBlk_ErrLogic); @@ -4212,6 +4298,20 @@ void Test_SB_SpecialCases(void) SB_UT_ADD_SUBTEST(Test_MessageString); } /* end Test_SB_SpecialCases */ +/* + * Test the use count rollover prevetion + */ +void Test_UseCount_Rollover_Prevention(void) +{ + CFE_SB_BufferD_t bd; + uint16 usecount_expected = 0x7FFF; + + /* Note this is just for coverage, limit can not be reached in nomal ops (would be a bug) */ + bd.UseCount = usecount_expected; + UtAssert_VOIDCALL(CFE_SB_IncrBufUseCnt(&bd)); + UtAssert_UINT32_EQ(bd.UseCount, usecount_expected); +} + /* ** Test pipe creation with semaphore take and give failures */ @@ -4568,6 +4668,8 @@ void Test_SB_TransmitMsgPaths_IgnoreOpt(void) int32 PipeDepth = 2; CFE_MSG_Type_t Type = CFE_MSG_Type_Tlm; CFE_MSG_Size_t Size = sizeof(TlmPkt); + CFE_SB_PipeD_t * PipeDscPtr; + CFE_ES_AppId_t AppId; /* Setup Test skipping sending to a pipe when the pipe option is set to ignore */ MsgId = SB_UT_TLM_MID; @@ -4581,6 +4683,23 @@ void Test_SB_TransmitMsgPaths_IgnoreOpt(void) /* Test skipping this pipe and the send should pass */ CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(&TlmPkt.Hdr.Msg, true)); + UtAssert_STUB_COUNT(OS_QueuePut, 0); + + /* Set up and send again without matching ApId and it should transmit */ + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetMsgId), &MsgId, sizeof(MsgId), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetSize), &Size, sizeof(Size), false); + UT_SetDataBuffer(UT_KEY(CFE_MSG_GetType), &Type, sizeof(Type), false); + PipeDscPtr = CFE_SB_LocatePipeDescByID(PipeId); + AppId = PipeDscPtr->AppId; + PipeDscPtr->AppId = CFE_ES_APPID_UNDEFINED; + + /* Also hit case where not the peak depth */ + PipeDscPtr->PeakQueueDepth += 2; + CFE_UtAssert_SUCCESS(CFE_SB_TransmitMsg(&TlmPkt.Hdr.Msg, true)); + UtAssert_STUB_COUNT(OS_QueuePut, 1); + + /* Set AppId back so it can be deleted */ + PipeDscPtr->AppId = AppId; CFE_UtAssert_TEARDOWN(CFE_SB_SetPipeOpts(PipeId, 0)); CFE_UtAssert_TEARDOWN(CFE_SB_DeletePipe(PipeId)); diff --git a/modules/sb/ut-coverage/sb_UT.h b/modules/sb/ut-coverage/sb_UT.h index 083402e6b..0f1d422be 100644 --- a/modules/sb/ut-coverage/sb_UT.h +++ b/modules/sb/ut-coverage/sb_UT.h @@ -2349,6 +2349,22 @@ void Test_CFE_SB_ZeroCopyReleaseAppId(void); ******************************************************************************/ void Test_SB_SpecialCases(void); +/*****************************************************************************/ +/** +** \brief Test Use Count rollover protection +** +** \par Description +** This function tests a buffer descriptor with the max possible +** use count. +** +** \par Assumptions, External Events, and Notes: +** None +** +** \returns +** This function does not return a value. +******************************************************************************/ +void Test_UseCount_Rollover_Prevention(void); + /*****************************************************************************/ /** ** \brief Test pipe creation with semaphore take and give failures