/* * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace Swift; class ConnectorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ConnectorTest); CPPUNIT_TEST(testConnect); CPPUNIT_TEST(testConnect_NoServiceLookups); CPPUNIT_TEST(testConnect_NoServiceLookups_DefaultPort); CPPUNIT_TEST(testConnect_OnlyLiteral); CPPUNIT_TEST(testConnect_FirstAddressHostFails); CPPUNIT_TEST(testConnect_NoSRVHost); CPPUNIT_TEST(testConnect_NoHosts); CPPUNIT_TEST(testConnect_FirstSRVHostFails); CPPUNIT_TEST(testConnect_AllSRVHostsFailWithoutFallbackHost); CPPUNIT_TEST(testConnect_AllSRVHostsFailWithFallbackHost); CPPUNIT_TEST(testConnect_SRVAndFallbackHostsFail); //CPPUNIT_TEST(testConnect_TimeoutDuringResolve); CPPUNIT_TEST(testConnect_TimeoutDuringConnectToOnlyCandidate); CPPUNIT_TEST(testConnect_TimeoutDuringConnectToCandidateFallsBack); CPPUNIT_TEST(testConnect_NoTimeout); CPPUNIT_TEST(testStop_DuringSRVQuery); CPPUNIT_TEST(testStop_Timeout); CPPUNIT_TEST_SUITE_END(); public: void setUp() { host1 = HostAddressPort(HostAddress::fromString("1.1.1.1").get(), 1234); host2 = HostAddressPort(HostAddress::fromString("2.2.2.2").get(), 2345); host3 = HostAddressPort(HostAddress::fromString("3.3.3.3").get(), 5222); eventLoop = new DummyEventLoop(); resolver = new StaticDomainNameResolver(eventLoop); connectionFactory = new MockConnectionFactory(eventLoop); timerFactory = new DummyTimerFactory(); } void tearDown() { delete timerFactory; delete connectionFactory; delete resolver; delete eventLoop; } void testConnect() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host1 == *(connections[0]->hostAddressPort)); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_NoServiceLookups() { Connector::ref testling(createConnector(4321, boost::optional())); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); CPPUNIT_ASSERT(4321 == (*(connections[0]->hostAddressPort)).getPort()); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_NoServiceLookups_DefaultPort() { Connector::ref testling(createConnector(0, boost::optional())); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3.getAddress() == (*(connections[0]->hostAddressPort)).getAddress()); CPPUNIT_ASSERT_EQUAL(static_cast(5222), (*(connections[0]->hostAddressPort)).getPort()); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_NoSRVHost() { Connector::ref testling(createConnector()); resolver->addAddress("foo.com", host3.getAddress()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_OnlyLiteral() { auto testling = Connector::create("1.1.1.1", 1234, boost::none, resolver, connectionFactory, timerFactory); testling->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); auto address1 = HostAddress::fromString("1.1.1.1").get(); connectionFactory->failingPorts.push_back(HostAddressPort(address1, 1234)); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); CPPUNIT_ASSERT_EQUAL(1, static_cast(connectionFactory->createdConnections.size())); } void testConnect_FirstAddressHostFails() { Connector::ref testling(createConnector()); auto address1 = HostAddress::fromString("1.1.1.1").get(); auto address2 = HostAddress::fromString("2.2.2.2").get(); resolver->addXMPPClientService("foo.com", "host-foo.com", 1234); resolver->addAddress("host-foo.com", address1); resolver->addAddress("host-foo.com", address2); connectionFactory->failingPorts.push_back(HostAddressPort(address1, 1234)); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_NoHosts() { Connector::ref testling(createConnector()); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); CPPUNIT_ASSERT(std::dynamic_pointer_cast(error)); } void testConnect_FirstSRVHostFails() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); connectionFactory->failingPorts.push_back(host1); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(host2 == *(connections[0]->hostAddressPort)); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_AllSRVHostsFailWithoutFallbackHost() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); connectionFactory->failingPorts.push_back(host1); connectionFactory->failingPorts.push_back(host2); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_AllSRVHostsFailWithFallbackHost() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addXMPPClientService("foo.com", host2); resolver->addAddress("foo.com", host3.getAddress()); connectionFactory->failingPorts.push_back(host1); connectionFactory->failingPorts.push_back(host2); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(host3 == *(connections[0]->hostAddressPort)); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_SRVAndFallbackHostsFail() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); resolver->addAddress("foo.com", host3.getAddress()); connectionFactory->failingPorts.push_back(host1); connectionFactory->failingPorts.push_back(host3); testling->start(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } /*void testConnect_TimeoutDuringResolve() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->setIsResponsive(false); testling->start(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(std::dynamic_pointer_cast(error)); CPPUNIT_ASSERT(!connections[0]); }*/ void testConnect_TimeoutDuringConnectToOnlyCandidate() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->addXMPPClientService("foo.com", host1); connectionFactory->isResponsive = false; testling->start(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_TimeoutDuringConnectToCandidateFallsBack() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); auto address2 = HostAddress::fromString("2.2.2.2").get(); resolver->addXMPPClientService("foo.com", "host-foo.com", 1234); resolver->addAddress("host-foo.com", HostAddress::fromString("1.1.1.1").get()); resolver->addAddress("host-foo.com", address2); connectionFactory->isResponsive = false; testling->start(); eventLoop->processEvents(); connectionFactory->isResponsive = true; timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(HostAddressPort(address2, 1234) == *(connections[0]->hostAddressPort)); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testConnect_NoTimeout() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->addXMPPClientService("foo.com", host1); testling->start(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(connections[0]); CPPUNIT_ASSERT(!std::dynamic_pointer_cast(error)); } void testStop_DuringSRVQuery() { Connector::ref testling(createConnector()); resolver->addXMPPClientService("foo.com", host1); testling->start(); testling->stop(); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); CPPUNIT_ASSERT(std::dynamic_pointer_cast(error)); } void testStop_Timeout() { Connector::ref testling(createConnector()); testling->setTimeoutMilliseconds(10); resolver->addXMPPClientService("foo.com", host1); testling->start(); testling->stop(); eventLoop->processEvents(); timerFactory->setTime(10); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, static_cast(connections.size())); CPPUNIT_ASSERT(!connections[0]); } private: Connector::ref createConnector(unsigned short port = 0, boost::optional serviceLookupPrefix = boost::optional("_xmpp-client._tcp.")) { Connector::ref connector = Connector::create("foo.com", port, serviceLookupPrefix, resolver, connectionFactory, timerFactory); connector->onConnectFinished.connect(boost::bind(&ConnectorTest::handleConnectorFinished, this, _1, _2)); return connector; } void handleConnectorFinished(std::shared_ptr connection, std::shared_ptr resultError) { std::shared_ptr c(std::dynamic_pointer_cast(connection)); if (connection) { assert(c); } connections.push_back(c); error = resultError; } struct MockConnection : public Connection { public: MockConnection(const std::vector& failingPorts, bool isResponsive, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), isResponsive(isResponsive) {} void listen() { assert(false); } void connect(const HostAddressPort& address) { hostAddressPort = address; if (isResponsive) { bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end(); eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail)); } } HostAddressPort getLocalAddress() const { return HostAddressPort(); } HostAddressPort getRemoteAddress() const { return HostAddressPort(); } void disconnect() { assert(false); } void write(const SafeByteArray&) { assert(false); } EventLoop* eventLoop; boost::optional hostAddressPort; std::vector failingPorts; bool isResponsive; }; struct MockConnectionFactory : public ConnectionFactory { MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop), isResponsive(true) { } std::shared_ptr createConnection() { auto connection = std::make_shared(failingPorts, isResponsive, eventLoop); createdConnections.push_back(connection); return connection; } EventLoop* eventLoop; bool isResponsive; std::vector failingPorts; std::vector> createdConnections; }; private: HostAddressPort host1; HostAddressPort host2; HostAddressPort host3; DummyEventLoop* eventLoop; StaticDomainNameResolver* resolver; MockConnectionFactory* connectionFactory; DummyTimerFactory* timerFactory; std::vector< std::shared_ptr > connections; std::shared_ptr error; }; CPPUNIT_TEST_SUITE_REGISTRATION(ConnectorTest);