From 60925bd2f77df3be75ad46118a940a096499f18b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sun, 17 Apr 2011 00:11:30 +0200
Subject: Added HTTPConnectProxiedConnection test.


diff --git a/Swiften/Network/Connection.cpp b/Swiften/Network/Connection.cpp
new file mode 100644
index 0000000..9bb29e1
--- /dev/null
+++ b/Swiften/Network/Connection.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Network/Connection.h>
+
+using namespace Swift;
+
+Connection::Connection() {
+}
+
+Connection::~Connection() {
+}
diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h
index fdbbef6..74d25aa 100644
--- a/Swiften/Network/Connection.h
+++ b/Swiften/Network/Connection.h
@@ -23,8 +23,8 @@ namespace Swift {
 				WriteError
 			};
 
-			Connection() {}
-			virtual ~Connection() {}
+			Connection();
+			virtual ~Connection();
 
 			virtual void listen() = 0;
 			virtual void connect(const HostAddressPort& address) = 0;
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp
index 2e90b52..51130e5 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.cpp
+++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp
@@ -64,7 +64,6 @@ void HTTPConnectProxiedConnection::write(const ByteArray& data) {
 void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) {
 	connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1));
 	if (!error) {
-		proxyState_ = ProxyConnecting;
 		std::stringstream connect;
 		connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n\r\n";
 		connection_->write(ByteArray(connect.str()));
@@ -76,29 +75,24 @@ void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) {
 
 void HTTPConnectProxiedConnection::handleDataRead(const ByteArray& data) {
 	if (!connected_) {
-		if (proxyState_ == ProxyConnecting) {
-			SWIFT_LOG(debug) << data.toString() << std::endl;
-			std::vector<std::string> tmp = String::split(data.toString(), ' ');
-			if(tmp.size() > 1) {
-				int status = boost::lexical_cast<int> (tmp[1].c_str()); 
-				SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
-				if (status / 100 == 2) { // all 2XX states are OK
-					connected_ = true;
-					onConnectFinished(false);
-					return;
-				}
+		SWIFT_LOG(debug) << data.toString() << std::endl;
+		std::vector<std::string> tmp = String::split(data.toString(), ' ');
+		if(tmp.size() > 1) {
+			int status = boost::lexical_cast<int> (tmp[1].c_str()); 
+			SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl;
+			if (status / 100 == 2) { // all 2XX states are OK
+				connected_ = true;
+				onConnectFinished(false);
+				return;
 			}
-
-			std::cerr << "HTTP Proxy returned an error: " << data.toString() << std::endl;
-			return;
+			SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << data.toString() << std::endl;
 		}
+		disconnect();
+		onConnectFinished(true);
 	}
 	else {
 		onDataRead(data);
-		return;
 	}
-	disconnect();
-	onConnectFinished(true);
 }
 
 HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const {
diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h
index 232f4eb..930f5e1 100644
--- a/Swiften/Network/HTTPConnectProxiedConnection.h
+++ b/Swiften/Network/HTTPConnectProxiedConnection.h
@@ -38,11 +38,6 @@ namespace Swift {
 
 			virtual HostAddressPort getLocalAddress() const;
 		private:
-			enum {
-				ProxyAuthenticating = 0,
-				ProxyConnecting,
-			} proxyState_;
-
 			HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy);
 
 			void handleConnectionConnectFinished(bool error);
diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript
index 61eb69a..ecfc66a 100644
--- a/Swiften/Network/SConscript
+++ b/Swiften/Network/SConscript
@@ -20,6 +20,7 @@ sourceList = [
 			"FakeConnection.cpp",
  			"ChainedConnector.cpp",
  			"Connector.cpp",
+ 			"Connection.cpp",
 			"TimerFactory.cpp",
 			"DummyTimerFactory.cpp",
 			"BoostTimerFactory.cpp",
diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
new file mode 100644
index 0000000..6c4c89c
--- /dev/null
+++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp
@@ -0,0 +1,244 @@
+/*
+ * 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 <boost/optional.hpp>
+#include <boost/bind.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Network/Connection.h>
+#include <Swiften/Network/ConnectionFactory.h>
+#include <Swiften/Network/HTTPConnectProxiedConnection.h>
+#include <Swiften/Network/HostAddressPort.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);
+			host = HostAddressPort(HostAddress("2.2.2.2"), 2345);
+			eventLoop = new DummyEventLoop();
+			connectionFactory = new MockConnectionFactory(eventLoop);
+			connectFinished = false;
+			disconnected = false;
+		}
+
+		void tearDown() {
+			delete connectionFactory;
+			delete eventLoop;
+		}
+
+		void testConnect_CreatesConnectionToProxy() {
+			HTTPConnectProxiedConnection::ref testling(createTestling());
+
+			testling->connect(host);
+			eventLoop->processEvents();
+
+			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(!connectFinished);
+		}
+
+		void testConnect_SendsConnectRequest() {
+			HTTPConnectProxiedConnection::ref testling(createTestling());
+
+			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+			eventLoop->processEvents();
+
+			CPPUNIT_ASSERT_EQUAL(ByteArray("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();
+
+			connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+			eventLoop->processEvents();
+
+			CPPUNIT_ASSERT(connectFinished);
+			CPPUNIT_ASSERT(!connectFinishedWithError);
+			CPPUNIT_ASSERT(dataRead.isEmpty());
+		}
+
+		void testConnect_ReceiveMalformedConnectResponse() {
+			HTTPConnectProxiedConnection::ref testling(createTestling());
+			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+			eventLoop->processEvents();
+
+			connectionFactory->connections[0]->onDataRead(ByteArray("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();
+
+			connectionFactory->connections[0]->onDataRead(ByteArray("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();
+			connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+			eventLoop->processEvents();
+
+			connectionFactory->connections[0]->onDataRead(ByteArray("abcdef"));
+
+			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), dataRead);
+		}
+
+		void testWrite_AfterConnect() {
+			HTTPConnectProxiedConnection::ref testling(createTestling());
+			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+			eventLoop->processEvents();
+			connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n"));
+			eventLoop->processEvents();
+			connectionFactory->connections[0]->dataWritten.clear();
+
+			testling->write(ByteArray("abcdef"));
+
+			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), connectionFactory->connections[0]->dataWritten);
+		}
+
+		void testDisconnect_AfterConnectRequest() {
+			HTTPConnectProxiedConnection::ref testling(createTestling());
+			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345));
+			eventLoop->processEvents();
+
+			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();
+			connectionFactory->connections[0]->onDataRead(ByteArray("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);
+			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(const ByteArray& d) {
+			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 ByteArray& d) { 
+					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;
+		HostAddressPort host;
+		DummyEventLoop* eventLoop;
+		MockConnectionFactory* connectionFactory;
+		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);
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 0a229e8..f207c62 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -232,6 +232,7 @@ if env["SCONS_STAGE"] == "build" :
 			File("Network/UnitTest/HostAddressTest.cpp"),
 			File("Network/UnitTest/ConnectorTest.cpp"),
 			File("Network/UnitTest/ChainedConnectorTest.cpp"),
+			File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"),
 			File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"),
 			File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"),
 			File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"),
-- 
cgit v0.10.2-6-g49f6