Skip to content

RDK-60476: Update L1 and L2 testcases for fork elimination#260

Open
yogeswaransky wants to merge 41 commits intodevelopfrom
topic/RDK-60476
Open

RDK-60476: Update L1 and L2 testcases for fork elimination#260
yogeswaransky wants to merge 41 commits intodevelopfrom
topic/RDK-60476

Conversation

@yogeswaransky
Copy link
Contributor

No description provided.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 11, 2026 13:14
@yogeswaransky yogeswaransky requested a review from a team as a code owner February 11, 2026 13:14
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates unit tests to align with the new “fork elimination” HTTP implementation (connection-pool + libcurl), replacing older pipe/fork/read-based expectations and expanding the test mocks to interpose additional libcurl calls.

Changes:

  • Enable previously disabled xconf-client and protocol HTTP tests and update them to use curl/pool expectations instead of fork()/pipe().
  • Extend FileioMock interposition to cover curl_easy_getinfo() and curl_easy_setopt().
  • Add helper logic intended to avoid deadlocks when GTest/logging writes to FILE* while file I/O is mocked.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
source/test/xconf-client/xconfclientTest.cpp Enables/updates doHttpGet tests to mock curl/pool behavior; adds a helper macro intended to prevent GTest logging deadlocks.
source/test/protocol/ProtocolTest.cpp Updates protocol HTTP tests to mock curl/pool behavior; adds default curl behaviors in fixture setup and a helper macro/comment.
source/test/mocks/FileioMock.h Adds/adjusts mock method signatures for curl interposition (curl_easy_setopt).
source/test/mocks/FileioMock.cpp Adds interposed curl_easy_getinfo() and a new interposed curl_easy_setopt() implementation for tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 13, 2026 20:05
Copy link
Contributor

Copilot AI left a 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 13 out of 13 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 15, 2026 07:38
Copy link
Contributor

Copilot AI left a 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 13 out of 13 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 15, 2026 10:48
Copy link
Contributor

Copilot AI left a 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 13 out of 13 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 15, 2026 16:14
Copy link
Contributor

Copilot AI left a 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 14 out of 14 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 15, 2026 17:46
Copy link
Contributor

Copilot AI left a 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 16 out of 16 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (4)

test/functional-tests/tests/helper_functions.py:60

  • The certificate discovery logic runs at import time and prints to stdout, which adds side effects/noise to every test that imports helper_functions. Consider moving certificate detection into a function (lazy initialization) and using the test logger instead of print, so importing utilities doesn’t change runtime behavior/output.
# Certificate configuration for mTLS
# Check for combined PEM files (cert+key in one file) first, then separate files
CERT_COMBINED_PATHS = [
    '/opt/certs/client.pem',
    '/etc/pki/Test-RDK-root/Test-RDK-client-ICA/certs/rdkclient.pem',
]

CERT_SEPARATE_PATHS = [
    ('/opt/certs/client.pem', '/opt/certs/client.key'),
    ('/etc/pki/Test-RDK-root/Test-RDK-client-ICA/certs/rdkclient.pem', '/etc/pki/Test-RDK-root/Test-RDK-client-ICA/private/rdkclient.key'),
]

# Find the first valid certificate
CERT_PATH = None

# Try combined PEM files first (cert+key in single file)
for cert_file in CERT_COMBINED_PATHS:
    if os.path.exists(cert_file):
        CERT_PATH = cert_file
        print(f"Using combined client certificate+key: {cert_file}")
        break

# If no combined file found, try separate cert and key files
if CERT_PATH is None:
    for cert_file, key_file in CERT_SEPARATE_PATHS:
        if os.path.exists(cert_file) and os.path.exists(key_file):
            CERT_PATH = (cert_file, key_file)
            print(f"Using client certificate: {cert_file} with key: {key_file}")
            break

if CERT_PATH is None:
    print("WARNING: No valid client certificate found!")

source/protocol/http/multicurlinterface.c:66

  • DEFAULT_POOL_SIZE was reduced from 2 to 1, which removes parallelism for HTTP requests by default and can increase latency when multiple threads contend for the pool. If this is only meant for low-end devices, consider keeping the previous default and relying on T2_CONNECTION_POOL_SIZE (or a device-type-based default) instead of globally lowering the default.
#define DEFAULT_POOL_SIZE 1

test/run_l2.sh:41

  • Two L2 test invocations are now commented out, which reduces coverage and can hide regressions. If these tests are intentionally disabled for fork elimination, please switch to an explicit mechanism (e.g., conditional execution with an env flag + a clear message, or pytest markers) so CI output makes it obvious what was skipped and why.
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/runs_as_daemon.json test/functional-tests/tests/test_runs_as_daemon.py || final_result=1

test/functional-tests/tests/test_multiprofile_msgpacket.py:79

  • A large block of tests is being disabled by wrapping it in a module-level triple-quoted string. This silently removes coverage and is easy to miss during maintenance; prefer marking individual tests with pytest skip/xfail (with a reason) or deleting the dead tests if they’re no longer valid.
'''
#negative case without hashvalue, without version field & without Protocol field
@pytest.mark.run(order=2)
def test_without_hashvalue():
    clear_T2logs()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Signed-off-by: Yogeswaran K <yogeswaransky@gmail.com>
Copilot AI review requested due to automatic review settings February 23, 2026 04:11
Copy link
Contributor

Copilot AI left a 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 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (14)

source/protocol/http/Makefile.am:27

  • Added -lrdkconfig to LDFLAGS when LIBRDKCERTSEL is enabled. Similar to the issue in xconf-client/Makefile.am, this creates a dependency on librdkconfig even when using RdkCertSelector. The code guards rdkconfig.h includes with #ifndef LIBRDKCERTSEL_BUILD in curlinterface.c and multicurlinterface.c, suggesting rdkconfig should only be linked when LIBRDKCERTSEL is NOT enabled.
libhttp_la_LDFLAGS += -lRdkCertSelector -lrdkconfig

source/test/xconf-client/xconfclientTest.cpp:421

  • Comment says "default 2" but DEFAULT_POOL_SIZE was changed to 1 in line 66 of multicurlinterface.c. Update this comment to reflect the correct default pool size of 1.
        // The pool will call curl_easy_init() based on pool size (default 2)

source/test/protocol/ProtocolTest.cpp:372

  • Unused variable 'cm' is declared but never used in this test. This appears to be leftover from the fork-based implementation that was removed. Consider removing this unused variable declaration.
      char *cm = (char*)0xFFFFFFFF;

source/protocol/http/multicurlinterface.c:779

  • The removed line clearing CURLOPT_HTTPGET is important when reusing pooled handles. When switching from GET to POST, if CURLOPT_HTTPGET was previously set to 1L (line 497 in http_pool_get), it needs to be explicitly cleared. While CURLOPT_POST sets the request method, not clearing CURLOPT_HTTPGET could lead to ambiguous state. Consider adding back CURLOPT_HTTPGET reset to 0L before setting up POST.
    // Clear any GET-specific settings from previous use

source/xconf-client/Makefile.am:27

  • Added -lrdkconfig to LDFLAGS when LIBRDKCERTSEL is enabled. This creates a dependency on librdkconfig even when using RdkCertSelector. Review whether rdkconfig is actually needed when LIBRDKCERTSEL_BUILD is defined, as the code has #ifndef LIBRDKCERTSEL_BUILD guards around rdkconfig.h includes in xconfclient.c and t2MtlsUtils.c. This suggests rdkconfig should only be linked when LIBRDKCERTSEL is NOT enabled, which contradicts this change.
libxconfclient_la_LDFLAGS += -lRdkCertSelector -lrdkconfig

source/xconf-client/xconfclient.c:287

  • Added null/empty check before strdup(zone). This is a good defensive programming practice that prevents potential issues when zone is NULL or empty. However, there's a subtle issue: the warning message at line 286 says "zone is NULL or empty, skipping", but zoneValue is already set to NULL at line 285. The real issue is that the code continues the while loop even after this condition, potentially reading more data. Consider whether the loop should break when zone is NULL/empty, or if this is intentional to skip empty lines.
                if (zone != NULL && strlen(zone) > 0)
                {
                    zoneValue = strdup(zone);
                }
                else
                {
                    zoneValue = NULL;
                    T2Warning("Warning: zone is NULL or empty, skipping\n");
                }

source/test/xconf-client/xconfclientTest.cpp:627

  • Test expects doHttpGet to return T2ERROR_SUCCESS but doesn't free the allocated data. When doHttpGet succeeds with a 200 response, it allocates memory for the data parameter. The test should free this memory to prevent memory leaks in test runs. Add if (data) free(data); after the assertion.
    EXPECT_EQ(T2ERROR_SUCCESS, doHttpGet("https://test.com", &data));

test/functional-tests/tests/helper_functions.py:114

  • The CERT_PATH variable can be either a string (combined PEM file) or a tuple (separate cert and key files). While the requests library supports both formats, the code should handle the case where CERT_PATH is None (when no certificate is found). Currently, passing cert=None to requests.get is valid but may cause unexpected behavior. Consider adding a check before the requests call to handle missing certificates more explicitly, or ensure that tests skip mTLS validation when CERT_PATH is None.
    if(requests.get(ADMIN_SUPPORT_SET, verify=CA_BUNDLE, cert=CERT_PATH, params={ADMIN_CACHE_ARG: str(save).lower()})):

source/test/xconf-client/xconfclientTest.cpp:674

  • Test expects doHttpGet to return T2ERROR_SUCCESS but doesn't free the allocated data. When doHttpGet succeeds with a 200 response, it allocates memory for the data parameter. The test should free this memory to prevent memory leaks in test runs. Add if (data) free(data); after the assertion.
    EXPECT_EQ(doHttpGet("https://test.com", &data), T2ERROR_SUCCESS);

source/test/protocol/ProtocolTest.cpp:274

  • Test expects sendReportOverHTTP to return T2ERROR_SUCCESS but the test doesn't verify that the report was actually sent. Unlike the old fork-based tests, the new pooled implementation needs to mock the actual HTTP write callback to simulate data transmission. Consider enhancing this test to verify the write callback is invoked with the correct payload.
      EXPECT_EQ(T2ERROR_SUCCESS, sendReportOverHTTP(httpURL, payload));

source/test/protocol/ProtocolTest.cpp:333

  • Unused variable 'cm' is declared but never used in this test. This appears to be leftover from the fork-based implementation that was removed. Consider removing this unused variable declaration.
      char *cm = (char*)0xFFFFFFFF;

source/protocol/http/multicurlinterface.c:66

  • Changed DEFAULT_POOL_SIZE from 2 to 1. This reduces the default connection pool size, which may impact performance for concurrent HTTP requests. While this may be appropriate for low-end devices, consider documenting the rationale for this change. The environment variable T2_CONNECTION_POOL_SIZE allows runtime configuration, but the default affects systems where it's not set. Verify that single-connection pooling doesn't create bottlenecks in production scenarios with concurrent telemetry uploads.
#define DEFAULT_POOL_SIZE 1

source/test/xconf-client/xconfclientTest.cpp:478

  • Test expects doHttpGet to return T2ERROR_SUCCESS but doesn't free the allocated data. When doHttpGet succeeds with a 200 response, it allocates memory for the data parameter (see multicurlinterface.c lines 677-682). The test should free this memory to prevent memory leaks in test runs. Add if (data) free(data); after the assertion.
    EXPECT_EQ(T2ERROR_SUCCESS, doHttpGet("https://test.com", &data));

source/test/xconf-client/xconfclientTest.cpp:721

  • Test expects doHttpGet to return T2ERROR_SUCCESS but doesn't free the allocated data. When doHttpGet succeeds with a 200 response, it allocates memory for the data parameter. The test should free this memory to prevent memory leaks in test runs. Add if (data) free(data); after the assertion.
    EXPECT_EQ(doHttpGet("https://test.com", &data), T2ERROR_SUCCESS);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings February 23, 2026 11:43
RDK-60805: Adding L1 unit test cases for reportprofiles (#265)
Copy link
Contributor

Copilot AI left a 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 17 out of 17 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

source/test/mocks/FileioMock.cpp:503

  • This wrapper returns CURLE_FAILED_INIT whenever g_fileIOMock is null, instead of falling back to the real curl_easy_setopt (similar to how other wrappers fall back via dlsym). This can cause unrelated tests or code paths to fail if they invoke curl_easy_setopt before the mock is installed. Prefer calling curl_easy_setopt_func when g_fileIOMock == nullptr.
extern "C" CURLcode curl_easy_setopt(CURL* handle, CURLoption option, ...) {
    if (g_fileIOMock != nullptr) {
        va_list args;
        va_start(args, option);
        void* param = va_arg(args, void*);
        va_end(args);
        return g_fileIOMock->curl_easy_setopt(handle, option, param);
    }
    return CURLE_FAILED_INIT;
}

test/functional-tests/tests/helper_functions.py:120

  • verify=CA_BUNDLE hard-codes /etc/ssl/certs/ca-certificates.crt without checking it exists. In minimal containers/distros this file may be missing or in a different location, causing requests.get(...) to raise and fail tests. Consider checking os.path.exists(CA_BUNDLE) and falling back to verify=True (requests default) or to verify=False in the test environment, and/or make the CA bundle path configurable via env var.
# CA certificate for server verification
CA_BUNDLE = '/etc/ssl/certs/ca-certificates.crt'  # System CA bundle


def run_telemetry():
    return subprocess.run("/usr/local/bin/telemetry2_0", shell=True)

def run_shell_silent(command):
    subprocess.run(command, shell=True, capture_output=False, text=False)
    return 

def run_shell_command(command):
    result = subprocess.run(command, shell=True, capture_output=True, text=True)
    return result.stdout.strip()

def kill_telemetry(signal: int=9):
    print(f"Recived Signal to kill telemetry2_0 {signal} with pid {get_pid('telemetry2_0')}")
    resp = subprocess.run(f"kill -{signal} {get_pid('telemetry2_0')}", shell=True, capture_output=True)
    print(resp.stdout.decode('utf-8'))
    print(resp.stderr.decode('utf-8'))
    return ""
"""
def sigterm_telemetry(pid:str):
    resp = subprocess.run(f"echo 'this is a test'; kill -15 `pidof telemetry2_0`; echo $?; echo !!", shell=True, capture_output=True)
    print(resp.stdout.decode('utf-8'))
    print(resp.stderr.decode('utf-8'))
    print(get_pid("telemetry2_0"))
    cmd=["kill","-15",str(pid)]
    print(f"Running command: {' '.join(cmd)}")
    result = subprocess.run(cmd, capture_output=True, text=True)
    print("Output:", result.stdout)
    print("Error:", result.stderr)
"""

def sigterm_telemetry(pid):
    try:
        # Print the command being executed
        print(f"Sending SIGTERM to process {pid}")
        
        # Send the SIGTERM signal to the process
        os.kill(int(pid), signal.SIGTERM)
        
        print(f"Process {pid} has been terminated.")
    except ProcessLookupError:
        print(f"No process with PID {pid} found.")
    except PermissionError:
        print(f"Permission denied to kill process {pid}.")
    except Exception as e:
        print(f"An error occurred: {e}")


def adminSupport_cache(save: bool = True):
    if(requests.get(ADMIN_SUPPORT_SET, verify=CA_BUNDLE, cert=CERT_PATH, params={ADMIN_CACHE_ARG: str(save).lower()})):
        return True
    return False

def adminSupport_requestData():
    return_data = requests.get(ADMIN_SUPPORT_GET, verify=CA_BUNDLE, cert=CERT_PATH, params={ADMIN_RQUEST_DATA: "true"})
    try:

test/run_l2.sh:41

  • $RESULT_DIR is expanded unquoted in the --json-report-file arguments. Quoting it avoids failures if the path ever contains spaces or glob characters (and is consistent with how mkdir -p is called above).
pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/runs_as_daemon.json test/functional-tests/tests/test_runs_as_daemon.py || final_result=1
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

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings February 23, 2026 14:20
Copy link
Contributor

Copilot AI left a 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 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (12)

source/protocol/http/multicurlinterface.c:115

  • The log message incorrectly states "Curl connection pool size set from environment" even though it's printed regardless of whether the value came from the environment or the default. This should only be logged when env_size is actually set. Consider moving this log inside the if condition or changing the message to indicate whether it's from the environment or the default.
            T2Info("Curl connection pool size set from environment: %d\n", configured_size);

source/protocol/http/multicurlinterface.c:472

  • This comment is misleading. The function still clears CURLOPT_POSTFIELDS, CURLOPT_POSTFIELDSIZE, and CURLOPT_HTTPHEADER even though the comment only mentions that CURLOPT_CUSTOMREQUEST was removed. The comment should be updated to accurately describe which POST-specific options are being cleared. Note that line 469 that clears CURLOPT_CUSTOMREQUEST was removed but the comment wasn't updated accordingly.
    // Clear any POST-specific settings so that the handle can be used for GET operations
    // curl_easy_perform ends up in crash when POST specific options are not cleared
    CURL_SETOPT_CHECK(easy, CURLOPT_POSTFIELDS, NULL);
    CURL_SETOPT_CHECK(easy, CURLOPT_POSTFIELDSIZE, 0L);
    CURL_SETOPT_CHECK(easy, CURLOPT_HTTPHEADER, NULL);

source/xconf-client/xconfclient.c:547

  • Logging level changed from T2Info to T2Debug. This reduces log verbosity for successful HTTP GET operations. While this may be intentional for reducing log noise, consider whether successful HTTP GET operations should still be logged at INFO level for operational visibility. Debug-level logging may make troubleshooting more difficult in production environments.
        T2Debug("HTTP GET request completed successfully\n");

source/test/xconf-client/xconfclientTest.cpp:651

  • The lambda function for getParameterValue mock returns void (empty return statement at line 650), but the function is expected to return T2ERROR. This will cause a compilation error or undefined behavior. The return statement should be 'return T2ERROR_SUCCESS;' to match the function signature and the pattern used in other similar mocks in this file.
    EXPECT_CALL(*m_xconfclientMock, getParameterValue(_,_))
            .Times(1)
            .WillOnce([](const char* paramName, char** paramValue) {
            if (strcmp(paramName, "Device.X_RDK_WanManager.CurrentActiveInterface") == 0)
                *paramValue = strdup("erouter0");
            else
                *paramValue = strdup("unknown");
            return ;
    });

source/test/xconf-client/xconfclientTest.cpp:698

  • The lambda function for getParameterValue mock returns void (empty return statement at line 697), but the function is expected to return T2ERROR. This will cause a compilation error or undefined behavior. The return statement should be 'return T2ERROR_SUCCESS;' to match the function signature and the pattern used in other similar mocks in this file.
    EXPECT_CALL(*m_xconfclientMock, getParameterValue(_,_))
            .Times(1)
            .WillOnce([](const char* paramName, char** paramValue) {
            if (strcmp(paramName, "Device.X_RDK_WanManager.CurrentActiveInterface") == 0)
                *paramValue = strdup("erouter0");
            else
                *paramValue = strdup("unknown");
            return ;
    });

source/test/xconf-client/xconfclientTest.cpp:68

  • The comment describes preventing a deadlock caused by mocked fwrite calls when GTest logs output. However, this macro only mocks fwrite and not fputs which is also mentioned in the comment. If fputs can also cause deadlock issues, it should be included in the macro. Otherwise, the comment should be updated to only mention fwrite.
// Helper macro to prevent deadlock from mocked fwrite and fputs calls in the protocol code when GTest tries to log output, which can cause a deadlock if the logging functions are mocked without allowing real calls to them.
#define PREVENT_GTEST_LOGGING_DEADLOCK() \
    EXPECT_CALL(*g_fileIOMock, fwrite(::testing::_, ::testing::_, ::testing::_, ::testing::_)) \
        .Times(::testing::AnyNumber()) \
        .WillRepeatedly(::testing::Invoke( \
            [](const void* ptr, size_t size, size_t nitems, FILE* stream) { \
                return ::fwrite(ptr, size, nitems, stream); \
            }))

source/xconf-client/Makefile.am:27

  • Adding -lrdkconfig to the linker flags when LIBRDKCERTSEL is enabled. However, based on the conditional compilation guards in the code (#ifndef LIBRDKCERTSEL_BUILD wrapping #ifdef LIBRDKCONFIG_BUILD), rdkconfig should NOT be used when LIBRDKCERTSEL_BUILD is defined. This creates a potential inconsistency - the library will be linked but the code won't use it when LIBRDKCERTSEL is enabled. Consider whether -lrdkconfig should be added unconditionally or under a separate IS_LIBRDKCONFIG_ENABLED condition rather than within the IS_LIBRDKCERTSEL_ENABLED block.
libxconfclient_la_LDFLAGS += -lRdkCertSelector -lrdkconfig

test/functional-tests/tests/helper_functions.py:60

  • The certificate path discovery logic attempts to find valid certificates by checking multiple standard locations. However, if CERT_PATH remains None (no valid certificates found), subsequent requests.get() calls will still use cert=CERT_PATH which passes None, effectively disabling client certificates. While a warning is printed, consider whether the tests should fail explicitly if no certificates are found, or if this is intentional to allow running tests without mTLS in some environments.
if CERT_PATH is None:
    print("WARNING: No valid client certificate found!")

build_inside_container.sh:34

  • Adding -DENABLE_MTLS to CFLAGS and --enable-rdkcertselector=yes to configure. This enables mTLS support in the build. Ensure that the test environment (docker containers) has the necessary certificates and configuration to support mTLS testing, as indicated by the ENABLE_MTLS=true environment variable being passed to the docker containers in the L2-tests.yml workflow.
export CFLAGS=" ${DEBUG_CFLAGS} -I${INSTALL_DIR}/include/rtmessage -I${INSTALL_DIR}/include/msgpack -I${INSTALL_DIR}/include/rbus -I${INSTALL_DIR}/include -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/local/include -DFEATURE_SUPPORT_WEBCONFIG -DRDK_LOGGER -DPERSIST_LOG_MON_REF -DDCMAGENT -DENABLE_MTLS" 

export LDFLAGS="-L/usr/lib/x86_64-linux-gnu -lglib-2.0"

./configure --prefix=${INSTALL_DIR} --enable-rdkcertselector=yes && make && make install

source/test/protocol/ProtocolTest.cpp:363

  • The test expects T2ERROR_FAILURE but doesn't set up the necessary mocks to simulate the failure condition. The test only mocks isMtlsEnabled() to return true and access() to return 0, but doesn't mock curl_easy_perform or curl_easy_getinfo_mock, which are likely needed for the actual HTTP operation. Without these mocks, the test may not behave as intended. Consider adding the missing mock expectations or documenting why this specific failure case is being tested.
TEST_F(protocolTestFixture, SENDREPORTOVERHTTP3)
{
      char* httpURL = "https://mockxconf:50051/dataLakeMock";
      char* payload = strdup("This is a payload string");
      char *cm = (char*)0xFFFFFFFF;

      EXPECT_CALL(*g_fileIOMock, curl_easy_init())
      .Times(::testing::AnyNumber())
      .WillRepeatedly(::testing::Invoke([]() {
          // Return unique fake handles for each call
          static int handle_counter = 1;
          return (CURL*)(uintptr_t)(0x1000 + handle_counter++);
      }));

      #if defined(ENABLE_RDKB_SUPPORT) && !defined(RDKB_EXTENDER)
      #if defined(WAN_FAILOVER_SUPPORTED) || defined(FEATURE_RDKB_CONFIGURABLE_WAN_INTERFACE)
      EXPECT_CALL(*m_xconfclientMock, getParameterValue(_,_))
              .Times(1)
              .WillOnce(Return(T2ERROR_SUCCESS));
      #endif
      #endif
      EXPECT_CALL(*m_xconfclientMock, isMtlsEnabled())
              .Times(1)
              .WillOnce(Return(true));
      EXPECT_CALL(*g_systemMock, access(_,_))
             .Times(1)
             .WillOnce(Return(0));
      #ifdef LIBRDKCONFIG_BUILD
      EXPECT_CALL(*g_rdkconfigMock, rdkconfig_get(_,_,_))
             .Times(1)
             .WillOnce(Return(RDKCONFIG_OK));
      #endif
      EXPECT_EQ(T2ERROR_FAILURE, sendReportOverHTTP(httpURL, payload));
      free(payload);
}

source/protocol/http/multicurlinterface.c:66

  • The DEFAULT_POOL_SIZE is reduced from 2 to 1. While this is a valid optimization for low-end devices, consider verifying that this change doesn't negatively impact performance in scenarios with concurrent HTTP requests. The pool size can still be configured via the T2_CONNECTION_POOL_SIZE environment variable for devices that need higher concurrency.
#define DEFAULT_POOL_SIZE 1

source/protocol/http/Makefile.am:27

  • Adding -lrdkconfig to the linker flags when LIBRDKCERTSEL is enabled. However, based on the conditional compilation guards in the code (#ifndef LIBRDKCERTSEL_BUILD wrapping #ifdef LIBRDKCONFIG_BUILD), rdkconfig should NOT be used when LIBRDKCERTSEL_BUILD is defined. This creates a potential inconsistency - the library will be linked but the code won't use it when LIBRDKCERTSEL is enabled. Consider whether -lrdkconfig should be added unconditionally or under a separate IS_LIBRDKCONFIG_ENABLED condition rather than within the IS_LIBRDKCERTSEL_ENABLED block.
libhttp_la_LDFLAGS += -lRdkCertSelector -lrdkconfig

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings February 23, 2026 15:14
Copy link
Contributor

Copilot AI left a 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 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

source/protocol/http/multicurlinterface.c:781

  • The removal of CURL_SETOPT_CHECK(easy, CURLOPT_HTTPGET, 0L); from the POST request cleanup could cause issues. When a curl handle is reused from the pool after performing a GET request, CURLOPT_HTTPGET may still be set to 1L (from line 497). Setting CURLOPT_POST to 1L doesn't necessarily disable the GET flag. According to libcurl documentation, you should explicitly disable HTTPGET before doing a POST to avoid undefined behavior. Consider restoring this line or verifying that CURLOPT_POST automatically clears CURLOPT_HTTPGET.
    // Clear any GET-specific settings from previous use
    CURL_SETOPT_CHECK(easy, CURLOPT_WRITEFUNCTION, NULL);
    CURL_SETOPT_CHECK(easy, CURLOPT_WRITEDATA, NULL);

source/protocol/http/multicurlinterface.c:66

  • The DEFAULT_POOL_SIZE was changed from 2 to 1. This is a significant change that may impact performance. With a pool size of 1, concurrent HTTP requests will have to wait for the single handle to become available, potentially creating a bottleneck. Consider documenting why this change was made, especially since the comment on line 106 mentions "configure the connection pool size based on the device type" and there's an environment variable T2_CONNECTION_POOL_SIZE to override this. If this is intentional for low-end devices, it should be clearly documented.
#define DEFAULT_POOL_SIZE 1

source/protocol/http/multicurlinterface.c:469

  • The comment states "curl_easy_perform ends up in crash when POST specific options are not cleared", but this is actually clearing POST options before a GET request, not after. The comment should say "Clear any POST-specific settings from previous use to prevent crashes" to be more accurate.
    // curl_easy_perform ends up in crash when POST specific options are not cleared

source/protocol/http/multicurlinterface.c:107

  • The comment on line 106 has a typo: "to have the size" should be part of a grammatically complete sentence. Consider rewording to: "Check environment variable T2_CONNECTION_POOL_SIZE to configure the connection pool size based on the device type".
    // Check environment variable T2_CONNECTION_POOL_SIZE to have the size
    // of the connection pool based on the device type

source/protocol/http/multicurlinterface.c:726

  • The spelling of "certicates" is incorrect. It should be "certificates" for consistency with standard spelling.
    // In case of CertSelector, CertSelector will take care of freeing the certicates

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings February 24, 2026 11:27
Copy link
Contributor

Copilot AI left a 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 17 out of 17 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (3)

test/functional-tests/tests/report_profiles.py:1240

  • This URL change updates the Split66 profile endpoint, but related functional tests still assert the old dataLookeMock URL (e.g., test_temp_profile.py and test_multiprofile_msgpacket.py grep for it). Either keep the profile URL consistent with those expectations or update the assertions/test data so they match the new endpoint.
        "HTTP": {
          "URL": "https://mockxconf:50051/dataLakeMockXconf/",
          "Compression": "None",
          "Method": "POST",
          "RequestURIParameter": [

test/run_l2.sh:44

  • Unquoted shell variables can break if paths ever contain spaces or glob characters. Quote $RESULT_DIR (and $final_result in the test) consistently in the pytest invocations and the [ ... ] comparison to avoid word-splitting issues.
pytest -v --json-report --json-report-summary --json-report-file $RESULT_DIR/runs_as_daemon.json test/functional-tests/tests/test_runs_as_daemon.py || final_result=1
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."

source/test/xconf-client/xconfclientTest.cpp:422

  • The comment here says the pool default size is 2, but this PR changes DEFAULT_POOL_SIZE to 1 in multicurlinterface.c. Please update the comment to reflect the current default (or avoid hard-coding the number in the comment).
        // Set up curl_easy_init to return valid handles for pool initialization
        // The pool will call curl_easy_init() based on pool size (default 2)
        EXPECT_CALL(*g_fileIOMock, curl_easy_init())

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@shibu-kv shibu-kv left a comment

Choose a reason for hiding this comment

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

Please revisit . There are high chances of race conditions and deadlocks.

active_requests--;
// Wake both waiting acquire threads AND cleanup function
// in case they are waiting for handles to be released
pthread_cond_broadcast(&pool_cond);
Copy link
Contributor

Choose a reason for hiding this comment

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

This change suggests that there are multiple parallel threads waiting on something. We should try to avoid this if possible as this creates a lot of context switching.


// Wait for for active_requests to drop to 0, which indicates all threads have completed
// their curl_easy_perform calls and released their handles back to the pool.
while (active_requests > 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

High risks of dead locks. Is the active_requests are not decremented in the shutdown sequence, then this part gets hung forever. If this path is chosen further, there should be some bound checks. Value of active_requests should never exceed the poolsize. So some sort of boundry checks should be added. Fact that this implementation limits the pool size to 1, there seems to be something that is not quite right with the mutex locking some critical path.

static http_pool_entry_t *pool_entries = NULL; // Dynamic array of pool entries
static struct curl_slist *post_headers = NULL; // Shared POST headers
static int pool_size = 0; // Number of pool entries
static int active_requests = 0; // Number of curl handles in use
Copy link
Contributor

Choose a reason for hiding this comment

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

Use unsigned int or even unsigned short int.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants