fix(accounts): keep pending values over reads answered before the change lands

pull/18/head
reionwong 3 weeks ago
parent 82672bdc6f
commit e7195ec1ad

@ -2,6 +2,7 @@
#include "usersmodel.h"
#include <QtCore/QProcess>
#include <QtCore/QTimer>
#include <QtDBus/QDBusAbstractAdaptor>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusInterface>
@ -26,6 +27,7 @@ class TestUserAdaptor : public QDBusAbstractAdaptor
Q_PROPERTY(QString UserName READ userName)
Q_PROPERTY(QString RealName READ realName)
Q_PROPERTY(qulonglong Uid READ uid)
Q_PROPERTY(QString Email READ email)
public:
TestUserAdaptor(QObject *parent, const QString &name, qulonglong uid)
@ -38,6 +40,7 @@ public:
QString userName() const { return m_name; }
QString realName() const { return m_realName; }
qulonglong uid() const { return m_uid; }
QString email() const { return m_email; }
public Q_SLOTS:
void SetUserName(const QString &name)
@ -57,12 +60,26 @@ public Q_SLOTS:
m_realName = name;
}
// Answers late, as behind a polkit prompt, and reports an unrelated
// change while the caller waits.
void SetEmail(const QString &address, const QDBusMessage &message)
{
message.setDelayedReply(true);
Q_EMIT Changed();
QTimer::singleShot(300, this, [this, address, message] {
m_email = address;
QDBusConnection::sessionBus().send(message.createReply());
Q_EMIT Changed();
});
}
Q_SIGNALS:
void Changed();
private:
QString m_name;
QString m_realName;
QString m_email;
qulonglong m_uid;
};
@ -379,6 +396,26 @@ private Q_SLOTS:
QCOMPARE(account->realName(), QStringLiteral("Bob Current"));
}
void aPendingChangeOutlastsReadsAnsweredMeanwhile()
{
AccountsManager manager(QDBusConnection::sessionBus());
QSignalSpy cached(&manager, &AccountsManager::userCached);
manager.cacheUser(QStringLiteral("carol"));
QTRY_COMPARE(cached.size(), 1);
UserAccount *account = manager.cachedUser(QStringLiteral("carol"));
QVERIFY(account);
QTRY_COMPARE(account->userName(), QStringLiteral("carol"));
account->setEmail(QStringLiteral("carol@example.org"));
QCOMPARE(account->email(), QStringLiteral("carol@example.org"));
for (int i = 0; i < 6; ++i) {
QTest::qWait(40);
QCOMPARE(account->email(), QStringLiteral("carol@example.org"));
}
QTest::qWait(400);
QCOMPARE(account->email(), QStringLiteral("carol@example.org"));
}
void synchronousQueriesAndCreateDelete()
{
AccountsManager manager(QDBusConnection::sessionBus());

@ -46,6 +46,7 @@ void UserAccount::setObjectPath(const QString &path)
delete d_ptr->service;
d_ptr->objectPath = path;
d_ptr->values.clear();
d_ptr->pendingValues.clear();
d_ptr->values.insert(QStringLiteral("Uid"), path.mid(userPathPrefix.size()).toLongLong());
d_ptr->service = new OrgFreedesktopAccountsUserInterface(serviceName, path,
d_ptr->bus, this);
@ -107,8 +108,12 @@ void UserAccount::refresh()
});
}
void UserAccount::applyValues(const QVariantMap &updated)
void UserAccount::applyValues(const QVariantMap &reply)
{
QVariantMap updated = reply;
for (auto it = d_ptr->pendingValues.cbegin(); it != d_ptr->pendingValues.cend(); ++it)
updated.insert(it.key(), it.value());
const QVariantMap previous = d_ptr->values;
d_ptr->values = updated;
@ -154,11 +159,14 @@ void UserAccount::applyValues(const QVariantMap &updated)
void UserAccount::watch(const QDBusPendingCall &call, void (UserAccount::*notify)(),
bool displayName)
{
++d_ptr->pendingSets;
auto *watcher = new QDBusPendingCallWatcher(call, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this,
[this, notify, displayName](QDBusPendingCallWatcher *finished) {
QDBusPendingReply<> reply = *finished;
finished->deleteLater();
if (--d_ptr->pendingSets == 0)
d_ptr->pendingValues.clear();
if (reply.isError()) {
qWarning("AccountsService update failed: %s",
reply.error().message().toUtf8().constData());
@ -179,6 +187,7 @@ void UserAccount::watch(const QDBusPendingCall &call, void (UserAccount::*notify
void UserAccount::notePendingChange(const char *property, const QVariant &value,
void (UserAccount::*notify)(), bool displayName)
{
d_ptr->pendingValues.insert(QString::fromLatin1(property), value);
d_ptr->values.insert(QString::fromLatin1(property), value);
Q_EMIT (this->*notify)();
if (displayName)

@ -117,7 +117,7 @@ private:
bool displayName = false);
void notePendingChange(const char *property, const QVariant &value,
void (UserAccount::*notify)(), bool displayName = false);
void applyValues(const QVariantMap &updated);
void applyValues(const QVariantMap &reply);
QVariant value(const char *property) const;
UserAccountPrivate *const d_ptr;

@ -17,6 +17,9 @@ public:
QString objectPath;
// Every getter reads from here; GetAll replies fill it asynchronously.
QVariantMap values;
// Values set but not yet confirmed; a GetAll answered meanwhile still has the old ones.
QVariantMap pendingValues;
int pendingSets = 0;
quint64 refreshSerial = 0;
};

Loading…
Cancel
Save