Commit 4fcca5749bbd04aa711628c462ba51a43668b5a4
1 parent
4526f0bd
Fix packet order in subscribing to topic with retained messages
The order packets would (mostly) arrive, is 'retained publish', then 'sub ack'. This is now fixed. This also stablizes test_retained_changed(). The test was also refactored to use the new test client.
Showing
3 changed files
with
45 additions
and
16 deletions
FlashMQTests/tst_maintests.cpp
| ... | ... | @@ -436,27 +436,31 @@ void MainTests::test_retained() |
| 436 | 436 | |
| 437 | 437 | void MainTests::test_retained_changed() |
| 438 | 438 | { |
| 439 | - TwoClientTestContext testContext; | |
| 439 | + FlashMQTestClient sender; | |
| 440 | + sender.start(); | |
| 441 | + sender.connectClient(ProtocolVersion::Mqtt311); | |
| 440 | 442 | |
| 441 | - QByteArray payload = "We are testing"; | |
| 442 | - QString topic = "retaintopic"; | |
| 443 | + const std::string topic = "retaintopic"; | |
| 443 | 444 | |
| 444 | - testContext.connectSender(); | |
| 445 | - testContext.publish(topic, payload, true); | |
| 445 | + Publish p(topic, "We are testing", 0); | |
| 446 | + p.retain = true; | |
| 447 | + sender.publish(p); | |
| 446 | 448 | |
| 447 | - payload = "Changed payload"; | |
| 449 | + p.payload = "Changed payload"; | |
| 450 | + sender.publish(p); | |
| 448 | 451 | |
| 449 | - testContext.publish(topic, payload, true); | |
| 452 | + FlashMQTestClient receiver; | |
| 453 | + receiver.start(); | |
| 454 | + receiver.connectClient(ProtocolVersion::Mqtt5); | |
| 455 | + receiver.subscribe(topic, 0); | |
| 450 | 456 | |
| 451 | - testContext.connectReceiver(); | |
| 452 | - testContext.subscribeReceiver(topic); | |
| 453 | - testContext.waitReceiverReceived(1); | |
| 457 | + receiver.waitForMessageCount(1); | |
| 454 | 458 | |
| 455 | - QCOMPARE(testContext.receivedMessages.count(), 1); | |
| 459 | + MYCASTCOMPARE(receiver.receivedPublishes.size(), 1); | |
| 456 | 460 | |
| 457 | - QMQTT::Message msg = testContext.receivedMessages.first(); | |
| 458 | - QCOMPARE(msg.payload(), payload); | |
| 459 | - QVERIFY(msg.retain()); | |
| 461 | + MqttPacket &pack = receiver.receivedPublishes.front(); | |
| 462 | + QCOMPARE(pack.getPayloadCopy(), p.payload); | |
| 463 | + QVERIFY(pack.getRetain()); | |
| 460 | 464 | } |
| 461 | 465 | |
| 462 | 466 | void MainTests::test_retained_removed() | ... | ... |
mqttpacket.cpp
| ... | ... | @@ -1011,6 +1011,8 @@ void MqttPacket::handleSubscribe() |
| 1011 | 1011 | |
| 1012 | 1012 | Authentication &authentication = *ThreadGlobals::getAuth(); |
| 1013 | 1013 | |
| 1014 | + std::forward_list<SubscriptionTuple> deferredSubscribes; | |
| 1015 | + | |
| 1014 | 1016 | std::list<ReasonCodes> subs_reponse_codes; |
| 1015 | 1017 | while (remainingAfterPos() > 0) |
| 1016 | 1018 | { |
| ... | ... | @@ -1031,8 +1033,7 @@ void MqttPacket::handleSubscribe() |
| 1031 | 1033 | splitTopic(topic, subtopics); |
| 1032 | 1034 | if (authentication.aclCheck(sender->getClientId(), sender->getUsername(), topic, subtopics, AclAccess::subscribe, qos, false, getUserProperties()) == AuthResult::success) |
| 1033 | 1035 | { |
| 1034 | - logger->logf(LOG_SUBSCRIBE, "Client '%s' subscribed to '%s' QoS %d", sender->repr().c_str(), topic.c_str(), qos); | |
| 1035 | - MainApp::getMainApp()->getSubscriptionStore()->addSubscription(sender, topic, subtopics, qos); | |
| 1036 | + deferredSubscribes.emplace_front(topic, subtopics, qos); | |
| 1036 | 1037 | subs_reponse_codes.push_back(static_cast<ReasonCodes>(qos)); |
| 1037 | 1038 | } |
| 1038 | 1039 | else |
| ... | ... | @@ -1054,6 +1055,13 @@ void MqttPacket::handleSubscribe() |
| 1054 | 1055 | SubAck subAck(this->protocolVersion, packet_id, subs_reponse_codes); |
| 1055 | 1056 | MqttPacket response(subAck); |
| 1056 | 1057 | sender->writeMqttPacket(response); |
| 1058 | + | |
| 1059 | + // Adding the subscription will also send publishes for retained messages, so that's why we're doing it at the end. | |
| 1060 | + for(const SubscriptionTuple &tup : deferredSubscribes) | |
| 1061 | + { | |
| 1062 | + logger->logf(LOG_SUBSCRIBE, "Client '%s' subscribed to '%s' QoS %d", sender->repr().c_str(), tup.topic.c_str(), tup.qos); | |
| 1063 | + MainApp::getMainApp()->getSubscriptionStore()->addSubscription(sender, tup.topic, tup.subtopics, tup.qos); | |
| 1064 | + } | |
| 1057 | 1065 | } |
| 1058 | 1066 | |
| 1059 | 1067 | void MqttPacket::handleUnsubscribe() |
| ... | ... | @@ -1804,6 +1812,14 @@ void MqttPacket::readIntoBuf(CirBuf &buf) const |
| 1804 | 1812 | buf.write(bites.data(), bites.size()); |
| 1805 | 1813 | } |
| 1806 | 1814 | |
| 1815 | +SubscriptionTuple::SubscriptionTuple(const std::string &topic, const std::vector<std::string> &subtopics, char qos) : | |
| 1816 | + topic(topic), | |
| 1817 | + subtopics(subtopics), | |
| 1818 | + qos(qos) | |
| 1819 | +{ | |
| 1820 | + | |
| 1821 | +} | |
| 1822 | + | |
| 1807 | 1823 | |
| 1808 | 1824 | |
| 1809 | 1825 | ... | ... |
mqttpacket.h
| ... | ... | @@ -163,4 +163,13 @@ public: |
| 163 | 163 | const std::vector<std::pair<std::string, std::string>> *getUserProperties() const; |
| 164 | 164 | }; |
| 165 | 165 | |
| 166 | +struct SubscriptionTuple | |
| 167 | +{ | |
| 168 | + const std::string topic; | |
| 169 | + const std::vector<std::string> subtopics; | |
| 170 | + const char qos; | |
| 171 | + | |
| 172 | + SubscriptionTuple(const std::string &topic, const std::vector<std::string> &subtopics, char qos); | |
| 173 | +}; | |
| 174 | + | |
| 166 | 175 | #endif // MQTTPACKET_H | ... | ... |