Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / remoting / signaling / xmpp_signal_strategy_unittest.cc
blob82a2ed8fa1a901cc576d13edf36b925cc67dcfcf
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/signaling/xmpp_signal_strategy.h"
7 #include "base/base64.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "net/socket/socket_test_util.h"
11 #include "net/url_request/url_request_test_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
15 namespace remoting {
17 namespace {
19 class XmppSocketDataProvider : public net::SocketDataProvider {
20 public:
21 net::MockRead OnRead() override {
22 return net::MockRead(net::ASYNC, net::ERR_IO_PENDING);
25 net::MockWriteResult OnWrite(const std::string& data) override {
26 if (write_error_ != net::OK)
27 return net::MockWriteResult(net::SYNCHRONOUS, write_error_);
29 written_data_.append(data);
31 if (use_async_write_) {
32 pending_write_size_ = data.size();
33 return net::MockWriteResult(net::ASYNC, net::ERR_IO_PENDING);
36 return net::MockWriteResult(net::SYNCHRONOUS, data.size());
39 void Reset() override {}
41 bool AllReadDataConsumed() const override {
42 return true;
45 bool AllWriteDataConsumed() const override {
46 return true;
49 void ReceiveData(const std::string& text) {
50 socket()->OnReadComplete(
51 net::MockRead(net::ASYNC, text.data(), text.size()));
54 void Close() {
55 ReceiveData(std::string());
58 void SimulateAsyncReadError() {
59 socket()->OnReadComplete(
60 net::MockRead(net::ASYNC, net::ERR_CONNECTION_RESET));
63 std::string GetAndClearWrittenData() {
64 std::string data;
65 data.swap(written_data_);
66 return data;
69 void set_use_async_write(bool use_async_write) {
70 use_async_write_ = use_async_write;
73 void set_write_error(net::Error error) {
74 write_error_ = error;
77 void CompletePendingWrite() {
78 socket()->OnWriteComplete(pending_write_size_);
81 private:
82 std::string written_data_;
83 bool use_async_write_ = false;
84 int pending_write_size_ = 0;
85 net::Error write_error_ = net::OK;
88 class MockClientSocketFactory : public net::MockClientSocketFactory {
89 public:
90 scoped_ptr<net::SSLClientSocket> CreateSSLClientSocket(
91 scoped_ptr<net::ClientSocketHandle> transport_socket,
92 const net::HostPortPair& host_and_port,
93 const net::SSLConfig& ssl_config,
94 const net::SSLClientSocketContext& context) override {
95 ssl_socket_created_ = true;
96 return net::MockClientSocketFactory::CreateSSLClientSocket(
97 transport_socket.Pass(), host_and_port, ssl_config, context);
100 bool ssl_socket_created() const { return ssl_socket_created_; }
102 private:
103 bool ssl_socket_created_ = false;
106 } // namespace
108 const char kTestUsername[] = "test_username@example.com";
109 const char kTestAuthToken[] = "test_auth_token";
110 const int kDefaultPort = 443;
112 class XmppSignalStrategyTest : public testing::Test,
113 public SignalStrategy::Listener {
114 public:
115 XmppSignalStrategyTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
117 void SetUp() override {
118 scoped_ptr<net::TestURLRequestContext> context(
119 new net::TestURLRequestContext());
120 request_context_getter_ = new net::TestURLRequestContextGetter(
121 message_loop_.task_runner(), context.Pass());
124 void CreateSignalStrategy(int port) {
125 XmppSignalStrategy::XmppServerConfig config;
126 config.host = "talk.google.com";
127 config.port = port;
128 config.username = kTestUsername;
129 config.auth_token = kTestAuthToken;
130 signal_strategy_.reset(new XmppSignalStrategy(
131 &client_socket_factory_, request_context_getter_, config));
132 signal_strategy_->AddListener(this);
135 void TearDown() override {
136 signal_strategy_->RemoveListener(this);
137 signal_strategy_.reset();
138 base::RunLoop().RunUntilIdle();
141 void OnSignalStrategyStateChange(SignalStrategy::State state) override {
142 state_history_.push_back(state);
145 bool OnSignalStrategyIncomingStanza(const buzz::XmlElement* stanza) override {
146 received_messages_.push_back(
147 make_scoped_ptr(new buzz::XmlElement(*stanza)));
148 return true;
151 void Connect(bool success);
153 protected:
154 base::MessageLoop message_loop_;
155 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
156 MockClientSocketFactory client_socket_factory_;
157 scoped_ptr<XmppSocketDataProvider> socket_data_provider_;
158 scoped_ptr<net::SSLSocketDataProvider> ssl_socket_data_provider_;
159 scoped_ptr<XmppSignalStrategy> signal_strategy_;
161 std::vector<SignalStrategy::State> state_history_;
162 ScopedVector<buzz::XmlElement> received_messages_;
165 void XmppSignalStrategyTest::Connect(bool success) {
166 EXPECT_EQ(SignalStrategy::DISCONNECTED, signal_strategy_->GetState());
167 state_history_.clear();
169 socket_data_provider_.reset(new XmppSocketDataProvider());
170 socket_data_provider_->set_connect_data(
171 net::MockConnect(net::ASYNC, net::OK));
172 client_socket_factory_.AddSocketDataProvider(socket_data_provider_.get());
174 ssl_socket_data_provider_.reset(
175 new net::SSLSocketDataProvider(net::ASYNC, net::OK));
176 client_socket_factory_.AddSSLSocketDataProvider(
177 ssl_socket_data_provider_.get());
179 signal_strategy_->Connect();
181 EXPECT_EQ(SignalStrategy::CONNECTING, signal_strategy_->GetState());
182 EXPECT_EQ(1U, state_history_.size());
183 EXPECT_EQ(SignalStrategy::CONNECTING, state_history_[0]);
185 // No data written before TLS.
186 EXPECT_EQ("", socket_data_provider_->GetAndClearWrittenData());
188 base::RunLoop().RunUntilIdle();
190 socket_data_provider_->ReceiveData(
191 "<stream:stream from=\"google.com\" id=\"DCDDE5171CB2154A\" "
192 "version=\"1.0\" "
193 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
194 "xmlns=\"jabber:client\">"
195 "<stream:features>"
196 "<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
197 "<mechanism>X-OAUTH2</mechanism>"
198 "<mechanism>X-GOOGLE-TOKEN</mechanism>"
199 "<mechanism>PLAIN</mechanism>"
200 "</mechanisms>"
201 "</stream:features>");
203 base::RunLoop().RunUntilIdle();
205 std::string cookie;
206 base::Base64Encode(std::string("\0", 1) + kTestUsername +
207 std::string("\0", 1) + kTestAuthToken,
208 &cookie);
209 // Expect auth message.
210 EXPECT_EQ(
211 "<stream:stream to=\"google.com\" version=\"1.0\" "
212 "xmlns=\"jabber:client\" "
213 "xmlns:stream=\"http://etherx.jabber.org/streams\">"
214 "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-OAUTH2\" "
215 "auth:service=\"oauth2\" auth:allow-generated-jid=\"true\" "
216 "auth:client-uses-full-bind-result=\"true\" "
217 "auth:allow-non-google-login=\"true\" "
218 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">" + cookie +
219 "</auth>", socket_data_provider_->GetAndClearWrittenData());
221 if (!success) {
222 socket_data_provider_->ReceiveData(
223 "<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
224 "<not-authorized/></failure>");
225 EXPECT_EQ(2U, state_history_.size());
226 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[1]);
227 EXPECT_EQ(SignalStrategy::AUTHENTICATION_FAILED,
228 signal_strategy_->GetError());
229 return;
232 socket_data_provider_->ReceiveData(
233 "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
235 base::RunLoop().RunUntilIdle();
237 EXPECT_EQ(
238 "<stream:stream to=\"google.com\" version=\"1.0\" "
239 "xmlns=\"jabber:client\" "
240 "xmlns:stream=\"http://etherx.jabber.org/streams\">"
241 "<iq type=\"set\" id=\"0\">"
242 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">"
243 "<resource>chromoting</resource>"
244 "</bind>"
245 "</iq>"
246 "<iq type=\"set\" id=\"1\">"
247 "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>"
248 "</iq>",
249 socket_data_provider_->GetAndClearWrittenData());
250 socket_data_provider_->ReceiveData(
251 "<stream:stream from=\"google.com\" id=\"104FA10576E2AA80\" "
252 "version=\"1.0\" "
253 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
254 "xmlns=\"jabber:client\">"
255 "<stream:features>"
256 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>"
257 "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>"
258 "</stream:features>"
259 "<iq id=\"0\" type=\"result\">"
260 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">"
261 "<jid>" + std::string(kTestUsername) + "/chromoting52B4920E</jid>"
262 "</bind>"
263 "</iq>"
264 "<iq type=\"result\" id=\"1\"/>");
266 EXPECT_EQ(2U, state_history_.size());
267 EXPECT_EQ(SignalStrategy::CONNECTED, state_history_[1]);
270 TEST_F(XmppSignalStrategyTest, SendAndReceive) {
271 CreateSignalStrategy(kDefaultPort);
272 Connect(true);
274 EXPECT_TRUE(signal_strategy_->SendStanza(make_scoped_ptr(
275 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
276 EXPECT_EQ("<hello/>", socket_data_provider_->GetAndClearWrittenData());
278 socket_data_provider_->ReceiveData("<hi xmlns=\"hello\"/>");
279 EXPECT_EQ(1U, received_messages_.size());
280 EXPECT_EQ("<hi xmlns=\"hello\"/>", received_messages_[0]->Str());
283 TEST_F(XmppSignalStrategyTest, AuthError) {
284 CreateSignalStrategy(kDefaultPort);
285 Connect(false);
288 TEST_F(XmppSignalStrategyTest, ConnectionClosed) {
289 CreateSignalStrategy(kDefaultPort);
290 Connect(true);
292 socket_data_provider_->Close();
294 EXPECT_EQ(3U, state_history_.size());
295 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[2]);
296 EXPECT_EQ(SignalStrategy::DISCONNECTED, signal_strategy_->GetState());
297 EXPECT_EQ(SignalStrategy::OK, signal_strategy_->GetError());
299 // Can't send messages anymore.
300 EXPECT_FALSE(signal_strategy_->SendStanza(make_scoped_ptr(
301 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
303 // Try connecting again.
304 Connect(true);
307 TEST_F(XmppSignalStrategyTest, NetworkReadError) {
308 CreateSignalStrategy(kDefaultPort);
309 Connect(true);
311 socket_data_provider_->SimulateAsyncReadError();
313 EXPECT_EQ(3U, state_history_.size());
314 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[2]);
315 EXPECT_EQ(SignalStrategy::NETWORK_ERROR, signal_strategy_->GetError());
317 // Can't send messages anymore.
318 EXPECT_FALSE(signal_strategy_->SendStanza(make_scoped_ptr(
319 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
321 // Try connecting again.
322 Connect(true);
325 TEST_F(XmppSignalStrategyTest, NetworkWriteError) {
326 CreateSignalStrategy(kDefaultPort);
327 Connect(true);
329 socket_data_provider_->set_write_error(net::ERR_FAILED);
331 // Next SendMessage() will call Write() which will fail.
332 EXPECT_FALSE(signal_strategy_->SendStanza(make_scoped_ptr(
333 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
335 EXPECT_EQ(3U, state_history_.size());
336 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[2]);
337 EXPECT_EQ(SignalStrategy::NETWORK_ERROR, signal_strategy_->GetError());
339 // Try connecting again.
340 Connect(true);
343 TEST_F(XmppSignalStrategyTest, StartTlsWithPendingWrite) {
344 // Use port 5222 so that XmppLoginHandler uses starttls/proceed handshake
345 // before starting TLS.
346 CreateSignalStrategy(5222);
348 socket_data_provider_.reset(new XmppSocketDataProvider());
349 socket_data_provider_->set_connect_data(
350 net::MockConnect(net::SYNCHRONOUS, net::OK));
351 client_socket_factory_.AddSocketDataProvider(socket_data_provider_.get());
353 ssl_socket_data_provider_.reset(
354 new net::SSLSocketDataProvider(net::ASYNC, net::OK));
355 client_socket_factory_.AddSSLSocketDataProvider(
356 ssl_socket_data_provider_.get());
358 // Make sure write is handled asynchronously.
359 socket_data_provider_->set_use_async_write(true);
361 signal_strategy_->Connect();
362 base::RunLoop().RunUntilIdle();
364 socket_data_provider_->ReceiveData(
365 "<stream:stream from=\"google.com\" id=\"104FA10576E2AA80\" "
366 "version=\"1.0\" "
367 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
368 "xmlns=\"jabber:client\">"
369 "<stream:features>"
370 "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"
371 "</stream:features>"
372 "<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
374 // Verify that SSL is connected only after write is finished.
375 EXPECT_FALSE(client_socket_factory_.ssl_socket_created());
376 socket_data_provider_->CompletePendingWrite();
377 EXPECT_TRUE(client_socket_factory_.ssl_socket_created());
381 } // namespace remoting