diff options
Diffstat (limited to 'Swiften/Network/UnitTest')
| -rw-r--r-- | Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp | 38 | ||||
| -rw-r--r-- | Swiften/Network/UnitTest/BOSHConnectionTest.cpp | 14 | ||||
| -rw-r--r-- | Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp | 55 |
3 files changed, 80 insertions, 27 deletions
diff --git a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp index 1bfee10..82762c5 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp @@ -1,322 +1,352 @@ /* * Copyright (c) 2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/optional.hpp> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/BOSHConnection.h> #include <Swiften/Network/BOSHConnectionPool.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> + + using namespace Swift; typedef boost::shared_ptr<BOSHConnectionPool> PoolRef; + class BOSHConnectionPoolTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BOSHConnectionPoolTest); CPPUNIT_TEST(testConnectionCount_OneWrite); CPPUNIT_TEST(testConnectionCount_TwoWrites); CPPUNIT_TEST(testConnectionCount_ThreeWrites); CPPUNIT_TEST(testConnectionCount_ThreeWrites_ManualConnect); CPPUNIT_TEST(testConnectionCount_ThreeWritesTwoReads); CPPUNIT_TEST(testSession); CPPUNIT_TEST(testWrite_Empty); CPPUNIT_TEST_SUITE_END(); public: void setUp() { to = "wonderland.lit"; path = "http-bind"; port = "5280"; sid = "MyShinySID"; initial = "<body wait='60' " "inactivity='30' " "polling='5' " "requests='2' " "hold='1' " "maxpause='120' " "sid='" + sid + "' " "ver='1.6' " "from='wonderland.lit' " "xmlns='http://jabber.org/protocol/httpbind'/>"; eventLoop = new DummyEventLoop(); connectionFactory = new MockConnectionFactory(eventLoop); boshURL = URL("http", to, 5280, path); sessionTerminated = 0; sessionStarted = 0; initialRID = 2349876; xmppDataRead.clear(); boshDataRead.clear(); boshDataWritten.clear(); + resolver = new StaticDomainNameResolver(eventLoop); + resolver->addAddress(to, HostAddress("127.0.0.1")); + timerFactory = new DummyTimerFactory(); } void tearDown() { eventLoop->processEvents(); delete connectionFactory; + delete resolver; + delete timerFactory; delete eventLoop; } void testConnectionCount_OneWrite() { PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(0, sessionStarted); readResponse(initial, connectionFactory->connections[0]); CPPUNIT_ASSERT_EQUAL(1, sessionStarted); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); testling->write(createSafeByteArray("<blah/>")); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(1, sessionStarted); } void testConnectionCount_TwoWrites() { PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); readResponse(initial, connectionFactory->connections[0]); + eventLoop->processEvents(); testling->write(createSafeByteArray("<blah/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); testling->write(createSafeByteArray("<bleh/>")); eventLoop->processEvents(); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); } void testConnectionCount_ThreeWrites() { PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); readResponse(initial, connectionFactory->connections[0]); testling->restartStream(); readResponse("<body/>", connectionFactory->connections[0]); testling->restartStream(); readResponse("<body/>", connectionFactory->connections[0]); testling->write(createSafeByteArray("<blah/>")); testling->write(createSafeByteArray("<bleh/>")); testling->write(createSafeByteArray("<bluh/>")); eventLoop->processEvents(); CPPUNIT_ASSERT(st(2) >= connectionFactory->connections.size()); } void testConnectionCount_ThreeWrites_ManualConnect() { connectionFactory->autoFinishConnect = false; PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(st(0), boshDataWritten.size()); /* Connection not connected yet, can't send data */ connectionFactory->connections[0]->onConnectFinished(false); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* Connection finished, stream header sent */ readResponse(initial, connectionFactory->connections[0]); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* Don't respond to initial data with a holding call */ testling->restartStream(); + eventLoop->processEvents(); readResponse("<body/>", connectionFactory->connections[0]); + eventLoop->processEvents(); testling->restartStream(); + eventLoop->processEvents(); testling->write(createSafeByteArray("<blah/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); /* New connection isn't up yet. */ connectionFactory->connections[1]->onConnectFinished(false); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* New connection ready. */ testling->write(createSafeByteArray("<bleh/>")); + eventLoop->processEvents(); testling->write(createSafeByteArray("<bluh/>")); CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* New data can't be sent, no free connections. */ eventLoop->processEvents(); CPPUNIT_ASSERT(st(2) >= connectionFactory->connections.size()); } void testConnectionCount_ThreeWritesTwoReads() { boost::shared_ptr<MockConnection> c0; boost::shared_ptr<MockConnection> c1; long rid = initialRID; PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); c0 = connectionFactory->connections[0]; eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* header*/ rid++; readResponse(initial, c0); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); CPPUNIT_ASSERT(!c0->pending); rid++; testling->restartStream(); + eventLoop->processEvents(); readResponse("<body/>", connectionFactory->connections[0]); rid++; testling->write(createSafeByteArray("<blah/>")); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); /* 0 was waiting for response, open and send on 1 */ CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* data */ c1 = connectionFactory->connections[1]; std::string fullBody = "<body rid='" + boost::lexical_cast<std::string>(rid) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'><blah/></body>"; /* check empty write */ CPPUNIT_ASSERT_EQUAL(fullBody, lastBody()); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); rid++; readResponse("<body xmlns='http://jabber.org/protocol/httpbind'><message><splatploing/></message></body>", c0); /* Doesn't include necessary attributes - as the support is improved this'll start to fail */ eventLoop->processEvents(); CPPUNIT_ASSERT(!c0->pending); CPPUNIT_ASSERT(c1->pending); CPPUNIT_ASSERT_EQUAL(st(4), boshDataWritten.size()); /* don't send empty in [0], still have [1] waiting */ CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); rid++; readResponse("<body xmlns='http://jabber.org/protocol/httpbind'><message><splatploing><blittlebarg/></splatploing></message></body>", c1); eventLoop->processEvents(); CPPUNIT_ASSERT(!c1->pending); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT_EQUAL(st(5), boshDataWritten.size()); /* empty to make room */ CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); rid++; testling->write(createSafeByteArray("<bleh/>")); + eventLoop->processEvents(); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); /* data */ rid++; testling->write(createSafeByteArray("<bluh/>")); CPPUNIT_ASSERT(c0->pending); CPPUNIT_ASSERT(c1->pending); CPPUNIT_ASSERT_EQUAL(st(6), boshDataWritten.size()); /* Don't send data, no room */ eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), connectionFactory->connections.size()); } void testSession() { to = "prosody.doomsong.co.uk"; + resolver->addAddress("prosody.doomsong.co.uk", HostAddress("127.0.0.1")); path = "http-bind/"; boshURL = URL("http", to, 5280, path); PoolRef testling = createTestling(); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* header*/ CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); std::string response = "<body authid='743da605-4c2e-4de1-afac-ac040dd4a940' xmpp:version='1.0' xmlns:stream='http://etherx.jabber.org/streams' xmlns:xmpp='urn:xmpp:xbosh' inactivity='60' wait='60' polling='5' secure='true' hold='1' from='prosody.doomsong.co.uk' ver='1.6' sid='743da605-4c2e-4de1-afac-ac040dd4a940' requests='2' xmlns='http://jabber.org/protocol/httpbind'><stream:features><auth xmlns='http://jabber.org/features/iq-auth'/><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>SCRAM-SHA-1</mechanism><mechanism>DIGEST-MD5</mechanism></mechanisms></stream:features></body>"; readResponse(response, connectionFactory->connections[0]); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); std::string send = "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"SCRAM-SHA-1\">biwsbj1hZG1pbixyPWZhOWE5ZDhiLWZmMDctNGE4Yy04N2E3LTg4YWRiNDQxZGUwYg==</auth>"; testling->write(createSafeByteArray(send)); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); response = "<body xmlns='http://jabber.org/protocol/httpbind' sid='743da605-4c2e-4de1-afac-ac040dd4a940' xmlns:stream = 'http://etherx.jabber.org/streams'><challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1mYTlhOWQ4Yi1mZjA3LTRhOGMtODdhNy04OGFkYjQ0MWRlMGJhZmZlMWNhMy1mMDJkLTQ5NzEtYjkyNS0yM2NlNWQ2MDQyMjYscz1OVGd5WkdWaFptTXRaVE15WXkwMFpXUmhMV0ZqTURRdFpqYzRNbUppWmpGa1pqWXgsaT00MDk2</challenge></body>"; readResponse(response, connectionFactory->connections[0]); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); send = "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">Yz1iaXdzLHI9ZmE5YTlkOGItZmYwNy00YThjLTg3YTctODhhZGI0NDFkZTBiYWZmZTFjYTMtZjAyZC00OTcxLWI5MjUtMjNjZTVkNjA0MjI2LHA9aU11NWt3dDN2VWplU2RqL01Jb3VIRldkZjBnPQ==</response>"; testling->write(createSafeByteArray(send)); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); response = "<body xmlns='http://jabber.org/protocol/httpbind' sid='743da605-4c2e-4de1-afac-ac040dd4a940' xmlns:stream = 'http://etherx.jabber.org/streams'><success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1YNmNBY3BBOWxHNjNOOXF2bVQ5S0FacERrVm89</success></body>"; readResponse(response, connectionFactory->connections[0]); eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); } void testWrite_Empty() { boost::shared_ptr<MockConnection> c0; PoolRef testling = createTestling(); - c0 = connectionFactory->connections[0]; CPPUNIT_ASSERT_EQUAL(st(1), connectionFactory->connections.size()); - eventLoop->processEvents(); + c0 = connectionFactory->connections[0]; readResponse(initial, c0); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(1), boshDataWritten.size()); /* Shouldn't have sent anything extra */ + eventLoop->processEvents(); testling->restartStream(); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(2), boshDataWritten.size()); readResponse("<body></body>", c0); + eventLoop->processEvents(); CPPUNIT_ASSERT_EQUAL(st(3), boshDataWritten.size()); std::string fullBody = "<body rid='" + boost::lexical_cast<std::string>(initialRID + 2) + "' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'></body>"; std::string response = boshDataWritten[2]; size_t bodyPosition = response.find("\r\n\r\n"); CPPUNIT_ASSERT_EQUAL(fullBody, response.substr(bodyPosition+4)); } private: PoolRef createTestling() { - PoolRef pool = boost::make_shared<BOSHConnectionPool>(boshURL, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), to, initialRID, URL(), "", ""); + BOSHConnectionPool* a = new BOSHConnectionPool(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString("")); + PoolRef pool(a); + //FIXME: Remko - why does the above work, but the below fail? + //PoolRef pool = boost::make_shared<BOSHConnectionPool>(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString("")); pool->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPoolTest::handleXMPPDataRead, this, _1)); pool->onBOSHDataRead.connect(boost::bind(&BOSHConnectionPoolTest::handleBOSHDataRead, this, _1)); pool->onBOSHDataWritten.connect(boost::bind(&BOSHConnectionPoolTest::handleBOSHDataWritten, this, _1)); pool->onSessionStarted.connect(boost::bind(&BOSHConnectionPoolTest::handleSessionStarted, this)); pool->onSessionTerminated.connect(boost::bind(&BOSHConnectionPoolTest::handleSessionTerminated, this)); + eventLoop->processEvents(); + eventLoop->processEvents(); return pool; } std::string lastBody() { std::string response = boshDataWritten[boshDataWritten.size() - 1]; size_t bodyPosition = response.find("\r\n\r\n"); return response.substr(bodyPosition+4); } size_t st(int val) { return static_cast<size_t>(val); } void handleXMPPDataRead(const SafeByteArray& d) { xmppDataRead.push_back(safeByteArrayToString(d)); } void handleBOSHDataRead(const SafeByteArray& d) { boshDataRead.push_back(safeByteArrayToString(d)); } void handleBOSHDataWritten(const SafeByteArray& d) { boshDataWritten.push_back(safeByteArrayToString(d)); } void handleSessionStarted() { sessionStarted++; } void handleSessionTerminated() { sessionTerminated++; } struct MockConnection : public Connection { @@ -374,48 +404,50 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture { void readResponse(const std::string& response, boost::shared_ptr<MockConnection> connection) { connection->pending = false; boost::shared_ptr<SafeByteArray> data1 = boost::make_shared<SafeByteArray>(createSafeByteArray( "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; charset=utf-8\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Headers: Content-Type\r\n" "Content-Length: ")); connection->onDataRead(data1); boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size()))); connection->onDataRead(data2); boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n")); connection->onDataRead(data3); boost::shared_ptr<SafeByteArray> data4 = boost::make_shared<SafeByteArray>(createSafeByteArray(response)); connection->onDataRead(data4); } std::string fullRequestFor(const std::string& data) { std::string body = data; std::string result = "POST /" + path + " HTTP/1.1\r\n" + "Host: " + to + ":" + port + "\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" + "Content-Length: " + boost::lexical_cast<std::string>(body.size()) + "\r\n\r\n" + body; return result; } private: URL boshURL; DummyEventLoop* eventLoop; MockConnectionFactory* connectionFactory; std::vector<std::string> xmppDataRead; std::vector<std::string> boshDataRead; std::vector<std::string> boshDataWritten; PlatformXMLParserFactory parserFactory; + StaticDomainNameResolver* resolver; + TimerFactory* timerFactory; std::string to; std::string path; std::string port; std::string sid; std::string initial; long initialRID; int sessionStarted; int sessionTerminated; }; CPPUNIT_TEST_SUITE_REGISTRATION(BOSHConnectionPoolTest); diff --git a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp index 8062bea..e0dc0bf 100644 --- a/Swiften/Network/UnitTest/BOSHConnectionTest.cpp +++ b/Swiften/Network/UnitTest/BOSHConnectionTest.cpp @@ -1,90 +1,96 @@ /* * Copyright (c) 2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/optional.hpp> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/BOSHConnection.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Parser/PlatformXMLParserFactory.h> using namespace Swift; class BOSHConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(BOSHConnectionTest); CPPUNIT_TEST(testHeader); CPPUNIT_TEST(testReadiness_ok); CPPUNIT_TEST(testReadiness_pending); CPPUNIT_TEST(testReadiness_disconnect); CPPUNIT_TEST(testReadiness_noSID); CPPUNIT_TEST(testWrite_Receive); CPPUNIT_TEST(testWrite_ReceiveTwice); CPPUNIT_TEST(testRead_Fragment); CPPUNIT_TEST(testHTTPRequest); CPPUNIT_TEST(testHTTPRequest_Empty); CPPUNIT_TEST_SUITE_END(); public: void setUp() { eventLoop = new DummyEventLoop(); connectionFactory = new MockConnectionFactory(eventLoop); + resolver = new StaticDomainNameResolver(eventLoop); + timerFactory = new DummyTimerFactory(); connectFinished = false; disconnected = false; disconnectedError = false; dataRead.clear(); } void tearDown() { eventLoop->processEvents(); delete connectionFactory; - delete eventLoop; + delete resolver; + delete timerFactory; + delete eventLoop; } void testHeader() { BOSHConnection::ref testling = createTestling(); testling->connect(); eventLoop->processEvents(); testling->startStream("wonderland.lit", 1); std::string initial("<body wait='60' " "inactivity='30' " "polling='5' " "requests='2' " "hold='1' " "maxpause='120' " "sid='MyShinySID' " "ver='1.6' " "from='wonderland.lit' " "xmlns='http://jabber.org/protocol/httpbind'/>"); readResponse(initial, connectionFactory->connections[0]); CPPUNIT_ASSERT_EQUAL(std::string("MyShinySID"), sid); CPPUNIT_ASSERT(testling->isReadyToSend()); } void testReadiness_ok() { BOSHConnection::ref testling = createTestling(); testling->connect(); eventLoop->processEvents(); testling->setSID("blahhhhh"); CPPUNIT_ASSERT(testling->isReadyToSend()); } void testReadiness_pending() { BOSHConnection::ref testling = createTestling(); testling->connect(); eventLoop->processEvents(); testling->setSID("mySID"); @@ -153,71 +159,73 @@ class BOSHConnectionTest : public CppUnit::TestFixture { boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray( "\r\n<body xmlns='http://jabber.org/protocol/httpbind'>" "<bl")); boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray( "ah/>" "</body>")); connection->onDataRead(data1); connection->onDataRead(data2); CPPUNIT_ASSERT(dataRead.empty()); connection->onDataRead(data3); CPPUNIT_ASSERT_EQUAL(std::string("<blah/>"), byteArrayToString(dataRead)); } void testHTTPRequest() { std::string data = "<blah/>"; std::string sid = "wigglebloom"; std::string fullBody = "<body xmlns='http://jabber.org/protocol/httpbind' sid='" + sid + "' rid='20'>" + data + "</body>"; std::pair<SafeByteArray, size_t> http = BOSHConnection::createHTTPRequest(createSafeByteArray(data), false, false, 20, sid, URL()); CPPUNIT_ASSERT_EQUAL(fullBody.size(), http.second); } void testHTTPRequest_Empty() { std::string data = ""; std::string sid = "wigglebloomsickle"; std::string fullBody = "<body rid='42' sid='" + sid + "' xmlns='http://jabber.org/protocol/httpbind'>" + data + "</body>"; std::pair<SafeByteArray, size_t> http = BOSHConnection::createHTTPRequest(createSafeByteArray(data), false, false, 42, sid, URL()); CPPUNIT_ASSERT_EQUAL(fullBody.size(), http.second); std::string response = safeByteArrayToString(http.first); size_t bodyPosition = response.find("\r\n\r\n"); CPPUNIT_ASSERT_EQUAL(fullBody, response.substr(bodyPosition+4)); } private: BOSHConnection::ref createTestling() { - BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL)); + resolver->addAddress("wonderland.lit", HostAddress("127.0.0.1")); + Connector::ref connector = Connector::create("wonderland.lit", resolver, connectionFactory, timerFactory, 5280); + BOSHConnection::ref c = BOSHConnection::create(URL("http", "wonderland.lit", 5280, "http-bind"), connector, &parserFactory); c->onConnectFinished.connect(boost::bind(&BOSHConnectionTest::handleConnectFinished, this, _1)); c->onDisconnected.connect(boost::bind(&BOSHConnectionTest::handleDisconnected, this, _1)); c->onXMPPDataRead.connect(boost::bind(&BOSHConnectionTest::handleDataRead, this, _1)); c->onSessionStarted.connect(boost::bind(&BOSHConnectionTest::handleSID, this, _1)); c->setRID(42); return c; } void handleConnectFinished(bool error) { connectFinished = true; connectFinishedWithError = error; } void handleDisconnected(bool e) { disconnected = true; disconnectedError = e; } void handleDataRead(const SafeByteArray& d) { append(dataRead, d); } void handleSID(const std::string& s) { sid = s; } struct MockConnection : public Connection { public: MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) { } void listen() { assert(false); } void connect(const HostAddressPort& address) { hostAddressPort = address; @@ -252,41 +260,43 @@ class BOSHConnectionTest : public CppUnit::TestFixture { connections.push_back(connection); return connection; } EventLoop* eventLoop; std::vector< boost::shared_ptr<MockConnection> > connections; std::vector<HostAddressPort> failingPorts; }; void readResponse(const std::string& response, boost::shared_ptr<MockConnection> connection) { boost::shared_ptr<SafeByteArray> data1 = boost::make_shared<SafeByteArray>(createSafeByteArray( "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; charset=utf-8\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Headers: Content-Type\r\n" "Content-Length: ")); connection->onDataRead(data1); boost::shared_ptr<SafeByteArray> data2 = boost::make_shared<SafeByteArray>(createSafeByteArray(boost::lexical_cast<std::string>(response.size()))); connection->onDataRead(data2); boost::shared_ptr<SafeByteArray> data3 = boost::make_shared<SafeByteArray>(createSafeByteArray("\r\n\r\n")); connection->onDataRead(data3); boost::shared_ptr<SafeByteArray> data4 = boost::make_shared<SafeByteArray>(createSafeByteArray(response)); connection->onDataRead(data4); } private: DummyEventLoop* eventLoop; MockConnectionFactory* connectionFactory; bool connectFinished; bool connectFinishedWithError; bool disconnected; bool disconnectedError; ByteArray dataRead; PlatformXMLParserFactory parserFactory; + StaticDomainNameResolver* resolver; + TimerFactory* timerFactory; std::string sid; }; CPPUNIT_TEST_SUITE_REGISTRATION(BOSHConnectionTest); diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp index c0252d4..347a145 100644 --- a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -1,246 +1,257 @@ /* * Copyright (c) 2010 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/optional.hpp> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <boost/shared_ptr.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Network/Connection.h> #include <Swiften/Network/ConnectionFactory.h> #include <Swiften/Network/HTTPConnectProxiedConnection.h> #include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest); CPPUNIT_TEST(testConnect_CreatesConnectionToProxy); CPPUNIT_TEST(testConnect_SendsConnectRequest); CPPUNIT_TEST(testConnect_ReceiveConnectResponse); CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse); CPPUNIT_TEST(testConnect_ReceiveErrorConnectResponse); CPPUNIT_TEST(testConnect_ReceiveDataAfterConnect); CPPUNIT_TEST(testWrite_AfterConnect); CPPUNIT_TEST(testDisconnect_AfterConnectRequest); CPPUNIT_TEST(testDisconnect_AfterConnect); CPPUNIT_TEST_SUITE_END(); public: void setUp() { - proxyHost = HostAddressPort(HostAddress("1.1.1.1"), 1234); + proxyHost = "doo.bah"; + proxyPort = 1234; + proxyHostAddress = HostAddressPort(HostAddress("1.1.1.1"), proxyPort); host = HostAddressPort(HostAddress("2.2.2.2"), 2345); eventLoop = new DummyEventLoop(); + resolver = new StaticDomainNameResolver(eventLoop); + resolver->addAddress(proxyHost, proxyHostAddress.getAddress()); + timerFactory = new DummyTimerFactory(); connectionFactory = new MockConnectionFactory(eventLoop); connectFinished = false; disconnected = false; } void tearDown() { + delete timerFactory; delete connectionFactory; + delete resolver; delete eventLoop; } + void connect(HTTPConnectProxiedConnection::ref connection, const HostAddressPort& to) { + connection->connect(to); + eventLoop->processEvents(); + eventLoop->processEvents(); + eventLoop->processEvents(); + } + void testConnect_CreatesConnectionToProxy() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(host); - eventLoop->processEvents(); + connect(testling, host); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->connections.size())); CPPUNIT_ASSERT(connectionFactory->connections[0]->hostAddressPort); - CPPUNIT_ASSERT(proxyHost == *connectionFactory->connections[0]->hostAddressPort); + CPPUNIT_ASSERT(proxyHostAddress == *connectionFactory->connections[0]->hostAddressPort); CPPUNIT_ASSERT(!connectFinished); } void testConnect_SendsConnectRequest() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n\r\n"), connectionFactory->connections[0]->dataWritten); } void testConnect_ReceiveConnectResponse() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); CPPUNIT_ASSERT(connectFinished); CPPUNIT_ASSERT(!connectFinishedWithError); CPPUNIT_ASSERT(dataRead.empty()); } void testConnect_ReceiveMalformedConnectResponse() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("FLOOP")); eventLoop->processEvents(); CPPUNIT_ASSERT(connectFinished); CPPUNIT_ASSERT(connectFinishedWithError); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); } void testConnect_ReceiveErrorConnectResponse() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 401 Unauthorized\r\n\r\n")); eventLoop->processEvents(); CPPUNIT_ASSERT(connectFinished); CPPUNIT_ASSERT(connectFinishedWithError); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); } void testConnect_ReceiveDataAfterConnect() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("abcdef")); CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), dataRead); } void testWrite_AfterConnect() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); connectionFactory->connections[0]->dataWritten.clear(); testling->write(createSafeByteArray("abcdef")); CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), connectionFactory->connections[0]->dataWritten); } void testDisconnect_AfterConnectRequest() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); testling->disconnect(); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); CPPUNIT_ASSERT(disconnected); CPPUNIT_ASSERT(!disconnectedError); } void testDisconnect_AfterConnect() { HTTPConnectProxiedConnection::ref testling(createTestling()); - testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); - eventLoop->processEvents(); + connect(testling, HostAddressPort(HostAddress("2.2.2.2"), 2345)); connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); eventLoop->processEvents(); testling->disconnect(); CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); CPPUNIT_ASSERT(disconnected); CPPUNIT_ASSERT(!disconnectedError); } private: HTTPConnectProxiedConnection::ref createTestling() { - boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(connectionFactory, proxyHost, "", ""); + boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(resolver, connectionFactory, timerFactory, eventLoop, proxyHost, proxyPort, "", ""); c->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleConnectFinished, this, _1)); c->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDisconnected, this, _1)); c->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDataRead, this, _1)); return c; } void handleConnectFinished(bool error) { connectFinished = true; connectFinishedWithError = error; } void handleDisconnected(const boost::optional<Connection::Error>& e) { disconnected = true; disconnectedError = e; } void handleDataRead(boost::shared_ptr<SafeByteArray> d) { append(dataRead, *d); } struct MockConnection : public Connection { public: MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) { } void listen() { assert(false); } void connect(const HostAddressPort& address) { hostAddressPort = address; bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end(); eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail)); } HostAddressPort getLocalAddress() const { return HostAddressPort(); } void disconnect() { disconnected = true; onDisconnected(boost::optional<Connection::Error>()); } void write(const SafeByteArray& d) { append(dataWritten, d); } EventLoop* eventLoop; boost::optional<HostAddressPort> hostAddressPort; std::vector<HostAddressPort> failingPorts; ByteArray dataWritten; bool disconnected; }; struct MockConnectionFactory : public ConnectionFactory { MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop) { } boost::shared_ptr<Connection> createConnection() { boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop); connections.push_back(connection); return connection; } EventLoop* eventLoop; std::vector< boost::shared_ptr<MockConnection> > connections; std::vector<HostAddressPort> failingPorts; }; private: - HostAddressPort proxyHost; + std::string proxyHost; + HostAddressPort proxyHostAddress; + int proxyPort; HostAddressPort host; DummyEventLoop* eventLoop; + StaticDomainNameResolver* resolver; MockConnectionFactory* connectionFactory; + TimerFactory* timerFactory; std::vector< boost::shared_ptr<MockConnection> > connections; bool connectFinished; bool connectFinishedWithError; bool disconnected; boost::optional<Connection::Error> disconnectedError; ByteArray dataRead; }; CPPUNIT_TEST_SUITE_REGISTRATION(HTTPConnectProxiedConnectionTest); |
Swift