OLD | NEW |
| (Empty) |
1 // Copyright 2013 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. | |
4 | |
5 #include "google_apis/gcm/engine/connection_handler.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/run_loop.h" | |
10 #include "base/strings/string_number_conversions.h" | |
11 #include "base/test/test_timeouts.h" | |
12 #include "google/protobuf/io/coded_stream.h" | |
13 #include "google/protobuf/io/zero_copy_stream_impl_lite.h" | |
14 #include "google_apis/gcm/base/mcs_util.h" | |
15 #include "google_apis/gcm/base/socket_stream.h" | |
16 #include "google_apis/gcm/protocol/mcs.pb.h" | |
17 #include "net/socket/socket_test_util.h" | |
18 #include "net/socket/stream_socket.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 namespace gcm { | |
22 namespace { | |
23 | |
24 typedef scoped_ptr<google::protobuf::MessageLite> ScopedMessage; | |
25 typedef std::vector<net::MockRead> ReadList; | |
26 typedef std::vector<net::MockWrite> WriteList; | |
27 | |
28 const uint64 kAuthId = 54321; | |
29 const uint64 kAuthToken = 12345; | |
30 const char kMCSVersion = 38; // The protocol version. | |
31 const int kMCSPort = 5228; // The server port. | |
32 const char kDataMsgFrom[] = "data_from"; | |
33 const char kDataMsgCategory[] = "data_category"; | |
34 const char kDataMsgFrom2[] = "data_from2"; | |
35 const char kDataMsgCategory2[] = "data_category2"; | |
36 const char kDataMsgFromLong[] = | |
37 "this is a long from that will result in a message > 128 bytes"; | |
38 const char kDataMsgCategoryLong[] = | |
39 "this is a long category that will result in a message > 128 bytes"; | |
40 const char kDataMsgFromLong2[] = | |
41 "this is a second long from that will result in a message > 128 bytes"; | |
42 const char kDataMsgCategoryLong2[] = | |
43 "this is a second long category that will result in a message > 128 bytes"; | |
44 | |
45 // ---- Helpers for building messages. ---- | |
46 | |
47 // Encode a protobuf packet with protobuf type |tag| and serialized protobuf | |
48 // bytes |proto| into the MCS message form (tag + varint size + bytes). | |
49 std::string EncodePacket(uint8 tag, const std::string& proto) { | |
50 std::string result; | |
51 google::protobuf::io::StringOutputStream string_output_stream(&result); | |
52 google::protobuf::io::CodedOutputStream coded_output_stream( | |
53 &string_output_stream); | |
54 const unsigned char tag_byte[1] = {tag}; | |
55 coded_output_stream.WriteRaw(tag_byte, 1); | |
56 coded_output_stream.WriteVarint32(proto.size()); | |
57 coded_output_stream.WriteRaw(proto.c_str(), proto.size()); | |
58 return result; | |
59 } | |
60 | |
61 // Encode a handshake request into the MCS message form. | |
62 std::string EncodeHandshakeRequest() { | |
63 std::string result; | |
64 const char version_byte[1] = {kMCSVersion}; | |
65 result.append(version_byte, 1); | |
66 ScopedMessage login_request(BuildLoginRequest(kAuthId, kAuthToken)); | |
67 result.append(EncodePacket(kLoginRequestTag, | |
68 login_request->SerializeAsString())); | |
69 return result; | |
70 } | |
71 | |
72 // Build a serialized login response protobuf. | |
73 std::string BuildLoginResponse() { | |
74 std::string result; | |
75 mcs_proto::LoginResponse login_response; | |
76 login_response.set_id("id"); | |
77 result.append(login_response.SerializeAsString()); | |
78 return result; | |
79 } | |
80 | |
81 // Encoode a handshake response into the MCS message form. | |
82 std::string EncodeHandshakeResponse() { | |
83 std::string result; | |
84 const char version_byte[1] = {kMCSVersion}; | |
85 result.append(version_byte, 1); | |
86 result.append(EncodePacket(kLoginResponseTag, BuildLoginResponse())); | |
87 return result; | |
88 } | |
89 | |
90 // Build a serialized data message stanza protobuf. | |
91 std::string BuildDataMessage(const std::string& from, | |
92 const std::string& category) { | |
93 std::string result; | |
94 mcs_proto::DataMessageStanza data_message; | |
95 data_message.set_from(from); | |
96 data_message.set_category(category); | |
97 return data_message.SerializeAsString(); | |
98 } | |
99 | |
100 class GCMConnectionHandlerTest : public testing::Test { | |
101 public: | |
102 GCMConnectionHandlerTest(); | |
103 virtual ~GCMConnectionHandlerTest(); | |
104 | |
105 net::StreamSocket* BuildSocket(const ReadList& read_list, | |
106 const WriteList& write_list); | |
107 | |
108 // Pump |message_loop_|, resetting |run_loop_| after completion. | |
109 void PumpLoop(); | |
110 | |
111 ConnectionHandler* connection_handler() { return &connection_handler_; } | |
112 base::MessageLoop* message_loop() { return &message_loop_; }; | |
113 net::DelayedSocketData* data_provider() { return data_provider_.get(); } | |
114 int last_error() const { return last_error_; } | |
115 | |
116 // Initialize the connection handler, setting |dst_proto| as the destination | |
117 // for any received messages. | |
118 void Connect(ScopedMessage* dst_proto); | |
119 | |
120 // Runs the message loop until a message is received. | |
121 void WaitForMessage(); | |
122 | |
123 private: | |
124 void ReadContinuation(ScopedMessage* dst_proto, ScopedMessage new_proto); | |
125 void WriteContinuation(); | |
126 void ConnectionContinuation(int error); | |
127 | |
128 // SocketStreams and their data provider. | |
129 ReadList mock_reads_; | |
130 WriteList mock_writes_; | |
131 scoped_ptr<net::DelayedSocketData> data_provider_; | |
132 scoped_ptr<SocketInputStream> socket_input_stream_; | |
133 scoped_ptr<SocketOutputStream> socket_output_stream_; | |
134 | |
135 // The connection handler being tested. | |
136 ConnectionHandler connection_handler_; | |
137 | |
138 // The last connection error received. | |
139 int last_error_; | |
140 | |
141 // net:: components. | |
142 scoped_ptr<net::StreamSocket> socket_; | |
143 net::MockClientSocketFactory socket_factory_; | |
144 net::AddressList address_list_; | |
145 | |
146 base::MessageLoopForIO message_loop_; | |
147 scoped_ptr<base::RunLoop> run_loop_; | |
148 }; | |
149 | |
150 GCMConnectionHandlerTest::GCMConnectionHandlerTest() | |
151 : connection_handler_(TestTimeouts::tiny_timeout()), | |
152 last_error_(0) { | |
153 net::IPAddressNumber ip_number; | |
154 net::ParseIPLiteralToNumber("127.0.0.1", &ip_number); | |
155 address_list_ = net::AddressList::CreateFromIPAddress(ip_number, kMCSPort); | |
156 } | |
157 | |
158 GCMConnectionHandlerTest::~GCMConnectionHandlerTest() { | |
159 } | |
160 | |
161 net::StreamSocket* GCMConnectionHandlerTest::BuildSocket( | |
162 const ReadList& read_list, | |
163 const WriteList& write_list) { | |
164 mock_reads_ = read_list; | |
165 mock_writes_ = write_list; | |
166 data_provider_.reset( | |
167 new net::DelayedSocketData(0, | |
168 &(mock_reads_[0]), mock_reads_.size(), | |
169 &(mock_writes_[0]), mock_writes_.size())); | |
170 socket_factory_.AddSocketDataProvider(data_provider_.get()); | |
171 | |
172 socket_ = socket_factory_.CreateTransportClientSocket( | |
173 address_list_, NULL, net::NetLog::Source()); | |
174 socket_->Connect(net::CompletionCallback()); | |
175 | |
176 run_loop_.reset(new base::RunLoop()); | |
177 PumpLoop(); | |
178 | |
179 DCHECK(socket_->IsConnected()); | |
180 return socket_.get(); | |
181 } | |
182 | |
183 void GCMConnectionHandlerTest::PumpLoop() { | |
184 run_loop_->RunUntilIdle(); | |
185 run_loop_.reset(new base::RunLoop()); | |
186 } | |
187 | |
188 void GCMConnectionHandlerTest::Connect( | |
189 ScopedMessage* dst_proto) { | |
190 connection_handler_.Init( | |
191 socket_.Pass(), | |
192 *BuildLoginRequest(kAuthId, kAuthToken), | |
193 base::Bind(&GCMConnectionHandlerTest::ReadContinuation, | |
194 base::Unretained(this), | |
195 dst_proto), | |
196 base::Bind(&GCMConnectionHandlerTest::WriteContinuation, | |
197 base::Unretained(this)), | |
198 base::Bind(&GCMConnectionHandlerTest::ConnectionContinuation, | |
199 base::Unretained(this))); | |
200 } | |
201 | |
202 void GCMConnectionHandlerTest::ReadContinuation( | |
203 ScopedMessage* dst_proto, | |
204 ScopedMessage new_proto) { | |
205 *dst_proto = new_proto.Pass(); | |
206 run_loop_->Quit(); | |
207 } | |
208 | |
209 void GCMConnectionHandlerTest::WaitForMessage() { | |
210 run_loop_->Run(); | |
211 run_loop_.reset(new base::RunLoop()); | |
212 } | |
213 | |
214 void GCMConnectionHandlerTest::WriteContinuation() { | |
215 run_loop_->Quit(); | |
216 } | |
217 | |
218 void GCMConnectionHandlerTest::ConnectionContinuation(int error) { | |
219 last_error_ = error; | |
220 run_loop_->Quit(); | |
221 } | |
222 | |
223 // Initialize the connection handler and ensure the handshake completes | |
224 // successfully. | |
225 TEST_F(GCMConnectionHandlerTest, Init) { | |
226 std::string handshake_request = EncodeHandshakeRequest(); | |
227 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
228 handshake_request.c_str(), | |
229 handshake_request.size())); | |
230 std::string handshake_response = EncodeHandshakeResponse(); | |
231 ReadList read_list(1, net::MockRead(net::ASYNC, | |
232 handshake_response.c_str(), | |
233 handshake_response.size())); | |
234 BuildSocket(read_list, write_list); | |
235 | |
236 ScopedMessage received_message; | |
237 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
238 Connect(&received_message); | |
239 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
240 WaitForMessage(); // The login send. | |
241 WaitForMessage(); // The login response. | |
242 ASSERT_TRUE(received_message.get()); | |
243 EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString()); | |
244 EXPECT_TRUE(connection_handler()->CanSendMessage()); | |
245 } | |
246 | |
247 // Simulate the handshake response returning an older version. Initialization | |
248 // should fail. | |
249 TEST_F(GCMConnectionHandlerTest, InitFailedVersionCheck) { | |
250 std::string handshake_request = EncodeHandshakeRequest(); | |
251 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
252 handshake_request.c_str(), | |
253 handshake_request.size())); | |
254 std::string handshake_response = EncodeHandshakeResponse(); | |
255 // Overwrite the version byte. | |
256 handshake_response[0] = 37; | |
257 ReadList read_list(1, net::MockRead(net::ASYNC, | |
258 handshake_response.c_str(), | |
259 handshake_response.size())); | |
260 BuildSocket(read_list, write_list); | |
261 | |
262 ScopedMessage received_message; | |
263 Connect(&received_message); | |
264 WaitForMessage(); // The login send. | |
265 WaitForMessage(); // The login response. Should result in a connection error. | |
266 EXPECT_FALSE(received_message.get()); | |
267 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
268 EXPECT_EQ(net::ERR_FAILED, last_error()); | |
269 } | |
270 | |
271 // Attempt to initialize, but receive no server response, resulting in a time | |
272 // out. | |
273 TEST_F(GCMConnectionHandlerTest, InitTimeout) { | |
274 std::string handshake_request = EncodeHandshakeRequest(); | |
275 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
276 handshake_request.c_str(), | |
277 handshake_request.size())); | |
278 ReadList read_list(1, net::MockRead(net::SYNCHRONOUS, | |
279 net::ERR_IO_PENDING)); | |
280 BuildSocket(read_list, write_list); | |
281 | |
282 ScopedMessage received_message; | |
283 Connect(&received_message); | |
284 WaitForMessage(); // The login send. | |
285 WaitForMessage(); // The login response. Should result in a connection error. | |
286 EXPECT_FALSE(received_message.get()); | |
287 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
288 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); | |
289 } | |
290 | |
291 // Attempt to initialize, but receive an incomplete server response, resulting | |
292 // in a time out. | |
293 TEST_F(GCMConnectionHandlerTest, InitIncompleteTimeout) { | |
294 std::string handshake_request = EncodeHandshakeRequest(); | |
295 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
296 handshake_request.c_str(), | |
297 handshake_request.size())); | |
298 std::string handshake_response = EncodeHandshakeResponse(); | |
299 ReadList read_list; | |
300 read_list.push_back(net::MockRead(net::ASYNC, | |
301 handshake_response.c_str(), | |
302 handshake_response.size() / 2)); | |
303 read_list.push_back(net::MockRead(net::SYNCHRONOUS, | |
304 net::ERR_IO_PENDING)); | |
305 BuildSocket(read_list, write_list); | |
306 | |
307 ScopedMessage received_message; | |
308 Connect(&received_message); | |
309 WaitForMessage(); // The login send. | |
310 WaitForMessage(); // The login response. Should result in a connection error. | |
311 EXPECT_FALSE(received_message.get()); | |
312 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
313 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); | |
314 } | |
315 | |
316 // Reinitialize the connection handler after failing to initialize. | |
317 TEST_F(GCMConnectionHandlerTest, ReInit) { | |
318 std::string handshake_request = EncodeHandshakeRequest(); | |
319 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
320 handshake_request.c_str(), | |
321 handshake_request.size())); | |
322 ReadList read_list(1, net::MockRead(net::SYNCHRONOUS, | |
323 net::ERR_IO_PENDING)); | |
324 BuildSocket(read_list, write_list); | |
325 | |
326 ScopedMessage received_message; | |
327 Connect(&received_message); | |
328 WaitForMessage(); // The login send. | |
329 WaitForMessage(); // The login response. Should result in a connection error. | |
330 EXPECT_FALSE(received_message.get()); | |
331 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
332 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); | |
333 | |
334 // Build a new socket and reconnect, successfully this time. | |
335 std::string handshake_response = EncodeHandshakeResponse(); | |
336 read_list[0] = net::MockRead(net::ASYNC, | |
337 handshake_response.c_str(), | |
338 handshake_response.size()); | |
339 BuildSocket(read_list, write_list); | |
340 Connect(&received_message); | |
341 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
342 WaitForMessage(); // The login send. | |
343 WaitForMessage(); // The login response. | |
344 ASSERT_TRUE(received_message.get()); | |
345 EXPECT_EQ(BuildLoginResponse(), received_message->SerializeAsString()); | |
346 EXPECT_TRUE(connection_handler()->CanSendMessage()); | |
347 } | |
348 | |
349 // Verify that messages can be received after initialization. | |
350 TEST_F(GCMConnectionHandlerTest, RecvMsg) { | |
351 std::string handshake_request = EncodeHandshakeRequest(); | |
352 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
353 handshake_request.c_str(), | |
354 handshake_request.size())); | |
355 std::string handshake_response = EncodeHandshakeResponse(); | |
356 | |
357 std::string data_message_proto = BuildDataMessage(kDataMsgFrom, | |
358 kDataMsgCategory); | |
359 std::string data_message_pkt = | |
360 EncodePacket(kDataMessageStanzaTag, data_message_proto); | |
361 ReadList read_list; | |
362 read_list.push_back(net::MockRead(net::ASYNC, | |
363 handshake_response.c_str(), | |
364 handshake_response.size())); | |
365 read_list.push_back(net::MockRead(net::ASYNC, | |
366 data_message_pkt.c_str(), | |
367 data_message_pkt.size())); | |
368 BuildSocket(read_list, write_list); | |
369 | |
370 ScopedMessage received_message; | |
371 Connect(&received_message); | |
372 WaitForMessage(); // The login send. | |
373 WaitForMessage(); // The login response. | |
374 WaitForMessage(); // The data message. | |
375 ASSERT_TRUE(received_message.get()); | |
376 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); | |
377 } | |
378 | |
379 // Verify that if two messages arrive at once, they're treated appropriately. | |
380 TEST_F(GCMConnectionHandlerTest, Recv2Msgs) { | |
381 std::string handshake_request = EncodeHandshakeRequest(); | |
382 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
383 handshake_request.c_str(), | |
384 handshake_request.size())); | |
385 std::string handshake_response = EncodeHandshakeResponse(); | |
386 | |
387 std::string data_message_proto = BuildDataMessage(kDataMsgFrom, | |
388 kDataMsgCategory); | |
389 std::string data_message_proto2 = BuildDataMessage(kDataMsgFrom2, | |
390 kDataMsgCategory2); | |
391 std::string data_message_pkt = | |
392 EncodePacket(kDataMessageStanzaTag, data_message_proto); | |
393 data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2); | |
394 ReadList read_list; | |
395 read_list.push_back(net::MockRead(net::ASYNC, | |
396 handshake_response.c_str(), | |
397 handshake_response.size())); | |
398 read_list.push_back(net::MockRead(net::SYNCHRONOUS, | |
399 data_message_pkt.c_str(), | |
400 data_message_pkt.size())); | |
401 BuildSocket(read_list, write_list); | |
402 | |
403 ScopedMessage received_message; | |
404 Connect(&received_message); | |
405 WaitForMessage(); // The login send. | |
406 WaitForMessage(); // The login response. | |
407 WaitForMessage(); // The first data message. | |
408 ASSERT_TRUE(received_message.get()); | |
409 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); | |
410 received_message.reset(); | |
411 WaitForMessage(); // The second data message. | |
412 ASSERT_TRUE(received_message.get()); | |
413 EXPECT_EQ(data_message_proto2, received_message->SerializeAsString()); | |
414 } | |
415 | |
416 // Receive a long (>128 bytes) message. | |
417 TEST_F(GCMConnectionHandlerTest, RecvLongMsg) { | |
418 std::string handshake_request = EncodeHandshakeRequest(); | |
419 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
420 handshake_request.c_str(), | |
421 handshake_request.size())); | |
422 std::string handshake_response = EncodeHandshakeResponse(); | |
423 | |
424 std::string data_message_proto = | |
425 BuildDataMessage(kDataMsgFromLong, kDataMsgCategoryLong); | |
426 std::string data_message_pkt = | |
427 EncodePacket(kDataMessageStanzaTag, data_message_proto); | |
428 DCHECK_GT(data_message_pkt.size(), 128U); | |
429 ReadList read_list; | |
430 read_list.push_back(net::MockRead(net::ASYNC, | |
431 handshake_response.c_str(), | |
432 handshake_response.size())); | |
433 read_list.push_back(net::MockRead(net::ASYNC, | |
434 data_message_pkt.c_str(), | |
435 data_message_pkt.size())); | |
436 BuildSocket(read_list, write_list); | |
437 | |
438 ScopedMessage received_message; | |
439 Connect(&received_message); | |
440 WaitForMessage(); // The login send. | |
441 WaitForMessage(); // The login response. | |
442 WaitForMessage(); // The data message. | |
443 ASSERT_TRUE(received_message.get()); | |
444 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); | |
445 } | |
446 | |
447 // Receive two long (>128 bytes) message. | |
448 TEST_F(GCMConnectionHandlerTest, Recv2LongMsgs) { | |
449 std::string handshake_request = EncodeHandshakeRequest(); | |
450 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
451 handshake_request.c_str(), | |
452 handshake_request.size())); | |
453 std::string handshake_response = EncodeHandshakeResponse(); | |
454 | |
455 std::string data_message_proto = | |
456 BuildDataMessage(kDataMsgFromLong, kDataMsgCategoryLong); | |
457 std::string data_message_proto2 = | |
458 BuildDataMessage(kDataMsgFromLong2, kDataMsgCategoryLong2); | |
459 std::string data_message_pkt = | |
460 EncodePacket(kDataMessageStanzaTag, data_message_proto); | |
461 data_message_pkt += EncodePacket(kDataMessageStanzaTag, data_message_proto2); | |
462 DCHECK_GT(data_message_pkt.size(), 256U); | |
463 ReadList read_list; | |
464 read_list.push_back(net::MockRead(net::ASYNC, | |
465 handshake_response.c_str(), | |
466 handshake_response.size())); | |
467 read_list.push_back(net::MockRead(net::SYNCHRONOUS, | |
468 data_message_pkt.c_str(), | |
469 data_message_pkt.size())); | |
470 BuildSocket(read_list, write_list); | |
471 | |
472 ScopedMessage received_message; | |
473 Connect(&received_message); | |
474 WaitForMessage(); // The login send. | |
475 WaitForMessage(); // The login response. | |
476 WaitForMessage(); // The first data message. | |
477 ASSERT_TRUE(received_message.get()); | |
478 EXPECT_EQ(data_message_proto, received_message->SerializeAsString()); | |
479 received_message.reset(); | |
480 WaitForMessage(); // The second data message. | |
481 ASSERT_TRUE(received_message.get()); | |
482 EXPECT_EQ(data_message_proto2, received_message->SerializeAsString()); | |
483 } | |
484 | |
485 // Simulate a message where the end of the data does not arrive in time and the | |
486 // read times out. | |
487 TEST_F(GCMConnectionHandlerTest, ReadTimeout) { | |
488 std::string handshake_request = EncodeHandshakeRequest(); | |
489 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
490 handshake_request.c_str(), | |
491 handshake_request.size())); | |
492 std::string handshake_response = EncodeHandshakeResponse(); | |
493 | |
494 std::string data_message_proto = BuildDataMessage(kDataMsgFrom, | |
495 kDataMsgCategory); | |
496 std::string data_message_pkt = | |
497 EncodePacket(kDataMessageStanzaTag, data_message_proto); | |
498 int bytes_in_first_message = data_message_pkt.size() / 2; | |
499 ReadList read_list; | |
500 read_list.push_back(net::MockRead(net::ASYNC, | |
501 handshake_response.c_str(), | |
502 handshake_response.size())); | |
503 read_list.push_back(net::MockRead(net::ASYNC, | |
504 data_message_pkt.c_str(), | |
505 bytes_in_first_message)); | |
506 read_list.push_back(net::MockRead(net::SYNCHRONOUS, | |
507 net::ERR_IO_PENDING)); | |
508 read_list.push_back(net::MockRead(net::ASYNC, | |
509 data_message_pkt.c_str() + | |
510 bytes_in_first_message, | |
511 data_message_pkt.size() - | |
512 bytes_in_first_message)); | |
513 BuildSocket(read_list, write_list); | |
514 | |
515 ScopedMessage received_message; | |
516 Connect(&received_message); | |
517 WaitForMessage(); // The login send. | |
518 WaitForMessage(); // The login response. | |
519 received_message.reset(); | |
520 WaitForMessage(); // Should time out. | |
521 EXPECT_FALSE(received_message.get()); | |
522 EXPECT_EQ(net::ERR_TIMED_OUT, last_error()); | |
523 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
524 | |
525 // Finish the socket read. Should have no effect. | |
526 data_provider()->ForceNextRead(); | |
527 } | |
528 | |
529 // Receive a message with zero data bytes. | |
530 TEST_F(GCMConnectionHandlerTest, RecvMsgNoData) { | |
531 std::string handshake_request = EncodeHandshakeRequest(); | |
532 WriteList write_list(1, net::MockWrite(net::ASYNC, | |
533 handshake_request.c_str(), | |
534 handshake_request.size())); | |
535 std::string handshake_response = EncodeHandshakeResponse(); | |
536 | |
537 std::string data_message_pkt = EncodePacket(kHeartbeatPingTag, ""); | |
538 ASSERT_EQ(data_message_pkt.size(), 2U); | |
539 ReadList read_list; | |
540 read_list.push_back(net::MockRead(net::ASYNC, | |
541 handshake_response.c_str(), | |
542 handshake_response.size())); | |
543 read_list.push_back(net::MockRead(net::ASYNC, | |
544 data_message_pkt.c_str(), | |
545 data_message_pkt.size())); | |
546 BuildSocket(read_list, write_list); | |
547 | |
548 ScopedMessage received_message; | |
549 Connect(&received_message); | |
550 WaitForMessage(); // The login send. | |
551 WaitForMessage(); // The login response. | |
552 received_message.reset(); | |
553 WaitForMessage(); // The heartbeat ping. | |
554 EXPECT_TRUE(received_message.get()); | |
555 EXPECT_EQ(GetMCSProtoTag(*received_message), kHeartbeatPingTag); | |
556 EXPECT_EQ(net::OK, last_error()); | |
557 EXPECT_TRUE(connection_handler()->CanSendMessage()); | |
558 } | |
559 | |
560 // Send a message after performing the handshake. | |
561 TEST_F(GCMConnectionHandlerTest, SendMsg) { | |
562 mcs_proto::DataMessageStanza data_message; | |
563 data_message.set_from(kDataMsgFrom); | |
564 data_message.set_category(kDataMsgCategory); | |
565 std::string handshake_request = EncodeHandshakeRequest(); | |
566 std::string data_message_pkt = | |
567 EncodePacket(kDataMessageStanzaTag, data_message.SerializeAsString()); | |
568 WriteList write_list; | |
569 write_list.push_back(net::MockWrite(net::ASYNC, | |
570 handshake_request.c_str(), | |
571 handshake_request.size())); | |
572 write_list.push_back(net::MockWrite(net::ASYNC, | |
573 data_message_pkt.c_str(), | |
574 data_message_pkt.size())); | |
575 std::string handshake_response = EncodeHandshakeResponse(); | |
576 ReadList read_list; | |
577 read_list.push_back(net::MockRead(net::ASYNC, | |
578 handshake_response.c_str(), | |
579 handshake_response.size())); | |
580 read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)); | |
581 BuildSocket(read_list, write_list); | |
582 | |
583 ScopedMessage received_message; | |
584 Connect(&received_message); | |
585 WaitForMessage(); // The login send. | |
586 WaitForMessage(); // The login response. | |
587 EXPECT_TRUE(connection_handler()->CanSendMessage()); | |
588 connection_handler()->SendMessage(data_message); | |
589 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
590 WaitForMessage(); // The message send. | |
591 EXPECT_TRUE(connection_handler()->CanSendMessage()); | |
592 } | |
593 | |
594 // Attempt to send a message after the socket is disconnected due to a timeout. | |
595 TEST_F(GCMConnectionHandlerTest, SendMsgSocketDisconnected) { | |
596 std::string handshake_request = EncodeHandshakeRequest(); | |
597 WriteList write_list; | |
598 write_list.push_back(net::MockWrite(net::ASYNC, | |
599 handshake_request.c_str(), | |
600 handshake_request.size())); | |
601 std::string handshake_response = EncodeHandshakeResponse(); | |
602 ReadList read_list; | |
603 read_list.push_back(net::MockRead(net::ASYNC, | |
604 handshake_response.c_str(), | |
605 handshake_response.size())); | |
606 read_list.push_back(net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING)); | |
607 net::StreamSocket* socket = BuildSocket(read_list, write_list); | |
608 | |
609 ScopedMessage received_message; | |
610 Connect(&received_message); | |
611 WaitForMessage(); // The login send. | |
612 WaitForMessage(); // The login response. | |
613 EXPECT_TRUE(connection_handler()->CanSendMessage()); | |
614 socket->Disconnect(); | |
615 mcs_proto::DataMessageStanza data_message; | |
616 data_message.set_from(kDataMsgFrom); | |
617 data_message.set_category(kDataMsgCategory); | |
618 connection_handler()->SendMessage(data_message); | |
619 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
620 WaitForMessage(); // The message send. Should result in an error | |
621 EXPECT_FALSE(connection_handler()->CanSendMessage()); | |
622 EXPECT_EQ(net::ERR_CONNECTION_CLOSED, last_error()); | |
623 } | |
624 | |
625 } // namespace | |
626 } // namespace gcm | |
OLD | NEW |