Dbus API for "Display Off" signal 90/23090/5
authorLukasz Kostyra <l.kostyra@samsung.com>
Thu, 12 Jun 2014 13:31:19 +0000 (15:31 +0200)
committerLukasz Kostyra <l.kostyra@samsung.com>
Mon, 30 Jun 2014 06:47:55 +0000 (08:47 +0200)
[Feature]       - API in Dbus to handle "Display Off" signal.
                - Switching to default container when "Display Off" signal occurs.
[Cause]         SC must properly react when device is inactive for some time.
[Solution]      Create a Dbus API for Display Off signal. Use this event to switch to default
                container.
[Verification]  Build, install, run ContainersManagerSuite and ContainerConnectionSuite tests. Both
                suites should pass.

Change-Id: I34e0178cd9d8efbbdad92e1f2d69f4c32b41f779
Signed-off-by: Lukasz Kostyra <l.kostyra@samsung.com>
18 files changed:
server/configs/daemon.conf
server/container-connection.cpp
server/container-connection.hpp
server/container.cpp
server/container.hpp
server/containers-manager-config.hpp
server/containers-manager.cpp
server/containers-manager.hpp
server/fake-power-manager-dbus-definitions.hpp [new file with mode: 0644]
tests/unit_tests/server/configs/ut-containers-manager/buggy-daemon.conf
tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf [new file with mode: 0644]
tests/unit_tests/server/configs/ut-containers-manager/buggy-foreground-daemon.conf
tests/unit_tests/server/configs/ut-containers-manager/test-daemon.conf
tests/unit_tests/server/configs/ut-containers-manager/test-dbus-daemon.conf
tests/unit_tests/server/configs/ut-server/buggy-daemon.conf
tests/unit_tests/server/configs/ut-server/test-daemon.conf
tests/unit_tests/server/ut-container-connection.cpp
tests/unit_tests/server/ut-containers-manager.cpp

index 2610f5e..591e0b7 100644 (file)
@@ -1,6 +1,7 @@
 {
     "containerConfigs" : ["containers/private.conf", "containers/business.conf" ],
     "foregroundId" : "private",
+    "defaultId" : "private",
     "inputConfig" : {"enabled" : true,
                      "device" : "gpio-keys",
                      "code" : 139,
index 9f8a417..cf541f7 100644 (file)
@@ -27,6 +27,8 @@
 #include "container-connection.hpp"
 #include "container-dbus-definitions.hpp"
 #include "exception.hpp"
+// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager
+#include "fake-power-manager-dbus-definitions.hpp"
 
 #include "log/logger.hpp"
 
@@ -77,6 +79,16 @@ ContainerConnection::ContainerConnection(const std::string& address, const OnNam
                                               _3,
                                               _4,
                                               _5));
+
+    mDbusConnection->signalSubscribe(std::bind(&ContainerConnection::onSignalReceived,
+                                               this,
+                                               _1,
+                                               _2,
+                                               _3,
+                                               _4,
+                                               _5),
+                                     std::string(fake_power_manager_api::BUS_NAME));
+
     LOGD("Connected");
 }
 
@@ -123,6 +135,11 @@ void ContainerConnection::setNotifyActiveContainerCallback(
     mNotifyActiveContainerCallback = callback;
 }
 
+void ContainerConnection::setDisplayOffCallback(const DisplayOffCallback& callback)
+{
+    mDisplayOffCallback = callback;
+}
+
 void ContainerConnection::onMessageCall(const std::string& objectPath,
                                         const std::string& interface,
                                         const std::string& methodName,
@@ -144,6 +161,23 @@ void ContainerConnection::onMessageCall(const std::string& objectPath,
     }
 }
 
+void ContainerConnection::onSignalReceived(const std::string& senderBusName,
+                                           const std::string& objectPath,
+                                           const std::string& interface,
+                                           const std::string& signalName,
+                                           GVariant* /*parameters*/)
+{
+    LOGD("Received signal: " << senderBusName << "; " << objectPath << "; " << interface << "; "
+         << signalName);
+    if (objectPath == fake_power_manager_api::OBJECT_PATH &&
+        interface == fake_power_manager_api::INTERFACE) {
+        //power-manager sent us a signal, check it
+        if (signalName == fake_power_manager_api::SIGNAL_DISPLAY_OFF && mDisplayOffCallback) {
+            mDisplayOffCallback();
+        }
+    }
+}
+
 void ContainerConnection::sendNotification(const std::string& container,
                                            const std::string& application,
                                            const std::string& message)
index 4ddac0e..e0b2467 100644 (file)
@@ -39,6 +39,7 @@ class ContainerConnection {
 
 public:
     typedef std::function<void()> OnNameLostCallback;
+    typedef std::function<void()> DisplayOffCallback;
 
     ContainerConnection(const std::string& address, const OnNameLostCallback& callback);
     ~ContainerConnection();
@@ -55,6 +56,11 @@ public:
     void setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback);
 
     /**
+     * Register callback to handle turning off the display
+     */
+    void setDisplayOffCallback(const DisplayOffCallback& callback);
+
+    /**
      * Send notification signal to this container
      */
     void sendNotification(const std::string& container,
@@ -69,6 +75,7 @@ private:
     bool mNameLost;
     OnNameLostCallback mOnNameLostCallback;
     NotifyActiveContainerCallback mNotifyActiveContainerCallback;
+    DisplayOffCallback mDisplayOffCallback;
 
     void onNameAcquired();
     void onNameLost();
@@ -79,6 +86,11 @@ private:
                        const std::string& methodName,
                        GVariant* parameters,
                        dbus::MethodResultBuilder& result);
+    void onSignalReceived(const std::string& senderBusName,
+                          const std::string& objectPath,
+                          const std::string& interface,
+                          const std::string& signalName,
+                          GVariant* parameters);
 };
 
 
index cebdb55..2d7114f 100644 (file)
@@ -101,6 +101,10 @@ void Container::start()
     if (mNotifyCallback) {
         mConnection->setNotifyActiveContainerCallback(mNotifyCallback);
     }
+    if (mDisplayOffCallback) {
+        mConnection->setDisplayOffCallback(mDisplayOffCallback);
+    }
+
     // Send to the background only after we're connected,
     // otherwise it'd take ages.
     LOGD(getId() << ": DBUS connected, sending to the background");
@@ -218,4 +222,15 @@ void Container::sendNotification(const std::string& container,
     }
 }
 
+void Container::setDisplayOffCallback(const DisplayOffCallback& callback)
+{
+    Lock lock(mReconnectMutex);
+
+    mDisplayOffCallback = callback;
+    if (mConnection) {
+        mConnection->setDisplayOffCallback(callback);
+    }
+}
+
+
 } // namespace security_containers
index a30708f..5dbccad 100644 (file)
@@ -48,6 +48,7 @@ public:
     virtual ~Container();
 
     typedef ContainerConnection::NotifyActiveContainerCallback NotifyActiveContainerCallback;
+    typedef ContainerConnection::DisplayOffCallback DisplayOffCallback;
 
     /**
      * Get the container id
@@ -114,6 +115,11 @@ public:
     void setNotifyActiveContainerCallback(const NotifyActiveContainerCallback& callback);
 
     /**
+     * Register callback used when switching to default container.
+     */
+    void setDisplayOffCallback(const DisplayOffCallback& callback);
+
+    /**
      * Send notification signal to this container
      *
      * @param container   name of container in which the notification occurred
@@ -133,6 +139,7 @@ private:
     std::thread mReconnectThread;
     mutable std::recursive_mutex mReconnectMutex;
     NotifyActiveContainerCallback mNotifyCallback;
+    DisplayOffCallback mDisplayOffCallback;
 
     void onNameLostCallback();
     void reconnectHandler();
index f523479..9f881c1 100644 (file)
@@ -56,10 +56,16 @@ struct ContainersManagerConfig {
      */
     std::string foregroundId;
 
+    /**
+     * An ID of default container.
+     */
+    std::string defaultId;
+
     CONFIG_REGISTER
     (
         containerConfigs,
         foregroundId,
+        defaultId,
         inputConfig
     )
 };
index d26ac06..13ee3d4 100644 (file)
@@ -64,9 +64,21 @@ ContainersManager::ContainersManager(const std::string& managerConfigPath): mDet
                                                  id,
                                                  _1,
                                                  _2));
+
+        c->setDisplayOffCallback(bind(&ContainersManager::displayOffHandler,
+                                      this,
+                                      id));
+
         mContainers.insert(ContainerMap::value_type(id, std::move(c)));
     }
 
+    // check if default container exists, throw ContainerOperationException if not found
+    if (mContainers.find(mConfig.defaultId) == mContainers.end()) {
+        LOGE("Provided default container ID " << mConfig.defaultId << " is invalid.");
+        throw ContainerOperationException("Provided default container ID " + mConfig.defaultId +
+                                          " is invalid.");
+    }
+
     LOGD("ContainersManager object instantiated");
 
     if (mConfig.inputConfig.enabled) {
@@ -192,4 +204,10 @@ void ContainersManager::notifyActiveContainerHandler(const std::string& caller,
     }
 }
 
+void ContainersManager::displayOffHandler(const std::string& /*caller*/)
+{
+    LOGI("Switching to default container " << mConfig.defaultId);
+    focus(mConfig.defaultId);
+}
+
 } // namespace security_containers
index 7fa3382..316e7bb 100644 (file)
@@ -85,6 +85,7 @@ private:
     void notifyActiveContainerHandler(const std::string& caller,
                                       const std::string& appliaction,
                                       const std::string& message);
+    void displayOffHandler(const std::string& caller);
 };
 
 
diff --git a/server/fake-power-manager-dbus-definitions.hpp b/server/fake-power-manager-dbus-definitions.hpp
new file mode 100644 (file)
index 0000000..f24bc81
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Kostyra <l.kostyra@samsung.com>
+ *
+ *  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
+ */
+
+/**
+ * @file    fake-power-manager-dbus-definitions.h
+ * @author  Lukasz Kostyra (l.kostyra@samsung.com)
+ * @brief   Declaration of fake dbus definitions from power-manager. Made only to test API in
+ *          ContainerConnection.
+ */
+
+#ifndef FAKE_POWER_MANAGER_DBUS_DEFINITIONS_H
+#define FAKE_POWER_MANAGER_DBUS_DEFINITIONS_H
+
+/**
+ * !!WARNING!!
+ *
+ * This header file is created only to test if API in ContainerConnection works correctly. It should
+ * be removed when power-managers API will be created.
+ */
+
+namespace fake_power_manager_api
+{
+
+const std::string BUS_NAME                          = "com.tizen.fakepowermanager";
+const std::string OBJECT_PATH                       = "/com/tizen/fakepowermanager";
+const std::string INTERFACE                         = "com.tizen.fakepowermanager.manager";
+
+const std::string SIGNAL_DISPLAY_OFF                = "DisplayOff";
+
+const std::string DEFINITION =
+    "<node>"
+    "  <interface name='" + INTERFACE + "'>"
+    "    <signal name='" + SIGNAL_DISPLAY_OFF + "'>"
+    "    </signal>"
+    "  </interface>"
+    "</node>";
+
+
+} // namespace fake_power_manager_api
+
+#endif // FAKE_POWER_MANAGER_DBUS_DEFINITIONS_H
index ec42fdc..a403aa8 100644 (file)
@@ -1,6 +1,7 @@
 {
     "containerConfigs" : ["containers/console1.conf", "missing/file/path/missing.conf", "containers/console3.conf"],
     "foregroundId" : "ut-containers-manager-console1",
+    "defaultId" : "ut-containers-manager-console1",
     "inputConfig" : {"enabled" : false,
                      "device" : "/dev/doesnotexist",
                      "code" : 139,
diff --git a/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf b/tests/unit_tests/server/configs/ut-containers-manager/buggy-default-daemon.conf
new file mode 100644 (file)
index 0000000..39d56df
--- /dev/null
@@ -0,0 +1,10 @@
+{
+    "containerConfigs" : ["containers/console1-dbus.conf", "containers/console2-dbus.conf", "containers/console3-dbus.conf"],
+    "foregroundId" : "ut-containers-manager-console1",
+    "defaultId" : "in_no_way_there_is_a_valid_id_here",
+    "inputConfig" : {"enabled" : false,
+                     "device" : "/dev/doesnotexist",
+                     "code" : 139,
+                     "numberOfEvents" : 2,
+                     "timeWindowMs" : 500}
+}
index 0bb38b7..e12964a 100644 (file)
@@ -1,6 +1,7 @@
 {
     "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"],
     "foregroundId" : "this_id_does_not_exist",
+    "defaultId" : "ut-containers-manager-console1",
     "inputConfig" : {"enabled" : false,
                      "device" : "/dev/doesnotexist",
                      "code" : 139,
index 29ac710..4ffe017 100644 (file)
@@ -1,6 +1,7 @@
 {
     "containerConfigs" : ["containers/console1.conf", "containers/console2.conf", "containers/console3.conf"],
     "foregroundId" : "ut-containers-manager-console1",
+    "defaultId" : "ut-containers-manager-console1",
     "inputConfig" : {"enabled" : false,
                      "device" : "/dev/doesnotexist",
                      "code" : 139,
index c403e04..ae59483 100644 (file)
@@ -3,6 +3,7 @@
                           "containers/console2-dbus.conf",
                           "containers/console3-dbus.conf"],
     "foregroundId" : "ut-containers-manager-console1",
+    "defaultId" : "ut-containers-manager-console1",
     "inputConfig" : {"enabled" : false,
                      "device" : "/dev/doesnotexist",
                      "code" : 139,
index 0d27a85..47b4450 100644 (file)
@@ -1,6 +1,7 @@
 {
     "containerConfigs" : ["containers/container1.conf", "missing/file/path/missing.conf", "containers/container3.conf"],
     "foregroundId" : "ut-server-container1",
+    "defaultId" : "ut-server-container1",
     "inputConfig" : {"enabled" : false,
                      "device" : "/dev/doesnotexist",
                      "code" : 139,
index fc55c54..360bab7 100644 (file)
@@ -1,6 +1,7 @@
 {
     "containerConfigs" : ["containers/container1.conf", "containers/container2.conf", "containers/container3.conf"],
     "foregroundId" : "ut-server-container1",
+    "defaultId" : "ut-server-container1",
     "inputConfig" : {"enabled" : false,
                      "device" : "gpio-keys.4",
                      "code" : 139,
index 4b757a3..92f98ac 100644 (file)
 #include "container-connection.hpp"
 #include "container-connection-transport.hpp"
 #include "container-dbus-definitions.hpp"
+// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager
+#include "fake-power-manager-dbus-definitions.hpp"
 
 #include "dbus/connection.hpp"
+#include "dbus/exception.hpp"
 #include "utils/scoped-daemon.hpp"
 #include "utils/glib-loop.hpp"
 #include "utils/latch.hpp"
@@ -73,6 +76,53 @@ private:
     ScopedDaemon mDaemon;
 };
 
+class DbusNameSetter {
+public:
+    DbusNameSetter()
+        : mNameAcquired(false),
+          mPendingDisconnect(false)
+    {
+    }
+
+    void setName(const std::unique_ptr<DbusConnection>& conn, const std::string& name)
+    {
+        conn->setName(name,
+                      std::bind(&DbusNameSetter::onNameAcquired, this),
+                      std::bind(&DbusNameSetter::onDisconnect, this));
+
+        if(!waitForName()) {
+            throw dbus::DbusOperationException("Could not acquire name.");
+        }
+    }
+
+    bool waitForName()
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mNameCondition.wait(lock, [this] {return mNameAcquired || mPendingDisconnect;});
+        return mNameAcquired;
+    }
+
+    void onNameAcquired()
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mNameAcquired = true;
+        mNameCondition.notify_one();
+    }
+
+    void onDisconnect()
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mPendingDisconnect = true;
+        mNameCondition.notify_one();
+    }
+
+private:
+    bool mNameAcquired;
+    bool mPendingDisconnect;
+    std::mutex mMutex;
+    std::condition_variable mNameCondition;
+};
+
 } // namespace
 
 
@@ -151,5 +201,45 @@ BOOST_AUTO_TEST_CASE(SignalNotificationApiTest)
     BOOST_CHECK(signalEmitted.wait(EVENT_TIMEOUT));
 }
 
+BOOST_AUTO_TEST_CASE(SignalDisplayOffApiTest)
+{
+    ScopedGlibLoop loop;
+    ScopedDbusDaemon dbus;
+
+    Latch displayOffCalled;
+    std::unique_ptr<ContainerConnection> connection;
+
+    BOOST_REQUIRE_NO_THROW(connection.reset(new ContainerConnection(dbus.acquireAddress(),
+                                            nullptr)));
+
+    DbusConnection::Pointer client = DbusConnection::create(dbus.acquireAddress());
+
+    auto callback = [&]() {
+        displayOffCalled.set();
+    };
+
+    connection->setDisplayOffCallback(callback);
+
+    client->emitSignal(fake_power_manager_api::OBJECT_PATH,
+                       fake_power_manager_api::INTERFACE,
+                       fake_power_manager_api::SIGNAL_DISPLAY_OFF,
+                       nullptr);
+
+    // timeout should occur, since no name is set to client
+    BOOST_CHECK(!displayOffCalled.wait(EVENT_TIMEOUT));
+
+    DbusNameSetter setter;
+
+    setter.setName(client, fake_power_manager_api::BUS_NAME);
+
+    client->emitSignal(fake_power_manager_api::OBJECT_PATH,
+                       fake_power_manager_api::INTERFACE,
+                       fake_power_manager_api::SIGNAL_DISPLAY_OFF,
+                       nullptr);
+
+    // now signal should be delivered correctly
+    BOOST_CHECK(displayOffCalled.wait(EVENT_TIMEOUT));
+}
+
 
 BOOST_AUTO_TEST_SUITE_END()
index f12c9d6..61eea40 100644 (file)
 
 #include "containers-manager.hpp"
 #include "container-dbus-definitions.hpp"
+// TODO: Switch to real power-manager dbus defs when they will be implemented in power-manager
+#include "fake-power-manager-dbus-definitions.hpp"
 #include "exception.hpp"
 
 #include "dbus/connection.hpp"
+#include "dbus/exception.hpp"
 #include "utils/glib-loop.hpp"
 #include "config/exception.hpp"
 #include "utils/latch.hpp"
@@ -39,6 +42,8 @@
 #include <string>
 #include <algorithm>
 #include <functional>
+#include <mutex>
+#include <condition_variable>
 
 
 using namespace security_containers;
@@ -52,6 +57,7 @@ const std::string TEST_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-cont
 const std::string TEST_DBUS_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/test-dbus-daemon.conf";
 const std::string BUGGY_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-daemon.conf";
 const std::string BUGGY_FOREGROUND_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-foreground-daemon.conf";
+const std::string BUGGY_DEFAULTID_CONFIG_PATH = SC_TEST_CONFIG_INSTALL_DIR "/server/ut-containers-manager/buggy-default-daemon.conf";
 const std::string MISSING_CONFIG_PATH = "/this/is/a/missing/file/path/missing-daemon.conf";
 const int EVENT_TIMEOUT = 5000;
 const int TEST_DBUS_CONNECTION_CONTAINERS_COUNT = 3;
@@ -63,20 +69,63 @@ class DbusAccessory {
 public:
     std::vector<std::string> mReceivedSignalsSource;
 
-    DbusAccessory(int id, Latch& signalEmittedLatch)
+    DbusAccessory(int id)
         : mId(id),
           mClient(DbusConnection::create(acquireAddress())),
-          mSignalEmittedLatch(signalEmittedLatch)
+          mNameAcquired(false),
+          mPendingDisconnect(false)
     {
     }
 
-    void signalSubscribe()
+    void setName(const std::string& name)
+    {
+        mClient->setName(name,
+                         std::bind(&DbusAccessory::onNameAcquired, this),
+                         std::bind(&DbusAccessory::onDisconnect, this));
+
+        if(!waitForName()) {
+            mClient.reset();
+            throw dbus::DbusOperationException("Could not acquire name.");
+        }
+    }
+
+    bool waitForName()
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mNameCondition.wait(lock, [this] {return mNameAcquired || mPendingDisconnect;});
+        return mNameAcquired;
+    }
+
+    void onNameAcquired()
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mNameAcquired = true;
+        mNameCondition.notify_one();
+    }
+
+    void onDisconnect()
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mPendingDisconnect = true;
+        mNameCondition.notify_one();
+    }
+
+    void signalSubscribe(Latch& referenceLatch)
     {
         using namespace std::placeholders;
-        mClient->signalSubscribe(std::bind(&DbusAccessory::handler, this, _1, _2, _3, _4, _5),
+        mClient->signalSubscribe(std::bind(&DbusAccessory::handler,
+                                 this, std::ref(referenceLatch), _1, _2, _3, _4, _5),
                                  api::BUS_NAME);
     }
 
+    void emitSignal(const std::string& objectPath,
+                    const std::string& interface,
+                    const std::string& name,
+                    GVariant* parameters)
+    {
+        mClient->emitSignal(objectPath, interface, name, parameters);
+    }
+
     void callMethod()
     {
         GVariant* parameters = g_variant_new("(ss)", TEST_APP_NAME.c_str(), TEST_MESSGAE.c_str());
@@ -96,7 +145,10 @@ public:
 private:
     const int mId;
     DbusConnection::Pointer mClient;
-    Latch& mSignalEmittedLatch;
+    bool mNameAcquired;
+    bool mPendingDisconnect;
+    std::mutex mMutex;
+    std::condition_variable mNameCondition;
 
     std::string acquireAddress() const
     {
@@ -104,7 +156,8 @@ private:
                "-dbus/dbus/system_bus_socket";
     }
 
-    void handler(const std::string& /*senderBusName*/,
+    void handler(Latch& referenceLatch,
+                 const std::string& /*senderBusName*/,
                  const std::string& objectPath,
                  const std::string& interface,
                  const std::string& signalName,
@@ -121,7 +174,7 @@ private:
             g_variant_get(parameters, "(&s&s&s)", &container, &application, &message);
             mReceivedSignalsSource.push_back(container);
             if (application == TEST_APP_NAME && message == TEST_MESSGAE) {
-                mSignalEmittedLatch.set();
+                referenceLatch.set();
             }
         }
     }
@@ -168,6 +221,12 @@ BOOST_AUTO_TEST_CASE(BuggyForegroundTest)
     BOOST_CHECK(cm.getRunningForegroundContainerId() == "ut-containers-manager-console2");
 }
 
+BOOST_AUTO_TEST_CASE(BuggyDefaultTest)
+{
+    BOOST_REQUIRE_THROW(ContainersManager cm(BUGGY_DEFAULTID_CONFIG_PATH),
+                        ContainerOperationException);
+}
+
 BOOST_AUTO_TEST_CASE(StopAllTest)
 {
     ContainersManager cm(TEST_CONFIG_PATH);
@@ -210,10 +269,10 @@ BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest)
 
     std::vector< std::unique_ptr<DbusAccessory> > dbuses;
     for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
-        dbuses.push_back(std::unique_ptr<DbusAccessory>(new DbusAccessory(i, signalReceivedLatch)));
+        dbuses.push_back(std::unique_ptr<DbusAccessory>(new DbusAccessory(i)));
     }
     for (auto& dbus : dbuses) {
-        dbus->signalSubscribe();
+        dbus->signalSubscribe(signalReceivedLatch);
     }
     for (auto& dbus : dbuses) {
         dbus->callMethod();
@@ -238,4 +297,41 @@ BOOST_AUTO_TEST_CASE(NotifyActiveContainerTest)
     dbuses.clear();
 }
 
+BOOST_AUTO_TEST_CASE(DisplayOffTest)
+{
+    ContainersManager cm(TEST_DBUS_CONFIG_PATH);
+    BOOST_REQUIRE_NO_THROW(cm.startAll());
+
+    std::vector<std::unique_ptr<DbusAccessory>> clients;
+    for (int i = 1; i <= TEST_DBUS_CONNECTION_CONTAINERS_COUNT; ++i) {
+        clients.push_back(std::unique_ptr<DbusAccessory>(new DbusAccessory(i)));
+    }
+
+    for (auto& client : clients) {
+        client->setName(fake_power_manager_api::BUS_NAME);
+    }
+
+    std::mutex Mutex;
+    std::unique_lock<std::mutex> Lock(Mutex);
+    std::condition_variable Condition;
+    auto cond = [&cm]() -> bool {
+        return cm.getRunningForegroundContainerId() == "ut-containers-manager-console1";
+    };
+
+    for (auto& client : clients) {
+        // TEST SWITCHING TO DEFAULT CONTAINER
+        // focus non-default container
+        BOOST_REQUIRE_NO_THROW(cm.focus("ut-containers-manager-console3"));
+
+        // emit signal from dbus connection
+        BOOST_REQUIRE_NO_THROW(client->emitSignal(fake_power_manager_api::OBJECT_PATH,
+                                                  fake_power_manager_api::INTERFACE,
+                                                  fake_power_manager_api::SIGNAL_DISPLAY_OFF,
+                                                  nullptr));
+
+        // check if default container has focus
+        BOOST_CHECK(Condition.wait_for(Lock, std::chrono::milliseconds(EVENT_TIMEOUT), cond));
+    }
+}
+
 BOOST_AUTO_TEST_SUITE_END()