/* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <memory> #include <vector> #include <boost/bind.hpp> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <Swiften/Client/DummyStanzaChannel.h> #include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/Disco/CapsInfoGenerator.h> #include <Swiften/Disco/CapsProvider.h> #include <Swiften/Disco/EntityCapsManager.h> #include <Swiften/Elements/CapsInfo.h> using namespace Swift; class EntityCapsManagerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(EntityCapsManagerTest); CPPUNIT_TEST(testReceiveKnownHash); CPPUNIT_TEST(testReceiveKnownHashTwiceDoesNotTriggerChange); CPPUNIT_TEST(testReceiveUnknownHashDoesNotTriggerChange); CPPUNIT_TEST(testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps); CPPUNIT_TEST(testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps); CPPUNIT_TEST(testReconnectTriggersChangeAndClearsCaps); CPPUNIT_TEST(testHashAvailable); CPPUNIT_TEST_SUITE_END(); public: void setUp() { crypto = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); stanzaChannel = std::unique_ptr<DummyStanzaChannel>(new DummyStanzaChannel()); capsProvider = std::unique_ptr<DummyCapsProvider>(new DummyCapsProvider()); user1 = JID("user1@bar.com/bla"); discoInfo1 = std::make_shared<DiscoInfo>(); discoInfo1->addFeature("http://swift.im/feature1"); capsInfo1 = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node1.im", crypto.get()).generateCapsInfo(*discoInfo1.get())); capsInfo1alt = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo1.get())); user2 = JID("user2@foo.com/baz"); discoInfo2 = std::make_shared<DiscoInfo>(); discoInfo2->addFeature("http://swift.im/feature2"); capsInfo2 = std::make_shared<CapsInfo>(CapsInfoGenerator("http://node2.im", crypto.get()).generateCapsInfo(*discoInfo2.get())); user3 = JID("user3@foo.com/baz"); legacyCapsInfo = std::make_shared<CapsInfo>("http://swift.im", "ver1", ""); } void testReceiveKnownHash() { std::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1, changes[0]); CPPUNIT_ASSERT_EQUAL(discoInfo1, testling->getCaps(user1)); } void testReceiveKnownHashTwiceDoesNotTriggerChange() { std::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); changes.clear(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); } void testReceiveUnknownHashDoesNotTriggerChange() { std::shared_ptr<EntityCapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); } void testHashAvailable() { std::shared_ptr<EntityCapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; capsProvider->onCapsAvailable(capsInfo1->getVersion()); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1, changes[0]); CPPUNIT_ASSERT_EQUAL(discoInfo1, testling->getCaps(user1)); } void testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps() { std::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); changes.clear(); sendPresenceWithCaps(user1, capsInfo2); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1, changes[0]); CPPUNIT_ASSERT(!testling->getCaps(user1)); } void testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps() { std::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); changes.clear(); sendUnavailablePresence(user1); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1, changes[0]); CPPUNIT_ASSERT(!testling->getCaps(user1)); } void testReconnectTriggersChangeAndClearsCaps() { std::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; capsProvider->caps[capsInfo2->getVersion()] = discoInfo2; sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo2); changes.clear(); stanzaChannel->setAvailable(false); stanzaChannel->setAvailable(true); CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(changes.size())); CPPUNIT_ASSERT_EQUAL(user1, changes[0]); CPPUNIT_ASSERT(!testling->getCaps(user1)); CPPUNIT_ASSERT_EQUAL(user2, changes[1]); CPPUNIT_ASSERT(!testling->getCaps(user2)); } private: std::shared_ptr<EntityCapsManager> createManager() { std::shared_ptr<EntityCapsManager> manager(new EntityCapsManager(capsProvider.get(), stanzaChannel.get())); manager->onCapsChanged.connect(boost::bind(&EntityCapsManagerTest::handleCapsChanged, this, _1)); return manager; } void handleCapsChanged(const JID& jid) { changes.push_back(jid); } void sendPresenceWithCaps(const JID& jid, std::shared_ptr<CapsInfo> caps) { std::shared_ptr<Presence> presence(new Presence()); presence->setFrom(jid); presence->addPayload(caps); stanzaChannel->onPresenceReceived(presence); } void sendUnavailablePresence(const JID& jid) { std::shared_ptr<Presence> presence(new Presence()); presence->setFrom(jid); presence->setType(Presence::Unavailable); stanzaChannel->onPresenceReceived(presence); } private: struct DummyCapsProvider : public CapsProvider { virtual DiscoInfo::ref getCaps(const std::string& hash) const { std::map<std::string, DiscoInfo::ref>::const_iterator i = caps.find(hash); if (i != caps.end()) { return i->second; } return DiscoInfo::ref(); } std::map<std::string, DiscoInfo::ref> caps; }; private: std::unique_ptr<DummyStanzaChannel> stanzaChannel; std::unique_ptr<DummyCapsProvider> capsProvider; JID user1; std::shared_ptr<DiscoInfo> discoInfo1; std::shared_ptr<CapsInfo> capsInfo1; std::shared_ptr<CapsInfo> capsInfo1alt; JID user2; std::shared_ptr<DiscoInfo> discoInfo2; std::shared_ptr<CapsInfo> capsInfo2; std::shared_ptr<CapsInfo> legacyCapsInfo; JID user3; std::vector<JID> changes; std::shared_ptr<CryptoProvider> crypto; }; CPPUNIT_TEST_SUITE_REGISTRATION(EntityCapsManagerTest);