-
Notifications
You must be signed in to change notification settings - Fork 1
Featue/rdk 59919 3 backup #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request implements an "UploadLogsNow" feature as a new mode in the logupload binary. This appears to be a C-based reimplementation of functionality previously handled by shell scripts, providing immediate on-demand log uploads.
Changes:
- Adds new uploadlogsnow.c implementation with workflow for immediate log uploads
- Integrates uploadlogsnow mode into the main logupload binary via command-line parameter detection
- Adds comprehensive unit tests and functional tests for the new functionality
- Updates build configuration to include new source files and dependencies
- Adds snprintf truncation checks in file_operations.c for improved safety
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 19 comments.
Show a summary per file
| File | Description |
|---|---|
| uploadstblogs/src/uploadlogsnow.c | New implementation of UploadLogsNow workflow including file copying, archiving, and upload |
| uploadstblogs/include/uploadlogsnow.h | Header file declaring the execute_uploadlogsnow_workflow function |
| uploadstblogs/src/uploadstblogs.c | Integration of uploadlogsnow mode with special parameter handling |
| uploadstblogs/src/file_operations.c | Added add_timestamp_to_files_uploadlogsnow function and snprintf safety checks |
| uploadstblogs/src/event_manager.c | Skip IARM events for uploadlogsnow mode |
| uploadstblogs/src/context_manager.c | Added extended RDK logger initialization |
| uploadstblogs/include/uploadstblogs_types.h | Added STATUS_FILE and DCM_TEMP_DIR constants, uploadlogsnow_mode field |
| uploadstblogs/unittest/uploadlogsnow_gtest.cpp | Comprehensive unit tests for uploadlogsnow workflow |
| uploadstblogs/unittest/Makefile.am | Added uploadlogsnow_gtest build target |
| uploadstblogs/src/Makefile.am | Added uploadlogsnow.c to library sources |
| test/functional-tests/tests/test_uploadLogsNow.py | New functional tests for uploadlogsnow feature |
| test/functional-tests/tests/uploadstblogs_helper.py | Minor whitespace cleanup |
| test/functional-tests/tests/test_log_upload_onreboot_false_case.py | Removed several test functions |
| test/run_uploadstblogs_l2.sh | Added uploadLogsNow test execution (with incorrect test file reference) |
| unit_test.sh | Added rdk_logger dependency and uploadlogsnow test execution |
| cov_build.sh | Added rdk_logger dependency setup |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #################################################################################### | ||
|
|
||
| """ | ||
| Test cases for uploadLogsNOw functionality |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in the docstring: "uploadLogsNOw" should be "uploadLogsNow" (lowercase 'w').
| Test cases for uploadLogsNOw functionality | |
| Test cases for uploadLogsNow functionality |
test/run_uploadstblogs_l2.sh
Outdated
| echo "1. Running Error Handling Tests..." | ||
| echo "1. Running UploadLogsNow Tests..." | ||
| pytest -v --json-report --json-report-summary \ | ||
| --json-report-file $RESULT_DIR/uploadLogsNow.json test/functional-tests/tests/test4.py |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test file references 'test4.py' which does not exist in the test directory. This should be changed to 'test_uploadLogsNow.py' to match the actual test file name.
| --json-report-file $RESULT_DIR/uploadLogsNow.json test/functional-tests/tests/test4.py | |
| --json-report-file $RESULT_DIR/uploadLogsNow.json test/functional-tests/tests/test_uploadLogsNow.py |
|
|
||
| def check_upload_status_success(self): | ||
| """Check upload status files for success indicators""" | ||
| status_files = [ |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The STATUS_FILE is defined as "/opt/loguploadstatus.txt" in uploadstblogs_types.h, but the test checks for it in "/tmp/loguploadstatus.txt" first. The test should check the actual STATUS_FILE location ("/opt/loguploadstatus.txt") as the primary location, not "/tmp/loguploadstatus.txt".
| status_files = [ | |
| status_files = [ | |
| "/opt/loguploadstatus.txt", |
| """Clean up DCM temporary files and directories""" | ||
| temp_paths = [ | ||
| "/tmp/DCM", | ||
| "/tmp/loguploadstatus.txt", |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cleanup function is trying to delete "/tmp/loguploadstatus.txt", but based on the STATUS_FILE definition in uploadstblogs_types.h, the actual status file is located at "/opt/loguploadstatus.txt". This cleanup path should be corrected to match the actual status file location.
| "/tmp/loguploadstatus.txt", | |
| "/opt/loguploadstatus.txt", |
| @@ -34,29 +34,3 @@ def test_upload_cron_present(): | |||
| sleep(20) | |||
| assert "urn:settings:LogUploadSettings:UploadSchedule:cron" in grep_dcmdlogs("is present setting cron jobs") | |||
|
|
|||
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of several test functions (test_upload_script_started_onboot_false, test_fw_cron_scheduled, test_upload_cron_scheduled, test_upload_script_started, test_fwupdate_script_started) reduces test coverage significantly. If these tests are no longer applicable due to architectural changes, this should be documented. Otherwise, consider whether equivalent test coverage is provided elsewhere to ensure no regression in functionality.
| import subprocess as sp | ||
| import os | ||
| import tempfile | ||
| import shutil |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'shutil' is not used.
| import shutil |
| for path in temp_paths: | ||
| try: | ||
| subprocess.run(f"rm -rf {path}", shell=True) | ||
| except: |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except block directly handles BaseException.
| except: | |
| except Exception: |
| with open(filepath, 'w') as f: | ||
| f.write(content) | ||
| created_files.append(filepath) | ||
| except: |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except block directly handles BaseException.
| except: | ||
| pass |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| except: | |
| pass | |
| except Exception as e: | |
| print(f"Warning: failed to remove temporary path '{path}': {e}") |
| if filename.endswith(('.tar.gz', '.tgz')): | ||
| print(f"Found archive file: {location}/{filename}") | ||
| return True | ||
| except Exception: |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| except Exception: | |
| except Exception: | |
| # Directory scanning here is best-effort; ignore errors (e.g. permissions, races) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 14 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| #define MAX_FILENAME_LENGTH 256 | ||
| #define MAX_CERT_PATH_LENGTH 256 | ||
| #define LOG_UPLOADSTB "LOG.RDK.UPLOADSTB" | ||
| #define STATUS_FILE "/opt/loguploadstatus.txt" |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The STATUS_FILE path is defined as "/opt/loguploadstatus.txt", but in the test file it's also checked in "/tmp/loguploadstatus.txt". There's a discrepancy between the defined constant and the test expectations. Consider making the status file path configurable or ensuring consistency across the codebase.
| #define STATUS_FILE "/opt/loguploadstatus.txt" | |
| #define STATUS_FILE "/tmp/loguploadstatus.txt" |
| """Set the RFC LogUploadEndpoint URL using rbuscli""" | ||
| try: | ||
| cmd = f"rbuscli set Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.LogUploadEndpoint.URL string {url}" | ||
| result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30) |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using subprocess.run with shell=True for rbuscli commands is a security risk. While rbuscli commands have controlled inputs here, consider using a list-based approach for better security: result = subprocess.run(["rbuscli", "set", "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.LogUploadEndpoint.URL", "string", url], capture_output=True, text=True, timeout=30)
| /* Extended initialization with programmatic configuration */ | ||
| #ifndef L2_TEST_ENABLED | ||
| #ifndef GTEST_ENABLE | ||
| rdk_logger_ext_config_t config = { | ||
| .pModuleName = "LOG.RDK.UPLOADSTB", /* Module name */ | ||
| .loglevel = RDK_LOG_INFO, /* Default log level */ | ||
| .output = RDKLOG_OUTPUT_CONSOLE, /* Output to console (stdout/stderr) */ | ||
| .format = RDKLOG_FORMAT_WITH_TS, /* Timestamped format */ | ||
| .pFilePolicy = NULL /* Not using file output, so NULL */ | ||
| }; | ||
|
|
||
| if (rdk_logger_ext_init(&config) != RDK_SUCCESS) { | ||
| printf("UPLOADSTB : ERROR - Extended logger init failed\n"); | ||
| } | ||
| #endif | ||
| #endif | ||
| if (0 == rdk_logger_init(DEBUG_INI_NAME)) { | ||
| g_rdk_logger_enabled = 1; | ||
| RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, "[%s:%d] RDK Logger initialized\n", __FUNCTION__, __LINE__); | ||
| } else { | ||
| fprintf(stderr, "WARNING: RDK Logger initialization failed, using fallback logging\n"); | ||
| } | ||
|
|
||
| } | ||
| if (!ctx) { | ||
| RDK_LOG(RDK_LOG_ERROR, LOG_UPLOADSTB, "[%s:%d] Context pointer is NULL\n", __FUNCTION__, __LINE__); | ||
| return false; |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code initializes RDK logger first (lines 167-182) and then checks if ctx is NULL (line 189). However, if ctx is NULL, the function returns false after the logger has been initialized. This could lead to resource leaks or inconsistent state. The NULL check should be performed before any initialization logic.
| RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, | ||
| "[%s:%d] Processing file...%s\n", | ||
| __FUNCTION__, __LINE__, filename); |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The log message "Processing file...%s" is misleading. When should_skip is set to 1, the file is being skipped, not processed. The message should be changed to something like "Skipping file (already has timestamp): %s" or "Excluding file from timestamp: %s" for clarity.
| RDK_LOG(RDK_LOG_INFO, LOG_UPLOADSTB, | ||
| "[%s:%d] Processing file...%s\n", | ||
| __FUNCTION__, __LINE__, filename); |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The log message "Processing file...%s" is misleading. When should_skip is set to 1 for reboot.log, the file is being skipped, not processed. The message should be changed to something like "Skipping file (reboot.log): %s" or "Excluding file from timestamp: %s" for clarity.
| // Initialize test context with safe paths | ||
| memset(&ctx, 0, sizeof(ctx)); | ||
| strncpy(ctx.log_path, test_log_dir.c_str(), sizeof(ctx.log_path) - 1); | ||
| strcpy(ctx.dcm_log_path, ""); |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using strcpy() to set dcm_log_path to an empty string is less safe than using array initialization or strncpy. Consider using: ctx.dcm_log_path[0] = '\0'; which is clearer and safer.
| strcpy(ctx.dcm_log_path, ""); | |
| ctx.dcm_log_path[0] = '\0'; |
|
|
||
| // Get current timestamp in script format: MM-DD-YY-HH-MMAM/PM- | ||
| time_t now = time(NULL); | ||
| struct tm* tm_info = localtime(&now); |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using localtime() is not thread-safe as it returns a pointer to a static buffer. In a multi-threaded environment, this could lead to race conditions. Use localtime_r() instead, which is the thread-safe version. Example: struct tm tm_info; localtime_r(&now, &tm_info);
| def run_uploadlogsnow(): | ||
| """Execute uploadlogsnow using the specific binary command""" | ||
| cmd = "/usr/local/bin/logupload uploadlogsnow" | ||
| result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300) |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using subprocess.run with shell=True is a security risk. The command string should be passed as a list to avoid shell injection vulnerabilities, especially if any part of the command could be influenced by user input. Change to: result = subprocess.run(["/usr/local/bin/logupload", "uploadlogsnow"], capture_output=True, text=True, timeout=300)
| import tempfile | ||
| import shutil | ||
| from uploadstblogs_helper import * | ||
| from helper_functions import * |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import pollutes the enclosing namespace, as the imported module helper_functions does not define 'all'.
| except Exception: | ||
| pass |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'except' clause does nothing but pass and there is no explanatory comment.
| except Exception: | |
| pass | |
| except (OSError, IOError) as e: | |
| # Ignore filesystem access errors while checking for temporary archive files, | |
| # but log them for debugging purposes. | |
| print(f"Error accessing temporary location {location}: {e}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| print(f"Checking {log_file} for success indicators") | ||
| for pattern in success_patterns: | ||
| # Use grep to search for pattern in the log file | ||
| cmd = f"grep -E '{pattern}' {log_file}" |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using f-string with shell=True is unsafe. The 'pattern' variable contains user-controlled regex patterns that could potentially contain shell metacharacters. Use subprocess with shell=False and proper argument lists, or use shlex.quote() to sanitize the pattern. Better yet, use Python's built-in file reading and regex matching instead of calling grep.
| TEST_F(UploadLogsNowTest, IntegrationTest_CascadingFailures) { | ||
| // Test various failure scenarios one by one | ||
|
|
||
| // First test: directory creation fails (early failure) | ||
| g_create_directory_should_fail = true; | ||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
|
|
||
| // Reset and test copy failure | ||
| SetUp(); // Reset all mocks | ||
| g_copy_file_should_fail = true; | ||
| result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
|
|
||
| // Reset and test archive creation failure | ||
| SetUp(); // Reset all mocks | ||
| g_create_archive_should_fail = true; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
| result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
|
|
||
| // Reset and test upload failure | ||
| SetUp(); // Reset all mocks | ||
| g_execute_upload_cycle_return_value = false; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
| result = execute_uploadlogsnow_workflow(&ctx); |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling SetUp() manually within a test is not a recommended practice in Google Test. The SetUp() method is automatically called before each test, so the state should already be reset. The multiple calls to execute_uploadlogsnow_workflow within the same test could lead to side effects. Consider splitting this into separate test cases instead of manually calling SetUp().
| TEST_F(UploadLogsNowTest, IntegrationTest_CascadingFailures) { | |
| // Test various failure scenarios one by one | |
| // First test: directory creation fails (early failure) | |
| g_create_directory_should_fail = true; | |
| int result = execute_uploadlogsnow_workflow(&ctx); | |
| EXPECT_EQ(-1, result); | |
| // Reset and test copy failure | |
| SetUp(); // Reset all mocks | |
| g_copy_file_should_fail = true; | |
| result = execute_uploadlogsnow_workflow(&ctx); | |
| EXPECT_EQ(-1, result); | |
| // Reset and test archive creation failure | |
| SetUp(); // Reset all mocks | |
| g_create_archive_should_fail = true; | |
| g_copy_files_return_count = 3; // Some files copied | |
| result = execute_uploadlogsnow_workflow(&ctx); | |
| EXPECT_EQ(-1, result); | |
| // Reset and test upload failure | |
| SetUp(); // Reset all mocks | |
| g_execute_upload_cycle_return_value = false; | |
| g_copy_files_return_count = 3; // Some files copied | |
| result = execute_uploadlogsnow_workflow(&ctx); | |
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_DirectoryCreationFails) { | |
| // Directory creation fails (early failure) | |
| g_create_directory_should_fail = true; | |
| int result = execute_uploadlogsnow_workflow(&ctx); | |
| EXPECT_EQ(-1, result); | |
| } | |
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_CopyFileFails) { | |
| // Copying files fails | |
| g_copy_file_should_fail = true; | |
| int result = execute_uploadlogsnow_workflow(&ctx); | |
| EXPECT_EQ(-1, result); | |
| } | |
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_ArchiveCreationFails) { | |
| // Archive creation fails after some files are copied | |
| g_create_archive_should_fail = true; | |
| g_copy_files_return_count = 3; // Some files copied | |
| int result = execute_uploadlogsnow_workflow(&ctx); | |
| EXPECT_EQ(-1, result); | |
| } | |
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_UploadCycleFails) { | |
| // Upload cycle fails after some files are copied | |
| g_execute_upload_cycle_return_value = false; | |
| g_copy_files_return_count = 3; // Some files copied | |
| int result = execute_uploadlogsnow_workflow(&ctx); |
| time_t now = time(NULL); | ||
| struct tm* tm_info = localtime(&now); | ||
| char timestamp[32]; | ||
| strftime(timestamp, sizeof(timestamp), "%m-%d-%y-%I-%M%p-", tm_info); |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The localtime() function is not thread-safe and returns a pointer to static storage that can be overwritten by subsequent calls. While the code immediately uses the result, in a multi-threaded environment this could be problematic. Other parts of the codebase also use localtime() without checking for NULL (e.g., archive_manager.c line 418 checks, but file_operations.c line 351 and 541 don't). Consider using localtime_r() for thread safety and add NULL checks consistently, as done in archive_manager.c.
| // Test cases for execute_uploadlogsnow_workflow | ||
|
|
||
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_NullContext) { | ||
| // Test null context parameter | ||
| int result = execute_uploadlogsnow_workflow(nullptr); | ||
| EXPECT_EQ(-1, result); | ||
| } | ||
|
|
||
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_CreateDirectoryFails) { | ||
| g_create_directory_should_fail = true; | ||
|
|
||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); // Should fail due to directory creation failure | ||
| } | ||
|
|
||
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_CopyFilesFails) { | ||
| g_copy_file_should_fail = true; | ||
|
|
||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); // Should fail due to file copy failure | ||
| } | ||
|
|
||
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_CreateArchiveFails) { | ||
| g_create_archive_should_fail = true; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
|
|
||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); // Should fail due to archive creation failure | ||
| } | ||
|
|
||
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_ArchiveFileNotFound) { | ||
| g_file_exists_return_value = false; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
|
|
||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); // Should fail when archive file doesn't exist after creation | ||
| } | ||
|
|
||
| TEST_F(UploadLogsNowTest, ExecuteWorkflow_UploadFails) { | ||
| g_execute_upload_cycle_return_value = false; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
|
|
||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); // Should fail when upload fails | ||
| } | ||
|
|
||
| TEST_F(UploadLogsNowTest, IntegrationTest_CascadingFailures) { | ||
| // Test various failure scenarios one by one | ||
|
|
||
| // First test: directory creation fails (early failure) | ||
| g_create_directory_should_fail = true; | ||
| int result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
|
|
||
| // Reset and test copy failure | ||
| SetUp(); // Reset all mocks | ||
| g_copy_file_should_fail = true; | ||
| result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
|
|
||
| // Reset and test archive creation failure | ||
| SetUp(); // Reset all mocks | ||
| g_create_archive_should_fail = true; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
| result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
|
|
||
| // Reset and test upload failure | ||
| SetUp(); // Reset all mocks | ||
| g_execute_upload_cycle_return_value = false; | ||
| g_copy_files_return_count = 3; // Some files copied | ||
| result = execute_uploadlogsnow_workflow(&ctx); | ||
| EXPECT_EQ(-1, result); | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unit tests only cover failure scenarios but do not include a test for the successful execution path of execute_uploadlogsnow_workflow. There should be at least one test case that verifies the function succeeds when all dependencies return success values.
| def run_uploadlogsnow(): | ||
| """Execute uploadlogsnow using the specific binary command""" | ||
| cmd = "/usr/local/bin/logupload uploadlogsnow" | ||
| result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300) |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The module is imported as 'sp' on line 27 but used as 'subprocess' throughout the file. This inconsistency should be resolved by either using 'sp' consistently or importing as 'subprocess' directly.
| "/tmp/loguploadstatus.txt", | ||
| "/opt/logs/loguploadstatus.txt" |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The STATUS_FILE is defined as "/opt/loguploadstatus.txt" in uploadstblogs_types.h, but the test checks for the file in both "/tmp/loguploadstatus.txt" and "/opt/logs/loguploadstatus.txt". This inconsistency could lead to test failures. The test should check the actual path defined by STATUS_FILE constant, which is "/opt/loguploadstatus.txt".
| "/tmp/loguploadstatus.txt", | |
| "/opt/logs/loguploadstatus.txt" | |
| "/opt/loguploadstatus.txt" |
| // Initialize test context with safe paths | ||
| memset(&ctx, 0, sizeof(ctx)); | ||
| strncpy(ctx.log_path, test_log_dir.c_str(), sizeof(ctx.log_path) - 1); | ||
| strcpy(ctx.dcm_log_path, ""); |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using strcpy without bounds checking is unsafe. While the code sets dcm_log_path to an empty string which is safe in this specific case, it's better to use a safer alternative like strncpy or memset for consistency with the rest of the code and to prevent potential security issues if this line is modified in the future.
| strcpy(ctx.dcm_log_path, ""); | |
| memset(ctx.dcm_log_path, 0, sizeof(ctx.dcm_log_path)); |
| std::string cleanup_cmd = "rm -rf " + test_log_dir; | ||
| system(cleanup_cmd.c_str()); |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using system() to execute shell commands with user-controlled strings can be a security risk. While in this case the path is constructed from getpid() which is safe, it's better practice to use proper directory removal APIs like rmdir() or std::filesystem::remove_all() instead of system() to avoid potential command injection vulnerabilities and to have better error handling.
| cmd = "/usr/local/bin/logupload uploadlogsnow" | ||
| result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300) |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using subprocess.run with shell=True can be a security risk if the command contains user-controlled input. While in this specific case the command is hardcoded, it's better practice to use shell=False with a list of arguments for security and to avoid potential command injection issues. Consider changing to: subprocess.run(["/usr/local/bin/logupload", "uploadlogsnow"], capture_output=True, text=True, timeout=300)
| cmd = "/usr/local/bin/logupload uploadlogsnow" | |
| result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=300) | |
| cmd = ["/usr/local/bin/logupload", "uploadlogsnow"] | |
| result = sp.run(cmd, capture_output=True, text=True, timeout=300) |
| from uploadstblogs_helper import * | ||
| from helper_functions import * | ||
|
|
||
|
|
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import pollutes the enclosing namespace, as the imported module uploadstblogs_helper does not define 'all'.
| from uploadstblogs_helper import * | |
| from helper_functions import * | |
| import uploadstblogs_helper as _uploadstblogs_helper | |
| from helper_functions import * | |
| # Explicitly expose only the helpers used from uploadstblogs_helper | |
| remove_lock_file = _uploadstblogs_helper.remove_lock_file | |
| cleanup_test_log_files = _uploadstblogs_helper.cleanup_test_log_files | |
| kill_uploadstblogs = _uploadstblogs_helper.kill_uploadstblogs |
Comment out assertion for uploadLogsNow success check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
Update lcov command to include additional directory for coverage data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| result = run_uploadlogsnow() | ||
|
|
||
| # Verify basic execution success | ||
| #assert result.returncode == 0, f"Upload should succeed, got return code: {result.returncode}" |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assertion checking the return code is commented out. This means the test won't actually validate whether the upload succeeded or failed. Either uncomment this assertion or provide an alternative validation mechanism. Commented-out assertions reduce test effectiveness.
| // Skip IARM events for uploadLogNow case | ||
| if (ctx && ctx->uploadlogsnow_mode) { | ||
| RDK_LOG(RDK_LOG_DEBUG, LOG_UPLOADSTB, | ||
| "[%s:%d] Skipping IARM events for uploadLogNow mode\n", __FUNCTION__, __LINE__); | ||
| return; | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The emit_upload_failure function checks ctx for null at line 169 but then at line 179 (outside the visible diff but part of the function) it may call is_device_broadband(ctx) without a null check. Review the full function to ensure all uses of ctx have appropriate null checks, similar to line 148 where ctx is checked before dereferencing.
| if (rdk_logger_ext_init(&config) != RDK_SUCCESS) { | ||
| printf("UPLOADSTB : ERROR - Extended logger init failed\n"); | ||
| } |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rdk_logger_ext_init() is called but its failure only prints a message without returning an error or affecting program flow. The function then continues to call rdk_logger_init() regardless of the extended init failure. Consider whether this dual initialization is intentional and if the failure of rdk_logger_ext_init() should be handled more explicitly.
| # | ||
|
|
||
| ENABLE_COV=false | ||
| ENABLE_COV=true |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ENABLE_COV flag has been changed from false to true. This enables code coverage by default, which is generally good for comprehensive testing. However, ensure this change is intentional and aligns with the project's CI/CD configuration, as it may affect build times and resource usage.
| ENABLE_COV=true | |
| ENABLE_COV=false |
| // Rename directly without pre-check to avoid TOCTOU issue | ||
| if (rename(old_path, new_path) == 0) { |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment mentions "Rename directly without pre-check to avoid TOCTOU issue," but the original code had a stat check that verified the file was a regular file before renaming. While removing the TOCTOU vulnerability is good, this change now allows renaming of directories and other special files. If the original behavior was intentional (i.e., only rename regular files), you should consider using rename() with appropriate error handling to skip directories, or document this behavior change.
| assert len(init_logs) >= 0, "Should find context initialization evidence" | ||
|
|
||
| # Check for device properties loading | ||
| device_logs = grep_uploadstb_logs_regex(r"DEVICE_TYPE|device.*propert|loading.*propert") | ||
| assert len(device_logs) >= 0, "Should load device properties" | ||
|
|
||
| # Check for path validation/setup | ||
| path_logs = grep_uploadstb_logs_regex(r"LOG_PATH|DCM_LOG_PATH|path.*valid|directory.*creat") | ||
| assert len(path_logs) >= 0, "Should validate and setup paths" | ||
|
|
||
| # Check for RFC endpoint configuration reading | ||
| rfc_logs = grep_uploadstb_logs_regex(r"RFC|LogUploadEndpoint|endpoint.*config") | ||
| assert len(rfc_logs) >= 0, "Should read RFC configuration" |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assertions at lines 167, 171, 175, and 179 all check "len(init_logs) >= 0" which will always be true since len() always returns a non-negative integer. These assertions provide no actual validation. Consider changing them to check for a positive count: "assert len(init_logs) > 0" if you expect these patterns to be found, or remove the assertions if they're not meant to be strict requirements.
| assert len(init_logs) >= 0, "Should find context initialization evidence" | |
| # Check for device properties loading | |
| device_logs = grep_uploadstb_logs_regex(r"DEVICE_TYPE|device.*propert|loading.*propert") | |
| assert len(device_logs) >= 0, "Should load device properties" | |
| # Check for path validation/setup | |
| path_logs = grep_uploadstb_logs_regex(r"LOG_PATH|DCM_LOG_PATH|path.*valid|directory.*creat") | |
| assert len(path_logs) >= 0, "Should validate and setup paths" | |
| # Check for RFC endpoint configuration reading | |
| rfc_logs = grep_uploadstb_logs_regex(r"RFC|LogUploadEndpoint|endpoint.*config") | |
| assert len(rfc_logs) >= 0, "Should read RFC configuration" | |
| assert len(init_logs) > 0, "Should find context initialization evidence" | |
| # Check for device properties loading | |
| device_logs = grep_uploadstb_logs_regex(r"DEVICE_TYPE|device.*propert|loading.*propert") | |
| assert len(device_logs) > 0, "Should load device properties" | |
| # Check for path validation/setup | |
| path_logs = grep_uploadstb_logs_regex(r"LOG_PATH|DCM_LOG_PATH|path.*valid|directory.*creat") | |
| assert len(path_logs) > 0, "Should validate and setup paths" | |
| # Check for RFC endpoint configuration reading | |
| rfc_logs = grep_uploadstb_logs_regex(r"RFC|LogUploadEndpoint|endpoint.*config") | |
| assert len(rfc_logs) > 0, "Should read RFC configuration" |
| assert os.path.exists(filepath), f"Test file should exist: {filepath}" | ||
|
|
||
| # Execute uploadLogsNow | ||
| result = run_uploadlogsnow() |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable result is not used.
| result = run_uploadlogsnow() | |
| run_uploadlogsnow() |
|
|
||
| import pytest | ||
| import time | ||
| import subprocess as sp |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'sp' is not used.
No description provided.