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"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/test/simple_test_clock.h"
16 #include "base/timer/timer.h"
17 #include "google_apis/gcm/base/fake_encryptor.h"
18 #include "google_apis/gcm/base/mcs_util.h"
19 #include "google_apis/gcm/engine/fake_connection_factory.h"
20 #include "google_apis/gcm/engine/fake_connection_handler.h"
21 #include "google_apis/gcm/engine/gcm_store_impl.h"
22 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
23 #include "testing/gtest/include/gtest/gtest.h"
29 const uint64 kAndroidId
= 54321;
30 const uint64 kSecurityToken
= 12345;
32 // Number of messages to send when testing batching.
33 // Note: must be even for tests that split batches in half.
34 const int kMessageBatchSize
= 6;
36 // The number of unacked messages the client will receive before sending a
38 // TODO(zea): get this (and other constants) directly from the mcs client.
39 const int kAckLimitSize
= 10;
41 // TTL value for reliable messages.
42 const int kTTLValue
= 5 * 60; // 5 minutes.
44 // Helper for building arbitrary data messages.
45 MCSMessage
BuildDataMessage(const std::string
& from
,
46 const std::string
& category
,
47 const std::string
& message_id
,
48 int last_stream_id_received
,
49 const std::string
& persistent_id
,
53 const std::string
& token
,
54 const uint64
& user_id
) {
55 mcs_proto::DataMessageStanza data_message
;
56 data_message
.set_id(message_id
);
57 data_message
.set_from(from
);
58 data_message
.set_category(category
);
59 data_message
.set_last_stream_id_received(last_stream_id_received
);
60 if (!persistent_id
.empty())
61 data_message
.set_persistent_id(persistent_id
);
62 data_message
.set_ttl(ttl
);
63 data_message
.set_sent(sent
);
64 data_message
.set_queued(queued
);
65 data_message
.set_token(token
);
66 data_message
.set_device_user_id(user_id
);
67 return MCSMessage(kDataMessageStanzaTag
, data_message
);
70 // MCSClient with overriden exposed persistent id logic.
71 class TestMCSClient
: public MCSClient
{
73 TestMCSClient(base::Clock
* clock
,
74 ConnectionFactory
* connection_factory
,
76 gcm::GCMStatsRecorder
* recorder
)
77 : MCSClient("", clock
, connection_factory
, gcm_store
, recorder
),
81 std::string
GetNextPersistentId() override
{
82 return base::UintToString(++next_id_
);
89 class MCSClientTest
: public testing::Test
{
92 ~MCSClientTest() override
;
94 void SetUp() override
;
96 void BuildMCSClient();
97 void InitializeClient();
98 void StoreCredentials();
99 void LoginClient(const std::vector
<std::string
>& acknowledged_ids
);
101 base::SimpleTestClock
* clock() { return &clock_
; }
102 TestMCSClient
* mcs_client() const { return mcs_client_
.get(); }
103 FakeConnectionFactory
* connection_factory() {
104 return &connection_factory_
;
106 bool init_success() const { return init_success_
; }
107 uint64
restored_android_id() const { return restored_android_id_
; }
108 uint64
restored_security_token() const { return restored_security_token_
; }
109 MCSMessage
* received_message() const { return received_message_
.get(); }
110 std::string
sent_message_id() const { return sent_message_id_
;}
111 MCSClient::MessageSendStatus
message_send_status() const {
112 return message_send_status_
;
115 void SetDeviceCredentialsCallback(bool success
);
117 FakeConnectionHandler
* GetFakeHandler() const;
119 void WaitForMCSEvent();
123 void ErrorCallback();
124 void MessageReceivedCallback(const MCSMessage
& message
);
125 void MessageSentCallback(int64 user_serial_number
,
126 const std::string
& app_id
,
127 const std::string
& message_id
,
128 MCSClient::MessageSendStatus status
);
130 base::SimpleTestClock clock_
;
132 base::ScopedTempDir temp_directory_
;
133 base::MessageLoop message_loop_
;
134 scoped_ptr
<base::RunLoop
> run_loop_
;
135 scoped_ptr
<GCMStore
> gcm_store_
;
137 FakeConnectionFactory connection_factory_
;
138 scoped_ptr
<TestMCSClient
> mcs_client_
;
140 uint64 restored_android_id_
;
141 uint64 restored_security_token_
;
142 scoped_ptr
<MCSMessage
> received_message_
;
143 std::string sent_message_id_
;
144 MCSClient::MessageSendStatus message_send_status_
;
146 gcm::FakeGCMStatsRecorder recorder_
;
149 MCSClientTest::MCSClientTest()
150 : run_loop_(new base::RunLoop()),
152 restored_android_id_(0),
153 restored_security_token_(0),
154 message_send_status_(MCSClient::SENT
) {
155 EXPECT_TRUE(temp_directory_
.CreateUniqueTempDir());
156 run_loop_
.reset(new base::RunLoop());
158 // Advance the clock to a non-zero time.
159 clock_
.Advance(base::TimeDelta::FromSeconds(1));
162 MCSClientTest::~MCSClientTest() {}
164 void MCSClientTest::SetUp() {
165 testing::Test::SetUp();
168 void MCSClientTest::BuildMCSClient() {
169 gcm_store_
.reset(new GCMStoreImpl(
170 temp_directory_
.path(),
171 message_loop_
.message_loop_proxy(),
172 make_scoped_ptr
<Encryptor
>(new FakeEncryptor
)));
173 mcs_client_
.reset(new TestMCSClient(&clock_
,
174 &connection_factory_
,
179 void MCSClientTest::InitializeClient() {
180 gcm_store_
->Load(base::Bind(
181 &MCSClient::Initialize
,
182 base::Unretained(mcs_client_
.get()),
183 base::Bind(&MCSClientTest::ErrorCallback
,
184 base::Unretained(this)),
185 base::Bind(&MCSClientTest::MessageReceivedCallback
,
186 base::Unretained(this)),
187 base::Bind(&MCSClientTest::MessageSentCallback
, base::Unretained(this))));
188 run_loop_
->RunUntilIdle();
189 run_loop_
.reset(new base::RunLoop());
192 void MCSClientTest::LoginClient(
193 const std::vector
<std::string
>& acknowledged_ids
) {
194 scoped_ptr
<mcs_proto::LoginRequest
> login_request
=
195 BuildLoginRequest(kAndroidId
, kSecurityToken
, "");
196 for (size_t i
= 0; i
< acknowledged_ids
.size(); ++i
)
197 login_request
->add_received_persistent_id(acknowledged_ids
[i
]);
198 GetFakeHandler()->ExpectOutgoingMessage(
199 MCSMessage(kLoginRequestTag
, login_request
.Pass()));
200 mcs_client_
->Login(kAndroidId
, kSecurityToken
);
202 run_loop_
.reset(new base::RunLoop());
205 void MCSClientTest::StoreCredentials() {
206 gcm_store_
->SetDeviceCredentials(
207 kAndroidId
, kSecurityToken
,
208 base::Bind(&MCSClientTest::SetDeviceCredentialsCallback
,
209 base::Unretained(this)));
211 run_loop_
.reset(new base::RunLoop());
214 FakeConnectionHandler
* MCSClientTest::GetFakeHandler() const {
215 return reinterpret_cast<FakeConnectionHandler
*>(
216 connection_factory_
.GetConnectionHandler());
219 void MCSClientTest::WaitForMCSEvent() {
221 run_loop_
.reset(new base::RunLoop());
224 void MCSClientTest::PumpLoop() {
225 run_loop_
->RunUntilIdle();
226 run_loop_
.reset(new base::RunLoop());
229 void MCSClientTest::ErrorCallback() {
230 init_success_
= false;
231 DVLOG(1) << "Error callback invoked, killing loop.";
235 void MCSClientTest::MessageReceivedCallback(const MCSMessage
& message
) {
236 received_message_
.reset(new MCSMessage(message
));
237 DVLOG(1) << "Message received callback invoked, killing loop.";
241 void MCSClientTest::MessageSentCallback(int64 user_serial_number
,
242 const std::string
& app_id
,
243 const std::string
& message_id
,
244 MCSClient::MessageSendStatus status
) {
245 DVLOG(1) << "Message sent callback invoked, killing loop.";
246 sent_message_id_
= message_id
;
247 message_send_status_
= status
;
251 void MCSClientTest::SetDeviceCredentialsCallback(bool success
) {
252 ASSERT_TRUE(success
);
256 // Initialize a new client.
257 TEST_F(MCSClientTest
, InitializeNew
) {
260 EXPECT_TRUE(init_success());
263 // Initialize a new client, shut it down, then restart the client. Should
264 // reload the existing device credentials.
265 TEST_F(MCSClientTest
, InitializeExisting
) {
268 LoginClient(std::vector
<std::string
>());
270 // Rebuild the client, to reload from the GCM store.
274 EXPECT_TRUE(init_success());
277 // Log in successfully to the MCS endpoint.
278 TEST_F(MCSClientTest
, LoginSuccess
) {
281 LoginClient(std::vector
<std::string
>());
282 EXPECT_TRUE(connection_factory()->IsEndpointReachable());
283 EXPECT_TRUE(init_success());
284 ASSERT_TRUE(received_message());
285 EXPECT_EQ(kLoginResponseTag
, received_message()->tag());
288 // Encounter a server error during the login attempt. Should trigger a
290 TEST_F(MCSClientTest
, FailLogin
) {
293 GetFakeHandler()->set_fail_login(true);
294 connection_factory()->set_delay_reconnect(true);
295 LoginClient(std::vector
<std::string
>());
296 EXPECT_FALSE(connection_factory()->IsEndpointReachable());
297 EXPECT_FALSE(init_success());
298 EXPECT_FALSE(received_message());
299 EXPECT_TRUE(connection_factory()->reconnect_pending());
302 // Send a message without RMQ support.
303 TEST_F(MCSClientTest
, SendMessageNoRMQ
) {
306 LoginClient(std::vector
<std::string
>());
308 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
309 GetFakeHandler()->ExpectOutgoingMessage(message
);
310 mcs_client()->SendMessage(message
);
311 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
314 // Send a message without RMQ support while disconnected. Message send should
315 // fail immediately, invoking callback.
316 TEST_F(MCSClientTest
, SendMessageNoRMQWhileDisconnected
) {
320 EXPECT_TRUE(sent_message_id().empty());
322 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
323 mcs_client()->SendMessage(message
);
325 // Message sent callback should be invoked, but no message should actually
327 EXPECT_EQ("X", sent_message_id());
328 EXPECT_EQ(MCSClient::NO_CONNECTION_ON_ZERO_TTL
, message_send_status());
329 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
332 // Send a message with RMQ support.
333 TEST_F(MCSClientTest
, SendMessageRMQ
) {
336 LoginClient(std::vector
<std::string
>());
337 MCSMessage
message(BuildDataMessage(
338 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
339 GetFakeHandler()->ExpectOutgoingMessage(message
);
340 mcs_client()->SendMessage(message
);
341 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
344 // Send a message with RMQ support while disconnected. On reconnect, the message
346 TEST_F(MCSClientTest
, SendMessageRMQWhileDisconnected
) {
349 LoginClient(std::vector
<std::string
>());
350 GetFakeHandler()->set_fail_send(true);
351 MCSMessage
message(BuildDataMessage(
352 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
354 // The initial (failed) send.
355 GetFakeHandler()->ExpectOutgoingMessage(message
);
356 // The login request.
357 GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(
358 kLoginRequestTag
, BuildLoginRequest(kAndroidId
, kSecurityToken
, "")));
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(MCSMessage(kIqStanzaTag
, ack
.Pass()));
380 EXPECT_EQ(MCSClient::SENT
, message_send_status());
381 EXPECT_EQ("X", sent_message_id());
382 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
385 // Send a message with RMQ support without receiving an acknowledgement. On
386 // restart the message should be resent.
387 TEST_F(MCSClientTest
, SendMessageRMQOnRestart
) {
390 LoginClient(std::vector
<std::string
>());
391 GetFakeHandler()->set_fail_send(true);
392 MCSMessage
message(BuildDataMessage(
393 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
395 // The initial (failed) send.
396 GetFakeHandler()->ExpectOutgoingMessage(message
);
397 GetFakeHandler()->set_fail_send(false);
398 mcs_client()->SendMessage(message
);
400 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
402 // Rebuild the client, which should resend the old message.
407 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
- 1));
408 MCSMessage
message2(BuildDataMessage(
409 "from", "category", "X", 1, "1", kTTLValue
, 1, kTTLValue
- 1, "", 0));
410 LoginClient(std::vector
<std::string
>());
411 GetFakeHandler()->ExpectOutgoingMessage(message2
);
413 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
416 // Send messages with RMQ support, followed by receiving a stream ack. On
417 // restart nothing should be recent.
418 TEST_F(MCSClientTest
, SendMessageRMQWithStreamAck
) {
421 LoginClient(std::vector
<std::string
>());
423 // Send some messages.
424 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
425 MCSMessage
message(BuildDataMessage("from",
429 base::IntToString(i
),
435 GetFakeHandler()->ExpectOutgoingMessage(message
);
436 mcs_client()->SendMessage(message
);
439 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
442 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
443 ack
->set_last_stream_id_received(kMessageBatchSize
+ 1);
444 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
447 // Reconnect and ensure no messages are resent.
451 LoginClient(std::vector
<std::string
>());
455 // Send messages with RMQ support. On restart, receive a SelectiveAck with
456 // the login response. No messages should be resent.
457 TEST_F(MCSClientTest
, SendMessageRMQAckOnReconnect
) {
460 LoginClient(std::vector
<std::string
>());
462 // Send some messages.
463 std::vector
<std::string
> id_list
;
464 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
465 id_list
.push_back(base::IntToString(i
));
466 MCSMessage
message(BuildDataMessage("from",
476 GetFakeHandler()->ExpectOutgoingMessage(message
);
477 mcs_client()->SendMessage(message
);
480 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
482 // Rebuild the client, and receive an acknowledgment for the messages as
483 // part of the login response.
487 LoginClient(std::vector
<std::string
>());
488 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(id_list
));
489 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
490 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
493 // Send messages with RMQ support. On restart, receive a SelectiveAck with
494 // the login response that only acks some messages. The unacked messages should
496 TEST_F(MCSClientTest
, SendMessageRMQPartialAckOnReconnect
) {
499 LoginClient(std::vector
<std::string
>());
501 // Send some messages.
502 std::vector
<std::string
> id_list
;
503 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
504 id_list
.push_back(base::IntToString(i
));
505 MCSMessage
message(BuildDataMessage("from",
515 GetFakeHandler()->ExpectOutgoingMessage(message
);
516 mcs_client()->SendMessage(message
);
519 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
521 // Rebuild the client, and receive an acknowledgment for the messages as
522 // part of the login response.
526 LoginClient(std::vector
<std::string
>());
528 std::vector
<std::string
> acked_ids
, remaining_ids
;
529 acked_ids
.insert(acked_ids
.end(),
531 id_list
.begin() + kMessageBatchSize
/ 2);
532 remaining_ids
.insert(remaining_ids
.end(),
533 id_list
.begin() + kMessageBatchSize
/ 2,
535 for (int i
= 1; i
<= kMessageBatchSize
/ 2; ++i
) {
536 MCSMessage
message(BuildDataMessage("from",
538 remaining_ids
[i
- 1],
540 remaining_ids
[i
- 1],
546 GetFakeHandler()->ExpectOutgoingMessage(message
);
548 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(acked_ids
));
549 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
552 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
555 // Handle a selective ack that only acks some messages. The remaining unacked
556 // messages should be resent. On restart, those same unacked messages should be
557 // resent, and any pending acks for incoming messages should also be resent.
558 TEST_F(MCSClientTest
, SelectiveAckMidStream
) {
561 LoginClient(std::vector
<std::string
>());
563 // Server stream id 2 ("s1").
564 // Acks client stream id 0 (login).
565 MCSMessage
sMessage1(BuildDataMessage(
566 "from", "category", "X", 0, "s1", kTTLValue
, 1, 0, "", 0));
567 GetFakeHandler()->ReceiveMessage(sMessage1
);
571 // Client stream id 1 ("1").
572 // Acks server stream id 2 ("s1").
573 MCSMessage
cMessage1(BuildDataMessage(
574 "from", "category", "Y", 2, "1", kTTLValue
, 1, 0, "", 0));
575 GetFakeHandler()->ExpectOutgoingMessage(cMessage1
);
576 mcs_client()->SendMessage(cMessage1
);
578 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
580 // Server stream id 3 ("s2").
581 // Acks client stream id 1 ("1").
582 // Confirms ack of server stream id 2 ("s1").
583 MCSMessage
sMessage2(BuildDataMessage(
584 "from", "category", "X", 1, "s2", kTTLValue
, 1, 0, "", 0));
585 GetFakeHandler()->ReceiveMessage(sMessage2
);
589 // Client Stream id 2 ("2").
590 // Acks server stream id 3 ("s2").
591 MCSMessage
cMessage2(BuildDataMessage(
592 "from", "category", "Y", 3, "2", kTTLValue
, 1, 0, "", 0));
593 GetFakeHandler()->ExpectOutgoingMessage(cMessage2
);
594 mcs_client()->SendMessage(cMessage2
);
596 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
598 // Simulate the last message being dropped by having the server selectively
599 // ack client message "1".
600 // Client message "2" should be resent, acking server stream id 4 (selective
602 MCSMessage
cMessage3(BuildDataMessage(
603 "from", "category", "Y", 4, "2", kTTLValue
, 1, 0, "", 0));
604 GetFakeHandler()->ExpectOutgoingMessage(cMessage3
);
605 std::vector
<std::string
> acked_ids(1, "1");
606 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(acked_ids
));
607 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
610 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
612 // Rebuild the client without any further acks from server. Note that this
613 // resets the stream ids.
614 // Sever message "s2" should be acked as part of login.
615 // Client message "2" should be resent.
621 LoginClient(acked_ids
);
623 MCSMessage
cMessage4(BuildDataMessage(
624 "from", "category", "Y", 1, "2", kTTLValue
, 1, 0, "", 0));
625 GetFakeHandler()->ExpectOutgoingMessage(cMessage4
);
627 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
630 // Receive some messages. On restart, the login request should contain the
631 // appropriate acknowledged ids.
632 TEST_F(MCSClientTest
, AckOnLogin
) {
635 LoginClient(std::vector
<std::string
>());
637 // Receive some messages.
638 std::vector
<std::string
> id_list
;
639 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
640 id_list
.push_back(base::IntToString(i
));
641 MCSMessage
message(BuildDataMessage(
642 "from", "category", "X", 1, id_list
.back(), kTTLValue
, 1, 0, "", 0));
643 GetFakeHandler()->ReceiveMessage(message
);
648 // Restart the client.
652 LoginClient(id_list
);
655 // Receive some messages. On the next send, the outgoing message should contain
656 // the appropriate last stream id received field to ack the received messages.
657 TEST_F(MCSClientTest
, AckOnSend
) {
660 LoginClient(std::vector
<std::string
>());
662 // Receive some messages.
663 std::vector
<std::string
> id_list
;
664 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
665 id_list
.push_back(base::IntToString(i
));
666 MCSMessage
message(BuildDataMessage("from",
676 GetFakeHandler()->ReceiveMessage(message
);
680 // Trigger a message send, which should acknowledge via stream ack.
681 MCSMessage
message(BuildDataMessage("from",
684 kMessageBatchSize
+ 1,
691 GetFakeHandler()->ExpectOutgoingMessage(message
);
692 mcs_client()->SendMessage(message
);
693 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
696 // Receive the ack limit in messages, which should trigger an automatic
697 // stream ack. Receive a heartbeat to confirm the ack.
698 TEST_F(MCSClientTest
, AckWhenLimitReachedWithHeartbeat
) {
701 LoginClient(std::vector
<std::string
>());
704 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
705 ack
->set_last_stream_id_received(kAckLimitSize
+ 1);
706 GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
708 // Receive some messages.
709 std::vector
<std::string
> id_list
;
710 for (int i
= 1; i
<= kAckLimitSize
; ++i
) {
711 id_list
.push_back(base::IntToString(i
));
712 MCSMessage
message(BuildDataMessage("from",
722 GetFakeHandler()->ReceiveMessage(message
);
726 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
728 // Receive a heartbeat confirming the ack (and receive the heartbeat ack).
729 scoped_ptr
<mcs_proto::HeartbeatPing
> heartbeat(
730 new mcs_proto::HeartbeatPing());
731 heartbeat
->set_last_stream_id_received(2);
733 scoped_ptr
<mcs_proto::HeartbeatAck
> heartbeat_ack(
734 new mcs_proto::HeartbeatAck());
735 heartbeat_ack
->set_last_stream_id_received(kAckLimitSize
+ 2);
736 GetFakeHandler()->ExpectOutgoingMessage(
737 MCSMessage(kHeartbeatAckTag
, heartbeat_ack
.Pass()));
739 GetFakeHandler()->ReceiveMessage(
740 MCSMessage(kHeartbeatPingTag
, heartbeat
.Pass()));
742 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
744 // Rebuild the client. Nothing should be sent on login.
748 LoginClient(std::vector
<std::string
>());
749 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
752 // If a message's TTL has expired by the time it reaches the front of the send
753 // queue, it should be dropped.
754 TEST_F(MCSClientTest
, ExpiredTTLOnSend
) {
757 LoginClient(std::vector
<std::string
>());
758 MCSMessage
message(BuildDataMessage(
759 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
761 // Advance time to after the TTL.
762 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
+ 2));
763 EXPECT_TRUE(sent_message_id().empty());
764 mcs_client()->SendMessage(message
);
766 // No messages should be sent, but the callback should still be invoked.
767 EXPECT_EQ("X", sent_message_id());
768 EXPECT_EQ(MCSClient::TTL_EXCEEDED
, message_send_status());
769 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
772 TEST_F(MCSClientTest
, ExpiredTTLOnRestart
) {
775 LoginClient(std::vector
<std::string
>());
776 GetFakeHandler()->set_fail_send(true);
777 MCSMessage
message(BuildDataMessage(
778 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
780 // The initial (failed) send.
781 GetFakeHandler()->ExpectOutgoingMessage(message
);
782 GetFakeHandler()->set_fail_send(false);
783 mcs_client()->SendMessage(message
);
785 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
787 // Move the clock forward and rebuild the client, which should fail the
788 // message send on restart.
789 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
+ 2));
793 LoginClient(std::vector
<std::string
>());
795 EXPECT_EQ("X", sent_message_id());
796 EXPECT_EQ(MCSClient::TTL_EXCEEDED
, message_send_status());
797 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
800 // Sending two messages with the same collapse key and same app id while
801 // disconnected should only send the latter of the two on reconnection.
802 TEST_F(MCSClientTest
, CollapseKeysSameApp
) {
805 MCSMessage
message(BuildDataMessage(
806 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
807 mcs_client()->SendMessage(message
);
809 MCSMessage
message2(BuildDataMessage(
810 "from", "app", "message id 2", 1, "1", kTTLValue
, 1, 0, "token", 0));
811 mcs_client()->SendMessage(message2
);
813 LoginClient(std::vector
<std::string
>());
814 GetFakeHandler()->ExpectOutgoingMessage(message2
);
818 // Sending two messages with the same collapse key and different app id while
819 // disconnected should not perform any collapsing.
820 TEST_F(MCSClientTest
, CollapseKeysDifferentApp
) {
823 MCSMessage
message(BuildDataMessage(
824 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
825 mcs_client()->SendMessage(message
);
827 MCSMessage
message2(BuildDataMessage("from",
837 mcs_client()->SendMessage(message2
);
839 LoginClient(std::vector
<std::string
>());
840 GetFakeHandler()->ExpectOutgoingMessage(message
);
841 GetFakeHandler()->ExpectOutgoingMessage(message2
);
845 // Sending two messages with the same collapse key and app id, but different
846 // user, while disconnected, should not perform any collapsing.
847 TEST_F(MCSClientTest
, CollapseKeysDifferentUser
) {
850 MCSMessage
message(BuildDataMessage(
851 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
852 mcs_client()->SendMessage(message
);
854 MCSMessage
message2(BuildDataMessage("from",
864 mcs_client()->SendMessage(message2
);
866 LoginClient(std::vector
<std::string
>());
867 GetFakeHandler()->ExpectOutgoingMessage(message
);
868 GetFakeHandler()->ExpectOutgoingMessage(message2
);