diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..3767c828 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,271 @@ +# WPEFramework Plugin L2 Integration Tes - Use EXPECT_CALL for mocks with ::testing::_ for arguments unless a specific value is required for the test logic. + - Use only error codes defined in the implementation (e.g., Core::ERROR_NONE, Core::ERROR_GENERAL, Core::ERROR_INVALID_PARAMETER). Do not invent error codes. + - Ensure mock objects are properly initialized and cleaned up in the test fixture setup and teardown. + - Use EXPECT_TRUE, EXPECT_FALSE, and EXPECT_EQ to check returned, updated, or tested event values using the test fixture's initialization, notification flags, handlers, and helper methods. + - Test both successful integration scenarios and failure/error conditions in multi-plugin environments- Use real Thunder framework RPC stack for communication testing - Every test must verify end-to-end integration behavior, state changes across plugins, and event propagationing Guide + +### L2 Testing Objectives + +For specified APIs, ensure the generated L2 tests meet the following criteria: +- **Integration Testing**: Test complete plugin lifecycle and inter-component communication in realistic environments +- **Cross-Plugin Communication**: Validate interactions between multiple plugins and services +- **Asynchronous Event Testing**: Test notification systems, event propagation, and timing between plugins +- **Real System Integration**: Use actual plugin instances and system APIs rather than mocks + +## Testing +When generating L2 tests, please follow the below step-by-step approach: + +1. **Checking for Adequate Context and Information** + - Ensure that the test fixture, interface API header file, plugin implementation files, and related plugin dependencies are attached by the user for your reference. + - Verify understanding of cross-plugin communication patterns and dependencies. + +2. **Understanding the Plugin Integration** + - For each API/method, step through the complete integration flow: + - Map all plugin dependencies and inter-plugin communication paths + - Identify Thunder framework integration points (JSON-RPC and COM-RPC) + - Document asynchronous event flows and notification systems + - Note real system resources, IARM bus communications, and hardware interactions + - Before creating the tests, fully understand the complete plugin lifecycle and cross-plugin event propagation. + +3. **Test Coverage** + - For every cross-plugin interaction and integration scenario specified by the user, generate comprehensive test cases + - Test both JSON-RPC and COM-RPC communication protocols to ensure identical behavior + - Include full plugin activation, configuration, and cleanup testing + - Test asynchronous event handling with proper timing and condition variable usage + - Validate real system integration points and hardware abstraction layer interactions + - Do not summarize, skip, or instruct the user to extrapolate patterns. Every specified integration scenario must be tested explicitly. + +4. **Test Design** + - Test complete plugin integration rather than isolated functionality + - Use actual plugin instances instead of mocks for realistic testing + - Implement asynchronous event testing with WaitForRequestStatus and condition variables + - Test cross-plugin communication scenarios (e.g., UserPreferences ↔ UserSettings, SystemMode ↔ DisplaySettings) + - Use GTest syntax for test structure + - Write all tests as modifications to the existing test fixture file + - Use EXPECT_CALL for mocks with ::testing::_ for arguments unless a specific value is required for the test logic. + - Use only error codes defined in the implementation (e.g., Core::ERROR_NONE, Core::ERROR_GENERAL, Core::ERROR_INVALID_PARAMETER). Do not invent error codes. + - Ensure tests activate multiple services when testing plugin interactions + - Use actual IARM bus communication and device settings APIs where applicable + - Use EXPECT_TRUE, EXPECT_FALSE, and EXPECT_EQ to check returned, updated, or tested event values using the test fixture’s initialization, notification flags, handlers, and helper methods. + +5. **Format** + - Output only code, as if modifying the existing test fixture file + - Do not include explanations, summaries, or instructions + - Do not include comments like "repeat for other integrations" or "similarly for X" + - Do not include any code that is not a test for a specific integration scenario + +## Testing Example +Here are examples from the PowerManager L2 integration tests showing proper L2 test structure: + +**L2 Test Class Structure with Notification Handling:** +```cpp +class PowerManager_L2Test : public L2TestMocks { +public: + PowerManager_L2Test(); + virtual ~PowerManager_L2Test() override; + + void OnPowerModeChanged(const PowerState currentState, const PowerState newState); + void OnPowerModePreChange(const PowerState currentState, const PowerState newState, const int trxnId, const int stateChangeAfter); + void OnThermalModeChanged(const ThermalTemperature currentThermalLevel, const ThermalTemperature newThermalLevel, const float currentTemperature); + + uint32_t WaitForRequestStatus(uint32_t timeout_ms, PowerManagerL2test_async_events_t expected_status); + + Core::Sink mNotification; + +private: + std::mutex m_mutex; + std::condition_variable m_condition_variable; + uint32_t m_event_signalled; +}; +``` + +**Notification Interface Implementation:** +```cpp +class PwrMgr_Notification : public Exchange::IPowerManager::IRebootNotification, + public Exchange::IPowerManager::IModeChangedNotification, + public Exchange::IPowerManager::IThermalModeChangedNotification { + BEGIN_INTERFACE_MAP(PwrMgr_Notification) + INTERFACE_ENTRY(Exchange::IPowerManager::IRebootNotification) + INTERFACE_ENTRY(Exchange::IPowerManager::IModeChangedNotification) + INTERFACE_ENTRY(Exchange::IPowerManager::IThermalModeChangedNotification) + END_INTERFACE_MAP + +public: + void OnPowerModeChanged(const PowerState currentState, const PowerState newState) override { + std::unique_lock lock(m_mutex); + m_event_signalled |= POWERMANAGERL2TEST_SYSTEMSTATE_CHANGED; + m_condition_variable.notify_one(); + } + + uint32_t WaitForRequestStatus(uint32_t timeout_ms, PowerManagerL2test_async_events_t expected_status) { + std::unique_lock lock(m_mutex); + auto now = std::chrono::system_clock::now(); + std::chrono::milliseconds timeout(timeout_ms); + + while (!(expected_status & m_event_signalled)) { + if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { + return POWERMANAGERL2TEST_STATE_INVALID; + } + } + + uint32_t signalled = m_event_signalled; + m_event_signalled = POWERMANAGERL2TEST_STATE_INVALID; + return signalled; + } +}; +``` + +**Constructor with Plugin Activation and Mock Setup:** +```cpp +PowerManager_L2Test::PowerManager_L2Test() : L2TestMocks() { + m_event_signalled = POWERMANAGERL2TEST_STATE_INVALID; + + EXPECT_CALL(POWERMANAGER_MOCK, PLAT_DS_INIT()) + .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); + + EXPECT_CALL(POWERMANAGER_MOCK, PLAT_INIT()) + .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); + + EXPECT_CALL(*p_mfrMock, mfrSetTempThresholds(::testing::_, ::testing::_)) + .WillOnce(::testing::Invoke([](int high, int critical) { + EXPECT_EQ(high, 100); + EXPECT_EQ(critical, 110); + return mfrERR_NONE; + })); + + // Activate the actual plugin service + uint32_t status = ActivateService("org.rdk.PowerManager"); + EXPECT_EQ(Core::ERROR_NONE, status); +} +``` + +**Destructor with Plugin Cleanup:** +```cpp +PowerManager_L2Test::~PowerManager_L2Test() { + EXPECT_CALL(POWERMANAGER_MOCK, PLAT_TERM()) + .WillOnce(::testing::Return(PWRMGR_SUCCESS)); + + EXPECT_CALL(POWERMANAGER_MOCK, PLAT_DS_TERM()) + .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); + + uint32_t status = DeactivateService("org.rdk.PowerManager"); + EXPECT_EQ(Core::ERROR_NONE, status); +} +``` + +**COM-RPC Integration Test with Real Plugin Communication:** +```cpp +TEST_F(PowerManager_L2Test, PowerManagerComRpc) { + Core::ProxyType> mEngine_PowerManager; + Core::ProxyType mClient_PowerManager; + PluginHost::IShell *mController_PowerManager; + + mEngine_PowerManager = Core::ProxyType>::Create(); + mClient_PowerManager = Core::ProxyType::Create( + Core::NodeId("/tmp/communicator"), + Core::ProxyType(mEngine_PowerManager)); + + mEngine_PowerManager->Announcements(mClient_PowerManager->Announcement()); + + if (mClient_PowerManager.IsValid()) { + mController_PowerManager = mClient_PowerManager->Open("org.rdk.PowerManager"); + + if (mController_PowerManager) { + Exchange::IPowerManager* PowerManagerPlugin = mController_PowerManager->QueryInterface(); + + if (PowerManagerPlugin) { + PowerManagerPlugin->Register(&mNotification); + + Test_PowerStateChange(PowerManagerPlugin); + Test_TemperatureThresholds(PowerManagerPlugin); + Test_WakeupSrcConfig(PowerManagerPlugin); + Test_NetworkStandbyMode(PowerManagerPlugin); + + PowerManagerPlugin->Unregister(&mNotification); + PowerManagerPlugin->Release(); + } + mController_PowerManager->Release(); + } + mClient_PowerManager.Release(); + } +} +``` + +**Asynchronous Event Testing with State Verification:** +```cpp +void PowerManager_L2Test::Test_PowerStateChange(Exchange::IPowerManager* PowerManagerPlugin) { + uint32_t status = Core::ERROR_GENERAL; + uint32_t signalled = POWERMANAGERL2TEST_STATE_INVALID; + + PowerState currentState = PowerState::POWER_STATE_STANDBY; + const string standbyReason = ""; + int keyCode = KED_FP_POWER; + + // Set power state and wait for notification + status = PowerManagerPlugin->SetPowerState(keyCode, currentState, standbyReason); + EXPECT_EQ(status, Core::ERROR_NONE); + + // Wait for asynchronous event notification + signalled = mNotification.WaitForRequestStatus(JSON_TIMEOUT, POWERMANAGERL2TEST_SYSTEMSTATE_CHANGED); + EXPECT_TRUE(signalled & POWERMANAGERL2TEST_SYSTEMSTATE_CHANGED); + + // Verify state change through plugin interface + PowerState currentState1 = PowerState::POWER_STATE_UNKNOWN; + PowerState prevState1 = PowerState::POWER_STATE_UNKNOWN; + + status = PowerManagerPlugin->GetPowerState(currentState1, prevState1); + EXPECT_EQ(currentState1, currentState); + EXPECT_EQ(status, Core::ERROR_NONE); +} +``` + +**JSON-RPC Integration Test:** +```cpp +TEST_F(PowerManager_L2Test, JsonRpcWakeupSourceChange) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + JsonArray configs; + + JsonObject source; + source["wakeupSource"] = "WIFI"; + source["enabled"] = true; + configs.Add(source); + + params["wakeupSources"] = configs; + + EXPECT_CALL(POWERMANAGER_MOCK, PLAT_API_SetWakeupSrc(::testing::_, ::testing::_)) + .WillOnce(::testing::Invoke([](PWRMGR_WakeupSrcType_t wakeupSrc, bool enabled) { + EXPECT_EQ(wakeupSrc, PWRMGR_WAKEUPSRC_WIFI); + EXPECT_EQ(enabled, true); + return PWRMGR_SUCCESS; + })); + + status = InvokeServiceMethod("org.rdk.PowerManager.1.", "setWakeupSourceConfig", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} +``` + +**Cross-Plugin Integration Test with Multiple Services:** +```cpp +void PowerManager_L2Test::Test_NetworkStandbyMode(Exchange::IPowerManager* PowerManagerPlugin) { + uint32_t status = Core::ERROR_GENERAL; + uint32_t signalled = POWERMANAGERL2TEST_STATE_INVALID; + bool standbyMode = true; + + // Test setting network standby mode + status = PowerManagerPlugin->SetNetworkStandbyMode(standbyMode); + EXPECT_EQ(status, Core::ERROR_NONE); + + // Wait for notification event + signalled = mNotification.WaitForRequestStatus(JSON_TIMEOUT, POWERMANAGERL2TEST_NETWORK_STANDBYMODECHANGED); + EXPECT_TRUE(signalled & POWERMANAGERL2TEST_NETWORK_STANDBYMODECHANGED); + + // Verify state persistence + bool standbyMode1; + status = PowerManagerPlugin->GetNetworkStandbyMode(standbyMode1); + EXPECT_EQ(standbyMode, standbyMode1); + EXPECT_EQ(status, Core::ERROR_NONE); +} +``` + diff --git a/.github/workflows/L2-tests.yml b/.github/workflows/L2-tests.yml index 4e77ba75..0fa8ff7b 100755 --- a/.github/workflows/L2-tests.yml +++ b/.github/workflows/L2-tests.yml @@ -100,12 +100,19 @@ jobs: path: entservices-peripherals ref: develop + - name: Checkout entservices-deviceanddisplay + uses: actions/checkout@v3 + with: + repository: rdkcentral/entservices-deviceanddisplay + path: entservices-deviceanddisplay + ref: develop + - name: Checkout entservices-testframework uses: actions/checkout@v3 with: repository: rdkcentral/entservices-testframework path: entservices-testframework - ref: develop + ref: feature/RDKEMW-9479 token: ${{ secrets.RDKCM_RDKE }} - name: Checkout googletest @@ -309,7 +316,86 @@ jobs: cmake --build build/mocks -j8 && cmake --install build/mocks - + - name: Build entservices-deviceanddisplay + run: > + cmake + -S "$GITHUB_WORKSPACE/entservices-deviceanddisplay" + -B build/entservices-deviceanddisplay + -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" + -DCMAKE_INSTALL_PREFIX="$GITHUB_WORKSPACE/install/usr" + -DCMAKE_MODULE_PATH="$GITHUB_WORKSPACE/install/tools/cmake" + -DHIDE_NON_EXTERNAL_SYMBOLS=OFF + -DCMAKE_CXX_FLAGS=" + -DEXCEPTIONS_ENABLE=ON + -fprofile-arcs + -ftest-coverage + -DUSE_THUNDER_R4=ON + -DTHUNDER_VERSION=4 + -DTHUNDER_VERSION_MAJOR=4 + -DTHUNDER_VERSION_MINOR=4 + -DDEVICE_TYPE=AVOutputTV + -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" + -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/ds + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmbus + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/rdk/iarmmgrs-hal + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/headers/systemservices/proc + -I $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks + -I $GITHUB_WORKSPACE/install/usr/include + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/devicesettings.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Iarm.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Rfc.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/RBus.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Udev.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/Wraps.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/maintenanceMGR.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/pkg.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/secure_wrappermock.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/wpa_ctrl_mock.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/readprocMockInterface.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/btmgr.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tr181api.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettings.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvError.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsExtODM.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvSettingsODM.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/tvTypes.h + -include $GITHUB_WORKSPACE/entservices-testframework/Tests/mocks/essos-resmgr.h + -Wall -Wno-unused-result -Wno-deprecated-declarations -Wno-error=format= + -Wl,-wrap,system -Wl,-wrap,popen -Wl,-wrap,syslog -Wl,-wrap,v_secure_system -Wl,-wrap,v_secure_popen -Wl,-wrap,v_secure_pclose -Wl,-wrap,unlink + -DUSE_IARMBUS + -DENABLE_ERM + -DRDK_LOG_MILESTONE + -DRDK_SERVICE_L2_TEST + -DDISABLE_SECURITY_TOKEN + -DHAS_API_POWERSTATE + -DENABLE_THERMAL_PROTECTION" + -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/secure/persistent/rdkservicestore" + -DPLUGIN_PERSISTENTSTORE_LEGACYPATH="/tmp/persistent/rdkservicestore" + -DCOMCAST_CONFIG=OFF + -DCMAKE_DISABLE_FIND_PACKAGE_DS=ON + -DCMAKE_DISABLE_FIND_PACKAGE_IARMBus=ON + -DCMAKE_DISABLE_FIND_PACKAGE_Udev=ON + -DCMAKE_DISABLE_FIND_PACKAGE_RFC=ON + -DCMAKE_DISABLE_FIND_PACKAGE_RBus=ON + -DPLUGIN_SYSTEMSERVICES=OFF + -DPLUGIN_POWERMANAGER=ON + -DPLUGIN_DISPLAYSETTINGS=OFF + -DPLUGIN_USERPREFERENCES=OFF + -DPLUGIN_DEVICEDIAGNOSTICS=OFF + -DPLUGIN_WAREHOUSE=OFF + -DUSE_THUNDER_R4=ON + -DPLUGIN_L2Tests=ON + -DRDK_SERVICE_L2_TEST=ON + -DDS_FOUND=ON + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + && + cmake --build build/entservices-deviceanddisplay -j8 + && + cmake --install build/entservices-deviceanddisplay + - name: Build entservices-peripherals run: > cmake @@ -376,7 +462,7 @@ jobs: -DDS_FOUND=ON -DHAS_FRONT_PANEL=ON -DPLUGIN_LEDCONTROL=ON - -DPLUGIN_FRONTPANEL=OFF + -DPLUGIN_FRONTPANEL=ON -DPLUGIN_MOTION_DETECTION=ON -DRDK_SERVICE_L2_TEST=ON -DPLUGIN_L2Tests=ON @@ -454,7 +540,8 @@ jobs: -DDS_FOUND=ON -DHAS_FRONT_PANEL=ON -DPLUGIN_LEDCONTROL=ON - -DPLUGIN_FRONTPANEL=OFF + -DPLUGIN_FRONTPANEL=ON + -DPLUGIN_POWERMANAGER=ON -DPLUGIN_MOTION_DETECTION=ON -DRDK_SERVICE_L2_TEST=ON -DPLUGIN_L2Tests=ON diff --git a/FrontPanel/CMakeLists.txt b/FrontPanel/CMakeLists.txt index 3e40b42e..a3376857 100644 --- a/FrontPanel/CMakeLists.txt +++ b/FrontPanel/CMakeLists.txt @@ -41,6 +41,16 @@ set_target_properties(${PLUGIN_IMPLEMENTATION} PROPERTIES CXX_STANDARD_REQUIRED YES) set_source_files_properties(FrontPanel.cpp FrontPanelImplementation.cpp ../helpers/frontpanel.cpp PROPERTIES COMPILE_FLAGS "-fexceptions") +if (RDK_SERVICE_L2_TEST) + find_library(TESTMOCKLIB_LIBRARIES NAMES TestMocklib) + if (TESTMOCKLIB_LIBRARIES) + message ("linking mock libraries ${TESTMOCKLIB_LIBRARIES} library") + target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${TESTMOCKLIB_LIBRARIES}) + else (TESTMOCKLIB_LIBRARIES) + message ("Require ${TESTMOCKLIB_LIBRARIES} library") + endif (TESTMOCKLIB_LIBRARIES) +endif (RDK_SERVICES_L2_TEST) + target_compile_definitions(${MODULE_NAME} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) target_compile_definitions(${PLUGIN_IMPLEMENTATION} PRIVATE MODULE_NAME=Plugin_${PLUGIN_NAME}) diff --git a/FrontPanel/FrontPanel.cpp b/FrontPanel/FrontPanel.cpp index 0d79d02c..7026d52e 100644 --- a/FrontPanel/FrontPanel.cpp +++ b/FrontPanel/FrontPanel.cpp @@ -69,7 +69,7 @@ namespace WPEFramework { _frontPanel->Configure(service); Exchange::JFrontPanel::Register(*this, _frontPanel); - LOGINFO("HdmiCecSource plugin is available. Successfully activated FrontPanel Plugin"); + LOGINFO("FrontPanel plugin is available. Successfully activated FrontPanel Plugin"); } else { diff --git a/FrontPanel/FrontPanelImplementation.cpp b/FrontPanel/FrontPanelImplementation.cpp index 51d7080d..9a7a177f 100644 --- a/FrontPanel/FrontPanelImplementation.cpp +++ b/FrontPanel/FrontPanelImplementation.cpp @@ -159,7 +159,7 @@ namespace WPEFramework _powerManagerPlugin->Unregister(_pwrMgrNotification.baseInterface()); _powerManagerPlugin.Reset(); } - + LOGINFO("[%s]", __FUNCTION__); CFrontPanel::instance()->deinitialize(); _registeredEventHandlers = false; @@ -170,6 +170,7 @@ namespace WPEFramework Core::hresult FrontPanelImplementation::Configure(PluginHost::IShell* service) { + LOGINFO("[%s]", __FUNCTION__); InitializePowerManager(service); FrontPanelImplementation::_instance = this; CFrontPanel::instance(service); @@ -237,6 +238,7 @@ namespace WPEFramework } else if (brightness >= 0 && brightness <= 100) { + LOGINFO("[%s]", __FUNCTION__); LOGWARN("calling setBrightness"); ok = CFrontPanel::instance()->setBrightness(brightness); } @@ -283,6 +285,7 @@ namespace WPEFramework } else { + LOGINFO("[%s]", __FUNCTION__); LOGWARN("calling getBrightness"); value = CFrontPanel::instance()->getBrightness(); } @@ -319,6 +322,7 @@ namespace WPEFramework Core::hresult FrontPanelImplementation::PowerLedOff(const string& index, FrontPanelSuccess& success) { + LOGINFO("[%s]", __FUNCTION__); bool ok = false; if (index == DATA_LED) { ok = CFrontPanel::instance()->powerOffLed(FRONT_PANEL_INDICATOR_MESSAGE); @@ -437,6 +441,7 @@ namespace WPEFramework properties["green"] = green; properties["blue"] = blue; + LOGINFO("[%s]", __FUNCTION__); bool ok = CFrontPanel::instance()->setLED(properties); success.success = ok; return ok ? Core::ERROR_NONE : Core::ERROR_GENERAL; @@ -452,6 +457,7 @@ namespace WPEFramework */ void FrontPanelImplementation::setBlink(const JsonObject& blinkInfo) { + LOGINFO("[%s]", __FUNCTION__); CFrontPanel::instance()->setBlink(blinkInfo); } diff --git a/Tests/L2Tests/CMakeLists.txt b/Tests/L2Tests/CMakeLists.txt index 4c0c4cb4..1919ec9f 100755 --- a/Tests/L2Tests/CMakeLists.txt +++ b/Tests/L2Tests/CMakeLists.txt @@ -25,6 +25,10 @@ if(PLUGIN_LEDCONTROL) set(SRC_FILES ${SRC_FILES} tests/LedControl_L2Test.cpp) endif() +if(PLUGIN_FRONTPANEL) + set(SRC_FILES ${SRC_FILES} tests/FrontPanel_L2Test.cpp) +endif() + add_library(${MODULE_NAME} SHARED ${SRC_FILES}) set_target_properties(${MODULE_NAME} PROPERTIES diff --git a/Tests/L2Tests/tests/FrontPanel_L2Test.cpp b/Tests/L2Tests/tests/FrontPanel_L2Test.cpp new file mode 100644 index 00000000..d08eb59b --- /dev/null +++ b/Tests/L2Tests/tests/FrontPanel_L2Test.cpp @@ -0,0 +1,632 @@ +/** +* If not stated otherwise in this file or this component's LICENSE +* file the following copyright and licenses apply: +* +* Copyright 2024 RDK Management +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +**/ + +#include +#include +#include "L2Tests.h" +#include "L2TestsMock.h" +#include +#include +#include +#include +#include +#include "FrontPanelMock.h" +#include "PowerManagerMock.h" +#include "PowerManagerHalMock.h" +#include "frontpanel.h" +#include "frontpanel.cpp" + +#define TEST_LOG(x, ...) \ + fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); \ + fflush(stderr); + +#include "FrontPanelIndicatorMock.h" +#include "FrontPanelTextDisplayMock.h" +#include "FrontPanelConfigMock.h" +#include "ColorMock.h" +#include "IarmBusMock.h" + +// Device settings includes for proper mock setup +#include "frontPanelIndicator.hpp" +#include "frontPanelConfig.hpp" +#include "frontPanelTextDisplay.hpp" + +#define JSON_TIMEOUT (1000) +#define TEST_LOG(x, ...) fprintf(stderr, "\033[1;32m[%s:%d](%s)" x "\n\033[0m", __FILE__, __LINE__, __FUNCTION__, getpid(), gettid(), ##__VA_ARGS__); fflush(stderr); +#define FRONTPANEL_CALLSIGN _T("org.rdk.FrontPanel.1") +#define L2TEST_CALLSIGN _T("L2tests.1") + +using ::testing::NiceMock; +using namespace WPEFramework; +using testing::StrictMock; +using PowerState = WPEFramework::Exchange::IPowerManager::PowerState; + +typedef enum : uint32_t { + FRONTPANELL2TEST_BRIGHTNESS_CHANGED = 0x00000001, + FRONTPANELL2TEST_LED_STATE_CHANGED = 0x00000002, + FRONTPANELL2TEST_BLINK_COMPLETED = 0x00000004, + FRONTPANELL2TEST_POWER_STATE_CHANGED = 0x00000008, + FRONTPANELL2TEST_STATE_INVALID = 0x00000000 +} FrontPanelL2test_async_events_t; + +class FrontPanel_Notification : public Exchange::IPowerManager::IModeChangedNotification { + private: + std::mutex m_mutex; + std::condition_variable m_condition_variable; + uint32_t m_event_signalled; + + BEGIN_INTERFACE_MAP(FrontPanel_Notification) + INTERFACE_ENTRY(Exchange::IPowerManager::IModeChangedNotification) + END_INTERFACE_MAP + + public: + FrontPanel_Notification() : m_event_signalled(FRONTPANELL2TEST_STATE_INVALID) {} + ~FrontPanel_Notification() {} + + void OnPowerModeChanged(const PowerState currentState, const PowerState newState) override { + TEST_LOG("OnPowerModeChanged event triggered ***\n"); + std::unique_lock lock(m_mutex); + TEST_LOG("OnPowerModeChanged currentState: %u, newState: %u\n", currentState, newState); + m_event_signalled |= FRONTPANELL2TEST_POWER_STATE_CHANGED; + m_condition_variable.notify_one(); + } + + uint32_t WaitForRequestStatus(uint32_t timeout_ms, FrontPanelL2test_async_events_t expected_status) { + std::unique_lock lock(m_mutex); + auto now = std::chrono::system_clock::now(); + std::chrono::milliseconds timeout(timeout_ms); + + while (!(expected_status & m_event_signalled)) { + if (m_condition_variable.wait_until(lock, now + timeout) == std::cv_status::timeout) { + return FRONTPANELL2TEST_STATE_INVALID; + } + } + + uint32_t signalled = m_event_signalled; + m_event_signalled = FRONTPANELL2TEST_STATE_INVALID; + return signalled; + } +}; + +/* FrontPanel L2 test class declaration */ +class FrontPanel_L2Test : public L2TestMocks { +protected: + PluginHost::IShell* m_controller_FrontPanel; + Exchange::IFrontPanel* m_frontPanelPlugin; + + // Device settings mocks + IarmBusImplMock* p_iarmBusImplMock; + FrontPanelConfigMock* p_frontPanelConfigImplMock; + FrontPanelTextDisplayMock* p_frontPanelTextDisplayMock; + ColorMock* p_colorImplMock; + testing::NiceMock frontPanelIndicatorMock; + testing::NiceMock frontPanelTextDisplayIndicatorMock; + +public: + FrontPanel_L2Test(); + virtual ~FrontPanel_L2Test() override; + + uint32_t CreateDeviceFrontPanelInterfaceObject(); + + void Test_SetGetBrightness(Exchange::IFrontPanel* FrontPanelPlugin); + void Test_PowerLedOnOff(Exchange::IFrontPanel* FrontPanelPlugin); + void Test_GetFrontPanelLights(Exchange::IFrontPanel* FrontPanelPlugin); + void Test_SetLED(Exchange::IFrontPanel* FrontPanelPlugin); + void Test_PowerStateIntegration(Exchange::IFrontPanel* FrontPanelPlugin, Exchange::IPowerManager* PowerManagerPlugin); + + Core::Sink mNotification; + +private: + std::mutex m_mutex; + std::condition_variable m_condition_variable; + uint32_t m_event_signalled; +}; + +/** + * @brief Constructor for FrontPanel L2 test class + */ +FrontPanel_L2Test::FrontPanel_L2Test() + : L2TestMocks() + , m_controller_FrontPanel(nullptr) + , m_frontPanelPlugin(nullptr) + , p_iarmBusImplMock(nullptr) + , p_frontPanelConfigImplMock(nullptr) + , p_frontPanelTextDisplayMock(nullptr) + , p_colorImplMock(nullptr) + , m_event_signalled(FRONTPANELL2TEST_STATE_INVALID) { + + uint32_t status = Core::ERROR_GENERAL; + + // Reset all mocks to nullptr first to avoid assertion failures + IarmBus::setImpl(nullptr); + device::FrontPanelConfig::setImpl(nullptr); + device::FrontPanelTextDisplay::setImpl(nullptr); + device::FrontPanelIndicator::Color::setImpl(nullptr); + + // Set up device settings mocks + p_iarmBusImplMock = new testing::NiceMock; + IarmBus::setImpl(p_iarmBusImplMock); + + p_frontPanelConfigImplMock = new testing::NiceMock; + device::FrontPanelConfig::setImpl(p_frontPanelConfigImplMock); + + device::FrontPanelIndicator::getInstance().impl = &frontPanelIndicatorMock; + device::FrontPanelTextDisplay::getInstance().FrontPanelIndicator::impl = &frontPanelTextDisplayIndicatorMock; + + p_frontPanelTextDisplayMock = new testing::NiceMock; + device::FrontPanelTextDisplay::setImpl(p_frontPanelTextDisplayMock); + + p_colorImplMock = new testing::NiceMock; + device::FrontPanelIndicator::Color::setImpl(p_colorImplMock); + + // Set up ColorMock expectations to match L1 tests + ON_CALL(*p_colorImplMock, getName()) + .WillByDefault(::testing::Return("White")); + + ON_CALL(*p_colorImplMock, getInstanceByName(::testing::_)) + .WillByDefault(::testing::Invoke([](const std::string& name) { + (void)name; + return device::FrontPanelIndicator::Color::getInstance(); + })); + + // Set up basic mock expectations that are needed for plugin initialization + ON_CALL(frontPanelIndicatorMock, getInstanceString(::testing::_)) + .WillByDefault(::testing::Invoke( + [&](const std::string& name) -> device::FrontPanelIndicator& { + return device::FrontPanelIndicator::getInstance(); + })); + + ON_CALL(frontPanelIndicatorMock, getInstanceInt(::testing::_)) + .WillByDefault(::testing::Invoke( + [&](int id) -> device::FrontPanelIndicator& { + return device::FrontPanelIndicator::getInstance(); + })); + + ON_CALL(*p_frontPanelConfigImplMock, getIndicators()) + .WillByDefault(::testing::Return(device::List({ device::FrontPanelIndicator::getInstance() }))); + + ON_CALL(*p_frontPanelConfigImplMock, getTextDisplays()) + .WillByDefault(::testing::Return(device::List({ device::FrontPanelTextDisplay::getInstance() }))); + + ON_CALL(frontPanelTextDisplayIndicatorMock, getName()) + .WillByDefault(::testing::Return("Text")); + + ON_CALL(*p_frontPanelConfigImplMock, getTextDisplay(::testing::Matcher(::testing::_))) + .WillByDefault(::testing::ReturnRef(device::FrontPanelTextDisplay::getInstance())); + + ON_CALL(*p_frontPanelConfigImplMock, getTextDisplay(::testing::Matcher(::testing::_))) + .WillByDefault(::testing::ReturnRef(device::FrontPanelTextDisplay::getInstance())); + + ON_CALL(*p_frontPanelConfigImplMock, getTextDisplay()) + .WillByDefault(::testing::ReturnRef(device::FrontPanelTextDisplay::getInstance())); + + ON_CALL(frontPanelIndicatorMock, getBrightness(::testing::_)) + .WillByDefault(::testing::Return(100)); + + ON_CALL(frontPanelIndicatorMock, setBrightness(::testing::_, ::testing::_)) + .WillByDefault(::testing::Return()); + + ON_CALL(frontPanelIndicatorMock, setState(::testing::_)) + .WillByDefault(::testing::Return()); + + ON_CALL(frontPanelIndicatorMock, getName()) + .WillByDefault(::testing::Return("Power")); + + ON_CALL(frontPanelIndicatorMock, getBrightnessLevels(::testing::_, ::testing::_, ::testing::_)) + .WillByDefault(::testing::Invoke([](int& levels, int& min, int& max) { + levels = 100; min = 0; max = 100; + })); + + ON_CALL(frontPanelIndicatorMock, getSupportedColors()) + .WillByDefault(::testing::Return(device::List())); + + ON_CALL(frontPanelIndicatorMock, getColorMode()) + .WillByDefault(::testing::Return(0)); + + // Set up IARM Bus mock expectations for basic functionality + ON_CALL(*p_iarmBusImplMock, IARM_Bus_Connect()) + .WillByDefault(::testing::Return(IARM_RESULT_SUCCESS)); + + ON_CALL(*p_iarmBusImplMock, IARM_Bus_Init(::testing::_)) + .WillByDefault(::testing::Return(IARM_RESULT_SUCCESS)); + + ON_CALL(*p_iarmBusImplMock, IARM_Bus_RegisterEventHandler(::testing::_, ::testing::_, ::testing::_)) + .WillByDefault(::testing::Return(IARM_RESULT_SUCCESS)); + + ON_CALL(*p_iarmBusImplMock, IARM_Bus_UnRegisterEventHandler(::testing::_, ::testing::_)) + .WillByDefault(::testing::Return(IARM_RESULT_SUCCESS)); + + // Additional mock for color operations that might be needed + ON_CALL(frontPanelIndicatorMock, setColor(::testing::_, ::testing::_)) + .WillByDefault(::testing::Return()); + + ON_CALL(frontPanelIndicatorMock, setColorInt(::testing::_, ::testing::_)) + .WillByDefault(::testing::Return()); + + ON_CALL(frontPanelIndicatorMock, getColorName()) + .WillByDefault(::testing::Return("red")); + + EXPECT_CALL(*p_powerManagerHalMock, PLAT_DS_INIT()) + .WillOnce(::testing::Return(DEEPSLEEPMGR_SUCCESS)); + + EXPECT_CALL(*p_powerManagerHalMock, PLAT_INIT()) + .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); + + EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetWakeupSrc(::testing::_, ::testing::_)) + .WillRepeatedly(::testing::Return(PWRMGR_SUCCESS)); + + EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_GetPowerState(::testing::_)) + .WillRepeatedly(::testing::Invoke( + [](PWRMgr_PowerState_t* powerState) { + *powerState = PWRMGR_POWERSTATE_OFF; // by default over boot up, return PowerState OFF + return PWRMGR_SUCCESS; + })); + + EXPECT_CALL(*p_powerManagerHalMock, PLAT_API_SetPowerState(::testing::_)) + .WillRepeatedly(::testing::Invoke( + [](PWRMgr_PowerState_t powerState) { + // All tests are run without settings file + // so default expected power state is ON + return PWRMGR_SUCCESS; + })); + + // Activate PowerManager service first since FrontPanel depends on it + status = ActivateService("org.rdk.PowerManager"); + EXPECT_EQ(Core::ERROR_NONE, status); + + // Activate the actual FrontPanel plugin service + status = ActivateService("org.rdk.FrontPanel"); + EXPECT_EQ(Core::ERROR_NONE, status); + +} + +/** + * @brief Destructor for FrontPanel L2 test class + */ +FrontPanel_L2Test::~FrontPanel_L2Test() { + + uint32_t status = Core::ERROR_GENERAL; + + if (m_frontPanelPlugin) { + m_frontPanelPlugin->Release(); + m_frontPanelPlugin = nullptr; + } + + if (m_controller_FrontPanel) { + m_controller_FrontPanel->Release(); + m_controller_FrontPanel = nullptr; + } + + // Allow time for timer callbacks to complete before deactivating services + usleep(200000); + + // Deactivate FrontPanel service first + status = DeactivateService("org.rdk.FrontPanel"); + EXPECT_EQ(Core::ERROR_NONE, status); + + // Deactivate PowerManager service after FrontPanel + status = DeactivateService("org.rdk.PowerManager"); + + // Clean up device settings mocks + device::FrontPanelIndicator::getInstance().impl = nullptr; + device::FrontPanelTextDisplay::getInstance().FrontPanelIndicator::impl = nullptr; + + IarmBus::setImpl(nullptr); + if (p_iarmBusImplMock != nullptr) { + delete p_iarmBusImplMock; + p_iarmBusImplMock = nullptr; + } + + device::FrontPanelTextDisplay::setImpl(nullptr); + if (p_frontPanelTextDisplayMock != nullptr) { + delete p_frontPanelTextDisplayMock; + p_frontPanelTextDisplayMock = nullptr; + } + + device::FrontPanelConfig::setImpl(nullptr); + if (p_frontPanelConfigImplMock != nullptr) { + delete p_frontPanelConfigImplMock; + p_frontPanelConfigImplMock = nullptr; + } + + device::FrontPanelIndicator::Color::setImpl(nullptr); + if (p_colorImplMock != nullptr) { + delete p_colorImplMock; + p_colorImplMock = nullptr; + } + + // Clear CFrontPanel static variables like L1 tests do + //Plugin::CFrontPanel::initDone = 0; +} + +uint32_t FrontPanel_L2Test::CreateDeviceFrontPanelInterfaceObject() { + uint32_t return_value = Core::ERROR_GENERAL; + Core::ProxyType> FrontPanel_Engine; + Core::ProxyType FrontPanel_Client; + + TEST_LOG("Creating FrontPanel_Engine"); + FrontPanel_Engine = Core::ProxyType>::Create(); + FrontPanel_Client = Core::ProxyType::Create(Core::NodeId("/tmp/communicator"), Core::ProxyType(FrontPanel_Engine)); + + TEST_LOG("Creating FrontPanel_Engine Announcements"); +#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) + FrontPanel_Engine->Announcements(FrontPanel_Client->Announcement()); +#endif + if (!FrontPanel_Client.IsValid()) { + TEST_LOG("Invalid FrontPanel_Client"); + } else { + m_controller_FrontPanel = FrontPanel_Client->Open(_T("org.rdk.FrontPanel"), ~0, 3000); + if (m_controller_FrontPanel) { + m_frontPanelPlugin = m_controller_FrontPanel->QueryInterface(); + return_value = Core::ERROR_NONE; + } + } + return return_value; +} + +/* COM-RPC tests */ +void FrontPanel_L2Test::Test_SetGetBrightness(Exchange::IFrontPanel* FrontPanelPlugin) { + uint32_t status = Core::ERROR_GENERAL; + uint32_t brightness = 75; + uint32_t retrievedBrightness = 0; + bool success = false; + string index = "power_led"; + + TEST_LOG("\n################## Running Test_SetGetBrightness Test #################\n"); + + // Add mock expectations for device settings calls + EXPECT_CALL(frontPanelIndicatorMock, setBrightness(brightness, ::testing::_)) + .Times(::testing::AtLeast(0)); + + EXPECT_CALL(frontPanelIndicatorMock, getBrightness(::testing::_)) + .WillRepeatedly(::testing::Return(brightness)); + + Exchange::IFrontPanel::FrontPanelSuccess fpSuccess; + status = FrontPanelPlugin->SetBrightness(index, brightness, fpSuccess); + EXPECT_EQ(status, Core::ERROR_NONE); + + status = FrontPanelPlugin->GetBrightness(index, retrievedBrightness, success); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +void FrontPanel_L2Test::Test_PowerLedOnOff(Exchange::IFrontPanel* FrontPanelPlugin) { + uint32_t status = Core::ERROR_GENERAL; + string index = "power_led"; + Exchange::IFrontPanel::FrontPanelSuccess fpSuccess; + + TEST_LOG("\n################## Running Test_PowerLedOnOff Test #################\n"); + + // Add mock expectations for device settings calls + EXPECT_CALL(frontPanelIndicatorMock, setState(true)) + .Times(::testing::AtLeast(0)); + + EXPECT_CALL(frontPanelIndicatorMock, setState(false)) + .Times(::testing::AtLeast(0)); + + status = FrontPanelPlugin->PowerLedOn(index, fpSuccess); + EXPECT_EQ(status, Core::ERROR_NONE); + + status = FrontPanelPlugin->PowerLedOff(index, fpSuccess); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +void FrontPanel_L2Test::Test_GetFrontPanelLights(Exchange::IFrontPanel* FrontPanelPlugin) { + uint32_t status = Core::ERROR_GENERAL; + Exchange::IFrontPanel::IFrontPanelLightsListIterator* supportedLights = nullptr; + string supportedLightsInfo; + bool success = false; + + TEST_LOG("\n################## Running Test_GetFrontPanelLights Test #################\n"); + + // Add mock expectations for device settings calls + EXPECT_CALL(*p_frontPanelConfigImplMock, getIndicators()) + .WillRepeatedly(::testing::Return(device::List({ device::FrontPanelIndicator::getInstance() }))); + + EXPECT_CALL(frontPanelIndicatorMock, getBrightnessLevels(::testing::_, ::testing::_, ::testing::_)) + .Times(::testing::AtLeast(0)) + .WillRepeatedly(::testing::Invoke([](int& levels, int& min, int& max) { + levels = 100; min = 0; max = 100; + })); + + EXPECT_CALL(frontPanelIndicatorMock, getSupportedColors()) + .Times(::testing::AtLeast(0)) + .WillRepeatedly(::testing::Return(device::List())); + + status = FrontPanelPlugin->GetFrontPanelLights(supportedLights, supportedLightsInfo, success); + EXPECT_EQ(status, Core::ERROR_NONE); + + if (supportedLights) { + supportedLights->Release(); + } +} + +void FrontPanel_L2Test::Test_SetLED(Exchange::IFrontPanel* FrontPanelPlugin) { + uint32_t status = Core::ERROR_GENERAL; + string ledIndicator = "power_led"; + uint32_t brightness = 80; + string color = "blue"; + uint32_t red = 0, green = 0, blue = 255; + Exchange::IFrontPanel::FrontPanelSuccess fpSuccess; + + TEST_LOG("\n################## Running Test_SetLED Test #################\n"); + + // Add mock expectations for device settings calls + EXPECT_CALL(frontPanelIndicatorMock, setBrightness(::testing::_, ::testing::_)) + .Times(::testing::AtLeast(0)); + + EXPECT_CALL(frontPanelIndicatorMock, setColorInt(::testing::_, ::testing::_)) + .Times(::testing::AtLeast(0)); + + status = FrontPanelPlugin->SetLED(ledIndicator, brightness, color, red, green, blue, fpSuccess); + EXPECT_EQ(status, Core::ERROR_NONE); +} + + +void FrontPanel_L2Test::Test_PowerStateIntegration(Exchange::IFrontPanel* FrontPanelPlugin, Exchange::IPowerManager* PowerManagerPlugin) { + uint32_t status = Core::ERROR_GENERAL; + PowerState newPowerState = PowerState::POWER_STATE_STANDBY; + const string standbyReason = ""; + int keyCode = 10; + + TEST_LOG("\n################## Running Test_PowerStateIntegration Test #################\n"); + + if (PowerManagerPlugin) { + // Set power state through PowerManager + status = PowerManagerPlugin->SetPowerState(keyCode, newPowerState, standbyReason); + EXPECT_EQ(status, Core::ERROR_NONE); + } + + // Verify FrontPanel responds to power state change + Exchange::IFrontPanel::FrontPanelSuccess fpSuccess; + status = FrontPanelPlugin->PowerLedOff("power_led", fpSuccess); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +TEST_F(FrontPanel_L2Test, FrontPanelComRpc) { + uint32_t status = Core::ERROR_GENERAL; + + status = CreateDeviceFrontPanelInterfaceObject(); + EXPECT_EQ(Core::ERROR_NONE, status); + + if (m_frontPanelPlugin) { + Test_SetGetBrightness(m_frontPanelPlugin); + Test_PowerLedOnOff(m_frontPanelPlugin); + Test_GetFrontPanelLights(m_frontPanelPlugin); + Test_SetLED(m_frontPanelPlugin); + } +} + +TEST_F(FrontPanel_L2Test, CrossPluginIntegration) { + Core::ProxyType> mEngine_FrontPanel; + Core::ProxyType mClient_FrontPanel; + PluginHost::IShell *mController_FrontPanel; + + Core::ProxyType> mEngine_PowerManager; + Core::ProxyType mClient_PowerManager; + PluginHost::IShell *mController_PowerManager; + + TEST_LOG("Creating RPC engines for cross-plugin test"); + mEngine_FrontPanel = Core::ProxyType>::Create(); + mClient_FrontPanel = Core::ProxyType::Create( + Core::NodeId("/tmp/communicator"), + Core::ProxyType(mEngine_FrontPanel)); + + mEngine_PowerManager = Core::ProxyType>::Create(); + mClient_PowerManager = Core::ProxyType::Create( + Core::NodeId("/tmp/communicator2"), + Core::ProxyType(mEngine_PowerManager)); + +#if ((THUNDER_VERSION == 2) || ((THUNDER_VERSION == 4) && (THUNDER_VERSION_MINOR == 2))) + mEngine_FrontPanel->Announcements(mClient_FrontPanel->Announcement()); + mEngine_PowerManager->Announcements(mClient_PowerManager->Announcement()); +#endif + + if (mClient_FrontPanel.IsValid() && mClient_PowerManager.IsValid()) { + mController_FrontPanel = mClient_FrontPanel->Open("org.rdk.FrontPanel"); + mController_PowerManager = mClient_PowerManager->Open("org.rdk.PowerManager"); + + if (mController_FrontPanel && mController_PowerManager) { + Exchange::IFrontPanel* FrontPanelPlugin = mController_FrontPanel->QueryInterface(); + Exchange::IPowerManager* PowerManagerPlugin = mController_PowerManager->QueryInterface(); + + if (FrontPanelPlugin && PowerManagerPlugin) { + Test_PowerStateIntegration(FrontPanelPlugin, PowerManagerPlugin); + + FrontPanelPlugin->Release(); + PowerManagerPlugin->Release(); + } + + if (mController_FrontPanel) mController_FrontPanel->Release(); + if (mController_PowerManager) mController_PowerManager->Release(); + } + + mClient_FrontPanel.Release(); + mClient_PowerManager.Release(); + } +} + +TEST_F(FrontPanel_L2Test, JsonRpcSetBrightness) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + + params["index"] = "power_led"; + params["brightness"] = 75; + + status = InvokeServiceMethod("org.rdk.FrontPanel.1.", "setBrightness", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +TEST_F(FrontPanel_L2Test, JsonRpcGetBrightness) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + + params["index"] = "power_led"; + + status = InvokeServiceMethod("org.rdk.FrontPanel.1.", "getBrightness", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +TEST_F(FrontPanel_L2Test, JsonRpcPowerLedOn) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + + params["index"] = "power_led"; + + status = InvokeServiceMethod("org.rdk.FrontPanel.1.", "powerLedOn", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +TEST_F(FrontPanel_L2Test, JsonRpcPowerLedOff) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + + params["index"] = "power_led"; + + status = InvokeServiceMethod("org.rdk.FrontPanel.1.", "powerLedOff", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +TEST_F(FrontPanel_L2Test, JsonRpcSetLED) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + + params["ledIndicator"] = "power_led"; + params["brightness"] = 80; + params["color"] = "blue"; + params["red"] = 0; + params["green"] = 0; + params["blue"] = 255; + + status = InvokeServiceMethod("org.rdk.FrontPanel.1.", "setLED", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} + +TEST_F(FrontPanel_L2Test, JsonRpcGetFrontPanelLights) { + uint32_t status = Core::ERROR_GENERAL; + JsonObject params; + JsonObject result; + + status = InvokeServiceMethod("org.rdk.FrontPanel.1.", "getFrontPanelLights", params, result); + EXPECT_EQ(status, Core::ERROR_NONE); +} \ No newline at end of file