mirror of https://github.com/qTox/qTox.git
Browse Source
Mick Sayson (3): feat(offlinemsg): Force offline messages to always be enabled refactor(offlinemsg): Decouple OfflineMsgEngine from other components feat(offlinemsg): Enable offline messages with no historyreviewable/pr5695/r1
14 changed files with 401 additions and 122 deletions
@ -0,0 +1,36 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2019 by The qTox Project Contributors |
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 3 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef ICORE_FRIEND_MESSAGE_SENDER_H |
||||||
|
#define ICORE_FRIEND_MESSAGE_SENDER_H |
||||||
|
|
||||||
|
#include "receiptnum.h" |
||||||
|
|
||||||
|
#include <QString> |
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
class ICoreFriendMessageSender |
||||||
|
{ |
||||||
|
public: |
||||||
|
virtual bool sendAction(uint32_t friendId, const QString& action, ReceiptNum& receipt) = 0; |
||||||
|
virtual bool sendMessage(uint32_t friendId, const QString& message, ReceiptNum& receipt) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
#endif /* ICORE_FRIEND_MESSAGE_SENDER_H */ |
@ -0,0 +1,31 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2019 by The qTox Project Contributors |
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 3 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef RECEIPT_NUM_H |
||||||
|
#define RECEIPT_NUM_H |
||||||
|
|
||||||
|
#include "src/util/strongtype.h" |
||||||
|
|
||||||
|
#include <QMetaType> |
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
using ReceiptNum = NamedType<uint32_t, struct ReceiptNumTag>; |
||||||
|
Q_DECLARE_METATYPE(ReceiptNum); |
||||||
|
|
||||||
|
#endif /* RECEIPT_NUM_H */ |
@ -0,0 +1,33 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2019 by The qTox Project Contributors |
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 3 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef MESSAGE_H |
||||||
|
#define MESSAGE_H |
||||||
|
|
||||||
|
#include <QDateTime> |
||||||
|
#include <QString> |
||||||
|
|
||||||
|
struct Message |
||||||
|
{ |
||||||
|
bool isAction; |
||||||
|
QString content; |
||||||
|
QDateTime timestamp; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif /*MESSAGE_H*/ |
@ -0,0 +1,193 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2019 by The qTox Project Contributors |
||||||
|
|
||||||
|
This file is part of qTox, a Qt-based graphical interface for Tox. |
||||||
|
|
||||||
|
qTox is libre software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 3 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
|
||||||
|
qTox is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/core.h" |
||||||
|
#include "src/model/friend.h" |
||||||
|
#include "src/persistence/offlinemsgengine.h" |
||||||
|
|
||||||
|
#include <QtTest/QtTest> |
||||||
|
|
||||||
|
struct MockFriendMessageSender : public QObject, public ICoreFriendMessageSender |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
public: |
||||||
|
MockFriendMessageSender(Friend* f) |
||||||
|
: f(f){}; |
||||||
|
bool sendAction(uint32_t friendId, const QString& action, ReceiptNum& receipt) override |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
bool sendMessage(uint32_t friendId, const QString& message, ReceiptNum& receipt) override |
||||||
|
{ |
||||||
|
if (f->isOnline()) { |
||||||
|
receipt.get() = receiptNum++; |
||||||
|
if (!dropReceipts) { |
||||||
|
msgs.push_back(message); |
||||||
|
emit receiptReceived(receipt); |
||||||
|
} |
||||||
|
numMessagesSent++; |
||||||
|
} else { |
||||||
|
numMessagesFailed++; |
||||||
|
} |
||||||
|
return f->isOnline(); |
||||||
|
} |
||||||
|
|
||||||
|
signals: |
||||||
|
void receiptReceived(ReceiptNum receipt); |
||||||
|
|
||||||
|
public: |
||||||
|
Friend* f; |
||||||
|
bool dropReceipts = false; |
||||||
|
size_t numMessagesSent = 0; |
||||||
|
size_t numMessagesFailed = 0; |
||||||
|
int receiptNum = 0; |
||||||
|
std::vector<QString> msgs; |
||||||
|
}; |
||||||
|
|
||||||
|
class TestOfflineMsgEngine : public QObject |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
private slots: |
||||||
|
void testReceiptResolution(); |
||||||
|
void testOfflineFriend(); |
||||||
|
void testSentUnsentCoordination(); |
||||||
|
void testCallback(); |
||||||
|
}; |
||||||
|
|
||||||
|
class OfflineMsgEngineFixture |
||||||
|
{ |
||||||
|
public: |
||||||
|
OfflineMsgEngineFixture() |
||||||
|
: f(0, ToxPk(QByteArray(32, 0))) |
||||||
|
, friendMessageSender(&f) |
||||||
|
, offlineMsgEngine(&f, &friendMessageSender) |
||||||
|
{ |
||||||
|
f.setStatus(Status::Status::Online); |
||||||
|
QObject::connect(&friendMessageSender, &MockFriendMessageSender::receiptReceived, |
||||||
|
&offlineMsgEngine, &OfflineMsgEngine::onReceiptReceived); |
||||||
|
} |
||||||
|
|
||||||
|
Friend f; |
||||||
|
MockFriendMessageSender friendMessageSender; |
||||||
|
OfflineMsgEngine offlineMsgEngine; |
||||||
|
}; |
||||||
|
|
||||||
|
void completionFn() {} |
||||||
|
|
||||||
|
void TestOfflineMsgEngine::testReceiptResolution() |
||||||
|
{ |
||||||
|
OfflineMsgEngineFixture fixture; |
||||||
|
|
||||||
|
Message msg{false, QString(), QDateTime()}; |
||||||
|
|
||||||
|
ReceiptNum receipt; |
||||||
|
fixture.friendMessageSender.sendMessage(0, msg.content, receipt); |
||||||
|
fixture.offlineMsgEngine.addSentMessage(receipt, msg, completionFn); |
||||||
|
|
||||||
|
// We should have no offline messages to deliver if we resolved our receipt
|
||||||
|
// correctly
|
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
|
||||||
|
QVERIFY(fixture.friendMessageSender.numMessagesSent == 1); |
||||||
|
|
||||||
|
// If we drop receipts we should keep trying to send messages every time we
|
||||||
|
// "deliverOfflineMsgs"
|
||||||
|
fixture.friendMessageSender.dropReceipts = true; |
||||||
|
fixture.friendMessageSender.sendMessage(0, msg.content, receipt); |
||||||
|
fixture.offlineMsgEngine.addSentMessage(receipt, msg, completionFn); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
|
||||||
|
QVERIFY(fixture.friendMessageSender.numMessagesSent == 5); |
||||||
|
|
||||||
|
// And once we stop dropping and try one more time we should run out of
|
||||||
|
// messages to send again
|
||||||
|
fixture.friendMessageSender.dropReceipts = false; |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
QVERIFY(fixture.friendMessageSender.numMessagesSent == 6); |
||||||
|
} |
||||||
|
|
||||||
|
void TestOfflineMsgEngine::testOfflineFriend() |
||||||
|
{ |
||||||
|
OfflineMsgEngineFixture fixture; |
||||||
|
|
||||||
|
Message msg{false, QString(), QDateTime()}; |
||||||
|
|
||||||
|
fixture.f.setStatus(Status::Status::Offline); |
||||||
|
|
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
|
||||||
|
fixture.f.setStatus(Status::Status::Online); |
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
|
||||||
|
|
||||||
|
QVERIFY(fixture.friendMessageSender.numMessagesFailed == 0); |
||||||
|
QVERIFY(fixture.friendMessageSender.numMessagesSent == 5); |
||||||
|
} |
||||||
|
|
||||||
|
void TestOfflineMsgEngine::testSentUnsentCoordination() |
||||||
|
{ |
||||||
|
OfflineMsgEngineFixture fixture; |
||||||
|
Message msg{false, QString("a"), QDateTime()}; |
||||||
|
ReceiptNum receipt; |
||||||
|
|
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
msg.content = "b"; |
||||||
|
fixture.friendMessageSender.dropReceipts = true; |
||||||
|
fixture.friendMessageSender.sendMessage(0, msg.content, receipt); |
||||||
|
fixture.friendMessageSender.dropReceipts = false; |
||||||
|
fixture.offlineMsgEngine.addSentMessage(receipt, msg, completionFn); |
||||||
|
msg.content = "c"; |
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, completionFn); |
||||||
|
|
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
|
||||||
|
auto expectedResponseOrder = std::vector<QString>{"a", "b", "c"}; |
||||||
|
QVERIFY(fixture.friendMessageSender.msgs == expectedResponseOrder); |
||||||
|
} |
||||||
|
|
||||||
|
void TestOfflineMsgEngine::testCallback() |
||||||
|
{ |
||||||
|
OfflineMsgEngineFixture fixture; |
||||||
|
|
||||||
|
size_t numCallbacks = 0; |
||||||
|
auto callback = [&numCallbacks] { numCallbacks++; }; |
||||||
|
Message msg{false, QString(), QDateTime()}; |
||||||
|
ReceiptNum receipt; |
||||||
|
|
||||||
|
fixture.friendMessageSender.sendMessage(0, msg.content, receipt); |
||||||
|
fixture.offlineMsgEngine.addSentMessage(receipt, msg, callback); |
||||||
|
fixture.offlineMsgEngine.addUnsentMessage(msg, callback); |
||||||
|
|
||||||
|
fixture.offlineMsgEngine.deliverOfflineMsgs(); |
||||||
|
QVERIFY(numCallbacks == 2); |
||||||
|
} |
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(TestOfflineMsgEngine) |
||||||
|
#include "offlinemsgengine_test.moc" |
Loading…
Reference in new issue