Index: remoting/protocol/ice_transport_unittest.cc |
diff --git a/remoting/protocol/ice_transport_unittest.cc b/remoting/protocol/ice_transport_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..110a6d756c99c04346f4230f075f848e76de6959 |
--- /dev/null |
+++ b/remoting/protocol/ice_transport_unittest.cc |
@@ -0,0 +1,362 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "remoting/protocol/ice_transport.h" |
+ |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
+#include "base/single_thread_task_runner.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "jingle/glue/thread_wrapper.h" |
+#include "net/url_request/url_request_context_getter.h" |
+#include "remoting/protocol/chromium_port_allocator.h" |
+#include "remoting/protocol/connection_tester.h" |
+#include "remoting/protocol/fake_authenticator.h" |
+#include "remoting/protocol/p2p_stream_socket.h" |
+#include "remoting/protocol/stream_channel_factory.h" |
+#include "remoting/signaling/fake_signal_strategy.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/webrtc/libjingle/xmllite/xmlelement.h" |
+ |
+using testing::_; |
+ |
+namespace remoting { |
+namespace protocol { |
+ |
+namespace { |
+ |
+// Send 100 messages 1024 bytes each. UDP messages are sent with 10ms delay |
+// between messages (about 1 second for 100 messages). |
+const int kMessageSize = 1024; |
+const int kMessages = 100; |
+const char kChannelName[] = "test_channel"; |
+ |
+ACTION_P(QuitRunLoop, run_loop) { |
+ run_loop->Quit(); |
+} |
+ |
+ACTION_P2(QuitRunLoopOnCounter, run_loop, counter) { |
+ --(*counter); |
+ EXPECT_GE(*counter, 0); |
+ if (*counter == 0) |
+ run_loop->Quit(); |
+} |
+ |
+class MockChannelCreatedCallback { |
+ public: |
+ MOCK_METHOD1(OnDone, void(P2PStreamSocket* socket)); |
+}; |
+ |
+class TestTransportEventHandler : public Transport::EventHandler { |
+ public: |
+ typedef base::Callback<void(scoped_ptr<buzz::XmlElement> message)> |
+ TransportInfoCallback; |
+ typedef base::Callback<void(ErrorCode error)> ErrorCallback; |
+ |
+ TestTransportEventHandler() {} |
+ ~TestTransportEventHandler() {} |
+ |
+ // Both callback must be set before the test handler is passed to a Transport |
+ // object. |
+ void set_transport_info_callback(const TransportInfoCallback& callback) { |
+ transport_info_callback_ = callback; |
+ } |
+ void set_connected_callback(const base::Closure& callback) { |
+ connected_callback_ = callback; |
+ } |
+ void set_error_callback(const ErrorCallback& callback) { |
+ error_callback_ = callback; |
+ } |
+ |
+ // Transport::EventHandler interface. |
+ void OnOutgoingTransportInfo(scoped_ptr<buzz::XmlElement> message) override { |
+ transport_info_callback_.Run(message.Pass()); |
+ } |
+ void OnTransportRouteChange(const std::string& channel_name, |
+ const TransportRoute& route) override {} |
+ void OnTransportConnected() override { |
+ connected_callback_.Run(); |
+ } |
+ void OnTransportError(ErrorCode error) override { |
+ error_callback_.Run(error); |
+ } |
+ |
+ private: |
+ TransportInfoCallback transport_info_callback_; |
+ base::Closure connected_callback_; |
+ ErrorCallback error_callback_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TestTransportEventHandler); |
+}; |
+ |
+} // namespace |
+ |
+class IceTransportTest : public testing::Test { |
+ public: |
+ IceTransportTest() { |
+ jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
+ network_settings_ = |
+ NetworkSettings(NetworkSettings::NAT_TRAVERSAL_OUTGOING); |
+ } |
+ |
+ void TearDown() override { |
+ client_socket_.reset(); |
+ host_socket_.reset(); |
+ client_transport_.reset(); |
+ host_transport_.reset(); |
+ message_loop_.RunUntilIdle(); |
+ } |
+ |
+ void ProcessTransportInfo(scoped_ptr<IceTransport>* target_transport, |
+ scoped_ptr<buzz::XmlElement> transport_info) { |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, base::Bind(&IceTransportTest::DeliverTransportInfo, |
+ base::Unretained(this), target_transport, |
+ base::Passed(&transport_info)), |
+ transport_info_delay_); |
+ } |
+ |
+ void DeliverTransportInfo(scoped_ptr<IceTransport>* target_transport, |
+ scoped_ptr<buzz::XmlElement> transport_info) { |
+ ASSERT_TRUE(target_transport); |
+ EXPECT_TRUE( |
+ (*target_transport)->ProcessTransportInfo(transport_info.get())); |
+ } |
+ |
+ void InitializeConnection() { |
+ port_allocator_ = ChromiumPortAllocator::Create(nullptr, network_settings_); |
+ |
+ host_transport_.reset(new IceTransport( |
+ port_allocator_.get(), network_settings_, TransportRole::SERVER)); |
+ host_transport_->GetCanStartClosure().Run(); |
+ |
+ if (!host_authenticator_) { |
+ host_authenticator_.reset(new FakeAuthenticator( |
+ FakeAuthenticator::HOST, 0, FakeAuthenticator::ACCEPT, true)); |
+ } |
+ |
+ client_transport_.reset(new IceTransport( |
+ port_allocator_.get(), network_settings_, TransportRole::CLIENT)); |
+ client_transport_->GetCanStartClosure().Run(); |
+ if (!client_authenticator_) { |
+ client_authenticator_.reset(new FakeAuthenticator( |
+ FakeAuthenticator::CLIENT, 0, FakeAuthenticator::ACCEPT, true)); |
+ } |
+ |
+ // Connect signaling between the two IceTransport objects. |
+ host_event_handler_.set_transport_info_callback( |
+ base::Bind(&IceTransportTest::ProcessTransportInfo, |
+ base::Unretained(this), &client_transport_)); |
+ client_event_handler_.set_transport_info_callback( |
+ base::Bind(&IceTransportTest::ProcessTransportInfo, |
+ base::Unretained(this), &host_transport_)); |
+ |
+ host_event_handler_.set_connected_callback(base::Bind(&base::DoNothing)); |
+ host_event_handler_.set_error_callback(base::Bind( |
+ &IceTransportTest::OnTransportError, base::Unretained(this))); |
+ |
+ client_event_handler_.set_connected_callback(base::Bind(&base::DoNothing)); |
+ client_event_handler_.set_error_callback(base::Bind( |
+ &IceTransportTest::OnTransportError, base::Unretained(this))); |
+ |
+ host_transport_->Start(&host_event_handler_, host_authenticator_.get()); |
+ client_transport_->Start(&client_event_handler_, |
+ client_authenticator_.get()); |
+ } |
+ |
+ void WaitUntilConnected() { |
+ run_loop_.reset(new base::RunLoop()); |
+ |
+ int counter = 2; |
+ EXPECT_CALL(client_channel_callback_, OnDone(_)) |
+ .WillOnce(QuitRunLoopOnCounter(run_loop_.get(), &counter)); |
+ EXPECT_CALL(host_channel_callback_, OnDone(_)) |
+ .WillOnce(QuitRunLoopOnCounter(run_loop_.get(), &counter)); |
+ |
+ run_loop_->Run(); |
+ |
+ EXPECT_TRUE(client_socket_.get()); |
+ EXPECT_TRUE(host_socket_.get()); |
+ } |
+ |
+ void OnClientChannelCreated(scoped_ptr<P2PStreamSocket> socket) { |
+ client_socket_ = socket.Pass(); |
+ client_channel_callback_.OnDone(client_socket_.get()); |
+ } |
+ |
+ void OnHostChannelCreated(scoped_ptr<P2PStreamSocket> socket) { |
+ host_socket_ = socket.Pass(); |
+ host_channel_callback_.OnDone(host_socket_.get()); |
+ } |
+ |
+ void OnTransportError(ErrorCode error) { |
+ error_ = error; |
+ run_loop_->Quit(); |
+ } |
+ |
+ protected: |
+ base::MessageLoopForIO message_loop_; |
+ scoped_ptr<base::RunLoop> run_loop_; |
+ |
+ NetworkSettings network_settings_; |
+ |
+ scoped_ptr<FakeSignalStrategy> signal_strategy_; |
+ |
+ base::TimeDelta transport_info_delay_; |
+ |
+ scoped_ptr<cricket::PortAllocator> port_allocator_; |
+ |
+ // scoped_ptr<IceTransportFactory> host_transport_factory_; |
+ scoped_ptr<IceTransport> host_transport_; |
+ TestTransportEventHandler host_event_handler_; |
+ scoped_ptr<FakeAuthenticator> host_authenticator_; |
+ |
+ // scoped_ptr<IceTransportFactory> client_transport_factory_; |
+ scoped_ptr<IceTransport> client_transport_; |
+ TestTransportEventHandler client_event_handler_; |
+ scoped_ptr<FakeAuthenticator> client_authenticator_; |
+ |
+ MockChannelCreatedCallback client_channel_callback_; |
+ MockChannelCreatedCallback host_channel_callback_; |
+ |
+ scoped_ptr<P2PStreamSocket> client_socket_; |
+ scoped_ptr<P2PStreamSocket> host_socket_; |
+ |
+ ErrorCode error_ = OK; |
+}; |
+ |
+TEST_F(IceTransportTest, DataStream) { |
+ InitializeConnection(); |
+ |
+ client_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated, |
+ base::Unretained(this))); |
+ host_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated, |
+ base::Unretained(this))); |
+ |
+ WaitUntilConnected(); |
+ |
+ StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), |
+ kMessageSize, kMessages); |
+ tester.Start(); |
+ message_loop_.Run(); |
+ tester.CheckResults(); |
+} |
+ |
+TEST_F(IceTransportTest, MuxDataStream) { |
+ InitializeConnection(); |
+ |
+ client_transport_->GetMultiplexedChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated, |
+ base::Unretained(this))); |
+ host_transport_->GetMultiplexedChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated, |
+ base::Unretained(this))); |
+ |
+ WaitUntilConnected(); |
+ |
+ StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), |
+ kMessageSize, kMessages); |
+ tester.Start(); |
+ message_loop_.Run(); |
+ tester.CheckResults(); |
+} |
+ |
+TEST_F(IceTransportTest, FailedChannelAuth) { |
+ // Use host authenticator with one that rejects channel authentication. |
+ host_authenticator_.reset(new FakeAuthenticator( |
+ FakeAuthenticator::HOST, 0, FakeAuthenticator::REJECT_CHANNEL, true)); |
+ |
+ InitializeConnection(); |
+ |
+ client_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated, |
+ base::Unretained(this))); |
+ host_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated, |
+ base::Unretained(this))); |
+ |
+ run_loop_.reset(new base::RunLoop()); |
+ |
+ EXPECT_CALL(host_channel_callback_, OnDone(nullptr)) |
+ .WillOnce(QuitRunLoop(run_loop_.get())); |
+ |
+ run_loop_->Run(); |
+ |
+ EXPECT_FALSE(host_socket_); |
+ |
+ client_transport_->GetStreamChannelFactory()->CancelChannelCreation( |
+ kChannelName); |
+} |
+ |
+// Verify that channels are never marked connected if connection cannot be |
+// established. |
+TEST_F(IceTransportTest, TestBrokenTransport) { |
+ // Allow only incoming connections on both ends, which effectively renders |
+ // transport unusable. |
+ network_settings_ = NetworkSettings(NetworkSettings::NAT_TRAVERSAL_DISABLED); |
+ |
+ InitializeConnection(); |
+ |
+ client_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated, |
+ base::Unretained(this))); |
+ host_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated, |
+ base::Unretained(this))); |
+ |
+ message_loop_.RunUntilIdle(); |
+ |
+ // Verify that neither of the two ends of the channel is connected. |
+ EXPECT_FALSE(client_socket_); |
+ EXPECT_FALSE(host_socket_); |
+ |
+ client_transport_->GetStreamChannelFactory()->CancelChannelCreation( |
+ kChannelName); |
+ host_transport_->GetStreamChannelFactory()->CancelChannelCreation( |
+ kChannelName); |
+} |
+ |
+TEST_F(IceTransportTest, TestCancelChannelCreation) { |
+ InitializeConnection(); |
+ |
+ client_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated, |
+ base::Unretained(this))); |
+ client_transport_->GetStreamChannelFactory()->CancelChannelCreation( |
+ kChannelName); |
+ |
+ EXPECT_TRUE(!client_socket_.get()); |
+} |
+ |
+// Verify that we can still connect even when there is a delay in signaling |
+// messages delivery. |
+TEST_F(IceTransportTest, TestDelayedSignaling) { |
+ transport_info_delay_ = base::TimeDelta::FromMilliseconds(100); |
+ |
+ InitializeConnection(); |
+ |
+ client_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated, |
+ base::Unretained(this))); |
+ host_transport_->GetStreamChannelFactory()->CreateChannel( |
+ kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated, |
+ base::Unretained(this))); |
+ |
+ WaitUntilConnected(); |
+ |
+ StreamConnectionTester tester(host_socket_.get(), client_socket_.get(), |
+ kMessageSize, kMessages); |
+ tester.Start(); |
+ message_loop_.Run(); |
+ tester.CheckResults(); |
+} |
+ |
+ |
+} // namespace protocol |
+} // namespace remoting |