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/CHANGELOG.md b/CHANGELOG.md index 87ff36e9c..fa5458669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,25 @@ 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) +> 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) 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; 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");