From f3f1cfdc67e9474336f4a8f180afb36b1061148d Mon Sep 17 00:00:00 2001 From: nhanasi Date: Fri, 29 May 2026 10:23:36 -0400 Subject: [PATCH 01/13] Create L1_Test_Coverage.md (#482) --- test/docs/L1_Test_Coverage.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/docs/L1_Test_Coverage.md diff --git a/test/docs/L1_Test_Coverage.md b/test/docs/L1_Test_Coverage.md new file mode 100644 index 000000000..82a81b21a --- /dev/null +++ b/test/docs/L1_Test_Coverage.md @@ -0,0 +1 @@ +image From adcea7483c2ca3c6cee1b69b0cf247f00f938675 Mon Sep 17 00:00:00 2001 From: nhanas001c Date: Fri, 29 May 2026 14:26:55 +0000 Subject: [PATCH 02/13] tr69hostif 1.4.5 release changelog updates --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c22f303..10997c2f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.4.5](https://github.com/rdkcentral/tr69hostif/compare/1.4.4...1.4.5) + +- RDKEMW-19204 : Add AAMP config parameters to tr69hostif data model [`#479`](https://github.com/rdkcentral/tr69hostif/pull/479) +- RDKEMW-18790 : Disable the mutex logs and move to DEBUG mode [`#472`](https://github.com/rdkcentral/tr69hostif/pull/472) +- L2 Coverage Document [`#476`](https://github.com/rdkcentral/tr69hostif/pull/476) +- RDK-60108 : Refactor and Hardening of Thunder Plugin Interaction for tr69hostif Module [`#471`](https://github.com/rdkcentral/tr69hostif/pull/471) +- Merge tag '1.4.4' into develop [`3a6dd42`](https://github.com/rdkcentral/tr69hostif/commit/3a6dd423dfc6a49620f13fb99c79a787abf350b6) + #### [1.4.4](https://github.com/rdkcentral/tr69hostif/compare/1.4.3...1.4.4) +> 7 May 2026 + - Update Device_Time.cpp [`#467`](https://github.com/rdkcentral/tr69hostif/pull/467) - RDKEMW-15246 : Implement new RFC Parameters for chrony [`#464`](https://github.com/rdkcentral/tr69hostif/pull/464) +- tr69hostif 1.4.4 release changelog updates [`f27018b`](https://github.com/rdkcentral/tr69hostif/commit/f27018bc7321e0e51e3cc5355879431d4cd46c4f) - Merge tag '1.4.3' into develop [`f8a8611`](https://github.com/rdkcentral/tr69hostif/commit/f8a861166ad10fbe64d355770fffd9a30a1e388f) #### [1.4.3](https://github.com/rdkcentral/tr69hostif/compare/1.4.2...1.4.3) From 55410c7f288fe3659c69b53b46b4b43ec8eb9003 Mon Sep 17 00:00:00 2001 From: emutavchi Date: Fri, 5 Jun 2026 09:33:04 -0400 Subject: [PATCH 03/13] RDKEMW-19523: Add RFC for GoogleCast (#486) --- .../parodusClient/waldb/data-model/data-model-generic.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml b/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml index 4eb324ec4..a782036f4 100644 --- a/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml +++ b/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml @@ -3511,6 +3511,13 @@ + + + + + + + From a51b086104e21f07a6ef3028678db5b9a999c96a Mon Sep 17 00:00:00 2001 From: nhanas001c Date: Fri, 5 Jun 2026 13:36:27 +0000 Subject: [PATCH 04/13] tr69hostif 1.4.5 release changelog updates --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c22f303..4b8d4e791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,23 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.4.5](https://github.com/rdkcentral/tr69hostif/compare/1.4.4...1.4.5) + +- RDKEMW-19523: Add RFC for GoogleCast [`#486`](https://github.com/rdkcentral/tr69hostif/pull/486) +- Create L1_Test_Coverage.md [`#482`](https://github.com/rdkcentral/tr69hostif/pull/482) +- RDKEMW-19204 : Add AAMP config parameters to tr69hostif data model [`#479`](https://github.com/rdkcentral/tr69hostif/pull/479) +- RDKEMW-18790 : Disable the mutex logs and move to DEBUG mode [`#472`](https://github.com/rdkcentral/tr69hostif/pull/472) +- L2 Coverage Document [`#476`](https://github.com/rdkcentral/tr69hostif/pull/476) +- RDK-60108 : Refactor and Hardening of Thunder Plugin Interaction for tr69hostif Module [`#471`](https://github.com/rdkcentral/tr69hostif/pull/471) +- Merge tag '1.4.4' into develop [`3a6dd42`](https://github.com/rdkcentral/tr69hostif/commit/3a6dd423dfc6a49620f13fb99c79a787abf350b6) + #### [1.4.4](https://github.com/rdkcentral/tr69hostif/compare/1.4.3...1.4.4) +> 7 May 2026 + - Update Device_Time.cpp [`#467`](https://github.com/rdkcentral/tr69hostif/pull/467) - RDKEMW-15246 : Implement new RFC Parameters for chrony [`#464`](https://github.com/rdkcentral/tr69hostif/pull/464) +- tr69hostif 1.4.4 release changelog updates [`f27018b`](https://github.com/rdkcentral/tr69hostif/commit/f27018bc7321e0e51e3cc5355879431d4cd46c4f) - Merge tag '1.4.3' into develop [`f8a8611`](https://github.com/rdkcentral/tr69hostif/commit/f8a861166ad10fbe64d355770fffd9a30a1e388f) #### [1.4.3](https://github.com/rdkcentral/tr69hostif/compare/1.4.2...1.4.3) From d04a821f1dd5424a6d4d081a24863c66f3a2b877 Mon Sep 17 00:00:00 2001 From: nhanas001c Date: Fri, 5 Jun 2026 13:36:27 +0000 Subject: [PATCH 05/13] tr69hostif 1.4.5 release changelog updates --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23c22f303..4b8d4e791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,23 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.4.5](https://github.com/rdkcentral/tr69hostif/compare/1.4.4...1.4.5) + +- RDKEMW-19523: Add RFC for GoogleCast [`#486`](https://github.com/rdkcentral/tr69hostif/pull/486) +- Create L1_Test_Coverage.md [`#482`](https://github.com/rdkcentral/tr69hostif/pull/482) +- RDKEMW-19204 : Add AAMP config parameters to tr69hostif data model [`#479`](https://github.com/rdkcentral/tr69hostif/pull/479) +- RDKEMW-18790 : Disable the mutex logs and move to DEBUG mode [`#472`](https://github.com/rdkcentral/tr69hostif/pull/472) +- L2 Coverage Document [`#476`](https://github.com/rdkcentral/tr69hostif/pull/476) +- RDK-60108 : Refactor and Hardening of Thunder Plugin Interaction for tr69hostif Module [`#471`](https://github.com/rdkcentral/tr69hostif/pull/471) +- Merge tag '1.4.4' into develop [`3a6dd42`](https://github.com/rdkcentral/tr69hostif/commit/3a6dd423dfc6a49620f13fb99c79a787abf350b6) + #### [1.4.4](https://github.com/rdkcentral/tr69hostif/compare/1.4.3...1.4.4) +> 7 May 2026 + - Update Device_Time.cpp [`#467`](https://github.com/rdkcentral/tr69hostif/pull/467) - RDKEMW-15246 : Implement new RFC Parameters for chrony [`#464`](https://github.com/rdkcentral/tr69hostif/pull/464) +- tr69hostif 1.4.4 release changelog updates [`f27018b`](https://github.com/rdkcentral/tr69hostif/commit/f27018bc7321e0e51e3cc5355879431d4cd46c4f) - Merge tag '1.4.3' into develop [`f8a8611`](https://github.com/rdkcentral/tr69hostif/commit/f8a861166ad10fbe64d355770fffd9a30a1e388f) #### [1.4.3](https://github.com/rdkcentral/tr69hostif/compare/1.4.2...1.4.3) From 2b42960a7c8549f970003a16ff054dbff3d9e1c3 Mon Sep 17 00:00:00 2001 From: nhanas001c Date: Fri, 5 Jun 2026 16:13:44 +0000 Subject: [PATCH 06/13] tr69hostif 1.4.5 release changelog updates --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b8d4e791..c56dc51fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - RDKEMW-18790 : Disable the mutex logs and move to DEBUG mode [`#472`](https://github.com/rdkcentral/tr69hostif/pull/472) - L2 Coverage Document [`#476`](https://github.com/rdkcentral/tr69hostif/pull/476) - RDK-60108 : Refactor and Hardening of Thunder Plugin Interaction for tr69hostif Module [`#471`](https://github.com/rdkcentral/tr69hostif/pull/471) +- tr69hostif 1.4.5 release changelog updates [`a51b086`](https://github.com/rdkcentral/tr69hostif/commit/a51b086104e21f07a6ef3028678db5b9a999c96a) - Merge tag '1.4.4' into develop [`3a6dd42`](https://github.com/rdkcentral/tr69hostif/commit/3a6dd423dfc6a49620f13fb99c79a787abf350b6) #### [1.4.4](https://github.com/rdkcentral/tr69hostif/compare/1.4.3...1.4.4) From 440f28e94ffa3046eb3e7e75d25b7adaac1e8666 Mon Sep 17 00:00:00 2001 From: Anand73-n Date: Tue, 9 Jun 2026 20:55:37 +0530 Subject: [PATCH 07/13] RDK-61639: Implement WiFi Radio Data Model Parameters for RDKE (#485) Reason for change: Device.WiFi.* now owned by wifimetrics Test procedure: Flash the build and run rbuscli to get registered WiFi data model property Risks: low Priority: P0 Signed-off-by: Anand N Co-authored-by: Anand Co-authored-by: Karunakaran A <48997923+karuna2git@users.noreply.github.com> --- .../waldb/data-model/data-model-generic.xml | 554 ------------------ 1 file changed, 554 deletions(-) diff --git a/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml b/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml index a782036f4..44537af06 100644 --- a/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml +++ b/src/hostif/parodusClient/waldb/data-model/data-model-generic.xml @@ -63,25 +63,6 @@ - - - - - - - - - - - - - - - - - - - @@ -2461,541 +2442,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From e5cc22781b2884d767b1a4b09b6f2582e6661fa5 Mon Sep 17 00:00:00 2001 From: sindhu-krishnan <102755514+sindhu-krishnan@users.noreply.github.com> Date: Wed, 10 Jun 2026 20:08:16 +0530 Subject: [PATCH 08/13] RDKEMW-18818: Configure NTP servers with pool directive (#491) * Update Device_Time.cpp * Update hostIf_TimeClient_ReqHandler.cpp * Update Device_Time.h * Update Device_Time.cpp * Update Device_Time.h * Update hostIf_TimeClient_ReqHandler.cpp * Update Device_Time.cpp * Update Device_Time.cpp --- .../src/hostIf_TimeClient_ReqHandler.cpp | 48 --- src/hostif/profiles/Time/Device_Time.cpp | 280 +----------------- src/hostif/profiles/Time/Device_Time.h | 36 +-- 3 files changed, 6 insertions(+), 358 deletions(-) diff --git a/src/hostif/handlers/src/hostIf_TimeClient_ReqHandler.cpp b/src/hostif/handlers/src/hostIf_TimeClient_ReqHandler.cpp index ed74041cb..6ca5564c5 100644 --- a/src/hostif/handlers/src/hostIf_TimeClient_ReqHandler.cpp +++ b/src/hostif/handlers/src/hostIf_TimeClient_ReqHandler.cpp @@ -131,30 +131,6 @@ int TimeClientReqHandler::handleSetMsg(HOSTIF_MsgData_t *stMsgData) { ret = pIface->set_Device_Time_Chrony_Enable(stMsgData); } - - else if (strcasecmp(stMsgData->paramName,"Device.Time.NTPMinpoll") == 0) - { - ret = pIface->set_Device_Time_NTPMinpoll(stMsgData); - } - else if (strcasecmp(stMsgData->paramName,"Device.Time.NTPMaxpoll") == 0) - { - ret = pIface->set_Device_Time_NTPMaxpoll(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer1Directive") == 0) { - ret = pIface->set_Device_Time_NTPServer1Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer2Directive") == 0) { - ret = pIface->set_Device_Time_NTPServer2Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer3Directive") == 0) { - ret = pIface->set_Device_Time_NTPServer3Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer4Directive") == 0) { - ret = pIface->set_Device_Time_NTPServer4Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer5Directive") == 0) { - ret = pIface->set_Device_Time_NTPServer5Directive(stMsgData); - } else if (strcasecmp(stMsgData->paramName,"Device.Time.Chrony.Makestep") == 0) { ret = pIface->set_Device_Time_NTPMaxstep(stMsgData); } @@ -271,30 +247,6 @@ int TimeClientReqHandler::handleGetMsg(HOSTIF_MsgData_t *stMsgData) { ret = pIface->get_Device_Time_Chrony_Enable(stMsgData); } - - else if (strcasecmp(stMsgData->paramName,"Device.Time.NTPMinpoll") == 0) - { - ret = pIface->get_Device_Time_NTPMinpoll(stMsgData); - } - else if (strcasecmp(stMsgData->paramName,"Device.Time.NTPMaxpoll") == 0) - { - ret = pIface->get_Device_Time_NTPMaxpoll(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer1Directive") == 0) { - ret = pIface->get_Device_Time_NTPServer1Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer2Directive") == 0) { - ret = pIface->get_Device_Time_NTPServer2Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer3Directive") == 0) { - ret = pIface->get_Device_Time_NTPServer3Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer4Directive") == 0) { - ret = pIface->get_Device_Time_NTPServer4Directive(stMsgData); - } - else if (strcasecmp(stMsgData->paramName, "Device.Time.NTPServer5Directive") == 0) { - ret = pIface->get_Device_Time_NTPServer5Directive(stMsgData); - } else if (strcasecmp(stMsgData->paramName,"Device.Time.Chrony.Makestep") == 0) { ret = pIface->get_Device_Time_NTPMaxstep(stMsgData); } diff --git a/src/hostif/profiles/Time/Device_Time.cpp b/src/hostif/profiles/Time/Device_Time.cpp index 728eab547..d2be8f38e 100644 --- a/src/hostif/profiles/Time/Device_Time.cpp +++ b/src/hostif/profiles/Time/Device_Time.cpp @@ -58,18 +58,11 @@ #define TIME_ZONE_LENGTH 8 #define CHRONY_ENABLE_FILE "/opt/secure/RFC/chrony/chronyd_enabled" -#define NTP_MINPOLL_FILE "/opt/secure/RFC/chrony/ntp_minpoll" -#define NTP_MAXPOLL_FILE "/opt/secure/RFC/chrony/ntp_maxpoll" -#define NTP_SERVER1_DIRECTIVE_FILE "/opt/secure/RFC/chrony/ntp_server1_directive" -#define NTP_SERVER2_DIRECTIVE_FILE "/opt/secure/RFC/chrony/ntp_server2_directive" -#define NTP_SERVER3_DIRECTIVE_FILE "/opt/secure/RFC/chrony/ntp_server3_directive" -#define NTP_SERVER4_DIRECTIVE_FILE "/opt/secure/RFC/chrony/ntp_server4_directive" -#define NTP_SERVER5_DIRECTIVE_FILE "/opt/secure/RFC/chrony/ntp_server5_directive" #define NTP_MAXSTEP_FILE "/opt/secure/RFC/chrony/ntp_maxstep" #define NTP_MAXSTEP_DEFAULT "1.0,3" #define NTP_SERVER_SETTINGS_FILE_PREFIX "/opt/secure/RFC/chrony/ntp_server" #define NTP_SERVER_SETTINGS_FILE_SUFFIX "_settings" -#define NTP_SERVER_SETTINGS_DEFAULT "server,0,true,10,12" +#define NTP_SERVER_SETTINGS_DEFAULT "pool,4,true,10,12" #define NTP_SERVER_MAX_INSTANCES 5 GHashTable* hostIf_Time::ifHash = NULL; @@ -426,277 +419,6 @@ int hostIf_Time::get_Device_Time_Chrony_Enable(HOSTIF_MsgData_t *stMsgData, bool return OK; } - -// Get handler for NTPMinpoll -int hostIf_Time::get_Device_Time_NTPMinpoll(HOSTIF_MsgData_t *stMsgData, bool *pChanged) -{ - stMsgData->paramtype = hostIf_UnsignedIntType; - - unsigned int minpoll = 10; // Default value - std::ifstream file(NTP_MINPOLL_FILE); - if (file.is_open()) { - std::string value; - std::getline(file, value); - file.close(); - if (!value.empty()) { - try { - minpoll = static_cast(std::stoul(value)); - } catch (const std::exception&) { - minpoll = 10; - } - } - } - - put_uint(stMsgData->paramValue, minpoll); - stMsgData->paramLen = sizeof(unsigned int); - - if (pChanged) *pChanged = false; - return OK; -} - -// Set handler for NTPMinpoll -int hostIf_Time::set_Device_Time_NTPMinpoll(HOSTIF_MsgData_t *stMsgData, bool *pChanged) -{ - const char* chronyDir = "/opt/secure/RFC/chrony"; - if (mkdir(chronyDir, 0755) != 0 && errno != EEXIST) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Failed to create %s: %s\n", - __FUNCTION__, __FILE__, __LINE__, - chronyDir, strerror(errno)); - return NOK; - } - - std::string minpollStr = getStringValue(stMsgData); - - // Validate that minpollStr is a number in a valid range [4, 17] for NTP - int minpoll = atoi(minpollStr.c_str()); - if (minpoll < 4 || minpoll > 24) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Invalid NTPMinpoll value: %s\n", - __FUNCTION__, __FILE__, __LINE__, minpollStr.c_str()); - return NOK; - } - - std::ofstream file(NTP_MINPOLL_FILE); - if (!file.is_open()) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Failed to open %s for writing\n", - __FUNCTION__, __FILE__, __LINE__, NTP_MINPOLL_FILE); - return NOK; - } - file << minpollStr; - file.close(); - - if (pChanged) *pChanged = true; - return OK; -} - - -// Get handler for NTPMaxpoll -int hostIf_Time::get_Device_Time_NTPMaxpoll(HOSTIF_MsgData_t *stMsgData, bool *pChanged) -{ - stMsgData->paramtype = hostIf_UnsignedIntType; - - unsigned int maxpoll = 12; // Default if file is empty or missing (NTP typical maxpoll default) - - std::ifstream file(NTP_MAXPOLL_FILE); - if (file.is_open()) { - std::string value; - std::getline(file, value); - file.close(); - - if (!value.empty()) { - maxpoll = static_cast(atoi(value.c_str())); - } - } - - put_uint(stMsgData->paramValue, maxpoll); - stMsgData->paramLen = sizeof(unsigned int); - if (pChanged) *pChanged = false; - return OK; -} - -// Set handler for NTPMaxpoll -int hostIf_Time::set_Device_Time_NTPMaxpoll(HOSTIF_MsgData_t *stMsgData, bool *pChanged) -{ - const char* chronyDir = "/opt/secure/RFC/chrony"; - if (mkdir(chronyDir, 0755) != 0 && errno != EEXIST) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Failed to create %s: %s\n", - __FUNCTION__, __FILE__, __LINE__, - chronyDir, strerror(errno)); - return NOK; - } - - std::string maxpollStr = getStringValue(stMsgData); - - // Validate maxpoll in NTP allowed range [4,24] - int maxpoll = atoi(maxpollStr.c_str()); - if (maxpoll < 4 || maxpoll > 24) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Invalid NTPMaxpoll value: %s\n", - __FUNCTION__, __FILE__, __LINE__, maxpollStr.c_str()); - return NOK; - } - - std::ofstream file(NTP_MAXPOLL_FILE); - if (!file.is_open()) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Failed to open %s for writing\n", - __FUNCTION__, __FILE__, __LINE__, NTP_MAXPOLL_FILE); - return NOK; - } - file << maxpollStr; - file.close(); - - if (pChanged) *pChanged = true; - return OK; -} - - -int hostIf_Time::get_Device_Time_NTPServer1Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) -{ - stMsgData->paramtype = hostIf_StringType; - std::ifstream file(NTP_SERVER1_DIRECTIVE_FILE); - std::string value; - - if (file.is_open()) { - std::getline(file, value); - file.close(); - } - if (value.empty()) { - value = "server"; - } - strncpy(stMsgData->paramValue, value.c_str(), sizeof(stMsgData->paramValue)-1); - stMsgData->paramValue[sizeof(stMsgData->paramValue)-1] = '\0'; - stMsgData->paramLen = strlen(stMsgData->paramValue); - - if (pChanged) *pChanged = false; - return OK; -} - -int hostIf_Time::set_Device_Time_NTPServer1Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) -{ - std::string directive = getStringValue(stMsgData); - std::ofstream file(NTP_SERVER1_DIRECTIVE_FILE); - if (!file.is_open()) { - RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, - "[%s:%s:%d] Failed to open %s for writing: %s\n", - __FUNCTION__, __FILE__, __LINE__, - NTP_SERVER1_DIRECTIVE_FILE, strerror(errno)); - return NOK; - } - file << directive; - file.close(); - - if (pChanged) *pChanged = true; - return OK; -} - -int hostIf_Time::get_Device_Time_NTPServer2Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - stMsgData->paramtype = hostIf_StringType; - std::ifstream file(NTP_SERVER2_DIRECTIVE_FILE); - std::string value; - if (file.is_open()) { - std::getline(file, value); - file.close(); - } - if (value.empty()) value = "server"; - strncpy(stMsgData->paramValue, value.c_str(), sizeof(stMsgData->paramValue)-1); - stMsgData->paramValue[sizeof(stMsgData->paramValue)-1] = '\0'; - stMsgData->paramLen = strlen(stMsgData->paramValue); - if (pChanged) *pChanged = false; - return OK; -} - -int hostIf_Time::set_Device_Time_NTPServer2Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - std::string directive = getStringValue(stMsgData); - std::ofstream file(NTP_SERVER2_DIRECTIVE_FILE); - if (!file.is_open()) return NOK; - file << directive; - file.close(); - if (pChanged) *pChanged = true; - return OK; -} - -int hostIf_Time::get_Device_Time_NTPServer3Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - stMsgData->paramtype = hostIf_StringType; - std::ifstream file(NTP_SERVER3_DIRECTIVE_FILE); - std::string value; - if (file.is_open()) { - std::getline(file, value); - file.close(); - } - if (value.empty()) value = "server"; - strncpy(stMsgData->paramValue, value.c_str(), sizeof(stMsgData->paramValue)-1); - stMsgData->paramValue[sizeof(stMsgData->paramValue)-1] = '\0'; - stMsgData->paramLen = strlen(stMsgData->paramValue); - if (pChanged) *pChanged = false; - return OK; -} - -int hostIf_Time::set_Device_Time_NTPServer3Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - std::string directive = getStringValue(stMsgData); - std::ofstream file(NTP_SERVER3_DIRECTIVE_FILE); - if (!file.is_open()) return NOK; - file << directive; - file.close(); - if (pChanged) *pChanged = true; - return OK; -} - -int hostIf_Time::get_Device_Time_NTPServer4Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - stMsgData->paramtype = hostIf_StringType; - std::ifstream file(NTP_SERVER4_DIRECTIVE_FILE); - std::string value; - if (file.is_open()) { - std::getline(file, value); - file.close(); - } - if (value.empty()) value = "server"; - strncpy(stMsgData->paramValue, value.c_str(), sizeof(stMsgData->paramValue)-1); - stMsgData->paramValue[sizeof(stMsgData->paramValue)-1] = '\0'; - stMsgData->paramLen = strlen(stMsgData->paramValue); - if (pChanged) *pChanged = false; - return OK; -} - -int hostIf_Time::set_Device_Time_NTPServer4Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - std::string directive = getStringValue(stMsgData); - std::ofstream file(NTP_SERVER4_DIRECTIVE_FILE); - if (!file.is_open()) return NOK; - file << directive; - file.close(); - if (pChanged) *pChanged = true; - return OK; -} - -int hostIf_Time::get_Device_Time_NTPServer5Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - stMsgData->paramtype = hostIf_StringType; - std::ifstream file(NTP_SERVER5_DIRECTIVE_FILE); - std::string value; - if (file.is_open()) { - std::getline(file, value); - file.close(); - } - if (value.empty()) value = "server"; - strncpy(stMsgData->paramValue, value.c_str(), sizeof(stMsgData->paramValue)-1); - stMsgData->paramValue[sizeof(stMsgData->paramValue)-1] = '\0'; - stMsgData->paramLen = strlen(stMsgData->paramValue); - if (pChanged) *pChanged = false; - return OK; -} - -int hostIf_Time::set_Device_Time_NTPServer5Directive(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { - std::string directive = getStringValue(stMsgData); - std::ofstream file(NTP_SERVER5_DIRECTIVE_FILE); - if (!file.is_open()) return NOK; - file << directive; - file.close(); - if (pChanged) *pChanged = true; - return OK; -} - int hostIf_Time::get_Device_Time_NTPMaxstep(HOSTIF_MsgData_t *stMsgData, bool *pChanged) { stMsgData->paramtype = hostIf_StringType; diff --git a/src/hostif/profiles/Time/Device_Time.h b/src/hostif/profiles/Time/Device_Time.h index ab903aa38..8c97b27b0 100644 --- a/src/hostif/profiles/Time/Device_Time.h +++ b/src/hostif/profiles/Time/Device_Time.h @@ -277,24 +277,14 @@ class hostIf_Time { */ int get_Device_Time_CurrentLocalTime(HOSTIF_MsgData_t *, bool *pChanged = NULL); - + + /* To Enable chrony as NTP client and configure the chrony settings */ + int get_Device_Time_Chrony_Enable(HOSTIF_MsgData_t *,bool *pChanged = NULL); - int get_Device_Time_NTPMinpoll(HOSTIF_MsgData_t *,bool *pChanged = NULL); - - int get_Device_Time_NTPMaxpoll(HOSTIF_MsgData_t *,bool *pChanged = NULL); - - int get_Device_Time_NTPServer1Directive(HOSTIF_MsgData_t*, bool* pChanged = NULL); - - int get_Device_Time_NTPServer2Directive(HOSTIF_MsgData_t*, bool* pChanged = NULL); - - int get_Device_Time_NTPServer3Directive(HOSTIF_MsgData_t*, bool* pChanged = NULL); - - int get_Device_Time_NTPServer4Directive(HOSTIF_MsgData_t*, bool* pChanged = NULL); - - int get_Device_Time_NTPServer5Directive(HOSTIF_MsgData_t*, bool* pChanged = NULL); - int get_Device_Time_NTPMaxstep(HOSTIF_MsgData_t *stMsgData, bool *pChanged = NULL); + + int get_Device_Time_NTPServerSettings(HOSTIF_MsgData_t *stMsgData, bool *pChanged = NULL); /** @@ -441,24 +431,8 @@ class hostIf_Time { int set_Device_Time_Chrony_Enable(HOSTIF_MsgData_t *, bool *pChanged = NULL); - int set_Device_Time_NTPMinpoll(HOSTIF_MsgData_t *, bool *pChanged = NULL); - - int set_Device_Time_NTPMaxpoll(HOSTIF_MsgData_t *, bool *pChanged = NULL); - - int set_Device_Time_NTPServer1Directive(HOSTIF_MsgData_t *, bool *pChanged = NULL); - - int set_Device_Time_NTPServer2Directive(HOSTIF_MsgData_t *, bool *pChanged = NULL); - - int set_Device_Time_NTPServer3Directive(HOSTIF_MsgData_t *, bool *pChanged = NULL); - - int set_Device_Time_NTPServer4Directive(HOSTIF_MsgData_t *, bool *pChanged = NULL); - - int set_Device_Time_NTPServer5Directive(HOSTIF_MsgData_t *, bool *pChanged = NULL); - int set_Device_Time_NTPMaxstep(HOSTIF_MsgData_t *stMsgData, bool *pChanged = NULL); - int get_Device_Time_NTPServerSettings(HOSTIF_MsgData_t *stMsgData, bool *pChanged = NULL); - int set_Device_Time_NTPServerSettings(HOSTIF_MsgData_t *stMsgData, bool *pChanged = NULL); /** From 8c60d18bc86c4eb6adfdcd092507f9f0562cfa47 Mon Sep 17 00:00:00 2001 From: nhanas001c Date: Wed, 10 Jun 2026 15:04:38 +0000 Subject: [PATCH 09/13] tr69hostif 1.4.6 release changelog updates --- CHANGELOG.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c56dc51fa..a3a77f49e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,26 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.4.6](https://github.com/rdkcentral/tr69hostif/compare/1.4.5...1.4.6) + +- RDKEMW-18818: Configure NTP servers with pool directive [`#491`](https://github.com/rdkcentral/tr69hostif/pull/491) +- RDK-61639: Implement WiFi Radio Data Model Parameters for RDKE [`#485`](https://github.com/rdkcentral/tr69hostif/pull/485) +- Merge tag '1.4.5' into develop [`531c18e`](https://github.com/rdkcentral/tr69hostif/commit/531c18ee3d8da3e17b2f3e7d454b0637f542cd65) +- tr69hostif 1.4.5 release changelog updates [`a51b086`](https://github.com/rdkcentral/tr69hostif/commit/a51b086104e21f07a6ef3028678db5b9a999c96a) + #### [1.4.5](https://github.com/rdkcentral/tr69hostif/compare/1.4.4...1.4.5) +> 5 June 2026 + - RDKEMW-19523: Add RFC for GoogleCast [`#486`](https://github.com/rdkcentral/tr69hostif/pull/486) - Create L1_Test_Coverage.md [`#482`](https://github.com/rdkcentral/tr69hostif/pull/482) - RDKEMW-19204 : Add AAMP config parameters to tr69hostif data model [`#479`](https://github.com/rdkcentral/tr69hostif/pull/479) - RDKEMW-18790 : Disable the mutex logs and move to DEBUG mode [`#472`](https://github.com/rdkcentral/tr69hostif/pull/472) - L2 Coverage Document [`#476`](https://github.com/rdkcentral/tr69hostif/pull/476) - RDK-60108 : Refactor and Hardening of Thunder Plugin Interaction for tr69hostif Module [`#471`](https://github.com/rdkcentral/tr69hostif/pull/471) -- tr69hostif 1.4.5 release changelog updates [`a51b086`](https://github.com/rdkcentral/tr69hostif/commit/a51b086104e21f07a6ef3028678db5b9a999c96a) -- Merge tag '1.4.4' into develop [`3a6dd42`](https://github.com/rdkcentral/tr69hostif/commit/3a6dd423dfc6a49620f13fb99c79a787abf350b6) +- tr69hostif 1.4.5 release changelog updates [`d04a821`](https://github.com/rdkcentral/tr69hostif/commit/d04a821f1dd5424a6d4d081a24863c66f3a2b877) +- tr69hostif 1.4.5 release changelog updates [`adcea74`](https://github.com/rdkcentral/tr69hostif/commit/adcea7483c2ca3c6cee1b69b0cf247f00f938675) +- tr69hostif 1.4.5 release changelog updates [`2b42960`](https://github.com/rdkcentral/tr69hostif/commit/2b42960a7c8549f970003a16ff054dbff3d9e1c3) #### [1.4.4](https://github.com/rdkcentral/tr69hostif/compare/1.4.3...1.4.4) From 8080c0d0cbd1220e5a0355f2def3e94b4ea58d46 Mon Sep 17 00:00:00 2001 From: nhanasi Date: Thu, 11 Jun 2026 15:53:53 -0400 Subject: [PATCH 10/13] Update L2_Test_Coverage.md (#493) --- test/docs/L2_Test_Coverage.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/test/docs/L2_Test_Coverage.md b/test/docs/L2_Test_Coverage.md index 08d6d7f5b..6f34401d5 100644 --- a/test/docs/L2_Test_Coverage.md +++ b/test/docs/L2_Test_Coverage.md @@ -7,14 +7,30 @@ the full tr69hostif module surface. It identifies what is covered, what is not, precisely quantifies the tests needed to reach 100% functional coverage. > Last analysed: March 2026 -> Test suite: `test/functional-tests/` — 4 feature files, **45 ordered pytest functions** -> Module surface: **708 parameter handlers** + **38 behavioral scenarios** = **746 testable items** -> **Tests needed for 100% coverage: ~761** -> **Current effective coverage: ~52 tests (~6.8%)** -> **Tests still required: ~709** --- - +**Test Coverage Summary** +``` +Total source functions (approx): ~761 +Functions with direct L2 coverage: ~34 +Functions with indirect L2 coverage: ~18 +Functions with no L2 coverage: ~709 + +Active L2 test functions: 51 +Disabled L2 test functions: 0 +Active feature scenarios: 170 +Proposed new test scenarios: 68 + +High priority: 46 +Medium priority: 12 +Low priority: 10 +Test files active: 5 +Test files disabled (commented out): 0 + +Estimated current L2 functional coverage: ~6.8% +Target L2 functional coverage: ~80% +``` +--- ## Test Suite Layout ``` From 74aa1a0a28402ecf5a2e25adba0915ff2fb2905f Mon Sep 17 00:00:00 2001 From: madhubabutt <114217841+madhubabutt@users.noreply.github.com> Date: Fri, 12 Jun 2026 20:19:39 +0530 Subject: [PATCH 11/13] RDKEMW-19229 : Improve L1 Coverage for tr69hostif and Fix Errors (#492) Co-authored-by: mtirum011 --- .../httpserver/include/XrdkCentralComRFCVar.h | 4 + .../httpserver/src/gtest/gtest_httpserver.cpp | 292 ++++++- src/hostif/httpserver/src/request_handler.cpp | 10 + src/hostif/include/IniFile.h | 1 + src/hostif/parodusClient/gtest/dm_test.cpp | 227 ++++++ .../profiles/DHCPv4/Device_DHCPv4_Client.h | 11 +- .../profiles/DHCPv4/gtest/gtest_dhcpv4.cpp | 136 ++-- .../profiles/Device/gtest/gtest_device.cpp | 54 ++ .../profiles/DeviceInfo/gtest/gtest_main.cpp | 732 ++++++++++++++---- .../Ethernet/gtest/gtest_ethernet.cpp | 80 ++ src/hostif/profiles/Time/gtest/gtest_time.cpp | 43 +- src/hostif/src/gtest/gtest_src.cpp | 114 +++ src/unittest/stubs/file_writer.cpp | 2 +- src/unittest/stubs/wdmp-c.h | 8 + 14 files changed, 1505 insertions(+), 209 deletions(-) mode change 100644 => 100755 src/hostif/profiles/Device/gtest/gtest_device.cpp diff --git a/src/hostif/httpserver/include/XrdkCentralComRFCVar.h b/src/hostif/httpserver/include/XrdkCentralComRFCVar.h index 6143bc9e4..b0636db83 100644 --- a/src/hostif/httpserver/include/XrdkCentralComRFCVar.h +++ b/src/hostif/httpserver/include/XrdkCentralComRFCVar.h @@ -57,6 +57,10 @@ class XRFCVarStore FRIEND_TEST(httpserverTest, initRFCVarFileName); FRIEND_TEST(httpserverTest, loadRFCVarIntoCache); FRIEND_TEST(httpserverTest, Invalid_RFC_filename); + FRIEND_TEST(httpserverTest, loadRFCVarIntoCache_EmptyFilename_ReturnsFalse); + FRIEND_TEST(httpserverTest, getValue_InitNotDone_ReturnsEmptyEvenWhenKeyExists); + FRIEND_TEST(httpserverTest, reloadCache_WithQuotedFilename_LoadsValues); + FRIEND_TEST(httpserverTest, handleRFCRequest_GET); #endif }; diff --git a/src/hostif/httpserver/src/gtest/gtest_httpserver.cpp b/src/hostif/httpserver/src/gtest/gtest_httpserver.cpp index 20993fdd7..a9d539d22 100644 --- a/src/hostif/httpserver/src/gtest/gtest_httpserver.cpp +++ b/src/hostif/httpserver/src/gtest/gtest_httpserver.cpp @@ -11,6 +11,7 @@ #include "XrdkCentralComRFCVar.h" #include "request_handler.h" #include "IniFile.h" +#include "http_server.h" #include "hostIf_utils.h" #include "hostIf_main.h" #include "webpa_notification.h" @@ -41,6 +42,7 @@ extern "C" #include #include +#include #define GTEST_DEFAULT_RESULT_FILEPATH "/tmp/Gtest_Report/" #define GTEST_DEFAULT_RESULT_FILENAME "hostif_gtest_report.json" @@ -81,6 +83,8 @@ extern void (*HTTPRequestHandlerFunc()) ( void *user_data); extern void (*convertAndAssignParamValueFunc()) (HOSTIF_MsgData_t *param, char *value); extern char* (*getStringValueFunc()) (HostIf_ParamType_t paramType, char *value); +extern bool (*isAuthorizedFunc())(const char* pcCallerID, const char* pcParamName); +extern void (*getHostIfParamStFromRequestFunc())(REQ_TYPE reqType, param_t *param, HOSTIF_MsgData_t *hostIfParam); #endif TEST(httpserverTest,initRFCVarFileName){ @@ -112,6 +116,64 @@ TEST(httpserverTest, getValue) { } } +TEST(httpserverTest, getValue_UnknownKey_ReturnsEmpty) { + m_varStore = XRFCVarStore::getInstance(); + const string key = "RFC_UNKNOWN_TEST_KEY"; + if(m_varStore) + { + string value = m_varStore->getValue(key); + EXPECT_EQ(value, ""); + } +} + +TEST(httpserverTest, loadRFCVarIntoCache_EmptyFilename_ReturnsFalse) { + m_varStore = XRFCVarStore::getInstance(); + + ASSERT_NE(m_varStore, nullptr); + + const std::string prevFilename = m_varStore->m_filename; + m_varStore->m_filename = ""; + + bool ret = m_varStore->loadRFCVarIntoCache(); + EXPECT_EQ(ret, false); + + m_varStore->m_filename = prevFilename; +} + +TEST(httpserverTest, getValue_InitNotDone_ReturnsEmptyEvenWhenKeyExists) { + m_varStore = XRFCVarStore::getInstance(); + + ASSERT_NE(m_varStore, nullptr); + + const bool prevInitDone = m_varStore->initDone; + m_varStore->m_dict["RFC_TEST_KEY"] = "RFC_TEST_VALUE"; + m_varStore->initDone = false; + string value = m_varStore->getValue("RFC_TEST_KEY"); + EXPECT_EQ(value, ""); + + m_varStore->m_dict.erase("RFC_TEST_KEY"); + m_varStore->initDone = prevInitDone; +} + +TEST(httpserverTest, reloadCache_WithQuotedFilename_LoadsValues) { + m_varStore = XRFCVarStore::getInstance(); + + ASSERT_NE(m_varStore, nullptr); + + const string prevFilename = m_varStore->m_filename; + const char *tmpFile = "/tmp/rfc_var_reload_test.ini"; + std::ofstream ofs(tmpFile, std::ios::trunc | std::ios::out); + ofs << "export RFC_TEST_RELOAD_KEY=reload_value" << std::endl; + ofs.close(); + + m_varStore->m_filename = "\"/tmp/rfc_var_reload_test.ini\""; + m_varStore->reloadCache(); + EXPECT_EQ(m_varStore->getValue("RFC_TEST_RELOAD_KEY"), "reload_value"); + + m_varStore->m_filename = prevFilename; + std::remove(tmpFile); +} + TEST(httpserverTest, getWdmpDataType) { EXPECT_EQ(getWdmpDataTypeFunc()("string"), WDMP_STRING); @@ -160,9 +222,18 @@ TEST(httpserverTest, validateParamValue) { const string invalidLongValue = "123dab"; dataType = hostIf_UnsignedLongType; EXPECT_EQ(validateParamValueFunc()(invalidLongValue, dataType), false); + + const string unknownTypeValue = "anything"; + dataType = (HostIf_ParamType_t)999; + EXPECT_EQ(validateParamValueFunc()(unknownTypeValue, dataType), false); } TEST(httpserverTest, handleRFCRequest_GET) { + m_varStore = XRFCVarStore::getInstance(); + ASSERT_NE(m_varStore, nullptr); + m_varStore->m_dict["Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.IssueType"] = "testtype"; + m_varStore->initDone = true; + param_t param; memset(¶m,0,sizeof(param_t)); param.name = strdup("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.IssueType"); @@ -677,11 +748,72 @@ TEST(httpserverTest, convertAndAssignParamValue_UnsignedLongType) { } TEST(httpserverTest, getStringValue) { - EXPECT_STREQ(getStringValueFunc()(hostIf_StringType, "global"), "global"); - EXPECT_STREQ(getStringValueFunc()(hostIf_IntegerType, "100"), "3158065"); - EXPECT_STREQ(getStringValueFunc()(hostIf_BooleanType, "true"), "false"); - EXPECT_STREQ(getStringValueFunc()(hostIf_BooleanType, "false"), "false"); - EXPECT_STREQ(getStringValueFunc()(hostIf_UnsignedLongType, "123456789"), "4050765991979987505"); + + // Test hostIf_StringType: passes string pointer directly + char* stringResult = getStringValueFunc()(hostIf_StringType, "global"); + EXPECT_STREQ(stringResult, "global"); + free(stringResult); + + // Test hostIf_IntegerType: dereferences as int* + int intValue = 100; + char* intResult = getStringValueFunc()(hostIf_IntegerType, (char*)&intValue); + EXPECT_STREQ(intResult, "100"); + free(intResult); + + // Test hostIf_BooleanType with true: dereferences as bool* + bool boolValueTrue = true; + char* boolTrueResult = getStringValueFunc()(hostIf_BooleanType, (char*)&boolValueTrue); + EXPECT_STREQ(boolTrueResult, "true"); + free(boolTrueResult); + + // Test hostIf_BooleanType with false: dereferences as bool* + bool boolValueFalse = false; + char* boolFalseResult = getStringValueFunc()(hostIf_BooleanType, (char*)&boolValueFalse); + EXPECT_STREQ(boolFalseResult, "false"); + free(boolFalseResult); + + // Test hostIf_UnsignedLongType: dereferences as unsigned long* + unsigned long ulValue = 123456789; + char* ulResult = getStringValueFunc()(hostIf_UnsignedLongType, (char*)&ulValue); + EXPECT_STREQ(ulResult, "123456789"); + free(ulResult); + + // Test unknown type: should return empty string + char value[] = "x"; + char* unknownType = getStringValueFunc()((HostIf_ParamType_t)999, value); + EXPECT_STREQ(unknownType, ""); + free(unknownType); +} + +TEST(httpserverTest, getHostIfParamStFromRequest_InvalidReqType_NoMutation) { + param_t param; + memset(¶m, 0, sizeof(param_t)); + param.name = strdup("Device.DeviceInfo.ModelName"); + param.type = WDMP_STRING; + param.value = strdup("model"); + + HOSTIF_MsgData_t hostIfParam; + memset(&hostIfParam, 0, sizeof(HOSTIF_MsgData_t)); + hostIfParam.reqType = HOSTIF_GETATTRIB; + + getHostIfParamStFromRequestFunc()(DELETE_ROW, ¶m, &hostIfParam); + + EXPECT_STREQ(hostIfParam.paramName, "Device.DeviceInfo.ModelName"); + EXPECT_EQ(hostIfParam.reqType, HOSTIF_GETATTRIB); + + free(param.name); + free(param.value); +} + +TEST(httpserverTest, isAuthorized_CoversRebootAndAllowedPaths) { + EXPECT_EQ(isAuthorizedFunc()("webpa", "Device.X_CISCO_COM_DeviceControl.RebootDevice"), false); + EXPECT_EQ(isAuthorizedFunc()("webpa", "Device.DeviceInfo.ModelName"), true); +} + +TEST(httpserverTest, XRFCVarStore_getInstance_IsSingleton) { + XRFCVarStore* instance1 = XRFCVarStore::getInstance(); + XRFCVarStore* instance2 = XRFCVarStore::getInstance(); + EXPECT_EQ(instance1, instance2); } TEST(httpserverTest, Invalid_RFC_filename) { @@ -696,19 +828,147 @@ TEST(httpserverTest, Invalid_RFC_filename) { } } -TEST(httpserverTest, HTTPRequestHandler_GET) { +TEST(httpserverTest, HTTPServerStartThread_And_Stop_CoversLifecycle) { + // Ensure data model is initialized for checkDataModelStatus() + EXPECT_EQ(loadDataModel(), DB_SUCCESS); - // Create a SoupMessage for POST - SoupServer *server = soup_server_new(nullptr, nullptr); - SoupMessage *msg = soup_message_new("POST", "http://localhost/api/status"); - const char *json_body = "{\"action\":\"ping\"}"; - GBytes *body_bytes = g_bytes_new_static(json_body, strlen(json_body)); - soup_message_set_request_body_from_bytes(msg, "application/json", body_bytes); - SoupMessageHeaders *headers = soup_message_get_request_headers(msg); - soup_message_headers_append(headers, "CallerID", "unittest"); + // Use ephemeral port to avoid collisions + argList.httpServerPort = 0; + + std::remove("/tmp/.tr69hostif_http_server_ready"); + + void *thread_result = HTTPServerStartThread(nullptr); + EXPECT_EQ(thread_result, nullptr); - HTTPRequestHandlerFunc()(server, reinterpret_cast(msg), "/api/status", nullptr, nullptr); - EXPECT_EQ(0, 0); + std::ifstream ready_file("/tmp/.tr69hostif_http_server_ready"); + EXPECT_TRUE(ready_file.good()); + ready_file.close(); + + HttpServerStop(); + EXPECT_EQ(httpServerThreadDone, false); + + std::remove("/tmp/.tr69hostif_http_server_ready"); +} + +TEST(httpserverTest, HttpServerStop_WhenServerAlreadyStopped_NoCrash) { + HttpServerStop(); + EXPECT_EQ(httpServerThreadDone, false); +} + +TEST(httpserverTest, handleRequest_InvalidReqType_ReturnsNull) { + req_struct reqSt; + memset(&reqSt, 0, sizeof(req_struct)); + reqSt.reqType = DELETE_ROW; + + res_struct* respSt = handleRequest("rfc", &reqSt); + EXPECT_EQ(respSt, nullptr); +} + +TEST(httpserverTest, handleRequest_GetWithZeroParamCount_ReturnsNull) { + get_req_t *getReq = (get_req_t *)malloc(sizeof(get_req_t)); + memset(getReq, 0, sizeof(get_req_t)); + getReq->paramCnt = 0; + + req_struct reqSt; + memset(&reqSt, 0, sizeof(req_struct)); + reqSt.reqType = GET; + reqSt.u.getReq = getReq; + + res_struct* respSt = handleRequest("rfc", &reqSt); + EXPECT_EQ(respSt, nullptr); + + free(getReq); +} + +TEST(httpserverTest, handleRequest_SetWithZeroParamCount_ReturnsNull) { + set_req_t *setReq = (set_req_t *)malloc(sizeof(set_req_t)); + memset(setReq, 0, sizeof(set_req_t)); + setReq->paramCnt = 0; + setReq->param = nullptr; + + req_struct reqSt; + memset(&reqSt, 0, sizeof(req_struct)); + reqSt.reqType = SET; + reqSt.u.setReq = setReq; + + res_struct* respSt = handleRequest("rfc", &reqSt); + EXPECT_EQ(respSt, nullptr); + + free(setReq); +} + +TEST(httpserverTest, handleRequest_GetLongParamName_ReturnsInvalidParameterName) { + std::string longParamName(MAX_PARAMETERNAME_LEN + 32, 'A'); + + get_req_t *getReq = (get_req_t *)malloc(sizeof(get_req_t)); + memset(getReq, 0, sizeof(get_req_t)); + getReq->paramCnt = 1; + getReq->paramNames[0] = strdup(longParamName.c_str()); + + req_struct reqSt; + memset(&reqSt, 0, sizeof(req_struct)); + reqSt.reqType = GET; + reqSt.u.getReq = getReq; + + res_struct* respSt = handleRequest("rfc", &reqSt); + ASSERT_NE(respSt, nullptr); + EXPECT_EQ(respSt->retStatus[0], WDMP_ERR_INVALID_PARAMETER_NAME); + + wdmp_free_res_struct(respSt); + free(getReq->paramNames[0]); + free(getReq); +} + +TEST(httpserverTest, handleRequest_SetRFCVariable_MethodNotSupported) { + set_req_t *setReq = (set_req_t *)malloc(sizeof(set_req_t)); + memset(setReq, 0, sizeof(set_req_t)); + setReq->paramCnt = 1; + setReq->param = (param_t *)malloc(sizeof(param_t)); + memset(setReq->param, 0, sizeof(param_t)); + setReq->param[0].name = strdup("RFC_TEST_VARIABLE"); + setReq->param[0].value = strdup("true"); + setReq->param[0].type = WDMP_STRING; + + req_struct reqSt; + memset(&reqSt, 0, sizeof(req_struct)); + reqSt.reqType = SET; + reqSt.u.setReq = setReq; + + res_struct* respSt = handleRequest("rfc", &reqSt); + ASSERT_NE(respSt, nullptr); + EXPECT_EQ(respSt->retStatus[0], WDMP_ERR_METHOD_NOT_SUPPORTED); + + wdmp_free_res_struct(respSt); + free(setReq->param[0].name); + free(setReq->param[0].value); + free(setReq->param); + free(setReq); +} + +TEST(httpserverTest, handleRequest_SetRFCReloadCache_Success) { + set_req_t *setReq = (set_req_t *)malloc(sizeof(set_req_t)); + memset(setReq, 0, sizeof(set_req_t)); + setReq->paramCnt = 1; + setReq->param = (param_t *)malloc(sizeof(param_t)); + memset(setReq->param, 0, sizeof(param_t)); + setReq->param[0].name = strdup(XRFC_VAR_STORE_RELOADCACHE); + setReq->param[0].value = strdup("1"); + setReq->param[0].type = WDMP_STRING; + + req_struct reqSt; + memset(&reqSt, 0, sizeof(req_struct)); + reqSt.reqType = SET; + reqSt.u.setReq = setReq; + + res_struct* respSt = handleRequest("rfc", &reqSt); + ASSERT_NE(respSt, nullptr); + EXPECT_EQ(respSt->retStatus[0], WDMP_SUCCESS); + + wdmp_free_res_struct(respSt); + free(setReq->param[0].name); + free(setReq->param[0].value); + free(setReq->param); + free(setReq); } diff --git a/src/hostif/httpserver/src/request_handler.cpp b/src/hostif/httpserver/src/request_handler.cpp index a324f5f23..a8a01ee80 100644 --- a/src/hostif/httpserver/src/request_handler.cpp +++ b/src/hostif/httpserver/src/request_handler.cpp @@ -780,4 +780,14 @@ char* (*getStringValueFunc()) (HostIf_ParamType_t paramType, char *value) { return &getStringValue; } + +bool (*isAuthorizedFunc())(const char* pcCallerID, const char* pcParamName) +{ + return &isAuthorized; +} + +void (*getHostIfParamStFromRequestFunc())(REQ_TYPE reqType, param_t *param, HOSTIF_MsgData_t *hostIfParam) +{ + return &getHostIfParamStFromRequest; +} #endif diff --git a/src/hostif/include/IniFile.h b/src/hostif/include/IniFile.h index 1bff86c3c..8169b3432 100644 --- a/src/hostif/include/IniFile.h +++ b/src/hostif/include/IniFile.h @@ -43,6 +43,7 @@ class IniFile #if defined(GTEST_ENABLE) FRIEND_TEST(srcTest, flush); + FRIEND_TEST(srcTest, iniFileClearFlushesEmptyContent); #endif }; diff --git a/src/hostif/parodusClient/gtest/dm_test.cpp b/src/hostif/parodusClient/gtest/dm_test.cpp index 83f6dba14..9439ef873 100644 --- a/src/hostif/parodusClient/gtest/dm_test.cpp +++ b/src/hostif/parodusClient/gtest/dm_test.cpp @@ -266,6 +266,11 @@ TEST(datamodelTest, getNumberofInstances) { } +TEST(datamodelTest, getNumberofInstances_NullParam) { + int cnt = getNumberofInstances(NULL); + EXPECT_EQ(cnt, 0); +} + TEST(datamodelTest, isWildCardParam) { int wildParam = isWildCardParam("Device.DeviceInfo."); EXPECT_EQ(wildParam, 1); @@ -276,11 +281,21 @@ TEST(datamodelTest, isParamEndsWithInstance) { EXPECT_EQ(instance, 0); } +TEST(datamodelTest, isParamEndsWithInstance_NullInput) { + int instance = isParamEndsWithInstance(NULL); + EXPECT_EQ(instance, 1); +} + TEST(datamodelTest, getNumberOfDigitsInInstanceNumber) { int instance = getNumberOfDigitsInInstanceNumber("Device.WiFi.SSID.123.Name", 17); EXPECT_EQ(instance, 3); } +TEST(datamodelTest, getNumberOfDigitsInInstanceNumber_NullInput) { + int instance = getNumberOfDigitsInInstanceNumber(NULL, 0); + EXPECT_EQ(instance, 0); +} + TEST(datamodelTest, getChildParamNamesFromDataModel) { /* Load the data model xml file*/ @@ -326,6 +341,29 @@ TEST(datamodelTest, getChildParamNamesFromDataModel_InvalidParam) { EXPECT_EQ(status, 2); } +TEST(datamodelTest, getChildParamNamesFromDataModel_NonWildcard) { + DB_STATUS dbStatus = loadDataModel(); + EXPECT_EQ(dbStatus, DB_SUCCESS); + + char *ParamList = NULL; + char *ParamDataTypeList = NULL; + + char *paramName = (char *)"Device.DeviceInfo.ModelName"; + int paramCount = 0; + DB_STATUS status = getChildParamNamesFromDataModel(getDataModelHandle(), paramName, &ParamList, &ParamDataTypeList, ¶mCount); + EXPECT_EQ(status, DB_ERR_WILDCARD_NOT_SUPPORTED); +} + +TEST(datamodelTest, getChildParamNamesFromDataModel_NullDbHandle) { + char *ParamList = NULL; + char *ParamDataTypeList = NULL; + + char *paramName = (char *)"Device.DeviceInfo."; + int paramCount = 0; + DB_STATUS status = getChildParamNamesFromDataModel(NULL, paramName, &ParamList, &ParamDataTypeList, ¶mCount); + EXPECT_EQ(status, DB_FAILURE); +} + TEST(datamodelTest, checkDataModelStatus) { DB_STATUS status = checkDataModelStatus(); EXPECT_EQ(status, DB_SUCCESS); @@ -339,12 +377,46 @@ TEST(datamodelTest, checkMatchingParameter) { EXPECT_EQ(retValue, 1); } +TEST(datamodelTest, checkMatchingParameter_NoMatch) { + const char* attrValue = "a.b.c.{i}."; + char* paramName = (char*)"x.y.z."; + int ret = 0; + int retValue = checkMatchingParameter(attrValue, paramName, &ret); + EXPECT_EQ(retValue, 0); + EXPECT_EQ(ret, 0); +} + +TEST(datamodelTest, getParamInfoFromDataModel_NullDbHandle) { + DataModelParam dmParam = {0}; + int match = getParamInfoFromDataModel(NULL, "Device.DeviceInfo.ModelName", &dmParam); + EXPECT_EQ(match, 0); +} + +TEST(datamodelTest, freeDataModelParam_AllFields) { + DataModelParam dmParam = {0}; + dmParam.objectName = strdup("Device.DeviceInfo.ModelName"); + dmParam.paramName = strdup("ModelName"); + dmParam.access = strdup("readOnly"); + dmParam.dataType = strdup("string"); + dmParam.defaultValue = strdup("NA"); + dmParam.bsUpdate = strdup("none"); + + freeDataModelParam(dmParam); + EXPECT_EQ(0, 0); +} + TEST(startParodusTest, get_HWMAcAddress) { write_on_file("/tmp/.macAddress", "D4:52:EE:DE:C6:FA"); std::string macAddr = get_HWMAcAddress(); EXPECT_EQ(macAddr, "D452EEDEC6FA"); } +TEST(startParodusTest, get_HWMAcAddress_MissingFile) { + std::remove("/tmp/.macAddress"); + std::string macAddr = get_HWMAcAddress(); + EXPECT_EQ(macAddr, ""); +} + TEST(startParodusTest, get_PartnerId_Empty) { write_on_file("/opt/www/authService/partnerId3.dat", ""); std::string partnerId = get_PartnerId(); @@ -365,6 +437,12 @@ TEST(startParodusTest, get_PartnerId_Unknown) { std::remove("/opt/www/authService/partnerId3.dat"); } +TEST(startParodusTest, get_PartnerId_MissingFile_FallbackPrefixOnly) { + std::remove("/opt/www/authService/partnerId3.dat"); + std::string partnerId = get_PartnerId(); + EXPECT_EQ(partnerId, "*,"); +} + TEST(startParodusTest, get_RebootReason_Empty) { write_on_file("/opt/secure/reboot/previousreboot.info", ""); std::string reboot_reason = get_RebootReason(); @@ -378,12 +456,24 @@ TEST(startParodusTest, get_RebootReason) { EXPECT_EQ(reboot_reason, "PowerOnReset"); } +TEST(startParodusTest, get_RebootReason_InvalidJson) { + write_on_file("/opt/secure/reboot/previousreboot.info", "{invalid json}"); + std::string reboot_reason = get_RebootReason(); + EXPECT_EQ(reboot_reason, ""); +} + TEST(startParodusTest, get_FwName) { write_on_file("/version.txt", "imagename:ELTE11MWR_VBN_25Q3_sprint_20250814010729sdy_NG"); std::string fw_name = get_FwName(); EXPECT_EQ(fw_name, "ELTE11MWR_VBN_25Q3_sprint_20250814010729sdy_NG"); } +TEST(startParodusTest, get_FwName_MalformedLine) { + write_on_file("/version.txt", "imagename-only-without-delimiter"); + std::string fw_name = get_FwName(); + EXPECT_EQ(fw_name, ""); +} + TEST(palTest, macToLower) { char macValue[32] = "A8:4A:63:88:E9:B5"; char macConverted[32]; @@ -757,6 +847,25 @@ TEST(palPdTest, get_parodus_url_MissingConfigFileSetsDefaults) { EXPECT_NE(client_url, ""); } +TEST(palPdTest, get_parodus_url_InvalidJsonSetsDefaults) { + write_on_file("/etc/webpa_cfg.json", "{invalid json}"); + char parodus_url[64] = {'\0'}; + char client_url[64] = {'\0'}; + get_parodus_urlFunc()(parodus_url, client_url); + EXPECT_NE(parodus_url, ""); + EXPECT_NE(client_url, ""); +} + +TEST(palPdTest, get_parodus_url_MissingClientUrlSetsDefaults) { + const char *webpaCfgFile = "{ \"ParodusURL\": \"tcp://parodus.xcal.tv:6666\" }"; + write_on_file("/etc/webpa_cfg.json", webpaCfgFile); + char parodus_url[64] = {'\0'}; + char client_url[64] = {'\0'}; + get_parodus_urlFunc()(parodus_url, client_url); + EXPECT_NE(parodus_url, ""); + EXPECT_NE(client_url, ""); +} + TEST(palTest, get_parodus_url) { char parodus_url[256] = {0}; char client_url[256] = {0}; @@ -821,6 +930,38 @@ TEST(palTest, validate_parameter_NOT_Support) { free(params); } +TEST(palTest, validate_parameter_Success) { + param_t *params = (param_t *) malloc(sizeof(param_t) * 1); + + int paramCount = 1; + params[0].name = strdup("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.IncrementalCDL.Enable"); + params[0].value = strdup("true"); + params[0].type = WDMP_BOOLEAN; + + WDMP_STATUS status = validate_parameterFunc()(params, paramCount); + EXPECT_EQ(status, WDMP_SUCCESS); + + free(params[0].name); + free(params[0].value); + free(params); +} + +TEST(palTest, validate_parameter_CID_NotSupported) { + param_t *params = (param_t *) malloc(sizeof(param_t) * 1); + + int paramCount = 1; + params[0].name = strdup(PARAM_CID); + params[0].value = strdup("test"); + params[0].type = WDMP_STRING; + + WDMP_STATUS status = validate_parameterFunc()(params, paramCount); + EXPECT_EQ(status, WDMP_ERR_SET_OF_CMC_OR_CID_NOT_SUPPORTED); + + free(params[0].name); + free(params[0].value); + free(params); +} + TEST(palTest, processRequest_GET) { strcpy(argList.confFile, "/etc/mgrlist.conf"); bool ret = hostIf_initalize_ConfigManger(); @@ -994,6 +1135,15 @@ TEST(palTest, getParamAttributes) { EXPECT_EQ(status, WAL_ERR_INVALID_PARAM); } +TEST(palTest, getParamAttributes_NullInputs) { + AttrVal **attributes = NULL; + int totalParams = 0; + + EXPECT_EQ(getParamAttributesFunc()(NULL, &attributes, &totalParams), WAL_ERR_INVALID_PARAM); + EXPECT_EQ(getParamAttributesFunc()("Device.DeviceInfo.ModelName", NULL, &totalParams), WAL_ERR_INVALID_PARAM); + EXPECT_EQ(getParamAttributesFunc()("Device.DeviceInfo.ModelName", &attributes, NULL), WAL_ERR_INVALID_PARAM); +} + TEST(palTest, setParamAttributes) { const char *paramName = "Device.WiFi.SSID.1.SSID"; @@ -1210,6 +1360,83 @@ TEST(palTest, getnotifyparamList_NULL) { EXPECT_EQ(ret, -1); } +TEST(palTest, getnotifyparamList_MissingFile) { + setNotifyConfigurationFile("/tmp/non_existent_notify_list.json"); + char **notifyParamList = NULL; + int notifyListSize = 0; + int result = getnotifyparamList(¬ifyParamList, ¬ifyListSize); + EXPECT_EQ(result, -1); +} + +TEST(palTest, getnotifyparamList_NoNotifyArray) { + const char* json_data = R"({"NoNotify":["Device.DeviceInfo.ModelName"]})"; + write_on_file("/tmp/notify_no_array.conf", json_data); + setNotifyConfigurationFile("/tmp/notify_no_array.conf"); + + char **notifyParamList = NULL; + int notifyListSize = 7; + int result = getnotifyparamList(¬ifyParamList, ¬ifyListSize); + + EXPECT_EQ(result, 0); + EXPECT_EQ(notifyParamList, nullptr); + EXPECT_EQ(notifyListSize, 7); +} + +TEST(palTest, isWildCardParam_NullInput) { + int ret = isWildCardParam(NULL); + EXPECT_EQ(ret, 0); +} + +TEST(palTest, converttoWalType_DefaultBranch) { + WAL_DATA_TYPE walType = WAL_INT; + converttoWalTypeFunc()((HostIf_ParamType_t)999, &walType); + EXPECT_EQ(walType, WAL_STRING); +} + +/*TEST(palTest, SetParamInfoFunc_InvalidBooleanValue) { + DB_STATUS dbStatus = loadDataModel(); + EXPECT_EQ(dbStatus, DB_SUCCESS); + + ParamVal param; + param.name = (char*)"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.IncrementalCDL.Enable"; + param.value = (char*)"not_bool"; + param.type = WAL_BOOLEAN; + + char transactionID[] = "txn12344"; + WAL_STATUS status = SetParamInfoFunc()(param, transactionID); + EXPECT_EQ(status, WAL_ERR_INVALID_PARAMETER_VALUE); +} + + +TEST(palTest, SetParamInfoFunc_InvalidUnsignedValue) { + DB_STATUS dbStatus = loadDataModel(); + EXPECT_EQ(dbStatus, DB_SUCCESS); + + ParamVal param; + param.name = (char*)"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.collectd.PortNumber"; + param.value = (char*)"-1"; + param.type = WAL_UINT; + + char transactionID[] = "txn12344"; + WAL_STATUS status = SetParamInfoFunc()(param, transactionID); + EXPECT_EQ(status, WAL_ERR_INVALID_PARAMETER_VALUE); +} + +TEST(palTest, SetParamInfoFunc_InvalidTypeMismatch) { + DB_STATUS dbStatus = loadDataModel(); + EXPECT_EQ(dbStatus, DB_SUCCESS); + + ParamVal param; + param.name = (char*)"Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.IncrementalCDL.Enable"; + param.value = (char*)"1"; + param.type = WAL_INT; + + char transactionID[] = "txn12344"; + WAL_STATUS status = SetParamInfoFunc()(param, transactionID); + EXPECT_EQ(status, WAL_ERR_INVALID_PARAMETER_TYPE); +} + +*/ TEST(ProcessStatus, DeviceInfo_ProcessStatus_Process_PID) { HOSTIF_MsgData_t param; bool bChanged; diff --git a/src/hostif/profiles/DHCPv4/Device_DHCPv4_Client.h b/src/hostif/profiles/DHCPv4/Device_DHCPv4_Client.h index 4edf4d995..b6e1e059e 100644 --- a/src/hostif/profiles/DHCPv4/Device_DHCPv4_Client.h +++ b/src/hostif/profiles/DHCPv4/Device_DHCPv4_Client.h @@ -181,11 +181,16 @@ class hostIf_DHCPv4Client { #if defined(GTEST_ENABLE) FRIEND_TEST(dhcpv4Test, isValidIPAddr); - FRIEND_TEST(dhcpv4Test, InvalidIPAddr); - FRIEND_TEST(dhcpv4Test, InvalidIP); - FRIEND_TEST(dhcpv4Test, InvalidIPAddr_alpha); + FRIEND_TEST(dhcpv4Test, InvalidIPAddr); + FRIEND_TEST(dhcpv4Test, InvalidIP); + FRIEND_TEST(dhcpv4Test, InvalidIPAddr_alpha); + FRIEND_TEST(dhcpv4Test, InvalidIPAddr_EmptyString); + FRIEND_TEST(dhcpv4Test, InvalidIPAddr_TooLong); + FRIEND_TEST(dhcpv4Test, InvalidIPAddr_MissingOctet); FRIEND_TEST(dhcpv4Test, getInterfaceName); + FRIEND_TEST(dhcpv4Test, getInterfaceName_InvalidInstance); FRIEND_TEST(dhcpv4Test, isIfnameInroutetoDNSServer); + FRIEND_TEST(dhcpv4Test, isIfnameInroutetoDNSServer_InvalidRoute); #endif }; #endif diff --git a/src/hostif/profiles/DHCPv4/gtest/gtest_dhcpv4.cpp b/src/hostif/profiles/DHCPv4/gtest/gtest_dhcpv4.cpp index 07677f5b8..103a3ae28 100644 --- a/src/hostif/profiles/DHCPv4/gtest/gtest_dhcpv4.cpp +++ b/src/hostif/profiles/DHCPv4/gtest/gtest_dhcpv4.cpp @@ -82,42 +82,79 @@ TEST(dhcpv4Test, InvalidIPAddr_alpha) { } } +TEST(dhcpv4Test, InvalidIPAddr_EmptyString) { + int instanceNumber = 1; + char addr[] = ""; + + hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); + ASSERT_NE(dhcpClient, nullptr); + + bool result = dhcpClient->isValidIPAddr(addr); + EXPECT_EQ(result, false); +} + +TEST(dhcpv4Test, InvalidIPAddr_TooLong) { + int instanceNumber = 1; + char addr[] = "192.168.100.1000"; + hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); + ASSERT_NE(dhcpClient, nullptr); + + bool result = dhcpClient->isValidIPAddr(addr); + EXPECT_EQ(result, false); +} + +TEST(dhcpv4Test, InvalidIPAddr_MissingOctet) { + int instanceNumber = 1; + char addr[] = "192..1.1"; + hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); + ASSERT_NE(dhcpClient, nullptr); + + bool result = dhcpClient->isValidIPAddr(addr); + EXPECT_EQ(result, false); +} + TEST(dhcpv4Test, getInterfaceName) { int instanceNumber = 1; char ifname[IFNAMSIZ]={'\0'}; hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - int result = dhcpClient->getInterfaceName(ifname); - EXPECT_EQ(result, OK); - } + ASSERT_NE(dhcpClient, nullptr); + + int result = dhcpClient->getInterfaceName(ifname); + EXPECT_EQ(result, OK); } +TEST(dhcpv4Test, getInterfaceName_InvalidInstance) { + int instanceNumber = 999; + char ifname[IFNAMSIZ]={'\0'}; + hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); + ASSERT_NE(dhcpClient, nullptr); + + int result = dhcpClient->getInterfaceName(ifname); + EXPECT_EQ(result, NOK); +} -/* TEST(dhcpv4Test, isIfnameInroutetoDNSServer) { +TEST(dhcpv4Test, isIfnameInroutetoDNSServer_InvalidRoute) { int instanceNumber = 1; - char* dnsServer = (char*)"8.8.8.8"; - char* ifname = (char*)"eth0"; + char* dnsServer = (char*)"203.0.113.254"; + char* ifname = (char*)"lo"; hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - bool result = dhcpClient->isIfnameInroutetoDNSServer(dnsServer, ifname); - EXPECT_EQ(result, true); - } -} */ + ASSERT_NE(dhcpClient, nullptr); + + bool result = dhcpClient->isIfnameInroutetoDNSServer(dnsServer, ifname); + EXPECT_EQ(result, false); +} TEST(dhcpv4Test, get_Device_DHCPv4_ClientNumberOfEntries) { int instanceNumber = 1; HOSTIF_MsgData_t param = { 0 }; memset(¶m,0,sizeof(HOSTIF_MsgData_t)); hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - int result = dhcpClient->get_Device_DHCPv4_ClientNumberOfEntries(¶m); - cout << "param.paramValue = " << param.paramValue << endl; - EXPECT_EQ(result, OK); - EXPECT_EQ(param.paramtype, hostIf_UnsignedIntType); - } + ASSERT_NE(dhcpClient, nullptr); + + int result = dhcpClient->get_Device_DHCPv4_ClientNumberOfEntries(¶m); + cout << "param.paramValue = " << param.paramValue << endl; + EXPECT_EQ(result, OK); + EXPECT_EQ(param.paramtype, hostIf_UnsignedIntType); } TEST(dhcpv4Test, get_Device_DHCPv4_Client_IPRouters) { @@ -126,14 +163,13 @@ TEST(dhcpv4Test, get_Device_DHCPv4_Client_IPRouters) { HOSTIF_MsgData_t param = { 0 }; memset(¶m,0,sizeof(HOSTIF_MsgData_t)); hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - bChanged = false; - int result = dhcpClient->get_Device_DHCPv4_Client_IPRouters(¶m, &bChanged); - cout << "param.paramValue = " << param.paramValue << endl; - EXPECT_EQ(result, OK); - EXPECT_EQ(param.paramtype, hostIf_StringType); - } + ASSERT_NE(dhcpClient, nullptr); + + bChanged = false; + int result = dhcpClient->get_Device_DHCPv4_Client_IPRouters(¶m, &bChanged); + cout << "param.paramValue = " << param.paramValue << endl; + EXPECT_EQ(result, OK); + EXPECT_EQ(param.paramtype, hostIf_StringType); } TEST(dhcpv4Test, get_Device_DHCPv4_Client_DnsServer) { @@ -142,14 +178,13 @@ TEST(dhcpv4Test, get_Device_DHCPv4_Client_DnsServer) { HOSTIF_MsgData_t param = { 0 }; memset(¶m,0,sizeof(HOSTIF_MsgData_t)); hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - bChanged = false; - int result = dhcpClient->get_Device_DHCPv4_Client_DnsServer(¶m, &bChanged); - cout << "param.paramValue = " << param.paramValue << endl; - EXPECT_EQ(result, OK); - EXPECT_EQ(param.paramtype, hostIf_StringType); - } + ASSERT_NE(dhcpClient, nullptr); + + bChanged = false; + int result = dhcpClient->get_Device_DHCPv4_Client_DnsServer(¶m, &bChanged); + cout << "param.paramValue = " << param.paramValue << endl; + EXPECT_EQ(result, OK); + EXPECT_EQ(param.paramtype, hostIf_StringType); } TEST(dhcpv4Test, get_Device_DHCPv4_Client_InterfaceReference) { @@ -158,25 +193,24 @@ TEST(dhcpv4Test, get_Device_DHCPv4_Client_InterfaceReference) { HOSTIF_MsgData_t param = { 0 }; memset(¶m,0,sizeof(HOSTIF_MsgData_t)); hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - bChanged = false; - int result = dhcpClient->get_Device_DHCPv4_Client_InterfaceReference(¶m, &bChanged); - cout << "param.paramValue = " << param.paramValue << endl; - EXPECT_EQ(result, OK); - EXPECT_EQ(param.paramtype, hostIf_StringType); - } + ASSERT_NE(dhcpClient, nullptr); + + bChanged = false; + int result = dhcpClient->get_Device_DHCPv4_Client_InterfaceReference(¶m, &bChanged); + cout << "param.paramValue = " << param.paramValue << endl; + EXPECT_EQ(result, OK); + EXPECT_EQ(param.paramtype, hostIf_StringType); } TEST(dhcpv4Test, Lock_ReleaseLock) { int instanceNumber = 1; hostIf_DHCPv4Client *dhcpClient= hostIf_DHCPv4Client::getInstance(instanceNumber); - if(dhcpClient) - { - dhcpClient->getLock(); - dhcpClient->releaseLock(); - EXPECT_EQ(0, 0); - } + ASSERT_NE(dhcpClient, nullptr); + + dhcpClient->getLock(); + dhcpClient->releaseLock(); + EXPECT_EQ(0, 0); + dhcpClient->closeInstance(dhcpClient); dhcpClient->closeAllInstances(); } diff --git a/src/hostif/profiles/Device/gtest/gtest_device.cpp b/src/hostif/profiles/Device/gtest/gtest_device.cpp old mode 100644 new mode 100755 index f4995fef8..5861462f3 --- a/src/hostif/profiles/Device/gtest/gtest_device.cpp +++ b/src/hostif/profiles/Device/gtest/gtest_device.cpp @@ -180,6 +180,60 @@ TEST(DeviceTest, handleGetMsg_WebPA_Server_URL) { } } +TEST(DeviceTest, handleGetMsg_WebPA_TokenServer_URL) { + HOSTIF_MsgData_t param = { 0 }; + memset(¶m,0,sizeof(HOSTIF_MsgData_t)); + param.reqType = HOSTIF_GET; + strncpy (param.paramName, "Device.X_RDK_WebPA_TokenServer.URL", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + param.bsUpdate = HOSTIF_NONE; + param.requestor = HOSTIF_SRC_WEBPA; + param.paramtype = hostIf_StringType; + param.paramLen = sizeof(hostIf_StringType); + + X_rdk_profile* profile = X_rdk_profile::getInstance(); + if(profile) + { + int ret = profile->handleGetMsg(¶m); + std::string value = getStringValue(¶m); + EXPECT_EQ(ret, OK); + EXPECT_EQ(value, ""); + } +} + +TEST(DeviceTest, handleSetMsg_EmptyParamName) { + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + param.reqType = HOSTIF_SET; + param.paramName[0] = '\0'; + param.bsUpdate = HOSTIF_NONE; + param.requestor = HOSTIF_SRC_WEBPA; + + X_rdk_profile* profile = X_rdk_profile::getInstance(); + ASSERT_NE(profile, nullptr); + + int ret = profile->handleSetMsg(¶m); + EXPECT_EQ(param.faultCode, fcInvalidParameterName); + EXPECT_EQ(ret, NOK); +} + +TEST(DeviceTest, handleGetMsg_EmptyParamName) { + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + param.reqType = HOSTIF_GET; + param.paramName[0] = '\0'; + param.bsUpdate = HOSTIF_NONE; + param.requestor = HOSTIF_SRC_WEBPA; + param.paramtype = hostIf_StringType; + param.paramLen = sizeof(hostIf_StringType); + + X_rdk_profile* profile = X_rdk_profile::getInstance(); + ASSERT_NE(profile, nullptr); + + int ret = profile->handleGetMsg(¶m); + EXPECT_EQ(ret, NOK); + EXPECT_EQ(param.faultCode, fcInvalidParameterName); +} + TEST(DeviceTest, handleSetMsg_InvalidParam) { int instanceNumber = 0; HOSTIF_MsgData_t param = { 0 }; diff --git a/src/hostif/profiles/DeviceInfo/gtest/gtest_main.cpp b/src/hostif/profiles/DeviceInfo/gtest/gtest_main.cpp index 01e95fbb1..07dff15a1 100644 --- a/src/hostif/profiles/DeviceInfo/gtest/gtest_main.cpp +++ b/src/hostif/profiles/DeviceInfo/gtest/gtest_main.cpp @@ -35,6 +35,7 @@ #include "waldb.h" #include "Device_DeviceInfo_Processor.h" #include "Device_DeviceInfo_ProcessStatus.h" +#include "Device_DeviceInfo_ProcessStatus_Process.h" #ifdef __cplusplus extern "C" @@ -183,6 +184,61 @@ TEST(rfcStoreTest, getLocalValueAfterClear) { EXPECT_EQ(ret, fcInternalError); } +TEST(rfcStoreTest, clearLocalValueWithWildcard) { + m_rfcStore = XRFCStore::getInstance(); + + HOSTIF_MsgData_t setParam1 = { 0 }; + memset(&setParam1, 0, sizeof(HOSTIF_MsgData_t)); + setParam1.reqType = HOSTIF_SET; + strncpy(setParam1.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.SystemServices.UnitTest.Param1", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setParam1.requestor = HOSTIF_SRC_WEBPA; + strncpy(setParam1.paramValue, "value1", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setParam1.paramtype = hostIf_StringType; + setParam1.paramLen = strlen(setParam1.paramValue); + EXPECT_EQ(m_rfcStore->setValue(&setParam1), fcNoFault); + + HOSTIF_MsgData_t setParam2 = { 0 }; + memset(&setParam2, 0, sizeof(HOSTIF_MsgData_t)); + setParam2.reqType = HOSTIF_SET; + strncpy(setParam2.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.SystemServices.UnitTest.Param2", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setParam2.requestor = HOSTIF_SRC_WEBPA; + strncpy(setParam2.paramValue, "value2", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setParam2.paramtype = hostIf_StringType; + setParam2.paramLen = strlen(setParam2.paramValue); + EXPECT_EQ(m_rfcStore->setValue(&setParam2), fcNoFault); + + HOSTIF_MsgData_t clearParam = { 0 }; + memset(&clearParam, 0, sizeof(HOSTIF_MsgData_t)); + clearParam.reqType = HOSTIF_SET; + strncpy(clearParam.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.ClearParam", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + clearParam.requestor = HOSTIF_SRC_WEBPA; + strncpy(clearParam.paramValue, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.SystemServices.UnitTest.", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + clearParam.paramtype = hostIf_StringType; + clearParam.paramLen = strlen(clearParam.paramValue); + EXPECT_EQ(m_rfcStore->setValue(&clearParam), fcNoFault); + + HOSTIF_MsgData_t getParam = { 0 }; + memset(&getParam, 0, sizeof(HOSTIF_MsgData_t)); + getParam.reqType = HOSTIF_GET; + strncpy(getParam.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.SystemServices.UnitTest.Param1", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + EXPECT_EQ(m_rfcStore->getValue(&getParam), fcInternalError); +} + +TEST(rfcStoreTest, setValue_NonPersistentFromWebpa_Fails) { + m_rfcStore = XRFCStore::getInstance(); + + HOSTIF_MsgData_t param = { 0 }; + memset(¶m,0,sizeof(HOSTIF_MsgData_t)); + param.reqType = HOSTIF_SET; + strncpy(param.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.NonPersistent.UnitTest.Enable", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + param.requestor = HOSTIF_SRC_WEBPA; + put_boolean(param.paramValue, true); + param.paramtype = hostIf_BooleanType; + param.paramLen = sizeof(hostIf_BooleanType); + + EXPECT_EQ(m_rfcStore->setValue(¶m), fcInternalError); +} + TEST(bsStoreTest, getValueFactoryFresh) { m_bsStore = XBSStore::getInstance(); @@ -1777,6 +1833,121 @@ TEST(deviceTest, get_Device_DeviceInfo_IUI_Version_EmptyFile) { } } +TEST(deviceTest, get_Device_DeviceInfo_IUI_AppsVersion) { + std::remove("/tmp/.iuiAppsVersion"); + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + + int instanceNumber = 0; + write_on_file("/tmp/.iuiAppsVersion", "3.3\n"); + + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + ASSERT_NE(pIface, nullptr); + + int ret = pIface->get_Device_DeviceInfo_IUI_AppsVersion(&msgData); + EXPECT_EQ(ret, OK); + EXPECT_STREQ(msgData.paramValue, "3.3"); + std::remove("/tmp/.iuiAppsVersion"); +} + +TEST(deviceTest, set_Device_DeviceInfo_IUI_AppsVersion) { + int instanceNumber = 0; + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + msgData.reqType = HOSTIF_SET; + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM.IUI.AppsVersion", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + msgData.bsUpdate = HOSTIF_NONE; + msgData.requestor = HOSTIF_SRC_RFC; + + strncpy(msgData.paramValue, "6.6", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + msgData.paramtype = hostIf_StringType; + msgData.paramLen = strlen(msgData.paramValue); + + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + if(pIface) + { + int ret = pIface->set_Device_DeviceInfo_IUI_AppsVersion(&msgData); + EXPECT_EQ(ret, OK); + } +} + +TEST(deviceTest, set_Device_DeviceInfo_Empty_IUI_AppsVersion) { + int instanceNumber = 0; + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + msgData.reqType = HOSTIF_SET; + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM.IUI.AppsVersion", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + msgData.bsUpdate = HOSTIF_NONE; + msgData.requestor = HOSTIF_SRC_RFC; + + strncpy(msgData.paramValue, "", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + msgData.paramtype = hostIf_StringType; + msgData.paramLen = strlen(msgData.paramValue); + + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + if(pIface) + { + int ret = pIface->set_Device_DeviceInfo_IUI_AppsVersion(&msgData); + EXPECT_EQ(ret, OK); + } +} + +TEST(deviceTest, get_Device_DeviceInfo_IUI_AppsVersion_FileRemoved) { + std::remove("/tmp/.iuiAppsVersion"); + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + int instanceNumber = 0; + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + if(pIface) + { + int ret = pIface->get_Device_DeviceInfo_IUI_AppsVersion(&msgData); + EXPECT_EQ(ret, OK); + EXPECT_STREQ(msgData.paramValue, ""); + } +} + +TEST(deviceTest, get_Device_DeviceInfo_IUI_AppsVersion_EmptyFile) { + std::ofstream file("/tmp/.iuiAppsVersion"); + file.close(); + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + int instanceNumber = 0; + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + if(pIface) + { + int ret = pIface->get_Device_DeviceInfo_IUI_AppsVersion(&msgData); + EXPECT_EQ(ret, OK); + EXPECT_STREQ(msgData.paramValue, ""); + } +} + +TEST(deviceTest, get_HotelCheckoutLastResetTime) { + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + int instanceNumber = 0; + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + if(pIface) + { + int ret = pIface->get_HotelCheckoutLastResetTime(&msgData); + EXPECT_EQ(ret, NOK); + } +} + +TEST(deviceTest, get_HotelCheckoutStatus) { + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + int instanceNumber = 0; + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + if(pIface) + { + int ret = pIface->get_HotelCheckoutStatus(&msgData); + EXPECT_EQ(ret, NOK); + } +} + TEST(deviceTest, set_xOpsDMUploadLogsNow) { bool bChanged; int instanceNumber = 0; @@ -1841,7 +2012,7 @@ TEST(deviceInfoTest, get_Device_DeviceInfo_MigrationPreparer_MigrationReady) { bChanged = false; int ret = pIface->get_Device_DeviceInfo_MigrationPreparer_MigrationReady(&msgData); cout << "msgData.paramValue = " << msgData.paramValue << endl; - EXPECT_EQ(ret, OK); + EXPECT_EQ(ret, NOK); } } @@ -1946,6 +2117,7 @@ TEST(deviceInfoTest, get_X_RDK_FirmwareName) { } TEST(deviceInfoTest, get_X_RDKCENTRAL_COM_LastRebootReason) { + write_on_file("/opt/secure/reboot/previousreboot.info", "{\"reason\": \"PowerOnReset\", \"timestamp\": 1688914800}"); int instanceNumber = 0; HOSTIF_MsgData_t msgData; @@ -1974,6 +2146,39 @@ TEST(deviceInfoTest, get_Device_DeviceInfo_X_RDKCENTRAL_COM_XRPollingAction) { } } +TEST(deviceInfoTest, XRPollingAction_ChangeFlagBehavior) { + int instanceNumber = 0; + hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); + ASSERT_NE(pIface, nullptr); + + HOSTIF_MsgData_t setMsg; + memset(&setMsg, 0, sizeof(setMsg)); + setMsg.reqType = HOSTIF_SET; + strncpy(setMsg.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_XRPolling.Action", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setMsg.paramtype = hostIf_StringType; + + strncpy(setMsg.paramValue, "XRPoll", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setMsg.paramLen = strlen(setMsg.paramValue); + EXPECT_EQ(pIface->set_Device_DeviceInfo_X_RDKCENTRAL_COM_XRPollingAction(&setMsg), OK); + + HOSTIF_MsgData_t getMsg; + memset(&getMsg, 0, sizeof(getMsg)); + bool changed = false; + EXPECT_EQ(pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_XRPollingAction(&getMsg, &changed), OK); + EXPECT_TRUE(changed); + EXPECT_STREQ(getMsg.paramValue, "XRPoll"); + + strncpy(setMsg.paramValue, "0", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setMsg.paramLen = strlen(setMsg.paramValue); + EXPECT_EQ(pIface->set_Device_DeviceInfo_X_RDKCENTRAL_COM_XRPollingAction(&setMsg), OK); + + memset(&getMsg, 0, sizeof(getMsg)); + changed = false; + EXPECT_EQ(pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_XRPollingAction(&getMsg, &changed), OK); + EXPECT_FALSE(changed); + EXPECT_STREQ(getMsg.paramValue, "0"); +} + TEST(deviceInfoTest, findLocalPortAvailable) { int instanceNumber = 0; @@ -3424,69 +3629,6 @@ TEST(deviceTest, set_xRDKCentralComRFC_RebootStopEnable_XRE_CONTAINER_RFC_ENABLE } } -TEST(deviceTest, RDKRemoteDebuggergetProfileData) -{ - int instanceNumber = 0; - bool pChanged; - HOSTIF_MsgData_t param = { 0 }; - memset(¶m,0,sizeof(HOSTIF_MsgData_t)); - param.reqType = HOSTIF_GET; - strncpy (param.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.getProfileData", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); - param.bsUpdate = HOSTIF_NONE; - param.requestor = HOSTIF_SRC_RFC; - - hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); - if(pIface) - { - int ret = pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggergetProfileData(¶m); - cout << "msgData.paramValue = " << param.paramValue << endl; - EXPECT_EQ(ret, OK); - } -} - -TEST(deviceTest, RDKRemoteDebuggergetProfileData_FileRemoved) -{ - std::remove("/etc/rrd/remote_debugger.json"); - int instanceNumber = 0; - bool pChanged; - HOSTIF_MsgData_t param = { 0 }; - memset(¶m,0,sizeof(HOSTIF_MsgData_t)); - param.reqType = HOSTIF_GET; - strncpy (param.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.getProfileData", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); - param.bsUpdate = HOSTIF_NONE; - param.requestor = HOSTIF_SRC_RFC; - - hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); - if(pIface) - { - int ret = pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggergetProfileData(¶m); - cout << "msgData.paramValue = " << param.paramValue << endl; - EXPECT_EQ(ret, NOK); - } -} - -TEST(deviceTest, RDKRemoteDebuggergetProfileData_EmptyFile) -{ - std::ofstream file("/etc/rrd/remote_debugger.json"); - file.close(); - int instanceNumber = 0; - bool pChanged; - HOSTIF_MsgData_t param = { 0 }; - memset(¶m,0,sizeof(HOSTIF_MsgData_t)); - param.reqType = HOSTIF_GET; - strncpy (param.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.getProfileData", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); - param.bsUpdate = HOSTIF_NONE; - param.requestor = HOSTIF_SRC_RFC; - - hostIf_DeviceInfo *pIface = hostIf_DeviceInfo::getInstance(instanceNumber); - if(pIface) - { - int ret = pIface->get_Device_DeviceInfo_X_RDKCENTRAL_COM_RDKRemoteDebuggergetProfileData(¶m); - cout << "msgData.paramValue = " << param.paramValue << endl; - EXPECT_EQ(ret, NOK); - } -} - TEST(deviceTest, set_xRDKCentralComRFCRoamTrigger) { int instanceNumber = 0; @@ -3954,6 +4096,11 @@ TEST(deviceInfoTest, GetLock_ShouldAcquireMutex) { } } +TEST(deviceInfoTest, ReleaseLock_WithoutOwnership_DoesNotCrash) { + hostIf_DeviceInfo::releaseLock(); + EXPECT_EQ(0, 0); +} + TEST(deviceTest, get_xOpsRPC_Profile_NOTIFICATION) { int instanceNumber = 0; @@ -4280,6 +4427,7 @@ TEST(deviceTest, xOpsDMUploadLogsNow) { int ret = pIface->get_xOpsDMUploadLogsNow(&msgData); cout << "msgData.paramValue = " << msgData.paramValue << endl; EXPECT_EQ(ret, OK); + EXPECT_EQ(get_boolean(msgData.paramValue), false); } } @@ -4344,6 +4492,18 @@ TEST(bsStoreTest, getRawValue_Empty) { EXPECT_EQ(value, ""); } +TEST(bsStoreTest, setRawValue) { + m_bsStore = XBSStore::getInstance(); + const string key = "Device.Time.NTPServer2"; + const string sameValue = "time1.com"; + + m_bsStore->m_initialUpdate = false; + bool ret = m_bsStore->setRawValue(key, sameValue, HOSTIF_SRC_RFC); + EXPECT_EQ(ret, true); + EXPECT_EQ(m_bsStore->getRawValue(key), sameValue); + EXPECT_EQ(XBSStore::xbsJournalInstance->getJournalSource(key), HOSTIF_SRC_RFC); +} + TEST(bsStoreTest, getValue) { m_bsStore = XBSStore::getInstance(); @@ -4397,6 +4557,35 @@ TEST(bsStoreTest, setValue_BS_CLEAR_DB_END) { EXPECT_EQ(ret, 0); } +TEST(bsStoreTest, overrideValue_NewParam_AllowsOverride) { + m_bsStore = XBSStore::getInstance(); + + HOSTIF_MsgData_t setParam = { 0 }; + memset(&setParam,0,sizeof(HOSTIF_MsgData_t)); + setParam.reqType = HOSTIF_SET; + strncpy(setParam.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.UnitTest.NewParam", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setParam.bsUpdate = HOSTIF_NONE; + setParam.requestor = HOSTIF_SRC_WEBPA; + + strncpy(setParam.paramValue, "unit_test_value", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + setParam.paramtype = hostIf_StringType; + setParam.paramLen = strlen(setParam.paramValue); + + int setRet = m_bsStore->overrideValue(&setParam); + EXPECT_EQ(setRet, fcNoFault); + + HOSTIF_MsgData_t getParam = { 0 }; + memset(&getParam,0,sizeof(HOSTIF_MsgData_t)); + getParam.reqType = HOSTIF_GET; + strncpy(getParam.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.UnitTest.NewParam", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + getParam.bsUpdate = HOSTIF_NONE; + getParam.requestor = HOSTIF_SRC_RFC; + + int getRet = m_bsStore->getValue(&getParam); + EXPECT_EQ(getRet, fcNoFault); + EXPECT_EQ(getStringValue(&getParam), "unit_test_value"); +} + TEST(bsStoreTest, createFile) { createFile("/tmp/bootstrap.txt"); EXPECT_EQ(0, 0); @@ -4461,6 +4650,18 @@ TEST(bsStoreJournalTest, getBuildTime) { EXPECT_EQ(value, "2025-05-27 06:39:24"); } +TEST(bsStoreJournalTest, getBuildTime_Version) { + m_bsStoreJournal = XBSStoreJournal::getInstance("/opt/secure/RFC/bootstrap.journal"); + + std::remove("/version.txt"); + EXPECT_EQ(m_bsStoreJournal->getBuildTime(), ""); + + write_on_file("/version.txt", "BUILD_TIME=\"2026-06-09 12:34:56\"\n"); + EXPECT_EQ(m_bsStoreJournal->getBuildTime(), "2026-06-09 12:34:56"); + + std::remove("/version.txt"); +} + TEST(bsStoreJournalTest, setJournalValue) { m_bsStoreJournal = XBSStoreJournal::getInstance("/opt/secure/RFC/bootstrap.journal"); const string key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.RDKRemoteDebugger.Enable"; @@ -4485,6 +4686,9 @@ TEST(bsStoreJournalTest, resetClearRfc) { } bool result = m_bsStoreJournal->resetClearRfc(key); EXPECT_EQ(result, true); + + EXPECT_EQ(m_bsStoreJournal->resetClearRfc(key), false); + EXPECT_EQ(m_bsStoreJournal->resetClearRfc("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.Missing"), false); } TEST(bsStoreJournalTest, removeRecord) { @@ -4513,14 +4717,25 @@ TEST(bsStoreJournalTest, clearRfcAndGetDefaultValue) { bool result = m_bsStoreJournal->clearRfcAndGetDefaultValue(key, defaultValue); EXPECT_EQ(result, true); EXPECT_EQ(defaultValue, "time.com"); + + EXPECT_EQ(m_bsStoreJournal->clearRfcAndGetDefaultValue(key, defaultValue), false); + EXPECT_EQ(m_bsStoreJournal->clearRfcAndGetDefaultValue("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.Missing", defaultValue), false); } TEST(bsStoreJournalTest, rfcUpdateStarted) { m_bsStoreJournal = XBSStoreJournal::getInstance("/opt/secure/RFC/bootstrap.journal"); - const string key = "Device.Time.NTPServer4"; + const string rfcKey = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.RfcUpdate"; + const string webpaKey = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.WebpaUpdate"; + + EXPECT_EQ(m_bsStoreJournal->setJournalValue(rfcKey, "true", HOSTIF_SRC_RFC), true); + EXPECT_EQ(m_bsStoreJournal->setJournalValue(webpaKey, "false", HOSTIF_SRC_WEBPA), true); bool result = m_bsStoreJournal->rfcUpdateStarted(); EXPECT_EQ(result, true); + + string defaultValue; + EXPECT_EQ(m_bsStoreJournal->clearRfcAndGetDefaultValue(rfcKey, defaultValue), true); + EXPECT_EQ(m_bsStoreJournal->clearRfcAndGetDefaultValue(webpaKey, defaultValue), false); } TEST(bsStoreJournalTest, rfcUpdateEnd) { @@ -4533,7 +4748,10 @@ TEST(bsStoreJournalTest, rfcUpdateEnd) { TEST(bsStoreJournalTest, constructor) { XBSStoreJournal* journalPtr = new XBSStoreJournal(); - EXPECT_EQ(0, 0); + EXPECT_EQ(journalPtr->m_initDone, false); + + XBSStoreJournal* journalWithFile = new XBSStoreJournal("/opt/secure/RFC/bootstrap.journal"); + EXPECT_EQ(journalWithFile->m_initDone, true); } TEST(bsStoreJournalTest, setJournalValue_New_Key) { @@ -4729,79 +4947,139 @@ TEST(rfcStorageTest, setRawValue) { } TEST(processTest, getNumOfProcessorEntries) { - int instanceNumber = 0; + hostIf_DeviceProcessorInterface::closeAllInstances(); + hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(0); + ASSERT_NE(processorIface, nullptr); - hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(instanceNumber); - if(processorIface) - { - unsigned int ret = processorIface->getNumOfProcessorEntries(); - EXPECT_EQ(ret, 4); - } + unsigned int ret = processorIface->getNumOfProcessorEntries(); + EXPECT_GE(ret, 1u); + + hostIf_DeviceProcessorInterface::closeAllInstances(); } TEST(processTest, get_Device_DeviceInfo_Processor_Architecture) { - int instanceNumber = 0; - + hostIf_DeviceProcessorInterface::closeAllInstances(); HOSTIF_MsgData_t msgData; memset(&msgData,0,sizeof(HOSTIF_MsgData_t)); - hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(instanceNumber); - if(processorIface) - { - int ret = processorIface->get_Device_DeviceInfo_Processor_Architecture(&msgData); - cout << "msgData.paramValue = " << msgData.paramValue << endl; - EXPECT_EQ(ret, OK); - EXPECT_STREQ(msgData.paramValue, "x86_64"); - } + hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(0); + ASSERT_NE(processorIface, nullptr); + + int ret = processorIface->get_Device_DeviceInfo_Processor_Architecture(&msgData); + cout << "msgData.paramValue = " << msgData.paramValue << endl; + EXPECT_EQ(ret, OK); + EXPECT_GT(strlen(msgData.paramValue), 0u); + + hostIf_DeviceProcessorInterface::closeAllInstances(); +} + +TEST(processTest, getInstance_ReusesObjectForSameId_AndRejectsOutOfRangeId) { + hostIf_DeviceProcessorInterface::closeAllInstances(); + hostIf_DeviceProcessorInterface *processorIface0 = hostIf_DeviceProcessorInterface::getInstance(0); + ASSERT_NE(processorIface0, nullptr); + + hostIf_DeviceProcessorInterface *sameProcessorIface = hostIf_DeviceProcessorInterface::getInstance(0); + EXPECT_EQ(processorIface0, sameProcessorIface); + + unsigned int totalEntries = hostIf_DeviceProcessorInterface::getNumOfProcessorEntries(); + hostIf_DeviceProcessorInterface *invalidIface = hostIf_DeviceProcessorInterface::getInstance(static_cast(totalEntries + 1)); + EXPECT_EQ(invalidIface, nullptr); + + hostIf_DeviceProcessorInterface::closeAllInstances(); +} + +TEST(processTest, getAllInstances_TracksLifecycleAcrossCreateAndClose) { + hostIf_DeviceProcessorInterface::closeAllInstances(); + + GList* emptyInstances = hostIf_DeviceProcessorInterface::getAllInstances(); + EXPECT_EQ(emptyInstances, nullptr); + + hostIf_DeviceProcessorInterface *processorIface0 = hostIf_DeviceProcessorInterface::getInstance(0); + ASSERT_NE(processorIface0, nullptr); + hostIf_DeviceProcessorInterface *processorIface1 = hostIf_DeviceProcessorInterface::getInstance(1); + ASSERT_NE(processorIface1, nullptr); + + GList* allInstances = hostIf_DeviceProcessorInterface::getAllInstances(); + ASSERT_NE(allInstances, nullptr); + EXPECT_EQ(g_list_length(allInstances), 2); + g_list_free(allInstances); + + hostIf_DeviceProcessorInterface::closeInstance(processorIface0); + GList* oneLeft = hostIf_DeviceProcessorInterface::getAllInstances(); + ASSERT_NE(oneLeft, nullptr); + EXPECT_EQ(g_list_length(oneLeft), 1); + g_list_free(oneLeft); + + hostIf_DeviceProcessorInterface::closeAllInstances(); + EXPECT_EQ(hostIf_DeviceProcessorInterface::getAllInstances(), nullptr); +} + +TEST(processTest, ProcessorArchitecture_ChangeFlagAcrossCalls) { + hostIf_DeviceProcessorInterface::closeAllInstances(); + hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(0); + ASSERT_NE(processorIface, nullptr); + + HOSTIF_MsgData_t firstRead; + memset(&firstRead, 0, sizeof(HOSTIF_MsgData_t)); + bool changed = true; + EXPECT_EQ(processorIface->get_Device_DeviceInfo_Processor_Architecture(&firstRead, &changed), OK); + EXPECT_TRUE(changed); + + hostIf_DeviceProcessorInterface::closeAllInstances(); +} + +TEST(processTest, closeInstance_HandlesNull) { + hostIf_DeviceProcessorInterface::closeInstance(nullptr); + EXPECT_EQ(0, 0); } TEST(processTest, Processor_Lock_ReleaseLock) { - int instanceNumber = 0; + hostIf_DeviceProcessorInterface::closeAllInstances(); + hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(0); + ASSERT_NE(processorIface, nullptr); - hostIf_DeviceProcessorInterface *processorIface = hostIf_DeviceProcessorInterface::getInstance(instanceNumber); - if(processorIface) - { - processorIface->getLock(); - processorIface->releaseLock(); - EXPECT_EQ(0, 0); - } - processorIface->closeInstance(processorIface); - processorIface->closeAllInstances(); + processorIface->getLock(); + processorIface->releaseLock(); + EXPECT_EQ(0, 0); + + hostIf_DeviceProcessorInterface::closeInstance(processorIface); + hostIf_DeviceProcessorInterface::closeAllInstances(); } TEST(processTest, getProcessStatusCPUUsage) { - int instanceNumber = 0; + hostIf_DeviceProcessStatusInterface::closeAllInstances(); + hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(0); + ASSERT_NE(processStatusIface, nullptr); - HOSTIF_MsgData_t msgData; - memset(&msgData,0,sizeof(HOSTIF_MsgData_t)); - hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(instanceNumber); - if(processStatusIface) - { - int ret = processStatusIface->getProcessStatusCPUUsage(); - EXPECT_EQ(0, 0); - } + int ret = processStatusIface->getProcessStatusCPUUsage(); + EXPECT_GE(ret, 0); + + hostIf_DeviceProcessStatusInterface::closeAllInstances(); } TEST(processTest, get_Device_DeviceInfo_ProcessStatus_CPUUsage) { - int instanceNumber = 0; - bool pChanged; - + hostIf_DeviceProcessStatusInterface::closeAllInstances(); HOSTIF_MsgData_t msgData; memset(&msgData,0,sizeof(HOSTIF_MsgData_t)); - hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(instanceNumber); - if(processStatusIface) - { - pChanged = false; - int ret = processStatusIface->get_Device_DeviceInfo_ProcessStatus_CPUUsage(&msgData, &pChanged); - EXPECT_EQ(ret, OK); - } + hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(0); + ASSERT_NE(processStatusIface, nullptr); + + bool pChanged = false; + int ret = processStatusIface->get_Device_DeviceInfo_ProcessStatus_CPUUsage(&msgData, &pChanged); + EXPECT_EQ(ret, OK); + EXPECT_EQ(msgData.paramtype, hostIf_IntegerType); + EXPECT_FALSE(pChanged); + + HOSTIF_MsgData_t secondRead; + memset(&secondRead, 0, sizeof(HOSTIF_MsgData_t)); + bool secondChanged = false; + EXPECT_EQ(processStatusIface->get_Device_DeviceInfo_ProcessStatus_CPUUsage(&secondRead, &secondChanged), OK); + + hostIf_DeviceProcessStatusInterface::closeAllInstances(); } TEST(processTest, getProcessStatParam) { - int instanceNumber = 0; - bool pChanged; - long long unsigned int mUser = 0; long long unsigned int mNice = 0; long long unsigned int mSystem = 0; @@ -4810,34 +5088,201 @@ TEST(processTest, getProcessStatParam) { long long unsigned int mIrq = 0; long long unsigned int mSoftirq = 0; - HOSTIF_MsgData_t msgData; - memset(&msgData,0,sizeof(HOSTIF_MsgData_t)); - hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(instanceNumber); - if(processStatusIface) - { - pChanged = false; - int ret = processStatusIface->getProcessStatParam(&mUser, &mNice, &mSystem, &mIdle, &mIOwait, &mIrq, &mSoftirq); - EXPECT_EQ(ret, OK); - } + hostIf_DeviceProcessStatusInterface::closeAllInstances(); + hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(0); + ASSERT_NE(processStatusIface, nullptr); + + int ret = processStatusIface->getProcessStatParam(&mUser, &mNice, &mSystem, &mIdle, &mIOwait, &mIrq, &mSoftirq); + EXPECT_EQ(ret, OK); + EXPECT_GT(mUser + mNice + mSystem + mIdle + mIOwait + mIrq + mSoftirq, 0u); + + hostIf_DeviceProcessStatusInterface::closeAllInstances(); +} + +TEST(processTest, ProcessStatus_InstanceLifecycleAndList) { + hostIf_DeviceProcessStatusInterface::closeAllInstances(); + + EXPECT_EQ(hostIf_DeviceProcessStatusInterface::getAllInstances(), nullptr); + + hostIf_DeviceProcessStatusInterface *first = hostIf_DeviceProcessStatusInterface::getInstance(0); + ASSERT_NE(first, nullptr); + hostIf_DeviceProcessStatusInterface *same = hostIf_DeviceProcessStatusInterface::getInstance(0); + EXPECT_EQ(first, same); + hostIf_DeviceProcessStatusInterface *second = hostIf_DeviceProcessStatusInterface::getInstance(1); + ASSERT_NE(second, nullptr); + + GList* allInstances = hostIf_DeviceProcessStatusInterface::getAllInstances(); + ASSERT_NE(allInstances, nullptr); + EXPECT_EQ(g_list_length(allInstances), 2); + g_list_free(allInstances); + + hostIf_DeviceProcessStatusInterface::closeInstance(first); + GList* oneLeft = hostIf_DeviceProcessStatusInterface::getAllInstances(); + ASSERT_NE(oneLeft, nullptr); + EXPECT_EQ(g_list_length(oneLeft), 1); + g_list_free(oneLeft); + + hostIf_DeviceProcessStatusInterface::closeInstance(nullptr); + hostIf_DeviceProcessStatusInterface::closeAllInstances(); + EXPECT_EQ(hostIf_DeviceProcessStatusInterface::getAllInstances(), nullptr); } TEST(processTest, ProcessStatus_Lock_ReleaseLock) { - int instanceNumber = 0; - bool pChanged; + hostIf_DeviceProcessStatusInterface::closeAllInstances(); + hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(0); + ASSERT_NE(processStatusIface, nullptr); + + processStatusIface->getLock(); + processStatusIface->releaseLock(); + EXPECT_EQ(0, 0); + + hostIf_DeviceProcessStatusInterface::closeInstance(processStatusIface); + hostIf_DeviceProcessStatusInterface::closeAllInstances(); +} + + +TEST(bsStoreJournalTest, getUpdatedSourceString_AndGetJournalSourceMissing) { + m_bsStoreJournal = XBSStoreJournal::getInstance("/opt/secure/RFC/bootstrap.journal"); + EXPECT_EQ(m_bsStoreJournal->getUpdatedSourceString(HOSTIF_SRC_RFC), "rfc"); + EXPECT_EQ(m_bsStoreJournal->getUpdatedSourceString(HOSTIF_SRC_WEBPA), "webpa"); + EXPECT_EQ(m_bsStoreJournal->getUpdatedSourceString(HOSTIF_NONE), "-"); + EXPECT_EQ(m_bsStoreJournal->getJournalSource("Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Missing.Param"), HOSTIF_NONE); +} + +TEST(bsStoreJournalTest, setInitialUpdate_AndGetJournalSourceExisting) { + m_bsStoreJournal = XBSStoreJournal::getInstance("/opt/secure/RFC/bootstrap.journal"); + m_bsStoreJournal->setInitialUpdate(true); + + const string key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.BSJournal"; + EXPECT_EQ(m_bsStoreJournal->setJournalValue(key, "true", HOSTIF_SRC_WEBPA), true); + EXPECT_EQ(m_bsStoreJournal->getJournalSource(key), HOSTIF_SRC_WEBPA); + + m_bsStoreJournal->setInitialUpdate(false); +} + +/* TEST(bsStoreJournalTest, resetCacheAndStore_RemovesCacheAndAllowsReuse) { + m_bsStoreJournal = XBSStoreJournal::getInstance("/opt/secure/RFC/bootstrap.journal"); + const string key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.ResetCache"; + + EXPECT_EQ(m_bsStoreJournal->setJournalValue(key, "true", HOSTIF_SRC_WEBPA), true); + EXPECT_NE(m_bsStoreJournal->getJournalSource(key), HOSTIF_NONE); + + m_bsStoreJournal->resetCacheAndStore(); + EXPECT_EQ(m_bsStoreJournal->getJournalSource(key), HOSTIF_NONE); + + EXPECT_EQ(m_bsStoreJournal->setJournalValue(key, "false", HOSTIF_SRC_WEBPA), true); + EXPECT_EQ(m_bsStoreJournal->getJournalSource(key), HOSTIF_SRC_WEBPA); +} + +*/ + +TEST(bsStoreTest, stop_And_call_loadJson) { + m_bsStore = XBSStore::getInstance(); + bool loaded = m_bsStore->call_loadJson(); + EXPECT_EQ(loaded, true); + m_bsStore->stop(); +} + +TEST(rfcStoreTest, setValue_ClearParam_Path) { + m_rfcStore = XRFCStore::getInstance(); HOSTIF_MsgData_t msgData; - memset(&msgData,0,sizeof(HOSTIF_MsgData_t)); - hostIf_DeviceProcessStatusInterface *processStatusIface = hostIf_DeviceProcessStatusInterface::getInstance(instanceNumber); - if(processStatusIface) - { - pChanged = false; - processStatusIface->getLock(); - processStatusIface->releaseLock(); - EXPECT_EQ(0, 0); - } - processStatusIface->closeInstance(processStatusIface); - processStatusIface->closeAllInstances(); + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + msgData.reqType = HOSTIF_SET; + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.ClearParam", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + strncpy(msgData.paramValue, "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Unknown.Param", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + msgData.requestor = HOSTIF_SRC_WEBPA; + + faultCode_t ret = m_rfcStore->setValue(&msgData); + EXPECT_EQ(ret, fcNoFault); +} + +TEST(rfcStoreTest, clearAllAndReloadCache_DuplicateSafe) { + m_rfcStore = XRFCStore::getInstance(); + m_rfcStore->clearAll(); + m_rfcStore->clearAll(); + + m_rfcStore->reloadCache(); + m_rfcStore->reloadCache(); + EXPECT_EQ(0, 0); +} + +TEST(rfcStorageTest, setRawValue_And_clearAll) { + const string key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.UnitTest.Temp"; + EXPECT_EQ(m_rfcStoreage->setRawValue(key, "true"), true); + EXPECT_EQ(m_rfcStoreage->getRawValue(key), "true"); + + m_rfcStoreage->clearAll(); + EXPECT_EQ(m_rfcStoreage->getRawValue(key), ""); +} + +#ifdef USE_XRDK_BT_PROFILE +TEST(blueToothTest, singletonResetAndClose) { + hostIf_DeviceInfoRdk_xBT *btIface = hostIf_DeviceInfoRdk_xBT::getInstance(); + ASSERT_NE(btIface, nullptr); + hostIf_DeviceInfoRdk_xBT::reset(); + hostIf_DeviceInfoRdk_xBT::closeInstance(); +} + +TEST(blueToothTest, handleSetMsg_InvalidPath_ReturnsNotHandled) { + hostIf_DeviceInfoRdk_xBT *btIface = hostIf_DeviceInfoRdk_xBT::getInstance(); + ASSERT_NE(btIface, nullptr); + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_Invalid.enable", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + + int ret = btIface->handleSetMsg(&msgData); + EXPECT_EQ(ret, NOT_HANDLED); + EXPECT_EQ(msgData.faultCode, fcInvalidParameterName); + + hostIf_DeviceInfoRdk_xBT::closeInstance(); +} + +TEST(blueToothTest, handleSetMsg_UnknownUnderRoot_ReturnsNotHandled) { + hostIf_DeviceInfoRdk_xBT *btIface = hostIf_DeviceInfoRdk_xBT::getInstance(); + ASSERT_NE(btIface, nullptr); + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_xBlueTooth.UnknownParam", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + + int ret = btIface->handleSetMsg(&msgData); + EXPECT_EQ(ret, NOT_HANDLED); + EXPECT_EQ(msgData.faultCode, fcInvalidParameterName); + + hostIf_DeviceInfoRdk_xBT::closeInstance(); +} + +TEST(blueToothTest, handleGetMsg_InvalidPath_ReturnsNotHandled) { + hostIf_DeviceInfoRdk_xBT *btIface = hostIf_DeviceInfoRdk_xBT::getInstance(); + ASSERT_NE(btIface, nullptr); + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_Invalid.DiscoveryEnabled", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + + int ret = btIface->handleGetMsg(&msgData); + EXPECT_EQ(ret, NOT_HANDLED); + + hostIf_DeviceInfoRdk_xBT::closeInstance(); +} + +TEST(blueToothTest, handleGetMsg_UnknownUnderRoot_ReturnsNok) { + hostIf_DeviceInfoRdk_xBT *btIface = hostIf_DeviceInfoRdk_xBT::getInstance(); + ASSERT_NE(btIface, nullptr); + + HOSTIF_MsgData_t msgData; + memset(&msgData, 0, sizeof(HOSTIF_MsgData_t)); + strncpy(msgData.paramName, "Device.DeviceInfo.X_RDKCENTRAL-COM_xBlueTooth.UnknownParam", TR69HOSTIFMGR_MAX_PARAM_LEN - 1); + + int ret = btIface->handleGetMsg(&msgData); + EXPECT_EQ(ret, NOK); + EXPECT_EQ(msgData.faultCode, fcInvalidParameterName); + + hostIf_DeviceInfoRdk_xBT::closeInstance(); } +#endif TEST(clearTest, rfcclearAll) { @@ -4864,6 +5309,19 @@ TEST(StoreClearTest, resetCacheAndStore) { EXPECT_EQ(0, 0); } +TEST(StoreClearTest, setRawValue_Flush) { + m_bsStore = XBSStore::getInstance(); + const string key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Bootstrap.UnitTest.Flush"; + const string value = "flush_path_value"; + + m_bsStore->m_initialUpdate = true; + bool ret = m_bsStore->setRawValue(key, value, HOSTIF_SRC_DEFAULT); + m_bsStore->m_initialUpdate = false; + + EXPECT_EQ(ret, true); + EXPECT_EQ(m_bsStore->getRawValue(key), value); +} + /* TEST(StoreClearTest, init) { std::remove("/opt/secure/RFC/tr181store.ini"); std::ofstream file("/opt/secure/RFC/tr181store.ini"); diff --git a/src/hostif/profiles/Ethernet/gtest/gtest_ethernet.cpp b/src/hostif/profiles/Ethernet/gtest/gtest_ethernet.cpp index 28a6bcb8e..441246a6d 100644 --- a/src/hostif/profiles/Ethernet/gtest/gtest_ethernet.cpp +++ b/src/hostif/profiles/Ethernet/gtest/gtest_ethernet.cpp @@ -421,6 +421,86 @@ TEST(EthernetTest, Lock_ReleaseLock) { ethernetIfStats->closeAllInstances(); } +TEST(EthernetTest, get_Device_Ethernet_Interface_LastChange_NotImplemented) { + int instanceNumber = 1; + bool pChanged = false; + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + + hostIf_EthernetInterface *ethernetIf = hostIf_EthernetInterface::getInstance(instanceNumber); + ASSERT_NE(ethernetIf, nullptr); + EXPECT_EQ(ethernetIf->get_Device_Ethernet_Interface_LastChange(¶m, &pChanged), NOK); +} + +TEST(EthernetTest, get_Device_Ethernet_Interface_LowerLayers_NotImplemented) { + int instanceNumber = 1; + bool pChanged = false; + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + + hostIf_EthernetInterface *ethernetIf = hostIf_EthernetInterface::getInstance(instanceNumber); + ASSERT_NE(ethernetIf, nullptr); + EXPECT_EQ(ethernetIf->get_Device_Ethernet_Interface_LowerLayers(¶m, &pChanged), NOK); +} + +TEST(EthernetTest, set_Device_Ethernet_Interface_NotImplementedSetters) { + int instanceNumber = 1; + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + + hostIf_EthernetInterface *ethernetIf = hostIf_EthernetInterface::getInstance(instanceNumber); + ASSERT_NE(ethernetIf, nullptr); + EXPECT_EQ(ethernetIf->set_Device_Ethernet_Interface_Alias(¶m), NOK); + EXPECT_EQ(ethernetIf->set_Device_Ethernet_Interface_LowerLayers(¶m), NOK); + EXPECT_EQ(ethernetIf->set_Device_Ethernet_Interface_MaxBitRate(¶m), NOK); + EXPECT_EQ(ethernetIf->set_Device_Ethernet_Interface_DuplexMode(¶m), NOK); +} + +TEST(EthernetTest, InterfaceNotifyHash_CreateAndReuse) { + GHashTable *hash1 = hostIf_EthernetInterface::getNotifyHash(); + GHashTable *hash2 = hostIf_EthernetInterface::getNotifyHash(); + + EXPECT_NE(hash1, nullptr); + EXPECT_EQ(hash1, hash2); +} + +TEST(EthernetTest, InterfaceAndStatsCloseInstance_NullSafe) { + hostIf_EthernetInterface::closeInstance(nullptr); + hostIf_EthernetInterfaceStats::closeInstance(nullptr); + SUCCEED(); +} + +TEST(EthernetTest, InterfaceAndStatsGetAllInstances_NotNullAfterCreate) { + hostIf_EthernetInterface *ethernetIf = hostIf_EthernetInterface::getInstance(100); + hostIf_EthernetInterfaceStats *ethernetIfStats = hostIf_EthernetInterfaceStats::getInstance(100); + + ASSERT_NE(ethernetIf, nullptr); + ASSERT_NE(ethernetIfStats, nullptr); + EXPECT_NE(hostIf_EthernetInterface::getAllInstances(), nullptr); + EXPECT_NE(hostIf_EthernetInterfaceStats::getAllInstances(), nullptr); +} + +TEST(EthernetTest, StatsBytesSent_SecondCallWithChangedPointer) { + int instanceNumber = 1; + bool pChanged = false; + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + + hostIf_EthernetInterfaceStats *ethernetIfStats = hostIf_EthernetInterfaceStats::getInstance(instanceNumber); + ASSERT_NE(ethernetIfStats, nullptr); + + EXPECT_EQ(ethernetIfStats->get_Device_Ethernet_Interface_Stats_BytesSent(¶m, &pChanged), OK); + EXPECT_EQ(ethernetIfStats->get_Device_Ethernet_Interface_Stats_BytesSent(¶m, &pChanged), OK); + EXPECT_EQ(param.paramtype, hostIf_UnsignedLongType); + EXPECT_EQ(param.paramLen, 4); +} + +TEST(EthernetTest, StatsCloseAllInstances_Idempotent) { + hostIf_EthernetInterfaceStats::closeAllInstances(); + hostIf_EthernetInterfaceStats::closeAllInstances(); + SUCCEED(); +} + GTEST_API_ int main(int argc, char *argv[]){ char testresults_fullfilepath[GTEST_REPORT_FILEPATH_SIZE]; char buffer[GTEST_REPORT_FILEPATH_SIZE]; diff --git a/src/hostif/profiles/Time/gtest/gtest_time.cpp b/src/hostif/profiles/Time/gtest/gtest_time.cpp index a00b10974..2c33e177b 100644 --- a/src/hostif/profiles/Time/gtest/gtest_time.cpp +++ b/src/hostif/profiles/Time/gtest/gtest_time.cpp @@ -357,7 +357,7 @@ TEST(TimeTest, get_Device_Time_NTPServerSettings_DefaultValue) int ret = pIface->get_Device_Time_NTPServerSettings(¶m); EXPECT_EQ(ret, OK); EXPECT_EQ(param.paramtype, hostIf_StringType); - EXPECT_STREQ(param.paramValue, "server,0,false,10,12"); + EXPECT_STREQ(param.paramValue, "pool,4,true,10,12"); } } @@ -656,6 +656,47 @@ TEST(TimeTest, set_Device_Time_NTPServerSettings_MissingFields) } } +TEST(TimeTest, get_Device_Time_NotImplemented_Getters_ReturnNOK) +{ + int instanceNumber = 0; + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + bool pChanged = false; + + hostIf_Time *pIface = hostIf_Time::getInstance(instanceNumber); + ASSERT_NE(pIface, nullptr); + + EXPECT_EQ(pIface->get_Device_Time_Enable(¶m, &pChanged), NOK); + EXPECT_EQ(pIface->get_Device_Time_Status(¶m, &pChanged), NOK); + EXPECT_EQ(pIface->get_Device_Time_NTPServer1(¶m, &pChanged), NOK); + EXPECT_EQ(pIface->get_Device_Time_NTPServer2(¶m, &pChanged), NOK); + EXPECT_EQ(pIface->get_Device_Time_NTPServer3(¶m, &pChanged), NOK); + EXPECT_EQ(pIface->get_Device_Time_NTPServer4(¶m, &pChanged), NOK); + EXPECT_EQ(pIface->get_Device_Time_NTPServer5(¶m, &pChanged), NOK); +} + +TEST(TimeTest, set_Device_Time_NotImplemented_Setters_ReturnNOK) +{ + int instanceNumber = 0; + HOSTIF_MsgData_t param = { 0 }; + memset(¶m, 0, sizeof(HOSTIF_MsgData_t)); + bool pChanged = false; + + hostIf_Time *pIface = hostIf_Time::getInstance(instanceNumber); + ASSERT_NE(pIface, nullptr); + + EXPECT_EQ(pIface->set_Device_Time_Enable(¶m), NOK); + EXPECT_EQ(pIface->set_Device_Time_NTPServer1(¶m), NOK); + EXPECT_EQ(pIface->set_Device_Time_NTPServer2(¶m), NOK); + EXPECT_EQ(pIface->set_Device_Time_NTPServer3(¶m), NOK); + EXPECT_EQ(pIface->set_Device_Time_NTPServer4(¶m), NOK); + EXPECT_EQ(pIface->set_Device_Time_NTPServer5(¶m), NOK); + EXPECT_EQ(pIface->set_Device_Time_LocalTimeZone(¶m), NOK); + + EXPECT_EQ(pChanged, false); +} + + GTEST_API_ int main(int argc, char *argv[]){ char testresults_fullfilepath[GTEST_REPORT_FILEPATH_SIZE]; char buffer[GTEST_REPORT_FILEPATH_SIZE]; diff --git a/src/hostif/src/gtest/gtest_src.cpp b/src/hostif/src/gtest/gtest_src.cpp index 9d9a22981..989cbff9f 100644 --- a/src/hostif/src/gtest/gtest_src.cpp +++ b/src/hostif/src/gtest/gtest_src.cpp @@ -618,6 +618,120 @@ TEST(srcTest, readThunderArrayItemByKeyBoolWrongType) EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", "type", "WIFI", "enabled", value)); } +TEST(srcTest, iniFileLoadQuotedFilenameAndDefaultValue) +{ + const char* filePath = "/tmp/hostif_ini_quoted.ini"; + FILE* fp = fopen(filePath, "w"); + ASSERT_NE(fp, nullptr); + fputs("A=B\n", fp); + fclose(fp); + + IniFile ini; + std::string quotedPath = "\"" + std::string(filePath) + "\""; + EXPECT_TRUE(ini.load(quotedPath)); + EXPECT_EQ(ini.value("A", "X"), "B"); + EXPECT_EQ(ini.value("MissingKey", "DefaultV"), "DefaultV"); + + remove(filePath); +} + +TEST(srcTest, iniFileClearFlushesEmptyContent) +{ + const char* filePath = "/tmp/hostif_ini_clear.ini"; + FILE* fp = fopen(filePath, "w"); + ASSERT_NE(fp, nullptr); + fputs("A=B\n", fp); + fclose(fp); + + IniFile ini; + ASSERT_TRUE(ini.load(filePath)); + EXPECT_TRUE(ini.clear()); + + fp = fopen(filePath, "r"); + ASSERT_NE(fp, nullptr); + int ch = fgetc(fp); + fclose(fp); + EXPECT_EQ(ch, EOF); + + remove(filePath); +} + +TEST(srcTest, getenvOrDefaultReturnsDefaultWhenUnset) +{ + const char* envName = "TEST_ENV_VAR_FOR_DEFAULT"; + unsetenv(envName); + char* result = getenvOrDefault(envName, "fallback"); + ASSERT_NE(result, nullptr); + EXPECT_STREQ(result, "fallback"); +} + +TEST(srcTest, matchComponentInvalidPaths) +{ + const char* setting = nullptr; + int instance = 0; + + EXPECT_FALSE(matchComponent("Device.WiFi.SSID", "Device.WiFi.SSID", &setting, instance)); + EXPECT_FALSE(matchComponent("Device.WiFi.SSID.12345678901.SSID", "Device.WiFi.SSID", &setting, instance)); +} + +TEST(srcTest, thunderFieldExtractorsRejectNullFieldName) +{ + std::string strVal; + int numVal = 0; + bool boolVal = false; + unsigned long ulongVal = 0; + + EXPECT_FALSE(thunderExtractResultStringField("{\"result\":{\"a\":\"b\"}}", nullptr, strVal)); + EXPECT_FALSE(thunderExtractResultNumberField("{\"result\":{\"a\":1}}", nullptr, numVal)); + EXPECT_FALSE(thunderExtractResultBoolField("{\"result\":{\"a\":true}}", nullptr, boolVal)); + EXPECT_FALSE(thunderExtractResultULongField("{\"result\":{\"a\":10}}", nullptr, ulongVal)); +} + +TEST(srcTest, extractThunderStringArrayAsDelimitedStringEmptyArray) +{ + cJSON* arrayObj = cJSON_Parse("[]"); + ASSERT_NE(arrayObj, nullptr); + + std::string value = "seed"; + EXPECT_TRUE(extractThunderStringArrayAsDelimitedString(arrayObj, ",", value)); + EXPECT_TRUE(value.empty()); + + cJSON_Delete(arrayObj); +} + +TEST(srcTest, thunderArrayReadersRejectNullInputs) +{ + std::string s; + bool b = false; + const std::string response = "{\"result\":{\"interfaces\":[]}}"; + + EXPECT_FALSE(readThunderArrayItemByKey(response, nullptr, "k", "v", "f", s)); + EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", nullptr, "v", "f", s)); + EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", "k", nullptr, "f", s)); + EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", "k", "v", nullptr, s)); + + EXPECT_FALSE(readThunderArrayItemByKey(response, nullptr, "k", "v", "f", b)); + EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", nullptr, "v", "f", b)); + EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", "k", nullptr, "f", b)); + EXPECT_FALSE(readThunderArrayItemByKey(response, "interfaces", "k", "v", nullptr, b)); +} + +TEST(srcTest, thunderInvokeHelpersFailForEmptyMethod) +{ + std::string sValue; + int nValue = 0; + bool bValue = false; + unsigned long ulValue = 0; + + EXPECT_FALSE(invokeThunderPluginMethodAndExtractStringField("", "", "field", sValue)); + EXPECT_FALSE(invokeThunderPluginMethodAndExtractNumberField("", "", "field", nValue)); + EXPECT_FALSE(invokeThunderPluginMethodAndExtractBoolField("", "", "field", bValue)); + EXPECT_FALSE(invokeThunderPluginMethodAndExtractULongField("", "", "field", ulValue)); + EXPECT_FALSE(invokeThunderPluginMethodAndExtractDelimitedStringArrayField("", "", "field", ",", sValue)); + EXPECT_FALSE(invokeThunderPluginMethodAndExtractScalarStringResult("", "", sValue)); +} + + GTEST_API_ int main(int argc, char *argv[]){ char testresults_fullfilepath[GTEST_REPORT_FILEPATH_SIZE]; char buffer[GTEST_REPORT_FILEPATH_SIZE]; diff --git a/src/unittest/stubs/file_writer.cpp b/src/unittest/stubs/file_writer.cpp index 7f064b656..bd8d41ef7 100644 --- a/src/unittest/stubs/file_writer.cpp +++ b/src/unittest/stubs/file_writer.cpp @@ -51,7 +51,7 @@ void writeToTr181storeFile(const std::string& key, const std::string& value, con void write_on_file(const std::string& filePath, const std::string& data) { - std::ofstream outfile(filePath, std::ios::app); + std::ofstream outfile(filePath, std::ios::out | std::ios::trunc); if (outfile.is_open()) { std::cout << "File Open" << std::endl; outfile << data ; diff --git a/src/unittest/stubs/wdmp-c.h b/src/unittest/stubs/wdmp-c.h index 7a540f19a..6e0294c55 100644 --- a/src/unittest/stubs/wdmp-c.h +++ b/src/unittest/stubs/wdmp-c.h @@ -19,6 +19,10 @@ #ifndef __WDMP_C_H__ #define __WDMP_C_H__ +#ifdef __cplusplus +extern "C" { +#endif + #include #include @@ -286,4 +290,8 @@ void mapWdmpStatusToStatusMessage(WDMP_STATUS status, char *result); /*----------------------------------------------------------------------------*/ /* none */ +#ifdef __cplusplus +} +#endif + #endif From 5c1b2009363397bcc8efa26f1a2d9a5c2bdab653 Mon Sep 17 00:00:00 2001 From: nhanasi Date: Fri, 12 Jun 2026 13:40:02 -0400 Subject: [PATCH 12/13] Integrate Openspec skills for TR69 (#488) * Integrate Openspec skills for TR69 * Update LICENSE * Update NOTICE * Update NOTICE * Update LICENSE * Update LICENSE * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Hanasi Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/prompts/opsx-apply.prompt.md | 149 +++++++++ .github/prompts/opsx-archive.prompt.md | 154 ++++++++++ .github/prompts/opsx-explore.prompt.md | 170 +++++++++++ .github/prompts/opsx-propose.prompt.md | 103 +++++++ .github/skills/openspec-apply-change/SKILL.md | 156 ++++++++++ .../skills/openspec-archive-change/SKILL.md | 114 +++++++ .github/skills/openspec-explore/SKILL.md | 288 ++++++++++++++++++ .github/skills/openspec-propose/SKILL.md | 110 +++++++ LICENSE | 22 ++ NOTICE | 4 + openspec/config.yaml | 20 ++ 11 files changed, 1290 insertions(+) create mode 100644 .github/prompts/opsx-apply.prompt.md create mode 100644 .github/prompts/opsx-archive.prompt.md create mode 100644 .github/prompts/opsx-explore.prompt.md create mode 100644 .github/prompts/opsx-propose.prompt.md create mode 100644 .github/skills/openspec-apply-change/SKILL.md create mode 100644 .github/skills/openspec-archive-change/SKILL.md create mode 100644 .github/skills/openspec-explore/SKILL.md create mode 100644 .github/skills/openspec-propose/SKILL.md create mode 100644 openspec/config.yaml diff --git a/.github/prompts/opsx-apply.prompt.md b/.github/prompts/opsx-apply.prompt.md new file mode 100644 index 000000000..e23ec64d1 --- /dev/null +++ b/.github/prompts/opsx-apply.prompt.md @@ -0,0 +1,149 @@ +--- +description: Implement tasks from an OpenSpec change (Experimental) +--- + +Implement tasks from an OpenSpec change. + +**Input**: Optionally specify a change name (e.g., `/opsx:apply add-auth`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. + +**Steps** + +1. **Select the change** + + If a name is provided, use it. Otherwise: + - Infer from conversation context if the user mentioned a change + - Auto-select if only one active change exists + - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select + + Always announce: "Using change: " and how to override (e.g., `/opsx:apply `). + +2. **Check status to understand the schema** + ```bash + openspec status --change "" --json + ``` + Parse the JSON to understand: + - `schemaName`: The workflow being used (e.g., "spec-driven") + - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) + +3. **Get apply instructions** + + ```bash + openspec instructions apply --change "" --json + ``` + + This returns: + - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema) + - Progress (total, complete, remaining) + - Task list with status + - Dynamic instruction based on current state + + **Handle states:** + - If `state: "blocked"` (missing artifacts): show message, suggest using `/opsx:continue` + - If `state: "all_done"`: congratulate, suggest archive + - Otherwise: proceed to implementation + +4. **Read context files** + + Read every file path listed under `contextFiles` from the apply instructions output. + The files depend on the schema being used: + - **spec-driven**: proposal, specs, design, tasks + - Other schemas: follow the contextFiles from CLI output + +5. **Show current progress** + + Display: + - Schema being used + - Progress: "N/M tasks complete" + - Remaining tasks overview + - Dynamic instruction from CLI + +6. **Implement tasks (loop until done or blocked)** + + For each pending task: + - Show which task is being worked on + - Make the code changes required + - Keep changes minimal and focused + - Mark task complete in the tasks file: `- [ ]` → `- [x]` + - Continue to next task + + **Pause if:** + - Task is unclear → ask for clarification + - Implementation reveals a design issue → suggest updating artifacts + - Error or blocker encountered → report and wait for guidance + - User interrupts + +7. **On completion or pause, show status** + + Display: + - Tasks completed this session + - Overall progress: "N/M tasks complete" + - If all done: suggest archive + - If paused: explain why and wait for guidance + +**Output During Implementation** + +``` +## Implementing: (schema: ) + +Working on task 3/7: +[...implementation happening...] +✓ Task complete + +Working on task 4/7: +[...implementation happening...] +✓ Task complete +``` + +**Output On Completion** + +``` +## Implementation Complete + +**Change:** +**Schema:** +**Progress:** 7/7 tasks complete ✓ + +### Completed This Session +- [x] Task 1 +- [x] Task 2 +... + +All tasks complete! You can archive this change with `/opsx:archive`. +``` + +**Output On Pause (Issue Encountered)** + +``` +## Implementation Paused + +**Change:** +**Schema:** +**Progress:** 4/7 tasks complete + +### Issue Encountered + + +**Options:** +1. - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2919,31 +2892,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2964,80 +2912,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -