From a938df43f385f8cc85e032a5459247423c2d9ed2 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:16:07 +0530 Subject: [PATCH 01/36] Update dcautil.c --- source/dcautil/dcautil.c | 144 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 5f7185c63..bc654c8b2 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -19,7 +19,13 @@ #include #include +#include +#include +#include #include +#include +#include +#include #include "dca.h" #include "dcautil.h" #include "telemetry2_0.h" @@ -28,6 +34,130 @@ #include "legacyutils.h" #include "persistence.h" +/** + * @brief Wait for the backup_logs completion sentinel before grepping PreviousLogs. + * + * Strategy: + * 1. Fast path: sentinel already present → return true immediately. + * 2. Set up inotify on BACKUP_LOGS_DONE_DIR (/tmp) for IN_CREATE | IN_MOVED_TO. + * 3. Re-check after watch is established to close the creation race window. + * 4. select() loop with 2 s heartbeat; exit when sentinel appears or + * BACKUP_LOGS_SYNC_TIMEOUT_S total seconds have elapsed. + * + * This is a **soft gate**: if the function returns false (timeout or inotify + * failure) the caller still proceeds — previous-log grep runs against whatever + * files are present, and a warning is logged. + * + * @return true sentinel detected within timeout + * @return false timeout elapsed or inotify initialisation failed + */ +static bool waitForBackupLogsDone(void) +{ + /* Fast path: sentinel already written by backup_logs */ + if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) + { + T2Info("backup_logs sentinel %s already present\n", BACKUP_LOGS_DONE_FLAG); + return true; + } + + int ifd = inotify_init1(IN_CLOEXEC); + if (ifd < 0) + { + T2Error("inotify_init1 failed (errno=%d); proceeding without backup_logs sync\n", errno); + return false; + } + + int wd = inotify_add_watch(ifd, BACKUP_LOGS_DONE_DIR, IN_CREATE | IN_MOVED_TO); + if (wd < 0) + { + T2Error("inotify_add_watch on %s failed (errno=%d); proceeding without backup_logs sync\n", + BACKUP_LOGS_DONE_DIR, errno); + close(ifd); + return false; + } + + /* Re-check after watch is set — closes the race window between the first + * access() call and establishing the watch. */ + if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) + { + T2Info("backup_logs sentinel detected (race resolved): %s\n", BACKUP_LOGS_DONE_FLAG); + inotify_rm_watch(ifd, wd); + close(ifd); + return true; + } + + struct timespec deadline; + if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) + { + T2Error("clock_gettime failed (errno=%d); proceeding without backup_logs sync\n", errno); + inotify_rm_watch(ifd, wd); + close(ifd); + return false; + } + deadline.tv_sec += BACKUP_LOGS_SYNC_TIMEOUT_S; + + T2Info("Waiting up to %ds for backup_logs sentinel: %s\n", + BACKUP_LOGS_SYNC_TIMEOUT_S, BACKUP_LOGS_DONE_FLAG); + + bool found = false; + char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; + + while (!found) + { + /* Check deadline */ + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0 && now.tv_sec >= deadline.tv_sec) + { + T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", + BACKUP_LOGS_SYNC_TIMEOUT_S); + break; + } + + struct timeval tv = {2, 0}; + fd_set fds; + FD_ZERO(&fds); + FD_SET(ifd, &fds); + + int ret = select(ifd + 1, &fds, NULL, NULL, &tv); + if (ret < 0) + { + if (errno == EINTR) + { + continue; + } + T2Error("select() failed (errno=%d) waiting for backup_logs sentinel\n", errno); + break; + } + if (ret == 0) + { + continue; /* 2 s heartbeat — loop back to check deadline */ + } + + ssize_t len = read(ifd, buf, sizeof(buf)); + if (len <= 0) + { + continue; + } + + ssize_t offset = 0; + while (offset < len) + { + struct inotify_event *ev = (struct inotify_event *)(buf + offset); + if (ev->len > 0 && strcmp(ev->name, BACKUP_LOGS_DONE_FILENAME) == 0) + { + T2Info("backup_logs sentinel created: %s\n", BACKUP_LOGS_DONE_FLAG); + found = true; + break; + } + offset += (ssize_t)(sizeof(struct inotify_event) + ev->len); + } + } + + inotify_rm_watch(ifd, wd); + close(ifd); + return found; +} + /** * @brief Get the Grep Results object. Main function called by rest of the consumers. * @@ -50,6 +180,20 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, return T2ERROR_FAILURE; } + /* Synchronize with backup_logs before grepping the previous-log directory. + * backup_logs populates PREVIOUS_LOGS_PATH; reading it before the write is + * complete yields incomplete or empty results. This is a soft gate — if the + * sentinel does not appear within BACKUP_LOGS_SYNC_TIMEOUT_S seconds we + * still proceed so telemetry is never permanently blocked. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) + { + if (!waitForBackupLogsDone()) + { + T2Warning("%s: backup_logs sentinel absent; grepping %s with potentially incomplete data\n", + __FUNCTION__, PREVIOUS_LOGS_PATH); + } + } + getDCAResultsInVector(*GSP, markerList, check_rotated, customLogPath); if (isClearSeekMap) { From 91620a656c6982efa91b4d039724132f6e6ef28b Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 16 Jun 2026 21:16:57 +0530 Subject: [PATCH 02/36] Update dcautil.h --- source/dcautil/dcautil.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/dcautil/dcautil.h b/source/dcautil/dcautil.h index 73487672b..873d98348 100644 --- a/source/dcautil/dcautil.h +++ b/source/dcautil/dcautil.h @@ -35,6 +35,21 @@ #define PREVIOUS_LOGS_VAL "1" #define PREVIOUS_LOGS_PATH "/opt/logs/PreviousLogs/" +/** Sentinel written by dcm-agent backup_logs on successful completion. + * Telemetry waits for this file before grepping PREVIOUS_LOGS_PATH to + * guarantee the previous-log directory is fully populated. + * Cross-repo interface: also defined in dcm-agent backup_logs/include/backup_logs.h. + * Any path change MUST be coordinated with the dcm-agent repository. */ +#define BACKUP_LOGS_DONE_FLAG "/tmp/.backup_logs_done" +#define BACKUP_LOGS_DONE_DIR "/tmp" +#define BACKUP_LOGS_DONE_FILENAME ".backup_logs_done" + +#ifdef GTEST_ENABLE +# define BACKUP_LOGS_SYNC_TIMEOUT_S 2 +#else +# define BACKUP_LOGS_SYNC_TIMEOUT_S 60 +#endif + typedef struct _GrepResult { const char* markerName; From c7dbcff0e1c024fe03085ec27f8eb95aa467ca56 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Thu, 2 Jul 2026 17:37:27 +0530 Subject: [PATCH 03/36] Update dcautil.h --- source/dcautil/dcautil.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/source/dcautil/dcautil.h b/source/dcautil/dcautil.h index 873d98348..aacae9bcf 100644 --- a/source/dcautil/dcautil.h +++ b/source/dcautil/dcautil.h @@ -30,16 +30,11 @@ #define TOPTEMP "/tmp/t2toplog" #define DCADONEFLAG "/tmp/.dca_done" +#define TELEMETRY_PREVLOGS_DONE_FLAG "/tmp/.telemetry_prevlogs_done" #define PREVIOUS_LOG "PREVIOUS_LOG" #define PREVIOUS_LOGS_VAL "1" #define PREVIOUS_LOGS_PATH "/opt/logs/PreviousLogs/" - -/** Sentinel written by dcm-agent backup_logs on successful completion. - * Telemetry waits for this file before grepping PREVIOUS_LOGS_PATH to - * guarantee the previous-log directory is fully populated. - * Cross-repo interface: also defined in dcm-agent backup_logs/include/backup_logs.h. - * Any path change MUST be coordinated with the dcm-agent repository. */ #define BACKUP_LOGS_DONE_FLAG "/tmp/.backup_logs_done" #define BACKUP_LOGS_DONE_DIR "/tmp" #define BACKUP_LOGS_DONE_FILENAME ".backup_logs_done" From 878e4bdb0c1dce59be5172a3e17e1dc8bc47e15d Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 7 Jul 2026 10:35:01 +0530 Subject: [PATCH 04/36] Update dcautil.c --- source/dcautil/dcautil.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index bc654c8b2..91d2131be 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -201,7 +201,23 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, freeGrepSeekProfile(*GSP); *GSP = createGrepSeekProfile(count); } - + /* Signal that telemetry previous-log grep is complete. + * Downstream consumers (e.g. uploadSTBLogs) wait for this sentinel + * before starting the log upload to avoid incomplete telemetry data. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) + { + FILE *fp = fopen(TELEMETRY_PREVLOGS_DONE_FLAG, "w"); + if (fp != NULL) + { + fclose(fp); + T2Info("Created telemetry previous-logs sentinel: %s\n", TELEMETRY_PREVLOGS_DONE_FLAG); + } + else + { + T2Error("%s: Failed to create sentinel %s (errno=%d)\n", + __FUNCTION__, TELEMETRY_PREVLOGS_DONE_FLAG, errno); + } + } T2Debug("%s --out\n", __FUNCTION__); return T2ERROR_SUCCESS; } From 5078684317c5cc5f8142b324f644f65c0baed1c6 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Mon, 13 Jul 2026 12:03:38 +0530 Subject: [PATCH 05/36] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/dcautil/dcautil.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 91d2131be..5281ff731 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -106,7 +106,12 @@ static bool waitForBackupLogsDone(void) { /* Check deadline */ struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now) == 0 && now.tv_sec >= deadline.tv_sec) + if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) + { + T2Error("clock_gettime failed (errno=%d) while waiting for backup_logs sentinel; proceeding without sync\n", errno); + break; + } + if (now.tv_sec >= deadline.tv_sec) { T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", BACKUP_LOGS_SYNC_TIMEOUT_S); From ad31e4c858eeacb8d40a276b9adeac46bb8d01b1 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Mon, 13 Jul 2026 12:06:01 +0530 Subject: [PATCH 06/36] Potential fix for pull request finding 'CodeQL / File created without restricting permissions' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- source/dcautil/dcautil.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 5281ff731..341af54df 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "dca.h" #include "dcautil.h" #include "telemetry2_0.h" @@ -211,10 +213,10 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, * before starting the log upload to avoid incomplete telemetry data. */ if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) { - FILE *fp = fopen(TELEMETRY_PREVLOGS_DONE_FLAG, "w"); - if (fp != NULL) + int fd = open(TELEMETRY_PREVLOGS_DONE_FLAG, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd >= 0) { - fclose(fp); + close(fd); T2Info("Created telemetry previous-logs sentinel: %s\n", TELEMETRY_PREVLOGS_DONE_FLAG); } else From e0219630ed450ba5347171aeba1bc5e874e85e4a Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Mon, 13 Jul 2026 16:22:17 +0530 Subject: [PATCH 07/36] Update dcautil.c --- source/dcautil/dcautil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 341af54df..5e78aaf5a 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -53,7 +53,7 @@ * @return true sentinel detected within timeout * @return false timeout elapsed or inotify initialisation failed */ -static bool waitForBackupLogsDone(void) +bool waitForBackupLogsDone(void) { /* Fast path: sentinel already written by backup_logs */ if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) From 50a344d75200f88019baf41ea702424cddfae858 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Mon, 13 Jul 2026 16:23:23 +0530 Subject: [PATCH 08/36] Update dcautil.h --- source/dcautil/dcautil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dcautil/dcautil.h b/source/dcautil/dcautil.h index aacae9bcf..aa4bc4427 100644 --- a/source/dcautil/dcautil.h +++ b/source/dcautil/dcautil.h @@ -89,7 +89,7 @@ int getMemInfo(procMemCpuInfo *pmInfo); int getCPUInfo(procMemCpuInfo *pInfo, char* filename); int getProcPidStat(int pid, procinfo * pinfo); int getTotalCpuTimes(int * totalTime); - +bool waitForBackupLogsDone(void); #ifdef PERSIST_LOG_MON_REF typedef void (*freeconfigdata)(void *data); From ebff0b33980f089ee8f7ee628f562bde1438a3d4 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 14 Jul 2026 23:07:32 +0530 Subject: [PATCH 09/36] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- source/dcautil/dcautil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 5e78aaf5a..dc512c45d 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -50,8 +50,8 @@ * failure) the caller still proceeds — previous-log grep runs against whatever * files are present, and a warning is logged. * - * @return true sentinel detected within timeout - * @return false timeout elapsed or inotify initialisation failed + * @return true Sentinel detected within timeout + * @return false Timeout elapsed or sync could not be established (inotify/clock/select failure) */ bool waitForBackupLogsDone(void) { From 48652310d6ca0e89f7849dbb890ba9caaefc0424 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 14 Jul 2026 23:46:02 +0530 Subject: [PATCH 10/36] Update dcautil.c --- source/dcautil/dcautil.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index dc512c45d..bea2a09b4 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -187,17 +187,11 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, return T2ERROR_FAILURE; } - /* Synchronize with backup_logs before grepping the previous-log directory. - * backup_logs populates PREVIOUS_LOGS_PATH; reading it before the write is - * complete yields incomplete or empty results. This is a soft gate — if the - * sentinel does not appear within BACKUP_LOGS_SYNC_TIMEOUT_S seconds we - * still proceed so telemetry is never permanently blocked. */ if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) { if (!waitForBackupLogsDone()) { - T2Warning("%s: backup_logs sentinel absent; grepping %s with potentially incomplete data\n", - __FUNCTION__, PREVIOUS_LOGS_PATH); + T2Warning("%s: backup_logs sentinel absent; grepping %s with potentially incomplete data\n", __FUNCTION__, PREVIOUS_LOGS_PATH); } } @@ -208,9 +202,7 @@ getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, freeGrepSeekProfile(*GSP); *GSP = createGrepSeekProfile(count); } - /* Signal that telemetry previous-log grep is complete. - * Downstream consumers (e.g. uploadSTBLogs) wait for this sentinel - * before starting the log upload to avoid incomplete telemetry data. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) { int fd = open(TELEMETRY_PREVLOGS_DONE_FLAG, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); From dbcd9cc9f7f980c1d89b544cb96e86d38ead4897 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 14 Jul 2026 23:48:05 +0530 Subject: [PATCH 11/36] Fix formatting of error and info messages in dcautil.c --- source/dcautil/dcautil.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index bea2a09b4..73d8593fe 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -72,8 +72,7 @@ bool waitForBackupLogsDone(void) int wd = inotify_add_watch(ifd, BACKUP_LOGS_DONE_DIR, IN_CREATE | IN_MOVED_TO); if (wd < 0) { - T2Error("inotify_add_watch on %s failed (errno=%d); proceeding without backup_logs sync\n", - BACKUP_LOGS_DONE_DIR, errno); + T2Error("inotify_add_watch on %s failed (errno=%d); proceeding without backup_logs sync\n", BACKUP_LOGS_DONE_DIR, errno); close(ifd); return false; } @@ -98,8 +97,7 @@ bool waitForBackupLogsDone(void) } deadline.tv_sec += BACKUP_LOGS_SYNC_TIMEOUT_S; - T2Info("Waiting up to %ds for backup_logs sentinel: %s\n", - BACKUP_LOGS_SYNC_TIMEOUT_S, BACKUP_LOGS_DONE_FLAG); + T2Info("Waiting up to %ds for backup_logs sentinel: %s\n", BACKUP_LOGS_SYNC_TIMEOUT_S, BACKUP_LOGS_DONE_FLAG); bool found = false; char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; @@ -115,8 +113,7 @@ bool waitForBackupLogsDone(void) } if (now.tv_sec >= deadline.tv_sec) { - T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", - BACKUP_LOGS_SYNC_TIMEOUT_S); + T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", BACKUP_LOGS_SYNC_TIMEOUT_S); break; } From 0f107c3b018cbe6a1b791cf5aff41cd0cf719e2e Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Tue, 14 Jul 2026 23:49:43 +0530 Subject: [PATCH 12/36] Delete documentation comment for waitForBackupLogsDone Removed detailed documentation for waitForBackupLogsDone function. --- source/dcautil/dcautil.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 73d8593fe..8eef1b63d 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -36,23 +36,6 @@ #include "legacyutils.h" #include "persistence.h" -/** - * @brief Wait for the backup_logs completion sentinel before grepping PreviousLogs. - * - * Strategy: - * 1. Fast path: sentinel already present → return true immediately. - * 2. Set up inotify on BACKUP_LOGS_DONE_DIR (/tmp) for IN_CREATE | IN_MOVED_TO. - * 3. Re-check after watch is established to close the creation race window. - * 4. select() loop with 2 s heartbeat; exit when sentinel appears or - * BACKUP_LOGS_SYNC_TIMEOUT_S total seconds have elapsed. - * - * This is a **soft gate**: if the function returns false (timeout or inotify - * failure) the caller still proceeds — previous-log grep runs against whatever - * files are present, and a warning is logged. - * - * @return true Sentinel detected within timeout - * @return false Timeout elapsed or sync could not be established (inotify/clock/select failure) - */ bool waitForBackupLogsDone(void) { /* Fast path: sentinel already written by backup_logs */ From e8497e5a51bf6412e8faa41c3995527bea634aa6 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:33:53 +0530 Subject: [PATCH 13/36] Update dcautil.c --- source/dcautil/dcautil.c | 2347 +++++++++++++++++++++++++++++++++----- 1 file changed, 2055 insertions(+), 292 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index bff0211ea..05407e4d8 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -1,378 +1,2141 @@ /* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2019 RDK Management + * Copyright 2020 Comcast Cable Communications Management, LLC * * 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 + * 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. -*/ + * + * SPDX-License-Identifier: Apache-2.0 + */ -#include +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include +#include +#include "test/mocks/SystemMock.h" +#include "test/mocks/FileioMock.h" +#include "test/mocks/rdklogMock.h" + +extern "C" { #include -#include #include -#include +#include +#include #include -#include -#include +#include +#include #include -#include -#include -#include "dca.h" -#include "dcautil.h" +#include +#include +#include "utils/vector.h" +#include "dcautil/dca.h" +#include "dcautil/legacyutils.h" +#include "dcautil/dcautil.h" +#include "dcautil/dcalist.h" +#include "dcautil/rdk_linkedlist.h" #include "telemetry2_0.h" -#include "t2log_wrapper.h" -#include "t2common.h" -#include "legacyutils.h" -#include "persistence.h" +#include "utils/t2log_wrapper.h" +#include "utils/t2common.h" +#include "ccspinterface/busInterface.h" +} + +using namespace std; + +using ::testing::_; +using ::testing::Return; +using ::testing::StrEq; -bool waitForBackupLogsDone(void) +FileMock *g_fileIOMock = NULL; +SystemMock * g_systemMock = NULL; +rdklogMock *m_rdklogMock = NULL; + +// Define timestamp formats with their required lengths and strptime patterns +typedef struct +{ + const char* name; // Format name for logging + const char* pattern; // strptime pattern + size_t required_length; // Minimum characters needed + size_t extract_length; // Characters to extract for parsing +} TimestampFormat; + +#define MAX_TIMESTAMP_LENGTH 24 + +//testing the strnstr function +static const char *strnstr(const char *haystack, const char *needle, size_t len) { - /* Fast path: sentinel already written by backup_logs */ - if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) + if (haystack == NULL || needle == NULL) { - T2Info("backup_logs sentinel %s already present\n", BACKUP_LOGS_DONE_FLAG); - return true; + return NULL; } - - int ifd = inotify_init1(IN_CLOEXEC); - if (ifd < 0) + size_t needle_len = strlen(needle); + if (needle_len == 0) { - T2Error("inotify_init1 failed (errno=%d); proceeding without backup_logs sync\n", errno); - return false; + return haystack; } - int wd = inotify_add_watch(ifd, BACKUP_LOGS_DONE_DIR, IN_CREATE | IN_MOVED_TO); - if (wd < 0) + // Check if search is possible and prevent overflow + if (len < needle_len || len - needle_len > len) { - T2Error("inotify_add_watch on %s failed (errno=%d); proceeding without backup_logs sync\n", BACKUP_LOGS_DONE_DIR, errno); - close(ifd); - return false; + return NULL; } - /* Re-check after watch is set — closes the race window between the first - * access() call and establishing the watch. */ - if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) + // Check minimum length requirements for optimized search + if (needle_len < 4) { - T2Info("backup_logs sentinel detected (race resolved): %s\n", BACKUP_LOGS_DONE_FLAG); - inotify_rm_watch(ifd, wd); - close(ifd); - return true; + // Use simple search for short patterns + for (size_t i = 0; i <= len - needle_len; i++) + { + if (memcmp(haystack + i, needle, needle_len) == 0) + { + return haystack + i; + } + } + return NULL; } - struct timespec deadline; - if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) + size_t skip[256]; + for (size_t i = 0; i < 256; ++i) { - T2Error("clock_gettime failed (errno=%d); proceeding without backup_logs sync\n", errno); - inotify_rm_watch(ifd, wd); - close(ifd); - return false; + skip[i] = needle_len; + } + for (size_t i = 0; i < needle_len - 1; ++i) + { + skip[(unsigned char)needle[i]] = needle_len - i - 1; } - deadline.tv_sec += BACKUP_LOGS_SYNC_TIMEOUT_S; - - T2Info("Waiting up to %ds for backup_logs sentinel: %s\n", BACKUP_LOGS_SYNC_TIMEOUT_S, BACKUP_LOGS_DONE_FLAG); - - bool found = false; - char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; - while (!found) + size_t i = 0; + while (i <= len - needle_len) { - /* Check deadline */ - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) + size_t j = needle_len - 1; + while (j < needle_len && haystack[i + j] == needle[j]) { - T2Error("clock_gettime failed (errno=%d) while waiting for backup_logs sentinel; proceeding without sync\n", errno); - break; + j--; } - if (now.tv_sec >= deadline.tv_sec) + if (j == (size_t) -1) { - T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", BACKUP_LOGS_SYNC_TIMEOUT_S); - break; + return haystack + i; // Match found } + size_t s = skip[(unsigned char)haystack[i + needle_len - 1]]; + i += (s > 0) ? s : 1; + } + return NULL; +} - struct timeval tv = {2, 0}; - fd_set fds; - FD_ZERO(&fds); - FD_SET(ifd, &fds); +TEST(STRNSTR, SAMPLE1) +{ + char *haystack = "fdghfilikeflowershfjkh"; + char *needle = "ilikeflowers"; + EXPECT_STREQ(strnstr(haystack, needle, 22), "ilikeflowershfjkh"); +} - int ret = select(ifd + 1, &fds, NULL, NULL, &tv); - if (ret < 0) - { - if (errno == EINTR) - { - continue; - } - T2Error("select() failed (errno=%d) waiting for backup_logs sentinel\n", errno); - break; - } - if (ret == 0) - { - continue; /* 2 s heartbeat — loop back to check deadline */ - } +TEST(STRNSTR, SAMPLE2) +{ + char *haystack = "fdghfilikehjowershfjkhilikeflowers"; + char *needle = "ilikeflowers"; + EXPECT_STREQ(strnstr(haystack, needle, 34), "ilikeflowers"); +} - ssize_t len = read(ifd, buf, sizeof(buf)); - if (len <= 0) - { - continue; - } +TEST(STRNSTR, SAMPLE3) +{ + char *haystack = "filikeflowershfjkhdghf"; + char *needle = "ilikeflowers"; + EXPECT_STREQ(strnstr(haystack, needle, 22), "ilikeflowershfjkhdghf"); +} - ssize_t offset = 0; - while (offset < len) - { - struct inotify_event *ev = (struct inotify_event *)(buf + offset); - if (ev->len > 0 && strcmp(ev->name, BACKUP_LOGS_DONE_FILENAME) == 0) - { - T2Info("backup_logs sentinel created: %s\n", BACKUP_LOGS_DONE_FLAG); - found = true; - break; - } - offset += (ssize_t)(sizeof(struct inotify_event) + ev->len); - } - } +TEST(STRNSTR, SAMPLE4) +{ + char *haystack = "abcabcabcde"; + char *needle = "abcd"; + EXPECT_STREQ(strnstr(haystack, needle, 11), "abcde"); +} - inotify_rm_watch(ifd, wd); - close(ifd); - return found; +TEST(STRNSTR, SAMPLE5) +{ + char *haystack = "abcabcabcabcabc"; + char *needle = "abcd"; + EXPECT_STREQ(strnstr(haystack, needle, 15), NULL); } -/** - * @brief Get the Grep Results object. Main function called by rest of the consumers. - * - * @param profileName - * @param markerList - * @param grepResultList - * @param isClearSeekMap - * @param check_rotated - * @param customLogPath - * @return T2ERROR - */ +TEST(STRNSTR, SAMPLE6) +{ + char *haystack = "abcdabcabcabcabc"; + char *needle = "abcd"; + EXPECT_STREQ(strnstr(haystack, needle, 15), "abcdabcabcabcabc"); +} -T2ERROR -getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, bool check_rotated, char *customLogPath) +static time_t extractUnixTimestamp(const char* line_start, size_t line_length) { - T2Debug("%s ++in\n", __FUNCTION__); - if(GSP == NULL || markerList == NULL ) + if (!line_start || line_length == 0) { - T2Error("Invalid Args or Args are NULL\n"); - return T2ERROR_FAILURE; + T2Warning("%s: Invalid parameters\n", __FUNCTION__); + return 0; } - if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) + static const TimestampFormat formats[] = { - if (!waitForBackupLogsDone()) + {"ISO 8601", "%Y-%m-%dT%H:%M:%S", 23, 23}, // YYYY-MM-DDTHH:MM:SS.mmm + {"YYMMDD", "%y%m%d-%H:%M:%S", 15, 15}, // YYMMDD-HH:MM:SS + }; + + for (int i = 0; i < 2; i++) + { + const TimestampFormat* fmt = &formats[i]; + + if (line_length < fmt->required_length) { - T2Warning("%s: backup_logs sentinel absent; grepping %s with potentially incomplete data\n", __FUNCTION__, PREVIOUS_LOGS_PATH); + T2Debug("%s: Line too short for %s format (need %zu chars)\n", + __FUNCTION__, fmt->name, fmt->required_length); + continue; } - } - getDCAResultsInVector(*GSP, markerList, check_rotated, customLogPath); - if (isClearSeekMap) - { - int count = (*GSP)->execCounter; - freeGrepSeekProfile(*GSP); - *GSP = createGrepSeekProfile(count); - } - - if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) - { - int fd = open(TELEMETRY_PREVLOGS_DONE_FLAG, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd >= 0) + // Extract timestamp string safely with memcpy + char timestamp_str[MAX_TIMESTAMP_LENGTH] = {0}; + size_t copy_len = fmt->extract_length; + + memcpy(timestamp_str, line_start, copy_len); + timestamp_str[copy_len] = '\0'; + + struct tm tm_time = {0}; + char* result = strptime(timestamp_str, fmt->pattern, &tm_time); + if (result != NULL) { - close(fd); - T2Info("Created telemetry previous-logs sentinel: %s\n", TELEMETRY_PREVLOGS_DONE_FLAG); + tm_time.tm_isdst = -1; + time_t unix_timestamp = mktime(&tm_time); + if (unix_timestamp != -1) + { + T2Debug("%s: Successfully parsed %s timestamp: %s -> Unix: %ld\n", + __FUNCTION__, fmt->name, timestamp_str, (long)unix_timestamp); + return unix_timestamp; + } + else + { + T2Warning("%s: mktime() failed for %s timestamp: %s\n", + __FUNCTION__, fmt->name, timestamp_str); + } } else { - T2Error("%s: Failed to create sentinel %s (errno=%d)\n", - __FUNCTION__, TELEMETRY_PREVLOGS_DONE_FLAG, errno); + T2Debug("%s: %s strptime() failed for: %s\n", __FUNCTION__, fmt->name, timestamp_str); } } - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; + + size_t print_len = (line_length < MAX_TIMESTAMP_LENGTH) ? line_length : MAX_TIMESTAMP_LENGTH; + char debug_str[MAX_TIMESTAMP_LENGTH] = {0}; + memcpy(debug_str, line_start, print_len); + debug_str[print_len] = '\0'; + + T2Debug("%s: Timestamp does not match any supported formats. " + "Supported: 'YYYY-MM-DDTHH:MM:SS.mmm', 'YYMMDD-HH:MM:SS'. " + "Found at line start: '%s'\n", __FUNCTION__, debug_str); + + return 0; } -// dcaFlagReportCompleation this function is used to create legacy DCA Flag DCADONEFLAG -void dcaFlagReportCompleation() +// Testing the extractUnixTimestamp function +TEST(extractUnixTimestamp, VALID_ISO8601_TIMESTAMP) { - T2Debug("%s --in creating flag %s\n", __FUNCTION__, DCADONEFLAG); - FILE *fileCheck = fopen(DCADONEFLAG, "w+"); - if (fileCheck == NULL ) - { - T2Error(" Error in creating the Flag : %s\n", DCADONEFLAG); - } - else - { - fclose(fileCheck); - } - T2Debug("%s --out\n", __FUNCTION__); + // Test ISO 8601 format: YYYY-MM-DDTHH:MM:SS.mmm + const char* timestamp_str = "2025-11-26T14:30:45.123"; + time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); + EXPECT_NE(result, (time_t)0); + + // Verify the parsed timestamp + struct tm *tm_info = localtime(&result); + EXPECT_EQ(tm_info->tm_year + 1900, 2025); + EXPECT_EQ(tm_info->tm_mon + 1, 11); + EXPECT_EQ(tm_info->tm_mday, 26); + EXPECT_EQ(tm_info->tm_hour, 14); + EXPECT_EQ(tm_info->tm_min, 30); + EXPECT_EQ(tm_info->tm_sec, 45); } -# ifdef PERSIST_LOG_MON_REF -T2ERROR saveSeekConfigtoFile(char* profileName, GrepSeekProfile *ProfileSeekMap) +TEST(extractUnixTimestamp, VALID_YYMMDD_TIMESTAMP) { - T2Debug("%s ++in\n", __FUNCTION__); - if(profileName == NULL) - { - T2Error("Profile Name is not available\n"); - return T2ERROR_FAILURE; - } - if(ProfileSeekMap == NULL) - { - T2Error("ProfileSeekMap is NULL\n"); - return T2ERROR_FAILURE; - } - hash_map_t *logfileMap = ProfileSeekMap->logFileSeekMap; - if(logfileMap == NULL) - { - T2Error("logfileMap is NULL\n"); - return T2ERROR_FAILURE; - } + // Test YYMMDD format: YYMMDD-HH:MM:SS + const char* timestamp_str = "251126-14:30:45"; + time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); + EXPECT_NE(result, (time_t)0); + + // Verify the parsed timestamp + struct tm *tm_info = localtime(&result); + EXPECT_EQ(tm_info->tm_year + 1900, 2025); + EXPECT_EQ(tm_info->tm_mon + 1, 11); + EXPECT_EQ(tm_info->tm_mday, 26); + EXPECT_EQ(tm_info->tm_hour, 14); + EXPECT_EQ(tm_info->tm_min, 30); + EXPECT_EQ(tm_info->tm_sec, 45); +} - unsigned int count = (unsigned int) hash_map_count(logfileMap); +TEST(extractUnixTimestamp, INVALID_TIMESTAMP_FORMAT) +{ + // Test with invalid timestamp format + const char* timestamp_str = "invalid-timestamp-format"; + time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); + EXPECT_EQ(result, (time_t)0); +} - cJSON *valArray = cJSON_CreateArray(); - for (unsigned int i = 0; i < count ; i++) - { - char *logFileName = hash_map_lookupKey(logfileMap, i); - LogSeekInfo *seekInfo = (LogSeekInfo *)hash_map_lookup(logfileMap, i); - if (!logFileName || !seekInfo) - { - T2Warning("Skipping entry %u: NULL key or value in logFileSeekMap\n", i); - continue; - } - cJSON *logFileObj = cJSON_CreateObject(); - if (!logFileObj) - { - T2Error("Failed to allocate cJSON object for seek entry\n"); - continue; - } - cJSON_AddNumberToObject(logFileObj, "seekValue", (double)seekInfo->seekValue); - cJSON_AddNumberToObject(logFileObj, "inode", (double)seekInfo->inode); - cJSON *wrapper = cJSON_CreateObject(); - if (!wrapper) - { - T2Error("Failed to allocate cJSON wrapper object\n"); - cJSON_Delete(logFileObj); - continue; - } - cJSON_AddItemToObject(wrapper, logFileName, logFileObj); - cJSON_AddItemToArray(valArray, wrapper); - } - char *jsonReport = cJSON_PrintUnformatted(valArray); - if(T2ERROR_SUCCESS != saveConfigToFile(SEEKFOLDER, profileName, jsonReport)) - { - T2Error("Failed to save config to file\n"); - cJSON_Delete(valArray); - free(jsonReport); - return T2ERROR_FAILURE; - } - T2Debug("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; +TEST(extractUnixTimestamp, NULL_PARAMETERS) +{ + // Test with NULL line_start + time_t result = extractUnixTimestamp(NULL, 20); + EXPECT_EQ(result, (time_t)0); + + // Test with zero length + const char* timestamp_str = "2025-11-26T14:30:45.123"; + result = extractUnixTimestamp(timestamp_str, 0); + EXPECT_EQ(result, (time_t)0); } -T2ERROR loadSavedSeekConfig(char *profileName, GrepSeekProfile *ProfileSeekMap) +TEST(extractUnixTimestamp, SHORT_LINE_LENGTH) { - T2Debug("%s ++in\n", __FUNCTION__); + // Test with line too short for any valid timestamp + const char* timestamp_str = "2025-11-26T14:30:45.123"; + time_t result = extractUnixTimestamp(timestamp_str, 10); // Too short + EXPECT_EQ(result, (time_t)0); +} - if(profileName == NULL) - { - T2Error("Profile Name is not available\n"); - return T2ERROR_FAILURE; - } - int len = strlen(profileName) + strlen(SEEKFOLDER) + 2; - char *seekFile = (char *)malloc(len); - snprintf(seekFile, len, "%s/%s", SEEKFOLDER, profileName); - FILE *file = fopen(seekFile, "rb"); - if(file == NULL) - { - T2Error("Failed to open file\n"); - free(seekFile); - return T2ERROR_FAILURE; - } - fseek(file, 0, SEEK_END); - long fileSize = ftell(file); - fseek(file, 0, SEEK_SET); +TEST(extractUnixTimestamp, EDGE_CASE_MINIMUM_LENGTH) +{ + // Test with minimum length for YYMMDD format (15 characters) + const char* timestamp_str = "251126-14:30:45extra_data"; + time_t result = extractUnixTimestamp(timestamp_str, 15); + EXPECT_NE(result, (time_t)0); +} + +TEST(extractUnixTimestamp, PARTIAL_MATCH) +{ + // Test with partial timestamp that looks valid but isn't complete + const char* timestamp_str = "2025-11-26T"; // Incomplete ISO format + time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); + EXPECT_EQ(result, (time_t)0); +} + +TEST(extractUnixTimestamp, MALFORMED_DATE) +{ + // Test with malformed date values + const char* timestamp_str = "2025-13-32T25:70:70.123"; // Invalid month/day/hour/min/sec + time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); + EXPECT_EQ(result, (time_t)0); +} + +TEST(extractUnixTimestamp, BOUNDARY_YEAR_VALUES) +{ + // Test with boundary year values for YYMMDD format + const char* timestamp_str1 = "001126-14:30:45"; // Year 2000 + time_t result1 = extractUnixTimestamp(timestamp_str1, strlen(timestamp_str1)); + EXPECT_NE(result1, (time_t)0); + + const char* timestamp_str2 = "991126-14:30:45"; // Year 2099 + time_t result2 = extractUnixTimestamp(timestamp_str2, strlen(timestamp_str2)); + EXPECT_NE(result2, (time_t)0); +} + +//dcaproc.c + +TEST(GETPROCUSAGE, MARKER_NULL) +{ + EXPECT_EQ(-1, getProcUsage("telemetry2_0", NULL, NULL)); +} + +TEST(GETPROCUSAGE, PROCESS_NULL) +{ + char* filename = NULL; + filename = strdup("top_log.txt"); + EXPECT_EQ(-1, getProcUsage(NULL, NULL, filename)); + EXPECT_EQ(-1, getProcUsage(NULL, NULL, NULL)); + free(filename); +} + +TEST(GETPROCPIDSTAT, PINFO_NULL) +{ + EXPECT_EQ(0, getProcPidStat(12345, NULL)); +} + +TEST(GETPROCINFO, PMINFO_NULL) +{ + char* filename = NULL; + char* processName = NULL; + processName = strdup("telemetry2_0"); + EXPECT_EQ(0, getProcInfo(NULL, filename)); + + filename = strdup("top_log.txt"); + EXPECT_EQ(0, getProcInfo(NULL, filename)); + + procMemCpuInfo pInfo; + memset(&pInfo, '\0', sizeof(procMemCpuInfo)); + memcpy(pInfo.processName, processName, strlen(processName) + 1); + pInfo.total_instance = 0; + EXPECT_NE(0,getProcInfo(&pInfo, NULL)); + free(filename); + free(processName); +} + +TEST(GETMEMINFO, PMINFO_NULL) +{ + EXPECT_EQ(0, getMemInfo(NULL)); +} + +TEST(GETCPUINFO, PINFO_NULL) +{ + char* filename = NULL; + EXPECT_EQ(0, getCPUInfo(NULL, filename)); + filename = strdup("top_log.txt"); + EXPECT_EQ(0, getCPUInfo(NULL, filename)); + + +} - char *data = malloc(fileSize + 1); - if (data == NULL) + +//dcautil.c +char* gmarker1 = "SYS_INFO_BOOTUP"; +char* dcamarker1 = "SYS_INFO1"; +char* dcamarker2 = "SYS_INFO2"; + +TEST(GETGREPRESULTS, PROFILENAME_NULL) +{ + Vector* markerlist = NULL; + Vector_Create(&markerlist); + Vector_PushBack(markerlist, (void*) strdup(dcamarker1)); + Vector_PushBack(markerlist, (void*) strdup(dcamarker2)); + Vector* grepResultlist = NULL; + Vector_Create(&grepResultlist); + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)1, free); + EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(NULL, markerlist, false, false,"/opt/logs")); + EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(&gsProfile, NULL, false, false,"/opt/logs")); + EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(NULL, markerlist, false, true,"/opt/logs")); + EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(&gsProfile, NULL, false, true,"/opt/logs")); + Vector_Destroy(markerlist, free); + Vector_Destroy(grepResultlist, free); + if(gsProfile->logFileSeekMap) + { + hash_map_destroy(gsProfile->logFileSeekMap, free); + } + free(gsProfile); + grepResultlist = NULL; + markerlist = NULL; +} + +#ifdef PERSIST_LOG_MON_REF +TEST(saveSeekConfigtoFile, profilename_NULL) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)1, free); + EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile(NULL, gsProfile)); + EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile("RDKB_Profile1", NULL)); + if(gsProfile->logFileSeekMap) + { + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + } + EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile("RDKB_Profile1", gsProfile)); +} + +TEST(loadSavedSeekConfig, profilename_NULL) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + EXPECT_EQ(T2ERROR_FAILURE, loadSavedSeekConfig(NULL, gsProfile)); + hash_map_destroy(gsProfile->logFileSeekMap, free); + free(gsProfile); +} + +#endif + + +TEST(GETLOADAVG, MARKER_NULL) +{ + EXPECT_EQ(0, getLoadAvg(NULL)); +} + +TEST(GETLOADAVG, VALID_MARKER) +{ + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + EXPECT_EQ(1, getLoadAvg(topMarker)); + free(topMarker); +} + +TEST(CREATEGREPSEEKPROFILE, SEEKMAPCREATE_CHECK) +{ + GrepSeekProfile *gsProfile = createGrepSeekProfile(0); + EXPECT_NE(gsProfile, nullptr); + EXPECT_NE(gsProfile->logFileSeekMap, nullptr); + EXPECT_EQ(gsProfile->execCounter, 0); + hash_map_destroy(gsProfile->logFileSeekMap, free); + free(gsProfile); +} + +TEST(FREEFREPSEEKPROFILE, SEEKMAPFREE_CHECK) +{ + GrepSeekProfile *gsProfile = createGrepSeekProfile(0); + EXPECT_NE(gsProfile, nullptr); + EXPECT_NE(gsProfile->logFileSeekMap, nullptr); + EXPECT_EQ(gsProfile->execCounter, 0); + + freeGrepSeekProfile(gsProfile); + + // Check if the profile is freed correctly + EXPECT_NE(gsProfile, nullptr); +} + +TEST(CLEARCONFVAL, FREECONFVAL) +{ + clearConfVal(); +} + +//dca.c +TEST(PROCESSTOPPATTERN, VECTOR_NULL) +{ + Vector* topMarkerlist = NULL; + Vector_Create(&topMarkerlist); + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = false; + topMarker->regexParam = NULL; + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 0; + topMarker->paramType = strdup("grep"); + Vector_PushBack(topMarkerlist, (void*) topMarker); + EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); + + EXPECT_EQ(-1, processTopPattern(NULL, topMarkerlist, 1)); + EXPECT_EQ(-1, processTopPattern("RDK_Profile",NULL, 1)); + + Vector_Destroy(topMarkerlist, free); + topMarkerlist = NULL; +} + +TEST(getDCAResultsInVector, markerlist_NULL) +{ + Vector* markerlist = NULL; + Vector_Create(&markerlist); + Vector_PushBack(markerlist, (void*) strdup("SYS_INFO_BOOTUP")); + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)1, free); + EXPECT_EQ(-1, getDCAResultsInVector(NULL, markerlist, true, "/opt/logs/core_log.txt")); + EXPECT_EQ(-1, getDCAResultsInVector(gsProfile, NULL, true, "/opt/logs/core_log.txt")); + // commenting the below case as string will never be passed to this function instead of the vector. + //EXPECT_EQ(-1, getDCAResultsInVector(gsProfile, markerlist, true, "/opt/logs/core_log.txt")); + hash_map_destroy(gsProfile->logFileSeekMap, free); + Vector_Destroy(markerlist, free); +} + +class dcaTestFixture : public ::testing::Test { +protected: + void SetUp() override { - T2Error("Memory allocation failed\n"); - fclose(file); - return T2ERROR_FAILURE; + g_fileIOMock = new FileMock(); + g_systemMock = new SystemMock(); } - fread(data, 1, fileSize, file); - fclose(file); - data[fileSize] = '\0'; - cJSON *json = cJSON_Parse(data); - cJSON *item = NULL; - //GrepSeekProfile *ProfileSeekMap = NULL; - cJSON_ArrayForEach(item, json) + + void TearDown() override { - // Each `item` is an object in the array - if (item->child != NULL) - { - const char *key = item->child->string; - cJSON *value = item->child; + delete g_fileIOMock; + delete g_systemMock; - if (key != NULL) - { - // New format: {"logFileName": {"seekValue": N, "inode": M}} - if (cJSON_IsObject(value)) - { - cJSON *seekVal = cJSON_GetObjectItem(value, "seekValue"); - cJSON *inodeVal = cJSON_GetObjectItem(value, "inode"); - if (cJSON_IsNumber(seekVal)) - { - LogSeekInfo *info = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - if (info) - { - info->seekValue = (long)seekVal->valuedouble; - info->inode = (inodeVal && cJSON_IsNumber(inodeVal)) ? (ino_t)inodeVal->valuedouble : 0; - hash_map_put(ProfileSeekMap->logFileSeekMap, strdup(key), info, free); - } - } - } - // Legacy format: {"logFileName": N} - else if (cJSON_IsNumber(value)) - { - LogSeekInfo *info = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - if (info) - { - info->seekValue = (long)value->valuedouble; - info->inode = 0; // No inode info in legacy format - hash_map_put(ProfileSeekMap->logFileSeekMap, strdup(key), info, free); - } - } - } + g_fileIOMock = nullptr; + g_systemMock = nullptr; + } +}; - } - } - cJSON_Delete(json); - free(data); - free(seekFile); - return T2ERROR_SUCCESS; - T2Debug("%s --out\n", __FUNCTION__); +//dcautil.c +TEST_F(dcaTestFixture, firstBootstatus){ + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(-1)); + + EXPECT_EQ(true, firstBootStatus()); +} + +TEST_F(dcaTestFixture, firstBootstatus_1){ + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, firstBootStatus()); +} + +TEST_F(dcaTestFixture, dcaFlagReportCompleation) +{ + FILE* fp = (FILE*)NULL; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + dcaFlagReportCompleation(); +} + +TEST_F(dcaTestFixture, dcaFlagReportCompleation1) +{ + FILE* fp = (FILE*)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + dcaFlagReportCompleation(); +} + +#ifdef PERSIST_LOG_MON_REF +TEST_F(dcaTestFixture, loadSavedSeekConfig) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + FILE* fp = (FILE*)NULL; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_EQ(T2ERROR_FAILURE, loadSavedSeekConfig("RDK_Profile", gsProfile)); + hash_map_destroy(gsProfile->logFileSeekMap, free); + free(gsProfile); +} + +TEST_F(dcaTestFixture, loadSavedSeekConfig1) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + FILE* fp = (FILE*)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_CALL(*g_fileIOMock, fseek(_,_,_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, ftell(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(T2ERROR_SUCCESS, loadSavedSeekConfig("RDK_Profile", gsProfile)); + hash_map_destroy(gsProfile->logFileSeekMap,free); + free(gsProfile); +} + +TEST_F(dcaTestFixture, saveSeekConfigtoFile) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + long *tempnum; + double val = 123456; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); + FILE* fp = (FILE*)NULL; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile("RDK_Profile", gsProfile)); + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); +} +#endif + +//dcaproc.c + +TEST_F(dcaTestFixture, getProcUsage) +{ + Vector* topMarkerlist = NULL; + Vector_Create(&topMarkerlist); + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = false; + topMarker->regexParam = NULL; + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 0; + topMarker->paramType = strdup("grep"); + topMarker->reportEmptyParam = true; + Vector_PushBack(topMarkerlist, (void*) topMarker); + + char* filename = strdup("/tmp/t2toplog/RDK_Profile"); + + FILE* fp = (FILE*)NULL; + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #else + EXPECT_CALL(*g_fileIOMock, popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #endif + EXPECT_EQ(0, getProcUsage(topMarker->searchString, topMarker, filename)); + Vector_Destroy(topMarkerlist, NULL); + free(filename); +} + +TEST_F(dcaTestFixture, getProcPidStat) +{ + procinfo pinfo; + int fd = (int)0xffffffff; + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(-1)); + ASSERT_EQ(0, getProcPidStat(123, &pinfo)); +} + +TEST_F(dcaTestFixture, getProcPidStat1) +{ + procinfo pinfo; + int fd = (int)0xffffffff; + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, read(_,_,_)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(1) + .WillOnce(Return(0)); + ASSERT_EQ(0, getProcPidStat(123, &pinfo)); +} + +#if !defined(ENABLE_RDKC_SUPPORT) && !defined(ENABLE_RDKB_SUPPORT) +TEST_F(dcaTestFixture, saveTopOutput) +{ + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(0)); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(3) + .WillOnce(Return(0)) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(3) + .WillOnce(Return(0)) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + #endif + EXPECT_EQ(NULL, saveTopOutput("RDK_Profile")); +} + +TEST_F(dcaTestFixture, saveTopOutput1) +{ + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(-1)); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + #endif + EXPECT_EQ(NULL, saveTopOutput("RDK_Profile")); +} + +TEST_F(dcaTestFixture, saveTopOutput2) +{ + char* filename = NULL; + filename = "/tmp/t2toplog_RDK_Profile"; + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(-1)); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + #endif + EXPECT_STREQ(filename, saveTopOutput("RDK_Profile")); +} + +TEST_F(dcaTestFixture, removeTopOutput) +{ + char* filename = NULL; + filename = strdup("/tmp/t2toplog_RDK_Profile"); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(1) + .WillOnce(Return(-1)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(1) + .WillOnce(Return(-1)); + #endif + removeTopOutput(filename); +} + +TEST_F(dcaTestFixture, removeTopOutput1) +{ + char* filename = NULL; + filename = strdup("/tmp/t2toplog_RDK_Profile"); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(1) + .WillOnce(Return(0)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(1) + .WillOnce(Return(0)); + #endif + removeTopOutput(filename); +} + +#else +TEST_F(dcaTestFixture, getTotalCpuTimes) +{ + FILE* mockfp = (FILE *)NULL; + int *totaltime = 0; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(mockfp)); + EXPECT_EQ(0, getTotalCpuTimes(totaltime)); +} + +TEST_F(dcaTestFixture, getTotalCpuTimes1) +{ + FILE* mockfp = (FILE *)0xFFFFFFFF; + int *totaltime = 0; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(mockfp)); + EXPECT_CALL(*g_fileIOMock, fscanf(_,_,_)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_EQ(1, getTotalCpuTimes(totaltime)); +} +#endif + + +//legacyutils.c + +TEST_F(dcaTestFixture, getLoadAvg) +{ + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = false; + topMarker->regexParam = NULL; + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 0; + topMarker->paramType = strdup("grep"); + topMarker->reportEmptyParam = true; + FILE* fp = (FILE*)NULL; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_EQ(0, getLoadAvg(topMarker)); +} + +/*TEST_F(dcaTestFixture, getLoadAvg1) +{ + GrepResult* loadAvg = (GrepResult*) malloc(sizeof(GrepResult)); + loadAvg->markerName = strdup("Load_Average"); + loadAvg->markerValue = strdup("2.15"); + loadAvg->trimParameter = true; + loadAvg->regexParameter = "[0-9]+"; + Vector_PushBack(grepResultList, loadAvg); + FILE* fp = (FILE*)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_EQ(0, getLoadAvg(grepResultList, false, NULL)); + Vector_Destroy(grepResultList, freeGResult); +} +*/ +TEST_F(dcaTestFixture, getLoadAvg2) +{ + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = true; + topMarker->regexParam = "[0-9]+"; + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 0; + topMarker->paramType = strdup("grep"); + topMarker->reportEmptyParam = true; + FILE* fp = (FILE*)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) + .Times(1) + .WillOnce(Return(14)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_EQ(1, getLoadAvg(topMarker)); +} + +TEST_F(dcaTestFixture, initProperties) +{ + char* logpath = NULL; + long int pagesize = 0; + char* perspath = NULL; + FILE* fp = (FILE*)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(2) + .WillOnce(Return(fp)) + .WillOnce(Return(fp)); + EXPECT_CALL(*g_fileIOMock, fscanf(_,_,_)) + .Times(10) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(EOF)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(EOF)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + initProperties(&logpath, &perspath, &pagesize); +} + +//dca.c +#if 0 +//This testcase is not required as we don't pass trim and regex as separate arguments anymore +TEST_F(dcaTestFixture, processTopPattern) +{ + Vector* topMarkerlist = NULL; + Vector_Create(&topMarkerlist); + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = false; + topMarker->regexParam = NULL; + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 0; + topMarker->paramType = strdup("grep"); + topMarker->reportEmptyParam = true; + + TopMarker* topMarker1 = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker1->markerName = strdup("cpu_telemetry2_0"); + topMarker1->searchString = strdup("telemetry2_0"); + topMarker1->trimParam = false; + topMarker1->regexParam = NULL; + topMarker1->logFile = strdup("top_log.txt"); + topMarker1->skipFreq = 0; + topMarker1->paramType = strdup("grep"); + topMarker->reportEmptyParam = true; + Vector_PushBack(topMarkerlist, (void*) topMarker1); + + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(-1)); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(3) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(-1)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(3) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(-1)); + #endif + FILE* fp = (FILE*)NULL; + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #else + EXPECT_CALL(*g_fileIOMock, popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #endif + EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); + Vector_Destroy(topMarkerlist, NULL); } #endif -bool firstBootStatus() +TEST_F(dcaTestFixture, processTopPattern1) +{ + Vector* topMarkerlist = NULL; + Vector_Create(&topMarkerlist); + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = true; + topMarker->regexParam = strdup("[0-9]+"); + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 0; + TopMarker* topMarker1 = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker1, 0, sizeof(TopMarker)); + topMarker1->markerName = strdup("Load_Average"); + topMarker1->searchString = strdup("telemetry2_0"); + topMarker1->trimParam = true; + topMarker1->regexParam = strdup("[0-9]+"); + topMarker1->logFile = strdup("top_log.txt"); + topMarker1->skipFreq = 0; + Vector_PushBack(topMarkerlist, (void*) topMarker1); + Vector_PushBack(topMarkerlist, (void*) topMarker); + EXPECT_CALL(*g_systemMock, access(_,_)) + .Times(1) + .WillOnce(Return(-1)); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(3) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(-1)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(3) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(-1)); + #endif + FILE* fp = (FILE*)NULL; + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #else + EXPECT_CALL(*g_fileIOMock, popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #endif + FILE* fs= (FILE*)0xffffffff; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(fs)); + EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) + .Times(1) + .WillOnce(Return(14)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); + Vector_Destroy(topMarkerlist, freeGMarker); +} + +TEST_F(dcaTestFixture, processTopPattern2) +{ + Vector* topMarkerlist = NULL; + Vector_Create(&topMarkerlist); + TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker, 0, sizeof(TopMarker)); + topMarker->markerName = strdup("cpu_telemetry2_0"); + topMarker->searchString = strdup("telemetry2_0"); + topMarker->trimParam = true; + topMarker->regexParam = strdup("[0-9]+"); + topMarker->logFile = strdup("top_log.txt"); + topMarker->skipFreq = 1; + Vector_PushBack(topMarkerlist, (void*) topMarker); + + TopMarker* topMarker2 = (TopMarker*) malloc(sizeof(TopMarker)); + memset(topMarker2, 0, sizeof(TopMarker)); + topMarker2->markerName = strdup("mem_telemetry2_0"); + topMarker2->searchString = strdup("telemetry2_0"); + topMarker2->trimParam = true; + topMarker2->regexParam = strdup("[0-9]+"); + topMarker2->logFile = strdup("top_log.txt"); + topMarker2->skipFreq = 0; + Vector_PushBack(topMarkerlist, (void*) topMarker2); + + //saveTopoutput + EXPECT_CALL(*g_systemMock, access(_,_)) + .WillRepeatedly(Return(0)); + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_systemMock, v_secure_system(_)) + .Times(4) + .WillOnce(Return(0)) //saveTopoutput + .WillOnce(Return(0)) //removeTopoutput + .WillOnce(Return(0)) //saveTopoutput + .WillOnce(Return(0)); + #else + EXPECT_CALL(*g_systemMock, system(_)) + .Times(4) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + #endif + FILE* fp = (FILE*)0xFFFFFFFF; + //getProcUsage - pidof + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) + .Times(2) + .WillOnce(Return(fp)) + .WillOnce(Return(fp)); + #else + EXPECT_CALL(*g_fileIOMock, popen(_,_)) + .Times(1) + .WillOnce(Return(fp)); + #endif + + #ifdef LIBSYSWRAPPER_BUILD + EXPECT_CALL(*g_fileIOMock, v_secure_pclose(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + #else + EXPECT_CALL(*g_fileIOMock, pclose(_)) + .Times(1) + .WillOnce(Return(0)); + #endif + + // getCPUInfo reads TOPTEMP file directly via fopen + FILE* topfp = (FILE*)0xEEEEEEEE; + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(1) + .WillOnce(Return(topfp)); + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(1) + .WillOnce(Return(0)); + + //getMEMinfo + EXPECT_CALL(*g_fileIOMock, read(_,_,_)) + .WillOnce([](int fd, void* buf, size_t count) { + const char *stat_str = "7396 (telemetry2_0) S 1 7396 7396 0 -1 1077936448 17297 316924 7 544 410 610 1888 258 20 0 14 0 2373301 1024380928 3425 18446744073709551615 94059930939392 94059930943425 140725223263616 0 0 0 0 4096 268454400 0 0 0 17 3 0 0 0 0 0 94059930950768 94059930951697 94060511973376 140725223266476 140725223266504 140725223266504 140725223268316 0"; + size_t len = strlen(stat_str); + size_t to_copy = len < count ? len : count; + memcpy(buf, stat_str, to_copy); + return to_copy; + }); + + //getprocpidstat + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(1) + .WillOnce(Return(0)); + //getCPUInfo + EXPECT_CALL(*g_fileIOMock, fgets(_,_,_)) + .WillOnce([](char* buf, size_t size, FILE* stream) { + const char* test_line = "2268 root 20 0 831m 66m 20m S 27 13.1 491:06.82 telemetry2_0\n"; + strncpy(buf, test_line, size-1); + buf[size-1] = '\0'; + return buf; + }) + .WillOnce(Return((char*)NULL)); + EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); + Vector_Destroy(topMarkerlist, freeGMarker); +} + +TEST_F(dcaTestFixture, getDCAResultsInVector_1) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + memset(marker, 0, sizeof(GrepMarker)); + marker->markerName = strdup("SYS_INFO_TEST"); + marker->searchString = strdup("Test Marker"); + marker->trimParam = true; + marker->regexParam = strdup("[0-9]+"); + marker->logFile = strdup("Consolelog.txt.0"); + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->mType = MTYPE_COUNTER; + marker->u.count = 0; + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + //freeFileDescriptor + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + + //getLogFileDescriptor + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(2) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1235; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1300; // Set file size + return 0; // Success + }); + + //getDeltainmmapsearch + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) + .Times(1) + .WillOnce(Return(1300)); + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(1) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "This is a Test Marker with value 1234 in the log file.\nAnother line without the marker.\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, NULL); +} + +TEST_F(dcaTestFixture, getDCAResultsInVector_2) +{ + + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + memset(marker, 0, sizeof(GrepMarker)); + marker->markerName = strdup("SYS_INFO_TEST"); + marker->searchString = strdup("temp:"); + marker->trimParam = true; + marker->regexParam = strdup("[0-9]+"); + marker->logFile = strdup("Consolelog.txt.0"); + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->mType = MTYPE_ABSOLUTE; + marker->u.markerValue = NULL; + marker->u.count = 0; + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + //freeFileDescriptor + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + + //getLogFileDescriptor + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(2) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1300; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1300; // Set file size + return 0; // Success + }); + + //getDeltainmmapsearch + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) + .Times(1) + .WillOnce(Return(1300)); + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(1) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "This is a Test Marker with value temp:1245.\nAnother line without the marker.\n Another line with marker temp:2345\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + + EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, freeGMarker); +} + +TEST_F(dcaTestFixture, getDCAResultsInVector_3) +{ + + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 1; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + memset(marker, 0, sizeof(GrepMarker)); + marker->markerName = strdup("SYS_INFO_TEST"); + marker->searchString = strdup("Test Marker"); + marker->trimParam = true; + marker->u.markerValue = NULL; + marker->u.accumulatedValues = NULL; + marker->regexParam = strdup("[0-9]+"); + marker->logFile = strdup("Consolelog.txt.0"); + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->mType = MTYPE_COUNTER; + marker->u.count = 0; + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + + //freeFileDescriptor + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(4) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + + //getLogFileDescriptor + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(4) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1235; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1235; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1000; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1000; // Set file size + return 0; // Success + }); + + //getDeltainmmapsearch + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) + .Times(2) + .WillOnce(Return(1235)) + .WillOnce(Return(1000)); + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(2) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "This is a Test Marker with value 1234 in the log file.\nAnother line without the marker.\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "This is with value Test:1250 in the log file.\nAnother line without the marker.\nThe line with Test Markeris found\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + + EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, freeGMarker); +} + + +TEST_F(dcaTestFixture, getDCAResultsInVector_Accum) { - T2Debug("%s ++in\n", __FUNCTION__); - bool status = true; - if(access(BOOTFLAG, F_OK) != -1) + + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 1; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + memset(marker, 0, sizeof(GrepMarker)); + marker->markerName = strdup("SYS_INFO_TEST"); + marker->searchString = strdup("Test Marker"); + marker->trimParam = true; + marker->u.markerValue = NULL; + marker->u.count = 0; + marker->mType = MTYPE_ACCUMULATE; + marker->reportTimestampParam = REPORTTIMESTAMP_UNIXEPOCH; + Vector_Create(&marker->u.accumulatedValues); + if(marker->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) { - status = false; + Vector_Create(&marker->accumulatedTimestamp); } - T2Debug("%s --out\n", __FUNCTION__); - return status; + marker->regexParam = strdup("[0-9]+"); + marker->logFile = strdup("Consolelog.txt.0"); + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + //freeFileDescriptor + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .WillRepeatedly(Return(0)); + + //getLogFileDescriptor + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .WillRepeatedly(Return(0)); + + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(testing::AtMost(4)) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1235; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1235; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1000; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1000; // Set file size + return 0; // Success + }); + //getDeltainmmapsearch + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .WillRepeatedly(Return(0)); + EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) + .Times(testing::AtMost(2)) + .WillOnce(Return(1235)) + .WillOnce(Return(1000)); + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(testing::AtMost(2)) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "2025-10-26T14:40:55.001Z This is a Test Marker with value 1234 in the log file.\n2025-10-26T14:40:55.001Z Another line without the marker.\n2025-10-26T14:40:55.001Z Line with Test Marker"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "2025-10-26T14:40:55.001Z This is with value Test:1250 in the log file.\n2025-10-26T14:40:55.001Z Another line without the marker.\n2025-10-26T14:40:55.001Z The line with Test Markeris found\n2025-10-26T14:40:55.001Z Line with 0 vale for Test Marker0"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); + + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, freeGMarker); +} + +TEST_F(dcaTestFixture, T2InitProperties) +{ + EXPECT_CALL(*g_fileIOMock, fopen(_,_)) + .Times(2) + .WillOnce(Return((FILE*)0XFFFFFFFF)) + .WillOnce(Return((FILE*)0XFFFFFFFF)); + EXPECT_CALL(*g_fileIOMock, fscanf(_,_,_)) + .Times(2) + .WillOnce(Return(EOF)) + .WillOnce(Return(EOF)); + + EXPECT_CALL(*g_fileIOMock, fclose(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + + T2InitProperties(); +} + +//dcautil.c + +TEST_F(dcaTestFixture, getGrepResults_success) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 0; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + marker->markerName = strdup("SYS_INFO_TEST"); + marker->searchString = strdup("temp:"); + marker->trimParam = true; + marker->regexParam = strdup("[0-9]+"); + marker->logFile = strdup("Consolelog.txt.0"); + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->mType = MTYPE_ABSOLUTE; + marker->u.markerValue = NULL; + marker->u.count = 0; + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + //freeFileDescriptor + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(2) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + + //getLogFileDescriptor + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(2) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1300; // Set file size + return 0; // Success + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 1300; // Set file size + return 0; // Success + }); + + //getDeltainmmapsearch + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) + .Times(1) + .WillOnce(Return(1300)); + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(1) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + const char* test_str = "This is a Test Marker with value temp:1245.\nAnother line without the marker.\n Another line with marker temp:2345\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + + EXPECT_EQ(T2ERROR_SUCCESS, getGrepResults(&gsProfile, vecMarkerList, true, true, "/opt/logs")); + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, freeGMarker); +} + +// waitForBackupLogsDone L1 tests + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelAlreadyPresent) +{ + // Fast path: access() returns 0 meaning sentinel file exists + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyInitFails) +{ + // access() returns -1 (sentinel not present), inotify_init1 fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(-1)); + + EXPECT_EQ(false, waitForBackupLogsDone()); } + +TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyAddWatchFails) +{ + // access() returns -1, inotify_init1 succeeds, inotify_add_watch fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_RaceResolved) +{ + // First access() returns -1, inotify setup succeeds, second access() returns 0 (race resolved) + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFails) +{ + // access() returns -1 both times, inotify setup succeeds, clock_gettime fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_Timeout) +{ + // Sentinel never appears, select returns 0 (timeout heartbeat), deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + + // First clock_gettime sets the deadline (tv_sec=100) + // Second clock_gettime returns past deadline (tv_sec >= 100 + BACKUP_LOGS_SYNC_TIMEOUT_S) + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectFails) +{ + // select() fails with non-EINTR error + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline yet + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { + errno = EBADF; + return -1; + }); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectEINTR) +{ + // select() returns EINTR, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; // Past deadline + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { + errno = EINTR; + return -1; + }); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelDetectedViaInotify) +{ + // Sentinel detected via inotify event + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); // Data available to read + + // Construct a fake inotify_event with the sentinel filename + struct inotify_event fake_event; + fake_event.wd = 1; + fake_event.mask = IN_CREATE; + fake_event.cookie = 0; + fake_event.len = strlen(BACKUP_LOGS_DONE_FILENAME) + 1; + + // Build the buffer: struct inotify_event + filename (null-terminated) + size_t event_size = sizeof(struct inotify_event) + fake_event.len; + char *event_buf = (char *)malloc(event_size); + memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); + memcpy(event_buf + sizeof(struct inotify_event), BACKUP_LOGS_DONE_FILENAME, fake_event.len); + + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { + size_t copy_size = (event_size < count) ? event_size : count; + memcpy(buf, event_buf, copy_size); + return (ssize_t)copy_size; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); + free(event_buf); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_ReadReturnsZero) +{ + // select() returns data ready, but read() returns 0 — loop back, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_UnrelatedInotifyEvent) +{ + // An inotify event for a different file, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); + + // Construct an inotify event for a different filename + const char *other_file = "other_file.txt"; + struct inotify_event fake_event; + fake_event.wd = 1; + fake_event.mask = IN_CREATE; + fake_event.cookie = 0; + fake_event.len = strlen(other_file) + 1; + + size_t event_size = sizeof(struct inotify_event) + fake_event.len; + char *event_buf = (char *)malloc(event_size); + memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); + memcpy(event_buf + sizeof(struct inotify_event), other_file, fake_event.len); + + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { + size_t copy_size = (event_size < count) ? event_size : count; + memcpy(buf, event_buf, copy_size); + return (ssize_t)copy_size; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); + free(event_buf); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFailsInLoop) +{ + // clock_gettime succeeds initially but fails inside the while loop + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce(Return(-1)); // Fails in the loop + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +#ifdef GTEST_ENABLE +extern "C" { +typedef const char *(*strnstrFunc)(const char *, const char *, size_t); +strnstrFunc strnstrFuncCallback(void); +typedef time_t (*extractUnixTimestampFunc)(const char*, size_t); +extractUnixTimestampFunc extractUnixTimestampFuncCallback(void); +typedef T2ERROR (*updateLogSeekFunc)(hash_map_t *, const char *, const long); +updateLogSeekFunc updateLogSeekFuncCallback(void); +} +TEST(StaticStrnstrFunc, CoversMainBranches) +{ + auto fn = strnstrFuncCallback(); + ASSERT_NE(fn, nullptr); + + // NULL haystack or needle should return NULL + EXPECT_EQ(fn(NULL, "needle", 10), nullptr); + EXPECT_EQ(fn("haystack", NULL, 10), nullptr); + + // Empty needle returns haystack + const char* h1 = "haystack"; + EXPECT_EQ(fn(h1, "", 8), h1); + + // len < needle_len or overflow returns NULL + EXPECT_EQ(fn("foo", "foobar", 3), nullptr); + // May not always trigger overflow branch but included for completeness + // EXPECT_EQ(fn("foo", "foo", (size_t)-1), nullptr); + + // needle of length < 4 triggers simple search branch: found and not found + const char* h2 = "abcdef"; + EXPECT_EQ(fn(h2, "c", 6), h2 + 2); // found at position 2 + EXPECT_EQ(fn(h2, "e", 4), nullptr); // not found in first 4 chars + + // Optionally: COVER the optimized/longer path if you want (needle_len >= 4) + // This depends on your actual implementation for longer patterns +} +TEST(StaticExtractUnixTimestampFunc, CoversBranches) +{ + auto fn = extractUnixTimestampFuncCallback(); + ASSERT_NE(fn, nullptr); + + // NULL pointer or zero length hit early branch + EXPECT_EQ(fn(NULL, 12), (time_t)0); + EXPECT_EQ(fn("foo", 0), (time_t)0); + + // ISO 8601 - "2023-05-30T14:15:16.123 extra" + const char* iso = "2023-05-30T14:15:16.123 extra text"; + struct tm tm1 {}; + tm1.tm_year = 2023 - 1900; // years since 1900 + tm1.tm_mon = 5 - 1; // months since January + tm1.tm_mday = 30; + tm1.tm_hour = 14; + tm1.tm_min = 15; + tm1.tm_sec = 16; + time_t expected_iso = mktime(&tm1); + EXPECT_EQ(fn(iso, strlen(iso)), expected_iso); + + // YYMMDD-HH:MM:SS - "230530-14:15:16 something" + const char* yymmdd = "230530-14:15:16 something"; + struct tm tm2 {}; + tm2.tm_year = 2023 - 1900; + tm2.tm_mon = 5 - 1; + tm2.tm_mday = 30; + tm2.tm_hour = 14; + tm2.tm_min = 15; + tm2.tm_sec = 16; + time_t expected_yymmdd = mktime(&tm2); + EXPECT_EQ(fn(yymmdd, strlen(yymmdd)), expected_yymmdd); + + // Not matching format (should return 0) + EXPECT_EQ(fn("1656606000 extra text", strlen("1656606000 extra text")), (time_t)0); +} +TEST(StaticUpdateLogSeekFunc, CoversNullBranches) +{ + auto fn = updateLogSeekFuncCallback(); + ASSERT_NE(fn, nullptr); + + // First branch: logSeekMap == NULL + EXPECT_EQ(fn(NULL, "dummy.log", 100), T2ERROR_FAILURE); + + // Second branch: logFileName == NULL + hash_map_t dummyMap; + EXPECT_EQ(fn(&dummyMap, NULL, 100), T2ERROR_FAILURE); + + // Additional test for a stub/empty map and filename to reach further code + // (Will continue past the NULL check; optionally extend to later logic in the function) +} +#endif From 3d2470fcd3d02d58b70502e7c5b8c7dcacd6c445 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:35:13 +0530 Subject: [PATCH 14/36] Update SystemMock.cpp --- source/test/mocks/SystemMock.cpp | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/source/test/mocks/SystemMock.cpp b/source/test/mocks/SystemMock.cpp index d6a39397c..ee0b5f679 100644 --- a/source/test/mocks/SystemMock.cpp +++ b/source/test/mocks/SystemMock.cpp @@ -24,11 +24,21 @@ typedef int (*system_ptr) (const char * cmd); typedef int (*unlink_ptr) (const char * str); typedef int (*access_ptr) (const char * pathname, int mode); typedef int (*remove_ptr) (const char * pathname); +typedef int (*inotify_init1_ptr) (int flags); +typedef int (*inotify_add_watch_ptr) (int fd, const char *pathname, uint32_t mask); +typedef int (*inotify_rm_watch_ptr) (int fd, int wd); +typedef int (*clock_gettime_ptr) (clockid_t clk_id, struct timespec *tp); +typedef int (*select_ptr) (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); system_ptr system_func = (system_ptr) dlsym(RTLD_NEXT, "system"); unlink_ptr unlink_func = (unlink_ptr) dlsym(RTLD_NEXT, "unlink"); access_ptr access_func = (access_ptr) dlsym(RTLD_NEXT, "access"); remove_ptr remove_func = (remove_ptr) dlsym(RTLD_NEXT, "remove"); +inotify_init1_ptr inotify_init1_func = (inotify_init1_ptr) dlsym(RTLD_NEXT, "inotify_init1"); +inotify_add_watch_ptr inotify_add_watch_func = (inotify_add_watch_ptr) dlsym(RTLD_NEXT, "inotify_add_watch"); +inotify_rm_watch_ptr inotify_rm_watch_func = (inotify_rm_watch_ptr) dlsym(RTLD_NEXT, "inotify_rm_watch"); +clock_gettime_ptr clock_gettime_func = (clock_gettime_ptr) dlsym(RTLD_NEXT, "clock_gettime"); +select_ptr select_func = (select_ptr) dlsym(RTLD_NEXT, "select"); // Mock Method extern "C" int system(const char * cmd) @@ -65,4 +75,49 @@ extern "C" int remove(const char *pathname) return remove_func(pathname); } return g_systemMock->remove(pathname); +} + +extern "C" int inotify_init1(int flags) +{ + if (!g_systemMock) + { + return inotify_init1_func(flags); + } + return g_systemMock->inotify_init1(flags); +} + +extern "C" int inotify_add_watch(int fd, const char *pathname, uint32_t mask) +{ + if (!g_systemMock) + { + return inotify_add_watch_func(fd, pathname, mask); + } + return g_systemMock->inotify_add_watch(fd, pathname, mask); +} + +extern "C" int inotify_rm_watch(int fd, int wd) +{ + if (!g_systemMock) + { + return inotify_rm_watch_func(fd, wd); + } + return g_systemMock->inotify_rm_watch(fd, wd); +} + +extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + if (!g_systemMock) + { + return clock_gettime_func(clk_id, tp); + } + return g_systemMock->clock_gettime(clk_id, tp); +} + +extern "C" int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + if (!g_systemMock) + { + return select_func(nfds, readfds, writefds, exceptfds, timeout); + } + return g_systemMock->select(nfds, readfds, writefds, exceptfds, timeout); } From 65b3cf57c497aa8e9e96c7020dcf565e50b3a043 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:35:43 +0530 Subject: [PATCH 15/36] Update SystemMock.h --- source/test/mocks/SystemMock.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source/test/mocks/SystemMock.h b/source/test/mocks/SystemMock.h index 0c9ce8f8a..e32b3e376 100644 --- a/source/test/mocks/SystemMock.h +++ b/source/test/mocks/SystemMock.h @@ -19,7 +19,9 @@ #include #include - +#include +#include +#include #include "telemetry2_0.h" @@ -30,6 +32,11 @@ class SystemMock MOCK_METHOD(int, unlink, (const char *str), ()); MOCK_METHOD(int, access, (const char *pathname, int mode), ()); MOCK_METHOD(int, remove, (const char *pathname), ()); + MOCK_METHOD(int, inotify_init1, (int flags), ()); + MOCK_METHOD(int, inotify_add_watch, (int fd, const char *pathname, uint32_t mask), ()); + MOCK_METHOD(int, inotify_rm_watch, (int fd, int wd), ()); + MOCK_METHOD(int, clock_gettime, (clockid_t clk_id, struct timespec *tp), ()); + MOCK_METHOD(int, select, (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout), ()); }; extern SystemMock* g_systemMock; @@ -38,3 +45,8 @@ extern "C" int system(const char* cmd); extern "C" int unlink(const char* str); extern "C" int access(const char* pathname, int mode); extern "C" int remove(const char* pathname); +extern "C" int inotify_init1(int flags); +extern "C" int inotify_add_watch(int fd, const char *pathname, uint32_t mask); +extern "C" int inotify_rm_watch(int fd, int wd); +extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp); +extern "C" int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); From dcfeff2eebce33ce3ce4b9413d81dabe8701127f Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:43:26 +0530 Subject: [PATCH 16/36] Update dcautil.c --- source/dcautil/dcautil.c | 2341 +++++--------------------------------- 1 file changed, 286 insertions(+), 2055 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 05407e4d8..64e830561 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -1,2141 +1,372 @@ /* - * Copyright 2020 Comcast Cable Communications Management, LLC + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2019 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 + * 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include -#include -#include "test/mocks/SystemMock.h" -#include "test/mocks/FileioMock.h" -#include "test/mocks/rdklogMock.h" +*/ -extern "C" { +#include #include +#include #include -#include -#include +#include #include -#include -#include +#include +#include #include -#include -#include -#include "utils/vector.h" -#include "dcautil/dca.h" -#include "dcautil/legacyutils.h" -#include "dcautil/dcautil.h" -#include "dcautil/dcalist.h" -#include "dcautil/rdk_linkedlist.h" +#include +#include +#include "dca.h" +#include "dcautil.h" #include "telemetry2_0.h" -#include "utils/t2log_wrapper.h" -#include "utils/t2common.h" -#include "ccspinterface/busInterface.h" -} - -using namespace std; - -using ::testing::_; -using ::testing::Return; -using ::testing::StrEq; +#include "t2log_wrapper.h" +#include "t2common.h" +#include "legacyutils.h" +#include "persistence.h" -FileMock *g_fileIOMock = NULL; -SystemMock * g_systemMock = NULL; -rdklogMock *m_rdklogMock = NULL; - -// Define timestamp formats with their required lengths and strptime patterns -typedef struct -{ - const char* name; // Format name for logging - const char* pattern; // strptime pattern - size_t required_length; // Minimum characters needed - size_t extract_length; // Characters to extract for parsing -} TimestampFormat; - -#define MAX_TIMESTAMP_LENGTH 24 - -//testing the strnstr function -static const char *strnstr(const char *haystack, const char *needle, size_t len) +/** + * @brief Wait for the backup_logs completion sentinel before grepping PreviousLogs. + * + * Strategy: + * 1. Fast path: sentinel already present → return true immediately. + * 2. Set up inotify on BACKUP_LOGS_DONE_DIR (/tmp) for IN_CREATE | IN_MOVED_TO. + * 3. Re-check after watch is established to close the creation race window. + * 4. select() loop with 2 s heartbeat; exit when sentinel appears or + * BACKUP_LOGS_SYNC_TIMEOUT_S total seconds have elapsed. + * + * This is a **soft gate**: if the function returns false (timeout or inotify + * failure) the caller still proceeds — previous-log grep runs against whatever + * files are present, and a warning is logged. + * + * @return true Sentinel detected within timeout + * @return false Timeout elapsed or sync could not be established (inotify/clock/select failure) + */ +bool waitForBackupLogsDone(void) { - if (haystack == NULL || needle == NULL) - { - return NULL; - } - size_t needle_len = strlen(needle); - if (needle_len == 0) + /* Fast path: sentinel already written by backup_logs */ + if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) { - return haystack; + T2Info("backup_logs sentinel %s already present\n", BACKUP_LOGS_DONE_FLAG); + return true; } - // Check if search is possible and prevent overflow - if (len < needle_len || len - needle_len > len) + int ifd = inotify_init1(IN_CLOEXEC); + if (ifd < 0) { - return NULL; + T2Error("inotify_init1 failed (errno=%d); proceeding without backup_logs sync\n", errno); + return false; } - // Check minimum length requirements for optimized search - if (needle_len < 4) + int wd = inotify_add_watch(ifd, BACKUP_LOGS_DONE_DIR, IN_CREATE | IN_MOVED_TO); + if (wd < 0) { - // Use simple search for short patterns - for (size_t i = 0; i <= len - needle_len; i++) - { - if (memcmp(haystack + i, needle, needle_len) == 0) - { - return haystack + i; - } - } - return NULL; + T2Error("inotify_add_watch on %s failed (errno=%d); proceeding without backup_logs sync\n", + BACKUP_LOGS_DONE_DIR, errno); + close(ifd); + return false; } - size_t skip[256]; - for (size_t i = 0; i < 256; ++i) + /* Re-check after watch is set — closes the race window between the first + * access() call and establishing the watch. */ + if (access(BACKUP_LOGS_DONE_FLAG, F_OK) == 0) { - skip[i] = needle_len; + T2Info("backup_logs sentinel detected (race resolved): %s\n", BACKUP_LOGS_DONE_FLAG); + inotify_rm_watch(ifd, wd); + close(ifd); + return true; } - for (size_t i = 0; i < needle_len - 1; ++i) + + struct timespec deadline; + if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0) { - skip[(unsigned char)needle[i]] = needle_len - i - 1; + T2Error("clock_gettime failed (errno=%d); proceeding without backup_logs sync\n", errno); + inotify_rm_watch(ifd, wd); + close(ifd); + return false; } + deadline.tv_sec += BACKUP_LOGS_SYNC_TIMEOUT_S; - size_t i = 0; - while (i <= len - needle_len) + T2Info("Waiting up to %ds for backup_logs sentinel: %s\n", + BACKUP_LOGS_SYNC_TIMEOUT_S, BACKUP_LOGS_DONE_FLAG); + + bool found = false; + char buf[sizeof(struct inotify_event) + NAME_MAX + 1]; + + while (!found) { - size_t j = needle_len - 1; - while (j < needle_len && haystack[i + j] == needle[j]) + /* Check deadline */ + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) { - j--; + T2Error("clock_gettime failed (errno=%d) while waiting for backup_logs sentinel; proceeding without sync\n", errno); + break; } - if (j == (size_t) -1) + if (now.tv_sec >= deadline.tv_sec) { - return haystack + i; // Match found + T2Warning("backup_logs sentinel not present after %ds; proceeding without sync\n", + BACKUP_LOGS_SYNC_TIMEOUT_S); + break; } - size_t s = skip[(unsigned char)haystack[i + needle_len - 1]]; - i += (s > 0) ? s : 1; - } - return NULL; -} -TEST(STRNSTR, SAMPLE1) -{ - char *haystack = "fdghfilikeflowershfjkh"; - char *needle = "ilikeflowers"; - EXPECT_STREQ(strnstr(haystack, needle, 22), "ilikeflowershfjkh"); -} + struct timeval tv = {2, 0}; + fd_set fds; + FD_ZERO(&fds); + FD_SET(ifd, &fds); -TEST(STRNSTR, SAMPLE2) -{ - char *haystack = "fdghfilikehjowershfjkhilikeflowers"; - char *needle = "ilikeflowers"; - EXPECT_STREQ(strnstr(haystack, needle, 34), "ilikeflowers"); -} + int ret = select(ifd + 1, &fds, NULL, NULL, &tv); + if (ret < 0) + { + if (errno == EINTR) + { + continue; + } + T2Error("select() failed (errno=%d) waiting for backup_logs sentinel\n", errno); + break; + } + if (ret == 0) + { + continue; /* 2 s heartbeat — loop back to check deadline */ + } -TEST(STRNSTR, SAMPLE3) -{ - char *haystack = "filikeflowershfjkhdghf"; - char *needle = "ilikeflowers"; - EXPECT_STREQ(strnstr(haystack, needle, 22), "ilikeflowershfjkhdghf"); -} + ssize_t len = read(ifd, buf, sizeof(buf)); + if (len <= 0) + { + continue; + } -TEST(STRNSTR, SAMPLE4) -{ - char *haystack = "abcabcabcde"; - char *needle = "abcd"; - EXPECT_STREQ(strnstr(haystack, needle, 11), "abcde"); -} + ssize_t offset = 0; + while (offset < len) + { + struct inotify_event *ev = (struct inotify_event *)(buf + offset); + if (ev->len > 0 && strcmp(ev->name, BACKUP_LOGS_DONE_FILENAME) == 0) + { + T2Info("backup_logs sentinel created: %s\n", BACKUP_LOGS_DONE_FLAG); + found = true; + break; + } + offset += (ssize_t)(sizeof(struct inotify_event) + ev->len); + } + } -TEST(STRNSTR, SAMPLE5) -{ - char *haystack = "abcabcabcabcabc"; - char *needle = "abcd"; - EXPECT_STREQ(strnstr(haystack, needle, 15), NULL); + inotify_rm_watch(ifd, wd); + close(ifd); + return found; } -TEST(STRNSTR, SAMPLE6) -{ - char *haystack = "abcdabcabcabcabc"; - char *needle = "abcd"; - EXPECT_STREQ(strnstr(haystack, needle, 15), "abcdabcabcabcabc"); -} +/** + * @brief Get the Grep Results object. Main function called by rest of the consumers. + * + * @param profileName + * @param markerList + * @param grepResultList + * @param isClearSeekMap + * @param check_rotated + * @param customLogPath + * @return T2ERROR + */ -static time_t extractUnixTimestamp(const char* line_start, size_t line_length) +T2ERROR +getGrepResults (GrepSeekProfile **GSP, Vector *markerList, bool isClearSeekMap, bool check_rotated, char *customLogPath) { - if (!line_start || line_length == 0) + T2Debug("%s ++in\n", __FUNCTION__); + if(GSP == NULL || markerList == NULL ) { - T2Warning("%s: Invalid parameters\n", __FUNCTION__); - return 0; + T2Error("Invalid Args or Args are NULL\n"); + return T2ERROR_FAILURE; } - static const TimestampFormat formats[] = - { - {"ISO 8601", "%Y-%m-%dT%H:%M:%S", 23, 23}, // YYYY-MM-DDTHH:MM:SS.mmm - {"YYMMDD", "%y%m%d-%H:%M:%S", 15, 15}, // YYMMDD-HH:MM:SS - }; - - for (int i = 0; i < 2; i++) + /* Synchronize with backup_logs before grepping the previous-log directory. + * backup_logs populates PREVIOUS_LOGS_PATH; reading it before the write is + * complete yields incomplete or empty results. This is a soft gate — if the + * sentinel does not appear within BACKUP_LOGS_SYNC_TIMEOUT_S seconds we + * still proceed so telemetry is never permanently blocked. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) { - const TimestampFormat* fmt = &formats[i]; - - if (line_length < fmt->required_length) + if (!waitForBackupLogsDone()) { - T2Debug("%s: Line too short for %s format (need %zu chars)\n", - __FUNCTION__, fmt->name, fmt->required_length); - continue; + T2Warning("%s: backup_logs sentinel absent; grepping %s with potentially incomplete data\n", + __FUNCTION__, PREVIOUS_LOGS_PATH); } + } - // Extract timestamp string safely with memcpy - char timestamp_str[MAX_TIMESTAMP_LENGTH] = {0}; - size_t copy_len = fmt->extract_length; - - memcpy(timestamp_str, line_start, copy_len); - timestamp_str[copy_len] = '\0'; - - struct tm tm_time = {0}; - char* result = strptime(timestamp_str, fmt->pattern, &tm_time); - if (result != NULL) + getDCAResultsInVector(*GSP, markerList, check_rotated, customLogPath); + if (isClearSeekMap) + { + int count = (*GSP)->execCounter; + freeGrepSeekProfile(*GSP); + *GSP = createGrepSeekProfile(count); + } + /* Signal that telemetry previous-log grep is complete. + * Downstream consumers (e.g. uploadSTBLogs) wait for this sentinel + * before starting the log upload to avoid incomplete telemetry data. */ + if (customLogPath != NULL && strcmp(customLogPath, PREVIOUS_LOGS_PATH) == 0) + { + int fd = open(TELEMETRY_PREVLOGS_DONE_FLAG, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd >= 0) { - tm_time.tm_isdst = -1; - time_t unix_timestamp = mktime(&tm_time); - if (unix_timestamp != -1) - { - T2Debug("%s: Successfully parsed %s timestamp: %s -> Unix: %ld\n", - __FUNCTION__, fmt->name, timestamp_str, (long)unix_timestamp); - return unix_timestamp; - } - else - { - T2Warning("%s: mktime() failed for %s timestamp: %s\n", - __FUNCTION__, fmt->name, timestamp_str); - } + close(fd); + T2Info("Created telemetry previous-logs sentinel: %s\n", TELEMETRY_PREVLOGS_DONE_FLAG); } else { - T2Debug("%s: %s strptime() failed for: %s\n", __FUNCTION__, fmt->name, timestamp_str); + T2Error("%s: Failed to create sentinel %s (errno=%d)\n", + __FUNCTION__, TELEMETRY_PREVLOGS_DONE_FLAG, errno); } } - - size_t print_len = (line_length < MAX_TIMESTAMP_LENGTH) ? line_length : MAX_TIMESTAMP_LENGTH; - char debug_str[MAX_TIMESTAMP_LENGTH] = {0}; - memcpy(debug_str, line_start, print_len); - debug_str[print_len] = '\0'; - - T2Debug("%s: Timestamp does not match any supported formats. " - "Supported: 'YYYY-MM-DDTHH:MM:SS.mmm', 'YYMMDD-HH:MM:SS'. " - "Found at line start: '%s'\n", __FUNCTION__, debug_str); - - return 0; -} - -// Testing the extractUnixTimestamp function -TEST(extractUnixTimestamp, VALID_ISO8601_TIMESTAMP) -{ - // Test ISO 8601 format: YYYY-MM-DDTHH:MM:SS.mmm - const char* timestamp_str = "2025-11-26T14:30:45.123"; - time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); - EXPECT_NE(result, (time_t)0); - - // Verify the parsed timestamp - struct tm *tm_info = localtime(&result); - EXPECT_EQ(tm_info->tm_year + 1900, 2025); - EXPECT_EQ(tm_info->tm_mon + 1, 11); - EXPECT_EQ(tm_info->tm_mday, 26); - EXPECT_EQ(tm_info->tm_hour, 14); - EXPECT_EQ(tm_info->tm_min, 30); - EXPECT_EQ(tm_info->tm_sec, 45); -} - -TEST(extractUnixTimestamp, VALID_YYMMDD_TIMESTAMP) -{ - // Test YYMMDD format: YYMMDD-HH:MM:SS - const char* timestamp_str = "251126-14:30:45"; - time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); - EXPECT_NE(result, (time_t)0); - - // Verify the parsed timestamp - struct tm *tm_info = localtime(&result); - EXPECT_EQ(tm_info->tm_year + 1900, 2025); - EXPECT_EQ(tm_info->tm_mon + 1, 11); - EXPECT_EQ(tm_info->tm_mday, 26); - EXPECT_EQ(tm_info->tm_hour, 14); - EXPECT_EQ(tm_info->tm_min, 30); - EXPECT_EQ(tm_info->tm_sec, 45); -} - -TEST(extractUnixTimestamp, INVALID_TIMESTAMP_FORMAT) -{ - // Test with invalid timestamp format - const char* timestamp_str = "invalid-timestamp-format"; - time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); - EXPECT_EQ(result, (time_t)0); -} - -TEST(extractUnixTimestamp, NULL_PARAMETERS) -{ - // Test with NULL line_start - time_t result = extractUnixTimestamp(NULL, 20); - EXPECT_EQ(result, (time_t)0); - - // Test with zero length - const char* timestamp_str = "2025-11-26T14:30:45.123"; - result = extractUnixTimestamp(timestamp_str, 0); - EXPECT_EQ(result, (time_t)0); -} - -TEST(extractUnixTimestamp, SHORT_LINE_LENGTH) -{ - // Test with line too short for any valid timestamp - const char* timestamp_str = "2025-11-26T14:30:45.123"; - time_t result = extractUnixTimestamp(timestamp_str, 10); // Too short - EXPECT_EQ(result, (time_t)0); -} - -TEST(extractUnixTimestamp, EDGE_CASE_MINIMUM_LENGTH) -{ - // Test with minimum length for YYMMDD format (15 characters) - const char* timestamp_str = "251126-14:30:45extra_data"; - time_t result = extractUnixTimestamp(timestamp_str, 15); - EXPECT_NE(result, (time_t)0); -} - -TEST(extractUnixTimestamp, PARTIAL_MATCH) -{ - // Test with partial timestamp that looks valid but isn't complete - const char* timestamp_str = "2025-11-26T"; // Incomplete ISO format - time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); - EXPECT_EQ(result, (time_t)0); -} - -TEST(extractUnixTimestamp, MALFORMED_DATE) -{ - // Test with malformed date values - const char* timestamp_str = "2025-13-32T25:70:70.123"; // Invalid month/day/hour/min/sec - time_t result = extractUnixTimestamp(timestamp_str, strlen(timestamp_str)); - EXPECT_EQ(result, (time_t)0); -} - -TEST(extractUnixTimestamp, BOUNDARY_YEAR_VALUES) -{ - // Test with boundary year values for YYMMDD format - const char* timestamp_str1 = "001126-14:30:45"; // Year 2000 - time_t result1 = extractUnixTimestamp(timestamp_str1, strlen(timestamp_str1)); - EXPECT_NE(result1, (time_t)0); - - const char* timestamp_str2 = "991126-14:30:45"; // Year 2099 - time_t result2 = extractUnixTimestamp(timestamp_str2, strlen(timestamp_str2)); - EXPECT_NE(result2, (time_t)0); -} - -//dcaproc.c - -TEST(GETPROCUSAGE, MARKER_NULL) -{ - EXPECT_EQ(-1, getProcUsage("telemetry2_0", NULL, NULL)); -} - -TEST(GETPROCUSAGE, PROCESS_NULL) -{ - char* filename = NULL; - filename = strdup("top_log.txt"); - EXPECT_EQ(-1, getProcUsage(NULL, NULL, filename)); - EXPECT_EQ(-1, getProcUsage(NULL, NULL, NULL)); - free(filename); -} - -TEST(GETPROCPIDSTAT, PINFO_NULL) -{ - EXPECT_EQ(0, getProcPidStat(12345, NULL)); -} - -TEST(GETPROCINFO, PMINFO_NULL) -{ - char* filename = NULL; - char* processName = NULL; - processName = strdup("telemetry2_0"); - EXPECT_EQ(0, getProcInfo(NULL, filename)); - - filename = strdup("top_log.txt"); - EXPECT_EQ(0, getProcInfo(NULL, filename)); - - procMemCpuInfo pInfo; - memset(&pInfo, '\0', sizeof(procMemCpuInfo)); - memcpy(pInfo.processName, processName, strlen(processName) + 1); - pInfo.total_instance = 0; - EXPECT_NE(0,getProcInfo(&pInfo, NULL)); - free(filename); - free(processName); -} - -TEST(GETMEMINFO, PMINFO_NULL) -{ - EXPECT_EQ(0, getMemInfo(NULL)); -} - -TEST(GETCPUINFO, PINFO_NULL) -{ - char* filename = NULL; - EXPECT_EQ(0, getCPUInfo(NULL, filename)); - filename = strdup("top_log.txt"); - EXPECT_EQ(0, getCPUInfo(NULL, filename)); - - -} - - -//dcautil.c -char* gmarker1 = "SYS_INFO_BOOTUP"; -char* dcamarker1 = "SYS_INFO1"; -char* dcamarker2 = "SYS_INFO2"; - -TEST(GETGREPRESULTS, PROFILENAME_NULL) -{ - Vector* markerlist = NULL; - Vector_Create(&markerlist); - Vector_PushBack(markerlist, (void*) strdup(dcamarker1)); - Vector_PushBack(markerlist, (void*) strdup(dcamarker2)); - Vector* grepResultlist = NULL; - Vector_Create(&grepResultlist); - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)1, free); - EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(NULL, markerlist, false, false,"/opt/logs")); - EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(&gsProfile, NULL, false, false,"/opt/logs")); - EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(NULL, markerlist, false, true,"/opt/logs")); - EXPECT_EQ(T2ERROR_FAILURE, getGrepResults(&gsProfile, NULL, false, true,"/opt/logs")); - Vector_Destroy(markerlist, free); - Vector_Destroy(grepResultlist, free); - if(gsProfile->logFileSeekMap) - { - hash_map_destroy(gsProfile->logFileSeekMap, free); - } - free(gsProfile); - grepResultlist = NULL; - markerlist = NULL; -} - -#ifdef PERSIST_LOG_MON_REF -TEST(saveSeekConfigtoFile, profilename_NULL) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)1, free); - EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile(NULL, gsProfile)); - EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile("RDKB_Profile1", NULL)); - if(gsProfile->logFileSeekMap) - { - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - } - EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile("RDKB_Profile1", gsProfile)); -} - -TEST(loadSavedSeekConfig, profilename_NULL) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - EXPECT_EQ(T2ERROR_FAILURE, loadSavedSeekConfig(NULL, gsProfile)); - hash_map_destroy(gsProfile->logFileSeekMap, free); - free(gsProfile); -} - -#endif - - -TEST(GETLOADAVG, MARKER_NULL) -{ - EXPECT_EQ(0, getLoadAvg(NULL)); -} - -TEST(GETLOADAVG, VALID_MARKER) -{ - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - EXPECT_EQ(1, getLoadAvg(topMarker)); - free(topMarker); -} - -TEST(CREATEGREPSEEKPROFILE, SEEKMAPCREATE_CHECK) -{ - GrepSeekProfile *gsProfile = createGrepSeekProfile(0); - EXPECT_NE(gsProfile, nullptr); - EXPECT_NE(gsProfile->logFileSeekMap, nullptr); - EXPECT_EQ(gsProfile->execCounter, 0); - hash_map_destroy(gsProfile->logFileSeekMap, free); - free(gsProfile); -} - -TEST(FREEFREPSEEKPROFILE, SEEKMAPFREE_CHECK) -{ - GrepSeekProfile *gsProfile = createGrepSeekProfile(0); - EXPECT_NE(gsProfile, nullptr); - EXPECT_NE(gsProfile->logFileSeekMap, nullptr); - EXPECT_EQ(gsProfile->execCounter, 0); - - freeGrepSeekProfile(gsProfile); - - // Check if the profile is freed correctly - EXPECT_NE(gsProfile, nullptr); -} - -TEST(CLEARCONFVAL, FREECONFVAL) -{ - clearConfVal(); -} - -//dca.c -TEST(PROCESSTOPPATTERN, VECTOR_NULL) -{ - Vector* topMarkerlist = NULL; - Vector_Create(&topMarkerlist); - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = false; - topMarker->regexParam = NULL; - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 0; - topMarker->paramType = strdup("grep"); - Vector_PushBack(topMarkerlist, (void*) topMarker); - EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); - - EXPECT_EQ(-1, processTopPattern(NULL, topMarkerlist, 1)); - EXPECT_EQ(-1, processTopPattern("RDK_Profile",NULL, 1)); - - Vector_Destroy(topMarkerlist, free); - topMarkerlist = NULL; + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; } -TEST(getDCAResultsInVector, markerlist_NULL) +// dcaFlagReportCompleation this function is used to create legacy DCA Flag DCADONEFLAG +void dcaFlagReportCompleation() { - Vector* markerlist = NULL; - Vector_Create(&markerlist); - Vector_PushBack(markerlist, (void*) strdup("SYS_INFO_BOOTUP")); - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)1, free); - EXPECT_EQ(-1, getDCAResultsInVector(NULL, markerlist, true, "/opt/logs/core_log.txt")); - EXPECT_EQ(-1, getDCAResultsInVector(gsProfile, NULL, true, "/opt/logs/core_log.txt")); - // commenting the below case as string will never be passed to this function instead of the vector. - //EXPECT_EQ(-1, getDCAResultsInVector(gsProfile, markerlist, true, "/opt/logs/core_log.txt")); - hash_map_destroy(gsProfile->logFileSeekMap, free); - Vector_Destroy(markerlist, free); -} - -class dcaTestFixture : public ::testing::Test { -protected: - void SetUp() override + T2Debug("%s --in creating flag %s\n", __FUNCTION__, DCADONEFLAG); + FILE *fileCheck = fopen(DCADONEFLAG, "w+"); + if (fileCheck == NULL ) { - g_fileIOMock = new FileMock(); - g_systemMock = new SystemMock(); + T2Error(" Error in creating the Flag : %s\n", DCADONEFLAG); } - - void TearDown() override + else { - delete g_fileIOMock; - delete g_systemMock; - - g_fileIOMock = nullptr; - g_systemMock = nullptr; - } -}; - -//dcautil.c -TEST_F(dcaTestFixture, firstBootstatus){ - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(-1)); - - EXPECT_EQ(true, firstBootStatus()); -} - -TEST_F(dcaTestFixture, firstBootstatus_1){ - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, firstBootStatus()); -} - -TEST_F(dcaTestFixture, dcaFlagReportCompleation) -{ - FILE* fp = (FILE*)NULL; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - dcaFlagReportCompleation(); -} - -TEST_F(dcaTestFixture, dcaFlagReportCompleation1) -{ - FILE* fp = (FILE*)0xffffffff; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - dcaFlagReportCompleation(); -} - -#ifdef PERSIST_LOG_MON_REF -TEST_F(dcaTestFixture, loadSavedSeekConfig) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - FILE* fp = (FILE*)NULL; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_EQ(T2ERROR_FAILURE, loadSavedSeekConfig("RDK_Profile", gsProfile)); - hash_map_destroy(gsProfile->logFileSeekMap, free); - free(gsProfile); -} - -TEST_F(dcaTestFixture, loadSavedSeekConfig1) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - FILE* fp = (FILE*)0xffffffff; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_CALL(*g_fileIOMock, fseek(_,_,_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, ftell(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(T2ERROR_SUCCESS, loadSavedSeekConfig("RDK_Profile", gsProfile)); - hash_map_destroy(gsProfile->logFileSeekMap,free); - free(gsProfile); -} - -TEST_F(dcaTestFixture, saveSeekConfigtoFile) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - long *tempnum; - double val = 123456; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); - FILE* fp = (FILE*)NULL; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_EQ(T2ERROR_FAILURE, saveSeekConfigtoFile("RDK_Profile", gsProfile)); - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); -} -#endif - -//dcaproc.c - -TEST_F(dcaTestFixture, getProcUsage) -{ - Vector* topMarkerlist = NULL; - Vector_Create(&topMarkerlist); - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = false; - topMarker->regexParam = NULL; - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 0; - topMarker->paramType = strdup("grep"); - topMarker->reportEmptyParam = true; - Vector_PushBack(topMarkerlist, (void*) topMarker); - - char* filename = strdup("/tmp/t2toplog/RDK_Profile"); - - FILE* fp = (FILE*)NULL; - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #else - EXPECT_CALL(*g_fileIOMock, popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #endif - EXPECT_EQ(0, getProcUsage(topMarker->searchString, topMarker, filename)); - Vector_Destroy(topMarkerlist, NULL); - free(filename); -} - -TEST_F(dcaTestFixture, getProcPidStat) -{ - procinfo pinfo; - int fd = (int)0xffffffff; - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(1) - .WillOnce(Return(-1)); - ASSERT_EQ(0, getProcPidStat(123, &pinfo)); -} - -TEST_F(dcaTestFixture, getProcPidStat1) -{ - procinfo pinfo; - int fd = (int)0xffffffff; - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, read(_,_,_)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(1) - .WillOnce(Return(0)); - ASSERT_EQ(0, getProcPidStat(123, &pinfo)); -} - -#if !defined(ENABLE_RDKC_SUPPORT) && !defined(ENABLE_RDKB_SUPPORT) -TEST_F(dcaTestFixture, saveTopOutput) -{ - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(0)); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(3) - .WillOnce(Return(0)) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(3) - .WillOnce(Return(0)) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - #endif - EXPECT_EQ(NULL, saveTopOutput("RDK_Profile")); -} - -TEST_F(dcaTestFixture, saveTopOutput1) -{ - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(-1)); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - #endif - EXPECT_EQ(NULL, saveTopOutput("RDK_Profile")); -} - -TEST_F(dcaTestFixture, saveTopOutput2) -{ - char* filename = NULL; - filename = "/tmp/t2toplog_RDK_Profile"; - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(-1)); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - #endif - EXPECT_STREQ(filename, saveTopOutput("RDK_Profile")); -} - -TEST_F(dcaTestFixture, removeTopOutput) -{ - char* filename = NULL; - filename = strdup("/tmp/t2toplog_RDK_Profile"); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(1) - .WillOnce(Return(-1)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(1) - .WillOnce(Return(-1)); - #endif - removeTopOutput(filename); + fclose(fileCheck); + } + T2Debug("%s --out\n", __FUNCTION__); } -TEST_F(dcaTestFixture, removeTopOutput1) +# ifdef PERSIST_LOG_MON_REF +T2ERROR saveSeekConfigtoFile(char* profileName, GrepSeekProfile *ProfileSeekMap) { - char* filename = NULL; - filename = strdup("/tmp/t2toplog_RDK_Profile"); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(1) - .WillOnce(Return(0)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(1) - .WillOnce(Return(0)); - #endif - removeTopOutput(filename); -} + T2Debug("%s ++in\n", __FUNCTION__); + if(profileName == NULL) + { + T2Error("Profile Name is not available\n"); + return T2ERROR_FAILURE; + } + if(ProfileSeekMap == NULL) + { + T2Error("ProfileSeekMap is NULL\n"); + return T2ERROR_FAILURE; + } + hash_map_t *logfileMap = ProfileSeekMap->logFileSeekMap; + if(logfileMap == NULL) + { + T2Error("logfileMap is NULL\n"); + return T2ERROR_FAILURE; + } -#else -TEST_F(dcaTestFixture, getTotalCpuTimes) -{ - FILE* mockfp = (FILE *)NULL; - int *totaltime = 0; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(mockfp)); - EXPECT_EQ(0, getTotalCpuTimes(totaltime)); -} + unsigned int count = (unsigned int) hash_map_count(logfileMap); -TEST_F(dcaTestFixture, getTotalCpuTimes1) -{ - FILE* mockfp = (FILE *)0xFFFFFFFF; - int *totaltime = 0; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(mockfp)); - EXPECT_CALL(*g_fileIOMock, fscanf(_,_,_)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_EQ(1, getTotalCpuTimes(totaltime)); + cJSON *valArray = cJSON_CreateArray(); + for (unsigned int i = 0; i < count ; i++) + { + char *logFileName = NULL; + long *seekvalue = NULL; + logFileName = hash_map_lookupKey(logfileMap, i); + seekvalue = hash_map_lookup(logfileMap, i); + cJSON *logFileObj = cJSON_CreateObject(); + cJSON_AddNumberToObject(logFileObj, logFileName, (double)*seekvalue); + cJSON_AddItemToArray(valArray, logFileObj); + } + char *jsonReport = cJSON_PrintUnformatted(valArray); + if(T2ERROR_SUCCESS != saveConfigToFile(SEEKFOLDER, profileName, jsonReport)) + { + T2Error("Failed to save config to file\n"); + cJSON_Delete(valArray); + free(jsonReport); + return T2ERROR_FAILURE; + } + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; } -#endif - -//legacyutils.c - -TEST_F(dcaTestFixture, getLoadAvg) +T2ERROR loadSavedSeekConfig(char *profileName, GrepSeekProfile *ProfileSeekMap) { - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = false; - topMarker->regexParam = NULL; - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 0; - topMarker->paramType = strdup("grep"); - topMarker->reportEmptyParam = true; - FILE* fp = (FILE*)NULL; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_EQ(0, getLoadAvg(topMarker)); -} + T2Debug("%s ++in\n", __FUNCTION__); -/*TEST_F(dcaTestFixture, getLoadAvg1) -{ - GrepResult* loadAvg = (GrepResult*) malloc(sizeof(GrepResult)); - loadAvg->markerName = strdup("Load_Average"); - loadAvg->markerValue = strdup("2.15"); - loadAvg->trimParameter = true; - loadAvg->regexParameter = "[0-9]+"; - Vector_PushBack(grepResultList, loadAvg); - FILE* fp = (FILE*)0xffffffff; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_EQ(0, getLoadAvg(grepResultList, false, NULL)); - Vector_Destroy(grepResultList, freeGResult); -} -*/ -TEST_F(dcaTestFixture, getLoadAvg2) -{ - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = true; - topMarker->regexParam = "[0-9]+"; - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 0; - topMarker->paramType = strdup("grep"); - topMarker->reportEmptyParam = true; - FILE* fp = (FILE*)0xffffffff; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) - .Times(1) - .WillOnce(Return(14)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_EQ(1, getLoadAvg(topMarker)); -} + if(profileName == NULL) + { + T2Error("Profile Name is not available\n"); + return T2ERROR_FAILURE; + } + int len = strlen(profileName) + strlen(SEEKFOLDER) + 2; + char *seekFile = (char *)malloc(len); + snprintf(seekFile, len, "%s/%s", SEEKFOLDER, profileName); + FILE *file = fopen(seekFile, "rb"); + if(file == NULL) + { + T2Error("Failed to open file\n"); + free(seekFile); + return T2ERROR_FAILURE; + } + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + fseek(file, 0, SEEK_SET); -TEST_F(dcaTestFixture, initProperties) -{ - char* logpath = NULL; - long int pagesize = 0; - char* perspath = NULL; - FILE* fp = (FILE*)0xffffffff; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(2) - .WillOnce(Return(fp)) - .WillOnce(Return(fp)); - EXPECT_CALL(*g_fileIOMock, fscanf(_,_,_)) - .Times(10) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(EOF)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(EOF)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - initProperties(&logpath, &perspath, &pagesize); -} + char *data = malloc(fileSize + 1); + if (data == NULL) + { + T2Error("Memory allocation failed\n"); + fclose(file); + return T2ERROR_FAILURE; + } + fread(data, 1, fileSize, file); + fclose(file); + data[fileSize] = '\0'; + cJSON *json = cJSON_Parse(data); + cJSON *item = NULL; + //GrepSeekProfile *ProfileSeekMap = NULL; + cJSON_ArrayForEach(item, json) + { + // Each `item` is an object in the array + if (item->child != NULL) + { + const char *key = item->child->string; + cJSON *value = item->child; -//dca.c -#if 0 -//This testcase is not required as we don't pass trim and regex as separate arguments anymore -TEST_F(dcaTestFixture, processTopPattern) -{ - Vector* topMarkerlist = NULL; - Vector_Create(&topMarkerlist); - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = false; - topMarker->regexParam = NULL; - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 0; - topMarker->paramType = strdup("grep"); - topMarker->reportEmptyParam = true; - - TopMarker* topMarker1 = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker1->markerName = strdup("cpu_telemetry2_0"); - topMarker1->searchString = strdup("telemetry2_0"); - topMarker1->trimParam = false; - topMarker1->regexParam = NULL; - topMarker1->logFile = strdup("top_log.txt"); - topMarker1->skipFreq = 0; - topMarker1->paramType = strdup("grep"); - topMarker->reportEmptyParam = true; - Vector_PushBack(topMarkerlist, (void*) topMarker1); + if (key != NULL) + { + // Check the value type and print it + if (cJSON_IsNumber(value)) + { + long *tempnum; + double val = value->valuedouble; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; + hash_map_put(ProfileSeekMap->logFileSeekMap, strdup(key), tempnum, NULL); + //printf("Key: %s, Value: %ld\n", key, *tempnum); + } + } - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(-1)); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(3) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(-1)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(3) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(-1)); - #endif - FILE* fp = (FILE*)NULL; - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #else - EXPECT_CALL(*g_fileIOMock, popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #endif - EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); - Vector_Destroy(topMarkerlist, NULL); + } + } + cJSON_Delete(json); + free(data); + free(seekFile); + return T2ERROR_SUCCESS; + T2Debug("%s --out\n", __FUNCTION__); } #endif -TEST_F(dcaTestFixture, processTopPattern1) -{ - Vector* topMarkerlist = NULL; - Vector_Create(&topMarkerlist); - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = true; - topMarker->regexParam = strdup("[0-9]+"); - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 0; - TopMarker* topMarker1 = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker1, 0, sizeof(TopMarker)); - topMarker1->markerName = strdup("Load_Average"); - topMarker1->searchString = strdup("telemetry2_0"); - topMarker1->trimParam = true; - topMarker1->regexParam = strdup("[0-9]+"); - topMarker1->logFile = strdup("top_log.txt"); - topMarker1->skipFreq = 0; - Vector_PushBack(topMarkerlist, (void*) topMarker1); - Vector_PushBack(topMarkerlist, (void*) topMarker); - EXPECT_CALL(*g_systemMock, access(_,_)) - .Times(1) - .WillOnce(Return(-1)); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(3) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(-1)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(3) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(-1)); - #endif - FILE* fp = (FILE*)NULL; - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #else - EXPECT_CALL(*g_fileIOMock, popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #endif - FILE* fs= (FILE*)0xffffffff; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(fs)); - EXPECT_CALL(*g_fileIOMock, fread(_,_,_,_)) - .Times(1) - .WillOnce(Return(14)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); - Vector_Destroy(topMarkerlist, freeGMarker); -} - -TEST_F(dcaTestFixture, processTopPattern2) -{ - Vector* topMarkerlist = NULL; - Vector_Create(&topMarkerlist); - TopMarker* topMarker = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker, 0, sizeof(TopMarker)); - topMarker->markerName = strdup("cpu_telemetry2_0"); - topMarker->searchString = strdup("telemetry2_0"); - topMarker->trimParam = true; - topMarker->regexParam = strdup("[0-9]+"); - topMarker->logFile = strdup("top_log.txt"); - topMarker->skipFreq = 1; - Vector_PushBack(topMarkerlist, (void*) topMarker); - - TopMarker* topMarker2 = (TopMarker*) malloc(sizeof(TopMarker)); - memset(topMarker2, 0, sizeof(TopMarker)); - topMarker2->markerName = strdup("mem_telemetry2_0"); - topMarker2->searchString = strdup("telemetry2_0"); - topMarker2->trimParam = true; - topMarker2->regexParam = strdup("[0-9]+"); - topMarker2->logFile = strdup("top_log.txt"); - topMarker2->skipFreq = 0; - Vector_PushBack(topMarkerlist, (void*) topMarker2); - - //saveTopoutput - EXPECT_CALL(*g_systemMock, access(_,_)) - .WillRepeatedly(Return(0)); - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_systemMock, v_secure_system(_)) - .Times(4) - .WillOnce(Return(0)) //saveTopoutput - .WillOnce(Return(0)) //removeTopoutput - .WillOnce(Return(0)) //saveTopoutput - .WillOnce(Return(0)); - #else - EXPECT_CALL(*g_systemMock, system(_)) - .Times(4) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - #endif - FILE* fp = (FILE*)0xFFFFFFFF; - //getProcUsage - pidof - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_fileIOMock, v_secure_popen(_,_)) - .Times(2) - .WillOnce(Return(fp)) - .WillOnce(Return(fp)); - #else - EXPECT_CALL(*g_fileIOMock, popen(_,_)) - .Times(1) - .WillOnce(Return(fp)); - #endif - - #ifdef LIBSYSWRAPPER_BUILD - EXPECT_CALL(*g_fileIOMock, v_secure_pclose(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - #else - EXPECT_CALL(*g_fileIOMock, pclose(_)) - .Times(1) - .WillOnce(Return(0)); - #endif - - // getCPUInfo reads TOPTEMP file directly via fopen - FILE* topfp = (FILE*)0xEEEEEEEE; - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(1) - .WillOnce(Return(topfp)); - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(1) - .WillOnce(Return(0)); - - //getMEMinfo - EXPECT_CALL(*g_fileIOMock, read(_,_,_)) - .WillOnce([](int fd, void* buf, size_t count) { - const char *stat_str = "7396 (telemetry2_0) S 1 7396 7396 0 -1 1077936448 17297 316924 7 544 410 610 1888 258 20 0 14 0 2373301 1024380928 3425 18446744073709551615 94059930939392 94059930943425 140725223263616 0 0 0 0 4096 268454400 0 0 0 17 3 0 0 0 0 0 94059930950768 94059930951697 94060511973376 140725223266476 140725223266504 140725223266504 140725223268316 0"; - size_t len = strlen(stat_str); - size_t to_copy = len < count ? len : count; - memcpy(buf, stat_str, to_copy); - return to_copy; - }); - - //getprocpidstat - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(1) - .WillOnce(Return(0)); - //getCPUInfo - EXPECT_CALL(*g_fileIOMock, fgets(_,_,_)) - .WillOnce([](char* buf, size_t size, FILE* stream) { - const char* test_line = "2268 root 20 0 831m 66m 20m S 27 13.1 491:06.82 telemetry2_0\n"; - strncpy(buf, test_line, size-1); - buf[size-1] = '\0'; - return buf; - }) - .WillOnce(Return((char*)NULL)); - EXPECT_EQ(0, processTopPattern("RDK_Profile", topMarkerlist, 1)); - Vector_Destroy(topMarkerlist, freeGMarker); -} - -TEST_F(dcaTestFixture, getDCAResultsInVector_1) +bool firstBootStatus() { - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - memset(marker, 0, sizeof(GrepMarker)); - marker->markerName = strdup("SYS_INFO_TEST"); - marker->searchString = strdup("Test Marker"); - marker->trimParam = true; - marker->regexParam = strdup("[0-9]+"); - marker->logFile = strdup("Consolelog.txt.0"); - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->mType = MTYPE_COUNTER; - marker->u.count = 0; - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - //freeFileDescriptor - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - - //getLogFileDescriptor - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(2) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1235; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1300; // Set file size - return 0; // Success - }); - - //getDeltainmmapsearch - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) - .Times(1) - .WillOnce(Return(1300)); - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(1) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "This is a Test Marker with value 1234 in the log file.\nAnother line without the marker.\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, NULL); -} - -TEST_F(dcaTestFixture, getDCAResultsInVector_2) -{ - - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - memset(marker, 0, sizeof(GrepMarker)); - marker->markerName = strdup("SYS_INFO_TEST"); - marker->searchString = strdup("temp:"); - marker->trimParam = true; - marker->regexParam = strdup("[0-9]+"); - marker->logFile = strdup("Consolelog.txt.0"); - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->mType = MTYPE_ABSOLUTE; - marker->u.markerValue = NULL; - marker->u.count = 0; - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - //freeFileDescriptor - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - - //getLogFileDescriptor - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(2) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1300; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1300; // Set file size - return 0; // Success - }); - - //getDeltainmmapsearch - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) - .Times(1) - .WillOnce(Return(1300)); - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(1) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "This is a Test Marker with value temp:1245.\nAnother line without the marker.\n Another line with marker temp:2345\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - - EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, freeGMarker); -} - -TEST_F(dcaTestFixture, getDCAResultsInVector_3) -{ - - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 1; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - memset(marker, 0, sizeof(GrepMarker)); - marker->markerName = strdup("SYS_INFO_TEST"); - marker->searchString = strdup("Test Marker"); - marker->trimParam = true; - marker->u.markerValue = NULL; - marker->u.accumulatedValues = NULL; - marker->regexParam = strdup("[0-9]+"); - marker->logFile = strdup("Consolelog.txt.0"); - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->mType = MTYPE_COUNTER; - marker->u.count = 0; - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - - //freeFileDescriptor - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(4) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - - //getLogFileDescriptor - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(4) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1235; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1235; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1000; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1000; // Set file size - return 0; // Success - }); - - //getDeltainmmapsearch - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) - .Times(2) - .WillOnce(Return(1235)) - .WillOnce(Return(1000)); - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(2) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "This is a Test Marker with value 1234 in the log file.\nAnother line without the marker.\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "This is with value Test:1250 in the log file.\nAnother line without the marker.\nThe line with Test Markeris found\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - - EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, freeGMarker); -} - - -TEST_F(dcaTestFixture, getDCAResultsInVector_Accum) -{ - - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 1; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - memset(marker, 0, sizeof(GrepMarker)); - marker->markerName = strdup("SYS_INFO_TEST"); - marker->searchString = strdup("Test Marker"); - marker->trimParam = true; - marker->u.markerValue = NULL; - marker->u.count = 0; - marker->mType = MTYPE_ACCUMULATE; - marker->reportTimestampParam = REPORTTIMESTAMP_UNIXEPOCH; - Vector_Create(&marker->u.accumulatedValues); - if(marker->reportTimestampParam == REPORTTIMESTAMP_UNIXEPOCH) + T2Debug("%s ++in\n", __FUNCTION__); + bool status = true; + if(access(BOOTFLAG, F_OK) != -1) { - Vector_Create(&marker->accumulatedTimestamp); + status = false; } - marker->regexParam = strdup("[0-9]+"); - marker->logFile = strdup("Consolelog.txt.0"); - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - //freeFileDescriptor - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .WillRepeatedly(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .WillRepeatedly(Return(0)); - - //getLogFileDescriptor - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .WillRepeatedly(Return(0)); - - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(testing::AtMost(4)) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1235; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1235; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1000; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1000; // Set file size - return 0; // Success - }); - //getDeltainmmapsearch - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .WillRepeatedly(Return(0)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .WillRepeatedly(Return(0)); - EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) - .Times(testing::AtMost(2)) - .WillOnce(Return(1235)) - .WillOnce(Return(1000)); - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(testing::AtMost(2)) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "2025-10-26T14:40:55.001Z This is a Test Marker with value 1234 in the log file.\n2025-10-26T14:40:55.001Z Another line without the marker.\n2025-10-26T14:40:55.001Z Line with Test Marker"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "2025-10-26T14:40:55.001Z This is with value Test:1250 in the log file.\n2025-10-26T14:40:55.001Z Another line without the marker.\n2025-10-26T14:40:55.001Z The line with Test Markeris found\n2025-10-26T14:40:55.001Z Line with 0 vale for Test Marker0"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, true, "/opt/logs")); - - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, freeGMarker); -} - -TEST_F(dcaTestFixture, T2InitProperties) -{ - EXPECT_CALL(*g_fileIOMock, fopen(_,_)) - .Times(2) - .WillOnce(Return((FILE*)0XFFFFFFFF)) - .WillOnce(Return((FILE*)0XFFFFFFFF)); - EXPECT_CALL(*g_fileIOMock, fscanf(_,_,_)) - .Times(2) - .WillOnce(Return(EOF)) - .WillOnce(Return(EOF)); - - EXPECT_CALL(*g_fileIOMock, fclose(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - - T2InitProperties(); -} - -//dcautil.c - -TEST_F(dcaTestFixture, getGrepResults_success) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 0; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - marker->markerName = strdup("SYS_INFO_TEST"); - marker->searchString = strdup("temp:"); - marker->trimParam = true; - marker->regexParam = strdup("[0-9]+"); - marker->logFile = strdup("Consolelog.txt.0"); - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->mType = MTYPE_ABSOLUTE; - marker->u.markerValue = NULL; - marker->u.count = 0; - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - //freeFileDescriptor - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(2) - .WillOnce(Return(0)) - .WillOnce(Return(0)); - - //getLogFileDescriptor - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(2) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1300; // Set file size - return 0; // Success - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 1300; // Set file size - return 0; // Success - }); - - //getDeltainmmapsearch - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock,sendfile(_,_,_,_)) - .Times(1) - .WillOnce(Return(1300)); - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(1) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - const char* test_str = "This is a Test Marker with value temp:1245.\nAnother line without the marker.\n Another line with marker temp:2345\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - - EXPECT_EQ(T2ERROR_SUCCESS, getGrepResults(&gsProfile, vecMarkerList, true, true, "/opt/logs")); - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, freeGMarker); -} - -// waitForBackupLogsDone L1 tests - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelAlreadyPresent) -{ - // Fast path: access() returns 0 meaning sentinel file exists - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(true, waitForBackupLogsDone()); + T2Debug("%s --out\n", __FUNCTION__); + return status; } - -TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyInitFails) -{ - // access() returns -1 (sentinel not present), inotify_init1 fails - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(-1)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyAddWatchFails) -{ - // access() returns -1, inotify_init1 succeeds, inotify_add_watch fails - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_RaceResolved) -{ - // First access() returns -1, inotify setup succeeds, second access() returns 0 (race resolved) - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(true, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFails) -{ - // access() returns -1 both times, inotify setup succeeds, clock_gettime fails - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_Timeout) -{ - // Sentinel never appears, select returns 0 (timeout heartbeat), deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - - // First clock_gettime sets the deadline (tv_sec=100) - // Second clock_gettime returns past deadline (tv_sec >= 100 + BACKUP_LOGS_SYNC_TIMEOUT_S) - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; - tp->tv_nsec = 0; - return 0; - }); - - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectFails) -{ - // select() fails with non-EINTR error - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; // Not past deadline yet - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { - errno = EBADF; - return -1; - }); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectEINTR) -{ - // select() returns EINTR, then deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(3) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; // Not past deadline - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; // Past deadline - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { - errno = EINTR; - return -1; - }); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelDetectedViaInotify) -{ - // Sentinel detected via inotify event - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; // Not past deadline - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(1)); // Data available to read - - // Construct a fake inotify_event with the sentinel filename - struct inotify_event fake_event; - fake_event.wd = 1; - fake_event.mask = IN_CREATE; - fake_event.cookie = 0; - fake_event.len = strlen(BACKUP_LOGS_DONE_FILENAME) + 1; - - // Build the buffer: struct inotify_event + filename (null-terminated) - size_t event_size = sizeof(struct inotify_event) + fake_event.len; - char *event_buf = (char *)malloc(event_size); - memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); - memcpy(event_buf + sizeof(struct inotify_event), BACKUP_LOGS_DONE_FILENAME, fake_event.len); - - EXPECT_CALL(*g_fileIOMock, read(5, _, _)) - .Times(1) - .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { - size_t copy_size = (event_size < count) ? event_size : count; - memcpy(buf, event_buf, copy_size); - return (ssize_t)copy_size; - }); - - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(true, waitForBackupLogsDone()); - free(event_buf); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_ReadReturnsZero) -{ - // select() returns data ready, but read() returns 0 — loop back, then deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(3) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_fileIOMock, read(5, _, _)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_UnrelatedInotifyEvent) -{ - // An inotify event for a different file, then deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(3) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(1)); - - // Construct an inotify event for a different filename - const char *other_file = "other_file.txt"; - struct inotify_event fake_event; - fake_event.wd = 1; - fake_event.mask = IN_CREATE; - fake_event.cookie = 0; - fake_event.len = strlen(other_file) + 1; - - size_t event_size = sizeof(struct inotify_event) + fake_event.len; - char *event_buf = (char *)malloc(event_size); - memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); - memcpy(event_buf + sizeof(struct inotify_event), other_file, fake_event.len); - - EXPECT_CALL(*g_fileIOMock, read(5, _, _)) - .Times(1) - .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { - size_t copy_size = (event_size < count) ? event_size : count; - memcpy(buf, event_buf, copy_size); - return (ssize_t)copy_size; - }); - - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); - free(event_buf); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFailsInLoop) -{ - // clock_gettime succeeds initially but fails inside the while loop - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce(Return(-1)); // Fails in the loop - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -#ifdef GTEST_ENABLE -extern "C" { -typedef const char *(*strnstrFunc)(const char *, const char *, size_t); -strnstrFunc strnstrFuncCallback(void); -typedef time_t (*extractUnixTimestampFunc)(const char*, size_t); -extractUnixTimestampFunc extractUnixTimestampFuncCallback(void); -typedef T2ERROR (*updateLogSeekFunc)(hash_map_t *, const char *, const long); -updateLogSeekFunc updateLogSeekFuncCallback(void); -} -TEST(StaticStrnstrFunc, CoversMainBranches) -{ - auto fn = strnstrFuncCallback(); - ASSERT_NE(fn, nullptr); - - // NULL haystack or needle should return NULL - EXPECT_EQ(fn(NULL, "needle", 10), nullptr); - EXPECT_EQ(fn("haystack", NULL, 10), nullptr); - - // Empty needle returns haystack - const char* h1 = "haystack"; - EXPECT_EQ(fn(h1, "", 8), h1); - - // len < needle_len or overflow returns NULL - EXPECT_EQ(fn("foo", "foobar", 3), nullptr); - // May not always trigger overflow branch but included for completeness - // EXPECT_EQ(fn("foo", "foo", (size_t)-1), nullptr); - - // needle of length < 4 triggers simple search branch: found and not found - const char* h2 = "abcdef"; - EXPECT_EQ(fn(h2, "c", 6), h2 + 2); // found at position 2 - EXPECT_EQ(fn(h2, "e", 4), nullptr); // not found in first 4 chars - - // Optionally: COVER the optimized/longer path if you want (needle_len >= 4) - // This depends on your actual implementation for longer patterns -} -TEST(StaticExtractUnixTimestampFunc, CoversBranches) -{ - auto fn = extractUnixTimestampFuncCallback(); - ASSERT_NE(fn, nullptr); - - // NULL pointer or zero length hit early branch - EXPECT_EQ(fn(NULL, 12), (time_t)0); - EXPECT_EQ(fn("foo", 0), (time_t)0); - - // ISO 8601 - "2023-05-30T14:15:16.123 extra" - const char* iso = "2023-05-30T14:15:16.123 extra text"; - struct tm tm1 {}; - tm1.tm_year = 2023 - 1900; // years since 1900 - tm1.tm_mon = 5 - 1; // months since January - tm1.tm_mday = 30; - tm1.tm_hour = 14; - tm1.tm_min = 15; - tm1.tm_sec = 16; - time_t expected_iso = mktime(&tm1); - EXPECT_EQ(fn(iso, strlen(iso)), expected_iso); - - // YYMMDD-HH:MM:SS - "230530-14:15:16 something" - const char* yymmdd = "230530-14:15:16 something"; - struct tm tm2 {}; - tm2.tm_year = 2023 - 1900; - tm2.tm_mon = 5 - 1; - tm2.tm_mday = 30; - tm2.tm_hour = 14; - tm2.tm_min = 15; - tm2.tm_sec = 16; - time_t expected_yymmdd = mktime(&tm2); - EXPECT_EQ(fn(yymmdd, strlen(yymmdd)), expected_yymmdd); - - // Not matching format (should return 0) - EXPECT_EQ(fn("1656606000 extra text", strlen("1656606000 extra text")), (time_t)0); -} -TEST(StaticUpdateLogSeekFunc, CoversNullBranches) -{ - auto fn = updateLogSeekFuncCallback(); - ASSERT_NE(fn, nullptr); - - // First branch: logSeekMap == NULL - EXPECT_EQ(fn(NULL, "dummy.log", 100), T2ERROR_FAILURE); - - // Second branch: logFileName == NULL - hash_map_t dummyMap; - EXPECT_EQ(fn(&dummyMap, NULL, 100), T2ERROR_FAILURE); - - // Additional test for a stub/empty map and filename to reach further code - // (Will continue past the NULL check; optionally extend to later logic in the function) -} -#endif From 50b04ebd5449bd7db47d6be5c24c11bb1b80b85d Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:47:13 +0530 Subject: [PATCH 17/36] Update dcautil.c --- source/dcautil/dcautil.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index 64e830561..d7119a870 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -271,13 +271,30 @@ T2ERROR saveSeekConfigtoFile(char* profileName, GrepSeekProfile *ProfileSeekMap) cJSON *valArray = cJSON_CreateArray(); for (unsigned int i = 0; i < count ; i++) { - char *logFileName = NULL; - long *seekvalue = NULL; - logFileName = hash_map_lookupKey(logfileMap, i); - seekvalue = hash_map_lookup(logfileMap, i); + char *logFileName = hash_map_lookupKey(logfileMap, i); + LogSeekInfo *seekInfo = (LogSeekInfo *)hash_map_lookup(logfileMap, i); + if (!logFileName || !seekInfo) + { + T2Warning("Skipping entry %u: NULL key or value in logFileSeekMap\n", i); + continue; + } cJSON *logFileObj = cJSON_CreateObject(); - cJSON_AddNumberToObject(logFileObj, logFileName, (double)*seekvalue); - cJSON_AddItemToArray(valArray, logFileObj); + if (!logFileObj) + { + T2Error("Failed to allocate cJSON object for seek entry\n"); + continue; + } + cJSON_AddNumberToObject(logFileObj, "seekValue", (double)seekInfo->seekValue); + cJSON_AddNumberToObject(logFileObj, "inode", (double)seekInfo->inode); + cJSON *wrapper = cJSON_CreateObject(); + if (!wrapper) + { + T2Error("Failed to allocate cJSON wrapper object\n"); + cJSON_Delete(logFileObj); + continue; + } + cJSON_AddItemToObject(wrapper, logFileName, logFileObj); + cJSON_AddItemToArray(valArray, wrapper); } char *jsonReport = cJSON_PrintUnformatted(valArray); if(T2ERROR_SUCCESS != saveConfigToFile(SEEKFOLDER, profileName, jsonReport)) From 9d6bf4c3b03c2cb153b6be97ae69de12d8c03a29 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:50:17 +0530 Subject: [PATCH 18/36] Update dcautil.c --- source/dcautil/dcautil.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/source/dcautil/dcautil.c b/source/dcautil/dcautil.c index d7119a870..68ceac721 100644 --- a/source/dcautil/dcautil.c +++ b/source/dcautil/dcautil.c @@ -354,15 +354,32 @@ T2ERROR loadSavedSeekConfig(char *profileName, GrepSeekProfile *ProfileSeekMap) if (key != NULL) { - // Check the value type and print it - if (cJSON_IsNumber(value)) + // New format: {"logFileName": {"seekValue": N, "inode": M}} + if (cJSON_IsObject(value)) { - long *tempnum; - double val = value->valuedouble; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; - hash_map_put(ProfileSeekMap->logFileSeekMap, strdup(key), tempnum, NULL); - //printf("Key: %s, Value: %ld\n", key, *tempnum); + cJSON *seekVal = cJSON_GetObjectItem(value, "seekValue"); + cJSON *inodeVal = cJSON_GetObjectItem(value, "inode"); + if (cJSON_IsNumber(seekVal)) + { + LogSeekInfo *info = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + if (info) + { + info->seekValue = (long)seekVal->valuedouble; + info->inode = (inodeVal && cJSON_IsNumber(inodeVal)) ? (ino_t)inodeVal->valuedouble : 0; + hash_map_put(ProfileSeekMap->logFileSeekMap, strdup(key), info, free); + } + } + } + // Legacy format: {"logFileName": N} + else if (cJSON_IsNumber(value)) + { + LogSeekInfo *info = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + if (info) + { + info->seekValue = (long)value->valuedouble; + info->inode = 0; // No inode info in legacy format + hash_map_put(ProfileSeekMap->logFileSeekMap, strdup(key), info, free); + } } } From 58106a97efdb3ad03ff75889deebe6bdf0e09298 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:53:25 +0530 Subject: [PATCH 19/36] Update dcautilTest.cpp --- source/test/dcautils/dcautilTest.cpp | 724 +++++++++++++++++---------- 1 file changed, 453 insertions(+), 271 deletions(-) diff --git a/source/test/dcautils/dcautilTest.cpp b/source/test/dcautils/dcautilTest.cpp index 247b1e6ab..05407e4d8 100644 --- a/source/test/dcautils/dcautilTest.cpp +++ b/source/test/dcautils/dcautilTest.cpp @@ -31,6 +31,8 @@ extern "C" { #include #include #include +#include +#include #include #include #include "utils/vector.h" @@ -640,10 +642,10 @@ TEST_F(dcaTestFixture, saveSeekConfigtoFile) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 123456; - tempnum->inode = 12345; + long *tempnum; + double val = 123456; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); FILE* fp = (FILE*)NULL; EXPECT_CALL(*g_fileIOMock, fopen(_,_)) @@ -1170,10 +1172,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_1) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 1234; - tempnum->inode = 12345; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1249,10 +1251,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_2) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 1234; - tempnum->inode = 12345; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1330,10 +1332,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_3) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 1; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 1234; - tempnum->inode = 12345; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1436,10 +1438,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_Accum) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 1; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 1234; - tempnum->inode = 12345; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1527,250 +1529,6 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_Accum) Vector_Destroy(vecMarkerList, freeGMarker); } -/** - * Test: Log rotation corner case — new file grows past seek_value after rotation. - * - * Scenario: - * - Stored: seekValue=5000, inode=11111 for "Consolelog.txt.0" - * - Current "Consolelog.txt.0": size=8000, inode=22222 (DIFFERENT inode → rotation detected) - * - Rotated "Consolelog.txt.1": size=7000 (> 5000 → has unread data from offset 5000) - * - * Expected: reads rotated file from seek_value (5000) AND reads entire new current file. - * This verifies the inode-based rotation detection handles the flooding-logs corner case. - */ -TEST_F(dcaTestFixture, getDCAResultsInVector_InodeChanged_NewFileGrowsPastSeek) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 1; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 5000; - tempnum->inode = 11111; // Old inode before rotation - hash_map_put(gsProfile->logFileSeekMap, strdup("Consolelog.txt.0"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - memset(marker, 0, sizeof(GrepMarker)); - marker->markerName = strdup("SYS_INFO_ROTATION_TEST"); - marker->searchString = strdup("RotationMarker"); - marker->trimParam = true; - marker->regexParam = strdup("[0-9]+"); - marker->logFile = strdup("Consolelog.txt.0"); // Must match hash_map key - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->mType = MTYPE_COUNTER; - marker->u.count = 0; - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - // munmap for both main and rotated mmap regions - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .Times(2) - .WillRepeatedly(Return(0)); - - // close: tmp_rd, rd (rotated), tmp_fd (main), main fd - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(4) - .WillRepeatedly(Return(0)); - - // open: main file in getLogFileDescriptor, rotated file in getRotatedLogFileDescriptor - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(2) - .WillRepeatedly(Return(3)); - - // fstat calls: - // 1: getLogFileDescriptor on main → size=8000, inode=22222 (different from stored 11111) - // 2: getFileDeltaInMemMapAndSearch on main → size=8000 - // 3: getRotatedLogFileDescriptor on rotated → size=7000 - // 4: getFileDeltaInMemMapAndSearch on rotated → size=7000 - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(4) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 8000; - statbuf->st_ino = 22222; // Different inode → rotation detected - return 0; - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 8000; - statbuf->st_ino = 22222; - return 0; - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 7000; // Rotated file (old log) > seek_value (5000) - statbuf->st_ino = 11111; // Old inode - return 0; - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 7000; - statbuf->st_ino = 11111; - return 0; - }); - - // mkstemp: one for main tmp, one for rotated tmp - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .Times(2) - .WillRepeatedly(Return(4)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .Times(2) - .WillRepeatedly(Return(0)); - - // sendfile: main (8000 bytes), rotated (7000 bytes) - EXPECT_CALL(*g_fileIOMock, sendfile(_,_,_,_)) - .Times(2) - .WillOnce(Return(8000)) - .WillOnce(Return(7000)); - - // mmap: main file (entire, offset 0) + rotated file (from page-aligned seek offset) - // Both contain the marker — verifies both regions are searched - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(2) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - // Main file (new): mapped from offset 0 (entire file read) - const char* test_str = "New log data: RotationMarker value 42 found in new file\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - // Rotated file: mapped from seek offset (unread portion of old file) - const char* test_str = "Old unread data: RotationMarker value 99 in rotated file\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, false, "/opt/logs")); - - // Verify the marker was found in BOTH files (count should be 2) - EXPECT_EQ(2, marker->u.count); - - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, freeGMarker); -} - -/** - * Test: Multi-rotation corner case — rotated file is NOT the original. - * - * Scenario (from real device logs): - * - Stored: seekValue=5000, inode=11111 (original file, now at .log.2 or deeper) - * - Current "Consolelog.txt.0": size=8000, inode=22222 (newest file, rotation detected) - * - Rotated "Consolelog.txt.1": size=3000, inode=33333 (INTERMEDIATE file, NOT the original) - * - * Expected: reads ENTIRE rotated file from 0 AND ENTIRE new current file from 0. - * Without the fix, seek_value would be incorrectly applied to the intermediate - * rotated file, causing data loss (as seen with missing WPE_INFO_MigStatus_split). - */ -TEST_F(dcaTestFixture, getDCAResultsInVector_MultiRotation_IntermediateFile) -{ - GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); - gsProfile->logFileSeekMap = hash_map_create(); - gsProfile->execCounter = 1; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 5000; - tempnum->inode = 11111; // Original file inode (now at .log.2 or deeper) - hash_map_put(gsProfile->logFileSeekMap, strdup("Consolelog.txt.0"), (void*)tempnum, free); - - Vector* vecMarkerList = NULL; - Vector_Create(&vecMarkerList); - GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); - memset(marker, 0, sizeof(GrepMarker)); - marker->markerName = strdup("WPE_INFO_MigStatus"); - marker->searchString = strdup("Migration Status"); - marker->trimParam = true; - marker->regexParam = strdup("[A-Z_]+"); - marker->logFile = strdup("Consolelog.txt.0"); - marker->skipFreq = 0; - marker->paramType = strdup("grep"); - marker->mType = MTYPE_COUNTER; - marker->u.count = 0; - marker->reportEmptyParam = true; - Vector_PushBack(vecMarkerList, (void*) marker); - - EXPECT_CALL(*g_fileIOMock, munmap(_, _)) - .Times(2) - .WillRepeatedly(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(_)) - .Times(4) - .WillRepeatedly(Return(0)); - EXPECT_CALL(*g_fileIOMock, open(_,_)) - .Times(2) - .WillRepeatedly(Return(3)); - - // fstat: main inode=22222, rotated inode=33333 (DIFFERENT from stored 11111) - EXPECT_CALL(*g_fileIOMock, fstat(_, _)) - .Times(4) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 8000; - statbuf->st_ino = 22222; // Current file — different from stored - return 0; - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 8000; - statbuf->st_ino = 22222; - return 0; - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 3000; // Intermediate rotated file - statbuf->st_ino = 33333; // DIFFERENT from stored 11111 — multi-rotation! - return 0; - }) - .WillOnce([](int fd, struct stat* statbuf) { - statbuf->st_size = 3000; - statbuf->st_ino = 33333; - return 0; - }); - - EXPECT_CALL(*g_fileIOMock, mkstemp(_)) - .Times(2) - .WillRepeatedly(Return(4)); - EXPECT_CALL(*g_systemMock, unlink(_)) - .Times(2) - .WillRepeatedly(Return(0)); - EXPECT_CALL(*g_fileIOMock, sendfile(_,_,_,_)) - .Times(2) - .WillOnce(Return(8000)) - .WillOnce(Return(3000)); - - // Both files mapped from offset 0 — multi-rotation reads everything - EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) - .Times(2) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - // Main file: entire new file read from offset 0 - EXPECT_EQ(0, offset); - const char* test_str = "New file: Migration Status is COMPLETED in current\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }) - .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - // Rotated (intermediate) file: read entirely from offset 0 - EXPECT_EQ(0, offset); - const char* test_str = "Intermediate: Migration Status is STARTED in rotated\n"; - char* mapped_mem = (char*)malloc(length); - memset(mapped_mem, 0, length); - strncpy(mapped_mem, test_str, length - 1); - return (void*)mapped_mem; - }); - - EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, false, "/opt/logs")); - - // Marker found in BOTH files (no data lost from intermediate file) - EXPECT_EQ(2, marker->u.count); - - hash_map_destroy(gsProfile->logFileSeekMap, free); - gsProfile->logFileSeekMap = NULL; - free(gsProfile); - Vector_Destroy(vecMarkerList, freeGMarker); -} - TEST_F(dcaTestFixture, T2InitProperties) { EXPECT_CALL(*g_fileIOMock, fopen(_,_)) @@ -1797,10 +1555,10 @@ TEST_F(dcaTestFixture, getGrepResults_success) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - LogSeekInfo *tempnum; - tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); - tempnum->seekValue = 1234; - tempnum->inode = 12345; + long *tempnum; + double val = 1234; + tempnum = (long *)malloc(sizeof(long)); + *tempnum = (long)val; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1870,13 +1628,437 @@ TEST_F(dcaTestFixture, getGrepResults_success) free(gsProfile); Vector_Destroy(vecMarkerList, freeGMarker); } + +// waitForBackupLogsDone L1 tests + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelAlreadyPresent) +{ + // Fast path: access() returns 0 meaning sentinel file exists + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyInitFails) +{ + // access() returns -1 (sentinel not present), inotify_init1 fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(-1)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyAddWatchFails) +{ + // access() returns -1, inotify_init1 succeeds, inotify_add_watch fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_RaceResolved) +{ + // First access() returns -1, inotify setup succeeds, second access() returns 0 (race resolved) + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFails) +{ + // access() returns -1 both times, inotify setup succeeds, clock_gettime fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_Timeout) +{ + // Sentinel never appears, select returns 0 (timeout heartbeat), deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + + // First clock_gettime sets the deadline (tv_sec=100) + // Second clock_gettime returns past deadline (tv_sec >= 100 + BACKUP_LOGS_SYNC_TIMEOUT_S) + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectFails) +{ + // select() fails with non-EINTR error + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline yet + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { + errno = EBADF; + return -1; + }); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectEINTR) +{ + // select() returns EINTR, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; // Past deadline + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { + errno = EINTR; + return -1; + }); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelDetectedViaInotify) +{ + // Sentinel detected via inotify event + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); // Data available to read + + // Construct a fake inotify_event with the sentinel filename + struct inotify_event fake_event; + fake_event.wd = 1; + fake_event.mask = IN_CREATE; + fake_event.cookie = 0; + fake_event.len = strlen(BACKUP_LOGS_DONE_FILENAME) + 1; + + // Build the buffer: struct inotify_event + filename (null-terminated) + size_t event_size = sizeof(struct inotify_event) + fake_event.len; + char *event_buf = (char *)malloc(event_size); + memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); + memcpy(event_buf + sizeof(struct inotify_event), BACKUP_LOGS_DONE_FILENAME, fake_event.len); + + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { + size_t copy_size = (event_size < count) ? event_size : count; + memcpy(buf, event_buf, copy_size); + return (ssize_t)copy_size; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); + free(event_buf); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_ReadReturnsZero) +{ + // select() returns data ready, but read() returns 0 — loop back, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_UnrelatedInotifyEvent) +{ + // An inotify event for a different file, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); + + // Construct an inotify event for a different filename + const char *other_file = "other_file.txt"; + struct inotify_event fake_event; + fake_event.wd = 1; + fake_event.mask = IN_CREATE; + fake_event.cookie = 0; + fake_event.len = strlen(other_file) + 1; + + size_t event_size = sizeof(struct inotify_event) + fake_event.len; + char *event_buf = (char *)malloc(event_size); + memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); + memcpy(event_buf + sizeof(struct inotify_event), other_file, fake_event.len); + + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { + size_t copy_size = (event_size < count) ? event_size : count; + memcpy(buf, event_buf, copy_size); + return (ssize_t)copy_size; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); + free(event_buf); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFailsInLoop) +{ + // clock_gettime succeeds initially but fails inside the while loop + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce(Return(-1)); // Fails in the loop + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + #ifdef GTEST_ENABLE extern "C" { typedef const char *(*strnstrFunc)(const char *, const char *, size_t); strnstrFunc strnstrFuncCallback(void); typedef time_t (*extractUnixTimestampFunc)(const char*, size_t); extractUnixTimestampFunc extractUnixTimestampFuncCallback(void); -typedef T2ERROR (*updateLogSeekFunc)(hash_map_t *, const char *, const long, const ino_t); +typedef T2ERROR (*updateLogSeekFunc)(hash_map_t *, const char *, const long); updateLogSeekFunc updateLogSeekFuncCallback(void); } TEST(StaticStrnstrFunc, CoversMainBranches) @@ -1947,11 +2129,11 @@ TEST(StaticUpdateLogSeekFunc, CoversNullBranches) ASSERT_NE(fn, nullptr); // First branch: logSeekMap == NULL - EXPECT_EQ(fn(NULL, "dummy.log", 100, 12345), T2ERROR_FAILURE); + EXPECT_EQ(fn(NULL, "dummy.log", 100), T2ERROR_FAILURE); // Second branch: logFileName == NULL hash_map_t dummyMap; - EXPECT_EQ(fn(&dummyMap, NULL, 100, 12345), T2ERROR_FAILURE); + EXPECT_EQ(fn(&dummyMap, NULL, 100), T2ERROR_FAILURE); // Additional test for a stub/empty map and filename to reach further code // (Will continue past the NULL check; optionally extend to later logic in the function) From aaacb42f8bdaf37b3b734919c78f748fe117afe2 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 14:13:02 +0530 Subject: [PATCH 20/36] 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 4777b646a..d63568a4c 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Log in to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} From 3bfd0469d2ebcd2a0609e3d17b6d11180207a801 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:53:25 +0530 Subject: [PATCH 21/36] Update L1-tests.yml --- .github/workflows/L1-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index d63568a4c..a3793df71 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -7,6 +7,7 @@ on: env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} AUTOMATICS_PASSCODE: ${{ secrets.AUTOMATICS_PASSCODE }} + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true jobs: execute-L1-tests-on-pr: From e1e08677997412a707c854eb61fa99209bfb1af3 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 17:35:21 +0530 Subject: [PATCH 22/36] Update dcautilTest.cpp --- source/test/dcautils/dcautilTest.cpp | 300 ++++++++++++++++++++++++--- 1 file changed, 271 insertions(+), 29 deletions(-) diff --git a/source/test/dcautils/dcautilTest.cpp b/source/test/dcautils/dcautilTest.cpp index 05407e4d8..a091db1fd 100644 --- a/source/test/dcautils/dcautilTest.cpp +++ b/source/test/dcautils/dcautilTest.cpp @@ -31,8 +31,6 @@ extern "C" { #include #include #include -#include -#include #include #include #include "utils/vector.h" @@ -642,10 +640,10 @@ TEST_F(dcaTestFixture, saveSeekConfigtoFile) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - long *tempnum; - double val = 123456; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 123456; + tempnum->inode = 12345; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); FILE* fp = (FILE*)NULL; EXPECT_CALL(*g_fileIOMock, fopen(_,_)) @@ -1172,10 +1170,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_1) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 1234; + tempnum->inode = 12345; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1251,10 +1249,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_2) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 1234; + tempnum->inode = 12345; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1332,10 +1330,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_3) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 1; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 1234; + tempnum->inode = 12345; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1438,10 +1436,10 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_Accum) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 1; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 1234; + tempnum->inode = 12345; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -1529,6 +1527,250 @@ TEST_F(dcaTestFixture, getDCAResultsInVector_Accum) Vector_Destroy(vecMarkerList, freeGMarker); } +/** + * Test: Log rotation corner case — new file grows past seek_value after rotation. + * + * Scenario: + * - Stored: seekValue=5000, inode=11111 for "Consolelog.txt.0" + * - Current "Consolelog.txt.0": size=8000, inode=22222 (DIFFERENT inode → rotation detected) + * - Rotated "Consolelog.txt.1": size=7000 (> 5000 → has unread data from offset 5000) + * + * Expected: reads rotated file from seek_value (5000) AND reads entire new current file. + * This verifies the inode-based rotation detection handles the flooding-logs corner case. + */ +TEST_F(dcaTestFixture, getDCAResultsInVector_InodeChanged_NewFileGrowsPastSeek) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 1; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 5000; + tempnum->inode = 11111; // Old inode before rotation + hash_map_put(gsProfile->logFileSeekMap, strdup("Consolelog.txt.0"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + memset(marker, 0, sizeof(GrepMarker)); + marker->markerName = strdup("SYS_INFO_ROTATION_TEST"); + marker->searchString = strdup("RotationMarker"); + marker->trimParam = true; + marker->regexParam = strdup("[0-9]+"); + marker->logFile = strdup("Consolelog.txt.0"); // Must match hash_map key + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->mType = MTYPE_COUNTER; + marker->u.count = 0; + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + // munmap for both main and rotated mmap regions + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .Times(2) + .WillRepeatedly(Return(0)); + + // close: tmp_rd, rd (rotated), tmp_fd (main), main fd + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(4) + .WillRepeatedly(Return(0)); + + // open: main file in getLogFileDescriptor, rotated file in getRotatedLogFileDescriptor + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(2) + .WillRepeatedly(Return(3)); + + // fstat calls: + // 1: getLogFileDescriptor on main → size=8000, inode=22222 (different from stored 11111) + // 2: getFileDeltaInMemMapAndSearch on main → size=8000 + // 3: getRotatedLogFileDescriptor on rotated → size=7000 + // 4: getFileDeltaInMemMapAndSearch on rotated → size=7000 + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(4) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 8000; + statbuf->st_ino = 22222; // Different inode → rotation detected + return 0; + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 8000; + statbuf->st_ino = 22222; + return 0; + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 7000; // Rotated file (old log) > seek_value (5000) + statbuf->st_ino = 11111; // Old inode + return 0; + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 7000; + statbuf->st_ino = 11111; + return 0; + }); + + // mkstemp: one for main tmp, one for rotated tmp + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .Times(2) + .WillRepeatedly(Return(4)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(2) + .WillRepeatedly(Return(0)); + + // sendfile: main (8000 bytes), rotated (7000 bytes) + EXPECT_CALL(*g_fileIOMock, sendfile(_,_,_,_)) + .Times(2) + .WillOnce(Return(8000)) + .WillOnce(Return(7000)); + + // mmap: main file (entire, offset 0) + rotated file (from page-aligned seek offset) + // Both contain the marker — verifies both regions are searched + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(2) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + // Main file (new): mapped from offset 0 (entire file read) + const char* test_str = "New log data: RotationMarker value 42 found in new file\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + // Rotated file: mapped from seek offset (unread portion of old file) + const char* test_str = "Old unread data: RotationMarker value 99 in rotated file\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, false, "/opt/logs")); + + // Verify the marker was found in BOTH files (count should be 2) + EXPECT_EQ(2, marker->u.count); + + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, freeGMarker); +} + +/** + * Test: Multi-rotation corner case — rotated file is NOT the original. + * + * Scenario (from real device logs): + * - Stored: seekValue=5000, inode=11111 (original file, now at .log.2 or deeper) + * - Current "Consolelog.txt.0": size=8000, inode=22222 (newest file, rotation detected) + * - Rotated "Consolelog.txt.1": size=3000, inode=33333 (INTERMEDIATE file, NOT the original) + * + * Expected: reads ENTIRE rotated file from 0 AND ENTIRE new current file from 0. + * Without the fix, seek_value would be incorrectly applied to the intermediate + * rotated file, causing data loss (as seen with missing WPE_INFO_MigStatus_split). + */ +TEST_F(dcaTestFixture, getDCAResultsInVector_MultiRotation_IntermediateFile) +{ + GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); + gsProfile->logFileSeekMap = hash_map_create(); + gsProfile->execCounter = 1; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 5000; + tempnum->inode = 11111; // Original file inode (now at .log.2 or deeper) + hash_map_put(gsProfile->logFileSeekMap, strdup("Consolelog.txt.0"), (void*)tempnum, free); + + Vector* vecMarkerList = NULL; + Vector_Create(&vecMarkerList); + GrepMarker* marker = (GrepMarker*) malloc(sizeof(GrepMarker)); + memset(marker, 0, sizeof(GrepMarker)); + marker->markerName = strdup("WPE_INFO_MigStatus"); + marker->searchString = strdup("Migration Status"); + marker->trimParam = true; + marker->regexParam = strdup("[A-Z_]+"); + marker->logFile = strdup("Consolelog.txt.0"); + marker->skipFreq = 0; + marker->paramType = strdup("grep"); + marker->mType = MTYPE_COUNTER; + marker->u.count = 0; + marker->reportEmptyParam = true; + Vector_PushBack(vecMarkerList, (void*) marker); + + EXPECT_CALL(*g_fileIOMock, munmap(_, _)) + .Times(2) + .WillRepeatedly(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(_)) + .Times(4) + .WillRepeatedly(Return(0)); + EXPECT_CALL(*g_fileIOMock, open(_,_)) + .Times(2) + .WillRepeatedly(Return(3)); + + // fstat: main inode=22222, rotated inode=33333 (DIFFERENT from stored 11111) + EXPECT_CALL(*g_fileIOMock, fstat(_, _)) + .Times(4) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 8000; + statbuf->st_ino = 22222; // Current file — different from stored + return 0; + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 8000; + statbuf->st_ino = 22222; + return 0; + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 3000; // Intermediate rotated file + statbuf->st_ino = 33333; // DIFFERENT from stored 11111 — multi-rotation! + return 0; + }) + .WillOnce([](int fd, struct stat* statbuf) { + statbuf->st_size = 3000; + statbuf->st_ino = 33333; + return 0; + }); + + EXPECT_CALL(*g_fileIOMock, mkstemp(_)) + .Times(2) + .WillRepeatedly(Return(4)); + EXPECT_CALL(*g_systemMock, unlink(_)) + .Times(2) + .WillRepeatedly(Return(0)); + EXPECT_CALL(*g_fileIOMock, sendfile(_,_,_,_)) + .Times(2) + .WillOnce(Return(8000)) + .WillOnce(Return(3000)); + + // Both files mapped from offset 0 — multi-rotation reads everything + EXPECT_CALL(*g_fileIOMock, mmap(_,_,_,_,_,_)) + .Times(2) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + // Main file: entire new file read from offset 0 + EXPECT_EQ(0, offset); + const char* test_str = "New file: Migration Status is COMPLETED in current\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }) + .WillOnce([](void *addr, size_t length, int prot, int flags, int fd, off_t offset) { + // Rotated (intermediate) file: read entirely from offset 0 + EXPECT_EQ(0, offset); + const char* test_str = "Intermediate: Migration Status is STARTED in rotated\n"; + char* mapped_mem = (char*)malloc(length); + memset(mapped_mem, 0, length); + strncpy(mapped_mem, test_str, length - 1); + return (void*)mapped_mem; + }); + + EXPECT_EQ(0, getDCAResultsInVector(gsProfile, vecMarkerList, false, "/opt/logs")); + + // Marker found in BOTH files (no data lost from intermediate file) + EXPECT_EQ(2, marker->u.count); + + hash_map_destroy(gsProfile->logFileSeekMap, free); + gsProfile->logFileSeekMap = NULL; + free(gsProfile); + Vector_Destroy(vecMarkerList, freeGMarker); +} + TEST_F(dcaTestFixture, T2InitProperties) { EXPECT_CALL(*g_fileIOMock, fopen(_,_)) @@ -1555,10 +1797,10 @@ TEST_F(dcaTestFixture, getGrepResults_success) GrepSeekProfile *gsProfile = (GrepSeekProfile *)malloc(sizeof(GrepSeekProfile)); gsProfile->logFileSeekMap = hash_map_create(); gsProfile->execCounter = 0; - long *tempnum; - double val = 1234; - tempnum = (long *)malloc(sizeof(long)); - *tempnum = (long)val; + LogSeekInfo *tempnum; + tempnum = (LogSeekInfo *)malloc(sizeof(LogSeekInfo)); + tempnum->seekValue = 1234; + tempnum->inode = 12345; hash_map_put(gsProfile->logFileSeekMap, strdup("t2_log.txt"), (void*)tempnum, free); Vector* vecMarkerList = NULL; @@ -2058,7 +2300,7 @@ typedef const char *(*strnstrFunc)(const char *, const char *, size_t); strnstrFunc strnstrFuncCallback(void); typedef time_t (*extractUnixTimestampFunc)(const char*, size_t); extractUnixTimestampFunc extractUnixTimestampFuncCallback(void); -typedef T2ERROR (*updateLogSeekFunc)(hash_map_t *, const char *, const long); +typedef T2ERROR (*updateLogSeekFunc)(hash_map_t *, const char *, const long, const ino_t); updateLogSeekFunc updateLogSeekFuncCallback(void); } TEST(StaticStrnstrFunc, CoversMainBranches) @@ -2129,11 +2371,11 @@ TEST(StaticUpdateLogSeekFunc, CoversNullBranches) ASSERT_NE(fn, nullptr); // First branch: logSeekMap == NULL - EXPECT_EQ(fn(NULL, "dummy.log", 100), T2ERROR_FAILURE); + EXPECT_EQ(fn(NULL, "dummy.log", 100, 12345), T2ERROR_FAILURE); // Second branch: logFileName == NULL hash_map_t dummyMap; - EXPECT_EQ(fn(&dummyMap, NULL, 100), T2ERROR_FAILURE); + EXPECT_EQ(fn(&dummyMap, NULL, 100, 12345), T2ERROR_FAILURE); // Additional test for a stub/empty map and filename to reach further code // (Will continue past the NULL check; optionally extend to later logic in the function) From ea1c091ea48f305fe3156ff17dfae0a721b83c69 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:33:39 +0530 Subject: [PATCH 23/36] Update SystemMock.h --- source/test/mocks/SystemMock.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/test/mocks/SystemMock.h b/source/test/mocks/SystemMock.h index e32b3e376..4d8e35e2e 100644 --- a/source/test/mocks/SystemMock.h +++ b/source/test/mocks/SystemMock.h @@ -40,6 +40,11 @@ class SystemMock }; extern SystemMock* g_systemMock; +/* Separate enable flags for clock_gettime/select mocking — + * these must NOT be globally intercepted when g_systemMock is active + * because gtest itself calls clock_gettime for timing. */ +extern bool g_mockClockGettime; +extern bool g_mockSelect; extern "C" int system(const char* cmd); extern "C" int unlink(const char* str); From f1be14845ee50a4e30d4057e2947a9165db1c1df Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:34:26 +0530 Subject: [PATCH 24/36] Update SystemMock.cpp --- source/test/mocks/SystemMock.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/source/test/mocks/SystemMock.cpp b/source/test/mocks/SystemMock.cpp index ee0b5f679..2d2ab56c8 100644 --- a/source/test/mocks/SystemMock.cpp +++ b/source/test/mocks/SystemMock.cpp @@ -30,6 +30,7 @@ typedef int (*inotify_rm_watch_ptr) (int fd, int wd); typedef int (*clock_gettime_ptr) (clockid_t clk_id, struct timespec *tp); typedef int (*select_ptr) (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); + system_ptr system_func = (system_ptr) dlsym(RTLD_NEXT, "system"); unlink_ptr unlink_func = (unlink_ptr) dlsym(RTLD_NEXT, "unlink"); access_ptr access_func = (access_ptr) dlsym(RTLD_NEXT, "access"); @@ -40,6 +41,12 @@ inotify_rm_watch_ptr inotify_rm_watch_func = (inotify_rm_watch_ptr) dlsym(RTLD_N clock_gettime_ptr clock_gettime_func = (clock_gettime_ptr) dlsym(RTLD_NEXT, "clock_gettime"); select_ptr select_func = (select_ptr) dlsym(RTLD_NEXT, "select"); +/* Flags default to false — clock_gettime/select are only intercepted when + * a test explicitly enables them to avoid breaking gtest internals. */ +bool g_mockClockGettime = false; +bool g_mockSelect = false; + + // Mock Method extern "C" int system(const char * cmd) { @@ -106,18 +113,18 @@ extern "C" int inotify_rm_watch(int fd, int wd) extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp) { - if (!g_systemMock) + if (g_systemMock && g_mockClockGettime) { - return clock_gettime_func(clk_id, tp); + return g_systemMock->clock_gettime(clk_id, tp); } - return g_systemMock->clock_gettime(clk_id, tp); + return clock_gettime_func(clk_id, tp); } extern "C" int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { - if (!g_systemMock) + if (g_systemMock && g_mockSelect) { - return select_func(nfds, readfds, writefds, exceptfds, timeout); + return g_systemMock->select(nfds, readfds, writefds, exceptfds, timeout); } - return g_systemMock->select(nfds, readfds, writefds, exceptfds, timeout); -} + return select_func(nfds, readfds, writefds, exceptfds, timeout); +} From 99704040d3697b85fb500daf7e9a269ac4faa83d Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:35:18 +0530 Subject: [PATCH 25/36] Update dcautilTest.cpp --- source/test/dcautils/dcautilTest.cpp | 441 +++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) diff --git a/source/test/dcautils/dcautilTest.cpp b/source/test/dcautils/dcautilTest.cpp index a091db1fd..f5c1ee5ea 100644 --- a/source/test/dcautils/dcautilTest.cpp +++ b/source/test/dcautils/dcautilTest.cpp @@ -2294,6 +2294,447 @@ TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFailsInLoop) EXPECT_EQ(false, waitForBackupLogsDone()); } +// waitForBackupLogsDone L1 tests + +/* Fixture that enables clock_gettime/select mocking only during tests + * that need them — avoids intercepting gtest's internal timing calls. */ +class waitForBackupLogsDoneFixture : public dcaTestFixture { +protected: + void SetUp() override + { + dcaTestFixture::SetUp(); + g_mockClockGettime = true; + g_mockSelect = true; + } + void TearDown() override + { + g_mockClockGettime = false; + g_mockSelect = false; + dcaTestFixture::TearDown(); + } +}; + +TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelAlreadyPresent) +{ + // Fast path: access() returns 0 meaning sentinel file exists + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyInitFails) +{ + // access() returns -1 (sentinel not present), inotify_init1 fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(-1)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyAddWatchFails) +{ + // access() returns -1, inotify_init1 succeeds, inotify_add_watch fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(dcaTestFixture, waitForBackupLogsDone_RaceResolved) +{ + // First access() returns -1, inotify setup succeeds, second access() returns 0 (race resolved) + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_ClockGettimeFails) +{ + // access() returns -1 both times, inotify setup succeeds, clock_gettime fails + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(1) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_Timeout) +{ + // Sentinel never appears, select returns 0 (timeout heartbeat), deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + + // First clock_gettime sets the deadline (tv_sec=100) + // Second clock_gettime returns past deadline (tv_sec >= 100 + BACKUP_LOGS_SYNC_TIMEOUT_S) + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_SelectFails) +{ + // select() fails with non-EINTR error + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline yet + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { + errno = EBADF; + return -1; + }); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_SelectEINTR) +{ + // select() returns EINTR, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; // Past deadline + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { + errno = EINTR; + return -1; + }); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_SentinelDetectedViaInotify) +{ + // Sentinel detected via inotify event + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; // Not past deadline + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); // Data available to read + + // Construct a fake inotify_event with the sentinel filename + struct inotify_event fake_event; + fake_event.wd = 1; + fake_event.mask = IN_CREATE; + fake_event.cookie = 0; + fake_event.len = strlen(BACKUP_LOGS_DONE_FILENAME) + 1; + + // Build the buffer: struct inotify_event + filename (null-terminated) + size_t event_size = sizeof(struct inotify_event) + fake_event.len; + char *event_buf = (char *)malloc(event_size); + memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); + memcpy(event_buf + sizeof(struct inotify_event), BACKUP_LOGS_DONE_FILENAME, fake_event.len); + + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { + size_t copy_size = (event_size < count) ? event_size : count; + memcpy(buf, event_buf, copy_size); + return (ssize_t)copy_size; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(true, waitForBackupLogsDone()); + free(event_buf); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_ReadReturnsZero) +{ + // select() returns data ready, but read() returns 0 — loop back, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_UnrelatedInotifyEvent) +{ + // An inotify event for a different file, then deadline expires + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(3) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; + tp->tv_nsec = 0; + return 0; + }); + EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) + .Times(1) + .WillOnce(Return(1)); + + // Construct an inotify event for a different filename + const char *other_file = "other_file.txt"; + struct inotify_event fake_event; + fake_event.wd = 1; + fake_event.mask = IN_CREATE; + fake_event.cookie = 0; + fake_event.len = strlen(other_file) + 1; + + size_t event_size = sizeof(struct inotify_event) + fake_event.len; + char *event_buf = (char *)malloc(event_size); + memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); + memcpy(event_buf + sizeof(struct inotify_event), other_file, fake_event.len); + + EXPECT_CALL(*g_fileIOMock, read(5, _, _)) + .Times(1) + .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { + size_t copy_size = (event_size < count) ? event_size : count; + memcpy(buf, event_buf, copy_size); + return (ssize_t)copy_size; + }); + + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); + free(event_buf); +} + +TEST_F(waitForBackupLogsDoneFixture, waitForBackupLogsDone_ClockGettimeFailsInLoop) +{ + // clock_gettime succeeds initially but fails inside the while loop + EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) + .Times(2) + .WillOnce(Return(-1)) + .WillOnce(Return(-1)); + EXPECT_CALL(*g_systemMock, inotify_init1(_)) + .Times(1) + .WillOnce(Return(5)); + EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) + .Times(1) + .WillOnce(Return(1)); + EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) + .Times(2) + .WillOnce([](clockid_t, struct timespec *tp) { + tp->tv_sec = 100; + tp->tv_nsec = 0; + return 0; + }) + .WillOnce(Return(-1)); // Fails in the loop + EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_fileIOMock, close(5)) + .Times(1) + .WillOnce(Return(0)); + + EXPECT_EQ(false, waitForBackupLogsDone()); +} + #ifdef GTEST_ENABLE extern "C" { typedef const char *(*strnstrFunc)(const char *, const char *, size_t); From a352a6239904e58647a66ed4e9dd8339616af55f Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:36:28 +0530 Subject: [PATCH 26/36] Update L1-tests.yml --- .github/workflows/L1-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index a3793df71..4777b646a 100644 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -7,7 +7,6 @@ on: env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} AUTOMATICS_PASSCODE: ${{ secrets.AUTOMATICS_PASSCODE }} - ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true jobs: execute-L1-tests-on-pr: @@ -19,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} From 8d0c205e7397217eb3ad4ad9a7756a3ab4db0869 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 20:58:48 +0530 Subject: [PATCH 27/36] Update dcautilTest.cpp --- source/test/dcautils/dcautilTest.cpp | 423 --------------------------- 1 file changed, 423 deletions(-) diff --git a/source/test/dcautils/dcautilTest.cpp b/source/test/dcautils/dcautilTest.cpp index f5c1ee5ea..a8113dffb 100644 --- a/source/test/dcautils/dcautilTest.cpp +++ b/source/test/dcautils/dcautilTest.cpp @@ -1873,429 +1873,6 @@ TEST_F(dcaTestFixture, getGrepResults_success) // waitForBackupLogsDone L1 tests -TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelAlreadyPresent) -{ - // Fast path: access() returns 0 meaning sentinel file exists - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(true, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyInitFails) -{ - // access() returns -1 (sentinel not present), inotify_init1 fails - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(-1)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_InotifyAddWatchFails) -{ - // access() returns -1, inotify_init1 succeeds, inotify_add_watch fails - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_RaceResolved) -{ - // First access() returns -1, inotify setup succeeds, second access() returns 0 (race resolved) - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(true, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFails) -{ - // access() returns -1 both times, inotify setup succeeds, clock_gettime fails - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(1) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_Timeout) -{ - // Sentinel never appears, select returns 0 (timeout heartbeat), deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - - // First clock_gettime sets the deadline (tv_sec=100) - // Second clock_gettime returns past deadline (tv_sec >= 100 + BACKUP_LOGS_SYNC_TIMEOUT_S) - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; - tp->tv_nsec = 0; - return 0; - }); - - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectFails) -{ - // select() fails with non-EINTR error - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; // Not past deadline yet - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { - errno = EBADF; - return -1; - }); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SelectEINTR) -{ - // select() returns EINTR, then deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(3) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; // Not past deadline - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; // Past deadline - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce([](int, fd_set*, fd_set*, fd_set*, struct timeval*) { - errno = EINTR; - return -1; - }); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_SentinelDetectedViaInotify) -{ - // Sentinel detected via inotify event - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; // Not past deadline - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(1)); // Data available to read - - // Construct a fake inotify_event with the sentinel filename - struct inotify_event fake_event; - fake_event.wd = 1; - fake_event.mask = IN_CREATE; - fake_event.cookie = 0; - fake_event.len = strlen(BACKUP_LOGS_DONE_FILENAME) + 1; - - // Build the buffer: struct inotify_event + filename (null-terminated) - size_t event_size = sizeof(struct inotify_event) + fake_event.len; - char *event_buf = (char *)malloc(event_size); - memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); - memcpy(event_buf + sizeof(struct inotify_event), BACKUP_LOGS_DONE_FILENAME, fake_event.len); - - EXPECT_CALL(*g_fileIOMock, read(5, _, _)) - .Times(1) - .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { - size_t copy_size = (event_size < count) ? event_size : count; - memcpy(buf, event_buf, copy_size); - return (ssize_t)copy_size; - }); - - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(true, waitForBackupLogsDone()); - free(event_buf); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_ReadReturnsZero) -{ - // select() returns data ready, but read() returns 0 — loop back, then deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(3) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_fileIOMock, read(5, _, _)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_UnrelatedInotifyEvent) -{ - // An inotify event for a different file, then deadline expires - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(3) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100 + BACKUP_LOGS_SYNC_TIMEOUT_S; - tp->tv_nsec = 0; - return 0; - }); - EXPECT_CALL(*g_systemMock, select(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(1)); - - // Construct an inotify event for a different filename - const char *other_file = "other_file.txt"; - struct inotify_event fake_event; - fake_event.wd = 1; - fake_event.mask = IN_CREATE; - fake_event.cookie = 0; - fake_event.len = strlen(other_file) + 1; - - size_t event_size = sizeof(struct inotify_event) + fake_event.len; - char *event_buf = (char *)malloc(event_size); - memcpy(event_buf, &fake_event, sizeof(struct inotify_event)); - memcpy(event_buf + sizeof(struct inotify_event), other_file, fake_event.len); - - EXPECT_CALL(*g_fileIOMock, read(5, _, _)) - .Times(1) - .WillOnce([event_buf, event_size](int, void* buf, size_t count) -> ssize_t { - size_t copy_size = (event_size < count) ? event_size : count; - memcpy(buf, event_buf, copy_size); - return (ssize_t)copy_size; - }); - - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); - free(event_buf); -} - -TEST_F(dcaTestFixture, waitForBackupLogsDone_ClockGettimeFailsInLoop) -{ - // clock_gettime succeeds initially but fails inside the while loop - EXPECT_CALL(*g_systemMock, access(StrEq(BACKUP_LOGS_DONE_FLAG), _)) - .Times(2) - .WillOnce(Return(-1)) - .WillOnce(Return(-1)); - EXPECT_CALL(*g_systemMock, inotify_init1(_)) - .Times(1) - .WillOnce(Return(5)); - EXPECT_CALL(*g_systemMock, inotify_add_watch(5, StrEq(BACKUP_LOGS_DONE_DIR), _)) - .Times(1) - .WillOnce(Return(1)); - EXPECT_CALL(*g_systemMock, clock_gettime(_, _)) - .Times(2) - .WillOnce([](clockid_t, struct timespec *tp) { - tp->tv_sec = 100; - tp->tv_nsec = 0; - return 0; - }) - .WillOnce(Return(-1)); // Fails in the loop - EXPECT_CALL(*g_systemMock, inotify_rm_watch(5, 1)) - .Times(1) - .WillOnce(Return(0)); - EXPECT_CALL(*g_fileIOMock, close(5)) - .Times(1) - .WillOnce(Return(0)); - - EXPECT_EQ(false, waitForBackupLogsDone()); -} - -// waitForBackupLogsDone L1 tests - /* Fixture that enables clock_gettime/select mocking only during tests * that need them — avoids intercepting gtest's internal timing calls. */ class waitForBackupLogsDoneFixture : public dcaTestFixture { From d41909af8c7c5763686c039071aaf3ee51f4ea20 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:16:42 +0530 Subject: [PATCH 28/36] Update code-coverage.yml --- .github/workflows/code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 5ad3ac07f..706a0152b 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -2,7 +2,7 @@ name: Code Coverage on: pull_request: - branches: [ main] + branches: [ develop] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} From 40151d805eba57256ecee74302038a2b09aa0551 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 21:18:58 +0530 Subject: [PATCH 29/36] Create test_backup_logs_sync.py --- .../tests/test_backup_logs_sync.py | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 test/functional-tests/tests/test_backup_logs_sync.py diff --git a/test/functional-tests/tests/test_backup_logs_sync.py b/test/functional-tests/tests/test_backup_logs_sync.py new file mode 100644 index 000000000..2f795bc15 --- /dev/null +++ b/test/functional-tests/tests/test_backup_logs_sync.py @@ -0,0 +1,213 @@ +#################################################################################### +# If not stated otherwise in this file or this component's Licenses 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. +#################################################################################### + +""" +L2 functional tests for the backup_logs synchronisation gate +(waitForBackupLogsDone) added to dcautil.c. + +The function uses inotify to wait for /tmp/.backup_logs_done before +grepping PreviousLogs. These tests exercise: + 1. Fast path – sentinel already present at grep time. + 2. Inotify – sentinel created while the daemon is waiting. + 3. Timeout – sentinel never appears; daemon proceeds after 60 s. + 4. Completion – /tmp/.telemetry_prevlogs_done created after grep. +""" + +import json +import os +import subprocess +import threading +from datetime import datetime as dt +from time import sleep + +import base64 +import msgpack +import pytest + +from basic_constants import * +from helper_functions import * + +# ── Sentinel paths (must match dcautil.h) ──────────────────────────── +BACKUP_LOGS_DONE_FLAG = "/tmp/.backup_logs_done" +TELEMETRY_PREVLOGS_DONE_FLAG = "/tmp/.telemetry_prevlogs_done" +PREVIOUS_LOGS_DIR = "/opt/logs/PreviousLogs" +PREVIOUS_LOGS_FILE = os.path.join(PREVIOUS_LOGS_DIR, "backup_sync_test.txt") +PREVIOUS_LOGS_CONTENT = "backup_sync_test_marker_value_12345" + +# ── Profile that greps a PreviousLogs file with GenerateNow ────────── +_PROFILE_BACKUP_SYNC = json.dumps({ + "profiles": [{ + "name": "BACKUP_SYNC_TEST", + "hash": "hash_backup_sync_001", + "value": { + "Name": "BACKUP_SYNC_TEST", + "Description": "L2 test for backup_logs synchronisation gate", + "Version": "0.1", + "Protocol": "HTTP", + "EncodingType": "JSON", + "ActivationTimeOut": 180, + "ReportingInterval": 120, + "GenerateNow": True, + "RootName": "backup_sync_report", + "Parameter": [ + { + "type": "grep", + "marker": "PREVLOG_SYNC_MARKER", + "search": "backup_sync_test_marker_value", + "logFile": "backup_sync_test.txt", + "use": "absolute" + } + ] + } + }] +}) + +LOG_PROFILE_ENABLE = "Successfully enabled profile :" + +def _tomsgpack(json_string): + data = json.loads(json_string) + return base64.b64encode(msgpack.packb(data)).decode("utf-8") + +def _clean_sentinels(): + """Remove both sentinel files so each test starts clean.""" + for path in (BACKUP_LOGS_DONE_FLAG, TELEMETRY_PREVLOGS_DONE_FLAG): + try: + os.remove(path) + except FileNotFoundError: + pass + +def _create_previous_logs(): + """Populate the PreviousLogs directory with a known test file.""" + os.makedirs(PREVIOUS_LOGS_DIR, exist_ok=True) + with open(PREVIOUS_LOGS_FILE, "w") as f: + f.write(PREVIOUS_LOGS_CONTENT + "\n") + f.write("second line in backup sync test log\n") + +def _full_reset(): + """Kill daemon, remove flags/sentinels, recreate PreviousLogs.""" + kill_telemetry(9) + sleep(1) + remove_T2bootup_flag() + clear_persistant_files() + _clean_sentinels() + _create_previous_logs() + clear_T2logs() + + +# ── Test 1: fast path – sentinel already present ───────────────────── +@pytest.mark.run(order=1) +def test_backup_sync_sentinel_preexists(): + """When /tmp/.backup_logs_done exists before PreviousLogs grep, + the daemon should log 'already present' and harvest data immediately.""" + _full_reset() + + # Pre-create the sentinel BEFORE starting the daemon + open(BACKUP_LOGS_DONE_FLAG, "w").close() + + run_telemetry() + sleep(2) + run_shell_command("rdklogctrl telemetry2_0 LOG.RDK.T2 DEBUG") + sleep(1) + + rbus_set_data(T2_REPORT_PROFILE_PARAM_MSG_PCK, "string", + _tomsgpack(_PROFILE_BACKUP_SYNC)) + sleep(5) + + # Verify fast-path log message + assert "already present" in grep_T2logs("backup_logs sentinel") + + # Verify PreviousLogs data was harvested in the report + assert "PREVLOG_SYNC_MARKER" in grep_T2logs("cJSON Report") + + # Verify telemetry completion sentinel was created + assert os.path.exists(TELEMETRY_PREVLOGS_DONE_FLAG), \ + "Telemetry previous-logs completion sentinel not created" + + +# ── Test 2: inotify path – sentinel arrives during wait ────────────── +@pytest.mark.run(order=2) +def test_backup_sync_sentinel_via_inotify(): + """When the sentinel is absent at grep time but appears within the + timeout window, inotify should detect it and the daemon proceeds.""" + _full_reset() + + run_telemetry() + sleep(2) + run_shell_command("rdklogctrl telemetry2_0 LOG.RDK.T2 DEBUG") + sleep(1) + + # Push profile – daemon will start waiting for the sentinel + rbus_set_data(T2_REPORT_PROFILE_PARAM_MSG_PCK, "string", + _tomsgpack(_PROFILE_BACKUP_SYNC)) + + # Create the sentinel after a short delay (while daemon is waiting) + def _create_sentinel(): + sleep(3) + open(BACKUP_LOGS_DONE_FLAG, "w").close() + + t = threading.Thread(target=_create_sentinel, daemon=True) + t.start() + + sleep(10) # Allow time for inotify detection + grep + report + + # Verify inotify detection log (either "sentinel created" or "race resolved") + inotify_log = grep_T2logs("backup_logs sentinel") + assert ("sentinel created" in inotify_log or + "race resolved" in inotify_log or + "already present" in inotify_log), \ + f"Expected inotify sentinel detection log, got: {inotify_log}" + + # Verify PreviousLogs data was harvested + assert "PREVLOG_SYNC_MARKER" in grep_T2logs("cJSON Report") + + # Verify telemetry completion sentinel was created + assert os.path.exists(TELEMETRY_PREVLOGS_DONE_FLAG), \ + "Telemetry previous-logs completion sentinel not created" + + +# ── Test 3: timeout path – sentinel never appears ──────────────────── +@pytest.mark.run(order=3) +def test_backup_sync_timeout(): + """When the sentinel never appears the daemon should time out after + BACKUP_LOGS_SYNC_TIMEOUT_S (60 s) and proceed with the grep anyway.""" + _full_reset() + + # Do NOT create the sentinel — force the timeout path + run_telemetry() + sleep(2) + run_shell_command("rdklogctrl telemetry2_0 LOG.RDK.T2 DEBUG") + sleep(1) + + rbus_set_data(T2_REPORT_PROFILE_PARAM_MSG_PCK, "string", + _tomsgpack(_PROFILE_BACKUP_SYNC)) + + # Wait for the 60 s timeout + report generation + sleep(70) + + # Verify timeout warning was logged + assert "not present after" in grep_T2logs("backup_logs sentinel") or \ + "proceeding without" in grep_T2logs("backup_logs"), \ + "Expected timeout/proceeding-without log message" + + # Verify PreviousLogs data was still harvested (best-effort) + assert "PREVLOG_SYNC_MARKER" in grep_T2logs("cJSON Report") + + # Verify telemetry completion sentinel was created even after timeout + assert os.path.exists(TELEMETRY_PREVLOGS_DONE_FLAG), \ + "Telemetry previous-logs completion sentinel not created after timeout" From 1b99f3959876db37628a8e41bfedeb9894b1ce87 Mon Sep 17 00:00:00 2001 From: Abhinav P V Date: Wed, 15 Jul 2026 15:54:47 +0000 Subject: [PATCH 30/36] L2 --- test/run_l2.sh | 2 ++ 1 file changed, 2 insertions(+) mode change 100755 => 100644 test/run_l2.sh diff --git a/test/run_l2.sh b/test/run_l2.sh old mode 100755 new mode 100644 index 7dbd6410b..ba2e9fd96 --- a/test/run_l2.sh +++ b/test/run_l2.sh @@ -42,6 +42,7 @@ pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/run pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/bootup_sequence.json test/functional-tests/tests/test_bootup_sequence.py || final_result=1 pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/xconf_communications.json test/functional-tests/tests/test_xconf_communications.py || final_result=1 pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/msg_packet.json test/functional-tests/tests/test_multiprofile_msgpacket.py || final_result=1 +pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/backup_logs_sync.json test/functional-tests/tests/test_backup_logs_sync.py || final_result=1 if [ $final_result -ne 0 ]; then echo "Some tests failed. Please check the JSON reports in $RESULT_DIR for details." @@ -116,3 +117,4 @@ if [ "$ENABLE_TSAN" = true ]; then fi exit $final_result + From dc378871017ba8108405e2c3aeecc9a91effa674 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:57:07 +0530 Subject: [PATCH 31/36] Update test_backup_logs_sync.py --- .../tests/test_backup_logs_sync.py | 81 +++++++++++++------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/test/functional-tests/tests/test_backup_logs_sync.py b/test/functional-tests/tests/test_backup_logs_sync.py index 2f795bc15..b3a485c8d 100644 --- a/test/functional-tests/tests/test_backup_logs_sync.py +++ b/test/functional-tests/tests/test_backup_logs_sync.py @@ -50,7 +50,15 @@ PREVIOUS_LOGS_FILE = os.path.join(PREVIOUS_LOGS_DIR, "backup_sync_test.txt") PREVIOUS_LOGS_CONTENT = "backup_sync_test_marker_value_12345" -# ── Profile that greps a PreviousLogs file with GenerateNow ────────── +# ── Persistence paths (must match source/utils/persistence.h) ──────── +SEEKFOLDER = "/opt/.t2seekmap" +REPORTPROFILES_PATH = "/opt/.t2reportprofiles" +MSGPACK_FILE = "profiles.msgpack" +T2_BOOTFLAG = "/tmp/.t2bootup" + +# ── Profile that greps a PreviousLogs file ─────────────────────────── +# GenerateNow must be false for the checkPreviousSeek path to activate +# when the daemon loads this profile from disk at startup. _PROFILE_BACKUP_SYNC = json.dumps({ "profiles": [{ "name": "BACKUP_SYNC_TEST", @@ -62,8 +70,7 @@ "Protocol": "HTTP", "EncodingType": "JSON", "ActivationTimeOut": 180, - "ReportingInterval": 120, - "GenerateNow": True, + "ReportingInterval": 300, "RootName": "backup_sync_report", "Parameter": [ { @@ -99,6 +106,31 @@ def _create_previous_logs(): f.write(PREVIOUS_LOGS_CONTENT + "\n") f.write("second line in backup sync test log\n") +def _seed_persistence(): + """Create persistence state (seek config + profile on disk) so the + daemon loads the profile with checkPreviousSeek=true on next startup. + + Requires: + * SEEKFOLDER with a valid seek config for the profile name. + * Profile msgpack saved to REPORTPROFILES_PATH. + * BOOTFLAG absent so firstBootStatus() returns true. + """ + os.makedirs(SEEKFOLDER, exist_ok=True) + seek_config = json.dumps([{"backup_sync_test.txt": 0}]) + with open(os.path.join(SEEKFOLDER, "BACKUP_SYNC_TEST"), "w") as f: + f.write(seek_config) + + os.makedirs(REPORTPROFILES_PATH, exist_ok=True) + data = json.loads(_PROFILE_BACKUP_SYNC) + raw_msgpack = msgpack.packb(data) + with open(os.path.join(REPORTPROFILES_PATH, MSGPACK_FILE), "wb") as f: + f.write(raw_msgpack) + + try: + os.remove(T2_BOOTFLAG) + except FileNotFoundError: + pass + def _full_reset(): """Kill daemon, remove flags/sentinels, recreate PreviousLogs.""" kill_telemetry(9) @@ -108,6 +140,10 @@ def _full_reset(): _clean_sentinels() _create_previous_logs() clear_T2logs() + try: + os.remove(T2_BOOTFLAG) + except FileNotFoundError: + pass # ── Test 1: fast path – sentinel already present ───────────────────── @@ -120,13 +156,12 @@ def test_backup_sync_sentinel_preexists(): # Pre-create the sentinel BEFORE starting the daemon open(BACKUP_LOGS_DONE_FLAG, "w").close() - run_telemetry() - sleep(2) - run_shell_command("rdklogctrl telemetry2_0 LOG.RDK.T2 DEBUG") - sleep(1) + # Seed persistence so profile loads from disk with checkPreviousSeek=true. + # On startup the daemon will call NotifyTimeout which triggers a report + # with customLogPath=PREVIOUS_LOGS_PATH, invoking waitForBackupLogsDone(). + _seed_persistence() - rbus_set_data(T2_REPORT_PROFILE_PARAM_MSG_PCK, "string", - _tomsgpack(_PROFILE_BACKUP_SYNC)) + run_telemetry() sleep(5) # Verify fast-path log message @@ -147,24 +182,21 @@ def test_backup_sync_sentinel_via_inotify(): timeout window, inotify should detect it and the daemon proceeds.""" _full_reset() - run_telemetry() - sleep(2) - run_shell_command("rdklogctrl telemetry2_0 LOG.RDK.T2 DEBUG") - sleep(1) - - # Push profile – daemon will start waiting for the sentinel - rbus_set_data(T2_REPORT_PROFILE_PARAM_MSG_PCK, "string", - _tomsgpack(_PROFILE_BACKUP_SYNC)) + # Seed persistence so profile loads from disk with checkPreviousSeek=true. + # The daemon will call waitForBackupLogsDone() immediately at startup; + # since the sentinel doesn't exist yet it enters the inotify wait loop. + _seed_persistence() # Create the sentinel after a short delay (while daemon is waiting) def _create_sentinel(): - sleep(3) + sleep(5) open(BACKUP_LOGS_DONE_FLAG, "w").close() t = threading.Thread(target=_create_sentinel, daemon=True) t.start() - sleep(10) # Allow time for inotify detection + grep + report + run_telemetry() + sleep(15) # Allow time for daemon start + inotify detection + grep + report # Verify inotify detection log (either "sentinel created" or "race resolved") inotify_log = grep_T2logs("backup_logs sentinel") @@ -188,14 +220,11 @@ def test_backup_sync_timeout(): BACKUP_LOGS_SYNC_TIMEOUT_S (60 s) and proceed with the grep anyway.""" _full_reset() - # Do NOT create the sentinel — force the timeout path - run_telemetry() - sleep(2) - run_shell_command("rdklogctrl telemetry2_0 LOG.RDK.T2 DEBUG") - sleep(1) + # Do NOT create the sentinel — force the timeout path. + # Seed persistence so profile loads from disk with checkPreviousSeek=true. + _seed_persistence() - rbus_set_data(T2_REPORT_PROFILE_PARAM_MSG_PCK, "string", - _tomsgpack(_PROFILE_BACKUP_SYNC)) + run_telemetry() # Wait for the 60 s timeout + report generation sleep(70) From 0b4aebee714b4a8607568f2fd1347376590afcab Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:54:19 +0530 Subject: [PATCH 32/36] Delete test/functional-tests/tests/test_backup_logs_sync.py --- .../tests/test_backup_logs_sync.py | 242 ------------------ 1 file changed, 242 deletions(-) delete mode 100644 test/functional-tests/tests/test_backup_logs_sync.py diff --git a/test/functional-tests/tests/test_backup_logs_sync.py b/test/functional-tests/tests/test_backup_logs_sync.py deleted file mode 100644 index b3a485c8d..000000000 --- a/test/functional-tests/tests/test_backup_logs_sync.py +++ /dev/null @@ -1,242 +0,0 @@ -#################################################################################### -# If not stated otherwise in this file or this component's Licenses 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. -#################################################################################### - -""" -L2 functional tests for the backup_logs synchronisation gate -(waitForBackupLogsDone) added to dcautil.c. - -The function uses inotify to wait for /tmp/.backup_logs_done before -grepping PreviousLogs. These tests exercise: - 1. Fast path – sentinel already present at grep time. - 2. Inotify – sentinel created while the daemon is waiting. - 3. Timeout – sentinel never appears; daemon proceeds after 60 s. - 4. Completion – /tmp/.telemetry_prevlogs_done created after grep. -""" - -import json -import os -import subprocess -import threading -from datetime import datetime as dt -from time import sleep - -import base64 -import msgpack -import pytest - -from basic_constants import * -from helper_functions import * - -# ── Sentinel paths (must match dcautil.h) ──────────────────────────── -BACKUP_LOGS_DONE_FLAG = "/tmp/.backup_logs_done" -TELEMETRY_PREVLOGS_DONE_FLAG = "/tmp/.telemetry_prevlogs_done" -PREVIOUS_LOGS_DIR = "/opt/logs/PreviousLogs" -PREVIOUS_LOGS_FILE = os.path.join(PREVIOUS_LOGS_DIR, "backup_sync_test.txt") -PREVIOUS_LOGS_CONTENT = "backup_sync_test_marker_value_12345" - -# ── Persistence paths (must match source/utils/persistence.h) ──────── -SEEKFOLDER = "/opt/.t2seekmap" -REPORTPROFILES_PATH = "/opt/.t2reportprofiles" -MSGPACK_FILE = "profiles.msgpack" -T2_BOOTFLAG = "/tmp/.t2bootup" - -# ── Profile that greps a PreviousLogs file ─────────────────────────── -# GenerateNow must be false for the checkPreviousSeek path to activate -# when the daemon loads this profile from disk at startup. -_PROFILE_BACKUP_SYNC = json.dumps({ - "profiles": [{ - "name": "BACKUP_SYNC_TEST", - "hash": "hash_backup_sync_001", - "value": { - "Name": "BACKUP_SYNC_TEST", - "Description": "L2 test for backup_logs synchronisation gate", - "Version": "0.1", - "Protocol": "HTTP", - "EncodingType": "JSON", - "ActivationTimeOut": 180, - "ReportingInterval": 300, - "RootName": "backup_sync_report", - "Parameter": [ - { - "type": "grep", - "marker": "PREVLOG_SYNC_MARKER", - "search": "backup_sync_test_marker_value", - "logFile": "backup_sync_test.txt", - "use": "absolute" - } - ] - } - }] -}) - -LOG_PROFILE_ENABLE = "Successfully enabled profile :" - -def _tomsgpack(json_string): - data = json.loads(json_string) - return base64.b64encode(msgpack.packb(data)).decode("utf-8") - -def _clean_sentinels(): - """Remove both sentinel files so each test starts clean.""" - for path in (BACKUP_LOGS_DONE_FLAG, TELEMETRY_PREVLOGS_DONE_FLAG): - try: - os.remove(path) - except FileNotFoundError: - pass - -def _create_previous_logs(): - """Populate the PreviousLogs directory with a known test file.""" - os.makedirs(PREVIOUS_LOGS_DIR, exist_ok=True) - with open(PREVIOUS_LOGS_FILE, "w") as f: - f.write(PREVIOUS_LOGS_CONTENT + "\n") - f.write("second line in backup sync test log\n") - -def _seed_persistence(): - """Create persistence state (seek config + profile on disk) so the - daemon loads the profile with checkPreviousSeek=true on next startup. - - Requires: - * SEEKFOLDER with a valid seek config for the profile name. - * Profile msgpack saved to REPORTPROFILES_PATH. - * BOOTFLAG absent so firstBootStatus() returns true. - """ - os.makedirs(SEEKFOLDER, exist_ok=True) - seek_config = json.dumps([{"backup_sync_test.txt": 0}]) - with open(os.path.join(SEEKFOLDER, "BACKUP_SYNC_TEST"), "w") as f: - f.write(seek_config) - - os.makedirs(REPORTPROFILES_PATH, exist_ok=True) - data = json.loads(_PROFILE_BACKUP_SYNC) - raw_msgpack = msgpack.packb(data) - with open(os.path.join(REPORTPROFILES_PATH, MSGPACK_FILE), "wb") as f: - f.write(raw_msgpack) - - try: - os.remove(T2_BOOTFLAG) - except FileNotFoundError: - pass - -def _full_reset(): - """Kill daemon, remove flags/sentinels, recreate PreviousLogs.""" - kill_telemetry(9) - sleep(1) - remove_T2bootup_flag() - clear_persistant_files() - _clean_sentinels() - _create_previous_logs() - clear_T2logs() - try: - os.remove(T2_BOOTFLAG) - except FileNotFoundError: - pass - - -# ── Test 1: fast path – sentinel already present ───────────────────── -@pytest.mark.run(order=1) -def test_backup_sync_sentinel_preexists(): - """When /tmp/.backup_logs_done exists before PreviousLogs grep, - the daemon should log 'already present' and harvest data immediately.""" - _full_reset() - - # Pre-create the sentinel BEFORE starting the daemon - open(BACKUP_LOGS_DONE_FLAG, "w").close() - - # Seed persistence so profile loads from disk with checkPreviousSeek=true. - # On startup the daemon will call NotifyTimeout which triggers a report - # with customLogPath=PREVIOUS_LOGS_PATH, invoking waitForBackupLogsDone(). - _seed_persistence() - - run_telemetry() - sleep(5) - - # Verify fast-path log message - assert "already present" in grep_T2logs("backup_logs sentinel") - - # Verify PreviousLogs data was harvested in the report - assert "PREVLOG_SYNC_MARKER" in grep_T2logs("cJSON Report") - - # Verify telemetry completion sentinel was created - assert os.path.exists(TELEMETRY_PREVLOGS_DONE_FLAG), \ - "Telemetry previous-logs completion sentinel not created" - - -# ── Test 2: inotify path – sentinel arrives during wait ────────────── -@pytest.mark.run(order=2) -def test_backup_sync_sentinel_via_inotify(): - """When the sentinel is absent at grep time but appears within the - timeout window, inotify should detect it and the daemon proceeds.""" - _full_reset() - - # Seed persistence so profile loads from disk with checkPreviousSeek=true. - # The daemon will call waitForBackupLogsDone() immediately at startup; - # since the sentinel doesn't exist yet it enters the inotify wait loop. - _seed_persistence() - - # Create the sentinel after a short delay (while daemon is waiting) - def _create_sentinel(): - sleep(5) - open(BACKUP_LOGS_DONE_FLAG, "w").close() - - t = threading.Thread(target=_create_sentinel, daemon=True) - t.start() - - run_telemetry() - sleep(15) # Allow time for daemon start + inotify detection + grep + report - - # Verify inotify detection log (either "sentinel created" or "race resolved") - inotify_log = grep_T2logs("backup_logs sentinel") - assert ("sentinel created" in inotify_log or - "race resolved" in inotify_log or - "already present" in inotify_log), \ - f"Expected inotify sentinel detection log, got: {inotify_log}" - - # Verify PreviousLogs data was harvested - assert "PREVLOG_SYNC_MARKER" in grep_T2logs("cJSON Report") - - # Verify telemetry completion sentinel was created - assert os.path.exists(TELEMETRY_PREVLOGS_DONE_FLAG), \ - "Telemetry previous-logs completion sentinel not created" - - -# ── Test 3: timeout path – sentinel never appears ──────────────────── -@pytest.mark.run(order=3) -def test_backup_sync_timeout(): - """When the sentinel never appears the daemon should time out after - BACKUP_LOGS_SYNC_TIMEOUT_S (60 s) and proceed with the grep anyway.""" - _full_reset() - - # Do NOT create the sentinel — force the timeout path. - # Seed persistence so profile loads from disk with checkPreviousSeek=true. - _seed_persistence() - - run_telemetry() - - # Wait for the 60 s timeout + report generation - sleep(70) - - # Verify timeout warning was logged - assert "not present after" in grep_T2logs("backup_logs sentinel") or \ - "proceeding without" in grep_T2logs("backup_logs"), \ - "Expected timeout/proceeding-without log message" - - # Verify PreviousLogs data was still harvested (best-effort) - assert "PREVLOG_SYNC_MARKER" in grep_T2logs("cJSON Report") - - # Verify telemetry completion sentinel was created even after timeout - assert os.path.exists(TELEMETRY_PREVLOGS_DONE_FLAG), \ - "Telemetry previous-logs completion sentinel not created after timeout" From b8fbe70c2dd7365d8cd382630225f45792750dc2 Mon Sep 17 00:00:00 2001 From: Abhinavpv28 <162570454+Abhinavpv28@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:43:53 +0530 Subject: [PATCH 33/36] Update code-coverage.yml --- .github/workflows/code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 706a0152b..5ad3ac07f 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -2,7 +2,7 @@ name: Code Coverage on: pull_request: - branches: [ develop] + branches: [ main] env: AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} From eeea36686bb90e320e4c81449babf6555169f490 Mon Sep 17 00:00:00 2001 From: Aryan Y Date: Fri, 17 Jul 2026 11:37:43 +0000 Subject: [PATCH 34/36] L1 --- test/run_l2.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/run_l2.sh b/test/run_l2.sh index ba2e9fd96..3dc450986 100644 --- a/test/run_l2.sh +++ b/test/run_l2.sh @@ -42,8 +42,6 @@ pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/run pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/bootup_sequence.json test/functional-tests/tests/test_bootup_sequence.py || final_result=1 pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/xconf_communications.json test/functional-tests/tests/test_xconf_communications.py || final_result=1 pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/msg_packet.json test/functional-tests/tests/test_multiprofile_msgpacket.py || final_result=1 -pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/backup_logs_sync.json test/functional-tests/tests/test_backup_logs_sync.py || final_result=1 - if [ $final_result -ne 0 ]; then echo "Some tests failed. Please check the JSON reports in $RESULT_DIR for details." else @@ -117,4 +115,3 @@ if [ "$ENABLE_TSAN" = true ]; then fi exit $final_result - From 3145750acb8cdf4ae2ff5ce630f8f4f96fdd503b Mon Sep 17 00:00:00 2001 From: Aryan Y Date: Fri, 17 Jul 2026 11:42:59 +0000 Subject: [PATCH 35/36] L1 --- test/run_l2.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/run_l2.sh b/test/run_l2.sh index 3dc450986..7dbd6410b 100644 --- a/test/run_l2.sh +++ b/test/run_l2.sh @@ -42,6 +42,7 @@ pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/run pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/bootup_sequence.json test/functional-tests/tests/test_bootup_sequence.py || final_result=1 pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/xconf_communications.json test/functional-tests/tests/test_xconf_communications.py || final_result=1 pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/msg_packet.json test/functional-tests/tests/test_multiprofile_msgpacket.py || final_result=1 + if [ $final_result -ne 0 ]; then echo "Some tests failed. Please check the JSON reports in $RESULT_DIR for details." else From f4d2552dcbcd2e8c0cfe78148de4a9825fffc923 Mon Sep 17 00:00:00 2001 From: Aryan Y Date: Fri, 17 Jul 2026 11:53:22 +0000 Subject: [PATCH 36/36] L! --- test/run_l2.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/run_l2.sh diff --git a/test/run_l2.sh b/test/run_l2.sh old mode 100644 new mode 100755