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.
5 #include "google_apis/gcm/engine/mcs_client.h"
7 #include "base/command_line.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/test/simple_test_clock.h"
13 #include "google_apis/gcm/base/fake_encryptor.h"
14 #include "google_apis/gcm/base/mcs_util.h"
15 #include "google_apis/gcm/engine/fake_connection_factory.h"
16 #include "google_apis/gcm/engine/fake_connection_handler.h"
17 #include "google_apis/gcm/engine/gcm_store_impl.h"
18 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 const uint64 kAndroidId
= 54321;
26 const uint64 kSecurityToken
= 12345;
28 // Number of messages to send when testing batching.
29 // Note: must be even for tests that split batches in half.
30 const int kMessageBatchSize
= 6;
32 // The number of unacked messages the client will receive before sending a
34 // TODO(zea): get this (and other constants) directly from the mcs client.
35 const int kAckLimitSize
= 10;
37 // TTL value for reliable messages.
38 const int kTTLValue
= 5 * 60; // 5 minutes.
40 // Helper for building arbitrary data messages.
41 MCSMessage
BuildDataMessage(const std::string
& from
,
42 const std::string
& category
,
43 const std::string
& message_id
,
44 int last_stream_id_received
,
45 const std::string
& persistent_id
,
49 const std::string
& token
,
50 const uint64
& user_id
) {
51 mcs_proto::DataMessageStanza data_message
;
52 data_message
.set_id(message_id
);
53 data_message
.set_from(from
);
54 data_message
.set_category(category
);
55 data_message
.set_last_stream_id_received(last_stream_id_received
);
56 if (!persistent_id
.empty())
57 data_message
.set_persistent_id(persistent_id
);
58 data_message
.set_ttl(ttl
);
59 data_message
.set_sent(sent
);
60 data_message
.set_queued(queued
);
61 data_message
.set_token(token
);
62 data_message
.set_device_user_id(user_id
);
63 return MCSMessage(kDataMessageStanzaTag
, data_message
);
66 // MCSClient with overriden exposed persistent id logic.
67 class TestMCSClient
: public MCSClient
{
69 TestMCSClient(base::Clock
* clock
,
70 ConnectionFactory
* connection_factory
,
72 gcm::GCMStatsRecorder
* recorder
)
73 : MCSClient("", clock
, connection_factory
, gcm_store
, recorder
),
77 virtual std::string
GetNextPersistentId() OVERRIDE
{
78 return base::UintToString(++next_id_
);
85 class MCSClientTest
: public testing::Test
{
88 virtual ~MCSClientTest();
90 virtual void SetUp() OVERRIDE
;
92 void BuildMCSClient();
93 void InitializeClient();
94 void StoreCredentials();
95 void LoginClient(const std::vector
<std::string
>& acknowledged_ids
);
97 base::SimpleTestClock
* clock() { return &clock_
; }
98 TestMCSClient
* mcs_client() const { return mcs_client_
.get(); }
99 FakeConnectionFactory
* connection_factory() {
100 return &connection_factory_
;
102 bool init_success() const { return init_success_
; }
103 uint64
restored_android_id() const { return restored_android_id_
; }
104 uint64
restored_security_token() const { return restored_security_token_
; }
105 MCSMessage
* received_message() const { return received_message_
.get(); }
106 std::string
sent_message_id() const { return sent_message_id_
;}
107 MCSClient::MessageSendStatus
message_send_status() const {
108 return message_send_status_
;
111 void SetDeviceCredentialsCallback(bool success
);
113 FakeConnectionHandler
* GetFakeHandler() const;
115 void WaitForMCSEvent();
119 void ErrorCallback();
120 void MessageReceivedCallback(const MCSMessage
& message
);
121 void MessageSentCallback(int64 user_serial_number
,
122 const std::string
& app_id
,
123 const std::string
& message_id
,
124 MCSClient::MessageSendStatus status
);
126 base::SimpleTestClock clock_
;
128 base::ScopedTempDir temp_directory_
;
129 base::MessageLoop message_loop_
;
130 scoped_ptr
<base::RunLoop
> run_loop_
;
131 scoped_ptr
<GCMStore
> gcm_store_
;
133 FakeConnectionFactory connection_factory_
;
134 scoped_ptr
<TestMCSClient
> mcs_client_
;
136 uint64 restored_android_id_
;
137 uint64 restored_security_token_
;
138 scoped_ptr
<MCSMessage
> received_message_
;
139 std::string sent_message_id_
;
140 MCSClient::MessageSendStatus message_send_status_
;
142 gcm::FakeGCMStatsRecorder recorder_
;
145 MCSClientTest::MCSClientTest()
146 : run_loop_(new base::RunLoop()),
148 restored_android_id_(0),
149 restored_security_token_(0),
150 message_send_status_(MCSClient::SENT
) {
151 EXPECT_TRUE(temp_directory_
.CreateUniqueTempDir());
152 run_loop_
.reset(new base::RunLoop());
154 // Advance the clock to a non-zero time.
155 clock_
.Advance(base::TimeDelta::FromSeconds(1));
158 MCSClientTest::~MCSClientTest() {}
160 void MCSClientTest::SetUp() {
161 testing::Test::SetUp();
164 void MCSClientTest::BuildMCSClient() {
165 gcm_store_
.reset(new GCMStoreImpl(
166 temp_directory_
.path(),
167 message_loop_
.message_loop_proxy(),
168 make_scoped_ptr
<Encryptor
>(new FakeEncryptor
)));
169 mcs_client_
.reset(new TestMCSClient(&clock_
,
170 &connection_factory_
,
175 void MCSClientTest::InitializeClient() {
176 gcm_store_
->Load(base::Bind(
177 &MCSClient::Initialize
,
178 base::Unretained(mcs_client_
.get()),
179 base::Bind(&MCSClientTest::ErrorCallback
,
180 base::Unretained(this)),
181 base::Bind(&MCSClientTest::MessageReceivedCallback
,
182 base::Unretained(this)),
183 base::Bind(&MCSClientTest::MessageSentCallback
, base::Unretained(this))));
184 run_loop_
->RunUntilIdle();
185 run_loop_
.reset(new base::RunLoop());
188 void MCSClientTest::LoginClient(
189 const std::vector
<std::string
>& acknowledged_ids
) {
190 scoped_ptr
<mcs_proto::LoginRequest
> login_request
=
191 BuildLoginRequest(kAndroidId
, kSecurityToken
, "");
192 for (size_t i
= 0; i
< acknowledged_ids
.size(); ++i
)
193 login_request
->add_received_persistent_id(acknowledged_ids
[i
]);
194 GetFakeHandler()->ExpectOutgoingMessage(
195 MCSMessage(kLoginRequestTag
,
196 login_request
.PassAs
<const google::protobuf::MessageLite
>()));
197 mcs_client_
->Login(kAndroidId
, kSecurityToken
);
199 run_loop_
.reset(new base::RunLoop());
202 void MCSClientTest::StoreCredentials() {
203 gcm_store_
->SetDeviceCredentials(
204 kAndroidId
, kSecurityToken
,
205 base::Bind(&MCSClientTest::SetDeviceCredentialsCallback
,
206 base::Unretained(this)));
208 run_loop_
.reset(new base::RunLoop());
211 FakeConnectionHandler
* MCSClientTest::GetFakeHandler() const {
212 return reinterpret_cast<FakeConnectionHandler
*>(
213 connection_factory_
.GetConnectionHandler());
216 void MCSClientTest::WaitForMCSEvent() {
218 run_loop_
.reset(new base::RunLoop());
221 void MCSClientTest::PumpLoop() {
222 run_loop_
->RunUntilIdle();
223 run_loop_
.reset(new base::RunLoop());
226 void MCSClientTest::ErrorCallback() {
227 init_success_
= false;
228 DVLOG(1) << "Error callback invoked, killing loop.";
232 void MCSClientTest::MessageReceivedCallback(const MCSMessage
& message
) {
233 received_message_
.reset(new MCSMessage(message
));
234 DVLOG(1) << "Message received callback invoked, killing loop.";
238 void MCSClientTest::MessageSentCallback(int64 user_serial_number
,
239 const std::string
& app_id
,
240 const std::string
& message_id
,
241 MCSClient::MessageSendStatus status
) {
242 DVLOG(1) << "Message sent callback invoked, killing loop.";
243 sent_message_id_
= message_id
;
244 message_send_status_
= status
;
248 void MCSClientTest::SetDeviceCredentialsCallback(bool success
) {
249 ASSERT_TRUE(success
);
253 // Initialize a new client.
254 TEST_F(MCSClientTest
, InitializeNew
) {
257 EXPECT_TRUE(init_success());
260 // Initialize a new client, shut it down, then restart the client. Should
261 // reload the existing device credentials.
262 TEST_F(MCSClientTest
, InitializeExisting
) {
265 LoginClient(std::vector
<std::string
>());
267 // Rebuild the client, to reload from the GCM store.
271 EXPECT_TRUE(init_success());
274 // Log in successfully to the MCS endpoint.
275 TEST_F(MCSClientTest
, LoginSuccess
) {
278 LoginClient(std::vector
<std::string
>());
279 EXPECT_TRUE(connection_factory()->IsEndpointReachable());
280 EXPECT_TRUE(init_success());
281 ASSERT_TRUE(received_message());
282 EXPECT_EQ(kLoginResponseTag
, received_message()->tag());
285 // Encounter a server error during the login attempt. Should trigger a
287 TEST_F(MCSClientTest
, FailLogin
) {
290 GetFakeHandler()->set_fail_login(true);
291 connection_factory()->set_delay_reconnect(true);
292 LoginClient(std::vector
<std::string
>());
293 EXPECT_FALSE(connection_factory()->IsEndpointReachable());
294 EXPECT_FALSE(init_success());
295 EXPECT_FALSE(received_message());
296 EXPECT_TRUE(connection_factory()->reconnect_pending());
299 // Send a message without RMQ support.
300 TEST_F(MCSClientTest
, SendMessageNoRMQ
) {
303 LoginClient(std::vector
<std::string
>());
305 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
306 GetFakeHandler()->ExpectOutgoingMessage(message
);
307 mcs_client()->SendMessage(message
);
308 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
311 // Send a message without RMQ support while disconnected. Message send should
312 // fail immediately, invoking callback.
313 TEST_F(MCSClientTest
, SendMessageNoRMQWhileDisconnected
) {
317 EXPECT_TRUE(sent_message_id().empty());
319 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
320 mcs_client()->SendMessage(message
);
322 // Message sent callback should be invoked, but no message should actually
324 EXPECT_EQ("X", sent_message_id());
325 EXPECT_EQ(MCSClient::NO_CONNECTION_ON_ZERO_TTL
, message_send_status());
326 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
329 // Send a message with RMQ support.
330 TEST_F(MCSClientTest
, SendMessageRMQ
) {
333 LoginClient(std::vector
<std::string
>());
334 MCSMessage
message(BuildDataMessage(
335 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
336 GetFakeHandler()->ExpectOutgoingMessage(message
);
337 mcs_client()->SendMessage(message
);
338 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
341 // Send a message with RMQ support while disconnected. On reconnect, the message
343 TEST_F(MCSClientTest
, SendMessageRMQWhileDisconnected
) {
346 LoginClient(std::vector
<std::string
>());
347 GetFakeHandler()->set_fail_send(true);
348 MCSMessage
message(BuildDataMessage(
349 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
351 // The initial (failed) send.
352 GetFakeHandler()->ExpectOutgoingMessage(message
);
353 // The login request.
354 GetFakeHandler()->ExpectOutgoingMessage(
357 BuildLoginRequest(kAndroidId
, kSecurityToken
, "").
358 PassAs
<const google::protobuf::MessageLite
>()));
359 // The second (re)send.
360 MCSMessage
message2(BuildDataMessage(
361 "from", "category", "X", 1, "1", kTTLValue
, 1, kTTLValue
- 1, "", 0));
362 GetFakeHandler()->ExpectOutgoingMessage(message2
);
363 mcs_client()->SendMessage(message
);
364 PumpLoop(); // Wait for the queuing to happen.
365 EXPECT_EQ(MCSClient::QUEUED
, message_send_status());
366 EXPECT_EQ("X", sent_message_id());
367 EXPECT_FALSE(GetFakeHandler()->AllOutgoingMessagesReceived());
368 GetFakeHandler()->set_fail_send(false);
369 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
- 1));
370 connection_factory()->Connect();
371 WaitForMCSEvent(); // Wait for the login to finish.
372 PumpLoop(); // Wait for the send to happen.
375 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
376 ack
->set_last_stream_id_received(2);
377 GetFakeHandler()->ReceiveMessage(
378 MCSMessage(kIqStanzaTag
,
379 ack
.PassAs
<const google::protobuf::MessageLite
>()));
382 EXPECT_EQ(MCSClient::SENT
, message_send_status());
383 EXPECT_EQ("X", sent_message_id());
384 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
387 // Send a message with RMQ support without receiving an acknowledgement. On
388 // restart the message should be resent.
389 TEST_F(MCSClientTest
, SendMessageRMQOnRestart
) {
392 LoginClient(std::vector
<std::string
>());
393 GetFakeHandler()->set_fail_send(true);
394 MCSMessage
message(BuildDataMessage(
395 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
397 // The initial (failed) send.
398 GetFakeHandler()->ExpectOutgoingMessage(message
);
399 GetFakeHandler()->set_fail_send(false);
400 mcs_client()->SendMessage(message
);
402 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
404 // Rebuild the client, which should resend the old message.
409 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
- 1));
410 MCSMessage
message2(BuildDataMessage(
411 "from", "category", "X", 1, "1", kTTLValue
, 1, kTTLValue
- 1, "", 0));
412 LoginClient(std::vector
<std::string
>());
413 GetFakeHandler()->ExpectOutgoingMessage(message2
);
415 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
418 // Send messages with RMQ support, followed by receiving a stream ack. On
419 // restart nothing should be recent.
420 TEST_F(MCSClientTest
, SendMessageRMQWithStreamAck
) {
423 LoginClient(std::vector
<std::string
>());
425 // Send some messages.
426 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
427 MCSMessage
message(BuildDataMessage("from",
431 base::IntToString(i
),
437 GetFakeHandler()->ExpectOutgoingMessage(message
);
438 mcs_client()->SendMessage(message
);
441 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
444 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
445 ack
->set_last_stream_id_received(kMessageBatchSize
+ 1);
446 GetFakeHandler()->ReceiveMessage(
447 MCSMessage(kIqStanzaTag
,
448 ack
.PassAs
<const google::protobuf::MessageLite
>()));
451 // Reconnect and ensure no messages are resent.
455 LoginClient(std::vector
<std::string
>());
459 // Send messages with RMQ support. On restart, receive a SelectiveAck with
460 // the login response. No messages should be resent.
461 TEST_F(MCSClientTest
, SendMessageRMQAckOnReconnect
) {
464 LoginClient(std::vector
<std::string
>());
466 // Send some messages.
467 std::vector
<std::string
> id_list
;
468 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
469 id_list
.push_back(base::IntToString(i
));
470 MCSMessage
message(BuildDataMessage("from",
480 GetFakeHandler()->ExpectOutgoingMessage(message
);
481 mcs_client()->SendMessage(message
);
484 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
486 // Rebuild the client, and receive an acknowledgment for the messages as
487 // part of the login response.
491 LoginClient(std::vector
<std::string
>());
492 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(id_list
));
493 GetFakeHandler()->ReceiveMessage(
494 MCSMessage(kIqStanzaTag
,
495 ack
.PassAs
<const google::protobuf::MessageLite
>()));
496 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
499 // Send messages with RMQ support. On restart, receive a SelectiveAck with
500 // the login response that only acks some messages. The unacked messages should
502 TEST_F(MCSClientTest
, SendMessageRMQPartialAckOnReconnect
) {
505 LoginClient(std::vector
<std::string
>());
507 // Send some messages.
508 std::vector
<std::string
> id_list
;
509 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
510 id_list
.push_back(base::IntToString(i
));
511 MCSMessage
message(BuildDataMessage("from",
521 GetFakeHandler()->ExpectOutgoingMessage(message
);
522 mcs_client()->SendMessage(message
);
525 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
527 // Rebuild the client, and receive an acknowledgment for the messages as
528 // part of the login response.
532 LoginClient(std::vector
<std::string
>());
534 std::vector
<std::string
> acked_ids
, remaining_ids
;
535 acked_ids
.insert(acked_ids
.end(),
537 id_list
.begin() + kMessageBatchSize
/ 2);
538 remaining_ids
.insert(remaining_ids
.end(),
539 id_list
.begin() + kMessageBatchSize
/ 2,
541 for (int i
= 1; i
<= kMessageBatchSize
/ 2; ++i
) {
542 MCSMessage
message(BuildDataMessage("from",
544 remaining_ids
[i
- 1],
546 remaining_ids
[i
- 1],
552 GetFakeHandler()->ExpectOutgoingMessage(message
);
554 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(acked_ids
));
555 GetFakeHandler()->ReceiveMessage(
556 MCSMessage(kIqStanzaTag
,
557 ack
.PassAs
<const google::protobuf::MessageLite
>()));
560 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
563 // Handle a selective ack that only acks some messages. The remaining unacked
564 // messages should be resent. On restart, those same unacked messages should be
565 // resent, and any pending acks for incoming messages should also be resent.
566 TEST_F(MCSClientTest
, SelectiveAckMidStream
) {
569 LoginClient(std::vector
<std::string
>());
571 // Server stream id 2 ("s1").
572 // Acks client stream id 0 (login).
573 MCSMessage
sMessage1(BuildDataMessage(
574 "from", "category", "X", 0, "s1", kTTLValue
, 1, 0, "", 0));
575 GetFakeHandler()->ReceiveMessage(sMessage1
);
579 // Client stream id 1 ("1").
580 // Acks server stream id 2 ("s1").
581 MCSMessage
cMessage1(BuildDataMessage(
582 "from", "category", "Y", 2, "1", kTTLValue
, 1, 0, "", 0));
583 GetFakeHandler()->ExpectOutgoingMessage(cMessage1
);
584 mcs_client()->SendMessage(cMessage1
);
586 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
588 // Server stream id 3 ("s2").
589 // Acks client stream id 1 ("1").
590 // Confirms ack of server stream id 2 ("s1").
591 MCSMessage
sMessage2(BuildDataMessage(
592 "from", "category", "X", 1, "s2", kTTLValue
, 1, 0, "", 0));
593 GetFakeHandler()->ReceiveMessage(sMessage2
);
597 // Client Stream id 2 ("2").
598 // Acks server stream id 3 ("s2").
599 MCSMessage
cMessage2(BuildDataMessage(
600 "from", "category", "Y", 3, "2", kTTLValue
, 1, 0, "", 0));
601 GetFakeHandler()->ExpectOutgoingMessage(cMessage2
);
602 mcs_client()->SendMessage(cMessage2
);
604 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
606 // Simulate the last message being dropped by having the server selectively
607 // ack client message "1".
608 // Client message "2" should be resent, acking server stream id 4 (selective
610 MCSMessage
cMessage3(BuildDataMessage(
611 "from", "category", "Y", 4, "2", kTTLValue
, 1, 0, "", 0));
612 GetFakeHandler()->ExpectOutgoingMessage(cMessage3
);
613 std::vector
<std::string
> acked_ids(1, "1");
614 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(acked_ids
));
615 GetFakeHandler()->ReceiveMessage(
616 MCSMessage(kIqStanzaTag
,
617 ack
.PassAs
<const google::protobuf::MessageLite
>()));
620 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
622 // Rebuild the client without any further acks from server. Note that this
623 // resets the stream ids.
624 // Sever message "s2" should be acked as part of login.
625 // Client message "2" should be resent.
631 LoginClient(acked_ids
);
633 MCSMessage
cMessage4(BuildDataMessage(
634 "from", "category", "Y", 1, "2", kTTLValue
, 1, 0, "", 0));
635 GetFakeHandler()->ExpectOutgoingMessage(cMessage4
);
637 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
640 // Receive some messages. On restart, the login request should contain the
641 // appropriate acknowledged ids.
642 TEST_F(MCSClientTest
, AckOnLogin
) {
645 LoginClient(std::vector
<std::string
>());
647 // Receive some messages.
648 std::vector
<std::string
> id_list
;
649 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
650 id_list
.push_back(base::IntToString(i
));
651 MCSMessage
message(BuildDataMessage(
652 "from", "category", "X", 1, id_list
.back(), kTTLValue
, 1, 0, "", 0));
653 GetFakeHandler()->ReceiveMessage(message
);
658 // Restart the client.
662 LoginClient(id_list
);
665 // Receive some messages. On the next send, the outgoing message should contain
666 // the appropriate last stream id received field to ack the received messages.
667 TEST_F(MCSClientTest
, AckOnSend
) {
670 LoginClient(std::vector
<std::string
>());
672 // Receive some messages.
673 std::vector
<std::string
> id_list
;
674 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
675 id_list
.push_back(base::IntToString(i
));
676 MCSMessage
message(BuildDataMessage("from",
686 GetFakeHandler()->ReceiveMessage(message
);
690 // Trigger a message send, which should acknowledge via stream ack.
691 MCSMessage
message(BuildDataMessage("from",
694 kMessageBatchSize
+ 1,
701 GetFakeHandler()->ExpectOutgoingMessage(message
);
702 mcs_client()->SendMessage(message
);
703 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
706 // Receive the ack limit in messages, which should trigger an automatic
707 // stream ack. Receive a heartbeat to confirm the ack.
708 TEST_F(MCSClientTest
, AckWhenLimitReachedWithHeartbeat
) {
711 LoginClient(std::vector
<std::string
>());
714 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
715 ack
->set_last_stream_id_received(kAckLimitSize
+ 1);
716 GetFakeHandler()->ExpectOutgoingMessage(
717 MCSMessage(kIqStanzaTag
,
718 ack
.PassAs
<const google::protobuf::MessageLite
>()));
720 // Receive some messages.
721 std::vector
<std::string
> id_list
;
722 for (int i
= 1; i
<= kAckLimitSize
; ++i
) {
723 id_list
.push_back(base::IntToString(i
));
724 MCSMessage
message(BuildDataMessage("from",
734 GetFakeHandler()->ReceiveMessage(message
);
738 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
740 // Receive a heartbeat confirming the ack (and receive the heartbeat ack).
741 scoped_ptr
<mcs_proto::HeartbeatPing
> heartbeat(
742 new mcs_proto::HeartbeatPing());
743 heartbeat
->set_last_stream_id_received(2);
745 scoped_ptr
<mcs_proto::HeartbeatAck
> heartbeat_ack(
746 new mcs_proto::HeartbeatAck());
747 heartbeat_ack
->set_last_stream_id_received(kAckLimitSize
+ 2);
748 GetFakeHandler()->ExpectOutgoingMessage(
749 MCSMessage(kHeartbeatAckTag
,
750 heartbeat_ack
.PassAs
<const google::protobuf::MessageLite
>()));
752 GetFakeHandler()->ReceiveMessage(
753 MCSMessage(kHeartbeatPingTag
,
754 heartbeat
.PassAs
<const google::protobuf::MessageLite
>()));
756 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
758 // Rebuild the client. Nothing should be sent on login.
762 LoginClient(std::vector
<std::string
>());
763 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
766 // If a message's TTL has expired by the time it reaches the front of the send
767 // queue, it should be dropped.
768 TEST_F(MCSClientTest
, ExpiredTTLOnSend
) {
771 LoginClient(std::vector
<std::string
>());
772 MCSMessage
message(BuildDataMessage(
773 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
775 // Advance time to after the TTL.
776 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
+ 2));
777 EXPECT_TRUE(sent_message_id().empty());
778 mcs_client()->SendMessage(message
);
780 // No messages should be sent, but the callback should still be invoked.
781 EXPECT_EQ("X", sent_message_id());
782 EXPECT_EQ(MCSClient::TTL_EXCEEDED
, message_send_status());
783 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
786 TEST_F(MCSClientTest
, ExpiredTTLOnRestart
) {
789 LoginClient(std::vector
<std::string
>());
790 GetFakeHandler()->set_fail_send(true);
791 MCSMessage
message(BuildDataMessage(
792 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
794 // The initial (failed) send.
795 GetFakeHandler()->ExpectOutgoingMessage(message
);
796 GetFakeHandler()->set_fail_send(false);
797 mcs_client()->SendMessage(message
);
799 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
801 // Move the clock forward and rebuild the client, which should fail the
802 // message send on restart.
803 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
+ 2));
807 LoginClient(std::vector
<std::string
>());
809 EXPECT_EQ("X", sent_message_id());
810 EXPECT_EQ(MCSClient::TTL_EXCEEDED
, message_send_status());
811 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
814 // Sending two messages with the same collapse key and same app id while
815 // disconnected should only send the latter of the two on reconnection.
816 TEST_F(MCSClientTest
, CollapseKeysSameApp
) {
819 MCSMessage
message(BuildDataMessage(
820 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
821 mcs_client()->SendMessage(message
);
823 MCSMessage
message2(BuildDataMessage(
824 "from", "app", "message id 2", 1, "1", kTTLValue
, 1, 0, "token", 0));
825 mcs_client()->SendMessage(message2
);
827 LoginClient(std::vector
<std::string
>());
828 GetFakeHandler()->ExpectOutgoingMessage(message2
);
832 // Sending two messages with the same collapse key and different app id while
833 // disconnected should not perform any collapsing.
834 TEST_F(MCSClientTest
, CollapseKeysDifferentApp
) {
837 MCSMessage
message(BuildDataMessage(
838 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
839 mcs_client()->SendMessage(message
);
841 MCSMessage
message2(BuildDataMessage("from",
851 mcs_client()->SendMessage(message2
);
853 LoginClient(std::vector
<std::string
>());
854 GetFakeHandler()->ExpectOutgoingMessage(message
);
855 GetFakeHandler()->ExpectOutgoingMessage(message2
);
859 // Sending two messages with the same collapse key and app id, but different
860 // user, while disconnected, should not perform any collapsing.
861 TEST_F(MCSClientTest
, CollapseKeysDifferentUser
) {
864 MCSMessage
message(BuildDataMessage(
865 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
866 mcs_client()->SendMessage(message
);
868 MCSMessage
message2(BuildDataMessage("from",
878 mcs_client()->SendMessage(message2
);
880 LoginClient(std::vector
<std::string
>());
881 GetFakeHandler()->ExpectOutgoingMessage(message
);
882 GetFakeHandler()->ExpectOutgoingMessage(message2
);