/* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <vector> #include <boost/bind.hpp> #include <Swiften/Disco/CapsManager.h> #include <Swiften/Disco/CapsMemoryStorage.h> #include <Swiften/Disco/CapsInfoGenerator.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Elements/CapsInfo.h> #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; class CapsManagerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CapsManagerTest); CPPUNIT_TEST(testReceiveNewHashRequestsDisco); CPPUNIT_TEST(testReceiveSameHashDoesNotRequestDisco); CPPUNIT_TEST(testReceiveLegacyCapsDoesNotRequestDisco); CPPUNIT_TEST(testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco); CPPUNIT_TEST(testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco); CPPUNIT_TEST(testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco); CPPUNIT_TEST(testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco); CPPUNIT_TEST(testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco); CPPUNIT_TEST(testReceiveSuccesfulDiscoStoresCaps); CPPUNIT_TEST(testReceiveIncorrectVerificationDiscoDoesNotStoreCaps); CPPUNIT_TEST(testReceiveFailingDiscoFallsBack); CPPUNIT_TEST(testReceiveNoDiscoFallsBack); CPPUNIT_TEST(testReceiveFailingFallbackDiscoFallsBack); CPPUNIT_TEST(testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco); CPPUNIT_TEST(testReconnectResetsFallback); CPPUNIT_TEST(testReconnectResetsRequests); CPPUNIT_TEST_SUITE_END(); public: void setUp() { stanzaChannel = new DummyStanzaChannel(); iqRouter = new IQRouter(stanzaChannel); storage = new CapsMemoryStorage(); user1 = JID("user1@bar.com/bla"); discoInfo1 = boost::make_shared<DiscoInfo>(); discoInfo1->addFeature("http://swift.im/feature1"); capsInfo1 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im").generateCapsInfo(*discoInfo1.get())); capsInfo1alt = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im").generateCapsInfo(*discoInfo1.get())); user2 = JID("user2@foo.com/baz"); discoInfo2 = boost::make_shared<DiscoInfo>(); discoInfo2->addFeature("http://swift.im/feature2"); capsInfo2 = boost::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im").generateCapsInfo(*discoInfo2.get())); user3 = JID("user3@foo.com/baz"); legacyCapsInfo = boost::make_shared<CapsInfo>("http://swift.im", "ver1", ""); } void tearDown() { delete storage; delete iqRouter; delete stanzaChannel; } void testReceiveNewHashRequestsDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get)); boost::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[0]->getPayload<DiscoInfo>()); CPPUNIT_ASSERT(discoInfo); CPPUNIT_ASSERT_EQUAL("http://node1.im#" + capsInfo1->getVersion(), discoInfo->getNode()); } void testReceiveSameHashDoesNotRequestDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReceiveLegacyCapsDoesNotRequestDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, legacyCapsInfo); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo1); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID())); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReceiveSameHashFromSameUserAfterIncorrectVerificationDoesNotRequestDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo2); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user2, capsInfo1); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user2, IQ::Get)); } void testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo2); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user2, capsInfo1); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user2, IQ::Get)); } void testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID())); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo2); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get)); } void testReceiveSuccesfulDiscoStoresCaps() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo1); boost::shared_ptr<DiscoInfo> discoInfo(storage->getDiscoInfo(capsInfo1->getVersion())); CPPUNIT_ASSERT(discoInfo); CPPUNIT_ASSERT(discoInfo->hasFeature("http://swift.im/feature1")); } void testReceiveIncorrectVerificationDiscoDoesNotStoreCaps() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo2); boost::shared_ptr<DiscoInfo> discoInfo(storage->getDiscoInfo(capsInfo1->getVersion())); CPPUNIT_ASSERT(!discoInfo); } void testReceiveFailingDiscoFallsBack() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(1, user2, IQ::Get)); boost::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[1]->getPayload<DiscoInfo>()); CPPUNIT_ASSERT(discoInfo); CPPUNIT_ASSERT_EQUAL("http://node2.im#" + capsInfo1alt->getVersion(), discoInfo->getNode()); } void testReceiveNoDiscoFallsBack() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), boost::shared_ptr<DiscoInfo>())); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(1, user2, IQ::Get)); boost::shared_ptr<DiscoInfo> discoInfo(stanzaChannel->sentStanzas[1]->getPayload<DiscoInfo>()); CPPUNIT_ASSERT(discoInfo); CPPUNIT_ASSERT_EQUAL("http://node2.im#" + capsInfo1alt->getVersion(), discoInfo->getNode()); } void testReceiveFailingFallbackDiscoFallsBack() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); sendPresenceWithCaps(user3, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[1]->getTo(), stanzaChannel->sentStanzas[1]->getID())); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(2, user3, IQ::Get)); } void testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); stanzaChannel->setAvailable(false); stanzaChannel->setAvailable(true); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get)); } void testReconnectResetsFallback() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); stanzaChannel->setAvailable(false); stanzaChannel->setAvailable(true); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReconnectResetsRequests() { boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->sentStanzas.clear(); stanzaChannel->setAvailable(false); stanzaChannel->setAvailable(true); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get)); } private: boost::shared_ptr<CapsManager> createManager() { boost::shared_ptr<CapsManager> manager(new CapsManager(storage, stanzaChannel, iqRouter)); manager->setWarnOnInvalidHash(false); //manager->onCapsChanged.connect(boost::bind(&CapsManagerTest::handleCapsChanged, this, _1)); return manager; } void handleCapsChanged(const JID& jid) { changes.push_back(jid); } void sendPresenceWithCaps(const JID& jid, boost::shared_ptr<CapsInfo> caps) { boost::shared_ptr<Presence> presence(new Presence()); presence->setFrom(jid); presence->addPayload(caps); stanzaChannel->onPresenceReceived(presence); } void sendDiscoInfoResult(boost::shared_ptr<DiscoInfo> discoInfo) { stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), discoInfo)); } private: DummyStanzaChannel* stanzaChannel; IQRouter* iqRouter; CapsStorage* storage; std::vector<JID> changes; JID user1; boost::shared_ptr<DiscoInfo> discoInfo1; boost::shared_ptr<CapsInfo> capsInfo1; boost::shared_ptr<CapsInfo> capsInfo1alt; JID user2; boost::shared_ptr<DiscoInfo> discoInfo2; boost::shared_ptr<CapsInfo> capsInfo2; boost::shared_ptr<CapsInfo> legacyCapsInfo; JID user3; }; CPPUNIT_TEST_SUITE_REGISTRATION(CapsManagerTest);