// SPDX-FileCopyrightText: 2023 Tibor Csötönyi // // SPDX-License-Identifier: LGPL-2.1-or-later #include "QXmppClient.h" #include "QXmppConstants_p.h" #include "QXmppJingleMessageInitiationManager.h" #include "QXmppMessage.h" #include "QXmppUtils.h" #include "IntegrationTesting.h" #include "util.h" #include using Jmi = QXmppJingleMessageInitiation; using JmiType = QXmppJingleMessageInitiationElement::Type; using Result = QXmppJingleMessageInitiation::Result; class tst_QXmppJingleMessageInitiationManager : public QObject { Q_OBJECT private: Q_SLOT void initTestCase(); Q_SLOT void testClear(); Q_SLOT void testClearAll(); Q_SLOT void testRing(); Q_SLOT void testProceed(); Q_SLOT void testReject(); Q_SLOT void testRetract(); Q_SLOT void testFinish(); Q_SLOT void testPropose(); Q_SLOT void testSendMessage(); Q_SLOT void testHandleNonExistingSessionLowerId(); Q_SLOT void testHandleNonExistingSessionHigherId(); Q_SLOT void testHandleExistingSession(); Q_SLOT void testHandleTieBreak(); Q_SLOT void testHandleProposeJmiElement(); Q_SLOT void testHandleExistingJmi(); Q_SLOT void testHandleJmiElement(); Q_SLOT void testHandleMessage_data(); Q_SLOT void testHandleMessage(); Q_SLOT void testHandleMessageRinging(); Q_SLOT void testHandleMessageProceeded(); Q_SLOT void testHandleMessageClosedRejected(); Q_SLOT void testHandleMessageClosedRetracted(); Q_SLOT void testHandleMessageClosedFinished(); QXmppClient m_client; QXmppLogger m_logger; QXmppJingleMessageInitiationManager m_manager; }; void tst_QXmppJingleMessageInitiationManager::initTestCase() { m_client.addExtension(&m_manager); m_logger.setLoggingType(QXmppLogger::SignalLogging); m_client.setLogger(&m_logger); m_client.connectToServer(IntegrationTests::clientConfiguration()); qRegisterMetaType(); } void tst_QXmppJingleMessageInitiationManager::testClear() { QCOMPARE(m_manager.jmis().size(), 0); auto jmi1 { m_manager.addJmi("test1") }; auto jmi2 { m_manager.addJmi("test2") }; QCOMPARE(m_manager.jmis().size(), 2); m_manager.clear(jmi1); m_manager.clear(jmi2); QCOMPARE(m_manager.jmis().size(), 0); } void tst_QXmppJingleMessageInitiationManager::testClearAll() { QCOMPARE(m_manager.jmis().size(), 0); m_manager.addJmi("test1"); m_manager.addJmi("test2"); m_manager.addJmi("test3"); m_manager.addJmi("test4"); m_manager.addJmi("test5"); QCOMPARE(m_manager.jmis().size(), 5); m_manager.clearAll(); QCOMPARE(m_manager.jmis().size(), 0); } void tst_QXmppJingleMessageInitiationManager::testRing() { auto jmi { m_manager.addJmi("julietRing@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); connect(&m_logger, &QXmppLogger::message, this, [jmicallPartnerJid = jmi->callPartnerJid()](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmicallPartnerJid) { QVERIFY(message.jingleMessageInitiationElement()); QCOMPARE(message.jingleMessageInitiationElement()->type(), JmiType::Ringing); } } }); auto future = jmi->ring(); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testProceed() { auto jmi { m_manager.addJmi("julietProceed@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); connect(&m_logger, &QXmppLogger::message, this, [jmiCallPartnerJid = jmi->callPartnerJid()](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmiCallPartnerJid) { QVERIFY(message.jingleMessageInitiationElement()); QCOMPARE(message.jingleMessageInitiationElement()->type(), JmiType::Proceed); } } }); auto future = jmi->proceed(); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testReject() { auto jmi { m_manager.addJmi("julietReject@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); QXmppJingleReason reason; reason.setType(QXmppJingleReason::Decline); reason.setText("Declined"); connect(&m_logger, &QXmppLogger::message, this, [jmiCallPartnerJid = jmi->callPartnerJid()](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmiCallPartnerJid) { QVERIFY(message.jingleMessageInitiationElement()); QCOMPARE(message.jingleMessageInitiationElement()->type(), JmiType::Reject); QCOMPARE(message.jingleMessageInitiationElement()->reason()->type(), QXmppJingleReason::Decline); QCOMPARE(message.jingleMessageInitiationElement()->reason()->text(), "Declined"); QCOMPARE(message.jingleMessageInitiationElement()->containsTieBreak(), true); } } }); auto future = jmi->reject(reason, true); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testRetract() { auto jmi { m_manager.addJmi("julietRetract@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); QXmppJingleReason reason; reason.setType(QXmppJingleReason::Gone); reason.setText("Gone"); connect(&m_logger, &QXmppLogger::message, this, [jmicallPartnerJid = jmi->callPartnerJid()](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmicallPartnerJid) { QVERIFY(message.jingleMessageInitiationElement()); QCOMPARE(message.jingleMessageInitiationElement()->type(), JmiType::Retract); QCOMPARE(message.jingleMessageInitiationElement()->reason()->type(), QXmppJingleReason::Gone); QCOMPARE(message.jingleMessageInitiationElement()->reason()->text(), "Gone"); QCOMPARE(message.jingleMessageInitiationElement()->containsTieBreak(), true); } } }); auto future = jmi->retract(reason, true); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testFinish() { auto jmi { m_manager.addJmi("julietFinish@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); QXmppJingleReason reason; reason.setType(QXmppJingleReason::Success); reason.setText("Finished"); connect(&m_logger, &QXmppLogger::message, this, [jmicallPartnerJid = jmi->callPartnerJid()](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmicallPartnerJid) { QVERIFY(message.jingleMessageInitiationElement()); QCOMPARE(message.jingleMessageInitiationElement()->type(), JmiType::Finish); QCOMPARE(message.jingleMessageInitiationElement()->reason()->type(), QXmppJingleReason::Success); QCOMPARE(message.jingleMessageInitiationElement()->reason()->text(), "Finished"); QCOMPARE(message.jingleMessageInitiationElement()->migratedTo(), "fecbea35-08d3-404f-9ec7-2b57c566fa74"); } } }); auto future = jmi->finish(reason, "fecbea35-08d3-404f-9ec7-2b57c566fa74"); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testPropose() { QString jid { "julietPropose@capulet.example" }; QXmppJingleDescription description; description.setMedia(QStringLiteral("audio")); description.setSsrc(123); description.setType(ns_jingle_rtp); connect(&m_logger, &QXmppLogger::message, this, [&, jid, description](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jid) { const auto &jmiElement { message.jingleMessageInitiationElement() }; QVERIFY(jmiElement); QCOMPARE(jmiElement->type(), JmiType::Propose); QVERIFY(!jmiElement->id().isEmpty()); QVERIFY(jmiElement->description()); QCOMPARE(jmiElement->description()->media(), description.media()); QCOMPARE(jmiElement->description()->ssrc(), description.ssrc()); QCOMPARE(jmiElement->description()->type(), description.type()); SKIP_IF_INTEGRATION_TESTS_DISABLED() // verify that the JMI ID has been changed and the JMI was processed QCOMPARE(m_manager.jmis().size(), 1); } } }); auto future = m_manager.propose(jid, description); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testSendMessage() { QString jid { "julietSendMessage@capulet.example" }; QXmppJingleMessageInitiationElement jmiElement; jmiElement.setType(JmiType::Propose); jmiElement.setId(QStringLiteral("fecbea35-08d3-404f-9ec7-2b57c566fa74")); connect(&m_logger, &QXmppLogger::message, this, [jid, jmiElement](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jid) { QVERIFY(message.hasHint(QXmppMessage::Store)); QVERIFY(message.jingleMessageInitiationElement()); QCOMPARE(message.jingleMessageInitiationElement()->type(), jmiElement.type()); } } }); auto future = m_manager.sendMessage(jmiElement, jid); while (!future.isFinished()) { QCoreApplication::processEvents(); } QVERIFY(future.isFinished()); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleNonExistingSessionLowerId() { // --- request with lower id sends propose to request with higher id --- QByteArray xmlProposeLowId { "" "" "" "" "" "" }; auto jmiWithHigherId { m_manager.addJmi("romeoNonExistingSession@montague.example") }; jmiWithHigherId->setId("fecbea35-08d3-404f-9ec7-2b57c566fa74"); QXmppJingleReason reason; reason.setType(QXmppJingleReason::Expired); reason.setText("Tie-Break"); // make sure that request with higher ID is being retracted connect(&m_logger, &QXmppLogger::message, this, [jmiWithHigherId, reason](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmiWithHigherId->callPartnerJid()) { const auto &jmiElement { message.jingleMessageInitiationElement() }; QVERIFY(jmiElement); QCOMPARE(jmiElement->type(), JmiType::Retract); QCOMPARE(jmiElement->id(), "fecbea35-08d3-404f-9ec7-2b57c566fa74"); QVERIFY(jmiElement->reason()); QCOMPARE(jmiElement->reason()->type(), reason.type()); QCOMPARE(jmiElement->reason()->text(), reason.text()); SKIP_IF_INTEGRATION_TESTS_DISABLED() // verify that the JMI ID has been changed and the JMI was processed QCOMPARE(jmiWithHigherId->id(), "ca3cf894-5325-482f-a412-a6e9f832298d"); QVERIFY(jmiWithHigherId->isProceeded()); } } }); QXmppMessage message; message.parse(xmlToDom(xmlProposeLowId)); QVERIFY(m_manager.handleMessage(message)); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleNonExistingSessionHigherId() { // --- request with higher id sends propose to request with lower id --- QByteArray xmlProposeHighId { "" "" "" "" "" "" }; QXmppJingleReason reason; reason.setType(QXmppJingleReason::Expired); reason.setText("Tie-Break"); auto jmiWithLowerId { m_manager.addJmi("julietNonExistingSession@capulet.example") }; jmiWithLowerId->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); // make sure that request with lower id rejects request with higher id connect(&m_logger, &QXmppLogger::message, this, [jid = jmiWithLowerId->callPartnerJid(), reason](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jid) { const auto &jmiElement { message.jingleMessageInitiationElement() }; QVERIFY(jmiElement); QCOMPARE(jmiElement->type(), JmiType::Reject); QCOMPARE(jmiElement->id(), "fecbea35-08d3-404f-9ec7-2b57c566fa74"); QVERIFY(jmiElement->reason()); QCOMPARE(jmiElement->reason()->type(), reason.type()); QCOMPARE(jmiElement->reason()->text(), reason.text()); } } }); QXmppMessage message; message.parse(xmlToDom(xmlProposeHighId)); QVERIFY(m_manager.handleMessage(message)); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleExistingSession() { QXmppMessage message; QByteArray xmlPropose { "" "" "" "" "" "" }; auto jmi { m_manager.addJmi("julietExistingSession@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); jmi->setIsProceeded(true); QXmppJingleReason reason; reason.setType(QXmppJingleReason::Expired); reason.setText("Session migrated"); connect(&m_logger, &QXmppLogger::message, this, [jmi, reason](QXmppLogger::MessageType type, const QString &text) { if (type == QXmppLogger::SentMessage) { QXmppMessage message; parsePacket(message, text.toUtf8()); if (message.to() == jmi->callPartnerJid()) { const auto &jmiElement { message.jingleMessageInitiationElement() }; QVERIFY(jmiElement); QCOMPARE(jmiElement->type(), JmiType::Finish); QCOMPARE(jmiElement->id(), jmi->id()); QCOMPARE(jmiElement->migratedTo(), "989a46a6-f202-4910-a7c3-83c6ba3f3947"); QVERIFY(jmiElement->reason()); QCOMPARE(jmiElement->reason()->type(), reason.type()); QCOMPARE(jmiElement->reason()->text(), reason.text()); } } }); message.parse(xmlToDom(xmlPropose)); QVERIFY(m_manager.handleMessage(message)); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleTieBreak() { QString callPartnerJid { "romeoHandleTieBreakExistingSession@montague.example/orchard" }; QString jmiId { "ca3cf894-5325-482f-a412-a6e9f832298d" }; auto jmi { m_manager.addJmi(QXmppUtils::jidToBareJid(callPartnerJid)) }; jmi->setId(jmiId); QXmppJingleMessageInitiationElement jmiElement; QString newJmiId("989a46a6-f202-4910-a7c3-83c6ba3f3947"); jmiElement.setId(newJmiId); // Cannot use macro SKIP_IF_INTEGRATION_TESTS_DISABLED() here since // this would also skip the manager cleanup. if (IntegrationTests::enabled()) { // --- ensure handleExistingSession --- jmi->setIsProceeded(true); QSignalSpy closedSpy(jmi.get(), &QXmppJingleMessageInitiation::closed); QVERIFY(m_manager.handleTieBreak(jmi, jmiElement, QXmppUtils::jidToResource(callPartnerJid))); QCOMPARE(closedSpy.count(), 1); // --- ensure handleNonExistingSession --- jmi->setIsProceeded(false); QSignalSpy proceededSpy(jmi.get(), &QXmppJingleMessageInitiation::proceeded); QVERIFY(m_manager.handleTieBreak(jmi, jmiElement, QXmppUtils::jidToResource(callPartnerJid))); QCOMPARE(proceededSpy.count(), 1); } m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleProposeJmiElement() { QXmppJingleMessageInitiationElement jmiElement; QXmppJingleDescription description; description.setMedia("audio"); description.setSsrc(321); description.setType("abcd"); jmiElement.setId("ca3cf123-5325-482f-a412-a6e9f832298d"); jmiElement.setDescription(description); QString callPartnerJid { "juliet@capulet.example" }; // --- Tie break --- auto jmi { m_manager.addJmi(callPartnerJid) }; jmi->setId("989a4123-f202-4910-a7c3-83c6ba3f3947"); QVERIFY(m_manager.handleProposeJmiElement(jmiElement, callPartnerJid)); QCOMPARE(m_manager.jmis().size(), 1); m_manager.clearAll(); // --- usual JMI proposal --- connect(&m_manager, &QXmppJingleMessageInitiationManager::proposed, this, [&, jmiElement](const std::shared_ptr &, const QString &jmiElementId, const std::optional &description) { if (jmiElement.id() == jmiElementId) { QCOMPARE(m_manager.jmis().size(), 1); QVERIFY(description.has_value()); QCOMPARE(description->media(), jmiElement.description()->media()); QCOMPARE(description->ssrc(), jmiElement.description()->ssrc()); QCOMPARE(description->type(), jmiElement.description()->type()); } }); callPartnerJid = "romeoHandleProposeJmiElement@montague.example"; QVERIFY(m_manager.handleProposeJmiElement(jmiElement, callPartnerJid)); QCOMPARE(m_manager.jmis().size(), 1); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleExistingJmi() { QString callPartnerJid { "juliet@capulet.example" }; QString jmiId { "989a46a6-f202-4910-a7c3-83c6ba3f3947" }; auto jmi { m_manager.addJmi(callPartnerJid) }; jmi->setId(jmiId); QXmppJingleMessageInitiationElement jmiElement; jmiElement.setId(jmiId); // --- ringing --- QSignalSpy ringingSpy(jmi.get(), &QXmppJingleMessageInitiation::ringing); jmiElement.setType(JmiType::Ringing); QVERIFY(m_manager.handleExistingJmi(jmi, jmiElement, callPartnerJid)); QCOMPARE(ringingSpy.count(), 1); m_manager.clearAll(); // --- proceeded --- jmi = m_manager.addJmi(callPartnerJid); jmi->setId(jmiId); jmiElement.setType(JmiType::Proceed); connect(jmi.get(), &QXmppJingleMessageInitiation::proceeded, this, [jmiElement](const QString &jmiElementId) { if (jmiElementId == jmiElement.id()) { QVERIFY(true); } }); QVERIFY(m_manager.handleExistingJmi(jmi, jmiElement, callPartnerJid)); m_manager.clearAll(); // --- closed: rejected --- jmi = m_manager.addJmi(callPartnerJid); jmi->setId(jmiId); QXmppJingleReason reason; reason.setType(QXmppJingleReason::Expired); reason.setText("Rejected because expired."); jmiElement.setType(JmiType::Reject); jmiElement.setReason(reason); connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [jmiElement](const Result &result) { using ResultType = QXmppJingleMessageInitiation::Rejected; QVERIFY(std::holds_alternative(result)); const ResultType &rejectedJmiElement { std::get(result) }; QVERIFY(rejectedJmiElement.reason); QCOMPARE(rejectedJmiElement.reason->type(), jmiElement.reason()->type()); QCOMPARE(rejectedJmiElement.reason->text(), jmiElement.reason()->text()); QCOMPARE(rejectedJmiElement.containsTieBreak, jmiElement.containsTieBreak()); }); QVERIFY(m_manager.handleExistingJmi(jmi, jmiElement, callPartnerJid)); m_manager.clearAll(); // --- closed: retracted --- jmi = m_manager.addJmi(callPartnerJid); jmi->setId(jmiId); reason.setType(QXmppJingleReason::ConnectivityError); reason.setText("Retracted due to connectivity error."); jmiElement.setType(JmiType::Retract); jmiElement.setReason(reason); connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [jmiElement](const Result &result) { using ResultType = QXmppJingleMessageInitiation::Retracted; QVERIFY(std::holds_alternative(result)); const ResultType &rejectedJmiElement { std::get(result) }; QVERIFY(rejectedJmiElement.reason); QCOMPARE(rejectedJmiElement.reason->type(), jmiElement.reason()->type()); QCOMPARE(rejectedJmiElement.reason->text(), jmiElement.reason()->text()); QCOMPARE(rejectedJmiElement.containsTieBreak, jmiElement.containsTieBreak()); }); QVERIFY(m_manager.handleExistingJmi(jmi, jmiElement, callPartnerJid)); m_manager.clearAll(); // --- closed: finished --- jmi = m_manager.addJmi(callPartnerJid); jmi->setId(jmiId); reason.setType(QXmppJingleReason::Success); reason.setText("Finished."); jmiElement.setType(JmiType::Finish); jmiElement.setReason(reason); jmiElement.setMigratedTo("ca3cf894-5325-482f-a412-a6e9f832298d"); connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [jmiElement](const Result &result) { using ResultType = QXmppJingleMessageInitiation::Finished; QVERIFY(std::holds_alternative(result)); const ResultType &rejectedJmiElement { std::get(result) }; QVERIFY(rejectedJmiElement.reason); QCOMPARE(rejectedJmiElement.reason->type(), jmiElement.reason()->type()); QCOMPARE(rejectedJmiElement.reason->text(), jmiElement.reason()->text()); QCOMPARE(rejectedJmiElement.migratedTo, jmiElement.migratedTo()); }); QVERIFY(m_manager.handleExistingJmi(jmi, jmiElement, callPartnerJid)); m_manager.clearAll(); // --- none --- jmi = m_manager.addJmi(callPartnerJid); jmi->setId(jmiId); jmiElement.setType(JmiType::None); QCOMPARE(m_manager.handleExistingJmi(jmi, jmiElement, callPartnerJid), false); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleJmiElement() { QString callPartnerJid { "romeoHandleJmiElement@montague.example/orchard" }; QString jmiId { "ca3cf894-5325-482f-a412-a6e9f832298d" }; // case 1: no JMI found in JMIs vector and jmiElement is not a propose element QXmppJingleMessageInitiationElement jmiElement; jmiElement.setType(JmiType::None); QCOMPARE(m_manager.handleJmiElement(std::move(jmiElement), {}), false); // case 2: no JMI found in JMIs vector and jmiElement is a propose element jmiElement = {}; jmiElement.setType(JmiType::Propose); jmiElement.setId(jmiId); QSignalSpy proposedSpy(&m_manager, &QXmppJingleMessageInitiationManager::proposed); QVERIFY(m_manager.handleJmiElement(std::move(jmiElement), callPartnerJid)); QCOMPARE(proposedSpy.count(), 1); m_manager.clearAll(); // case 3: JMI found in JMIs vector, existing session jmiElement = {}; jmiElement.setType(JmiType::Ringing); jmiElement.setId(jmiId); auto jmi { m_manager.addJmi(QXmppUtils::jidToBareJid(callPartnerJid)) }; jmi->setId(jmiId); QSignalSpy ringingSpy(jmi.get(), &QXmppJingleMessageInitiation::ringing); QVERIFY(m_manager.handleJmiElement(std::move(jmiElement), callPartnerJid)); QCOMPARE(ringingSpy.count(), 1); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleMessage_data() { QTest::addColumn("xml"); QTest::addColumn("isValid"); QTest::newRow("xmlValid") << QByteArray( "" "" "" "" "" "") << true; QTest::newRow("xmlInvalidTypeNotChat") << QByteArray( "" "" "" "" "" "") << false; QTest::newRow("xmlInvalidNoStore") << QByteArray( "" "" "" "" "") << false; QTest::newRow("xmlInvalidNoJmiElement") << QByteArray("") << false; } void tst_QXmppJingleMessageInitiationManager::testHandleMessage() { QFETCH(QByteArray, xml); QFETCH(bool, isValid); QXmppMessage message; parsePacket(message, xml); QCOMPARE(m_manager.handleMessage(message), isValid); serializePacket(message, xml); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleMessageRinging() { QXmppMessage message; QByteArray xmlRinging { "" "" "" "" }; auto jmi { m_manager.addJmi("juliet@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); QSignalSpy ringingSpy(jmi.get(), &QXmppJingleMessageInitiation::ringing); message.parse(xmlToDom(xmlRinging)); QVERIFY(m_manager.handleMessage(message)); QCOMPARE(ringingSpy.count(), 1); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleMessageProceeded() { QXmppMessage message; QByteArray xmlProceed { "" "" "" "" }; auto jmi { m_manager.addJmi("juliet@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); QSignalSpy proceededSpy(jmi.get(), &QXmppJingleMessageInitiation::proceeded); message.parse(xmlToDom(xmlProceed)); QVERIFY(m_manager.handleMessage(message)); QCOMPARE(proceededSpy.count(), 1); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleMessageClosedRejected() { QXmppMessage message; QByteArray xmlReject { "" "" "" "" "Busy" "" "" "" "" }; auto jmi { m_manager.addJmi("juliet@capulet.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [](const Result &result) { using ResultType = QXmppJingleMessageInitiation::Rejected; QVERIFY(std::holds_alternative(result)); const ResultType &rejectedJmiElement { std::get(result) }; QCOMPARE(rejectedJmiElement.reason->type(), QXmppJingleReason::Busy); QCOMPARE(rejectedJmiElement.reason->text(), "Busy"); }); message.parse(xmlToDom(xmlReject)); QVERIFY(m_manager.handleMessage(message)); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleMessageClosedRetracted() { QXmppMessage message; QByteArray xmlRetract { "" "" "" "" "Retracted" "" "" "" "" }; auto jmi { m_manager.addJmi("romeo@montague.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [](const Result &result) { using ResultType = QXmppJingleMessageInitiation::Retracted; QVERIFY(std::holds_alternative(result)); const ResultType &retractedJmiElement { std::get(result) }; QCOMPARE(retractedJmiElement.reason->type(), QXmppJingleReason::Cancel); QCOMPARE(retractedJmiElement.reason->text(), "Retracted"); }); message.parse(xmlToDom(xmlRetract)); QVERIFY(m_manager.handleMessage(message)); m_manager.clearAll(); } void tst_QXmppJingleMessageInitiationManager::testHandleMessageClosedFinished() { QXmppMessage message; QByteArray xmlFinish { "" "" "" "" "Success" "" "" "" "" "" }; auto jmi { m_manager.addJmi("romeo@montague.example") }; jmi->setId("ca3cf894-5325-482f-a412-a6e9f832298d"); connect(jmi.get(), &QXmppJingleMessageInitiation::closed, this, [](const Result &result) { using ResultType = QXmppJingleMessageInitiation::Finished; QVERIFY(std::holds_alternative(result)); const ResultType &finishedJmiElement { std::get(result) }; QCOMPARE(finishedJmiElement.reason->type(), QXmppJingleReason::Success); QCOMPARE(finishedJmiElement.reason->text(), "Success"); QCOMPARE(finishedJmiElement.migratedTo, "989a46a6-f202-4910-a7c3-83c6ba3f3947"); }); message.parse(xmlToDom(xmlFinish)); QVERIFY(m_manager.handleMessage(message)); m_manager.clearAll(); } QTEST_MAIN(tst_QXmppJingleMessageInitiationManager) #include "tst_qxmppjinglemessageinitiationmanager.moc"