Commit 0262ae005d9d197aaff285737300970fdbc1152c

Authored by Wiebe Cazemier
1 parent 121e04de

Retained messages tests, plus fix

FlashMQTests/FlashMQTests.pro
1 1 QT += testlib
2 2 QT -= gui
3   -Qt += network
  3 +QT += network
  4 +QT += qmqtt
4 5  
5 6 DEFINES += TESTING
6 7  
... ... @@ -12,7 +13,34 @@ CONFIG -= app_bundle
12 13 TEMPLATE = app
13 14  
14 15 SOURCES += tst_maintests.cpp \
15   - ../cirbuf.cpp
  16 + ../MqttPacket.cpp \
  17 + ../cirbuf.cpp \
  18 + ../client.cpp \
  19 + ../exceptions.cpp \
  20 + ../mainapp.cpp \
  21 + ../mqttpacket.cpp \
  22 + ../retainedmessage.cpp \
  23 + ../rwlockguard.cpp \
  24 + ../subscriptionstore.cpp \
  25 + ../threaddata.cpp \
  26 + ../types.cpp \
  27 + ../utils.cpp \
  28 + mainappthread.cpp \
  29 + twoclienttestcontext.cpp
  30 +
16 31  
17 32 HEADERS += \
18   - ../cirbuf.h
  33 + ../cirbuf.h \
  34 + ../client.h \
  35 + ../exceptions.h \
  36 + ../forward_declarations.h \
  37 + ../mainapp.h \
  38 + ../mqttpacket.h \
  39 + ../retainedmessage.h \
  40 + ../rwlockguard.h \
  41 + ../subscriptionstore.h \
  42 + ../threaddata.h \
  43 + ../types.h \
  44 + ../utils.h \
  45 + mainappthread.h \
  46 + twoclienttestcontext.h
... ...
FlashMQTests/mainappthread.cpp 0 โ†’ 100644
  1 +#include "mainappthread.h"
  2 +
  3 +MainAppThread::MainAppThread(QObject *parent) : QThread(parent)
  4 +{
  5 + appInstance = MainApp::getMainApp();
  6 +}
  7 +
  8 +void MainAppThread::run()
  9 +{
  10 + appInstance->start();
  11 +}
  12 +
  13 +void MainAppThread::stopApp()
  14 +{
  15 + appInstance->quit();
  16 +}
  17 +
  18 +void MainAppThread::waitForStarted()
  19 +{
  20 + int n = 0;
  21 + while(!appInstance->getStarted())
  22 + {
  23 + QThread::msleep(10);
  24 +
  25 + if (n++ > 500)
  26 + throw new std::runtime_error("Waiting for app to start failed.");
  27 + }
  28 +}
... ...
FlashMQTests/mainappthread.h 0 โ†’ 100644
  1 +#ifndef MAINAPPTHREAD_H
  2 +#define MAINAPPTHREAD_H
  3 +
  4 +#include <QObject>
  5 +#include <QThread>
  6 +#include <mainapp.h>
  7 +
  8 +class MainAppThread : public QThread
  9 +{
  10 + Q_OBJECT
  11 + MainApp *appInstance = nullptr;
  12 +public:
  13 + explicit MainAppThread(QObject *parent = nullptr);
  14 +
  15 +public slots:
  16 + void run() override;
  17 + void stopApp();
  18 + void waitForStarted();
  19 +
  20 +signals:
  21 +
  22 +};
  23 +
  24 +#endif // MAINAPPTHREAD_H
... ...
FlashMQTests/tst_maintests.cpp
1 1 #include <QtTest>
2 2  
  3 +
  4 +#include <QtQmqtt/qmqtt.h>
  5 +#include <QScopedPointer>
  6 +#include <QHostInfo>
  7 +
3 8 #include "cirbuf.h"
  9 +#include "mainapp.h"
  10 +#include "mainappthread.h"
  11 +#include "twoclienttestcontext.h"
4 12  
5 13 class MainTests : public QObject
6 14 {
7 15 Q_OBJECT
8 16  
  17 + MainAppThread mainApp;
  18 +
9 19 public:
10 20 MainTests();
11 21 ~MainTests();
12 22  
13 23 private slots:
14   - void test_case1();
  24 + void cleanupTestCase();
  25 +
15 26 void test_circbuf();
16 27 void test_circbuf_unwrapped_doubling();
17 28 void test_circbuf_wrapped_doubling();
18 29 void test_circbuf_full_wrapped_buffer_doubling();
19 30  
  31 + void test_retained();
  32 + void test_retained_changed();
  33 + void test_retained_removed();
  34 +
20 35 };
21 36  
22 37 MainTests::MainTests()
23 38 {
24   -
  39 + mainApp.start();
  40 + mainApp.waitForStarted();
25 41 }
26 42  
27 43 MainTests::~MainTests()
... ... @@ -29,9 +45,9 @@ MainTests::~MainTests()
29 45  
30 46 }
31 47  
32   -void MainTests::test_case1()
  48 +void MainTests::cleanupTestCase()
33 49 {
34   -
  50 + mainApp.stopApp();
35 51 }
36 52  
37 53 void MainTests::test_circbuf()
... ... @@ -243,6 +259,85 @@ void MainTests::test_circbuf_full_wrapped_buffer_doubling()
243 259 QVERIFY(true);
244 260 }
245 261  
246   -QTEST_APPLESS_MAIN(MainTests)
  262 +void MainTests::test_retained()
  263 +{
  264 + TwoClientTestContext testContext;
  265 +
  266 + QByteArray payload = "We are testing";
  267 + QString topic = "retaintopic";
  268 +
  269 + testContext.connectSender();
  270 + testContext.publishRetained(topic, payload);
  271 + testContext.publishRetained("dummy2", "Nobody sees this");
  272 +
  273 + testContext.connectReceiver();
  274 + testContext.subscribeReceiver("dummy");
  275 + testContext.subscribeReceiver(topic);
  276 + testContext.waitReceiverReceived();
  277 +
  278 + QVERIFY2(testContext.receivedMessages.count() == 1, "There must be one message in the received list");
  279 +
  280 + QMQTT::Message msg = testContext.receivedMessages.first();
  281 + QCOMPARE(msg.payload(), payload);
  282 + QVERIFY(msg.retain());
  283 +
  284 + testContext.receivedMessages.clear();
  285 +
  286 + testContext.publishRetained(topic, payload);
  287 + testContext.waitReceiverReceived();
  288 +
  289 + QVERIFY2(testContext.receivedMessages.count() == 1, "There must be one message in the received list");
  290 + QMQTT::Message msg2 = testContext.receivedMessages.first();
  291 + QCOMPARE(msg2.payload(), payload);
  292 + QVERIFY2(!msg2.retain(), "Getting a retained message while already being subscribed must be marked as normal, not retain.");
  293 +}
  294 +
  295 +void MainTests::test_retained_changed()
  296 +{
  297 + TwoClientTestContext testContext;
  298 +
  299 + QByteArray payload = "We are testing";
  300 + QString topic = "retaintopic";
  301 +
  302 + testContext.connectSender();
  303 + testContext.publishRetained(topic, payload);
  304 +
  305 + payload = "Changed payload";
  306 +
  307 + testContext.publishRetained(topic, payload);
  308 +
  309 + testContext.connectReceiver();
  310 + testContext.subscribeReceiver(topic);
  311 + testContext.waitReceiverReceived();
  312 +
  313 + QVERIFY2(testContext.receivedMessages.count() == 1, "There must be one message in the received list");
  314 +
  315 + QMQTT::Message msg = testContext.receivedMessages.first();
  316 + QCOMPARE(msg.payload(), payload);
  317 + QVERIFY(msg.retain());
  318 +}
  319 +
  320 +void MainTests::test_retained_removed()
  321 +{
  322 + TwoClientTestContext testContext;
  323 +
  324 + QByteArray payload = "We are testing";
  325 + QString topic = "retaintopic";
  326 +
  327 + testContext.connectSender();
  328 + testContext.publishRetained(topic, payload);
  329 +
  330 + payload = "";
  331 +
  332 + testContext.publishRetained(topic, payload);
  333 +
  334 + testContext.connectReceiver();
  335 + testContext.subscribeReceiver(topic);
  336 + testContext.waitReceiverReceived();
  337 +
  338 + QVERIFY2(testContext.receivedMessages.empty(), "We erased the retained message. We shouldn't have received any.");
  339 +}
  340 +
  341 +QTEST_GUILESS_MAIN(MainTests)
247 342  
248 343 #include "tst_maintests.moc"
... ...
FlashMQTests/twoclienttestcontext.cpp 0 โ†’ 100644
  1 +#include "twoclienttestcontext.h"
  2 +
  3 +#include <QEventLoop>
  4 +#include <QTimer>
  5 +
  6 +TwoClientTestContext::TwoClientTestContext(QObject *parent) : QObject(parent)
  7 +{
  8 + QHostInfo targetHostInfo = QHostInfo::fromName("localhost");
  9 + QHostAddress targetHost(targetHostInfo.addresses().first());
  10 + sender.reset(new QMQTT::Client(targetHost));
  11 + receiver.reset(new QMQTT::Client(targetHost));
  12 +}
  13 +
  14 +void TwoClientTestContext::publishRetained(const QString &topic, const QByteArray &payload)
  15 +{
  16 + QMQTT::Message msg;
  17 + msg.setTopic(topic);
  18 + msg.setRetain(true);
  19 + msg.setQos(0);
  20 + msg.setPayload(payload);
  21 + sender->publish(msg);
  22 +}
  23 +
  24 +void TwoClientTestContext::connectSender()
  25 +{
  26 + sender->connectToHost();
  27 + QEventLoop waiter;
  28 + connect(sender.data(), &QMQTT::Client::connected, &waiter, &QEventLoop::quit);
  29 + waiter.exec();
  30 +}
  31 +
  32 +void TwoClientTestContext::connectReceiver()
  33 +{
  34 + connect(receiver.data(), &QMQTT::Client::received, this, &TwoClientTestContext::onReceiverReceived);
  35 +
  36 + receiver->connectToHost();
  37 + QEventLoop waiter;
  38 + connect(receiver.data(), &QMQTT::Client::connected, &waiter, &QEventLoop::quit);
  39 + waiter.exec();
  40 +}
  41 +
  42 +void TwoClientTestContext::disconnectReceiver()
  43 +{
  44 + receiver->disconnectFromHost();
  45 + QEventLoop waiter;
  46 + connect(sender.data(), &QMQTT::Client::disconnected, &waiter, &QEventLoop::quit);
  47 + waiter.exec();
  48 +}
  49 +
  50 +void TwoClientTestContext::subscribeReceiver(const QString &topic)
  51 +{
  52 + receiver->subscribe(topic);
  53 +}
  54 +
  55 +void TwoClientTestContext::waitReceiverReceived()
  56 +{
  57 + QEventLoop waiter;
  58 + QTimer timeout;
  59 + timeout.setSingleShot(true);
  60 + timeout.setInterval(1000);
  61 + connect(&timeout, &QTimer::timeout, &waiter, &QEventLoop::quit);
  62 + connect(receiver.data(), &QMQTT::Client::received, &waiter, &QEventLoop::quit);
  63 + timeout.start();
  64 + waiter.exec();
  65 +}
  66 +
  67 +void TwoClientTestContext::onReceiverReceived(const QMQTT::Message &message)
  68 +{
  69 + receivedMessages.append(message);
  70 +}
... ...
FlashMQTests/twoclienttestcontext.h 0 โ†’ 100644
  1 +#ifndef RETAINTESTCONTEXT_H
  2 +#define RETAINTESTCONTEXT_H
  3 +
  4 +#include <QObject>
  5 +#include <QtQmqtt/qmqtt.h>
  6 +#include <QHostInfo>
  7 +
  8 +class TwoClientTestContext : public QObject
  9 +{
  10 + Q_OBJECT
  11 +
  12 + QScopedPointer<QMQTT::Client> sender;
  13 + QScopedPointer<QMQTT::Client> receiver;
  14 +
  15 +private slots:
  16 + void onReceiverReceived(const QMQTT::Message& message);
  17 +
  18 +public:
  19 + explicit TwoClientTestContext(QObject *parent = nullptr);
  20 + void publishRetained(const QString &topic, const QByteArray &payload);
  21 + void connectSender();
  22 + void connectReceiver();
  23 + void disconnectReceiver();
  24 + void subscribeReceiver(const QString &topic);
  25 + void waitReceiverReceived();
  26 +
  27 + QList<QMQTT::Message> receivedMessages;
  28 +
  29 +signals:
  30 +
  31 +};
  32 +
  33 +#endif // RETAINTESTCONTEXT_H
... ...
mainapp.cpp
... ... @@ -171,6 +171,7 @@ void MainApp::start()
171 171  
172 172 uint next_thread_index = 0;
173 173  
  174 + started = true;
174 175 while (running)
175 176 {
176 177 int num_fds = epoll_wait(epoll_fd_accept, events, MAX_EVENTS, 100);
... ...
mainapp.h
... ... @@ -21,6 +21,7 @@ class MainApp
21 21 {
22 22 static MainApp *instance;
23 23  
  24 + bool started = false;
24 25 bool running = true;
25 26 std::vector<std::shared_ptr<ThreadData>> threads;
26 27 std::shared_ptr<SubscriptionStore> subscriptionStore;
... ... @@ -32,6 +33,7 @@ public:
32 33 static MainApp *getMainApp();
33 34 void start();
34 35 void quit();
  36 + bool getStarted() const {return started;}
35 37 };
36 38  
37 39 #endif // MAINAPP_H
... ...
subscriptionstore.cpp
... ... @@ -148,6 +148,9 @@ void SubscriptionStore::setRetainedMessage(const std::string &amp;topic, const std::
148 148 return;
149 149 }
150 150  
  151 + if (retained_found)
  152 + retainedMessages.erase(rm);
  153 +
151 154 retainedMessages.insert(std::move(rm));
152 155 }
153 156  
... ...