on xenial help sign in
Use asynchronous dbus requests for property updates. Fixes: #1436982

Approved by: Albert Astals Cid

commit26ca8508902322631ee57a6ebd325248193e7b9d authorNick Dedekind <nick.dedekind@canonical.com> dateWed 22 Apr 2015, 14:45 (11 years ago) parent8190f384853ac7
13 files changed+599−102
plugins/AccountsService/AccountsService.cpp+263−61 plugins/AccountsService/AccountsService.h+9−9 plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+12−2 plugins/AccountsService/AccountsServiceDBusAdaptor.h+3−1 tests/plugins/AccountsService/AccountsServer.cpp+23−7 tests/plugins/AccountsService/AccountsServer.h+11−1 tests/plugins/AccountsService/CMakeLists.txt+8 tests/plugins/AccountsService/PropertiesServer.cpp+43−6 tests/plugins/AccountsService/PropertiesServer.h+8−1 tests/plugins/AccountsService/client.cpp+186−7 tests/plugins/AccountsService/interfaces.xml+21 tests/plugins/AccountsService/server.cpp+11−6 tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
plugins/AccountsService/AccountsService.cpp+263−61
@@ -21,6 +21,7 @@
2121
2222#include <QFile>
2323#include <QStringList>
24+#include <QDebug>
2425
2526AccountsService::AccountsService(QObject* parent)
2627 : QObject(parent),
@@ -56,15 +57,15 @@ void AccountsService::setUser(const QString &user)
5657 m_user = user;
5758 Q_EMIT userChanged();
5859
59− updateDemoEdges();
60− updateEnableLauncherWhileLocked();
61− updateEnableIndicatorsWhileLocked();
62− updateBackgroundFile();
63− updateStatsWelcomeScreen();
64− updatePasswordDisplayHint();
65− updateFailedLogins();
66− updateHereEnabled();
67− updateHereLicensePath();
60+ updateDemoEdges(false);
61+ updateEnableLauncherWhileLocked(false);
62+ updateEnableIndicatorsWhileLocked(false);
63+ updateBackgroundFile(false);
64+ updateStatsWelcomeScreen(false);
65+ updatePasswordDisplayHint(false);
66+ updateFailedLogins(false);
67+ updateHereEnabled(false);
68+ updateHereLicensePath(false);
6869}
6970
7071bool AccountsService::demoEdges() const
@@ -74,8 +75,12 @@ bool AccountsService::demoEdges() const
7475
7576void AccountsService::setDemoEdges(bool demoEdges)
7677{
77− m_demoEdges = demoEdges;
78− m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
78+ if (m_demoEdges != demoEdges) {
79+ m_demoEdges = demoEdges;
80+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
81+
82+ Q_EMIT demoEdgesChanged();
83+ }
7984}
8085
8186bool AccountsService::enableLauncherWhileLocked() const
@@ -110,7 +115,12 @@ bool AccountsService::hereEnabled() const
110115
111116void AccountsService::setHereEnabled(bool enabled)
112117{
113− m_service->setUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseAccepted", enabled);
118+ if (m_hereEnabled != enabled) {
119+ m_hereEnabled = enabled;
120+ m_service->setUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseAccepted", enabled);
121+
122+ Q_EMIT hereEnabledChanged();
123+ }
114124}
115125
116126QString AccountsService::hereLicensePath() const
@@ -123,88 +133,276 @@ bool AccountsService::hereLicensePathValid() const
123133 return !m_hereLicensePath.isNull();
124134}
125135
126−void AccountsService::updateDemoEdges()
136+void AccountsService::updateDemoEdges(bool async)
127137{
128− auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
129− if (m_demoEdges != demoEdges) {
130− m_demoEdges = demoEdges;
131− Q_EMIT demoEdgesChanged();
138+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
139+ "com.canonical.unity.AccountsService",
140+ "demo-edges");
141+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
142+
143+ connect(watcher, &QDBusPendingCallWatcher::finished,
144+ this, [this](QDBusPendingCallWatcher* watcher) {
145+
146+ QDBusPendingReply<QDBusVariant> reply = *watcher;
147+ if (reply.isError()) {
148+ qWarning() << "Failed to get 'demo-edges' property - " << reply.error().message();
149+ watcher->deleteLater();
150+ return;
151+ }
152+
153+ auto demoEdges = reply.value().variant().toBool();
154+ if (m_demoEdges != demoEdges) {
155+ m_demoEdges = demoEdges;
156+ Q_EMIT demoEdgesChanged();
157+ }
158+ watcher->deleteLater();
159+ });
160+ if (!async) {
161+ watcher->waitForFinished();
162+ delete watcher;
132163 }
133164}
134165
135−void AccountsService::updateEnableLauncherWhileLocked()
166+void AccountsService::updateEnableLauncherWhileLocked(bool async)
136167{
137− auto enableLauncherWhileLocked = m_service->getUserProperty(m_user, "com.ubuntu.AccountsService.SecurityPrivacy", "EnableLauncherWhileLocked").toBool();
138− if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) {
139− m_enableLauncherWhileLocked = enableLauncherWhileLocked;
140− Q_EMIT enableLauncherWhileLockedChanged();
168+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
169+ "com.ubuntu.AccountsService.SecurityPrivacy",
170+ "EnableLauncherWhileLocked");
171+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
172+
173+ connect(watcher, &QDBusPendingCallWatcher::finished,
174+ this, [this](QDBusPendingCallWatcher* watcher) {
175+
176+ QDBusPendingReply<QDBusVariant> reply = *watcher;
177+ if (reply.isError()) {
178+ qWarning() << "Failed to get 'EnableLauncherWhileLocked' property - " << reply.error().message();
179+ watcher->deleteLater();
180+ return;
181+ }
182+
183+ auto enableLauncherWhileLocked = reply.value().variant().toBool();
184+ if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) {
185+ m_enableLauncherWhileLocked = enableLauncherWhileLocked;
186+ Q_EMIT enableLauncherWhileLockedChanged();
187+ }
188+ watcher->deleteLater();
189+ });
190+ if (!async) {
191+ watcher->waitForFinished();
192+ delete watcher;
141193 }
142194}
143195
144−void AccountsService::updateEnableIndicatorsWhileLocked()
196+void AccountsService::updateEnableIndicatorsWhileLocked(bool async)
145197{
146− auto enableIndicatorsWhileLocked = m_service->getUserProperty(m_user, "com.ubuntu.AccountsService.SecurityPrivacy", "EnableIndicatorsWhileLocked").toBool();
147− if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) {
148− m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked;
149− Q_EMIT enableIndicatorsWhileLockedChanged();
198+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
199+ "com.ubuntu.AccountsService.SecurityPrivacy",
200+ "EnableIndicatorsWhileLocked");
201+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
202+
203+ connect(watcher, &QDBusPendingCallWatcher::finished,
204+ this, [this](QDBusPendingCallWatcher* watcher) {
205+
206+ QDBusPendingReply<QDBusVariant> reply = *watcher;
207+ if (reply.isError()) {
208+ qWarning() << "Failed to get 'EnableIndicatorsWhileLocked' property - " << reply.error().message();
209+ watcher->deleteLater();
210+ return;
211+ }
212+
213+ auto enableIndicatorsWhileLocked = reply.value().variant().toBool();
214+ if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) {
215+ m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked;
216+ Q_EMIT enableIndicatorsWhileLockedChanged();
217+ }
218+ watcher->deleteLater();
219+ });
220+ if (!async) {
221+ watcher->waitForFinished();
222+ delete watcher;
150223 }
151224}
152225
153−void AccountsService::updateBackgroundFile()
226+void AccountsService::updateBackgroundFile(bool async)
154227{
155− QString backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
156− if (m_backgroundFile != backgroundFile) {
157− m_backgroundFile = backgroundFile;
158− Q_EMIT backgroundFileChanged();
228+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
229+ "org.freedesktop.Accounts.User",
230+ "BackgroundFile");
231+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
232+
233+ connect(watcher, &QDBusPendingCallWatcher::finished,
234+ this, [this](QDBusPendingCallWatcher* watcher) {
235+
236+ QDBusPendingReply<QDBusVariant> reply = *watcher;
237+ if (reply.isError()) {
238+ qWarning() << "Failed to get 'BackgroundFile' property - " << reply.error().message();
239+ watcher->deleteLater();
240+ return;
241+ }
242+
243+ auto backgroundFile = reply.value().variant().toString();
244+ if (m_backgroundFile != backgroundFile) {
245+ m_backgroundFile = backgroundFile;
246+ Q_EMIT backgroundFileChanged();
247+ }
248+ watcher->deleteLater();
249+ });
250+ if (!async) {
251+ watcher->waitForFinished();
252+ delete watcher;
159253 }
160254}
161255
162−void AccountsService::updateStatsWelcomeScreen()
256+void AccountsService::updateStatsWelcomeScreen(bool async)
163257{
164− bool statsWelcomeScreen = m_service->getUserProperty(m_user, "com.ubuntu.touch.AccountsService.SecurityPrivacy", "StatsWelcomeScreen").toBool();
165− if (m_statsWelcomeScreen != statsWelcomeScreen) {
166− m_statsWelcomeScreen = statsWelcomeScreen;
167− Q_EMIT statsWelcomeScreenChanged();
258+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
259+ "com.ubuntu.touch.AccountsService.SecurityPrivacy",
260+ "StatsWelcomeScreen");
261+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
262+
263+ connect(watcher, &QDBusPendingCallWatcher::finished,
264+ this, [this](QDBusPendingCallWatcher* watcher) {
265+
266+ QDBusPendingReply<QDBusVariant> reply = *watcher;
267+ if (reply.isError()) {
268+ qWarning() << "Failed to get 'StatsWelcomeScreen' property - " << reply.error().message();
269+ watcher->deleteLater();
270+ return;
271+ }
272+
273+ auto statsWelcomeScreen = reply.value().variant().toBool();
274+ if (m_statsWelcomeScreen != statsWelcomeScreen) {
275+ m_statsWelcomeScreen = statsWelcomeScreen;
276+ Q_EMIT statsWelcomeScreenChanged();
277+ }
278+ watcher->deleteLater();
279+ });
280+ if (!async) {
281+ watcher->waitForFinished();
282+ delete watcher;
168283 }
169284}
170285
171−void AccountsService::updatePasswordDisplayHint()
286+void AccountsService::updatePasswordDisplayHint(bool async)
172287{
173− PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)m_service->getUserProperty(m_user, "com.ubuntu.AccountsService.SecurityPrivacy", "PasswordDisplayHint").toInt();
174− if (m_passwordDisplayHint != passwordDisplayHint) {
175− m_passwordDisplayHint = passwordDisplayHint;
176− Q_EMIT passwordDisplayHintChanged();
288+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
289+ "com.ubuntu.AccountsService.SecurityPrivacy",
290+ "PasswordDisplayHint");
291+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
292+
293+ connect(watcher, &QDBusPendingCallWatcher::finished,
294+ this, [this](QDBusPendingCallWatcher* watcher) {
295+
296+ QDBusPendingReply<QDBusVariant> reply = *watcher;
297+ if (reply.isError()) {
298+ qWarning() << "Failed to get 'PasswordDisplayHint' property - " << reply.error().message();
299+ watcher->deleteLater();
300+ return;
301+ }
302+
303+ PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)reply.value().variant().toInt();
304+ if (m_passwordDisplayHint != passwordDisplayHint) {
305+ m_passwordDisplayHint = passwordDisplayHint;
306+ Q_EMIT passwordDisplayHintChanged();
307+ }
308+ watcher->deleteLater();
309+ });
310+ if (!async) {
311+ watcher->waitForFinished();
312+ delete watcher;
177313 }
178314}
179315
180−void AccountsService::updateFailedLogins()
316+void AccountsService::updateFailedLogins(bool async)
181317{
182− uint failedLogins = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService.Private", "FailedLogins").toUInt();
183− if (m_failedLogins != failedLogins) {
184− m_failedLogins = failedLogins;
185− Q_EMIT failedLoginsChanged();
318+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
319+ "com.canonical.unity.AccountsService.Private",
320+ "FailedLogins");
321+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
322+
323+ connect(watcher, &QDBusPendingCallWatcher::finished,
324+ this, [this](QDBusPendingCallWatcher* watcher) {
325+
326+ QDBusPendingReply<QDBusVariant> reply = *watcher;
327+ if (reply.isError()) {
328+ qWarning() << "Failed to get 'FailedLogins' property - " << reply.error().message();
329+ watcher->deleteLater();
330+ return;
331+ }
332+
333+ uint failedLogins = reply.value().variant().toUInt();
334+ if (m_failedLogins != failedLogins) {
335+ m_failedLogins = failedLogins;
336+ Q_EMIT failedLoginsChanged();
337+ }
338+ watcher->deleteLater();
339+ });
340+ if (!async) {
341+ watcher->waitForFinished();
342+ delete watcher;
186343 }
187344}
188345
189−void AccountsService::updateHereEnabled()
346+void AccountsService::updateHereEnabled(bool async)
190347{
191− bool hereEnabled = m_service->getUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseAccepted").toBool();
192− if (m_hereEnabled != hereEnabled) {
193− m_hereEnabled = hereEnabled;
194− Q_EMIT hereEnabledChanged();
348+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
349+ "com.ubuntu.location.providers.here.AccountsService",
350+ "LicenseAccepted");
351+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
352+
353+ connect(watcher, &QDBusPendingCallWatcher::finished,
354+ this, [this](QDBusPendingCallWatcher* watcher) {
355+
356+ QDBusPendingReply<QDBusVariant> reply = *watcher;
357+ if (reply.isError()) {
358+ qWarning() << "Failed to get 'LicenseAccepted' property - " << reply.error().message();
359+ watcher->deleteLater();
360+ return;
361+ }
362+
363+ auto hereEnabled = reply.value().variant().toBool();
364+ if (m_hereEnabled != hereEnabled) {
365+ m_hereEnabled = hereEnabled;
366+ Q_EMIT hereEnabledChanged();
367+ }
368+ watcher->deleteLater();
369+ });
370+ if (!async) {
371+ watcher->waitForFinished();
372+ delete watcher;
195373 }
196374}
197375
198−void AccountsService::updateHereLicensePath()
376+void AccountsService::updateHereLicensePath(bool async)
199377{
200− QString hereLicensePath = m_service->getUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseBasePath").toString();
378+ QDBusPendingCall pendingReply = m_service->getUserPropertyAsync(m_user,
379+ "com.ubuntu.location.providers.here.AccountsService",
380+ "LicenseBasePath");
381+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingReply, this);
382+
383+ connect(watcher, &QDBusPendingCallWatcher::finished,
384+ this, [this](QDBusPendingCallWatcher* watcher) {
385+
386+ QDBusPendingReply<QDBusVariant> reply = *watcher;
387+ if (reply.isError()) {
388+ qWarning() << "Failed to get 'LicenseBasePath' property - " << reply.error().message();
389+ watcher->deleteLater();
390+ return;
391+ }
201392
202− if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
203− hereLicensePath = "";
393+ auto hereLicensePath = reply.value().variant().toString();
394+ if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
395+ hereLicensePath = "";
204396
205− if (m_hereLicensePath.isNull() || m_hereLicensePath != hereLicensePath) {
206− m_hereLicensePath = hereLicensePath;
207− Q_EMIT hereLicensePathChanged();
397+ if (m_hereLicensePath.isNull() || m_hereLicensePath != hereLicensePath) {
398+ m_hereLicensePath = hereLicensePath;
399+ Q_EMIT hereLicensePathChanged();
400+ }
401+ watcher->deleteLater();
402+ });
403+ if (!async) {
404+ watcher->waitForFinished();
405+ delete watcher;
208406 }
209407}
210408
@@ -215,8 +413,12 @@ uint AccountsService::failedLogins() const
215413
216414void AccountsService::setFailedLogins(uint failedLogins)
217415{
218− m_failedLogins = failedLogins;
219− m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService.Private", "FailedLogins", failedLogins);
416+ if (m_failedLogins != failedLogins) {
417+ m_failedLogins = failedLogins;
418+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService.Private", "FailedLogins", failedLogins);
419+
420+ Q_EMIT failedLoginsChanged();
421+ }
220422}
221423
222424void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
plugins/AccountsService/AccountsService.h+9−9
@@ -107,15 +107,15 @@ private Q_SLOTS:
107107 void maybeChanged(const QString &user);
108108
109109private:
110− void updateDemoEdges();
111− void updateEnableLauncherWhileLocked();
112− void updateEnableIndicatorsWhileLocked();
113− void updateBackgroundFile();
114− void updateStatsWelcomeScreen();
115− void updatePasswordDisplayHint();
116− void updateFailedLogins();
117− void updateHereEnabled();
118− void updateHereLicensePath();
110+ void updateDemoEdges(bool async = true);
111+ void updateEnableLauncherWhileLocked(bool async = true);
112+ void updateEnableIndicatorsWhileLocked(bool async = true);
113+ void updateBackgroundFile(bool async = true);
114+ void updateStatsWelcomeScreen(bool async = true);
115+ void updatePasswordDisplayHint(bool async = true);
116+ void updateFailedLogins(bool async = true);
117+ void updateHereEnabled(bool async = true);
118+ void updateHereLicensePath(bool async = true);
119119
120120 AccountsServiceDBusAdaptor *m_service;
121121 QString m_user;
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+12−2
@@ -49,6 +49,15 @@ QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const
4949 return QVariant();
5050}
5151
52+QDBusPendingReply<QDBusVariant> AccountsServiceDBusAdaptor::getUserPropertyAsync(const QString &user, const QString &interface, const QString &property)
53+{
54+ QDBusInterface *iface = getUserInterface(user);
55+ if (iface != nullptr && iface->isValid()) {
56+ return iface->asyncCall("Get", interface, property);
57+ }
58+ return QDBusPendingReply<QVariant>(QDBusMessage::createError(QDBusError::Other, "Invalid Interface"));
59+}
60+
5261void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
5362{
5463 QDBusInterface *iface = getUserInterface(user);
@@ -58,13 +67,14 @@ void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QStr
5867 }
5968}
6069
61−void AccountsServiceDBusAdaptor::setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value)
70+QDBusPendingCall AccountsServiceDBusAdaptor::setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value)
6271{
6372 QDBusInterface *iface = getUserInterface(user);
6473 if (iface != nullptr && iface->isValid()) {
6574 // The value needs to be carefully wrapped
66− iface->asyncCall("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
75+ return iface->asyncCall("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
6776 }
77+ return QDBusPendingCall::fromCompletedCall(QDBusMessage::createError(QDBusError::Other, "Invalid Interface"));
6878}
6979
7080void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
plugins/AccountsService/AccountsServiceDBusAdaptor.h+3−1
@@ -22,6 +22,7 @@
2222#include <QDBusArgument>
2323#include <QDBusContext>
2424#include <QDBusInterface>
25+#include <QDBusPendingReply>
2526#include <QMap>
2627#include <QObject>
2728#include <QString>
@@ -34,6 +35,7 @@ public:
3435 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
3536
3637 Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
38+ Q_INVOKABLE QDBusPendingReply<QDBusVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property);
3739
3840 template <typename T>
3941 inline T getUserProperty(const QString &user, const QString &interface, const QString &property) {
@@ -45,7 +47,7 @@ public:
4547 }
4648
4749 Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
48− Q_INVOKABLE void setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
50+ Q_INVOKABLE QDBusPendingCall setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
4951
5052Q_SIGNALS:
5153 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
tests/plugins/AccountsService/AccountsServer.cpp+23−7
@@ -18,18 +18,34 @@
1818 */
1919
2020#include "AccountsServer.h"
21+#include "PropertiesServer.h"
22+#include <QDBusConnection>
23+#include <QDebug>
2124
22−AccountsServer::AccountsServer(QObject *parent)
25+AccountsServer::AccountsServer(PropertiesServer* propServer, QObject *parent)
2326 : QObject(parent)
27+ , m_propServer(propServer)
2428{
2529}
2630
2731QDBusObjectPath AccountsServer::FindUserByName(const QString &user)
2832{
29− if (user == "testuser") {
30− return QDBusObjectPath("/user");
31− } else {
32− sendErrorReply(QDBusError::InvalidArgs, "Bad user");
33− return QDBusObjectPath("/");
34− }
33+ return QDBusObjectPath(QString("/%1").arg(user));
34+}
35+
36+bool AccountsServer::AddUser(const QString &user)
37+{
38+ QString path(QString("/%1").arg(user));
39+ if (QDBusConnection::sessionBus().objectRegisteredAt(path) == m_propServer)
40+ return true;
41+ return QDBusConnection::sessionBus().registerObject(path, m_propServer);
42+}
43+
44+bool AccountsServer::RemoveUser(const QString &user)
45+{
46+ QString path(QString("/%1").arg(user));
47+ if (QDBusConnection::sessionBus().objectRegisteredAt(path) != m_propServer)
48+ return false;
49+ QDBusConnection::sessionBus().unregisterObject(path);
50+ return true;
3551}
tests/plugins/AccountsService/AccountsServer.h+11−1
@@ -25,15 +25,25 @@
2525#include <QObject>
2626#include <QString>
2727
28+class PropertiesServer;
29+
2830class AccountsServer: public QObject, protected QDBusContext
2931{
3032 Q_OBJECT
3133
3234public:
33− explicit AccountsServer(QObject *parent = 0);
35+ explicit AccountsServer(PropertiesServer *propServer, QObject *parent = 0);
3436
3537public Q_SLOTS:
38+
3639 QDBusObjectPath FindUserByName(const QString &user);
40+
41+ // mock only.
42+ bool AddUser(const QString &user);
43+ bool RemoveUser(const QString &user);
44+
45+private:
46+ PropertiesServer* m_propServer;
3747};
3848
3949#endif
tests/plugins/AccountsService/CMakeLists.txt+8
@@ -11,6 +11,10 @@ endmacro(make_dbus_class)
1111
1212make_dbus_class(Accounts org.freedesktop.Accounts)
1313make_dbus_class(Properties org.freedesktop.DBus.Properties)
14+make_dbus_class(SecurityPrivacy com.ubuntu.touch.AccountsService.SecurityPrivacy)
15+make_dbus_class(Location com.ubuntu.location.providers.here.AccountsService)
16+make_dbus_class(AccountsUser org.freedesktop.Accounts.User)
17+make_dbus_class(AccountsPrivate com.canonical.unity.AccountsService.Private)
1418
1519include_directories(
1620 ${CMAKE_CURRENT_BINARY_DIR}
@@ -21,7 +25,11 @@ add_definitions(-DSM_BUSNAME=sessionBus)
2125
2226add_executable(mock-server
2327 ${CMAKE_CURRENT_BINARY_DIR}/AccountsAdaptor.cpp
28+ ${CMAKE_CURRENT_BINARY_DIR}/AccountsPrivateAdaptor.cpp
29+ ${CMAKE_CURRENT_BINARY_DIR}/AccountsUserAdaptor.cpp
2430 ${CMAKE_CURRENT_BINARY_DIR}/PropertiesAdaptor.cpp
31+ ${CMAKE_CURRENT_BINARY_DIR}/LocationAdaptor.cpp
32+ ${CMAKE_CURRENT_BINARY_DIR}/SecurityPrivacyAdaptor.cpp
2533 server.cpp
2634 AccountsServer.cpp
2735 PropertiesServer.cpp
tests/plugins/AccountsService/PropertiesServer.cpp+43−6
@@ -18,17 +18,22 @@
1818 */
1919
2020#include "PropertiesServer.h"
21+#include "AccountsService.h"
22+
23+// Qt
24+#include <QDebug>
25+#include <QDBusMessage>
2126
2227PropertiesServer::PropertiesServer(QObject *parent)
23− : QObject(parent),
24− edge_demo(true)
28+ : QObject(parent)
2529{
30+ Reset();
2631}
2732
2833QDBusVariant PropertiesServer::Get(const QString &interface, const QString &property)
2934{
30− if (interface == "com.canonical.unity.AccountsService" && property == "demo-edges") {
31− return QDBusVariant(QVariant(edge_demo));
35+ if (m_properties[interface].contains(property)) {
36+ return QDBusVariant(m_properties[interface][property]);
3237 } else {
3338 sendErrorReply(QDBusError::InvalidArgs, "Bad interface or property");
3439 return QDBusVariant(QVariant());
@@ -37,9 +42,41 @@ QDBusVariant PropertiesServer::Get(const QString &interface, const QString &prop
3742
3843void PropertiesServer::Set(const QString &interface, const QString &property, const QDBusVariant &variant)
3944{
40− if (interface == "com.canonical.unity.AccountsService" && property == "demo-edges") {
41− edge_demo = variant.variant().toBool();
45+ QVariant newValue = variant.variant();
46+
47+ if (m_properties[interface].contains(property)) {
48+ QVariant& oldValue = m_properties[interface][property];
49+ if (oldValue != newValue) {
50+ oldValue = newValue;
51+
52+ // Special case for Background file.
53+ if (interface == "org.freedesktop.Accounts.User" && property == "BackgroundFile") {
54+ Q_EMIT Changed();
55+ } else {
56+ QVariantMap propertyChanges;
57+ propertyChanges[property] = newValue;
58+ Q_EMIT PropertiesChanged(interface, propertyChanges, QStringList());
59+
60+ // FIXME: Here to replicate current behaviour
61+ // Not sure why accounts-service is triggering Changed when we're
62+ // emitting PropertyChanges from org.freedesktop.DBus.Properties as well.
63+ Q_EMIT Changed();
64+ }
65+ }
4266 } else {
4367 sendErrorReply(QDBusError::InvalidArgs, "Bad interface or property");
4468 }
4569}
70+
71+void PropertiesServer::Reset()
72+{
73+ m_properties["com.canonical.unity.AccountsService"]["demo-edges"] = false;
74+ m_properties["com.canonical.unity.AccountsService.Private"]["FailedLogins"] = 0;
75+ m_properties["com.ubuntu.touch.AccountsService.SecurityPrivacy"]["StatsWelcomeScreen"] = true;
76+ m_properties["com.ubuntu.AccountsService.SecurityPrivacy"]["EnableLauncherWhileLocked"] = true;
77+ m_properties["com.ubuntu.AccountsService.SecurityPrivacy"]["EnableIndicatorsWhileLocked"] = true;
78+ m_properties["com.ubuntu.AccountsService.SecurityPrivacy"]["PasswordDisplayHint"] = AccountsService::Keyboard;
79+ m_properties["com.ubuntu.location.providers.here.AccountsService"]["LicenseAccepted"] = false;
80+ m_properties["com.ubuntu.location.providers.here.AccountsService"]["LicenseBasePath"] = "";
81+ m_properties["org.freedesktop.Accounts.User"]["BackgroundFile"] = "";
82+}
tests/plugins/AccountsService/PropertiesServer.h+8−1
@@ -37,8 +37,15 @@ public Q_SLOTS:
3737 QDBusVariant Get(const QString &interface, const QString &property);
3838 void Set(const QString &interface, const QString &property, const QDBusVariant &variant);
3939
40+ // mock only.
41+ void Reset();
42+
43+Q_SIGNALS:
44+ void PropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
45+ void Changed();
46+
4047private:
41− bool edge_demo;
48+ QHash<QString, QVariantMap> m_properties;
4249};
4350
4451#endif
tests/plugins/AccountsService/client.cpp+186−7
@@ -21,39 +21,218 @@
2121#include "AccountsServiceDBusAdaptor.h"
2222#include <QSignalSpy>
2323#include <QTest>
24+#include <QDebug>
25+#include <QDBusReply>
26+
27+template <class T>
28+QVariant dbusVariant(const T& value) { return QVariant::fromValue(QDBusVariant(value)); }
29+
30+#define ASSERT_DBUS_CALL(call) \
31+ { \
32+ QDBusReply<void> reply = call; \
33+ if (!reply.isValid()) QFAIL(reply.error().message().toLatin1()); \
34+ }
2435
2536class AccountsServiceTest : public QObject
2637{
2738 Q_OBJECT
2839
40+public:
41+ AccountsServiceTest(QObject* parent = 0)
42+ : QObject(parent)
43+ , m_userInterface(nullptr)
44+ , m_spy(this, &AccountsServiceTest::propertiesChanged)
45+ {
46+ }
47+
2948private Q_SLOTS:
3049
50+ void init() {
51+ QDBusReply<bool> addReply = QDBusInterface("org.freedesktop.Accounts",
52+ "/org/freedesktop/Accounts",
53+ "org.freedesktop.Accounts").call("AddUser", QTest::currentTestFunction());
54+ QVERIFY(addReply.isValid());
55+ QCOMPARE(addReply.value(), true);
56+
57+ m_userInterface = new QDBusInterface("org.freedesktop.Accounts",
58+ QString("/%1").arg(QTest::currentTestFunction()),
59+ "org.freedesktop.DBus.Properties", QDBusConnection::sessionBus(), this);
60+ QDBusReply<void> resetReply = m_userInterface->call("Reset");
61+ QVERIFY(resetReply.isValid());
62+
63+ QVERIFY(QObject::connect(m_userInterface, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)),
64+ this, SIGNAL(propertiesChanged(QString, QVariantMap, QStringList))));
65+ }
66+
67+ void cleanup() {
68+ QDBusReply<bool> reply = QDBusInterface("org.freedesktop.Accounts",
69+ "/org/freedesktop/Accounts",
70+ "org.freedesktop.Accounts").call("RemoveUser", QTest::currentTestFunction());
71+ QVERIFY(reply.isValid());
72+ QCOMPARE(reply.value(), true);
73+
74+ delete m_userInterface;
75+ m_spy.clear();
76+ }
77+
3178 void testInvalids()
3279 {
3380 // Test various invalid calls
3481 AccountsServiceDBusAdaptor session;
3582 QCOMPARE(session.getUserProperty("NOPE", "com.canonical.unity.AccountsService", "demo-edges"), QVariant());
36− QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "NOPE"), QVariant());
83+ QCOMPARE(session.getUserProperty(QTest::currentTestFunction(), "com.canonical.unity.AccountsService", "NOPE"), QVariant());
3784 }
3885
3986 void testGetSetServiceDBusAdaptor()
4087 {
4188 AccountsServiceDBusAdaptor session;
42− session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(true));
43− QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(true));
44− session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(false));
45− QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(false));
89+ session.setUserProperty(QTest::currentTestFunction(), "com.canonical.unity.AccountsService", "demo-edges", QVariant(true));
90+ QCOMPARE(session.getUserProperty(QTest::currentTestFunction(), "com.canonical.unity.AccountsService", "demo-edges"), QVariant(true));
91+ session.setUserProperty(QTest::currentTestFunction(), "com.canonical.unity.AccountsService", "demo-edges", QVariant(false));
92+ QCOMPARE(session.getUserProperty(QTest::currentTestFunction(), "com.canonical.unity.AccountsService", "demo-edges"), QVariant(false));
4693 }
4794
4895 void testGetSetService()
4996 {
5097 AccountsService session;
51− session.setUser("testuser");
98+ session.setUser(QTest::currentTestFunction());
99+
100+ QCOMPARE(session.demoEdges(), false);
52101 session.setDemoEdges(true);
53102 QCOMPARE(session.demoEdges(), true);
54− session.setDemoEdges(false);
103+
104+ QCOMPARE(session.failedLogins(), (uint)0);
105+ session.setFailedLogins(5);
106+ QCOMPARE(session.failedLogins(), (uint)5);
107+
108+ QCOMPARE(session.hereEnabled(), false);
109+ session.setHereEnabled(true);
110+ QCOMPARE(session.hereEnabled(), true);
111+ }
112+
113+ void testAsynchornousChangeForDemoEdges()
114+ {
115+ AccountsService session;
116+ session.setUser(QTest::currentTestFunction());
117+
55118 QCOMPARE(session.demoEdges(), false);
119+ ASSERT_DBUS_CALL(m_userInterface->call("Set",
120+ "com.canonical.unity.AccountsService",
121+ "demo-edges",
122+ dbusVariant(true)));
123+ QTRY_COMPARE(session.demoEdges(), true);
124+ }
125+
126+ void testAsynchornousChangeForFailedLogins()
127+ {
128+ AccountsService session;
129+ session.setUser(QTest::currentTestFunction());
130+
131+ QCOMPARE(session.failedLogins(), (uint)0);
132+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
133+ "com.canonical.unity.AccountsService.Private",
134+ "FailedLogins",
135+ dbusVariant(5)));
136+ QTRY_COMPARE(session.failedLogins(), (uint)5);
137+ }
138+
139+ void testAsynchornousChangeForStatsWelcomeScreen()
140+ {
141+ AccountsService session;
142+ session.setUser(QTest::currentTestFunction());
143+
144+ QCOMPARE(session.statsWelcomeScreen(), true);
145+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
146+ "com.ubuntu.touch.AccountsService.SecurityPrivacy",
147+ "StatsWelcomeScreen",
148+ dbusVariant(false)));
149+ QTRY_COMPARE(session.statsWelcomeScreen(), false);
56150 }
151+
152+ void testAsynchornousChangeForStatsEnableLauncherWhileLocked()
153+ {
154+ AccountsService session;
155+ session.setUser(QTest::currentTestFunction());
156+
157+ QCOMPARE(session.enableLauncherWhileLocked(), true);
158+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
159+ "com.ubuntu.AccountsService.SecurityPrivacy",
160+ "EnableLauncherWhileLocked",
161+ dbusVariant(false)));
162+ QTRY_COMPARE(session.enableLauncherWhileLocked(), false);
163+ }
164+
165+ void testAsynchornousChangeForStatsEnableIndicatorsWhileLocked()
166+ {
167+ AccountsService session;
168+ session.setUser(QTest::currentTestFunction());
169+
170+ QCOMPARE(session.enableIndicatorsWhileLocked(), true);
171+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
172+ "com.ubuntu.AccountsService.SecurityPrivacy",
173+ "EnableIndicatorsWhileLocked",
174+ dbusVariant(false)));
175+ QTRY_COMPARE(session.enableIndicatorsWhileLocked(), false);
176+ }
177+
178+ void testAsynchornousChangeForStatsPasswordDisplayHint()
179+ {
180+ AccountsService session;
181+ session.setUser(QTest::currentTestFunction());
182+
183+ QCOMPARE(session.passwordDisplayHint(), AccountsService::Keyboard);
184+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
185+ "com.ubuntu.AccountsService.SecurityPrivacy",
186+ "PasswordDisplayHint",
187+ dbusVariant(AccountsService::Numeric)));
188+ QTRY_COMPARE(session.passwordDisplayHint(), AccountsService::Numeric);
189+ }
190+
191+ void testAsynchornousChangeForStatsLicenseAccepted()
192+ {
193+ AccountsService session;
194+ session.setUser(QTest::currentTestFunction());
195+
196+ QCOMPARE(session.hereEnabled(), false);
197+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
198+ "com.ubuntu.location.providers.here.AccountsService",
199+ "LicenseAccepted",
200+ dbusVariant(true)));
201+ QTRY_COMPARE(session.hereEnabled(), true);
202+ }
203+
204+ void testAsynchornousChangeForLicenseBasePath()
205+ {
206+ AccountsService session;
207+ session.setUser(QTest::currentTestFunction());
208+
209+ QCOMPARE(session.hereLicensePath(), QString());
210+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
211+ "com.ubuntu.location.providers.here.AccountsService",
212+ "LicenseBasePath",
213+ dbusVariant("/")));
214+ QTRY_COMPARE(session.hereLicensePath(), QString("/"));
215+ }
216+
217+ void testAsynchornousChangeForStatsBackgroundFile()
218+ {
219+ AccountsService session;
220+ session.setUser(QTest::currentTestFunction());
221+
222+ QCOMPARE(session.backgroundFile(), QString());
223+ ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
224+ "org.freedesktop.Accounts.User",
225+ "BackgroundFile",
226+ dbusVariant("/test/BackgroundFile")));
227+ QTRY_COMPARE(session.backgroundFile(), QString("/test/BackgroundFile"));
228+ }
229+
230+Q_SIGNALS:
231+ void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
232+
233+private:
234+ QDBusInterface* m_userInterface;
235+ QSignalSpy m_spy;
57236};
58237
59238QTEST_MAIN(AccountsServiceTest)
tests/plugins/AccountsService/interfaces.xml+21
@@ -10,11 +10,32 @@
1010 <arg name="property" type="s" direction="in" />
1111 <arg name="value" type="v" direction="in" />
1212 </method>
13+ <method name="Reset" />
14+ <signal name="PropertiesChanged">
15+ <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
16+ <arg name="interface" type="s" direction="out" />
17+ <arg name="changed" type="a{sv}" direction="out" />
18+ <arg name="invalid" type="as" direction="out" />
19+ </signal>
1320 </interface>
1421 <interface name="org.freedesktop.Accounts">
1522 <method name="FindUserByName">
1623 <arg name="user" type="s" direction="in" />
1724 <arg name="path" type="o" direction="out" />
1825 </method>
26+ <method name="AddUser">
27+ <arg name="user" type="s" direction="in" />
28+ <arg name="success" type="b" direction="out" />
29+ </method>
30+ <method name="RemoveUser">
31+ <arg name="user" type="s" direction="in" />
32+ <arg name="success" type="b" direction="out" />
33+ </method>
34+ </interface>
35+ <interface name="com.ubuntu.touch.AccountsService.SecurityPrivacy" />
36+ <interface name="com.ubuntu.location.providers.here.AccountsService" />
37+ <interface name="org.freedesktop.Accounts.User">
38+ <signal name="Changed" />
1939 </interface>
40+ <interface name="com.canonical.unity.AccountsService.Private" />
2041</node>
tests/plugins/AccountsService/server.cpp+11−6
@@ -21,24 +21,29 @@
2121#include "AccountsServer.h"
2222#include "PropertiesAdaptor.h"
2323#include "PropertiesServer.h"
24+#include "SecurityPrivacyAdaptor.h"
25+#include "LocationAdaptor.h"
26+#include "AccountsUserAdaptor.h"
27+#include "AccountsPrivateAdaptor.h"
2428#include <QCoreApplication>
2529
2630int main(int argc, char *argv[])
2731{
2832 QCoreApplication a(argc, argv);
2933
30− auto accounts = new AccountsServer();
31− new AccountsAdaptor(accounts);
32−
33− auto props = new PropertiesServer();
34+ auto props = new PropertiesServer(&a);
3435 new PropertiesAdaptor(props);
36+ new AccountsUserAdaptor(props);
3537
38+ auto accounts = new AccountsServer(props, &a);
39+ new AccountsAdaptor(accounts);
40+ new SecurityPrivacyAdaptor(accounts);
41+ new LocationAdaptor(accounts);
42+ new AccountsPrivateAdaptor(accounts);
3643 // We use the session bus for testing. The real plugin uses the system bus
3744 auto connection = QDBusConnection::sessionBus();
3845 if (!connection.registerObject("/org/freedesktop/Accounts", accounts))
3946 return 1;
40− if (!connection.registerObject("/user", props))
41− return 1;
4247 if (!connection.registerService("org.freedesktop.Accounts"))
4348 return 1;
4449
tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -3,8 +3,8 @@ pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
33pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
44
55include_directories(
6+ ${CMAKE_CURRENT_SOURCE_DIR}
67 ${CMAKE_CURRENT_BINARY_DIR}
7− ${CMAKE_SOURCE_DIR}/plugins/AccountsService
88 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher
99 ${GSETTINGS_QT_INCLUDE_DIRS}
1010 ${libunity8-private_SOURCE_DIR}