From e6d912a6f3cefeb1669402c2974e168d8775426b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:08:16 +0000 Subject: [PATCH 01/14] Fix zone NULL/uninitialized issues in timezone fallback reader - Validate ftell return: reject -1 (error) and 0 (empty file) - Add malloc NULL check to prevent NULL pointer dereference - Initialize zone buffer to empty string before fscanf - Reset zone after each iteration to catch stale data - Check fscanf return == 1 instead of != EOF to catch format errors and whitespace-only files - Remove impossible 'zone != NULL' check (zone is stack-local pointer to heap memory, never NULL inside the loop) - Don't reset zoneValue to NULL on empty reads (preserve any previously read valid value) Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/45c3e1dc-dc54-4005-8756-3a32aa7fdeef Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- source/xconf-client/xconfclient.c | 51 ++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/source/xconf-client/xconfclient.c b/source/xconf-client/xconfclient.c index 788ce80e..bcda2c48 100644 --- a/source/xconf-client/xconfclient.c +++ b/source/xconf-client/xconfclient.c @@ -264,30 +264,47 @@ static char *getTimezone () { fseek(file, 0, SEEK_END); long numbytes = ftell(file); - char *zone = (char*)malloc(sizeof(char) * (numbytes + 1)); - fseek(file, 0, SEEK_SET); - - char fmt[32]; - snprintf(fmt, sizeof(fmt), "%%%lds", numbytes); //using numbytes as the length for reading the file - - while (fscanf(file, fmt, zone) != EOF) + if (numbytes <= 0) { - if(zoneValue) - { - free(zoneValue); - } - if (zone != NULL && strlen(zone) > 0) + T2Warning("Warning: timeZoneDST file is empty or unreadable (ftell returned %ld)\n", numbytes); + fclose(file); + } + else + { + char *zone = (char*)malloc(sizeof(char) * (numbytes + 1)); + if (zone == NULL) { - zoneValue = strdup(zone); + T2Error("Failed to allocate %ld bytes for timezone\n", numbytes + 1); + fclose(file); } else { - zoneValue = NULL; - T2Warning("Warning: zone is NULL or empty, skipping\n"); + zone[0] = '\0'; + fseek(file, 0, SEEK_SET); + + char fmt[32]; + snprintf(fmt, sizeof(fmt), "%%%lds", numbytes); + + while (fscanf(file, fmt, zone) == 1) + { + if (strlen(zone) > 0) + { + if(zoneValue) + { + free(zoneValue); + } + zoneValue = strdup(zone); + } + else + { + T2Warning("Warning: zone is empty, skipping\n"); + } + zone[0] = '\0'; + } + fclose(file); + free(zone); } } - fclose(file); - free(zone); } } From 134706cd20475686cfb11bc08bd08028a1df502e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:09:49 +0000 Subject: [PATCH 02/14] Address code review: separate error/empty checks, add size upper bound, remove redundant reset Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/45c3e1dc-dc54-4005-8756-3a32aa7fdeef Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- source/xconf-client/xconfclient.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/xconf-client/xconfclient.c b/source/xconf-client/xconfclient.c index bcda2c48..eceb27d5 100644 --- a/source/xconf-client/xconfclient.c +++ b/source/xconf-client/xconfclient.c @@ -264,9 +264,14 @@ static char *getTimezone () { fseek(file, 0, SEEK_END); long numbytes = ftell(file); - if (numbytes <= 0) + if (numbytes < 0) { - T2Warning("Warning: timeZoneDST file is empty or unreadable (ftell returned %ld)\n", numbytes); + T2Warning("Warning: timeZoneDST file is unreadable (ftell returned %ld)\n", numbytes); + fclose(file); + } + else if (numbytes == 0 || numbytes > 256) + { + T2Warning("Warning: timeZoneDST file has unexpected size %ld, skipping\n", numbytes); fclose(file); } else @@ -299,7 +304,6 @@ static char *getTimezone () { T2Warning("Warning: zone is empty, skipping\n"); } - zone[0] = '\0'; } fclose(file); free(zone); From 5171908bbe580221ea9bfebbf41fbceb385727b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Apr 2026 17:27:30 +0000 Subject: [PATCH 03/14] Remove upper bound check on timeZoneDST file size Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/0e080027-1be4-41cd-afbc-25283b55d93f Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- source/xconf-client/xconfclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/xconf-client/xconfclient.c b/source/xconf-client/xconfclient.c index eceb27d5..6427e18e 100644 --- a/source/xconf-client/xconfclient.c +++ b/source/xconf-client/xconfclient.c @@ -269,9 +269,9 @@ static char *getTimezone () T2Warning("Warning: timeZoneDST file is unreadable (ftell returned %ld)\n", numbytes); fclose(file); } - else if (numbytes == 0 || numbytes > 256) + else if (numbytes == 0) { - T2Warning("Warning: timeZoneDST file has unexpected size %ld, skipping\n", numbytes); + T2Warning("Warning: timeZoneDST file is empty, skipping\n"); fclose(file); } else From 1cbe8427b86064a1beafc8ce97135d0486f0c755 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Mon, 13 Apr 2026 14:29:33 +0530 Subject: [PATCH 04/14] RDKEMW-12350: Update xconfclient.c --- source/xconf-client/xconfclient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/xconf-client/xconfclient.c b/source/xconf-client/xconfclient.c index 6427e18e..ee608379 100644 --- a/source/xconf-client/xconfclient.c +++ b/source/xconf-client/xconfclient.c @@ -266,12 +266,12 @@ static char *getTimezone () long numbytes = ftell(file); if (numbytes < 0) { - T2Warning("Warning: timeZoneDST file is unreadable (ftell returned %ld)\n", numbytes); + T2Warning("timeZoneDST file is unreadable (ftell returned %ld)\n", numbytes); fclose(file); } else if (numbytes == 0) { - T2Warning("Warning: timeZoneDST file is empty, skipping\n"); + T2Warning("timeZoneDST file is empty, skipping\n"); fclose(file); } else From 7401952bd01682c793e0dec008ea621ec91fa390 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Mon, 13 Apr 2026 14:38:45 +0530 Subject: [PATCH 05/14] RDKEMW-12350: Update L1-tests.yml --- .github/workflows/L1-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index 307c71be..730f15d9 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -2,7 +2,7 @@ name: L1 Unit Tests on: pull_request: - branches: [ develop ] + branches: [ develop,support/1.8 ] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} From 4780c19b47f9d10a9ae76ec5b46ab668c186c237 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:33:44 +0530 Subject: [PATCH 06/14] RDKEMW-12350: Update L2-tests.yml --- .github/workflows/L2-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/L2-tests.yml b/.github/workflows/L2-tests.yml index 83828884..b97e5483 100644 --- a/.github/workflows/L2-tests.yml +++ b/.github/workflows/L2-tests.yml @@ -2,7 +2,7 @@ name: L2 Integration Tests on: pull_request: - branches: [ develop ] + branches: [ develop, support/1.8 ] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} From c7d368fd649c5efee5a75c995576086eaa235119 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:46:49 +0530 Subject: [PATCH 07/14] RDKEMW-12350: Fix missing error checks in timeZoneDST fallback path --- source/xconf-client/xconfclient.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/source/xconf-client/xconfclient.c b/source/xconf-client/xconfclient.c index ee608379..7d957567 100644 --- a/source/xconf-client/xconfclient.c +++ b/source/xconf-client/xconfclient.c @@ -269,9 +269,9 @@ static char *getTimezone () T2Warning("timeZoneDST file is unreadable (ftell returned %ld)\n", numbytes); fclose(file); } - else if (numbytes == 0) + else if (numbytes == 0 || numbytes > 256) { - T2Warning("timeZoneDST file is empty, skipping\n"); + T2Warning("Warning: timeZoneDST file has unexpected size %ld, skipping\n", numbytes); fclose(file); } else @@ -300,10 +300,6 @@ static char *getTimezone () } zoneValue = strdup(zone); } - else - { - T2Warning("Warning: zone is empty, skipping\n"); - } } fclose(file); free(zone); From aa88d6de72cf7a52742d486090861a0bd3690db3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:54:12 +0000 Subject: [PATCH 08/14] Initial plan From 0ceb491ae7bc6cc9cd73d480f29a7570bd581ea4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:15:52 +0000 Subject: [PATCH 09/14] Add unit tests for timeZoneDST fallback path in getTimezone() Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/2b39401a-79a0-4d6a-a81f-523a6997a872 Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- configure.ac | 2 +- source/test/Makefile.am | 2 +- source/test/xconf-client/Makefile.am | 97 ++++++++++ source/test/xconf-client/gtest_main.cpp | 44 +++++ source/test/xconf-client/xconfclientTest.cpp | 191 +++++++++++++++++++ test/run_ut.sh | 1 + 6 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 source/test/xconf-client/Makefile.am create mode 100644 source/test/xconf-client/gtest_main.cpp diff --git a/configure.ac b/configure.ac index 03951e9f..74156d71 100644 --- a/configure.ac +++ b/configure.ac @@ -46,7 +46,7 @@ AC_ARG_ENABLE([gtestapp], case "${enableval}" in yes) GTEST_SUPPORT_ENABLED=true GTEST_ENABLE_FLAG=" -DGTEST_ENABLE" - m4_if(m4_sysval,[0],[AC_CONFIG_FILES([source/test/Makefile source/test/dcautils/Makefile source/test/t2parser/Makefile source/test/scheduler/Makefile source/test/reportgen/Makefile source/test/bulkdata/Makefile source/test/ccspinterface/Makefile])]);; + m4_if(m4_sysval,[0],[AC_CONFIG_FILES([source/test/Makefile source/test/dcautils/Makefile source/test/t2parser/Makefile source/test/scheduler/Makefile source/test/reportgen/Makefile source/test/bulkdata/Makefile source/test/ccspinterface/Makefile source/test/xconf-client/Makefile])]);; no) GTEST_SUPPORT_ENABLED=false AC_MSG_ERROR([Gtest support is disabled]);; *) AC_MSG_ERROR([bad value ${enableval} for --enable-gtestapp ]);; esac diff --git a/source/test/Makefile.am b/source/test/Makefile.am index 145af5a0..f1a5862c 100644 --- a/source/test/Makefile.am +++ b/source/test/Makefile.am @@ -19,4 +19,4 @@ AUTOMAKE_OPTIONS = subdir-objects -SUBDIRS = bulkdata t2parser reportgen scheduler dcautils ccspinterface +SUBDIRS = bulkdata t2parser reportgen scheduler dcautils ccspinterface xconf-client diff --git a/source/test/xconf-client/Makefile.am b/source/test/xconf-client/Makefile.am new file mode 100644 index 00000000..666dc389 --- /dev/null +++ b/source/test/xconf-client/Makefile.am @@ -0,0 +1,97 @@ +########################################################################## +# If not stated otherwise in this file or this component's LICENSE +# file the following copyright and licenses apply: +# +# Copyright 2024 RDK Management +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################## + +AM_CXXFLAGS = -fno-permissive -std=c++11 -DGTEST_ENABLE -DPERSIST_LOG_MON_REF -fPIC -DPRIVACYMODES_CONTROL -DBULKDATA -DCCSP_SUPPORT_ENABLED -DFEATURE_SUPPORT_WEBCONFIG -DDROP_ROOT_PRIV -DDCMAGENT + +AM_CFLAGS = -DGTEST_ENABLE -DPERSIST_LOG_MON_REF -fPIC -DCCSP_SUPPORT_ENABLED -DPRIVACYMODES_CONTROL -DDCMAGENT + +AUTOMAKE_OPTIONS = subdir-objects + +ACLOCAL_AMFLAGS = -I m4 + +bin_PROGRAMS = xconfclient_gtest.bin + +xconfclient_gtest_bin_CPPFLAGS = -I$(PKG_CONFIG_SYSROOT_DIR)/usr/include/gtest \ + -I$(PKG_CONFIG_SYSROOT_DIR)/usr/include/glib-2.0 \ + -I$(PKG_CONFIG_SYSROOT_DIR)/usr/lib/x86_64-linux-gnu/glib-2.0/include \ + -I$(PKG_CONFIG_SYSROOT_DIR)/usr/local/lib \ + -I$(PKG_CONFIG_SYSROOT_DIR)$(includedir)/gtest \ + -I${top_srcdir}/gtest/include \ + -I${top_srcdir}/source/include \ + -I${top_srcdir}/source \ + -I${top_srcdir}/source/test/mocks \ + -I$(PKG_CONFIG_SYSROOT_DIR)/usr/local/include/rbus \ + -I${top_srcdir}/source/test/rdk_logger \ + -I${top_srcdir}/include \ + -I${top_srcdir}/source/utils \ + -I${top_srcdir}/source/privacycontrol \ + -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/rbus \ + -I${top_srcdir}/source/dcautil \ + -I${top_srcdir}/source/ccspinterface \ + -I${top_srcdir}/source/reportgen \ + -I${top_srcdir}/source/xconf-client \ + -I${top_srcdir}/source/protocol/http \ + -I${top_srcdir}/source/protocol/rbusMethod \ + -I${top_srcdir}/source/t2parser \ + -I${top_srcdir}/source/bulkdata \ + -I${top_srcdir}/source/scheduler \ + -I${PKG_CONFIG_SYSROOT_DIR}$(includedir) \ + -I${top_srcdir}/source/test/xconf-client \ + -I$(PKG_CONFIG_SYSROOT_DIR)/usr/src/googletest/googlemock/include \ + -I${RDK_PROJECT_ROOT_PATH}/$(GLIB_CFLAGS) \ + -I$(PKG_CONFIG_SYSROOT_DIR)$(includedir)/glib-2.0 \ + -I$(PKG_CONFIG_SYSROOT_DIR)$(libdir)/glib-2.0/include + +xconfclient_gtest_bin_SOURCES = \ + gtest_main.cpp \ + ../mocks/SystemMock.cpp \ + ../mocks/FileioMock.cpp \ + ../mocks/rdklogMock.cpp \ + ../mocks/rbusMock.cpp \ + ../mocks/rdkconfigMock.cpp \ + ../mocks/VectorMock.cpp \ + xconfclientMock.cpp \ + xconfclientTest.cpp \ + ../../utils/t2log_wrapper.c \ + ../../privacycontrol/rdkservices_privacyutils.c \ + ../../utils/persistence.c \ + ../../utils/t2common.c \ + ../../utils/t2collection.c \ + ../../utils/t2MtlsUtils.c \ + ../../ccspinterface/rbusInterface.c \ + ../../ccspinterface/busInterface.c \ + ../../reportgen/reportgen.c \ + ../../t2parser/t2parserxconf.c \ + ../../xconf-client/xconfclient.c \ + ../../protocol/http/curlinterface.c \ + ../../protocol/http/multicurlinterface.c + +xconfclient_gtest_bin_LDFLAGS = \ + -L/usr/src/googletest/googletest/lib/.libs \ + -lgcov \ + -L/src/googletest/googlemock/lib \ + -L/usr/src/googletest/googlemock/lib/.libs \ + -L/usr/include/glib-2.0 \ + -lgmock \ + -lcjson \ + -lcurl \ + -lmsgpackc \ + -lgtest \ + -lgtest_main \ + -lglib-2.0 diff --git a/source/test/xconf-client/gtest_main.cpp b/source/test/xconf-client/gtest_main.cpp new file mode 100644 index 00000000..bfe12742 --- /dev/null +++ b/source/test/xconf-client/gtest_main.cpp @@ -0,0 +1,44 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include + +#define GTEST_DEFAULT_RESULT_FILEPATH "/tmp/Gtest_Report/" +#define GTEST_DEFAULT_RESULT_FILENAME "xconfclient_gtest_report.json" +#define GTEST_REPORT_FILEPATH_SIZE 128 + +GTEST_API_ int main(int argc, char *argv[]) +{ + char testresults_fullfilepath[GTEST_REPORT_FILEPATH_SIZE]; + char buffer[GTEST_REPORT_FILEPATH_SIZE]; + + memset( testresults_fullfilepath, 0, GTEST_REPORT_FILEPATH_SIZE ); + memset( buffer, 0, GTEST_REPORT_FILEPATH_SIZE ); + + snprintf( testresults_fullfilepath, GTEST_REPORT_FILEPATH_SIZE, "json:%s%s" , GTEST_DEFAULT_RESULT_FILEPATH , GTEST_DEFAULT_RESULT_FILENAME); + ::testing::InitGoogleTest(&argc, argv); + ::testing::GTEST_FLAG(output) = testresults_fullfilepath; + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/source/test/xconf-client/xconfclientTest.cpp b/source/test/xconf-client/xconfclientTest.cpp index 5738c9a2..50cc4aba 100644 --- a/source/test/xconf-client/xconfclientTest.cpp +++ b/source/test/xconf-client/xconfclientTest.cpp @@ -762,3 +762,194 @@ TEST(STOPXCONFCLIENT, success_check) { EXPECT_EQ(T2ERROR_SUCCESS, stopXConfClient()); } + +/* + * Tests for the getTimezone() timeZoneDST fallback path. + * + * getTimezone() is a static function exercised indirectly via appendRequestParams(). + * The fallback to /opt/persistent/timeZoneDST is reached after the JSON-based + * primary path exhausts its 10 retries without finding a timezone. + * + * Preconditions for each test: + * - All getParameterValue calls succeed (6 calls with dummy values). + * - getBuildType succeeds: fopen(DEVICE_PROPERTIES) returns a fake handle, fscanf + * fills "BUILD_TYPE=PROD" and then returns EOF. + * - getTimezone CPU_ARCH read: fopen(DEVICE_PROPERTIES) returns NULL (no CPU_ARCH). + * - getTimezone JSON loop: fopen("/opt/output.json") returns NULL (10 retries fail). + * After these preconditions the timeZoneDST fallback is exercised. + */ +#if !defined(ENABLE_RDKB_SUPPORT) && !defined(ENABLE_RDKC_SUPPORT) + +// Helper to set up the mocks needed to reach the timeZoneDST fallback in getTimezone(). +// Requires g_fileIOMock and m_xconfclientMock to be set. +static void SetupReachTimeZoneDSTFallback(FILE* devicePropsHandle) +{ + using namespace testing; + + // All 6 getParameterValue calls succeed with dummy values. + EXPECT_CALL(*m_xconfclientMock, getParameterValue(_, _)) + .Times(AtLeast(6)) + .WillRepeatedly(Invoke([](const char*, char** val) -> T2ERROR { + *val = strdup("dummy"); + return T2ERROR_SUCCESS; + })); + + // getBuildType: fopen(DEVICE_PROPERTIES) -> devicePropsHandle, fscanf fills + // "BUILD_TYPE=PROD" then EOF, fclose returns 0. + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/etc/device.properties"), _)) + .WillOnce(Return(devicePropsHandle)) // getBuildType + .WillOnce(Return(nullptr)); // getTimezone CPU_ARCH read + + EXPECT_CALL(*g_fileIOMock, fscanf(devicePropsHandle, _, _)) + .WillOnce(Invoke([](FILE*, const char*, va_list args) -> int { + char* buf = va_arg(args, char*); + strncpy(buf, "BUILD_TYPE=PROD", 254); + buf[254] = '\0'; + return 1; + })) + .WillOnce(Return(EOF)); + + EXPECT_CALL(*g_fileIOMock, fclose(devicePropsHandle)) + .WillOnce(Return(0)); + + // getTimezone JSON loop: fopen("/opt/output.json") returns NULL all 10 retries. + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/opt/output.json"), _)) + .Times(10) + .WillRepeatedly(Return(nullptr)); +} + +// Test 1: fopen("/opt/persistent/timeZoneDST") returns NULL. +// The fallback cannot open the file; timezone stays NULL; appendRequestParams returns FAILURE. +TEST_F(xconfclientTestFixture, getTimezone_timeZoneDST_fopen_null) +{ + FILE* devicePropsHandle = reinterpret_cast(0x1234); + PREVENT_GTEST_LOGGING_DEADLOCK(); + SetupReachTimeZoneDSTFallback(devicePropsHandle); + + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/opt/persistent/timeZoneDST"), _)) + .WillOnce(Return(nullptr)); + + CURLU* requestURL = curl_url(); + curl_url_set(requestURL, CURLUPART_URL, + "https://mockxconf:50050/loguploader/getT2DCMSettings", 0); + EXPECT_EQ(T2ERROR_FAILURE, appendRequestParams(requestURL)); + curl_free(requestURL); + requestURL = NULL; +} + +// Test 2: ftell returns -1 (unreadable/error). +// The fallback opens the file but ftell fails; file is closed; timezone stays NULL. +TEST_F(xconfclientTestFixture, getTimezone_timeZoneDST_ftell_negative) +{ + FILE* devicePropsHandle = reinterpret_cast(0x1234); + FILE* tzFile = reinterpret_cast(0x5678); + PREVENT_GTEST_LOGGING_DEADLOCK(); + SetupReachTimeZoneDSTFallback(devicePropsHandle); + + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/opt/persistent/timeZoneDST"), _)) + .WillOnce(Return(tzFile)); + EXPECT_CALL(*g_fileIOMock, fseek(tzFile, 0, SEEK_END)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, ftell(tzFile)) + .WillOnce(Return(-1L)); + EXPECT_CALL(*g_fileIOMock, fclose(tzFile)) + .WillOnce(Return(0)); + + CURLU* requestURL = curl_url(); + curl_url_set(requestURL, CURLUPART_URL, + "https://mockxconf:50050/loguploader/getT2DCMSettings", 0); + EXPECT_EQ(T2ERROR_FAILURE, appendRequestParams(requestURL)); + curl_free(requestURL); + requestURL = NULL; +} + +// Test 3: ftell returns 0 (empty file). +// The fallback opens the file but it is empty; file is closed; timezone stays NULL. +TEST_F(xconfclientTestFixture, getTimezone_timeZoneDST_empty_file) +{ + FILE* devicePropsHandle = reinterpret_cast(0x1234); + FILE* tzFile = reinterpret_cast(0x5678); + PREVENT_GTEST_LOGGING_DEADLOCK(); + SetupReachTimeZoneDSTFallback(devicePropsHandle); + + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/opt/persistent/timeZoneDST"), _)) + .WillOnce(Return(tzFile)); + EXPECT_CALL(*g_fileIOMock, fseek(tzFile, 0, SEEK_END)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, ftell(tzFile)) + .WillOnce(Return(0L)); + EXPECT_CALL(*g_fileIOMock, fclose(tzFile)) + .WillOnce(Return(0)); + + CURLU* requestURL = curl_url(); + curl_url_set(requestURL, CURLUPART_URL, + "https://mockxconf:50050/loguploader/getT2DCMSettings", 0); + EXPECT_EQ(T2ERROR_FAILURE, appendRequestParams(requestURL)); + curl_free(requestURL); + requestURL = NULL; +} + +// Test 4: ftell returns a value exceeding the 256-byte limit. +// The fallback rejects oversized files; file is closed; timezone stays NULL. +TEST_F(xconfclientTestFixture, getTimezone_timeZoneDST_file_too_large) +{ + FILE* devicePropsHandle = reinterpret_cast(0x1234); + FILE* tzFile = reinterpret_cast(0x5678); + PREVENT_GTEST_LOGGING_DEADLOCK(); + SetupReachTimeZoneDSTFallback(devicePropsHandle); + + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/opt/persistent/timeZoneDST"), _)) + .WillOnce(Return(tzFile)); + EXPECT_CALL(*g_fileIOMock, fseek(tzFile, 0, SEEK_END)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, ftell(tzFile)) + .WillOnce(Return(512L)); + EXPECT_CALL(*g_fileIOMock, fclose(tzFile)) + .WillOnce(Return(0)); + + CURLU* requestURL = curl_url(); + curl_url_set(requestURL, CURLUPART_URL, + "https://mockxconf:50050/loguploader/getT2DCMSettings", 0); + EXPECT_EQ(T2ERROR_FAILURE, appendRequestParams(requestURL)); + curl_free(requestURL); + requestURL = NULL; +} + +// Test 5: Valid timezone string read from /opt/persistent/timeZoneDST. +// The fallback reads a valid timezone; appendRequestParams returns SUCCESS. +TEST_F(xconfclientTestFixture, getTimezone_timeZoneDST_valid_timezone) +{ + FILE* devicePropsHandle = reinterpret_cast(0x1234); + FILE* tzFile = reinterpret_cast(0x5678); + PREVENT_GTEST_LOGGING_DEADLOCK(); + SetupReachTimeZoneDSTFallback(devicePropsHandle); + + EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/opt/persistent/timeZoneDST"), _)) + .WillOnce(Return(tzFile)); + EXPECT_CALL(*g_fileIOMock, fseek(tzFile, 0, SEEK_END)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, ftell(tzFile)) + .WillOnce(Return(10L)); + EXPECT_CALL(*g_fileIOMock, fseek(tzFile, 0, SEEK_SET)) + .WillOnce(Return(0)); + // fscanf fills the zone buffer with "US/Eastern" and then signals end-of-file. + EXPECT_CALL(*g_fileIOMock, fscanf(tzFile, _, _)) + .WillOnce(Invoke([](FILE*, const char*, va_list args) -> int { + char* buf = va_arg(args, char*); + strncpy(buf, "US/Eastern", 10); + buf[10] = '\0'; + return 1; + })) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fclose(tzFile)) + .WillOnce(Return(0)); + + CURLU* requestURL = curl_url(); + curl_url_set(requestURL, CURLUPART_URL, + "https://mockxconf:50050/loguploader/getT2DCMSettings", 0); + EXPECT_EQ(T2ERROR_SUCCESS, appendRequestParams(requestURL)); + curl_free(requestURL); + requestURL = NULL; +} + +#endif /* !defined(ENABLE_RDKB_SUPPORT) && !defined(ENABLE_RDKC_SUPPORT) */ diff --git a/test/run_ut.sh b/test/run_ut.sh index 90f897f5..e1b63311 100755 --- a/test/run_ut.sh +++ b/test/run_ut.sh @@ -55,6 +55,7 @@ tests=" ./source/test/t2parser/t2parser_gtest.bin ./source/test/dcautils/dcautil_gtest.bin ./source/test/ccspinterface/ccspinterface_gtest.bin +./source/test/xconf-client/xconfclient_gtest.bin " for test in $tests From 46f82cd6b34cc7c44e0cf157accb12727b334fac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:56:28 +0000 Subject: [PATCH 10/14] Revert build infrastructure changes, keep only test and source changes Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/7f6ea2d9-36fa-4120-a7dc-e7bfe71e9f8a Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- .github/workflows/L1-tests.yml | 2 +- .github/workflows/L2-tests.yml | 2 +- configure.ac | 2 +- source/test/Makefile.am | 2 +- source/test/xconf-client/Makefile.am | 97 ------------------------- source/test/xconf-client/gtest_main.cpp | 44 ----------- test/run_ut.sh | 1 - 7 files changed, 4 insertions(+), 146 deletions(-) delete mode 100644 source/test/xconf-client/Makefile.am delete mode 100644 source/test/xconf-client/gtest_main.cpp diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index 730f15d9..307c71be 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -2,7 +2,7 @@ name: L1 Unit Tests on: pull_request: - branches: [ develop,support/1.8 ] + branches: [ develop ] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} diff --git a/.github/workflows/L2-tests.yml b/.github/workflows/L2-tests.yml index b97e5483..83828884 100644 --- a/.github/workflows/L2-tests.yml +++ b/.github/workflows/L2-tests.yml @@ -2,7 +2,7 @@ name: L2 Integration Tests on: pull_request: - branches: [ develop, support/1.8 ] + branches: [ develop ] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} diff --git a/configure.ac b/configure.ac index 74156d71..03951e9f 100644 --- a/configure.ac +++ b/configure.ac @@ -46,7 +46,7 @@ AC_ARG_ENABLE([gtestapp], case "${enableval}" in yes) GTEST_SUPPORT_ENABLED=true GTEST_ENABLE_FLAG=" -DGTEST_ENABLE" - m4_if(m4_sysval,[0],[AC_CONFIG_FILES([source/test/Makefile source/test/dcautils/Makefile source/test/t2parser/Makefile source/test/scheduler/Makefile source/test/reportgen/Makefile source/test/bulkdata/Makefile source/test/ccspinterface/Makefile source/test/xconf-client/Makefile])]);; + m4_if(m4_sysval,[0],[AC_CONFIG_FILES([source/test/Makefile source/test/dcautils/Makefile source/test/t2parser/Makefile source/test/scheduler/Makefile source/test/reportgen/Makefile source/test/bulkdata/Makefile source/test/ccspinterface/Makefile])]);; no) GTEST_SUPPORT_ENABLED=false AC_MSG_ERROR([Gtest support is disabled]);; *) AC_MSG_ERROR([bad value ${enableval} for --enable-gtestapp ]);; esac diff --git a/source/test/Makefile.am b/source/test/Makefile.am index f1a5862c..145af5a0 100644 --- a/source/test/Makefile.am +++ b/source/test/Makefile.am @@ -19,4 +19,4 @@ AUTOMAKE_OPTIONS = subdir-objects -SUBDIRS = bulkdata t2parser reportgen scheduler dcautils ccspinterface xconf-client +SUBDIRS = bulkdata t2parser reportgen scheduler dcautils ccspinterface diff --git a/source/test/xconf-client/Makefile.am b/source/test/xconf-client/Makefile.am deleted file mode 100644 index 666dc389..00000000 --- a/source/test/xconf-client/Makefile.am +++ /dev/null @@ -1,97 +0,0 @@ -########################################################################## -# If not stated otherwise in this file or this component's LICENSE -# file the following copyright and licenses apply: -# -# Copyright 2024 RDK Management -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -########################################################################## - -AM_CXXFLAGS = -fno-permissive -std=c++11 -DGTEST_ENABLE -DPERSIST_LOG_MON_REF -fPIC -DPRIVACYMODES_CONTROL -DBULKDATA -DCCSP_SUPPORT_ENABLED -DFEATURE_SUPPORT_WEBCONFIG -DDROP_ROOT_PRIV -DDCMAGENT - -AM_CFLAGS = -DGTEST_ENABLE -DPERSIST_LOG_MON_REF -fPIC -DCCSP_SUPPORT_ENABLED -DPRIVACYMODES_CONTROL -DDCMAGENT - -AUTOMAKE_OPTIONS = subdir-objects - -ACLOCAL_AMFLAGS = -I m4 - -bin_PROGRAMS = xconfclient_gtest.bin - -xconfclient_gtest_bin_CPPFLAGS = -I$(PKG_CONFIG_SYSROOT_DIR)/usr/include/gtest \ - -I$(PKG_CONFIG_SYSROOT_DIR)/usr/include/glib-2.0 \ - -I$(PKG_CONFIG_SYSROOT_DIR)/usr/lib/x86_64-linux-gnu/glib-2.0/include \ - -I$(PKG_CONFIG_SYSROOT_DIR)/usr/local/lib \ - -I$(PKG_CONFIG_SYSROOT_DIR)$(includedir)/gtest \ - -I${top_srcdir}/gtest/include \ - -I${top_srcdir}/source/include \ - -I${top_srcdir}/source \ - -I${top_srcdir}/source/test/mocks \ - -I$(PKG_CONFIG_SYSROOT_DIR)/usr/local/include/rbus \ - -I${top_srcdir}/source/test/rdk_logger \ - -I${top_srcdir}/include \ - -I${top_srcdir}/source/utils \ - -I${top_srcdir}/source/privacycontrol \ - -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/rbus \ - -I${top_srcdir}/source/dcautil \ - -I${top_srcdir}/source/ccspinterface \ - -I${top_srcdir}/source/reportgen \ - -I${top_srcdir}/source/xconf-client \ - -I${top_srcdir}/source/protocol/http \ - -I${top_srcdir}/source/protocol/rbusMethod \ - -I${top_srcdir}/source/t2parser \ - -I${top_srcdir}/source/bulkdata \ - -I${top_srcdir}/source/scheduler \ - -I${PKG_CONFIG_SYSROOT_DIR}$(includedir) \ - -I${top_srcdir}/source/test/xconf-client \ - -I$(PKG_CONFIG_SYSROOT_DIR)/usr/src/googletest/googlemock/include \ - -I${RDK_PROJECT_ROOT_PATH}/$(GLIB_CFLAGS) \ - -I$(PKG_CONFIG_SYSROOT_DIR)$(includedir)/glib-2.0 \ - -I$(PKG_CONFIG_SYSROOT_DIR)$(libdir)/glib-2.0/include - -xconfclient_gtest_bin_SOURCES = \ - gtest_main.cpp \ - ../mocks/SystemMock.cpp \ - ../mocks/FileioMock.cpp \ - ../mocks/rdklogMock.cpp \ - ../mocks/rbusMock.cpp \ - ../mocks/rdkconfigMock.cpp \ - ../mocks/VectorMock.cpp \ - xconfclientMock.cpp \ - xconfclientTest.cpp \ - ../../utils/t2log_wrapper.c \ - ../../privacycontrol/rdkservices_privacyutils.c \ - ../../utils/persistence.c \ - ../../utils/t2common.c \ - ../../utils/t2collection.c \ - ../../utils/t2MtlsUtils.c \ - ../../ccspinterface/rbusInterface.c \ - ../../ccspinterface/busInterface.c \ - ../../reportgen/reportgen.c \ - ../../t2parser/t2parserxconf.c \ - ../../xconf-client/xconfclient.c \ - ../../protocol/http/curlinterface.c \ - ../../protocol/http/multicurlinterface.c - -xconfclient_gtest_bin_LDFLAGS = \ - -L/usr/src/googletest/googletest/lib/.libs \ - -lgcov \ - -L/src/googletest/googlemock/lib \ - -L/usr/src/googletest/googlemock/lib/.libs \ - -L/usr/include/glib-2.0 \ - -lgmock \ - -lcjson \ - -lcurl \ - -lmsgpackc \ - -lgtest \ - -lgtest_main \ - -lglib-2.0 diff --git a/source/test/xconf-client/gtest_main.cpp b/source/test/xconf-client/gtest_main.cpp deleted file mode 100644 index bfe12742..00000000 --- a/source/test/xconf-client/gtest_main.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 RDK Management - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include - -#define GTEST_DEFAULT_RESULT_FILEPATH "/tmp/Gtest_Report/" -#define GTEST_DEFAULT_RESULT_FILENAME "xconfclient_gtest_report.json" -#define GTEST_REPORT_FILEPATH_SIZE 128 - -GTEST_API_ int main(int argc, char *argv[]) -{ - char testresults_fullfilepath[GTEST_REPORT_FILEPATH_SIZE]; - char buffer[GTEST_REPORT_FILEPATH_SIZE]; - - memset( testresults_fullfilepath, 0, GTEST_REPORT_FILEPATH_SIZE ); - memset( buffer, 0, GTEST_REPORT_FILEPATH_SIZE ); - - snprintf( testresults_fullfilepath, GTEST_REPORT_FILEPATH_SIZE, "json:%s%s" , GTEST_DEFAULT_RESULT_FILEPATH , GTEST_DEFAULT_RESULT_FILENAME); - ::testing::InitGoogleTest(&argc, argv); - ::testing::GTEST_FLAG(output) = testresults_fullfilepath; - ::testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/run_ut.sh b/test/run_ut.sh index e1b63311..90f897f5 100755 --- a/test/run_ut.sh +++ b/test/run_ut.sh @@ -55,7 +55,6 @@ tests=" ./source/test/t2parser/t2parser_gtest.bin ./source/test/dcautils/dcautil_gtest.bin ./source/test/ccspinterface/ccspinterface_gtest.bin -./source/test/xconf-client/xconfclient_gtest.bin " for test in $tests From d10e308faf973947b26053e20f49cd68ca24c019 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:30:23 +0530 Subject: [PATCH 11/14] Update L1-tests.yml --- .github/workflows/L1-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index 307c71be..1e58380b 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -2,7 +2,7 @@ name: L1 Unit Tests on: pull_request: - branches: [ develop ] + branches: [ develop, support/1.8, copilot/improve-zone-null-checks ] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} From e9e11174f3bb149794edf7c9d5ae8cc895d6a0e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 07:13:38 +0000 Subject: [PATCH 12/14] Fix unqualified Invoke in getTimezone_timeZoneDST_valid_timezone test Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/03d1c8d7-2587-443b-bbe5-50a78ff7f073 Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- source/test/xconf-client/xconfclientTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/test/xconf-client/xconfclientTest.cpp b/source/test/xconf-client/xconfclientTest.cpp index 50cc4aba..fe9b2ee2 100644 --- a/source/test/xconf-client/xconfclientTest.cpp +++ b/source/test/xconf-client/xconfclientTest.cpp @@ -934,7 +934,7 @@ TEST_F(xconfclientTestFixture, getTimezone_timeZoneDST_valid_timezone) .WillOnce(Return(0)); // fscanf fills the zone buffer with "US/Eastern" and then signals end-of-file. EXPECT_CALL(*g_fileIOMock, fscanf(tzFile, _, _)) - .WillOnce(Invoke([](FILE*, const char*, va_list args) -> int { + .WillOnce(::testing::Invoke([](FILE*, const char*, va_list args) -> int { char* buf = va_arg(args, char*); strncpy(buf, "US/Eastern", 10); buf[10] = '\0'; From 0bbe8154be799d8e582f3a9391de1dae414829d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Apr 2026 08:56:18 +0000 Subject: [PATCH 13/14] Fix SetupReachTimeZoneDSTFallback: fscanf called once not twice due to break in getBuildType Agent-Logs-Url: https://github.com/rdkcentral/telemetry/sessions/d94df585-444b-4056-a136-bc1f7415c614 Co-authored-by: yogeswaransky <166126056+yogeswaransky@users.noreply.github.com> --- source/test/xconf-client/xconfclientTest.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/test/xconf-client/xconfclientTest.cpp b/source/test/xconf-client/xconfclientTest.cpp index fe9b2ee2..9d3ec665 100644 --- a/source/test/xconf-client/xconfclientTest.cpp +++ b/source/test/xconf-client/xconfclientTest.cpp @@ -795,19 +795,20 @@ static void SetupReachTimeZoneDSTFallback(FILE* devicePropsHandle) })); // getBuildType: fopen(DEVICE_PROPERTIES) -> devicePropsHandle, fscanf fills - // "BUILD_TYPE=PROD" then EOF, fclose returns 0. + // "BUILD_TYPE=PROD" and breaks (no EOF call), fclose returns 0. EXPECT_CALL(*g_fileIOMock, fopen(StrEq("/etc/device.properties"), _)) .WillOnce(Return(devicePropsHandle)) // getBuildType .WillOnce(Return(nullptr)); // getTimezone CPU_ARCH read + // getBuildType breaks out of its fscanf loop as soon as it finds "BUILD_TYPE", + // so fscanf is called exactly once. EXPECT_CALL(*g_fileIOMock, fscanf(devicePropsHandle, _, _)) .WillOnce(Invoke([](FILE*, const char*, va_list args) -> int { char* buf = va_arg(args, char*); strncpy(buf, "BUILD_TYPE=PROD", 254); buf[254] = '\0'; return 1; - })) - .WillOnce(Return(EOF)); + })); EXPECT_CALL(*g_fileIOMock, fclose(devicePropsHandle)) .WillOnce(Return(0)); From 6f6777f61c588b3a50ecea5a09e9974926c19dc7 Mon Sep 17 00:00:00 2001 From: Yogeswaran K <166126056+yogeswaransky@users.noreply.github.com> Date: Thu, 16 Apr 2026 15:32:03 +0530 Subject: [PATCH 14/14] Update L1-tests.yml --- .github/workflows/L1-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index 1e58380b..307c71be 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -2,7 +2,7 @@ name: L1 Unit Tests on: pull_request: - branches: [ develop, support/1.8, copilot/improve-zone-null-checks ] + branches: [ develop ] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }}