Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/L2-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ jobs:

- name: Start mock-xconf service
run: |
docker run -d --name mockxconf -p 50050:50050 -p 50051:50051 -p 50052:50052 -v ${{ github.workspace }}:/mnt/L2_CONTAINER_SHARED_VOLUME ghcr.io/rdkcentral/docker-device-mgt-service-test/mockxconf:latest
docker run -d --name mockxconf -p 50050:50050 -p 50051:50051 -p 50052:50052 -e ENABLE_MTLS=true -v ${{ github.workspace }}:/mnt/L2_CONTAINER_SHARED_VOLUME ghcr.io/rdkcentral/docker-device-mgt-service-test/mockxconf:latest

- name: Start l2-container service
run: |
docker run -d --name native-platform --link mockxconf -v ${{ github.workspace }}:/mnt/L2_CONTAINER_SHARED_VOLUME ghcr.io/rdkcentral/docker-device-mgt-service-test/native-platform:latest
docker run -d --name native-platform --link mockxconf -e ENABLE_MTLS=true -v ${{ github.workspace }}:/mnt/L2_CONTAINER_SHARED_VOLUME ghcr.io/rdkcentral/docker-device-mgt-service-test/native-platform:latest

- name: Enter Inside Platform native container and run L2 Test
run: |
docker exec -i native-platform /bin/bash -c "cd /mnt/L2_CONTAINER_SHARED_VOLUME/ && sh cov_build.sh && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu:/usr/local/lib: && sh test/run_l2.sh && sh test/run_uploadstblogs_l2.sh"
docker exec -i native-platform /bin/bash -c "cd /mnt/L2_CONTAINER_SHARED_VOLUME/ && sh cov_build.sh && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu:/usr/local/lib: && sh test/run_uploadstblogs_l2.sh"

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow no longer runs test/run_l2.sh, so the DCM/L2 suites executed there (boot sequence, cron cases, etc.) won’t run in CI anymore. If the intent is to narrow coverage to uploadstblogs/usblogupload only, consider either adding those checks into run_uploadstblogs_l2.sh or running both scripts to avoid silently dropping coverage.

Suggested change
docker exec -i native-platform /bin/bash -c "cd /mnt/L2_CONTAINER_SHARED_VOLUME/ && sh cov_build.sh && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu:/usr/local/lib: && sh test/run_uploadstblogs_l2.sh"
docker exec -i native-platform /bin/bash -c "cd /mnt/L2_CONTAINER_SHARED_VOLUME/ && sh cov_build.sh && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu:/usr/local/lib: && sh test/run_l2.sh && sh test/run_uploadstblogs_l2.sh"

Copilot uses AI. Check for mistakes.

- name: Copy l2 test results to runner
run: |
Expand Down
4 changes: 2 additions & 2 deletions cov_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ cp include/*.h /usr/local/include
sh build_inside_container.sh

cd ${ROOT}
git clone https://github.com/rdkcentral/common_utilities.git -b feature/upload_L2
git clone https://github.com/rdkcentral/common_utilities.git -b feature/certupload
cd common_utilities
Comment on lines 57 to 59

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cov_build.sh now clones common_utilities without pinning a branch/tag/commit. This makes CI non-deterministic and can break builds when upstream changes. Prefer pinning to a known-good branch or commit SHA (and documenting it) to keep L2/Coverage runs reproducible.

Copilot uses AI. Check for mistakes.
autoreconf -i
./configure --enable-rdkcertselector --prefix=${INSTALL_DIR} CFLAGS="-Wno-stringop-truncation -DL2_TEST_ENABLED -DRDK_LOGGER"
./configure --enable-rdkcertselector --enable-mountutils --prefix=${INSTALL_DIR} CFLAGS="-Wno-stringop-truncation -DL2_TEST_ENABLED -DRDK_LOGGER"
cp uploadutils/*.h /usr/local/include
make
make install
Expand Down
2 changes: 1 addition & 1 deletion dcm_cronparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extern "C"
#endif
/**
* Parsed cron expression
*/
*/
typedef struct {
UINT8 seconds[8];
UINT8 minutes[8];
Expand Down
44 changes: 44 additions & 0 deletions test/functional-tests/features/usblogupload.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Feature: USB Log Upload
This feature covers the USB log upload functionality, including error handling, archive creation, MAC address logging, temp directory cleanup, and success/failure scenarios.

Scenario: USB not mounted or missing log path
Given the USB log upload binary is available
When I run usblogupload with a non-existent mount point
Then the process should fail with code 2 or 3
And a failure message should be logged

Scenario: Archive creation on valid mount
Given a valid USB mount point
When I run usblogupload
Then the process should exit with code 0 or 3
And an archive creation log may appear

Scenario: MAC address and file log
Given a valid USB mount point
When I run usblogupload
Then the process should exit with code 0 or 3
And a log line with MAC address and file name may appear

Scenario: Temp directory cleanup
Given a valid USB mount point
When I run usblogupload
Then the process should exit with code 0 or 3
And a cleanup log may appear

Scenario: Successful USB log upload
Given the USB log upload binary is available
When I run usblogupload with a valid mount point
Then the process should exit with code 0
And a completion message should be logged

Scenario: Invalid usage
Given the USB log upload binary is available
When I run usblogupload with no arguments
Then the process should exit with code 4
And a log about failed logging system initialization may appear

Scenario: USB not mounted
Given the USB log upload binary is available
When I run usblogupload with an unmounted path
Then the process should exit with code 2
And a log about failed USB mount point validation may appear
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ def test_upload_cron_present():

@pytest.mark.run(order=2)
def test_upload_script_started_onboot_false():
assert "UploadOnReboot=0" in grep_dcmdlogs("Triggered uploadSTBLogs.sh with arguments")
assert "Called uploadLogOnReboot with false" in grep_dcmdlogs("Called uploadLogOnReboot with false")
assert "Triggering log upload without reboot flag via library API" in grep_dcmdlogs("Triggering log upload without reboot flag via library API")
sleep(420)

@pytest.mark.run(order=3)
Expand All @@ -52,8 +51,7 @@ def test_upload_cron_scheduled():

@pytest.mark.run(order=5)
def test_upload_script_started():
assert "Start log upload Script" in grep_dcmdlogs("Start log upload Script")
assert "Called uploadDCMLogs" in grep_dcmdlogs("Called uploadDCMLogs")
assert "Start log upload via library API" in grep_dcmdlogs("Start log upload via library API")

@pytest.mark.run(order=6)
def test_fwupdate_script_started():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@
def test_upload_cron_present():
assert "urn:settings:LogUploadSettings:UploadSchedule:cron" in grep_dcmdlogs("is present setting cron jobs")

@pytest.mark.run(order=2)
def test_upload_script_started():
assert "UploadOnReboot=1" in grep_dcmdlogs("Triggered uploadSTBLogs.sh with arguments")
assert "Called uploadLogOnReboot with true" in grep_dcmdlogs("Called uploadLogOnReboot with true")

@pytest.mark.run(order=3)
def test_fw_cron_scheduled():
sleep(540)
Expand All @@ -50,7 +45,5 @@ def test_upload_cron_scheduled():

@pytest.mark.run(order=6)
def test_upload_started():
assert "Start log upload Script" in grep_dcmdlogs("Start log upload Script")
assert "FLAG=0" in grep_dcmdlogs("Triggered uploadSTBLogs.sh with arguments")
assert "Called uploadDCMLogs" in grep_dcmdlogs("Called uploadDCMLogs")
assert "Start log upload via library API" in grep_dcmdlogs("Start log upload via library API")

4 changes: 1 addition & 3 deletions test/functional-tests/tests/test_uploadLogsNow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,9 @@

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)
result = subprocess.run("/usr/local/bin/logupload uploadlogsnow >> /opt/logs/logupload.log.0",shell=True)

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subprocess.run(...) was changed to a shell command with output redirection and no timeout/capture_output. This makes the test less debuggable (stdout/stderr are lost to the test runner) and can cause CI hangs if the command blocks. Prefer passing args as a list (no shell), keep a timeout, and capture output so failures are actionable.

Suggested change
result = subprocess.run("/usr/local/bin/logupload uploadlogsnow >> /opt/logs/logupload.log.0",shell=True)
cmd = ["/usr/local/bin/logupload", "uploadlogsnow"]
result = sp.run(cmd, capture_output=True, text=True, timeout=60)

Copilot uses AI. Check for mistakes.
return result
Comment on lines 35 to 38

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run_uploadlogsnow() no longer sets a timeout or captures stdout/stderr. If logupload hangs in CI, this test suite can block indefinitely, and failures become harder to diagnose. Consider restoring a bounded timeout and capturing output (or at least enabling it on failure) instead of relying on shell redirection.

Copilot uses AI. Check for mistakes.
Comment on lines 35 to 38

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change removes the previous timeout=300 when running logupload uploadlogsnow. Without a timeout, CI can hang indefinitely if the process stalls. Consider restoring a timeout and capturing output to help diagnose failures.

Copilot uses AI. Check for mistakes.


class TestUploadLogsNow:
"""Test suite for uploadLogsNow immediate upload functionality"""

Expand Down
29 changes: 3 additions & 26 deletions test/functional-tests/tests/test_uploadstblogs_normal_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,29 +54,15 @@ def test_normal_upload_initialization(self):

# Run uploadSTBLogs
#result = run_uploadstblogs()

result = subprocess.run([
"/usr/local/bin/logupload",
"",
"1",
"1",
"true",
"HTTP",
"https://mockxconf:50058/"
])


result = subprocess.run("/usr/local/bin/logupload '' 1 1 true HTTP https://mockxconf:50058/ >> /opt/logs/logupload.log.0",shell=True)

Comment on lines +57 to +58

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching to shell=True with output redirection removes any timeout/capture of stdout/stderr and can hide failures or hang CI if logupload blocks. Prefer invoking the binary with an argument list (no shell), adding a timeout, and capturing output so assertions and failure logs remain reliable.

Copilot uses AI. Check for mistakes.
Comment on lines 55 to +58

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test file uses subprocess.run(...) but does not import subprocess. Unless subprocess is injected via one of the star-imported helpers (unlikely and non-obvious), this will raise NameError and fail the test.

Copilot uses AI. Check for mistakes.
# Verify initialization
assert result.returncode == 0 or result.returncode == 1, "Upload process should complete"
Comment on lines 55 to 60

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These calls switched to shell=True without any timeout or captured output. That makes the tests vulnerable to hanging indefinitely in CI and reduces debuggability when failures occur. Prefer subprocess.run([...], timeout=..., capture_output=True, text=True) (or reuse run_uploadstblogs() from uploadstblogs_helper.py) and write logs conditionally on failure.

Copilot uses AI. Check for mistakes.

# Check initialization logs
init_logs = grep_uploadstb_logs("Context initialization successful")
assert len(init_logs) > 0, "Context should be initialized successfully"

# Verify device properties loaded
logs = grep_uploadstb_logs("DEVICE_TYPE")
assert len(logs) > 0, "Device type should be loaded from properties"

collection_logs = grep_uploadstb_logs_regex(r"collect|archive|gather")
assert len(collection_logs) > 0, "Log collection should be attempted"

Expand Down Expand Up @@ -109,16 +95,7 @@ def test_large_file_collection(self):
"""Test: Service collects large log files within limits"""
# Create large test files (10MB each)
large_files = create_large_test_log_files(count=3, size_mb=10)

result = subprocess.run([
"/usr/local/bin/logupload",
"",
"1",
"1",
"true",
"HTTP",
"https://mockxconf:50058/"
])
result = subprocess.run("/usr/local/bin/logupload '' 1 1 true HTTP https://mockxconf:50058/ >> /opt/logs/logupload.log.0",shell=True)

Comment on lines 95 to 99

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: using shell=True without a timeout and redirecting output to a file reduces test observability and can cause CI hangs. Prefer subprocess.run([...], capture_output=True, text=True, timeout=...) (and write logs explicitly if needed).

Copilot uses AI. Check for mistakes.
Comment on lines +98 to 99

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here: using shell=True with a single command string (and '') changes argv compared to the previous list-form invocation, and removes the ability to easily capture stdout/stderr for assertions. Prefer passing an argv list (including an explicit empty-string argument if needed) and adding a timeout/capture for reliability.

Copilot uses AI. Check for mistakes.
# Verify files were processed

Expand Down
122 changes: 122 additions & 0 deletions test/functional-tests/tests/test_usb_logupload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import subprocess
import os
import re
import pytest

USBLOGUPLOAD_BIN = "/usr/local/bin/usblogupload"
LOG_FILE = "/opt/logs/logupload.log" # Adjust if needed

# Helper to grep logs

def grep_usblogupload_logs(search: str):
search_result = []
search_pattern = re.compile(re.escape(search), re.IGNORECASE)

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grep_usblogupload_logs() uses re.escape(search), so callers cannot pass regex patterns. Tests later pass strings like ":.*File:" expecting regex matching, which will never work with this helper. Add a regex-based grep helper (no escaping) or change the tests to search for a literal substring.

Suggested change
search_pattern = re.compile(re.escape(search), re.IGNORECASE)
search_pattern = re.compile(search, re.IGNORECASE)

Copilot uses AI. Check for mistakes.
try:
with open(LOG_FILE, 'r', encoding='utf-8', errors='ignore') as file:
for line in file:
if search_pattern.search(line):
search_result.append(line)
except Exception as e:
print(f"Could not read file {LOG_FILE}: {e}")
return search_result


@pytest.fixture(autouse=True)
def setup_device_properties(tmp_path):
# Path to device.properties for test
device_properties_path = os.path.join(os.path.dirname(__file__), "device.properties")
backup_path = device_properties_path + ".bak"
# Backup original if exists
if os.path.exists(device_properties_path):
os.rename(device_properties_path, backup_path)
# Ensure RDK_PROFILE=TV is present
with open(device_properties_path, "w", encoding="utf-8") as f:
f.write("RDK_PROFILE=TV\n")
yield
Comment on lines +24 to +35

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fixture writes RDK_PROFILE=TV to a device.properties file in the test directory, but usblogupload reads device properties via getDevicePropertyData() (typically backed by /etc/device.properties). As written, this setup likely has no effect on the binary under test. Consider updating /etc/device.properties (with proper backup/restore) or stubbing getDevicePropertyData() for this test environment.

Copilot uses AI. Check for mistakes.
# Restore original after test
if os.path.exists(backup_path):
os.remove(device_properties_path)
os.rename(backup_path, device_properties_path)

Comment on lines +26 to +40

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixture writes device.properties next to the test file, but the code under test reads properties via getDevicePropertyData (typically backed by /etc/device.properties). As-is, the fixture likely has no effect on usblogupload behavior and can give false confidence. Consider updating /etc/device.properties in an idempotent way (or mocking getDevicePropertyData) instead of creating a local file.

Suggested change
# Path to device.properties for test
device_properties_path = os.path.join(os.path.dirname(__file__), "device.properties")
backup_path = device_properties_path + ".bak"
# Backup original if exists
if os.path.exists(device_properties_path):
os.rename(device_properties_path, backup_path)
# Ensure RDK_PROFILE=TV is present
with open(device_properties_path, "w", encoding="utf-8") as f:
f.write("RDK_PROFILE=TV\n")
yield
# Restore original after test
if os.path.exists(backup_path):
os.remove(device_properties_path)
os.rename(backup_path, device_properties_path)
# Path to device.properties used by getDevicePropertyData (typically /etc/device.properties)
device_properties_path = "/etc/device.properties"
file_existed_before = os.path.exists(device_properties_path)
original_content = ""
modified = False
if file_existed_before:
# Read existing content so we can restore it after the test, if we modify it
try:
with open(device_properties_path, "r", encoding="utf-8", errors="ignore") as f:
original_content = f.read()
except OSError:
# If we cannot read the file, do not attempt to modify or restore it
original_content = ""
file_existed_before = False
# Ensure RDK_PROFILE=TV is present during the test
needs_write = True
if file_existed_before and original_content:
if "RDK_PROFILE=TV" in original_content:
needs_write = False
if needs_write:
try:
mode = "a" if file_existed_before else "w"
with open(device_properties_path, mode, encoding="utf-8") as f:
f.write("RDK_PROFILE=TV\n")
modified = True
except OSError:
# If we cannot write, proceed with the test; it may fail appropriately
modified = False
yield
# Restore original state after test if we modified the file
if modified:
try:
if file_existed_before:
with open(device_properties_path, "w", encoding="utf-8") as f:
f.write(original_content)
else:
# File was created by this fixture; remove it
if os.path.exists(device_properties_path):
os.remove(device_properties_path)
except OSError:
# Best-effort restore; ignore errors during cleanup
pass

Copilot uses AI. Check for mistakes.
class TestUSBLogUpload:
def test_usblogupload_missing_log_path(self, tmp_path):
# Simulate missing log path by passing a non-existent mount point
usb_mount = str(tmp_path / "not_a_mount")
result = subprocess.run([USBLOGUPLOAD_BIN, usb_mount], capture_output=True, text=True)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(result.stdout)
f.write(result.stderr)
Comment on lines +6 to +48

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOG_FILE is under /opt/logs, but the tests append to it without ensuring the directory exists. If /opt/logs is missing in the environment, open(LOG_FILE, "a") will raise and fail the test before any assertions. Consider creating the directory/file in a fixture (or using tmp_path for per-test logs).

Copilot uses AI. Check for mistakes.
assert result.returncode == 2 or result.returncode == 3, "Should fail with USB not mounted or write error"
logs = grep_usblogupload_logs("Failed")
# Accept log file or process output containing 'fail', 'error', or 'not mounted'
output = (result.stdout + result.stderr).lower()
assert (
logs or
"fail" in output or
"error" in output or
"not mounted" in output
), (
f"Should log a failure message. Got stdout: {result.stdout}, stderr: {result.stderr}"
)

def test_usblogupload_archive_creation(self, tmp_path):
# Simulate a valid mount and check for archive creation log
usb_mount = tmp_path / "usb"
usb_mount.mkdir()
result = subprocess.run([USBLOGUPLOAD_BIN, str(usb_mount)], capture_output=True, text=True)
with open(LOG_FILE, "a", encoding="utf-8") as f:
Comment on lines +42 to +67

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All subprocess.run(...) calls here lack a timeout. If usblogupload blocks (e.g., waiting on I/O), these tests can hang the entire suite. Consider adding a reasonable timeout per invocation and reporting stdout/stderr on timeout to aid debugging.

Copilot uses AI. Check for mistakes.
f.write(result.stdout)
f.write(result.stderr)
# Look for archive or compression log
logs = grep_usblogupload_logs("archive")
assert result.returncode in (0, 3), "Should exit with success or write error code"
# Archive log may or may not appear depending on implementation

def test_usblogupload_mac_address_log(self, tmp_path):
# Simulate a valid mount and check for MAC address log
usb_mount = tmp_path / "usb"
usb_mount.mkdir()
result = subprocess.run([USBLOGUPLOAD_BIN, str(usb_mount)], capture_output=True, text=True)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(result.stdout)
f.write(result.stderr)
logs = grep_usblogupload_logs(":.*File:")
# This checks for the log line with MAC address and file name
# (Regex match, may need adjustment based on actual log format)
assert result.returncode in (0, 3), "Should exit with success or write error code"
Comment on lines +83 to +86

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grep_usblogupload_logs escapes the search string, so patterns like ":.*File:" are treated literally (not as regex). In test_usblogupload_mac_address_log this likely never matches. If a regex match is intended, either add a separate helper that does regex matching or avoid re.escape for that call site.

Copilot uses AI. Check for mistakes.

def test_usblogupload_temp_dir_cleanup(self, tmp_path):
# Simulate a valid mount and check for temp dir cleanup log
usb_mount = tmp_path / "usb"
usb_mount.mkdir()
result = subprocess.run([USBLOGUPLOAD_BIN, str(usb_mount)], capture_output=True, text=True)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(result.stdout)
f.write(result.stderr)
logs = grep_usblogupload_logs("cleanup")
# This checks for cleanup log line (if implemented)
assert result.returncode in (0, 3), "Should exit with success or write error code"
def test_usblogupload_success(self, tmp_path):
usb_mount = "/tmp"
# Run the binary and capture output
result = subprocess.run([USBLOGUPLOAD_BIN, usb_mount], capture_output=True, text=True)
# Write output to log file
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(result.stdout)
f.write(result.stderr)
assert result.returncode == 0, "Should exit with success code 0"
# Check for expected log
logs = grep_usblogupload_logs("COMPLETED USB LOG UPLOAD")
assert logs, "Should log completion message"

def test_usblogupload_invalid_usage(self):
result = subprocess.run([USBLOGUPLOAD_BIN], capture_output=True)
assert result.returncode == 4, "Should exit with invalid usage code 4"
logs = grep_usblogupload_logs("Failed to initialize logging system")
# This log may or may not appear depending on implementation

def test_usblogupload_usb_not_mounted(self):
result = subprocess.run([USBLOGUPLOAD_BIN, "/tmp/notmounted"], capture_output=True)
assert result.returncode == 2, "Should exit with USB not mounted code 2"
logs = grep_usblogupload_logs("Failed to validate USB mount point")
# This log may or may not appear depending on implementation
4 changes: 3 additions & 1 deletion test/run_l2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/fil

pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_true_test.json test/functional-tests/tests/test_log_upload_onreboot_true_case.py

pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_false_test.json test/functional-tests/tests/test_log_upload_onreboot_false_case.py
#pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_false_test.json test/functional-tests/tests/test_log_upload_onreboot_false_case.py

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script now skips the test_log_upload_onreboot_false_case.py suite entirely. If this is intended, it should be documented and/or replaced with an equivalent assertion elsewhere; otherwise it reduces L2 coverage and can hide regressions for the "onreboot=false" path.

Suggested change
#pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_false_test.json test/functional-tests/tests/test_log_upload_onreboot_false_case.py
pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_false_test.json test/functional-tests/tests/test_log_upload_onreboot_false_case.py

Copilot uses AI. Check for mistakes.

cat /opt/logs/dcmd.log.0

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cat /opt/logs/dcmd.log.0 will dump the entire log into CI output, which can be very large and may contain sensitive data. Consider tailing a small number of lines, gating it behind a failure condition, or removing it entirely.

Suggested change
cat /opt/logs/dcmd.log.0
tail -n 200 /opt/logs/dcmd.log.0

Copilot uses AI. Check for mistakes.

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unconditionally cat-ing /opt/logs/dcmd.log.0 can flood CI logs and may fail if the file doesn’t exist yet. Consider guarding it (e.g., only print on failure, or check existence and tail a limited number of lines).

Suggested change
cat /opt/logs/dcmd.log.0
if [ -f /opt/logs/dcmd.log.0 ]; then
echo "Last 200 lines of /opt/logs/dcmd.log.0:"
tail -n 200 /opt/logs/dcmd.log.0
fi

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +47

Copilot AI Mar 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commenting out the log_upload_onreboot_false_case pytest invocation reduces L2 coverage, and cat /opt/logs/dcmd.log.0 can produce very large CI logs (and is noisy even on success). If this is temporary debugging, consider reverting it or gating the cat behind a failure condition / debug flag.

Suggested change
#pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_false_test.json test/functional-tests/tests/test_log_upload_onreboot_false_case.py
cat /opt/logs/dcmd.log.0
pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/log_upload_reboot_false_test.json test/functional-tests/tests/test_log_upload_onreboot_false_case.py
if [ "${DCM_SHOW_LOGS:-0}" -ne 0 ] && [ -f /opt/logs/dcmd.log.0 ]; then
cat /opt/logs/dcmd.log.0
fi

Copilot uses AI. Check for mistakes.

if ! grep -q "ENABLE_MAINTENANCE=" /etc/device.properties; then
echo "ENABLE_MAINTENANCE=true" >> /etc/device.properties
Expand Down
Loading
Loading