on xenial help sign in
Watch AccountsService for changes to the user's real name. This was preventing us from noticing when the user set their name in the welcome wizard.
1fee4d1Michael Terry
plugins/IntegratedLightDM/liblightdm/CMakeLists.txt+16−3
@@ -5,13 +5,16 @@ set(LibLightDM_SOURCES
5 UsersModel.cpp
5 UsersModel.cpp
6 GreeterPrivate.cpp
6 GreeterPrivate.cpp
7 UsersModelPrivate.cpp
7 UsersModelPrivate.cpp
8+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
8 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
9 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
9 )
10 )
10
11
11add_library(integratedLightDM STATIC ${LibLightDM_SOURCES})
12add_library(integratedLightDM STATIC ${LibLightDM_SOURCES})
13+add_library(integratedLightDMSession STATIC ${LibLightDM_SOURCES})
12add_library(MockLightDM-demo-shared SHARED ${LibLightDM_SOURCES})
14add_library(MockLightDM-demo-shared SHARED ${LibLightDM_SOURCES})
13
15
14include_directories(
16include_directories(
17+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
15 ${CMAKE_CURRENT_BINARY_DIR}
18 ${CMAKE_CURRENT_BINARY_DIR}
16 ${GLIB_INCLUDE_DIRS}
19 ${GLIB_INCLUDE_DIRS}
17 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
20 ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
@@ -22,17 +25,27 @@ target_link_libraries(integratedLightDM
22 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
25 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
23 -lpam
26 -lpam
24)
27)
28+target_link_libraries(integratedLightDMSession
29+ ${GLIB_LIBRARIES}
30+ ${LIBUSERMETRICSOUTPUT_LDFLAGS}
31+ -lpam
32+)
25target_link_libraries(MockLightDM-demo-shared
33target_link_libraries(MockLightDM-demo-shared
26 ${GLIB_LIBRARIES}
34 ${GLIB_LIBRARIES}
27 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
35 ${LIBUSERMETRICSOUTPUT_LDFLAGS}
28 -lpam
36 -lpam
29)
37)
30
38
31−qt5_use_modules(integratedLightDM Concurrent Gui)
39+qt5_use_modules(integratedLightDM Concurrent DBus Gui)
40+qt5_use_modules(integratedLightDMSession Concurrent DBus Gui)
32−qt5_use_modules(MockLightDM-demo-shared Concurrent Gui)
41+qt5_use_modules(MockLightDM-demo-shared Concurrent DBus Gui)
33
42
34−set_target_properties(integratedLightDM PROPERTIES COMPILE_FLAGS -fPIC)
43+set_target_properties(integratedLightDM PROPERTIES
44+ COMPILE_FLAGS "-DSM_BUSNAME=systemBus -fPIC")
45+set_target_properties(integratedLightDMSession PROPERTIES
46+ COMPILE_FLAGS "-DSM_BUSNAME=sessionBus -fPIC")
35set_target_properties(MockLightDM-demo-shared PROPERTIES
47set_target_properties(MockLightDM-demo-shared PROPERTIES
48+ COMPILE_FLAGS "-DSM_BUSNAME=systemBus"
36 OUTPUT_NAME lightdm-qt5-2)
49 OUTPUT_NAME lightdm-qt5-2)
37
50
38install(TARGETS MockLightDM-demo-shared
51install(TARGETS MockLightDM-demo-shared
plugins/IntegratedLightDM/liblightdm/UsersModel.cpp+4−18
@@ -54,24 +54,10 @@ UsersModel::UsersModel(QObject *parent) :
54 roles[ImagePathRole] = "imagePath";
54 roles[ImagePathRole] = "imagePath";
55 setRoleNames(roles);
55 setRoleNames(roles);
56
56
57− // Now modify our mock user backgrounds
57+ connect(d_ptr, &UsersModelPrivate::dataChanged, this, [this](int i) {
58− QDir bgdir = QDir(QStringLiteral("/usr/share/demo-assets/shell/backgrounds/"));
58+ QModelIndex index = createIndex(i, 0);
59− QStringList backgrounds = bgdir.entryList(QDir::Files | QDir::NoDotAndDotDot);
59+ Q_EMIT dataChanged(index, index);
60−
60+ });
61− for (int i = 0, j = 0; i < d->entries.size(); i++) {
62− Entry &entry = d->entries[i];
63− if (entry.background.isNull() && !backgrounds.isEmpty()) {
64− entry.background = bgdir.filePath(backgrounds[j++]);
65− if (j >= backgrounds.length()) {
66− j = 0;
67− }
68− }
69− }
70−}
71−
72−UsersModel::~UsersModel()
73−{
74− delete d_ptr;
75}
61}
76
62
77int UsersModel::rowCount(const QModelIndex &parent) const
63int UsersModel::rowCount(const QModelIndex &parent) const
plugins/IntegratedLightDM/liblightdm/UsersModel.h+1−1
@@ -41,7 +41,7 @@ class Q_DECL_EXPORT UsersModel : public QAbstractListModel
41
41
42public:
42public:
43 explicit UsersModel(QObject *parent = 0);
43 explicit UsersModel(QObject *parent = 0);
44− virtual ~UsersModel();
44+ virtual ~UsersModel() = default;
45
45
46 enum UserModelRoles {NameRole = Qt::UserRole,
46 enum UserModelRoles {NameRole = Qt::UserRole,
47 RealNameRole,
47 RealNameRole,
plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp+43−9
@@ -18,7 +18,11 @@
18
18
19#include "UsersModelPrivate.h"
19#include "UsersModelPrivate.h"
20
20
21+#include "AccountsServiceDBusAdaptor.h"
22+#include "UsersModel.h"
23+
21#include <glib.h>
24#include <glib.h>
25+#include <QDebug>
22#include <QDir>
26#include <QDir>
23#include <QSettings>
27#include <QSettings>
24#include <QStringList>
28#include <QStringList>
@@ -27,7 +31,9 @@ namespace QLightDM
27{
31{
28
32
29UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
33UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
34+ : QObject(parent),
30− : q_ptr(parent)
35+ q_ptr(parent),
36+ m_service(new AccountsServiceDBusAdaptor(this))
31{
37{
32 QFileInfo demoFile(QDir::homePath() + "/.unity8-greeter-demo");
38 QFileInfo demoFile(QDir::homePath() + "/.unity8-greeter-demo");
33 QString currentUser = g_get_user_name();
39 QString currentUser = g_get_user_name();
@@ -43,15 +49,43 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
43 entries.append({user, name, 0, 0, false, false, 0, 0});
49 entries.append({user, name, 0, 0, false, false, 0, 0});
44 }
50 }
45 } else {
51 } else {
46− // If we were using the actual liblightdm, we could just ask it
52+ entries.append({currentUser, 0, 0, 0, false, false, 0, 0});
47− // for the user's real name. But we aren't. We *should* ask
53+
48− // AccountsService for the real name, like liblightdm does internally,
54+ connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged,
49− // but this is close enough since AS and passwd are always in sync.
55+ this, [this](const QString &user) {
50− QString realName = QString::fromUtf8(g_get_real_name()); // gets name from passwd entry
56+ if (user == entries[0].username) {
51− if (realName == QStringLiteral("Unknown")) { // glib doesn't translate this string
57+ updateName(true);
52− realName.clear();
58+ }
59+ });
60+ updateName(false);
61+ }
62+}
63+
64+void UsersModelPrivate::updateName(bool async)
65+{
66+ auto pendingReply = m_service->getUserPropertyAsync(entries[0].username,
67+ QStringLiteral("org.freedesktop.Accounts.User"),
68+ QStringLiteral("RealName"));
69+ auto *watcher = new QDBusPendingCallWatcher(pendingReply, this);
70+
71+ connect(watcher, &QDBusPendingCallWatcher::finished,
72+ this, [this](QDBusPendingCallWatcher* watcher) {
73+
74+ QDBusPendingReply<QVariant> reply = *watcher;
75+ watcher->deleteLater();
76+ if (reply.isError()) {
77+ qWarning() << "Failed to get 'RealName' property - " << reply.error().message();
78+ return;
79+ }
80+
81+ const QString realName = reply.value().toString();
82+ if (entries[0].real_name != realName) {
83+ entries[0].real_name = realName;
84+ Q_EMIT dataChanged(0);
53 }
85 }
54− entries.append({currentUser, realName, 0, 0, false, false, 0, 0});
86+ });
87+ if (!async) {
88+ watcher->waitForFinished();
55 }
89 }
56}
90}
57
91
plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.h+15−3
@@ -19,8 +19,11 @@
19#ifndef UNITY_MOCK_USERSMODEL_PRIVATE_H
19#ifndef UNITY_MOCK_USERSMODEL_PRIVATE_H
20#define UNITY_MOCK_USERSMODEL_PRIVATE_H
20#define UNITY_MOCK_USERSMODEL_PRIVATE_H
21
21
22−#include <QtCore/QList>
22+#include <QList>
23−#include <QtCore/QString>
23+#include <QObject>
24+#include <QString>
25+
26+class AccountsServiceDBusAdaptor;
24
27
25namespace QLightDM
28namespace QLightDM
26{
29{
@@ -39,19 +42,28 @@ public:
39 QString infographic;
42 QString infographic;
40};
43};
41
44
42−class UsersModelPrivate
45+class UsersModelPrivate : public QObject
43{
46{
47+ Q_OBJECT
48+
44public:
49public:
45 explicit UsersModelPrivate(UsersModel *parent = 0);
50 explicit UsersModelPrivate(UsersModel *parent = 0);
46 virtual ~UsersModelPrivate() = default;
51 virtual ~UsersModelPrivate() = default;
47
52
48 QList<Entry> entries;
53 QList<Entry> entries;
49
54
55+Q_SIGNALS:
56+ void dataChanged(int);
57+
50protected:
58protected:
51 UsersModel * const q_ptr;
59 UsersModel * const q_ptr;
52
60
53private:
61private:
54 Q_DECLARE_PUBLIC(UsersModel)
62 Q_DECLARE_PUBLIC(UsersModel)
63+
64+ void updateName(bool async);
65+
66+ AccountsServiceDBusAdaptor *m_service;
55};
67};
56
68
57}
69}
tests/mocks/IntegratedLightDM/liblightdm/UsersModel.cpp−14
@@ -47,20 +47,6 @@ UsersModel::UsersModel(QObject *parent) :
47 roles[HasMessagesRole] = "hasMessages";
47 roles[HasMessagesRole] = "hasMessages";
48 roles[ImagePathRole] = "imagePath";
48 roles[ImagePathRole] = "imagePath";
49 setRoleNames(roles);
49 setRoleNames(roles);
50−
51− // Now modify our mock user backgrounds
52− QDir bgdir = QDir("/usr/share/demo-assets/shell/backgrounds/");
53− QStringList backgrounds = bgdir.entryList(QDir::Files | QDir::NoDotAndDotDot);
54−
55− for (int i = 0, j = 0; i < d->entries.size(); i++) {
56− Entry &entry = d->entries[i];
57− if (entry.background.isNull() && !backgrounds.isEmpty()) {
58− entry.background = bgdir.filePath(backgrounds[j++]);
59− if (j >= backgrounds.length()) {
60− j = 0;
61− }
62− }
63− }
64}
50}
65
51
66UsersModel::~UsersModel()
52UsersModel::~UsersModel()
tests/plugins/AccountsService/PropertiesServer.cpp+3−2
@@ -67,8 +67,8 @@ void PropertiesServer::Set(const QString &interface, const QString &property, co
67
67
68 oldValue = newValue;
68 oldValue = newValue;
69
69
70− // Special case for Background file.
70+ // Special case for user properties.
71− if (interface == "org.freedesktop.Accounts.User" && property == "BackgroundFile") {
71+ if (interface == "org.freedesktop.Accounts.User") {
72 Q_EMIT Changed();
72 Q_EMIT Changed();
73 } else {
73 } else {
74 QVariantMap propertyChanges;
74 QVariantMap propertyChanges;
@@ -99,4 +99,5 @@ void PropertiesServer::Reset()
99 m_properties["com.ubuntu.location.providers.here.AccountsService"]["LicenseAccepted"] = false;
99 m_properties["com.ubuntu.location.providers.here.AccountsService"]["LicenseAccepted"] = false;
100 m_properties["com.ubuntu.location.providers.here.AccountsService"]["LicenseBasePath"] = "";
100 m_properties["com.ubuntu.location.providers.here.AccountsService"]["LicenseBasePath"] = "";
101 m_properties["org.freedesktop.Accounts.User"]["BackgroundFile"] = "";
101 m_properties["org.freedesktop.Accounts.User"]["BackgroundFile"] = "";
102+ m_properties["org.freedesktop.Accounts.User"]["RealName"] = "";
102}
103}
tests/plugins/IntegratedLightDM/CMakeLists.txt+25
@@ -65,3 +65,28 @@ add_unity8_uitest(GreeterUsers GreeterUsersModelTestExec
65 DEPENDS MockLightDM
65 DEPENDS MockLightDM
66 LIGHTDM
66 LIGHTDM
67 )
67 )
68+
69+add_executable(GreeterIntegratedTestExec
70+ integrated.cpp
71+ )
72+qt5_use_modules(GreeterIntegratedTestExec Core DBus Quick Test)
73+target_link_libraries(GreeterIntegratedTestExec
74+ ${GLIB_LIBRARIES}
75+ integratedLightDMSession
76+ )
77+target_include_directories(GreeterIntegratedTestExec PUBLIC
78+ ${GLIB_INCLUDE_DIRS}
79+ ${CMAKE_SOURCE_DIR}/plugins/IntegratedLightDM/liblightdm
80+ )
81+add_unity8_unittest(GreeterIntegrated dbus-test-runner
82+ ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/IntegratedLightDM/liblightdm/
83+ ARG_PREFIX "--parameter"
84+ ARGS
85+ --task $<TARGET_FILE:mock-server>
86+ --task-name server
87+ --ignore-return
88+ --task $<TARGET_FILE:GreeterIntegratedTestExec>
89+ --task-name client
90+ --wait-for org.freedesktop.Accounts
91+ DEPENDS integratedLightDMSession
92+ )
tests/plugins/IntegratedLightDM/integrated.cppnew file+91
@@ -0,0 +1,91 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "UsersModel.h"
18+
19+#include <glib.h>
20+#include <QDBusInterface>
21+#include <QDBusReply>
22+#include <QtTest>
23+
24+class GreeterIntegratedTest : public QObject
25+{
26+ Q_OBJECT
27+
28+private Q_SLOTS:
29+
30+ void init()
31+ {
32+ m_accounts = new QDBusInterface(QStringLiteral("org.freedesktop.Accounts"),
33+ QStringLiteral("/org/freedesktop/Accounts"),
34+ QStringLiteral("org.freedesktop.Accounts"),
35+ QDBusConnection::sessionBus());
36+ QDBusReply<bool> addReply = m_accounts->call(QStringLiteral("AddUser"),
37+ g_get_user_name());
38+ QVERIFY(addReply.isValid());
39+ QCOMPARE(addReply.value(), true);
40+
41+ m_user = new QDBusInterface(QStringLiteral("org.freedesktop.Accounts"),
42+ QStringLiteral("/%1").arg(g_get_user_name()),
43+ QStringLiteral("org.freedesktop.DBus.Properties"),
44+ QDBusConnection::sessionBus());
45+
46+ m_model = new QLightDM::UsersModel();
47+ QVERIFY(m_model);
48+ }
49+
50+ void cleanup()
51+ {
52+ QDBusReply<bool> addReply = m_accounts->call(QStringLiteral("RemoveUser"),
53+ g_get_user_name());
54+ QVERIFY(addReply.isValid());
55+ QCOMPARE(addReply.value(), true);
56+
57+ delete m_model;
58+ delete m_accounts;
59+ delete m_user;
60+ }
61+
62+ void testWatchRealName()
63+ {
64+ auto index = m_model->index(0, 0);
65+
66+ QCOMPARE(m_model->data(index, QLightDM::UsersModel::RealNameRole).toString(),
67+ QStringLiteral(""));
68+
69+ // The real AccountsService doesn't let you set via dbus properties. You
70+ // have to call SetRealName instead (so that they can protect the call
71+ // via policykit). But our test server does let us.
72+ QVariant wrapped = QVariant::fromValue(QDBusVariant(QStringLiteral("Test User")));
73+ QDBusReply<void> reply = m_user->call(QStringLiteral("Set"),
74+ QStringLiteral("org.freedesktop.Accounts.User"),
75+ QStringLiteral("RealName"),
76+ wrapped);
77+ QVERIFY(reply.isValid());
78+
79+ QTRY_COMPARE(m_model->data(index, QLightDM::UsersModel::RealNameRole).toString(),
80+ QStringLiteral("Test User"));
81+ }
82+
83+private:
84+ QLightDM::UsersModel *m_model;
85+ QDBusInterface *m_accounts;
86+ QDBusInterface *m_user;
87+};
88+
89+QTEST_MAIN(GreeterIntegratedTest)
90+
91+#include "integrated.moc"