add pkgmgr plugin
authorYoungjae Shin <yj99.shin@samsung.com>
Fri, 30 Aug 2019 01:58:36 +0000 (10:58 +0900)
committerYoungjae Shin <yj99.shin@samsung.com>
Thu, 19 Mar 2020 04:30:19 +0000 (13:30 +0900)
13 files changed:
CMakeLists.txt
packaging/modes-plugins.spec
pkg/CMakeLists.txt [new file with mode: 0644]
pkg/PkgAction.cpp [new file with mode: 0644]
pkg/PkgAction.h [new file with mode: 0644]
pkg/PkgEnableSupportMode.cpp [new file with mode: 0644]
pkg/PkgEnableSupportMode.h [new file with mode: 0644]
pkg/PkgFactory.cpp [new file with mode: 0644]
pkg/PkgFactory.h [new file with mode: 0644]
pkg/PkgPlugin.cpp [new file with mode: 0644]
pkg/tizen_pkg_rule.xml [new file with mode: 0644]
unittests/CMakeLists.txt
unittests/mdsp_test_pkg.cpp [new file with mode: 0644]

index 26a3fb6..6f39fb7 100644 (file)
@@ -18,5 +18,6 @@ ENDIF(NOT DEFINED MODES_PLUGIN_DEFAULT_DIR)
 ADD_SUBDIRECTORY(wifi)
 ADD_SUBDIRECTORY(vconf)
 ADD_SUBDIRECTORY(app)
+ADD_SUBDIRECTORY(pkg)
 ADD_SUBDIRECTORY(bluetooth)
 ADD_SUBDIRECTORY(unittests)
index 6b0f6bb..9a7eddc 100644 (file)
@@ -22,6 +22,8 @@ BuildRequires: pkgconfig(capi-network-bluetooth)
 BuildRequires: pkgconfig(vconf)
 BuildRequires: pkgconfig(gmock)
 BuildRequires: pkgconfig(aul)
+BuildRequires: pkgconfig(pkgmgr)
+BuildRequires: pkgconfig(pkgmgr-info)
 
 %description
 Plugin Libraries for Mode Supervisor
@@ -71,7 +73,7 @@ xmllint --noout --schema %{modes_data_dir}/schema/tizen_action_rule.xsd %{buildr
 systemctl restart modes.service
 
 %post unittests
-%{modes_plugin_test_dir}/modes-gtest-app
+%{modes_plugin_test_dir}/modes-gtest-pkg
 %{modes_plugin_test_dir}/modes-gtest-vconf
 
 %postun -p /sbin/ldconfig
diff --git a/pkg/CMakeLists.txt b/pkg/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c4c363a
--- /dev/null
@@ -0,0 +1,13 @@
+SET(PKG_PLUGIN "modes-plugin-pkg")
+
+FILE(GLOB PKG_SRCS *.cpp)
+
+PKG_CHECK_MODULES(PKG_pkgs REQUIRED modes dlog capi-base-common capi-appfw-application capi-appfw-app-manager aul pkgmgr pkgmgr-info)
+INCLUDE_DIRECTORIES(${PKG_pkgs_INCLUDE_DIRS})
+LINK_DIRECTORIES(${PKG_pkgs_LIBRARY_DIRS})
+
+ADD_LIBRARY(${PKG_PLUGIN} SHARED ${PKG_SRCS})
+TARGET_LINK_LIBRARIES(${PKG_PLUGIN} ${PKG_pkgs_LIBRARIES})
+SET_TARGET_PROPERTIES(${PKG_PLUGIN} PROPERTIES NO_SONAME 1 )
+INSTALL(TARGETS ${PKG_PLUGIN} DESTINATION ${MODES_PLUGIN_DEFAULT_DIR})
+INSTALL(FILES tizen_pkg_rule.xml DESTINATION ${MODES_ACTIONRULE_DEFAULT_DIR})
diff --git a/pkg/PkgAction.cpp b/pkg/PkgAction.cpp
new file mode 100644 (file)
index 0000000..ccc03c5
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "PkgAction.h"
+#include <modes_errors.h>
+
+MODES_NAMESPACE_USE;
+
+PkgAction::PkgAction()
+{
+}
+
+PkgAction::~PkgAction()
+{
+}
+
+int PkgAction::set(int val)
+{
+       return MODES_ERROR_NOT_SUPPORTED;
+}
+
+int PkgAction::undo(int val)
+{
+       return MODES_ERROR_NOT_SUPPORTED;
+}
+
+int PkgAction::get(int *val)
+{
+       return MODES_ERROR_NOT_SUPPORTED;
+}
+
+void PkgAction::setName(std::string name)
+{
+       this->name = name;
+}
+
+std::string PkgAction::getName()
+{
+       return name;
+}
diff --git a/pkg/PkgAction.h b/pkg/PkgAction.h
new file mode 100644 (file)
index 0000000..8f2fc0e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+#pragma once
+
+#include <string>
+#include "plugin-def.h"
+
+MODES_NAMESPACE_BEGIN
+
+class PkgAction {
+public:
+       PkgAction();
+       virtual ~PkgAction();
+
+       std::string getName();
+       virtual int set(int val);
+       virtual int get(int *val);
+       virtual int undo(int val);
+
+protected:
+       void setName(std::string name);
+
+private:
+       std::string name;
+};
+
+MODES_NAMESPACE_END
+
diff --git a/pkg/PkgEnableSupportMode.cpp b/pkg/PkgEnableSupportMode.cpp
new file mode 100644 (file)
index 0000000..9a98ecb
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "PkgEnableSupportMode.h"
+#include <glib.h>
+#include <list>
+#include <string>
+#include <pkgmgr-info.h>
+#include <package-manager.h>
+#include <modes_errors.h>
+#include "plugin-log.h"
+
+MODES_NAMESPACE_USE;
+
+const std::string PkgStartSupportMode::NAME = "startSupportMode";
+int PkgStartSupportMode::appModeVal = 0;
+
+PkgStartSupportMode::PkgStartSupportMode()
+{
+       setName(NAME);
+}
+
+int PkgStartSupportMode::app_list_cb(const pkgmgrinfo_appinfo_h handle, void *userData)
+{
+       std::list<std::string> *appList = (std::list<std::string>*)userData;
+
+       int ret;
+       int appSupportMode = 0;
+       ret = pkgmgrinfo_appinfo_get_support_mode(handle, &appSupportMode);
+       if (PMINFO_R_OK != ret)
+               ERR("pkgmgrinfo_appinfo_get_support_mode() Fail");
+
+
+       if (appSupportMode != appModeVal) {
+               char *appid = NULL;
+               ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
+               if (PMINFO_R_OK != ret) {
+                       ERR("pkgmgrinfo_appinfo_get_appid() Fail");
+                       return 0;
+               }
+
+               appList->push_back(appid);
+       }
+       return 0;
+}
+
+int PkgStartSupportMode::set(int val)
+{
+       int ret;
+       pkgmgrinfo_appinfo_filter_h filter;
+
+       ret = pkgmgrinfo_appinfo_filter_create(&filter);
+       if (ret != PMINFO_R_OK)
+               return ret;
+
+       switch (val) {
+       case ULTRA_POWER_SAVING:
+               appModeVal = APP_SUPPORT_MODE_ULTRA_POWER_SAVING_VAL;
+               break;
+       case COOL_DOWN:
+               appModeVal = APP_SUPPORT_MODE_COOL_DOWN_VAL;
+               break;
+       case SCREEN_READER:
+               appModeVal = APP_SUPPORT_MODE_SCREEN_READER_VAL;
+               break;
+       default:
+               ERR("invalid Mode(%d)", val);
+               return MODES_ERROR_INVALID_PARAMETER;
+       }
+
+       pkgmgrinfo_appinfo_filter_foreach_appinfo(filter, app_list_cb, &appList);
+       pkgmgrinfo_appinfo_filter_destroy(filter);
+
+       int nApps = 0;
+       const char *appIDs[appList.size()];
+       for (auto it = appList.begin(); it != appList.end(); it++, nApps++) {
+               appIDs[nApps] = it->c_str();
+               DBG("Deactivate App(%s)", appIDs[nApps]);
+       }
+
+       pkgmgr_client *pc = pkgmgr_client_new(PC_REQUEST);
+
+       int reqId = pkgmgr_client_deactivate_apps(pc, appIDs, nApps, NULL, NULL);
+       DBG("Request id[%d] count[%d]", reqId, nApps);
+
+       pkgmgr_client_free(pc);
+
+       return MODES_ERROR_NONE;
+}
+
+int PkgStartSupportMode::get(int *val)
+{
+       if (val)
+               *val = appModeVal;
+
+       return MODES_ERROR_NONE;
+}
+
+
+int PkgStartSupportMode::undo(int val)
+{
+       //If the appList is empty, it will be ignored at subroutines.
+
+       int nApps = 0;
+       const char *appIDs[appList.size()];
+       for (auto it = appList.begin(); it != appList.end(); it++, nApps++) {
+               appIDs[nApps] = it->c_str();
+               DBG("Activate App(%s)", appIDs[nApps]);
+       }
+
+       pkgmgr_client *pc = pkgmgr_client_new(PC_REQUEST);
+
+       int reqId = pkgmgr_client_activate_apps(pc, appIDs, nApps, NULL, NULL);
+       WARN("Request id[%d] count[%d]", reqId, nApps);
+
+       pkgmgr_client_free(pc);
+
+       //The caller(Plugin undo function) includes destruction of this instance.
+       //Therefore, appList will be cleared by the destructor.
+
+       return MODES_ERROR_NONE;
+}
diff --git a/pkg/PkgEnableSupportMode.h b/pkg/PkgEnableSupportMode.h
new file mode 100644 (file)
index 0000000..b9d4f5c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+#pragma once
+
+#include <list>
+#include <string>
+#include <pkgmgr-info.h>
+#include "PkgAction.h"
+
+MODES_NAMESPACE_BEGIN
+
+class PkgStartSupportMode : public PkgAction {
+public:
+       PkgStartSupportMode();
+
+       virtual int set(int val) override;
+       virtual int get(int *val) override;
+       virtual int undo(int val) override;
+
+       static const std::string NAME;
+private:
+       enum AppSupportMode {
+               ULTRA_POWER_SAVING = 1,
+               COOL_DOWN = 2,
+               SCREEN_READER = 4
+       };
+
+       static int app_list_cb(const pkgmgrinfo_appinfo_h handle, void *user_data);
+       static int appModeVal;
+       std::list<std::string> appList;
+};
+
+MODES_NAMESPACE_END
diff --git a/pkg/PkgFactory.cpp b/pkg/PkgFactory.cpp
new file mode 100644 (file)
index 0000000..520f833
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 "PkgFactory.h"
+#include "plugin-log.h"
+#include "PkgEnableSupportMode.h"
+
+MODES_NAMESPACE_USE;
+
+std::map<std::string, PkgAction*> PkgFactory::savedActionMap;
+
+PkgFactory::PkgFactory()
+{
+       actionMap[PkgStartSupportMode::NAME] = PKG_ACT_STARTSUPPORTMODE;
+}
+
+PkgAction* PkgFactory::newStartSupportMode(const std::string &key, bool isUndo)
+{
+       auto it = savedActionMap.find(key);
+       if (it != savedActionMap.end()) {
+               if (isUndo) {
+                       DBG("savedAction(%s) exist", key.c_str());
+                       PkgAction *action = it->second;
+                       savedActionMap.erase(it);
+                       return action;
+               } else {
+                       ERR("savedAction(%s) exist", key.c_str());
+                       return nullptr;
+               }
+       } else {
+               if (isUndo) {
+                       ERR("No savedAction(%s)", key.c_str());
+                       return nullptr;
+               } else {
+                       PkgAction *action = new PkgStartSupportMode();
+                       savedActionMap[key] = action;
+                       return action;
+               }
+       }
+}
+
+PkgAction* PkgFactory::createAction(const std::string &key, bool isUndo)
+{
+       auto search = actionMap.find(key);
+       if (search == actionMap.end()) {
+               ERR("No PkgAction(%s)", key.c_str());
+               return nullptr;
+       }
+
+       PkgAction *action;
+       switch (search->second) {
+       case PKG_ACT_STARTSUPPORTMODE:
+               action = newStartSupportMode(key, isUndo);
+               break;
+       default:
+               action = nullptr;
+               break;
+       }
+
+       return action;
+}
+
+void PkgFactory::destroyAction(PkgAction *action)
+{
+       auto it = savedActionMap.find(action->getName());
+       if (it != savedActionMap.end()) {
+               if (action == it->second)
+                       DBG("savedAction(%s) exist", action->getName().c_str());
+               else
+                       ERR("Should not reach");
+       } else {
+               delete action;
+       }
+}
diff --git a/pkg/PkgFactory.h b/pkg/PkgFactory.h
new file mode 100644 (file)
index 0000000..fb251b0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+#pragma once
+
+#include <map>
+#include <string>
+#include "PkgAction.h"
+
+MODES_NAMESPACE_BEGIN
+
+class PkgFactory {
+public:
+       PkgFactory();
+       ~PkgFactory() = default;
+
+       PkgAction* createAction(const std::string &key, bool isUndo);
+       void destroyAction(PkgAction *action);
+private:
+       enum actionKey{
+               PKG_ACT_STARTSUPPORTMODE
+       };
+
+       PkgAction* newStartSupportMode(const std::string &key, bool isUndo);
+
+       std::map<std::string, enum actionKey> actionMap;
+       static std::map<std::string, PkgAction*> savedActionMap;
+};
+
+MODES_NAMESPACE_END
diff --git a/pkg/PkgPlugin.cpp b/pkg/PkgPlugin.cpp
new file mode 100644 (file)
index 0000000..0348319
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 pkglicable 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 <string>
+#include <modes_errors.h>
+#include <Plugin.h>
+#include "plugin-log.h"
+#include "PkgFactory.h"
+
+MODES_NAMESPACE_USE;
+
+class PkgPlugin : public Plugin {
+public:
+       PkgPlugin();
+       ~PkgPlugin();
+
+       int set(const std::string &key, int val, int *oldVal) override;
+       int undo(const std::string &key, int val) override;
+
+private:
+       PkgFactory pkgFactory;
+};
+
+extern "C" API Plugin *objectCreate(void)
+{
+       return new PkgPlugin;
+}
+
+extern "C" API void objectDelete(Plugin *plugin)
+{
+       delete plugin;
+}
+
+PkgPlugin::PkgPlugin()
+{
+       setName("pkg");
+}
+
+PkgPlugin::~PkgPlugin()
+{
+}
+
+int PkgPlugin::set(const std::string &key, int val, int *oldVal)
+{
+       PkgAction *action = pkgFactory.createAction(key, false);
+       RETVM_IF(nullptr == action, MODES_ERROR_INVALID_PARAMETER, "action(%s) is null", key.c_str());
+
+       DBG("set [%s, %d]", key.c_str(), val);
+
+       int ret = action->set(val);
+       if (oldVal)
+               action->get(oldVal);
+
+       pkgFactory.destroyAction(action);
+       return ret;
+}
+
+int PkgPlugin::undo(const std::string &key, int val)
+{
+       PkgAction *action = pkgFactory.createAction(key, true);
+       RETVM_IF(nullptr == action, MODES_ERROR_INVALID_PARAMETER, "action(%s) is null", key.c_str());
+
+       DBG("set [%s, %d]", key.c_str(), val);
+
+       int ret = action->undo(val);
+       pkgFactory.destroyAction(action);
+
+       return ret;
+}
diff --git a/pkg/tizen_pkg_rule.xml b/pkg/tizen_pkg_rule.xml
new file mode 100644 (file)
index 0000000..31aa414
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tizenModes xmlns="http://www.tizen.org" version="5.5">
+  <actionRule>
+    <rule name="pkg.startSupportMode" type="int" since="5.5" plugin="pkg">
+      <alias name="ULTRA_POWER_SAVING">1</alias>
+      <alias name="COOL_DOWN">2</alias>
+      <alias name="SCREEN_READER">4</alias>
+      <desc>Deactivate the applications which do not support the mode</desc>
+      <domain>App Framework</domain>
+    </rule>
+  </actionRule>
+</tizenModes>
index 4d3c274..7012093 100644 (file)
@@ -2,7 +2,9 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE")
 ADD_DEFINITIONS("-DMDS_TEST")
 
-pkg_check_modules(test_pkgs REQUIRED modes dlog capi-network-wifi-manager capi-network-bluetooth gmock capi-appfw-application vconf capi-appfw-app-manager aul)
+PKG_CHECK_MODULES(test_pkgs REQUIRED modes dlog gmock capi-network-wifi-manager capi-network-bluetooth vconf
+       capi-appfw-application capi-appfw-app-manager aul
+       pkgmgr pkgmgr-info)
 INCLUDE_DIRECTORIES(${test_pkgs_INCLUDE_DIRS})
 LINK_DIRECTORIES(${test_pkgs_LIBRARY_DIRS})
 
@@ -31,6 +33,15 @@ ADD_EXECUTABLE(${APP_PLUGIN_TEST} ${APP_SRCS})
 TARGET_LINK_LIBRARIES(${APP_PLUGIN_TEST} ${test_pkgs_LIBRARIES})
 INSTALL(TARGETS ${APP_PLUGIN_TEST} DESTINATION ${TEST_INSTALL_DIR})
 #===================================================================#
+SET(PKG_SRC_DIR "${CMAKE_SOURCE_DIR}/pkg" )
+SET(PKG_PLUGIN_TEST "modes-gtest-pkg")
+FILE(GLOB PKG_SRCS ${PKG_SRC_DIR}/*.cpp)
+SET(PKG_SRCS ${PKG_SRCS} "mdsp_test_pkg.cpp")
+
+ADD_EXECUTABLE(${PKG_PLUGIN_TEST} ${PKG_SRCS})
+TARGET_LINK_LIBRARIES(${PKG_PLUGIN_TEST} ${test_pkgs_LIBRARIES})
+INSTALL(TARGETS ${PKG_PLUGIN_TEST} DESTINATION ${TEST_INSTALL_DIR})
+#===================================================================#
 SET(VCONF_SRC_DIR "${CMAKE_SOURCE_DIR}/vconf" )
 SET(VCONF_PLUGIN_TEST "modes-gtest-vconf")
 FILE(GLOB VCONF_SRCS ${VCONF_SRC_DIR}/*.cpp)
diff --git a/unittests/mdsp_test_pkg.cpp b/unittests/mdsp_test_pkg.cpp
new file mode 100644 (file)
index 0000000..014f109
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <glib.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <Plugin.h>
+#include <modes_errors.h>
+#include "plugin-def.h"
+
+MODES_NAMESPACE_USE;
+
+extern "C" API Plugin *objectCreate(void);
+extern "C" API void objectDelete(Plugin *plugin);
+
+class PkgPluginTest : public ::testing::Test {
+protected:
+       void SetUp() override
+       {
+               loop = g_main_loop_new(NULL, FALSE);
+               plugin = objectCreate();
+       }
+
+       void TearDown() override
+       {
+               g_main_loop_unref(loop);
+               loop = NULL;
+               objectDelete(plugin);
+               plugin = NULL;
+       }
+
+       static gboolean pkgPluginTimeout(gpointer data)
+       {
+               Plugin *plugin = (Plugin *)data;
+               result = plugin->undo("startSupportMode", 1);
+               EXPECT_EQ(MODES_ERROR_NONE, result);
+               g_main_loop_quit(loop);
+
+               return G_SOURCE_REMOVE;
+       }
+
+       static gboolean pkgPluginIdler(gpointer data)
+       {
+               Plugin *plugin = (Plugin *)data;
+               result = plugin->set("startSupportMode", 1, nullptr);
+               EXPECT_EQ(MODES_ERROR_NONE, result);
+
+               g_timeout_add_seconds(5, pkgPluginTimeout, plugin);
+               return G_SOURCE_REMOVE;
+       }
+
+       static int result;
+       static GMainLoop *loop;
+       Plugin *plugin;
+};
+
+int PkgPluginTest::result = 0;
+GMainLoop *PkgPluginTest::loop = NULL;
+
+TEST_F(PkgPluginTest, setUndoTest)
+{
+       g_idle_add(pkgPluginIdler, plugin);
+       g_main_loop_run(loop);
+}
+
+int main(int argc, char **argv) {
+       testing::InitGoogleTest(&argc, argv);
+       return RUN_ALL_TESTS();
+}