/*
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 .
*/
#include "src/core/core.h"
#include "src/model/friend.h"
#include "src/persistence/offlinemsgengine.h"
#include
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 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{"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"