From 8b1d338075ed86671dc6ace7ede9c1825605175c Mon Sep 17 00:00:00 2001 From: neethuas379 Date: Wed, 28 Jan 2026 21:35:21 +0000 Subject: [PATCH 1/4] RDKEMW-11398: Implement HdmiCecSink & UserSettings communication. (#342) * RDKEMW-11398: Implement HdmiCecSink & UserSettings communication. * Update HdmiCecSinkImplementation.h * Update HdmiCecSinkImplementation.cpp Co-authored-by: neethu.arambilsunny@sky.uk --- HdmiCecSink/HdmiCecSinkImplementation.cpp | 88 ++++++++++++++++++++++- HdmiCecSink/HdmiCecSinkImplementation.h | 32 +++++++++ 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/HdmiCecSink/HdmiCecSinkImplementation.cpp b/HdmiCecSink/HdmiCecSinkImplementation.cpp index 422facccd..42e76f92a 100644 --- a/HdmiCecSink/HdmiCecSinkImplementation.cpp +++ b/HdmiCecSink/HdmiCecSinkImplementation.cpp @@ -92,7 +92,6 @@ static VendorID appVendorId = {defaultVendorId.at(0),defaultVendorId.at(1),defau static VendorID lgVendorId = {0x00,0xE0,0x91}; static PhysicalAddress physical_addr = {0x0F,0x0F,0x0F,0x0F}; static LogicalAddress logicalAddress = 0xF; -static Language defaultLanguage = "eng"; static OSDName osdName = "TV Box"; static int32_t powerState = DEVICE_POWER_STATE_OFF; static std::vector formatid = {0,0}; @@ -606,6 +605,8 @@ namespace WPEFramework , m_connectedDevices() , msgProcessor(nullptr) , msgFrameListener(nullptr) + , _userSettingsPlugin(nullptr) + , _userSettingsNotification(*this) , _powerManagerPlugin() , _pwrMgrNotification(*this) , _registeredEventHandlers(false) @@ -621,6 +622,13 @@ namespace WPEFramework _powerManagerPlugin.Reset(); } _registeredEventHandlers = false; + + if(_userSettingsPlugin) + { + _userSettingsPlugin->Unregister(&_userSettingsNotification); + _userSettingsPlugin->Release(); + _userSettingsPlugin = nullptr; + } CECDisable(); m_currentArcRoutingState = ARC_STATE_ARC_EXIT; @@ -779,6 +787,29 @@ namespace WPEFramework } } getCecVersion(); + + _userSettingsPlugin = service->QueryInterfaceByCallsign("org.rdk.UserSettings"); + if (nullptr == _userSettingsPlugin) { + LOGERR("Failed to get UserSettings interface"); + } + else + { + _userSettingsPlugin->Register(&_userSettingsNotification); + LOGINFO("Successfully registered for UserSettings notifications"); + + string presentationLanguage, isoLang; + uint32_t status = _userSettingsPlugin->GetPresentationLanguage(presentationLanguage); + if (status == Core::ERROR_NONE) { + isoLang = mapToIso639_2(presentationLanguage); + LOGINFO("Successfully retrieved the Presentation language from the userSettings plugin - BCP47: %s, ISO 639-2: %s", presentationLanguage.c_str(), isoLang.c_str()); + setCurrentLanguage(Language(isoLang.data())); + sendMenuLanguage(); + } + else { + LOGERR("Failed to get presentation language: %u", status); + } + } + LOGINFO(" HdmiCecSinkImplementation plugin Initialize completed \n"); return Core::ERROR_NONE; @@ -853,6 +884,17 @@ namespace WPEFramework HdmiCecSinkImplementation::_instance->onHdmiHotPlug((int) port, isConnected); } + void HdmiCecSinkImplementation::onPresentationLanguageChanged(const string& presentationLanguage) + { + if(!HdmiCecSinkImplementation::_instance) + return; + + string isoLang = mapToIso639_2(presentationLanguage); + LOGINFO("OnPresentationLanguageChanged - language BCP47: %s, ISO 639-2: %s", presentationLanguage.c_str(), isoLang.c_str()); + setCurrentLanguage(Language(isoLang.data())); + sendMenuLanguage(); + } + void HdmiCecSinkImplementation::onPowerModeChanged(const PowerState ¤tState, const PowerState &newState) { if(!HdmiCecSinkImplementation::_instance) @@ -1484,6 +1526,7 @@ namespace WPEFramework lang = language; setCurrentLanguage(Language(lang.data())); + sendMenuLanguage(); successResult.success = true; return Core::ERROR_NONE; @@ -1722,6 +1765,46 @@ namespace WPEFramework return cecSettingEnabled; } + std::string HdmiCecSinkImplementation::mapToIso639_2(const string& lang_BCP47) + { + if (lang_BCP47.empty()) + return "eng"; + + std::string lang = lang_BCP47.substr(0, lang_BCP47.find('-')); + std::transform(lang.begin(), lang.end(), lang.begin(), ::tolower); + + if (lang.length() == 3) + return lang; + + static const std::unordered_map iso639_1_to_2 = { + {"en", "eng"}, + {"fr", "fra"}, + {"de", "deu"}, + {"es", "spa"}, + {"it", "ita"}, + {"pt", "por"}, + {"ru", "rus"}, + {"zh", "zho"}, + {"ja", "jpn"}, + {"ko", "kor"}, + {"ar", "ara"}, + {"hi", "hin"}, + {"nl", "nld"}, + {"sv", "swe"}, + {"fi", "fin"}, + {"no", "nor"}, + {"da", "dan"}, + {"pl", "pol"}, + {"tr", "tur"} + }; + + auto it = iso639_1_to_2.find(lang); + if (it != iso639_1_to_2.end()) + return it->second; + + return "eng"; + } + void HdmiCecSinkImplementation::setEnabled(bool enabled) { LOGINFO("Entered setEnabled: %d cecSettingEnabled :%d ",enabled, cecSettingEnabled); @@ -2637,7 +2720,6 @@ namespace WPEFramework _instance->deviceList[_instance->m_logicalAddressAllocated].m_cecVersion = Version::V_1_4; _instance->deviceList[_instance->m_logicalAddressAllocated].m_vendorID = appVendorId; _instance->deviceList[_instance->m_logicalAddressAllocated].m_powerStatus = PowerStatus(powerState); - _instance->deviceList[_instance->m_logicalAddressAllocated].m_currentLanguage = defaultLanguage; _instance->deviceList[_instance->m_logicalAddressAllocated].m_osdName = osdName.toString().c_str(); if(cecVersion == 2.0) { _instance->deviceList[_instance->m_logicalAddressAllocated].m_cecVersion = Version::V_2_0; @@ -3497,4 +3579,4 @@ namespace WPEFramework } } // namespace Plugin -} // namespace WPEFramework \ No newline at end of file +} // namespace WPEFramework diff --git a/HdmiCecSink/HdmiCecSinkImplementation.h b/HdmiCecSink/HdmiCecSinkImplementation.h index bc1f37bcd..4869dadc9 100644 --- a/HdmiCecSink/HdmiCecSinkImplementation.h +++ b/HdmiCecSink/HdmiCecSinkImplementation.h @@ -40,6 +40,7 @@ #include "UtilsLogging.h" #include +#include #include "PowerManagerInterface.h" #include #include "host.hpp" @@ -527,6 +528,7 @@ namespace WPEFramework { static HdmiCecSinkImplementation* _instance; CECDeviceParams deviceList[16]; std::vector hdmiInputs; + std::string mapToIso639_2(const string& lang_BCP47); int m_currentActiveSource; void updateInActiveSource(const int logical_address, const InActiveSource &source ); void updateActiveSource(const int logical_address, const ActiveSource &source ); @@ -570,6 +572,7 @@ namespace WPEFramework { void sendGiveAudioStatusMsg(); void onPowerModeChanged(const PowerState ¤tState, const PowerState &newState); void registerEventHandlers(); + void onPresentationLanguageChanged(const string& language); void getHdmiArcPortID(); int m_numberOfDevices; /* Number of connected devices othethan own device */ bool m_audioDevicePowerStatusRequested; @@ -612,6 +615,33 @@ namespace WPEFramework { HdmiCecSinkImplementation& _parent; }; + + class UserSettingsNotification : public Exchange::IUserSettings::INotification { + private: + UserSettingsNotification(const UserSettingsNotification&) = delete; + UserSettingsNotification& operator=(const UserSettingsNotification&) = delete; + + public: + explicit UserSettingsNotification(HdmiCecSinkImplementation& parent) + : _parent(parent) + { + } + ~UserSettingsNotification() override = default; + + public: + void OnPresentationLanguageChanged(const string& language) override + { + _parent.onPresentationLanguageChanged(language); + } + + BEGIN_INTERFACE_MAP(UserSettingsNotification) + INTERFACE_ENTRY(Exchange::IUserSettings::INotification) + END_INTERFACE_MAP + + private: + HdmiCecSinkImplementation& _parent; + }; + // We do not allow this plugin to be copied !! HdmiCecSinkImplementation(const HdmiCecSinkImplementation&) = delete; HdmiCecSinkImplementation& operator=(const HdmiCecSinkImplementation&) = delete; @@ -664,6 +694,8 @@ namespace WPEFramework { std::vector m_connectedDevices; HdmiCecSinkProcessor *msgProcessor; HdmiCecSinkFrameListener *msgFrameListener; + Exchange::IUserSettings *_userSettingsPlugin; + Core::Sink _userSettingsNotification; PowerManagerInterfaceRef _powerManagerPlugin; Core::Sink _pwrMgrNotification; bool _registeredEventHandlers; From 217e33a7333aacf33134d7cb469dc8f0106a784b Mon Sep 17 00:00:00 2001 From: GitHub Actions <187267378+rdkcm-rdke@users.noreply.github.com> Date: Wed, 28 Jan 2026 21:35:53 +0000 Subject: [PATCH 2/4] 1.10.3 release changelog updates --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ff36e9c..be49840d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.10.3](https://github.com/rdkcentral/entservices-inputoutput/compare/1.10.2...1.10.3) + +- RDKEMW-11398: Implement HdmiCecSink & UserSettings communication. [`#342`](https://github.com/rdkcentral/entservices-inputoutput/pull/342) +- Merge tag '1.10.2' into develop [`e22d4a8`](https://github.com/rdkcentral/entservices-inputoutput/commit/e22d4a8db483fc7f6dbfeb67a43e207830ff7905) + #### [1.10.2](https://github.com/rdkcentral/entservices-inputoutput/compare/1.10.1...1.10.2) +> 13 January 2026 + - RDKEMW-12459: ARC - SAD is not updating as expected. [`#358`](https://github.com/rdkcentral/entservices-inputoutput/pull/358) +- 1.10.2 release changelog updates [`67dca55`](https://github.com/rdkcentral/entservices-inputoutput/commit/67dca55a00bd3e9bc6f5b4be23723cc916166b3b) - Merge tag '1.10.1' into develop [`168ed58`](https://github.com/rdkcentral/entservices-inputoutput/commit/168ed5828d53b3a411026b65cc53b866575ca31a) #### [1.10.1](https://github.com/rdkcentral/entservices-inputoutput/compare/1.10.0...1.10.1) From a3c49cf7a18705b9d93f69bed4bc5ebb3b089acd Mon Sep 17 00:00:00 2001 From: balav08 <54432605+balav08@users.noreply.github.com> Date: Sat, 21 Feb 2026 03:21:52 +0530 Subject: [PATCH 3/4] RDKEMW-10832 : Intermittent failure on testframework while running entservices-inputoutput workflow (#293) * Test PR to validate L1-L2 test * Update test_HdmiCecSink.cpp * Update L1-tests.yml * Remove listeners clearing in HdmiCecSinkDsTest destructor Removed unnecessary clearing of listeners vector in destructor. * Update expected response in getSPD test * Update expected response in getSPD test * Refactor getSPD test for HDMI SPD info Updated the expected data structure in getHDMISPDInfo mock and modified response validation to check for substrings. * Refactor test cases for pingDeviceUpdateList Updated mock expectations in tests to call pingDeviceUpdateList directly for failure scenarios, improving test clarity and reliability. * Refactor HDMI CEC tests for event handling Refactor tests to subscribe and unsubscribe to HDMI hot plug events during failure scenarios. * Udpate test_HdcpProfile.cpp * Update test_HdcpProfile.cpp * Update test_HdmiCecSource.cpp * Update test_HdmiCecSource.cpp * Add wait for detached thread operations to complete * Remove unwanted changes * Update test_HdmiCecSource.cpp * Add conditional check for tests running with valgrind and coverage generation when the caller source is Testframework * Change checkout reference to feature/L1-L2test * Update Tests/L1Tests/tests/test_HdmiCecSource.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Tests/L1Tests/tests/test_HdmiCecSource.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Tests/L1Tests/tests/test_HdmiCecSource.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix L1 cache collision: Add repository-specific cache key * Fix L1 cache paths to match actual build output locations * Add cache-hit condition to patch steps to prevent errors when cache is restored * Remove cache-hit condition from entservices-apis checkout - needed on every run * Remove cache-hit conditions from googletest - excluded from cache so must build every time * Always checkout Thunder source - headers needed for builds even when binaries cached * Remove Thunder source includes from builds - use only installed headers to prevent duplicate definitions * Always checkout Thunder source and add includes for testframework build needing Communicator mock * Add Thunder source includes back to inputoutput component build for HdmiCecSource compilation * Add Thunder source includes to mocks build to match L2-tests.yml configuration * Update L1-test.yml * Update L1-test.yml * Update L1-test.yml * Update L1-tests.yml * Update L2-tests.yml * Update L1-tests.yml * Update L2-tests.yml * Update test_HdcpProfile.cpp * Add COMRPC support to L2Tests Plugin * Fix segfault: Remove redundant AddRef() calls in HdmiCecSource L1 test The test had 10 AddRef() calls on p_hdmiCecSourceMock without matching Release() calls, causing reference count imbalance and segmentation fault during cleanup. These AddRef() calls were unnecessary since: 1. The mock object is created with new and managed manually 2. The Register() method doesn't actually increment reference count in the mock 3. No corresponding Release() was being called before cleanup This fix resolves the segmentation fault in tests like: - HdmiCecSourceInitializedEventTest.giveDeviceVendorIdProcess_LGTV * Fix giveDeviceVendorIdProcess_LGTV segfault with thread synchronization The test was segfaulting because OnDisplayHDMIHotPlug() spawns a detached thread that accesses instance members (m_lock, m_condSig). When the test fixture is destroyed immediately after calling OnDisplayHDMIHotPlug(), the detached thread may still be running and attempts to access destroyed objects, causing a segmentation fault. Added a 100ms sleep after OnDisplayHDMIHotPlug() to allow the detached thread sufficient time to complete its execution before the test fixture cleanup begins. This resolves the segmentation fault in: - HdmiCecSourceInitializedEventTest.giveDeviceVendorIdProcess_LGTV * Fix HdmiCecSink WaitForRequestStatus event flag handling Same issue as PowerManager: WaitForRequestStatus was not clearing event flags after returning, causing subsequent waits to see stale events or miss new ones. Fixed by clearing only the specific expected flag(s) after waiting: m_event_signalled &= ~expected_status; This prevents race conditions when multiple events fire in quick succession. * test_HdmiCecSource.cpp * test_HdmiCecSource.cpp * test_HdmiCecSource.cpp * Update HdmiCecSink_L2Test.cpp * Update test_HdmiCecSource.cpp * Fix SetLgTV and giveDeviceVendorIdProcess_LGTV intermittent segfault The tests override getEDIDBytes mock without wrapping calls in m_activeThreadCalls counter. When OnDisplayHDMIHotPlug spawns threadHotPlugEventHandler, it calls getEDIDBytes asynchronously. The test destructor completes before this thread finishes, causing segfault when accessing destroyed mock objects. Changed lambda capture from [&] to [this] and added m_activeThreadCalls increment/decrement to match the fixture's default mock setup. This ensures the destructor waits for all detached threads to complete before cleanup. * Update L2-tests.yml * Update L2_tests.yml * Update L1_tests.yml * Update L1-tests.yml * Update L2-tests.yml * Update L1-tests.yml * Update L2-tests.yml --------- Co-authored-by: smanes0213 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: preeja33 Co-authored-by: mkumar705 --- .github/workflows/L1-tests.yml | 54 ++++++------- .github/workflows/L2-tests.yml | 11 ++- Tests/L1Tests/tests/test_HdcpProfile.cpp | 11 +++ Tests/L1Tests/tests/test_HdmiCecSource.cpp | 90 +++++++++++++++++----- Tests/L2Tests/tests/HdmiCecSink_L2Test.cpp | 18 +++++ 5 files changed, 132 insertions(+), 52 deletions(-) diff --git a/.github/workflows/L1-tests.yml b/.github/workflows/L1-tests.yml index 3ba25a3a3..052041e35 100755 --- a/.github/workflows/L1-tests.yml +++ b/.github/workflows/L1-tests.yml @@ -13,6 +13,7 @@ on: env: BUILD_TYPE: Debug + REPO_NAME: "inputoutput" THUNDER_REF: "R4.4.1" INTERFACES_REF: "develop" AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME}} @@ -45,25 +46,25 @@ jobs: uses: actions/cache@v3 with: path: | - thunder/build/Thunder - thunder/build/entservices-apis - thunder/build/ThunderTools - thunder/install - !thunder/install/etc/WPEFramework/plugins - !thunder/install/usr/bin/RdkServicesTest - !thunder/install/usr/include/gmock - !thunder/install/usr/include/gtest - !thunder/install/usr/lib/libgmockd.a - !thunder/install/usr/lib/libgmock_maind.a - !thunder/install/usr/lib/libgtestd.a - !thunder/install/usr/lib/libgtest_maind.a - !thunder/install/usr/lib/cmake/GTest - !thunder/install/usr/lib/pkgconfig/gmock.pc - !thunder/install/usr/lib/pkgconfig/gmock_main.pc - !thunder/install/usr/lib/pkgconfig/gtest.pc - !thunder/install/usr/lib/pkgconfig/gtest_main.pc - !thunder/install/usr/lib/wpeframework/plugins - key: ${{ runner.os }}-${{ env.THUNDER_REF }}-${{ env.INTERFACES_REF }}-4 + build/Thunder + build/entservices-apis + build/ThunderTools + install + !install/etc/WPEFramework/plugins + !install/usr/bin/RdkServicesTest + !install/usr/include/gmock + !install/usr/include/gtest + !install/usr/lib/libgmockd.a + !install/usr/lib/libgmock_maind.a + !install/usr/lib/libgtestd.a + !install/usr/lib/libgtest_maind.a + !install/usr/lib/cmake/GTest + !install/usr/lib/pkgconfig/gmock.pc + !install/usr/lib/pkgconfig/gmock_main.pc + !install/usr/lib/pkgconfig/gtest.pc + !install/usr/lib/pkgconfig/gtest_main.pc + !install/usr/lib/wpeframework/plugins + key: ${{ runner.os }}-${{ env.REPO_NAME }}-${{ env.THUNDER_REF }}-${{ env.INTERFACES_REF }}-4 - name: Set up Python uses: actions/setup-python@v4 @@ -103,7 +104,6 @@ jobs: sudo ninja -C build install - name: Checkout Thunder - if: steps.cache.outputs.cache-hit != 'true' uses: actions/checkout@v3 with: repository: rdkcentral/Thunder @@ -141,7 +141,6 @@ jobs: ref: develop - name: Checkout googletest - if: steps.cache.outputs.cache-hit != 'true' uses: actions/checkout@v3 with: repository: google/googletest @@ -149,6 +148,7 @@ jobs: ref: v1.15.0 - name: Apply patches ThunderTools + if: steps.cache.outputs.cache-hit != 'true' run: | cd $GITHUB_WORKSPACE/ThunderTools patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/00010-R4.4-Add-support-for-project-dir.patch @@ -170,6 +170,7 @@ jobs: cmake --install build/ThunderTools - name: Apply patches Thunder + if: steps.cache.outputs.cache-hit != 'true' run: | cd $GITHUB_WORKSPACE/Thunder patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Use_Legact_Alt_Based_On_ThunderTools_R4.4.3.patch @@ -198,7 +199,6 @@ jobs: cmake --install build/Thunder - name: Checkout entservices-apis - if: steps.cache.outputs.cache-hit != 'true' uses: actions/checkout@v3 with: repository: rdkcentral/entservices-apis @@ -313,7 +313,6 @@ jobs: run: echo "TOOLCHAIN_FILE=$GITHUB_WORKSPACE/entservices-testframework/Tests/gcc-with-coverage.cmake" >> $GITHUB_ENV - name: Build googletest - if: steps.cache.outputs.cache-hit != 'true' run: > cmake -G Ninja -S "$GITHUB_WORKSPACE/googletest" @@ -360,8 +359,6 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/network -I $GITHUB_WORKSPACE/entservices-testframework/Tests -I $GITHUB_WORKSPACE/entservices-inputoutput/helpers - -I $GITHUB_WORKSPACE/Thunder/Source - -I $GITHUB_WORKSPACE/Thunder/Source/core -I $GITHUB_WORKSPACE/install/usr/include -I ./usr/include/libdrm -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h @@ -419,8 +416,6 @@ jobs: -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/ccec/drivers -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/network -I $GITHUB_WORKSPACE/entservices-testframework/Tests - -I $GITHUB_WORKSPACE/Thunder/Source - -I $GITHUB_WORKSPACE/Thunder/Source/core -I $GITHUB_WORKSPACE/install/usr/include -I $GITHUB_WORKSPACE/install/usr/include/WPEFramework -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h @@ -646,7 +641,7 @@ jobs: rm -rf $(pwd)/rdkL1TestResults.json - name: Run unit tests with valgrind - if: ${{ !env.ACT }} + if: ${{ !env.ACT && inputs.caller_source != 'testframework' }} run: > PATH=$GITHUB_WORKSPACE/install/usr/bin:${PATH} LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install/usr/lib:$GITHUB_WORKSPACE/install/usr/lib/wpeframework/plugins:${LD_LIBRARY_PATH} @@ -663,7 +658,7 @@ jobs: rm -rf $(pwd)/rdkL1TestResults.json - name: Generate coverage - if: ${{ matrix.coverage == 'with-coverage' && !env.ACT }} + if: ${{ matrix.coverage == 'with-coverage' && !env.ACT && inputs.caller_source != 'testframework' }} run: > cp $GITHUB_WORKSPACE/entservices-testframework/Tests/L1Tests/.lcovrc_l1 ~/.lcovrc && @@ -699,3 +694,4 @@ jobs: rdkL1TestResultsWithValgrind.json if-no-files-found: warn + diff --git a/.github/workflows/L2-tests.yml b/.github/workflows/L2-tests.yml index 8584a327c..9c676e1cf 100755 --- a/.github/workflows/L2-tests.yml +++ b/.github/workflows/L2-tests.yml @@ -152,6 +152,7 @@ jobs: patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/error_code_R4_4.patch patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/1004-Add-support-for-project-dir.patch patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/RDKEMW-733-Add-ENTOS-IDS.patch + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/Increase_Timout_For_L2Tests_Plugin.patch cd - - name: Build Thunder run: > @@ -179,6 +180,12 @@ jobs: ref: ${{env.INTERFACES_REF}} run: rm -rf $GITHUB_WORKSPACE/entservices-apis/jsonrpc/DTV.json + - name: Apply patches entservices-apis + run: | + cd $GITHUB_WORKSPACE/entservices-apis + patch -p1 < $GITHUB_WORKSPACE/entservices-testframework/patches/add-l2tests-interface.patch + cd - + - name: Build entservices-apis run: > cmake @@ -717,7 +724,7 @@ jobs: rm -rf $(pwd)/rdkL2TestResults.json - name: Run unit tests with valgrind - if: ${{ !env.ACT }} + if: ${{ !env.ACT && inputs.caller_source != 'testframework' }} run: > PATH=$GITHUB_WORKSPACE/install/usr/bin:${PATH} LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install/usr/lib:$GITHUB_WORKSPACE/install/usr/lib/wpeframework/plugins:${LD_LIBRARY_PATH} @@ -733,7 +740,7 @@ jobs: rm -rf $(pwd)/rdkL2TestResults.json - name: Generate coverage - if: ${{ matrix.coverage == 'with-coverage' && !env.ACT }} + if: ${{ matrix.coverage == 'with-coverage' && !env.ACT && inputs.caller_source != 'testframework' }} run: > cp $GITHUB_WORKSPACE/entservices-testframework/Tests/L2Tests/.lcovrc_l2 ~/.lcovrc && diff --git a/Tests/L1Tests/tests/test_HdcpProfile.cpp b/Tests/L1Tests/tests/test_HdcpProfile.cpp index 20d4e64c2..f77f0b5c4 100755 --- a/Tests/L1Tests/tests/test_HdcpProfile.cpp +++ b/Tests/L1Tests/tests/test_HdcpProfile.cpp @@ -119,6 +119,8 @@ class HDCPProfileTest : public ::testing::Test { dispatcher->Deactivate(); dispatcher->Release(); + workerPool->Stop(); + Core::IWorkerPool::Assign(nullptr); workerPool.Release(); @@ -213,11 +215,20 @@ class HDCPProfileEventIarmTest : public HDCPProfileEventTest { .Times(::testing::AnyNumber()) .WillRepeatedly(::testing::Return()); + // Deinitialize the instance created by parent class first + plugin->Deinitialize(&service); + + // Small delay to ensure worker threads complete any pending jobs + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + EXPECT_EQ(string(""), plugin->Initialize(&service)); } virtual ~HDCPProfileEventIarmTest() override { + // Small delay to allow worker threads to complete pending dispatched events + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + plugin->Deinitialize(&service); device::Manager::setImpl(nullptr); if (p_managerImplMock != nullptr) diff --git a/Tests/L1Tests/tests/test_HdmiCecSource.cpp b/Tests/L1Tests/tests/test_HdmiCecSource.cpp index c50a2b9d6..de4e2d2f8 100755 --- a/Tests/L1Tests/tests/test_HdmiCecSource.cpp +++ b/Tests/L1Tests/tests/test_HdmiCecSource.cpp @@ -518,6 +518,7 @@ class HdmiCecSourceInitializedEventTest : public HdmiCecSourceInitializedTest { FactoriesImplementation factoriesImplementation; PLUGINHOST_DISPATCHER* dispatcher; Core::JSONRPC::Message message; + std::atomic m_activeThreadCalls{0}; HdmiCecSourceInitializedEventTest() : HdmiCecSourceInitializedTest() @@ -527,10 +528,59 @@ class HdmiCecSourceInitializedEventTest : public HdmiCecSourceInitializedTest { dispatcher = static_cast( plugin->QueryInterface(PLUGINHOST_DISPATCHER_ID)); dispatcher->Activate(&service); + + // Wrap mock calls to track thread activity from OnDisplayHDMIHotPlug + ON_CALL(*p_hostImplMock, getDefaultVideoPortName()) + .WillByDefault(::testing::Invoke([this]() { + m_activeThreadCalls++; + auto result = std::string("HDMI0"); + m_activeThreadCalls--; + return result; + })); + + ON_CALL(*p_hostImplMock, getVideoOutputPort(::testing::_)) + .WillByDefault(::testing::Invoke([this](const std::string& name) -> device::VideoOutputPort& { + m_activeThreadCalls++; + auto& result = device::VideoOutputPort::getInstance(); + m_activeThreadCalls--; + return result; + })); + + ON_CALL(*p_videoOutputPortMock, getDisplay()) + .WillByDefault(::testing::Invoke([this]() -> device::Display& { + m_activeThreadCalls++; + auto& result = device::Display::getInstance(); + m_activeThreadCalls--; + return result; + })); + + ON_CALL(*p_displayMock, getEDIDBytes(::testing::_)) + .WillByDefault(::testing::Invoke([this](std::vector& edid) { + m_activeThreadCalls++; + // Use the standard helper function to provide valid EDID data + edid = createLGTVEdidBytes(); + m_activeThreadCalls--; + })); } virtual ~HdmiCecSourceInitializedEventTest() override { + // Wait for any detached threads from OnDisplayHDMIHotPlug to complete + // by checking if mock methods are still being called + auto timeout = std::chrono::milliseconds(2000); + auto start = std::chrono::steady_clock::now(); + + while (m_activeThreadCalls > 0 && + std::chrono::steady_clock::now() - start < timeout) { + usleep(10 * 1000); // 10ms polling interval + } + + // If timeout reached with active calls, log warning + if (m_activeThreadCalls > 0) { + fprintf(stderr, "WARNING: Test destructor timeout with %d active thread calls\n", + m_activeThreadCalls.load()); + } + dispatcher->Deactivate(); dispatcher->Release(); PluginHost::IFactories::Assign(nullptr); @@ -986,7 +1036,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, requestActiveSourceProccess){ TEST_F(HdmiCecSourceInitializedEventTest, standyProcess){ Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1112,7 +1161,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, giveDeviceVendorIdProcess){ TEST_F(HdmiCecSourceInitializedEventTest, setOSDNameProcess){ Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1140,7 +1188,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, routingChangeProcess){ } Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1168,7 +1215,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, routingInformationProcess){ } Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1194,7 +1240,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, setStreamPathProcess){ } Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1252,7 +1297,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, deviceVendorIDProcess){ } Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1323,7 +1367,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, reportPowerStatusProcess){ TEST_F(HdmiCecSourceInitializedEventTest, userControlPressedProcess){ Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1344,7 +1387,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, userControlPressedProcess){ TEST_F(HdmiCecSourceInitializedEventTest, userControlReleasedrocess){ Core::Sink notification; uint32_t signalled = false; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1523,7 +1565,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, HdmiCecSourceFrameListener_notify_GetC iCounter ++; } Core::Sink notification; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1563,7 +1604,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, requestActiveSourceProcess_failure){ TEST_F(HdmiCecSourceInitializedEventTest, standbyProcess_failure){ Core::Sink notification; - p_hdmiCecSourceMock->AddRef(); p_hdmiCecSourceMock->Register(¬ification); Header header; @@ -1729,10 +1769,6 @@ TEST_F(HdmiCecSourceSettingsTest, HdmiCecSourceInitialize_UnsupportedProfile) TEST_F(HdmiCecSourceInitializedEventTest, pingDeviceUpdateList_Failure) { - EXPECT_CALL(*p_connectionImplMock, ping(::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AtLeast(1)) - .WillRepeatedly(::testing::Throw(CECNoAckException())); - EVENT_SUBSCRIBE(0, _T("onHdmiHotPlug"), _T("client.events.onHdmiHotPlug"), message); EXPECT_NO_THROW(Plugin::HdmiCecSourceImplementation::_instance->OnDisplayHDMIHotPlug(dsDISPLAY_EVENT_DISCONNECTED)); @@ -1742,10 +1778,6 @@ TEST_F(HdmiCecSourceInitializedEventTest, pingDeviceUpdateList_Failure) TEST_F(HdmiCecSourceInitializedEventTest, pingDeviceUpdateList_IOException) { - EXPECT_CALL(*p_connectionImplMock, ping(::testing::_, ::testing::_, ::testing::_)) - .Times(::testing::AtLeast(1)) - .WillRepeatedly(::testing::Throw(IOException())); - EVENT_SUBSCRIBE(0, _T("onHdmiHotPlug"), _T("client.events.onHdmiHotPlug"), message); EXPECT_NO_THROW(Plugin::HdmiCecSourceImplementation::_instance->OnDisplayHDMIHotPlug(dsDISPLAY_EVENT_CONNECTED)); @@ -1755,8 +1787,20 @@ TEST_F(HdmiCecSourceInitializedEventTest, pingDeviceUpdateList_IOException) TEST_F(HdmiCecSourceInitializedEventTest, hdmiEventHandler_connect_ExceptionHandling) { + int iCounter = 0; + while ((!Plugin::HdmiCecSourceImplementation::_instance->deviceList[0].m_isOSDNameUpdated) && (iCounter < (2*10))) { //sleep for 2sec. + usleep (100 * 1000); + iCounter++; + } + + // Expect sendTo to be called during connection (ReportPhysicalAddress and DeviceVendorID) EXPECT_CALL(*p_connectionImplMock, sendTo(::testing::_, ::testing::_)) - .WillOnce(::testing::Throw(std::runtime_error("sendTo failed"))); + .Times(::testing::AtLeast(1)) + .WillRepeatedly(::testing::Throw(std::runtime_error("sendTo failed"))); + + EXPECT_CALL(*p_hostImplMock, getDefaultVideoPortName()) + .Times(1) + .WillOnce(::testing::Return("TEST")); EVENT_SUBSCRIBE(0, _T("onHdmiHotPlug"), _T("client.events.onHdmiHotPlug"), message); @@ -1820,8 +1864,10 @@ TEST_F(HdmiCecSourceInitializedEventTest, SetLgTV){ ON_CALL(*p_displayMock, getEDIDBytes(::testing::_)) .WillByDefault(::testing::Invoke( - [&](std::vector &edidVec2) { + [this](std::vector &edidVec2) { + m_activeThreadCalls++; edidVec2 = createLGTVEdidBytes(); + m_activeThreadCalls--; })); ON_CALL(*p_hostImplMock, getDefaultVideoPortName()) @@ -1853,8 +1899,10 @@ TEST_F(HdmiCecSourceInitializedEventTest, giveDeviceVendorIdProcess_LGTV){ ON_CALL(*p_displayMock, getEDIDBytes(::testing::_)) .WillByDefault(::testing::Invoke( - [&](std::vector &edidVec2) { + [this](std::vector &edidVec2) { + m_activeThreadCalls++; edidVec2 = createLGTVEdidBytes(); + m_activeThreadCalls--; })); ON_CALL(*p_hostImplMock, getDefaultVideoPortName()) diff --git a/Tests/L2Tests/tests/HdmiCecSink_L2Test.cpp b/Tests/L2Tests/tests/HdmiCecSink_L2Test.cpp index d73e47b1e..fdeaf0697 100644 --- a/Tests/L2Tests/tests/HdmiCecSink_L2Test.cpp +++ b/Tests/L2Tests/tests/HdmiCecSink_L2Test.cpp @@ -277,6 +277,8 @@ class HdmiCecSinkNotificationHandler : public Exchange::IHdmiCecSink::INotificat } } signalled = m_event_signalled; + // Clear only the expected flags that were waited for, not all flags + m_event_signalled &= ~expected_status; return signalled; } }; @@ -311,6 +313,7 @@ class HdmiCecSink_L2Test : public L2TestMocks { protected: HdmiCecSink_L2Test(); virtual ~HdmiCecSink_L2Test() override; + virtual void SetUp() override; public: uint32_t CreateHdmiCecSinkInterfaceObject(); @@ -496,6 +499,13 @@ HdmiCecSink_L2Test::HdmiCecSink_L2Test() EXPECT_EQ(Core::ERROR_NONE, status); } +void HdmiCecSink_L2Test::SetUp() +{ + // Reset all event flags before each test to prevent race conditions from stale flags + std::unique_lock lock(m_mutex); + m_event_signalled = HDMICECSINK_STATUS_INVALID; +} + HdmiCecSink_L2Test::~HdmiCecSink_L2Test() { uint32_t status = Core::ERROR_GENERAL; @@ -526,6 +536,7 @@ HdmiCecSink_L2Test::~HdmiCecSink_L2Test() class HdmiCecSink_L2Test_STANDBY : public L2TestMocks { protected: HdmiCecSink_L2Test_STANDBY(); + virtual void SetUp() override; virtual ~HdmiCecSink_L2Test_STANDBY() override; public: @@ -708,6 +719,13 @@ HdmiCecSink_L2Test_STANDBY::~HdmiCecSink_L2Test_STANDBY() removeFile("/opt/uimgr_settings.bin"); } +void HdmiCecSink_L2Test_STANDBY::SetUp() +{ + // Reset all event flags before each test to prevent race conditions from stale flags + std::unique_lock lock(m_mutex); + m_event_signalled = HDMICECSINK_STATUS_INVALID; +} + void HdmiCecSink_L2Test::arcInitiationEvent(const JsonObject& message) { TEST_LOG("arcInitiation event triggered ***\n"); From 00b481bd2f8e5808ddeae128f4aec5acd4c0d22b Mon Sep 17 00:00:00 2001 From: GitHub Actions <187267378+rdkcm-rdke@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:52:17 +0000 Subject: [PATCH 4/4] 1.11.0 release changelog updates --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be49840d7..fa5458669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,17 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [1.11.0](https://github.com/rdkcentral/entservices-inputoutput/compare/1.10.3...1.11.0) + +- RDKEMW-10832 : Intermittent failure on testframework while running entservices-inputoutput workflow [`#293`](https://github.com/rdkcentral/entservices-inputoutput/pull/293) +- Merge tag '1.10.3' into develop [`eb4921e`](https://github.com/rdkcentral/entservices-inputoutput/commit/eb4921e4724d9367e4a3f78edecf62b3ced97042) + #### [1.10.3](https://github.com/rdkcentral/entservices-inputoutput/compare/1.10.2...1.10.3) +> 28 January 2026 + - RDKEMW-11398: Implement HdmiCecSink & UserSettings communication. [`#342`](https://github.com/rdkcentral/entservices-inputoutput/pull/342) +- 1.10.3 release changelog updates [`217e33a`](https://github.com/rdkcentral/entservices-inputoutput/commit/217e33a7333aacf33134d7cb469dc8f0106a784b) - Merge tag '1.10.2' into develop [`e22d4a8`](https://github.com/rdkcentral/entservices-inputoutput/commit/e22d4a8db483fc7f6dbfeb67a43e207830ff7905) #### [1.10.2](https://github.com/rdkcentral/entservices-inputoutput/compare/1.10.1...1.10.2)