diff --git a/src/deviceutils/device_api.c b/src/deviceutils/device_api.c index 747f92ae..cc092a44 100644 --- a/src/deviceutils/device_api.c +++ b/src/deviceutils/device_api.c @@ -40,6 +40,65 @@ #define MAC_ADDRESS_LEN 17 +/* function isSecureDbgSrvUnlocked - determines whether secure debug services may be enabled for the given build type. + * Usage: bool isSecureDbgSrvUnlocked(BUILDTYPE eBuildType) + * + * For non-prod builds, debug services are always unlocked. + * + * For ePROD builds, debug services are unlocked only when all of the following are true: + * - debug services are enabled via isDebugServicesEnabled() (RFC-controlled), + * - the LABSIGNED_ENABLED device property indicates a labsigned image, and + * - the deviceType value from RFC allows test devices (for example "test"). + * + * RETURN - true if secure debug services are allowed to run for the given build type; false otherwise. + */ +bool isSecureDbgSrvUnlocked(BUILDTYPE eBuildType) +{ + char deviceType[16] = {0}; + bool isDebugServicesUnlocked = false; + char labsigned[8] = {0}; + int ret = -1; + + if ((eBuildType != ePROD) && (eBuildType != eUNKNOWN)) { + isDebugServicesUnlocked = true; + } + + else if (eBuildType == ePROD) + { + bool dbgServices = isDebugServicesEnabled(); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + ret = getDevicePropertyData("LABSIGNED_ENABLED", labsigned, sizeof(labsigned)); + if (ret == UTILS_SUCCESS) + { + if (0 == strncmp(labsigned, "true", 4)) + { + if ((strcmp(deviceType, "test") == 0) && dbgServices) + { + isDebugServicesUnlocked = true; + } + else + { + SWLOG_INFO("isSecureDbgSrvUnlocked: unable to enable debug services...\n"); + } + } + else + { + SWLOG_INFO("LABSIGNED_ENABLED not enabled (value: %s); debug services remain locked\n", labsigned); + } + } + else + { + SWLOG_ERROR("%s: getDevicePropertyData() for LABSIGNED_ENABLED failed\n", __FUNCTION__); + } + SWLOG_INFO("isSecureDbgSrvUnlocked: dbgServices=%s, deviceType=%s, LABSIGNED_ENABLED=%s\n", dbgServices ? "true" : "false", deviceType, labsigned); + } + if(isDebugServicesUnlocked){ + SWLOG_INFO("isSecureDbgSrvUnlocked: Enabling debug services...\n"); + t2ValNotify("SYST_INFO_FW_DbgSrv", "true"); + } + return isDebugServicesUnlocked; +} + /* function GetServerUrlFile - scans a file for a URL. Usage: size_t GetServerUrlFile @@ -891,7 +950,6 @@ size_t GetServURL( char *pServURL, size_t szBufSize ) BUILDTYPE eBuildType; char buf[URL_MAX_LEN]; bool skip = false; - bool dbgServices = isDebugServicesEnabled(); //check debug services enabled if( pServURL != NULL ) { @@ -899,7 +957,7 @@ size_t GetServURL( char *pServURL, size_t szBufSize ) GetBuildType( buf, sizeof(buf), &eBuildType ); if( isInStateRed() ) { - if(( eBuildType != ePROD ) || ( dbgServices == true )) + if(isSecureDbgSrvUnlocked(eBuildType)) { len = GetServerUrlFile( pServURL, szBufSize, STATE_RED_CONF ); } @@ -910,7 +968,7 @@ size_t GetServURL( char *pServURL, size_t szBufSize ) } else { - if(( eBuildType != ePROD ) || ( dbgServices == true )) + if(isSecureDbgSrvUnlocked(eBuildType)) { if( (filePresentCheck( SWUPDATE_CONF ) == RDK_API_SUCCESS) ) // if the file exists { diff --git a/src/deviceutils/device_api.h b/src/deviceutils/device_api.h index 7318f715..a4d15da7 100644 --- a/src/deviceutils/device_api.h +++ b/src/deviceutils/device_api.h @@ -23,6 +23,10 @@ #define GETRDMMANIFESTVERSION_IN_SCRIPT #endif +#ifdef GTEST_ENABLE +#include "rdkv_cdl_log_wrapper.h" +#endif + #ifndef GTEST_ENABLE #include "rdk_fwdl_utils.h" #include "common_device_api.h" @@ -301,4 +305,22 @@ size_t GetTR181Url(TR181URL eURL, char *pUrlOut, size_t szBufSize); */ size_t GetServURL(char *pServURL, size_t szBufSize); +/* function isSecureDbgSrvUnlocked - determines whether the secure debug service may be unlocked. + * + * The decision is based on: + * - DbgServices RFC + * - DeviceType RFC + * - build type (Prod vs non-Prod; e.g. ePROD vs known non-ePROD types; eUNKNOWN is + * treated as locked/Prod-like) + * - LABSIGNED_ENABLED property value from /etc/device.properties + * + * Usage: bool isSecureDbgSrvUnlocked(BUILDTYPE eBuildType) + * + * RETURN - true if: + * - the build type is non-Prod (i.e. not ePROD and not eUNKNOWN); or + * - the build type is Prod, DbgServices RFC is enabled, + * DeviceType is "test", and LABSIGNED_ENABLED is set to true; + * false otherwise (including when the build type is eUNKNOWN). + */ +bool isSecureDbgSrvUnlocked(BUILDTYPE eBuildType); #endif diff --git a/src/include/rfcinterface.h b/src/include/rfcinterface.h index 24fcf37b..c7994a7e 100644 --- a/src/include/rfcinterface.h +++ b/src/include/rfcinterface.h @@ -86,6 +86,7 @@ typedef struct rfcdetails { #define RFC_FW_REBOOT_NOTIFY "Device.DeviceInfo.X_RDKCENTRAL-COM_xOpsDeviceMgmt.RPC.RebootPendingNotification" #define RFC_FW_AUTO_EXCLUDE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.FWUpdate.AutoExcluded.Enable" #define RFC_DEBUGSRV "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Identity.DbgServices.Enable" +#define RFC_DEVICETYPE "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Identity.DeviceType" #define RFC_XCONF_CHECK_NOW "Device.X_COMCAST-COM_Xcalibur.Client.xconfCheckNow" @@ -98,5 +99,6 @@ int isMtlsEnabled(const char *); int isIncremetalCDLEnable(const char *file_name); bool isMmgbleNotifyEnabled(void); bool isDebugServicesEnabled(void); +void getDeviceTypeRFC(char *deviceType, size_t size); #endif /* VIDEO_RFCINTERFACE_RFCINTERFACE_H_ */ diff --git a/src/rfcInterface/rfcinterface.c b/src/rfcInterface/rfcinterface.c index 79527ed2..e7ad2d73 100644 --- a/src/rfcInterface/rfcinterface.c +++ b/src/rfcInterface/rfcinterface.c @@ -25,6 +25,7 @@ #include "rdk_fwdl_utils.h" #include "system_utils.h" #endif +#include /* * Description: Get RFC data and store inside structure. @@ -308,3 +309,36 @@ bool isDebugServicesEnabled(void) } return status; } + + +/* Description: Reads the device type RFC value and copies it into the provided buffer. + * @param deviceType Output buffer that receives the device type string ("test", "prod", or "unknown"). + * @param size Size of the deviceType buffer in bytes; must be greater than 0. The string is always NUL-terminated. + * @return void. On error or unrecognized RFC value, "unknown" is written to deviceType (if size > 0). + */ +void getDeviceTypeRFC(char *deviceType, size_t size ){ + + if (deviceType == NULL || size == 0){ + SWLOG_ERROR("%s: Invalid Arguments Passed...\n", __FUNCTION__); + return; + } + + const char* type = "unknown"; + char rfc_data[RFC_VALUE_BUF_SIZE] = {0}; + int ret = read_RFCProperty("DEVICETYPE", RFC_DEVICETYPE, rfc_data, sizeof(rfc_data)); + + if (ret == -1) { + SWLOG_ERROR("%s: Failed to read device type\n", __FUNCTION__); + } + + SWLOG_INFO("%s: RFC device type = %s\n", __FUNCTION__, rfc_data); + + if (strncasecmp(rfc_data, "prod", 4) == 0) { + type = "prod"; + } else if (strncasecmp(rfc_data, "test", 4) == 0) { + type = "test"; + } + + strncpy(deviceType, type, size - 1); + deviceType[size - 1] = '\0'; +} diff --git a/unittest/deviceutils/device_api_gtest.cpp b/unittest/deviceutils/device_api_gtest.cpp index f7918bbd..23e62bee 100644 --- a/unittest/deviceutils/device_api_gtest.cpp +++ b/unittest/deviceutils/device_api_gtest.cpp @@ -35,6 +35,7 @@ using namespace testing; using namespace std; using ::testing::Return; using ::testing::StrEq; +using ::testing::Invoke; //DeviceUtilsMock *g_DeviceApiMock = NULL; @@ -496,6 +497,190 @@ TEST_F(DeviceApiTestFixture, TestName_GetFileContents_Fail) } */ +/* isSecureDbgSrvUnlocked tests: verify the new ePROD gating logic that requires + * isDebugServicesEnabled (RFC), deviceType == "test" (RFC), and LABSIGNED_ENABLED == "true" + * to all be true before unlocking debug services on production builds. + */ + +/* Non-PROD build type: debug services are always unlocked regardless of other conditions */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_NonProd_AlwaysUnlocked) +{ + EXPECT_TRUE(isSecureDbgSrvUnlocked(eVBN)); +} + +/* ePROD + labsigned=true + deviceType=test + dbgServices=true → unlocked */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_Labsigned_DeviceTypeTest_DbgEnabled) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_CALL(*g_DeviceUtilsMock, + t2ValNotify(StrEq("SYST_INFO_FW_DbgSrv"), StrEq("true"))); + EXPECT_TRUE(isSecureDbgSrvUnlocked(ePROD)); +} + +/* ePROD + labsigned=true + deviceType=prod (not "test") → locked */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_Labsigned_DeviceTypeProd_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "prod", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} + +/* ePROD + labsigned=true + deviceType=unknown → locked */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_Labsigned_DeviceTypeUnknown_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "unknown", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} + +/* ePROD + labsigned=false → locked regardless of deviceType or dbgServices */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_LabsignedFalse_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "false", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} + +/* ePROD + labsigned=true + deviceType=test + dbgServices=false → locked */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_Labsigned_DeviceTypeTest_DbgDisabled_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(false)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} + +/* ePROD + getDevicePropertyData fails → locked */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_LabsignedPropertyFails_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} +/* eUNKNOWN build type → false (neither non-prod nor ePROD path triggers unlock) */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Unknown_Locked) +{ + EXPECT_FALSE(isSecureDbgSrvUnlocked(eUNKNOWN)); +} + +/* eDEV build type → true (non-prod, always unlocked) */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Dev_Unlocked) +{ + EXPECT_TRUE(isSecureDbgSrvUnlocked(eDEV)); +} + +/* eQA build type → true (non-prod, always unlocked) */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_QA_Unlocked) +{ + EXPECT_TRUE(isSecureDbgSrvUnlocked(eQA)); +} + +/* ePROD + labsigned=true + deviceType=prod + dbgServices=false → locked ("unable to enable debug services") */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_Labsigned_DeviceTypeProd_DbgDisabled_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(false)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "prod", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} + +/* ePROD + labsigned empty string → locked ("LABSIGNED_ENABLED not enabled" log path) */ +TEST_F(DeviceApiTestFixture, TestName_isSecureDbgSrvUnlocked_Prod_LabsignedEmpty_Locked) +{ + EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int /*size*/) { + data[0] = '\0'; + return 0; + })); + EXPECT_FALSE(isSecureDbgSrvUnlocked(ePROD)); +} TEST_F(DeviceApiTestFixture, TestName_GetServURL_Nullcheck) { EXPECT_EQ(GetServURL(NULL, 0), 0); @@ -509,7 +694,6 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessStatered_DebugServices_E //EXPECT_CALL(*g_DeviceUtilsMock, read_RFCProperty(_, _, _, _)).Times(1).WillOnce(Return(1)); ret = system("echo \"BUILD_TYPE=vbn\" > /tmp/device_gtest.prop"); //EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(1)); - EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); ret = system("echo \"https://www.statered.com\" > /tmp/stateredrecovry.conf"); ret = GetServURL(output, sizeof(output)); EXPECT_EQ(strncmp(output,servUrl,strlen(servUrl)),0); @@ -528,7 +712,6 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessStatered_DebugServices_D //EXPECT_CALL(*g_DeviceUtilsMock, read_RFCProperty(_, _, _, _)).Times(1).WillOnce(Return(1)); ret = system("echo \"BUILD_TYPE=vbn\" > /tmp/device_gtest.prop"); //EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(1)); - EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(false)); ret = system("echo \"https://www.statered.com\" > /tmp/stateredrecovry.conf"); ret = GetServURL(output, sizeof(output)); EXPECT_EQ(strncmp(output,servUrl,strlen(servUrl)),0); @@ -548,6 +731,22 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessStatered_Prod_DebugServi ret = system("echo \"BUILD_TYPE=PROD\" > /tmp/device_gtest.prop"); //EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(1)); EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); + EXPECT_CALL(*g_DeviceUtilsMock, + t2ValNotify(StrEq("SYST_INFO_FW_DbgSrv"), StrEq("true"))) + .Times(1); ret = system("echo \"https://www.statered.com\" > /tmp/stateredrecovry.conf"); ret = GetServURL(output, sizeof(output)); EXPECT_EQ(strncmp(output,servUrl,strlen(servUrl)),0); @@ -567,6 +766,19 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessStatered_Prod_DebugServi ret = system("echo \"BUILD_TYPE=PROD\" > /tmp/device_gtest.prop"); //EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(1)); EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(false)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); ret = system("echo \"https://www.statered.com\" > /tmp/stateredrecovry.conf"); ret = system("echo \"https://www.autotool.com\" > /tmp/swupdate.conf"); EXPECT_CALL(*g_DeviceUtilsMock, read_RFCProperty(_, _, _, _)) @@ -594,7 +806,6 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessSwupdate_DebugServices_E EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(0)); //EXPECT_CALL(*g_DeviceUtilsMock, read_RFCProperty(_, _, _, _)).Times(1).WillOnce(Return(1)); ret = system("echo \"BUILD_TYPE=vbn\" > /tmp/device_gtest.prop"); - EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); ret = system("echo \"https://www.rdkautotool.com\" > /tmp/swupdate.conf"); ret=GetServURL(output , sizeof(output)); EXPECT_EQ(strncmp(output , servUrl , strlen(servUrl)),0); @@ -614,7 +825,6 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessSwupdate_DebugServices_D EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(0)); //EXPECT_CALL(*g_DeviceUtilsMock, read_RFCProperty(_, _, _, _)).Times(1).WillOnce(Return(1)); ret = system("echo \"BUILD_TYPE=vbn\" > /tmp/device_gtest.prop"); - EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(false)); ret = system("echo \"https://www.rdkautotool.com\" > /tmp/swupdate.conf"); ret=GetServURL(output , sizeof(output)); EXPECT_EQ(strncmp(output , servUrl , strlen(servUrl)),0); @@ -634,6 +844,19 @@ TEST_F(DeviceApiTestFixture, TestName_GetServURL_SuccessSwupdate_Prod_DebugServi EXPECT_CALL(*g_DeviceUtilsMock, filePresentCheck(_)).Times(1).WillOnce(Return(0)); ret = system("echo \"BUILD_TYPE=PROD\" > /tmp/device_gtest.prop"); EXPECT_CALL(*g_DeviceUtilsMock, isDebugServicesEnabled()).Times(1).WillOnce(Return(true)); + EXPECT_CALL(*g_DeviceUtilsMock, getDeviceTypeRFC(_, _)) + .Times(1) + .WillOnce(Invoke([](char* deviceType, size_t size) { + strncpy(deviceType, "test", size - 1); + deviceType[size - 1] = '\0'; + })); + EXPECT_CALL(*g_DeviceUtilsMock, getDevicePropertyData(StrEq("LABSIGNED_ENABLED"), _, _)) + .Times(1) + .WillOnce(Invoke([](const char* /*model*/, char* data, int size) { + strncpy(data, "true", size - 1); + data[size - 1] = '\0'; + return 0; + })); ret = system("echo \"https://www.rdkautotool.com\" > /tmp/swupdate.conf"); ret=GetServURL(output , sizeof(output)); EXPECT_EQ(strncmp(output , servUrl , strlen(servUrl)),0); diff --git a/unittest/fwdl_interface_gtest.cpp b/unittest/fwdl_interface_gtest.cpp index 87aca214..682a11dd 100644 --- a/unittest/fwdl_interface_gtest.cpp +++ b/unittest/fwdl_interface_gtest.cpp @@ -171,6 +171,129 @@ TEST_F(InterfaceTestFixture, TestName_isDebugServicesEnableSuccess) EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)).Times(1).WillOnce(Return(1)); EXPECT_EQ(isDebugServicesEnabled(), true); } +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCNullArgs) +{ + /* NULL buffer and zero size must not crash and must not call getRFCParameter */ + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)).Times(0); + char buf[16]; + memset(buf, 'X', sizeof(buf)); + getDeviceTypeRFC(NULL, sizeof(buf)); + getDeviceTypeRFC(buf, 0); + /* buf[0] must remain 'X' because size == 0 means nothing should be written */ + EXPECT_EQ(buf[0], 'X'); +} +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCReadFailure) +{ + /* When RFC read fails, result must be "unknown" */ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)).Times(1).WillOnce(Return(0)); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "unknown"); +} +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCProd) +{ + /* When RFC value is "prod", result must be "prod" */ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "prod"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "prod"); +} +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCTest) +{ + /* When RFC value is "test", result must be "test" */ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "test"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "test"); +} +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCUnknown) +{ + /* When RFC value is unrecognized, result must be "unknown" */ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "staging"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "unknown"); +} +/* Case-insensitive match: "PROD" (uppercase) → "prod" */ +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCProdUpperCase) +{ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "PROD"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "prod"); +} +/* Case-insensitive match: "TEST" (uppercase) → "test" */ +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCTestUpperCase) +{ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "TEST"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "test"); +} +/* Case-insensitive match: "Prod" (mixed case) → "prod" */ +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCProdMixedCase) +{ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "Prod"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "prod"); +} +/* Buffer size = 1 → empty NUL-terminated string (truncation edge case) */ +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCBufferSizeOne) +{ + char deviceType[1] = {'X'}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", "prod"); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, 1); + EXPECT_EQ(deviceType[0], '\0'); +} +/* Empty string from RFC → "unknown" */ +TEST_F(InterfaceTestFixture, TestName_getDeviceTypeRFCEmptyString) +{ + char deviceType[32] = {0}; + EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)) + .Times(1) + .WillOnce(Invoke([](char* /*type*/, const char* /*key*/, RFC_ParamData_t *param) { + snprintf(param->value, sizeof(param->value), "%s", ""); + return WDMP_SUCCESS; + })); + getDeviceTypeRFC(deviceType, sizeof(deviceType)); + EXPECT_STREQ(deviceType, "unknown"); +} TEST_F(InterfaceTestFixture, TestName_isIncremetalCDLEnableSuccess) { EXPECT_CALL(*g_InterfaceMock, getRFCParameter(_, _, _)).Times(1).WillOnce(Return(1)); diff --git a/unittest/mocks/dbus_handlers_gmock.cpp b/unittest/mocks/dbus_handlers_gmock.cpp index 595bc578..c39968d4 100644 --- a/unittest/mocks/dbus_handlers_gmock.cpp +++ b/unittest/mocks/dbus_handlers_gmock.cpp @@ -607,6 +607,16 @@ bool isDebugServicesEnabled(void) { return false; // Debug services not enabled by default } +extern "C" { +void getDeviceTypeRFC(char *deviceType, size_t size) { + if (deviceType && size > 0) { + const char defaultType[] = "unknown"; + strncpy(deviceType, defaultType, size - 1); + deviceType[size - 1] = '\0'; + } + return; +} +} int isInStateRed(void) { return 0; // Not in RED state by default } diff --git a/unittest/mocks/deviceutils_mock.cpp b/unittest/mocks/deviceutils_mock.cpp index d7cdb51c..c2ba73bf 100644 --- a/unittest/mocks/deviceutils_mock.cpp +++ b/unittest/mocks/deviceutils_mock.cpp @@ -56,6 +56,30 @@ extern "C" FILE* v_secure_popen(const char *mode, ...) return g_DeviceUtilsMock->v_secure_popen(mode, cmd); }*/ +extern "C" void getDeviceTypeRFC(char *deviceType, size_t size) +{ + if (g_DeviceUtilsMock) + { + g_DeviceUtilsMock->getDeviceTypeRFC(deviceType, size); + } + else + { + cout << "getDeviceTypeRFC g_DeviceUtilsMock object is NULL" << endl; + if (deviceType != nullptr && size > 0) + { + const char *defaultType = "unknown"; + size_t i = 0; + /* Copy up to size - 1 characters from defaultType, then NUL-terminate */ + while (i + 1 < size && defaultType[i] != '\0') + { + deviceType[i] = defaultType[i]; + ++i; + } + deviceType[i] = '\0'; + } + } +} + extern "C" int v_secure_pclose(FILE *fp) { if (!g_DeviceUtilsMock) diff --git a/unittest/mocks/deviceutils_mock.h b/unittest/mocks/deviceutils_mock.h index 8d3c9d48..dccad764 100644 --- a/unittest/mocks/deviceutils_mock.h +++ b/unittest/mocks/deviceutils_mock.h @@ -37,6 +37,7 @@ class DeviceUtilsInterface virtual int getJsonRpcData(void *Curl_req, FileDwnl_t *req_data, char token_header, int httpCode ) = 0; virtual int getDevicePropertyData(const char *model, char *data, int size) = 0; virtual int read_RFCProperty(char* type, const char* key, char *out_value, size_t datasize) = 0; + virtual void getDeviceTypeRFC(char* deviceType, size_t datasize) = 0; virtual int filePresentCheck(const char *filename) = 0; virtual int getFileSize(const char *filename) = 0; virtual bool isInStateRed() = 0; @@ -63,6 +64,7 @@ class DeviceUtilsMock: public DeviceUtilsInterface MOCK_METHOD(int, getFileSize, (const char *filename ), ()); MOCK_METHOD(bool, isInStateRed, (), ()); MOCK_METHOD(bool, isDebugServicesEnabled, (), ()); + MOCK_METHOD(void, getDeviceTypeRFC, (char*, size_t), ()); MOCK_METHOD(size_t, GetHwMacAddress, (char *iface, char *pMac, size_t szBufSize), ()); MOCK_METHOD(size_t, GetModelNum, ( char *pModelNum, size_t szBufSize ), ()); MOCK_METHOD(void, t2CountNotify, (char *marker), ());