Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / remoting / signaling / xmpp_signal_strategy_unittest.cc
blobf4a6d0b5160131482d7f606da5c07a5ec39d750a
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 written_data_.append(data);
28 if (use_async_write_) {
29 pending_write_size_ = data.size();
30 return net::MockWriteResult(net::ASYNC, net::ERR_IO_PENDING);
33 return net::MockWriteResult(net::SYNCHRONOUS, data.size());
36 void Reset() override {}
38 bool AllReadDataConsumed() const override {
39 return true;
42 bool AllWriteDataConsumed() const override {
43 return true;
46 void ReceiveData(const std::string& text) {
47 socket()->OnReadComplete(
48 net::MockRead(net::ASYNC, text.data(), text.size()));
51 void Close() {
52 ReceiveData(std::string());
55 void SimulateNetworkError() {
56 socket()->OnReadComplete(
57 net::MockRead(net::ASYNC, net::ERR_CONNECTION_RESET));
60 std::string GetAndClearWrittenData() {
61 std::string data;
62 data.swap(written_data_);
63 return data;
66 void set_use_async_write(bool use_async_write) {
67 use_async_write_ = use_async_write;
70 void CompletePendingWrite() {
71 socket()->OnWriteComplete(pending_write_size_);
74 private:
75 std::string written_data_;
76 bool use_async_write_ = false;
77 int pending_write_size_ = 0;
80 class MockClientSocketFactory : public net::MockClientSocketFactory {
81 public:
82 scoped_ptr<net::SSLClientSocket> CreateSSLClientSocket(
83 scoped_ptr<net::ClientSocketHandle> transport_socket,
84 const net::HostPortPair& host_and_port,
85 const net::SSLConfig& ssl_config,
86 const net::SSLClientSocketContext& context) override {
87 ssl_socket_created_ = true;
88 return net::MockClientSocketFactory::CreateSSLClientSocket(
89 transport_socket.Pass(), host_and_port, ssl_config, context);
92 bool ssl_socket_created() const { return ssl_socket_created_; }
94 private:
95 bool ssl_socket_created_ = false;
98 } // namespace
100 const char kTestUsername[] = "test_username@example.com";
101 const char kTestAuthToken[] = "test_auth_token";
102 const int kDefaultPort = 443;
104 class XmppSignalStrategyTest : public testing::Test,
105 public SignalStrategy::Listener {
106 public:
107 XmppSignalStrategyTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
109 void SetUp() override {
110 scoped_ptr<net::TestURLRequestContext> context(
111 new net::TestURLRequestContext());
112 request_context_getter_ = new net::TestURLRequestContextGetter(
113 message_loop_.task_runner(), context.Pass());
116 void CreateSignalStrategy(int port) {
117 XmppSignalStrategy::XmppServerConfig config;
118 config.host = "talk.google.com";
119 config.port = port;
120 config.username = kTestUsername;
121 config.auth_token = kTestAuthToken;
122 signal_strategy_.reset(new XmppSignalStrategy(
123 &client_socket_factory_, request_context_getter_, config));
124 signal_strategy_->AddListener(this);
127 void TearDown() override {
128 signal_strategy_->RemoveListener(this);
129 signal_strategy_.reset();
130 base::RunLoop().RunUntilIdle();
133 void OnSignalStrategyStateChange(SignalStrategy::State state) override {
134 state_history_.push_back(state);
137 bool OnSignalStrategyIncomingStanza(const buzz::XmlElement* stanza) override {
138 received_messages_.push_back(
139 make_scoped_ptr(new buzz::XmlElement(*stanza)));
140 return true;
143 void Connect(bool success);
145 protected:
146 base::MessageLoop message_loop_;
147 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
148 MockClientSocketFactory client_socket_factory_;
149 scoped_ptr<XmppSocketDataProvider> socket_data_provider_;
150 scoped_ptr<net::SSLSocketDataProvider> ssl_socket_data_provider_;
151 scoped_ptr<XmppSignalStrategy> signal_strategy_;
153 std::vector<SignalStrategy::State> state_history_;
154 ScopedVector<buzz::XmlElement> received_messages_;
157 void XmppSignalStrategyTest::Connect(bool success) {
158 EXPECT_EQ(SignalStrategy::DISCONNECTED, signal_strategy_->GetState());
159 state_history_.clear();
161 socket_data_provider_.reset(new XmppSocketDataProvider());
162 socket_data_provider_->set_connect_data(
163 net::MockConnect(net::ASYNC, net::OK));
164 client_socket_factory_.AddSocketDataProvider(socket_data_provider_.get());
166 ssl_socket_data_provider_.reset(
167 new net::SSLSocketDataProvider(net::ASYNC, net::OK));
168 client_socket_factory_.AddSSLSocketDataProvider(
169 ssl_socket_data_provider_.get());
171 signal_strategy_->Connect();
173 EXPECT_EQ(SignalStrategy::CONNECTING, signal_strategy_->GetState());
174 EXPECT_EQ(1U, state_history_.size());
175 EXPECT_EQ(SignalStrategy::CONNECTING, state_history_[0]);
177 // No data written before TLS.
178 EXPECT_EQ("", socket_data_provider_->GetAndClearWrittenData());
180 base::RunLoop().RunUntilIdle();
182 socket_data_provider_->ReceiveData(
183 "<stream:stream from=\"google.com\" id=\"DCDDE5171CB2154A\" "
184 "version=\"1.0\" "
185 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
186 "xmlns=\"jabber:client\">"
187 "<stream:features>"
188 "<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
189 "<mechanism>X-OAUTH2</mechanism>"
190 "<mechanism>X-GOOGLE-TOKEN</mechanism>"
191 "<mechanism>PLAIN</mechanism>"
192 "</mechanisms>"
193 "</stream:features>");
195 base::RunLoop().RunUntilIdle();
197 std::string cookie;
198 base::Base64Encode(std::string("\0", 1) + kTestUsername +
199 std::string("\0", 1) + kTestAuthToken,
200 &cookie);
201 // Expect auth message.
202 EXPECT_EQ(
203 "<stream:stream to=\"google.com\" version=\"1.0\" "
204 "xmlns=\"jabber:client\" "
205 "xmlns:stream=\"http://etherx.jabber.org/streams\">"
206 "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-OAUTH2\" "
207 "auth:service=\"oauth2\" auth:allow-generated-jid=\"true\" "
208 "auth:client-uses-full-bind-result=\"true\" "
209 "auth:allow-non-google-login=\"true\" "
210 "xmlns:auth=\"http://www.google.com/talk/protocol/auth\">" + cookie +
211 "</auth>", socket_data_provider_->GetAndClearWrittenData());
213 if (!success) {
214 socket_data_provider_->ReceiveData(
215 "<failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"
216 "<not-authorized/></failure>");
217 EXPECT_EQ(2U, state_history_.size());
218 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[1]);
219 EXPECT_EQ(SignalStrategy::AUTHENTICATION_FAILED,
220 signal_strategy_->GetError());
221 return;
224 socket_data_provider_->ReceiveData(
225 "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"/>");
227 base::RunLoop().RunUntilIdle();
229 EXPECT_EQ(
230 "<stream:stream to=\"google.com\" version=\"1.0\" "
231 "xmlns=\"jabber:client\" "
232 "xmlns:stream=\"http://etherx.jabber.org/streams\">"
233 "<iq type=\"set\" id=\"0\">"
234 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">"
235 "<resource>chromoting</resource>"
236 "</bind>"
237 "</iq>"
238 "<iq type=\"set\" id=\"1\">"
239 "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>"
240 "</iq>",
241 socket_data_provider_->GetAndClearWrittenData());
242 socket_data_provider_->ReceiveData(
243 "<stream:stream from=\"google.com\" id=\"104FA10576E2AA80\" "
244 "version=\"1.0\" "
245 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
246 "xmlns=\"jabber:client\">"
247 "<stream:features>"
248 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>"
249 "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>"
250 "</stream:features>"
251 "<iq id=\"0\" type=\"result\">"
252 "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\">"
253 "<jid>" + std::string(kTestUsername) + "/chromoting52B4920E</jid>"
254 "</bind>"
255 "</iq>"
256 "<iq type=\"result\" id=\"1\"/>");
258 EXPECT_EQ(2U, state_history_.size());
259 EXPECT_EQ(SignalStrategy::CONNECTED, state_history_[1]);
262 TEST_F(XmppSignalStrategyTest, SendAndReceive) {
263 CreateSignalStrategy(kDefaultPort);
264 Connect(true);
266 EXPECT_TRUE(signal_strategy_->SendStanza(make_scoped_ptr(
267 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
268 EXPECT_EQ("<hello/>", socket_data_provider_->GetAndClearWrittenData());
270 socket_data_provider_->ReceiveData("<hi xmlns=\"hello\"/>");
271 EXPECT_EQ(1U, received_messages_.size());
272 EXPECT_EQ("<hi xmlns=\"hello\"/>", received_messages_[0]->Str());
275 TEST_F(XmppSignalStrategyTest, AuthError) {
276 CreateSignalStrategy(kDefaultPort);
277 Connect(false);
280 TEST_F(XmppSignalStrategyTest, ConnectionClosed) {
281 CreateSignalStrategy(kDefaultPort);
282 Connect(true);
284 socket_data_provider_->Close();
286 EXPECT_EQ(3U, state_history_.size());
287 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[2]);
288 EXPECT_EQ(SignalStrategy::DISCONNECTED, signal_strategy_->GetState());
289 EXPECT_EQ(SignalStrategy::OK, signal_strategy_->GetError());
291 // Can't send messages anymore.
292 EXPECT_FALSE(signal_strategy_->SendStanza(make_scoped_ptr(
293 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
295 // Try connecting again.
296 Connect(true);
299 TEST_F(XmppSignalStrategyTest, NetworkError) {
300 CreateSignalStrategy(kDefaultPort);
301 Connect(true);
303 socket_data_provider_->SimulateNetworkError();
305 EXPECT_EQ(3U, state_history_.size());
306 EXPECT_EQ(SignalStrategy::DISCONNECTED, state_history_[2]);
307 EXPECT_EQ(SignalStrategy::NETWORK_ERROR, signal_strategy_->GetError());
309 // Can't send messages anymore.
310 EXPECT_FALSE(signal_strategy_->SendStanza(make_scoped_ptr(
311 new buzz::XmlElement(buzz::QName(std::string(), "hello")))));
313 // Try connecting again.
314 Connect(true);
317 TEST_F(XmppSignalStrategyTest, StartTlsWithPendingWrite) {
318 // Use port 5222 so that XmppLoginHandler uses starttls/proceed handshake
319 // before starting TLS.
320 CreateSignalStrategy(5222);
322 socket_data_provider_.reset(new XmppSocketDataProvider());
323 socket_data_provider_->set_connect_data(
324 net::MockConnect(net::SYNCHRONOUS, net::OK));
325 client_socket_factory_.AddSocketDataProvider(socket_data_provider_.get());
327 ssl_socket_data_provider_.reset(
328 new net::SSLSocketDataProvider(net::ASYNC, net::OK));
329 client_socket_factory_.AddSSLSocketDataProvider(
330 ssl_socket_data_provider_.get());
332 // Make sure write is handled asynchronously.
333 socket_data_provider_->set_use_async_write(true);
335 signal_strategy_->Connect();
336 base::RunLoop().RunUntilIdle();
338 socket_data_provider_->ReceiveData(
339 "<stream:stream from=\"google.com\" id=\"104FA10576E2AA80\" "
340 "version=\"1.0\" "
341 "xmlns:stream=\"http://etherx.jabber.org/streams\" "
342 "xmlns=\"jabber:client\">"
343 "<stream:features>"
344 "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"
345 "</stream:features>"
346 "<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
348 // Verify that SSL is connected only after write is finished.
349 EXPECT_FALSE(client_socket_factory_.ssl_socket_created());
350 socket_data_provider_->CompletePendingWrite();
351 EXPECT_TRUE(client_socket_factory_.ssl_socket_created());
355 } // namespace remoting