Merge lp:~gerboland/qtmir/RTM-fix-lifecycle-exempt-keeps-wakelock into lp:qtmir/rtm-14.09

Proposed by Gerry Boland
Status: Merged
Approved by: Albert Astals Cid
Approved revision: 301
Merged at revision: 295
Proposed branch: lp:~gerboland/qtmir/RTM-fix-lifecycle-exempt-keeps-wakelock
Merge into: lp:qtmir/rtm-14.09
Diff against target: 1184 lines (+653/-249)
15 files modified
debian/control (+2/-0)
src/common/abstractdbusservicemonitor.cpp (+2/-3)
src/common/abstractdbusservicemonitor.h (+1/-7)
src/modules/Unity/Application/Application.pro (+1/-1)
src/modules/Unity/Application/application.cpp (+3/-1)
src/modules/Unity/Application/application_manager.cpp (+5/-2)
src/modules/Unity/Application/sharedwakelock.cpp (+120/-57)
src/modules/Unity/Application/sharedwakelock.h (+14/-9)
tests/modules/Application/application_test.cpp (+7/-7)
tests/modules/ApplicationManager/application_manager_test.cpp (+78/-0)
tests/modules/SharedWakelock/SharedWakelock.pro (+11/-0)
tests/modules/SharedWakelock/sharedwakelock_test.cpp (+365/-146)
tests/modules/common/common.pri (+2/-1)
tests/modules/common/mock_shared_wakelock.h (+41/-14)
tests/modules/modules.pro (+1/-1)
To merge this branch: bzr merge lp:~gerboland/qtmir/RTM-fix-lifecycle-exempt-keeps-wakelock
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Approve
Gerry Boland (community) Abstain
Review via email: mp+251131@code.launchpad.net

Commit message

Refactor wakelock handling. Lifecycle exempt apps now release wakelock when shell tries to suspend them

The previous Wakelock RAII design was faulty as it was wrapping an asynchronous service. It made it possible for wakelocks to be acquired and not be released.

This refactors SharedWakelock to hold a single instance of Wakelock, and Wakelock always holds a DBus connection.

Testing now includes testing the DBus calls are actually emitted.

Adds dependency on libqtdbusmock1-dev and libqtdbustest1-dev

To post a comment you must log in.
296. By Gerry Boland

Add test

Revision history for this message
Gerry Boland (gerboland) wrote :

2 wakelocks somehow acquired with this by the Music app, something wrong

review: Needs Fixing
297. By Gerry Boland

Refactor wakelock handling. Lifecycle exempt apps now release wakelock when shell tries to suspend them

The previous Wakelock RAII design was faulty as it was wrapping an asynchronous service. It made it possible for wakelocks to be acquired and not be released.

This refactors SharedWakelock to hold a single instance of Wakelock, and Wakelock always holds a DBus connection.

Testing now includes testing the DBus calls are actually emitted.

Adds dependency on libqtdbusmock1-dev and libqtdbustest1-dev

298. By Gerry Boland

Fix acquire(), release(), acquire() being called in quick succession, and only after do 2 cookies get sent from dbus

299. By Gerry Boland

Fix and add test for SharedWakelock acq/rel/acq not loosing a cookie

Revision history for this message
Gerry Boland (gerboland) wrote :

Is good now.

review: Abstain
300. By Gerry Boland

Delete unnecesary line

301. By Gerry Boland

Racey test not so reliable, this helps

Revision history for this message
Albert Astals Cid (aacid) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass?
No CI, but i compiled and ran the tests on a krillin

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2015-01-12 12:51:39 +0000
+++ debian/control 2015-03-06 14:19:39 +0000
@@ -16,6 +16,8 @@
16 libmirserver-dev (>= 0.8.1),16 libmirserver-dev (>= 0.8.1),
17 libmtdev-dev,17 libmtdev-dev,
18 libprocess-cpp-dev,18 libprocess-cpp-dev,
19 libqtdbusmock1-dev (>= 0.2),
20 libqtdbustest1-dev (>= 0.2),
19 libqt5sensors5-dev,21 libqt5sensors5-dev,
20 libubuntu-app-launch2-dev,22 libubuntu-app-launch2-dev,
21 libubuntu-application-api-dev (>= 2.1.0),23 libubuntu-application-api-dev (>= 2.1.0),
2224
=== modified file 'src/common/abstractdbusservicemonitor.cpp'
--- src/common/abstractdbusservicemonitor.cpp 2015-01-16 09:48:21 +0000
+++ src/common/abstractdbusservicemonitor.cpp 2015-03-06 14:19:39 +0000
@@ -41,14 +41,13 @@
41};41};
4242
43AbstractDBusServiceMonitor::AbstractDBusServiceMonitor(const QString &service, const QString &path,43AbstractDBusServiceMonitor::AbstractDBusServiceMonitor(const QString &service, const QString &path,
44 const QString &interface, const Bus bus,44 const QString &interface, const QDBusConnection connection,
45 QObject *parent)45 QObject *parent)
46 : QObject(parent)46 : QObject(parent)
47 , m_service(service)47 , m_service(service)
48 , m_path(path)48 , m_path(path)
49 , m_interface(interface)49 , m_interface(interface)
50 , m_busConnection((bus == SystemBus) ? QDBusConnection::systemBus()50 , m_busConnection(connection)
51 : QDBusConnection::sessionBus())
52 , m_watcher(new QDBusServiceWatcher(service, m_busConnection))51 , m_watcher(new QDBusServiceWatcher(service, m_busConnection))
53 , m_dbusInterface(nullptr)52 , m_dbusInterface(nullptr)
54{53{
5554
=== modified file 'src/common/abstractdbusservicemonitor.h'
--- src/common/abstractdbusservicemonitor.h 2015-01-16 09:48:21 +0000
+++ src/common/abstractdbusservicemonitor.h 2015-03-06 14:19:39 +0000
@@ -31,17 +31,11 @@
31class Q_DECL_EXPORT AbstractDBusServiceMonitor : public QObject31class Q_DECL_EXPORT AbstractDBusServiceMonitor : public QObject
32{32{
33 Q_OBJECT33 Q_OBJECT
34 Q_ENUMS(Bus)
35 Q_PROPERTY(bool serviceAvailable READ serviceAvailable NOTIFY serviceAvailableChanged)34 Q_PROPERTY(bool serviceAvailable READ serviceAvailable NOTIFY serviceAvailableChanged)
3635
37public:36public:
38 enum Bus {
39 SessionBus,
40 SystemBus,
41 };
42
43 explicit AbstractDBusServiceMonitor(const QString &service, const QString &path, const QString &interface,37 explicit AbstractDBusServiceMonitor(const QString &service, const QString &path, const QString &interface,
44 const Bus bus = SessionBus,38 const QDBusConnection connection = QDBusConnection::sessionBus(),
45 QObject *parent = 0);39 QObject *parent = 0);
46 ~AbstractDBusServiceMonitor();40 ~AbstractDBusServiceMonitor();
4741
4842
=== modified file 'src/modules/Unity/Application/Application.pro'
--- src/modules/Unity/Application/Application.pro 2015-01-16 09:48:21 +0000
+++ src/modules/Unity/Application/Application.pro 2015-03-06 14:19:39 +0000
@@ -12,7 +12,7 @@
12QMAKE_CXXFLAGS = -std=c++11 -Werror -Wall12QMAKE_CXXFLAGS = -std=c++11 -Werror -Wall
13QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined13QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined
1414
15PKGCONFIG += mirserver glib-2.0 gio-unix-2.0 process-cpp ubuntu-app-launch-215PKGCONFIG += mirserver glib-2.0 gio-unix-2.0 process-cpp ubuntu-app-launch-2 libqtdbusmock-1 libqtdbustest-1
1616
17INCLUDEPATH += ../../../platforms/mirserver ../../../common17INCLUDEPATH += ../../../platforms/mirserver ../../../common
18LIBS += -L../../../platforms/mirserver -lqpa-mirserver18LIBS += -L../../../platforms/mirserver -lqpa-mirserver
1919
=== modified file 'src/modules/Unity/Application/application.cpp'
--- src/modules/Unity/Application/application.cpp 2015-01-16 09:48:21 +0000
+++ src/modules/Unity/Application/application.cpp 2015-03-06 14:19:39 +0000
@@ -319,7 +319,9 @@
319void Application::setFocused(bool focused)319void Application::setFocused(bool focused)
320{320{
321 qCDebug(QTMIR_APPLICATIONS) << "Application::setFocused - appId=" << appId() << "focused=" << focused;321 qCDebug(QTMIR_APPLICATIONS) << "Application::setFocused - appId=" << appId() << "focused=" << focused;
322 holdWakelock(true);322 if (focused) {
323 holdWakelock(true);
324 }
323325
324 if (m_focused != focused) {326 if (m_focused != focused) {
325 m_focused = focused;327 m_focused = focused;
326328
=== modified file 'src/modules/Unity/Application/application_manager.cpp'
--- src/modules/Unity/Application/application_manager.cpp 2015-01-16 09:48:21 +0000
+++ src/modules/Unity/Application/application_manager.cpp 2015-03-06 14:19:39 +0000
@@ -372,9 +372,12 @@
372 return false;372 return false;
373 qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::suspendApplication - appId=" << application->appId();373 qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::suspendApplication - appId=" << application->appId();
374374
375 // Present in exceptions list, return.375 // Present in exceptions list, explicitly release wakelock and return. There's no need to keep the wakelock
376 if (!m_lifecycleExceptions.filter(application->appId().section('_',0,0)).empty())376 // as the process is never suspended and thus has no cleanup to perform when (for example) the display is blanked
377 if (!m_lifecycleExceptions.filter(application->appId().section('_',0,0)).empty()) {
378 m_sharedWakelock->release(application);
377 return false;379 return false;
380 }
378381
379 if (m_forceDashActive && application->appId() == "unity8-dash") {382 if (m_forceDashActive && application->appId() == "unity8-dash") {
380 return false;383 return false;
381384
=== modified file 'src/modules/Unity/Application/sharedwakelock.cpp'
--- src/modules/Unity/Application/sharedwakelock.cpp 2015-01-16 09:48:21 +0000
+++ src/modules/Unity/Application/sharedwakelock.cpp 2015-03-06 14:19:39 +0000
@@ -29,57 +29,129 @@
29const char cookieFile[] = "/tmp/qtmir_powerd_cookie";29const char cookieFile[] = "/tmp/qtmir_powerd_cookie";
3030
31/**31/**
32 * @brief The Wakelock class - on creation acquires a system wakelock, on destruction releases it32 * @brief The Wakelock class - wraps a single system wakelock
33 * Designed in the spirit of RAII. Should the PowerD service vanish from the bus, the wakelock33 * Should the PowerD service vanish from the bus, the wakelock will be re-acquired when it re-joins the bus.
34 * will be re-acquired when it re-joins the bus.
35 */34 */
36class Wakelock : public AbstractDBusServiceMonitor35class Wakelock : public AbstractDBusServiceMonitor
37{36{
38 Q_OBJECT37 Q_OBJECT
39public:38public:
40 Wakelock() noexcept39 Wakelock(const QDBusConnection &connection) noexcept
41 : AbstractDBusServiceMonitor("com.canonical.powerd", "/com/canonical/powerd", "com.canonical.powerd", SystemBus)40 : AbstractDBusServiceMonitor("com.canonical.powerd", "/com/canonical/powerd", "com.canonical.powerd", connection)
41 , m_wakelockEnabled(false)
42 {42 {
43 // (re-)acquire wake lock when powerd (re-)appears on the bus43 // (re-)acquire wake lock when powerd (re-)appears on the bus
44 QObject::connect(this, &Wakelock::serviceAvailableChanged,44 QObject::connect(this, &Wakelock::serviceAvailableChanged,
45 this, &Wakelock::acquireWakelock);45 this, &Wakelock::onServiceAvailableChanged);
46
47 if (!serviceAvailable()) {
48 qWarning() << "com.canonical.powerd DBus interface not available, waiting for it";
49 return;
50 }
5146
52 // WORKAROUND: if shell crashed while it held a wakelock, due to bug lp:1409722 powerd will not have released47 // WORKAROUND: if shell crashed while it held a wakelock, due to bug lp:1409722 powerd will not have released
53 // the wakelock for it. As workaround, we save the cookie to file and restore it if possible.48 // the wakelock for it. As workaround, we save the cookie to file and restore it if possible.
54 QFile cookie(cookieFile);49 QFile cookieCache(cookieFile);
55 if (cookie.exists() && cookie.open(QFile::ReadOnly | QFile::Text)) {50 if (cookieCache.exists() && cookieCache.open(QFile::ReadOnly | QFile::Text)) {
56 m_cookie = cookie.readAll();51 m_wakelockEnabled = true;
57 } else {52 m_cookie = cookieCache.readAll();
58 acquireWakelock(true);
59 }53 }
60 }54 }
6155
62 virtual ~Wakelock() noexcept56 virtual ~Wakelock() noexcept
63 {57 {
58 release();
59 }
60
61 Q_SIGNAL void enabledChanged(bool);
62 bool enabled() const
63 {
64 return m_wakelockEnabled;
65 }
66
67 void acquire()
68 {
69 if (m_wakelockEnabled) { // wakelock already requested/set
70 return;
71 }
72 m_wakelockEnabled = true;
73
74 acquireWakelock();
75 }
76
77 void release()
78 {
64 QFile::remove(cookieFile);79 QFile::remove(cookieFile);
6580
81 if (!m_wakelockEnabled) { // no wakelock already requested/set
82 return;
83 }
84 m_wakelockEnabled = false;
85 Q_EMIT enabledChanged(false);
86
66 if (!serviceAvailable()) {87 if (!serviceAvailable()) {
67 qWarning() << "com.canonical.powerd DBus interface not available";88 qWarning() << "com.canonical.powerd DBus interface not available, presuming no wakelocks held";
68 return;89 return;
69 }90 }
7091
71 if (!m_cookie.isEmpty()) {92 if (!m_cookie.isEmpty()) {
72 dbusInterface()->asyncCall("clearSysState", m_cookie);93 dbusInterface()->asyncCall("clearSysState", QString(m_cookie));
94 qCDebug(QTMIR_SESSIONS) << "Wakelock released" << m_cookie;
95 m_cookie.clear();
73 }96 }
74 qCDebug(QTMIR_SESSIONS) << "Wakelock released";
75 }97 }
7698
77private Q_SLOTS:99private Q_SLOTS:
78 void acquireWakelock(bool available)100 void onServiceAvailableChanged(bool available)
79 {101 {
80 if (!available) {102 // Assumption is if service vanishes & reappears on the bus, it has lost its wakelock state and
81 m_cookie.clear(); // clear cookie so that when powerd re-appears, new cookie will be set103 // we must re-acquire if necessary
104 if (!m_wakelockEnabled) {
105 return;
106 }
107
108 if (available) {
109 acquireWakelock();
110 } else {
111 m_cookie.clear();
82 QFile::remove(cookieFile);112 QFile::remove(cookieFile);
113 }
114 }
115
116 void onWakeLockAcquired(QDBusPendingCallWatcher *call)
117 {
118 QDBusPendingReply<QString> reply = *call;
119 if (reply.isError()) {
120 qCDebug(QTMIR_SESSIONS) << "Wakelock was NOT acquired, error:"
121 << QDBusError::errorString(reply.error().type());
122 if (m_wakelockEnabled) {
123 m_wakelockEnabled = false;
124 Q_EMIT enabledChanged(false);
125 }
126
127 call->deleteLater();
128 return;
129 }
130 QByteArray cookie = reply.argumentAt<0>().toLatin1();
131 call->deleteLater();
132
133 if (!m_wakelockEnabled || !m_cookie.isEmpty()) {
134 // notified wakelock was created, but we either don't want it, or already have one - release it immediately
135 dbusInterface()->asyncCall("clearSysState", QString(cookie));
136 return;
137 }
138
139 m_cookie = cookie;
140
141 // see WORKAROUND above for why we save cookie to disk
142 QFile cookieCache(cookieFile);
143 cookieCache.open(QFile::WriteOnly | QFile::Text);
144 cookieCache.write(m_cookie);
145
146 qCDebug(QTMIR_SESSIONS) << "Wakelock acquired" << m_cookie;
147 Q_EMIT enabledChanged(true);
148 }
149
150private:
151 void acquireWakelock()
152 {
153 if (!serviceAvailable()) {
154 qWarning() << "com.canonical.powerd DBus interface not available, waiting for it";
83 return;155 return;
84 }156 }
85157
@@ -90,29 +162,8 @@
90 this, &Wakelock::onWakeLockAcquired);162 this, &Wakelock::onWakeLockAcquired);
91 }163 }
92164
93 void onWakeLockAcquired(QDBusPendingCallWatcher *call)165 QByteArray m_cookie;
94 {166 bool m_wakelockEnabled;
95 if (m_cookie.isEmpty()) { // don't overwrite existing cookie
96 QDBusPendingReply<QString> reply = *call;
97 if (reply.isError()) {
98 qCDebug(QTMIR_SESSIONS) << "Wakelock was NOT acquired, error:"
99 << QDBusError::errorString(reply.error().type());
100 } else {
101 m_cookie = reply.argumentAt<0>();
102
103 // see WORKAROUND above for why we save cookie to disk
104 QFile cookie(cookieFile);
105 cookie.open(QFile::WriteOnly | QFile::Text);
106 cookie.write(m_cookie.toLatin1());
107
108 qCDebug(QTMIR_SESSIONS) << "Wakelock acquired" << m_cookie;
109 }
110 }
111 call->deleteLater();
112 }
113
114private:
115 QString m_cookie;
116167
117 Q_DISABLE_COPY(Wakelock)168 Q_DISABLE_COPY(Wakelock)
118};169};
@@ -132,36 +183,48 @@
132 * Note a caller cannot have multiple shares of the wakelock. Multiple calls to acquire are ignored.183 * Note a caller cannot have multiple shares of the wakelock. Multiple calls to acquire are ignored.
133 */184 */
134185
135QObject* SharedWakelock::createWakelock()186SharedWakelock::SharedWakelock(const QDBusConnection &connection)
136{187 : m_wakelock(new Wakelock(connection))
137 return new Wakelock;188{
138}189 connect(m_wakelock.data(), &Wakelock::enabledChanged,
139190 this, &SharedWakelock::enabledChanged);
191}
192
193// Define empty deconstructor here, as QScopedPointer<Wakelock> requires the destructor of the Wakelock class
194// to be defined first.
195SharedWakelock::~SharedWakelock()
196{
197}
198
199bool SharedWakelock::enabled() const
200{
201 return m_wakelock->enabled();
202}
140203
141void SharedWakelock::acquire(const QObject *caller)204void SharedWakelock::acquire(const QObject *caller)
142{205{
143 if (m_owners.contains(caller) || caller == nullptr) {206 if (caller == nullptr || m_owners.contains(caller)) {
144 return;207 return;
145 }208 }
146209
147 // register a slot to remove itself from owners list if destroyed210 // register a slot to remove itself from owners list if destroyed
148 QObject::connect(caller, &QObject::destroyed, this, &SharedWakelock::release);211 QObject::connect(caller, &QObject::destroyed, this, &SharedWakelock::release);
149212
150 if (m_wakelock.isNull()) {213 m_wakelock->acquire();
151 m_wakelock.reset(createWakelock());
152 }
153214
154 m_owners.insert(caller);215 m_owners.insert(caller);
155}216}
156217
157void SharedWakelock::release(const QObject *caller)218void SharedWakelock::release(const QObject *caller)
158{219{
159 if (!m_owners.remove(caller) || caller == nullptr) {220 if (caller == nullptr || !m_owners.remove(caller)) {
160 return;221 return;
161 }222 }
162223
163 if (m_owners.empty() && m_wakelock) {224 QObject::disconnect(caller, &QObject::destroyed, this, 0);
164 m_wakelock.reset();225
226 if (m_owners.empty()) {
227 m_wakelock->release();
165 }228 }
166}229}
167230
168231
=== modified file 'src/modules/Unity/Application/sharedwakelock.h'
--- src/modules/Unity/Application/sharedwakelock.h 2015-01-16 09:48:21 +0000
+++ src/modules/Unity/Application/sharedwakelock.h 2015-03-06 14:19:39 +0000
@@ -19,26 +19,31 @@
19#ifndef WAKELOCK_H19#ifndef WAKELOCK_H
20#define WAKELOCK_H20#define WAKELOCK_H
2121
22#include <QObject>22#include <QDBusConnection>
23#include <QSet>23#include <QSet>
24#include <QScopedPointer>24#include <QScopedPointer>
2525
26namespace qtmir {26namespace qtmir {
2727
28class Wakelock;
28class SharedWakelock : public QObject29class SharedWakelock : public QObject
29{30{
30 Q_OBJECT31 Q_OBJECT
32 Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
31public:33public:
32 SharedWakelock() = default;34 SharedWakelock(const QDBusConnection& connection = QDBusConnection::systemBus());
33 virtual ~SharedWakelock() noexcept = default;35 virtual ~SharedWakelock();
3436
35 void acquire(const QObject *caller);37 virtual bool enabled() const;
36 Q_SLOT void release(const QObject *caller);38
39 virtual void acquire(const QObject *caller);
40 Q_SLOT virtual void release(const QObject *caller);
41
42Q_SIGNALS:
43 void enabledChanged(bool enabled);
3744
38protected:45protected:
39 virtual QObject* createWakelock(); // override to test46 QScopedPointer<Wakelock> m_wakelock;
40
41 QScopedPointer<QObject> m_wakelock;
42 QSet<const QObject *> m_owners;47 QSet<const QObject *> m_owners;
4348
44private:49private:
4550
=== modified file 'tests/modules/Application/application_test.cpp'
--- tests/modules/Application/application_test.cpp 2015-01-16 09:48:21 +0000
+++ tests/modules/Application/application_test.cpp 2015-03-06 14:19:39 +0000
@@ -34,7 +34,7 @@
34{34{
35 using namespace ::testing;35 using namespace ::testing;
3636
37 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);37 EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
3838
39 startApplication(123, "app");39 startApplication(123, "app");
40 applicationManager.focusApplication("app");40 applicationManager.focusApplication("app");
@@ -50,14 +50,14 @@
50 applicationManager.focusApplication("app");50 applicationManager.focusApplication("app");
5151
52 Q_EMIT session->suspended();52 Q_EMIT session->suspended();
53 EXPECT_FALSE(sharedWakelock.wakelockHeld());53 EXPECT_FALSE(sharedWakelock.enabled());
54}54}
5555
56TEST_F(ApplicationTests, checkResumeAcquiresWakeLock)56TEST_F(ApplicationTests, checkResumeAcquiresWakeLock)
57{57{
58 using namespace ::testing;58 using namespace ::testing;
5959
60 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);60 EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
6161
62 auto app = startApplication(123, "app");62 auto app = startApplication(123, "app");
63 auto session = app->session();63 auto session = app->session();
@@ -69,7 +69,7 @@
69{69{
70 using namespace ::testing;70 using namespace ::testing;
7171
72 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);72 EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
73 const QString appId = "app";73 const QString appId = "app";
7474
75 auto app = startApplication(123, "app");75 auto app = startApplication(123, "app");
@@ -89,7 +89,7 @@
89{89{
90 using namespace ::testing;90 using namespace ::testing;
9191
92 EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);92 EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
9393
94 startApplication(123, "unity8-dash");94 startApplication(123, "unity8-dash");
95 applicationManager.focusApplication("unity8-dash");95 applicationManager.focusApplication("unity8-dash");
@@ -105,14 +105,14 @@
105 applicationManager.focusApplication("unity8-dash");105 applicationManager.focusApplication("unity8-dash");
106106
107 Q_EMIT session->suspended();107 Q_EMIT session->suspended();
108 EXPECT_FALSE(sharedWakelock.wakelockHeld());108 EXPECT_FALSE(sharedWakelock.enabled());
109}109}
110110
111TEST_F(ApplicationTests, checkDashResumeDoesNotAcquireWakeLock)111TEST_F(ApplicationTests, checkDashResumeDoesNotAcquireWakeLock)
112{112{
113 using namespace ::testing;113 using namespace ::testing;
114114
115 EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);115 EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
116116
117 auto app = startApplication(123, "unity8-dash");117 auto app = startApplication(123, "unity8-dash");
118 auto session = app->session();118 auto session = app->session();
119119
=== modified file 'tests/modules/ApplicationManager/application_manager_test.cpp'
--- tests/modules/ApplicationManager/application_manager_test.cpp 2014-10-20 18:48:53 +0000
+++ tests/modules/ApplicationManager/application_manager_test.cpp 2015-03-06 14:19:39 +0000
@@ -2135,3 +2135,81 @@
2135 cv.wait(lk, [&] { return done; } );2135 cv.wait(lk, [&] { return done; } );
2136 }2136 }
2137}2137}
2138
2139/*
2140 * Test lifecycle exempt applications have their wakelocks released when shell tries to suspend them
2141 */
2142TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnAttemptedSuspend)
2143{
2144 using namespace ::testing;
2145
2146 const QString appId("com.ubuntu.music"); // member of lifecycle exemption list
2147 const quint64 procId = 12345;
2148
2149 // Set up Mocks & signal watcher
2150 auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
2151 ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
2152 ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
2153
2154 ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
2155
2156 EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
2157 .Times(1)
2158 .WillOnce(Return(true));
2159
2160 auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
2161 applicationManager.onProcessStarting(appId);
2162 std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
2163 bool authed = true;
2164 applicationManager.authorizeSession(procId, authed);
2165 onSessionStarting(session);
2166
2167 // App creates surface, focuses it so state is running
2168 std::shared_ptr<mir::scene::Surface> surface(nullptr);
2169 applicationManager.onSessionCreatedSurface(session.get(), surface);
2170 applicationManager.focusApplication(appId);
2171
2172 applicationManager.unfocusCurrentApplication();
2173
2174 EXPECT_FALSE(sharedWakelock.enabled());
2175 EXPECT_EQ(application->state(), Application::Running);
2176}
2177
2178/*
2179 * Test lifecycle exempt applications have their wakelocks released on suspend
2180 */
2181TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnUnSuspend)
2182{
2183 using namespace ::testing;
2184
2185 const QString appId("com.ubuntu.music"); // member of lifecycle exemption list
2186 const quint64 procId = 12345;
2187
2188 // Set up Mocks & signal watcher
2189 auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
2190 ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
2191 ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
2192
2193 ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
2194
2195 EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
2196 .Times(1)
2197 .WillOnce(Return(true));
2198
2199 auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
2200 applicationManager.onProcessStarting(appId);
2201 std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
2202 bool authed = true;
2203 applicationManager.authorizeSession(procId, authed);
2204 onSessionStarting(session);
2205
2206 // App creates surface, focuses it so state is running
2207 std::shared_ptr<mir::scene::Surface> surface(nullptr);
2208 applicationManager.onSessionCreatedSurface(session.get(), surface);
2209 applicationManager.focusApplication(appId);
2210
2211 applicationManager.setSuspended(true);
2212
2213 EXPECT_FALSE(sharedWakelock.enabled());
2214 EXPECT_EQ(application->state(), Application::Running);
2215}
21382216
=== added file 'tests/modules/SharedWakelock/SharedWakelock.pro'
--- tests/modules/SharedWakelock/SharedWakelock.pro 1970-01-01 00:00:00 +0000
+++ tests/modules/SharedWakelock/SharedWakelock.pro 2015-03-06 14:19:39 +0000
@@ -0,0 +1,11 @@
1include(../../test-includes.pri)
2include(../common/common.pri)
3
4TARGET = sharedwakelock_test
5PKGCONFIG += libqtdbusmock-1 libqtdbustest-1
6
7INCLUDEPATH += \
8 ../../../src/modules/Unity/Application
9
10SOURCES += \
11 sharedwakelock_test.cpp
012
=== modified file 'tests/modules/SharedWakelock/sharedwakelock_test.cpp'
--- tests/modules/SharedWakelock/sharedwakelock_test.cpp 2015-01-16 09:48:21 +0000
+++ tests/modules/SharedWakelock/sharedwakelock_test.cpp 2015-03-06 14:19:39 +0000
@@ -17,154 +17,373 @@
1717
18#include <Unity/Application/sharedwakelock.h>18#include <Unity/Application/sharedwakelock.h>
1919
20#include "mock_shared_wakelock.h"20#include <libqtdbusmock/DBusMock.h>
2121
22#include <gmock/gmock.h>22#include <QCoreApplication>
23#include <QSignalSpy>
23#include <gtest/gtest.h>24#include <gtest/gtest.h>
2425
25using namespace qtmir;26using namespace qtmir;
26using testing::MockSharedWakelock;27using namespace testing;
2728using namespace QtDBusTest;
28TEST(SharedWakelock, acquireCreatesAWakelock)29using namespace QtDBusMock;
29{30
30 using namespace ::testing;31const char POWERD_NAME[] = "com.canonical.powerd";
3132const char POWERD_PATH[] = "/com/canonical/powerd";
32 testing::NiceMock<MockSharedWakelock> sharedWakelock;33const char POWERD_INTERFACE[] = "com.canonical.powerd";
33 QScopedPointer<QObject> app1(new QObject);34
3435class SharedWakelockTest: public Test
35 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);36{
36 sharedWakelock.acquire(app1.data());37protected:
37}38 SharedWakelockTest()
3839 : mock(dbus)
39TEST(SharedWakelock, acquireThenReleaseDestroysTheWakelock)40 {
40{41 mock.registerCustomMock(POWERD_NAME,
41 using namespace ::testing;42 POWERD_PATH,
4243 POWERD_INTERFACE,
43 testing::NiceMock<MockSharedWakelock> sharedWakelock;44 QDBusConnection::SystemBus);
44 QScopedPointer<QObject> app1(new QObject);45
4546 dbus.startServices();
46 sharedWakelock.acquire(app1.data());47 }
47 sharedWakelock.release(app1.data());48
48 EXPECT_FALSE(sharedWakelock.wakelockHeld());49 virtual ~SharedWakelockTest()
49}50 {}
5051
51TEST(SharedWakelock, doubleAcquireBySameOwnerOnlyCreatesASingleWakelock)52 virtual OrgFreedesktopDBusMockInterface& powerdMockInterface()
52{53 {
53 using namespace ::testing;54 return mock.mockInterface(POWERD_NAME,
5455 POWERD_PATH,
55 testing::NiceMock<MockSharedWakelock> sharedWakelock;56 POWERD_INTERFACE,
56 QScopedPointer<QObject> app1(new QObject);57 QDBusConnection::SystemBus);
5758 }
58 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));59
59 sharedWakelock.acquire(app1.data());60 void implementRequestSysState() {
60 sharedWakelock.acquire(app1.data());61 // Defines the mock impementation of this DBus method
61}62 powerdMockInterface().AddMethod("com.canonical.powerd",
6263 "requestSysState", "si", "s", "ret = 'cookie'").waitForFinished();
63TEST(SharedWakelock, doubleAcquireThenReleaseBySameOwnerDestroysWakelock)64 }
64{65
65 using namespace ::testing;66 void implementClearSysState() {
6667 powerdMockInterface().AddMethod("com.canonical.powerd",
67 testing::NiceMock<MockSharedWakelock> sharedWakelock;68 "clearSysState", "s", "", "").waitForFinished();
68 QScopedPointer<QObject> app1(new QObject);69 }
6970
70 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));71 void EXPECT_CALL(const QList<QVariantList> &spy, int index,
71 sharedWakelock.acquire(app1.data());72 const QString &name, const QVariantList &args)
72 sharedWakelock.acquire(app1.data());73 {
73 sharedWakelock.release(app1.data());74 QVariant args2(QVariant::fromValue(args));
74 EXPECT_FALSE(sharedWakelock.wakelockHeld());75 ASSERT_LT(index, spy.size());
75}76 const QVariantList &call(spy.at(index));
7677 EXPECT_EQ(name, call.at(0).toString());
77TEST(SharedWakelock, acquireByDifferentOwnerOnlyCreatesASingleWakelock)78 EXPECT_EQ(args2.toString().toStdString(), call.at(1).toString().toStdString());
78{79 }
79 using namespace ::testing;80
8081 DBusTestRunner dbus;
81 testing::NiceMock<MockSharedWakelock> sharedWakelock;82 DBusMock mock;
82 QScopedPointer<QObject> app1(new QObject);83};
83 QScopedPointer<QObject> app2(new QObject);84
8485TEST_F(SharedWakelockTest, acquireCreatesAWakelock)
85 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));86{
86 sharedWakelock.acquire(app1.data());87 implementRequestSysState();
87 sharedWakelock.acquire(app2.data());88
88}89 /* Note: we pass the DBusTestRunner constructed system DBus connection instead of letting
8990 * Qt create one. This is done as Qt has a non-testing friendly way of handling the built-in
90TEST(SharedWakelock, twoOwnersWhenOneReleasesStillHoldWakelock)91 * system and session connections, and as DBusTestRunner restarts the DBus daemon for each
91{92 * testcase, it unfortunately means Qt would end up pointing to a dead bus after one testcase. */
92 using namespace ::testing;93 SharedWakelock wakelock(dbus.systemConnection());
9394
94 testing::NiceMock<MockSharedWakelock> sharedWakelock;95 // Verify the DBus method is called & wakelock
95 QScopedPointer<QObject> app1(new QObject);96 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
96 QScopedPointer<QObject> app2(new QObject);97 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
9798
98 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));99 QScopedPointer<QObject> object(new QObject);
99 sharedWakelock.acquire(app1.data());100 wakelock.acquire(object.data());
100 sharedWakelock.acquire(app2.data());101 wakelockDBusMethodSpy.wait();
101 sharedWakelock.release(app1.data());102
102 EXPECT_TRUE(sharedWakelock.wakelockHeld());103 EXPECT_FALSE(wakelockDBusMethodSpy.empty());
103}104 EXPECT_CALL(wakelockDBusMethodSpy, 0, "requestSysState",
104105 QVariantList() << QString("active") << 1);
105TEST(SharedWakelock, twoOwnersWhenBothReleaseWakelockReleased)106
106{107 // Ensure a wakelock created
107 using namespace ::testing;108 wakelockEnabledSpy.wait();
108109 EXPECT_FALSE(wakelockEnabledSpy.empty());
109 testing::NiceMock<MockSharedWakelock> sharedWakelock;110 EXPECT_TRUE(wakelock.enabled());
110 QScopedPointer<QObject> app1(new QObject);111}
111 QScopedPointer<QObject> app2(new QObject);112
112113TEST_F(SharedWakelockTest, acquireThenReleaseDestroysTheWakelock)
113 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));114{
114 sharedWakelock.acquire(app1.data());115 implementRequestSysState();
115 sharedWakelock.acquire(app2.data());116 implementClearSysState();
116 sharedWakelock.release(app2.data());117
117 sharedWakelock.release(app1.data());118 SharedWakelock wakelock(dbus.systemConnection());
118 EXPECT_FALSE(sharedWakelock.wakelockHeld());119
119}120 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
120121
121TEST(SharedWakelock, doubleReleaseOfSingleOwnerIgnored)122 QScopedPointer<QObject> object(new QObject);
122{123 wakelock.acquire(object.data());
123 using namespace ::testing;124 wakelockEnabledSpy.wait();
124125
125 testing::NiceMock<MockSharedWakelock> sharedWakelock;126 // Verify the DBus method is called
126 QScopedPointer<QObject> app1(new QObject);127 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
127 QScopedPointer<QObject> app2(new QObject);128 wakelock.release(object.data());
128129 wakelockDBusMethodSpy.wait();
129 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));130
130 sharedWakelock.acquire(app1.data());131 EXPECT_FALSE(wakelockDBusMethodSpy.empty());
131 sharedWakelock.acquire(app2.data());132 EXPECT_CALL(wakelockDBusMethodSpy, 0, "clearSysState",
132 sharedWakelock.release(app1.data());133 QVariantList() << QString("cookie"));
133 EXPECT_TRUE(sharedWakelock.wakelockHeld());134
134135 EXPECT_FALSE(wakelock.enabled());
135 sharedWakelock.release(app1.data());136}
136 EXPECT_TRUE(sharedWakelock.wakelockHeld());137
137}138TEST_F(SharedWakelockTest, doubleAcquireBySameOwnerOnlyCreatesASingleWakelock)
138139{
139TEST(SharedWakelock, nullOwnerAcquireIgnored)140 implementRequestSysState();
140{141
141 using namespace ::testing;142 SharedWakelock wakelock(dbus.systemConnection());
142143
143 testing::NiceMock<MockSharedWakelock> sharedWakelock;144 // Verify the DBus method is called & wakelock
144145 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
145 EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);146
146 sharedWakelock.acquire(nullptr);147 QScopedPointer<QObject> object(new QObject);
147}148 wakelock.acquire(object.data());
148149 wakelock.acquire(object.data());
149TEST(SharedWakelock, nullOwnerReleaseIgnored)150 wakelockDBusMethodSpy.wait();
150{151
151 using namespace ::testing;152 EXPECT_EQ(wakelockDBusMethodSpy.count(), 1);
152153}
153 testing::NiceMock<MockSharedWakelock> sharedWakelock;154
154155TEST_F(SharedWakelockTest, doubleAcquireThenReleaseBySameOwnerDestroysWakelock)
155 EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);156{
156 sharedWakelock.release(nullptr);157 implementRequestSysState();
157}158 implementClearSysState();
158159
159TEST(SharedWakelock, ifOwnerDestroyedWakelockReleased)160 SharedWakelock wakelock(dbus.systemConnection());
160{161
161 using namespace ::testing;162 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
162163 QScopedPointer<QObject> object(new QObject);
163 testing::NiceMock<MockSharedWakelock> sharedWakelock;164
164 QScopedPointer<QObject> app1(new QObject);165 wakelock.acquire(object.data());
165166 wakelock.acquire(object.data());
166 EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));167 wakelock.release(object.data());
167 sharedWakelock.acquire(app1.data());168 wakelockEnabledSpy.wait();
168 app1.reset();169 EXPECT_FALSE(wakelock.enabled());
169 EXPECT_FALSE(sharedWakelock.wakelockHeld());170}
171
172TEST_F(SharedWakelockTest, acquireByDifferentOwnerOnlyCreatesASingleWakelock)
173{
174 implementRequestSysState();
175
176 SharedWakelock wakelock(dbus.systemConnection());
177
178 // Verify the DBus method is called & wakelock
179 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
180
181 QScopedPointer<QObject> object1(new QObject);
182 QScopedPointer<QObject> object2(new QObject);
183 wakelock.acquire(object1.data());
184 wakelock.acquire(object2.data());
185
186 wakelockDBusMethodSpy.wait();
187 EXPECT_EQ(wakelockDBusMethodSpy.count(), 1);
188}
189
190TEST_F(SharedWakelockTest, twoOwnersWhenBothReleaseWakelockReleased)
191{
192 implementRequestSysState();
193
194 SharedWakelock wakelock(dbus.systemConnection());
195
196 QScopedPointer<QObject> object1(new QObject);
197 QScopedPointer<QObject> object2(new QObject);
198 wakelock.acquire(object1.data());
199 wakelock.acquire(object2.data());
200
201 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
202
203 wakelock.release(object1.data());
204 wakelock.release(object2.data());
205
206 wakelockEnabledSpy.wait();
207 EXPECT_FALSE(wakelock.enabled());
208}
209
210TEST_F(SharedWakelockTest, doubleReleaseOfSingleOwnerIgnored)
211{
212 implementRequestSysState();
213
214 SharedWakelock wakelock(dbus.systemConnection());
215
216 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
217
218 QScopedPointer<QObject> object1(new QObject);
219 QScopedPointer<QObject> object2(new QObject);
220 wakelock.acquire(object1.data());
221 wakelock.acquire(object2.data());
222 wakelock.release(object1.data());
223
224 wakelockEnabledSpy.wait();
225
226 wakelock.release(object1.data());
227
228 EXPECT_TRUE(wakelock.enabled());
229}
230
231TEST_F(SharedWakelockTest, wakelockAcquireReleaseFlood)
232{
233 implementRequestSysState();
234 implementClearSysState();
235
236 SharedWakelock wakelock(dbus.systemConnection());
237
238 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
239
240 QScopedPointer<QObject> object(new QObject);
241 wakelock.acquire(object.data());
242 wakelock.release(object.data());
243 wakelock.acquire(object.data());
244 wakelock.release(object.data());
245 wakelock.acquire(object.data());
246 wakelock.release(object.data());
247 while (wakelockEnabledSpy.wait(100)) {}
248 EXPECT_FALSE(wakelock.enabled());
249}
250
251TEST_F(SharedWakelockTest, wakelockAcquireReleaseAcquireWithDelays)
252{
253 powerdMockInterface().AddMethod("com.canonical.powerd",
254 "requestSysState", "si", "s",
255 "i=100000\n" // delay the response from the mock dbus instance
256 "while i>0:\n"
257 " i-=1\n"
258 "ret = 'cookie'").waitForFinished();
259
260 implementClearSysState();
261
262 SharedWakelock wakelock(dbus.systemConnection());
263
264 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
265
266 QScopedPointer<QObject> object(new QObject);
267 wakelock.acquire(object.data());
268 wakelock.release(object.data());
269 wakelock.acquire(object.data());
270
271 while (wakelockDBusMethodSpy.wait(100)) {}
272 EXPECT_TRUE(wakelock.enabled());
273
274 // there must be at least one clearSysState call, but is not necessarily the second call
275 // should the dbus response be slow enough, it may be the third call. Is hard to reliably
276 // reproduce the racey condition for all platforms.
277 bool found = false;
278 for (int i=0; i<wakelockDBusMethodSpy.count(); i++) {
279 const QVariantList &call(wakelockDBusMethodSpy.at(i));
280
281 if (call.at(0).toString() == "clearSysState") {
282 found = true;
283 }
284 }
285 EXPECT_TRUE(found);
286}
287
288TEST_F(SharedWakelockTest, nullOwnerAcquireIgnored)
289{
290 implementRequestSysState();
291
292 SharedWakelock wakelock(dbus.systemConnection());
293
294 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
295
296 wakelock.acquire(nullptr);
297
298 wakelockEnabledSpy.wait(200); // have to wait to see if anything happens
299
300 EXPECT_FALSE(wakelock.enabled());
301}
302
303TEST_F(SharedWakelockTest, nullReleaseAcquireIgnored)
304{
305 implementRequestSysState();
306
307 SharedWakelock wakelock(dbus.systemConnection());
308
309 wakelock.release(nullptr);
310
311 EXPECT_FALSE(wakelock.enabled());
312}
313
314TEST_F(SharedWakelockTest, ifOwnerDestroyedWakelockReleased)
315{
316 implementRequestSysState();
317 implementClearSysState();
318
319 SharedWakelock wakelock(dbus.systemConnection());
320
321 QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
322
323 QScopedPointer<QObject> object(new QObject);
324 wakelock.acquire(object.data());
325 wakelockEnabledSpy.wait();
326
327 // Verify the DBus method is called
328 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
329
330 object.reset();
331 wakelockDBusMethodSpy.wait();
332
333 EXPECT_FALSE(wakelockDBusMethodSpy.empty());
334 EXPECT_CALL(wakelockDBusMethodSpy, 0, "clearSysState",
335 QVariantList() << QString("cookie"));
336
337 EXPECT_FALSE(wakelock.enabled());
338}
339
340TEST_F(SharedWakelockTest, reloadCachedWakelockCookie)
341{
342 const char cookieFile[] = "/tmp/qtmir_powerd_cookie";
343
344 // Custom Deleter for QScopedPointer to delete the qtmir cookie file no matter what
345 struct ScopedQFileCustomDeleter
346 {
347 static inline void cleanup(QFile *file)
348 {
349 file->remove();
350 delete file;
351 }
352 };
353 QScopedPointer<QFile, ScopedQFileCustomDeleter> cookieCache(new QFile(cookieFile));
354 cookieCache->open(QFile::WriteOnly | QFile::Text);
355 cookieCache->write("myCookie");
356
357 SharedWakelock wakelock(dbus.systemConnection());
358 EXPECT_TRUE(wakelock.enabled());
359}
360
361TEST_F(SharedWakelockTest, wakelockReleasedOnSharedWakelockDestroyed)
362{
363 implementRequestSysState();
364 implementClearSysState();
365
366 auto wakelock = new SharedWakelock(dbus.systemConnection());
367
368 QSignalSpy wakelockEnabledSpy(wakelock, SIGNAL( enabledChanged(bool) ));
369
370 QScopedPointer<QObject> object(new QObject);
371 wakelock->acquire(object.data());
372 wakelockEnabledSpy.wait(); // wait for wakelock to be enabled
373
374 QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
375 delete wakelock;
376 wakelockDBusMethodSpy.wait();
377
378 EXPECT_FALSE(wakelockDBusMethodSpy.empty());
379 EXPECT_CALL(wakelockDBusMethodSpy, 0, "clearSysState",
380 QVariantList() << QString("cookie"));
381}
382
383
384// Define custom main() as these tests rely on a QEventLoop
385int main(int argc, char** argv) {
386 QCoreApplication app(argc, argv);
387 ::testing::InitGoogleTest(&argc, argv);
388 return RUN_ALL_TESTS();
170}389}
171390
=== modified file 'tests/modules/common/common.pri'
--- tests/modules/common/common.pri 2014-10-20 18:48:53 +0000
+++ tests/modules/common/common.pri 2015-03-06 14:19:39 +0000
@@ -1,7 +1,7 @@
1CONFIG += no_keywords # keywords clash with ProcessC++1CONFIG += no_keywords # keywords clash with ProcessC++
2PKGCONFIG += ubuntu-app-launch-2 process-cpp2PKGCONFIG += ubuntu-app-launch-2 process-cpp
33
4QT += quick4QT += quick dbus
55
6HEADERS += ../common/mock_application_controller.h \6HEADERS += ../common/mock_application_controller.h \
7 ../common/mock_desktop_file_reader.h \7 ../common/mock_desktop_file_reader.h \
@@ -11,6 +11,7 @@
11 ../common/mock_prompt_session.h \11 ../common/mock_prompt_session.h \
12 ../common/mock_prompt_session_manager.h \12 ../common/mock_prompt_session_manager.h \
13 ../common/mock_renderable.h \13 ../common/mock_renderable.h \
14 ../common/mock_shared_wakelock.h \
14 ../common/mock_session.h \15 ../common/mock_session.h \
15 ../common/mock_surface.h \16 ../common/mock_surface.h \
16 ../common/qtmir_test.h \17 ../common/qtmir_test.h \
1718
=== modified file 'tests/modules/common/mock_shared_wakelock.h'
--- tests/modules/common/mock_shared_wakelock.h 2015-01-16 09:48:21 +0000
+++ tests/modules/common/mock_shared_wakelock.h 2015-03-06 14:19:39 +0000
@@ -23,21 +23,48 @@
2323
24namespace testing24namespace testing
25{25{
26struct MockSharedWakelock : public qtmir::SharedWakelock26class MockSharedWakelock : public qtmir::SharedWakelock
27{27{
28 MockSharedWakelock()28public:
29 {29 MockSharedWakelock(const QDBusConnection& /*connection*/= QDBusConnection::systemBus())
30 ON_CALL(*this, createWakelock()).WillByDefault(Invoke(this, &MockSharedWakelock::doCreateWakelock));30 {
31 }31 ON_CALL(*this, enabled()).WillByDefault(Invoke(this, &MockSharedWakelock::doEnabled));
3232 ON_CALL(*this, acquire(_)).WillByDefault(Invoke(this, &MockSharedWakelock::doAcquire));
33 MOCK_METHOD0(createWakelock, QObject*());33 ON_CALL(*this, release(_)).WillByDefault(Invoke(this, &MockSharedWakelock::doRelease));
34 bool wakelockHeld() { return m_wakelock; }34 }
3535
3636 MOCK_CONST_METHOD0(enabled, bool());
37 QObject* doCreateWakelock() const37 MOCK_METHOD1(acquire, void(const QObject *));
38 {38 MOCK_METHOD1(release, void(const QObject *));
39 return new QObject;39
40 }40 bool doEnabled()
41 {
42 return !m_owners.isEmpty();
43 }
44
45 void doAcquire(const QObject *object)
46 {
47 if (m_owners.contains(object)) {
48 return;
49 }
50 m_owners.insert(object);
51 if (m_owners.size() == 1) {
52 Q_EMIT enabledChanged(true);
53 }
54 }
55
56 void doRelease(const QObject *object)
57 {
58 if (!m_owners.remove(object)) {
59 return;
60 }
61 if (m_owners.isEmpty()) {
62 Q_EMIT enabledChanged(false);
63 }
64 }
65
66private:
67 QSet<const QObject *> m_owners;
41};68};
4269
43} // namespace testing70} // namespace testing
4471
=== modified file 'tests/modules/modules.pro'
--- tests/modules/modules.pro 2015-01-16 09:48:21 +0000
+++ tests/modules/modules.pro 2015-03-06 14:19:39 +0000
@@ -1,2 +1,2 @@
1TEMPLATE = subdirs1TEMPLATE = subdirs
2SUBDIRS = Application ApplicationManager General MirSurfaceItem SessionManager TaskController DesktopFileReader2SUBDIRS = Application ApplicationManager General MirSurfaceItem SessionManager SharedWakelock TaskController DesktopFileReader

Subscribers

People subscribed via source and target branches