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 TestConnectionListener
: public ConnectionFactory::ConnectionListener
{
91 TestConnectionListener() : disconnect_counter_(0) { }
92 ~TestConnectionListener() override
{ }
94 void OnConnected(const GURL
& current_server
,
95 const net::IPEndPoint
& ip_endpoint
) override
{ }
96 void OnDisconnected() override
{
97 ++disconnect_counter_
;
100 int get_disconnect_counter() const { return disconnect_counter_
; }
102 int disconnect_counter_
;
105 class MCSClientTest
: public testing::Test
{
108 ~MCSClientTest() override
;
110 void SetUp() override
;
112 void BuildMCSClient();
113 void InitializeClient();
114 void StoreCredentials();
115 void LoginClient(const std::vector
<std::string
>& acknowledged_ids
);
116 void LoginClientWithHeartbeat(
117 const std::vector
<std::string
>& acknowledged_ids
,
118 int heartbeat_interval_ms
);
119 void AddExpectedLoginRequest(const std::vector
<std::string
>& acknowledged_ids
,
120 int heartbeat_interval_ms
);
122 base::SimpleTestClock
* clock() { return &clock_
; }
123 TestMCSClient
* mcs_client() const { return mcs_client_
.get(); }
124 FakeConnectionFactory
* connection_factory() {
125 return &connection_factory_
;
127 bool init_success() const { return init_success_
; }
128 uint64
restored_android_id() const { return restored_android_id_
; }
129 uint64
restored_security_token() const { return restored_security_token_
; }
130 MCSMessage
* received_message() const { return received_message_
.get(); }
131 std::string
sent_message_id() const { return sent_message_id_
;}
132 MCSClient::MessageSendStatus
message_send_status() const {
133 return message_send_status_
;
136 void SetDeviceCredentialsCallback(bool success
);
138 FakeConnectionHandler
* GetFakeHandler() const;
140 void WaitForMCSEvent();
144 void ErrorCallback();
145 void MessageReceivedCallback(const MCSMessage
& message
);
146 void MessageSentCallback(int64 user_serial_number
,
147 const std::string
& app_id
,
148 const std::string
& message_id
,
149 MCSClient::MessageSendStatus status
);
151 base::SimpleTestClock clock_
;
153 base::ScopedTempDir temp_directory_
;
154 base::MessageLoop message_loop_
;
155 scoped_ptr
<base::RunLoop
> run_loop_
;
156 scoped_ptr
<GCMStore
> gcm_store_
;
158 FakeConnectionFactory connection_factory_
;
159 scoped_ptr
<TestMCSClient
> mcs_client_
;
161 uint64 restored_android_id_
;
162 uint64 restored_security_token_
;
163 scoped_ptr
<MCSMessage
> received_message_
;
164 std::string sent_message_id_
;
165 MCSClient::MessageSendStatus message_send_status_
;
167 gcm::FakeGCMStatsRecorder recorder_
;
170 MCSClientTest::MCSClientTest()
171 : run_loop_(new base::RunLoop()),
173 restored_android_id_(0),
174 restored_security_token_(0),
175 message_send_status_(MCSClient::SENT
) {
176 EXPECT_TRUE(temp_directory_
.CreateUniqueTempDir());
177 run_loop_
.reset(new base::RunLoop());
179 // Advance the clock to a non-zero time.
180 clock_
.Advance(base::TimeDelta::FromSeconds(1));
183 MCSClientTest::~MCSClientTest() {}
185 void MCSClientTest::SetUp() {
186 testing::Test::SetUp();
189 void MCSClientTest::BuildMCSClient() {
190 gcm_store_
.reset(new GCMStoreImpl(
191 temp_directory_
.path(),
192 message_loop_
.task_runner(),
193 make_scoped_ptr
<Encryptor
>(new FakeEncryptor
)));
194 mcs_client_
.reset(new TestMCSClient(&clock_
,
195 &connection_factory_
,
200 void MCSClientTest::InitializeClient() {
201 gcm_store_
->Load(GCMStore::CREATE_IF_MISSING
, base::Bind(
202 &MCSClient::Initialize
,
203 base::Unretained(mcs_client_
.get()),
204 base::Bind(&MCSClientTest::ErrorCallback
,
205 base::Unretained(this)),
206 base::Bind(&MCSClientTest::MessageReceivedCallback
,
207 base::Unretained(this)),
208 base::Bind(&MCSClientTest::MessageSentCallback
, base::Unretained(this))));
209 run_loop_
->RunUntilIdle();
210 run_loop_
.reset(new base::RunLoop());
213 void MCSClientTest::LoginClient(
214 const std::vector
<std::string
>& acknowledged_ids
) {
215 LoginClientWithHeartbeat(acknowledged_ids
, 0);
218 void MCSClientTest::LoginClientWithHeartbeat(
219 const std::vector
<std::string
>& acknowledged_ids
,
220 int heartbeat_interval_ms
) {
221 AddExpectedLoginRequest(acknowledged_ids
, heartbeat_interval_ms
);
222 mcs_client_
->Login(kAndroidId
, kSecurityToken
);
224 run_loop_
.reset(new base::RunLoop());
227 void MCSClientTest::AddExpectedLoginRequest(
228 const std::vector
<std::string
>& acknowledged_ids
,
229 int heartbeat_interval_ms
) {
230 scoped_ptr
<mcs_proto::LoginRequest
> login_request
=
231 BuildLoginRequest(kAndroidId
, kSecurityToken
, "");
232 for (size_t i
= 0; i
< acknowledged_ids
.size(); ++i
)
233 login_request
->add_received_persistent_id(acknowledged_ids
[i
]);
234 if (heartbeat_interval_ms
) {
235 mcs_proto::Setting
* setting
= login_request
->add_setting();
236 setting
->set_name("hbping");
237 setting
->set_value(base::IntToString(heartbeat_interval_ms
));
239 GetFakeHandler()->ExpectOutgoingMessage(
240 MCSMessage(kLoginRequestTag
, login_request
.Pass()));
243 void MCSClientTest::StoreCredentials() {
244 gcm_store_
->SetDeviceCredentials(
245 kAndroidId
, kSecurityToken
,
246 base::Bind(&MCSClientTest::SetDeviceCredentialsCallback
,
247 base::Unretained(this)));
249 run_loop_
.reset(new base::RunLoop());
252 FakeConnectionHandler
* MCSClientTest::GetFakeHandler() const {
253 return reinterpret_cast<FakeConnectionHandler
*>(
254 connection_factory_
.GetConnectionHandler());
257 void MCSClientTest::WaitForMCSEvent() {
259 run_loop_
.reset(new base::RunLoop());
262 void MCSClientTest::PumpLoop() {
263 run_loop_
->RunUntilIdle();
264 run_loop_
.reset(new base::RunLoop());
267 void MCSClientTest::ErrorCallback() {
268 init_success_
= false;
269 DVLOG(1) << "Error callback invoked, killing loop.";
273 void MCSClientTest::MessageReceivedCallback(const MCSMessage
& message
) {
274 received_message_
.reset(new MCSMessage(message
));
275 DVLOG(1) << "Message received callback invoked, killing loop.";
279 void MCSClientTest::MessageSentCallback(int64 user_serial_number
,
280 const std::string
& app_id
,
281 const std::string
& message_id
,
282 MCSClient::MessageSendStatus status
) {
283 DVLOG(1) << "Message sent callback invoked, killing loop.";
284 sent_message_id_
= message_id
;
285 message_send_status_
= status
;
289 void MCSClientTest::SetDeviceCredentialsCallback(bool success
) {
290 ASSERT_TRUE(success
);
294 // Initialize a new client.
295 TEST_F(MCSClientTest
, InitializeNew
) {
298 EXPECT_TRUE(init_success());
301 // Initialize a new client, shut it down, then restart the client. Should
302 // reload the existing device credentials.
303 TEST_F(MCSClientTest
, InitializeExisting
) {
306 LoginClient(std::vector
<std::string
>());
308 // Rebuild the client, to reload from the GCM store.
312 EXPECT_TRUE(init_success());
315 // Log in successfully to the MCS endpoint.
316 TEST_F(MCSClientTest
, LoginSuccess
) {
319 LoginClient(std::vector
<std::string
>());
320 EXPECT_TRUE(connection_factory()->IsEndpointReachable());
321 EXPECT_TRUE(init_success());
322 ASSERT_TRUE(received_message());
323 EXPECT_EQ(kLoginResponseTag
, received_message()->tag());
326 // Encounter a server error during the login attempt. Should trigger a
328 TEST_F(MCSClientTest
, FailLogin
) {
331 GetFakeHandler()->set_fail_login(true);
332 connection_factory()->set_delay_reconnect(true);
333 LoginClient(std::vector
<std::string
>());
334 EXPECT_FALSE(connection_factory()->IsEndpointReachable());
335 EXPECT_FALSE(init_success());
336 EXPECT_FALSE(received_message());
337 EXPECT_TRUE(connection_factory()->reconnect_pending());
340 // Send a message without RMQ support.
341 TEST_F(MCSClientTest
, SendMessageNoRMQ
) {
344 LoginClient(std::vector
<std::string
>());
346 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
347 GetFakeHandler()->ExpectOutgoingMessage(message
);
348 mcs_client()->SendMessage(message
);
349 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
352 // Send a message without RMQ support while disconnected. Message send should
353 // fail immediately, invoking callback.
354 TEST_F(MCSClientTest
, SendMessageNoRMQWhileDisconnected
) {
358 EXPECT_TRUE(sent_message_id().empty());
360 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
361 mcs_client()->SendMessage(message
);
363 // Message sent callback should be invoked, but no message should actually
365 EXPECT_EQ("X", sent_message_id());
366 EXPECT_EQ(MCSClient::NO_CONNECTION_ON_ZERO_TTL
, message_send_status());
367 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
370 // Send a message with RMQ support.
371 TEST_F(MCSClientTest
, SendMessageRMQ
) {
374 LoginClient(std::vector
<std::string
>());
375 MCSMessage
message(BuildDataMessage(
376 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
377 GetFakeHandler()->ExpectOutgoingMessage(message
);
378 mcs_client()->SendMessage(message
);
379 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
382 // Send a message with RMQ support while disconnected. On reconnect, the message
384 TEST_F(MCSClientTest
, SendMessageRMQWhileDisconnected
) {
387 LoginClient(std::vector
<std::string
>());
388 GetFakeHandler()->set_fail_send(true);
389 MCSMessage
message(BuildDataMessage(
390 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
392 // The initial (failed) send.
393 GetFakeHandler()->ExpectOutgoingMessage(message
);
394 // The login request.
395 GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(
396 kLoginRequestTag
, BuildLoginRequest(kAndroidId
, kSecurityToken
, "")));
397 // The second (re)send.
398 MCSMessage
message2(BuildDataMessage(
399 "from", "category", "X", 1, "1", kTTLValue
, 1, kTTLValue
- 1, "", 0));
400 GetFakeHandler()->ExpectOutgoingMessage(message2
);
401 mcs_client()->SendMessage(message
);
402 PumpLoop(); // Wait for the queuing to happen.
403 EXPECT_EQ(MCSClient::QUEUED
, message_send_status());
404 EXPECT_EQ("X", sent_message_id());
405 EXPECT_FALSE(GetFakeHandler()->AllOutgoingMessagesReceived());
406 GetFakeHandler()->set_fail_send(false);
407 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
- 1));
408 connection_factory()->Connect();
409 WaitForMCSEvent(); // Wait for the login to finish.
410 PumpLoop(); // Wait for the send to happen.
413 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
414 ack
->set_last_stream_id_received(2);
415 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
418 EXPECT_EQ(MCSClient::SENT
, message_send_status());
419 EXPECT_EQ("X", sent_message_id());
420 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
423 // Send a message with RMQ support without receiving an acknowledgement. On
424 // restart the message should be resent.
425 TEST_F(MCSClientTest
, SendMessageRMQOnRestart
) {
428 LoginClient(std::vector
<std::string
>());
429 GetFakeHandler()->set_fail_send(true);
430 MCSMessage
message(BuildDataMessage(
431 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
433 // The initial (failed) send.
434 GetFakeHandler()->ExpectOutgoingMessage(message
);
435 GetFakeHandler()->set_fail_send(false);
436 mcs_client()->SendMessage(message
);
438 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
440 // Rebuild the client, which should resend the old message.
445 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
- 1));
446 MCSMessage
message2(BuildDataMessage(
447 "from", "category", "X", 1, "1", kTTLValue
, 1, kTTLValue
- 1, "", 0));
448 LoginClient(std::vector
<std::string
>());
449 GetFakeHandler()->ExpectOutgoingMessage(message2
);
451 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
454 // Send messages with RMQ support, followed by receiving a stream ack. On
455 // restart nothing should be recent.
456 TEST_F(MCSClientTest
, SendMessageRMQWithStreamAck
) {
459 LoginClient(std::vector
<std::string
>());
461 // Send some messages.
462 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
463 MCSMessage
message(BuildDataMessage("from",
467 base::IntToString(i
),
473 GetFakeHandler()->ExpectOutgoingMessage(message
);
474 mcs_client()->SendMessage(message
);
477 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
480 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
481 ack
->set_last_stream_id_received(kMessageBatchSize
+ 1);
482 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
485 // Reconnect and ensure no messages are resent.
489 LoginClient(std::vector
<std::string
>());
493 // Send messages with RMQ support. On restart, receive a SelectiveAck with
494 // the login response. No messages should be resent.
495 TEST_F(MCSClientTest
, SendMessageRMQAckOnReconnect
) {
498 LoginClient(std::vector
<std::string
>());
500 // Send some messages.
501 std::vector
<std::string
> id_list
;
502 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
503 id_list
.push_back(base::IntToString(i
));
504 MCSMessage
message(BuildDataMessage("from",
514 GetFakeHandler()->ExpectOutgoingMessage(message
);
515 mcs_client()->SendMessage(message
);
518 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
520 // Rebuild the client, and receive an acknowledgment for the messages as
521 // part of the login response.
525 LoginClient(std::vector
<std::string
>());
526 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(id_list
));
527 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
528 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
531 // Send messages with RMQ support. On restart, receive a SelectiveAck with
532 // the login response that only acks some messages. The unacked messages should
534 TEST_F(MCSClientTest
, SendMessageRMQPartialAckOnReconnect
) {
537 LoginClient(std::vector
<std::string
>());
539 // Send some messages.
540 std::vector
<std::string
> id_list
;
541 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
542 id_list
.push_back(base::IntToString(i
));
543 MCSMessage
message(BuildDataMessage("from",
553 GetFakeHandler()->ExpectOutgoingMessage(message
);
554 mcs_client()->SendMessage(message
);
557 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
559 // Rebuild the client, and receive an acknowledgment for the messages as
560 // part of the login response.
564 LoginClient(std::vector
<std::string
>());
566 std::vector
<std::string
> acked_ids
, remaining_ids
;
567 acked_ids
.insert(acked_ids
.end(),
569 id_list
.begin() + kMessageBatchSize
/ 2);
570 remaining_ids
.insert(remaining_ids
.end(),
571 id_list
.begin() + kMessageBatchSize
/ 2,
573 for (int i
= 1; i
<= kMessageBatchSize
/ 2; ++i
) {
574 MCSMessage
message(BuildDataMessage("from",
576 remaining_ids
[i
- 1],
578 remaining_ids
[i
- 1],
584 GetFakeHandler()->ExpectOutgoingMessage(message
);
586 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(acked_ids
));
587 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
590 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
593 // Handle a selective ack that only acks some messages. The remaining unacked
594 // messages should be resent. On restart, those same unacked messages should be
595 // resent, and any pending acks for incoming messages should also be resent.
596 TEST_F(MCSClientTest
, SelectiveAckMidStream
) {
599 LoginClient(std::vector
<std::string
>());
601 // Server stream id 2 ("s1").
602 // Acks client stream id 0 (login).
603 MCSMessage
sMessage1(BuildDataMessage(
604 "from", "category", "X", 0, "s1", kTTLValue
, 1, 0, "", 0));
605 GetFakeHandler()->ReceiveMessage(sMessage1
);
609 // Client stream id 1 ("1").
610 // Acks server stream id 2 ("s1").
611 MCSMessage
cMessage1(BuildDataMessage(
612 "from", "category", "Y", 2, "1", kTTLValue
, 1, 0, "", 0));
613 GetFakeHandler()->ExpectOutgoingMessage(cMessage1
);
614 mcs_client()->SendMessage(cMessage1
);
616 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
618 // Server stream id 3 ("s2").
619 // Acks client stream id 1 ("1").
620 // Confirms ack of server stream id 2 ("s1").
621 MCSMessage
sMessage2(BuildDataMessage(
622 "from", "category", "X", 1, "s2", kTTLValue
, 1, 0, "", 0));
623 GetFakeHandler()->ReceiveMessage(sMessage2
);
627 // Client Stream id 2 ("2").
628 // Acks server stream id 3 ("s2").
629 MCSMessage
cMessage2(BuildDataMessage(
630 "from", "category", "Y", 3, "2", kTTLValue
, 1, 0, "", 0));
631 GetFakeHandler()->ExpectOutgoingMessage(cMessage2
);
632 mcs_client()->SendMessage(cMessage2
);
634 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
636 // Simulate the last message being dropped by having the server selectively
637 // ack client message "1".
638 // Client message "2" should be resent, acking server stream id 4 (selective
640 MCSMessage
cMessage3(BuildDataMessage(
641 "from", "category", "Y", 4, "2", kTTLValue
, 1, 0, "", 0));
642 GetFakeHandler()->ExpectOutgoingMessage(cMessage3
);
643 std::vector
<std::string
> acked_ids(1, "1");
644 scoped_ptr
<mcs_proto::IqStanza
> ack(BuildSelectiveAck(acked_ids
));
645 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
648 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
650 // Rebuild the client without any further acks from server. Note that this
651 // resets the stream ids.
652 // Sever message "s2" should be acked as part of login.
653 // Client message "2" should be resent.
659 LoginClient(acked_ids
);
661 MCSMessage
cMessage4(BuildDataMessage(
662 "from", "category", "Y", 1, "2", kTTLValue
, 1, 0, "", 0));
663 GetFakeHandler()->ExpectOutgoingMessage(cMessage4
);
665 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
668 // Receive some messages. On restart, the login request should contain the
669 // appropriate acknowledged ids.
670 TEST_F(MCSClientTest
, AckOnLogin
) {
673 LoginClient(std::vector
<std::string
>());
675 // Receive some messages.
676 std::vector
<std::string
> id_list
;
677 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
678 id_list
.push_back(base::IntToString(i
));
679 MCSMessage
message(BuildDataMessage(
680 "from", "category", "X", 1, id_list
.back(), kTTLValue
, 1, 0, "", 0));
681 GetFakeHandler()->ReceiveMessage(message
);
686 // Restart the client.
690 LoginClient(id_list
);
693 // Receive some messages. On the next send, the outgoing message should contain
694 // the appropriate last stream id received field to ack the received messages.
695 TEST_F(MCSClientTest
, AckOnSend
) {
698 LoginClient(std::vector
<std::string
>());
700 // Receive some messages.
701 std::vector
<std::string
> id_list
;
702 for (int i
= 1; i
<= kMessageBatchSize
; ++i
) {
703 id_list
.push_back(base::IntToString(i
));
704 MCSMessage
message(BuildDataMessage("from",
714 GetFakeHandler()->ReceiveMessage(message
);
718 // Trigger a message send, which should acknowledge via stream ack.
719 MCSMessage
message(BuildDataMessage("from",
722 kMessageBatchSize
+ 1,
729 GetFakeHandler()->ExpectOutgoingMessage(message
);
730 mcs_client()->SendMessage(message
);
731 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
734 // Receive the ack limit in messages, which should trigger an automatic
735 // stream ack. Receive a heartbeat to confirm the ack.
736 TEST_F(MCSClientTest
, AckWhenLimitReachedWithHeartbeat
) {
739 LoginClient(std::vector
<std::string
>());
742 scoped_ptr
<mcs_proto::IqStanza
> ack
= BuildStreamAck();
743 ack
->set_last_stream_id_received(kAckLimitSize
+ 1);
744 GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(kIqStanzaTag
, ack
.Pass()));
746 // Receive some messages.
747 std::vector
<std::string
> id_list
;
748 for (int i
= 1; i
<= kAckLimitSize
; ++i
) {
749 id_list
.push_back(base::IntToString(i
));
750 MCSMessage
message(BuildDataMessage("from",
760 GetFakeHandler()->ReceiveMessage(message
);
764 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
766 // Receive a heartbeat confirming the ack (and receive the heartbeat ack).
767 scoped_ptr
<mcs_proto::HeartbeatPing
> heartbeat(
768 new mcs_proto::HeartbeatPing());
769 heartbeat
->set_last_stream_id_received(2);
771 scoped_ptr
<mcs_proto::HeartbeatAck
> heartbeat_ack(
772 new mcs_proto::HeartbeatAck());
773 heartbeat_ack
->set_last_stream_id_received(kAckLimitSize
+ 2);
774 GetFakeHandler()->ExpectOutgoingMessage(
775 MCSMessage(kHeartbeatAckTag
, heartbeat_ack
.Pass()));
777 GetFakeHandler()->ReceiveMessage(
778 MCSMessage(kHeartbeatPingTag
, heartbeat
.Pass()));
780 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
782 // Rebuild the client. Nothing should be sent on login.
786 LoginClient(std::vector
<std::string
>());
787 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
790 // If a message's TTL has expired by the time it reaches the front of the send
791 // queue, it should be dropped.
792 TEST_F(MCSClientTest
, ExpiredTTLOnSend
) {
795 LoginClient(std::vector
<std::string
>());
796 MCSMessage
message(BuildDataMessage(
797 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
799 // Advance time to after the TTL.
800 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
+ 2));
801 EXPECT_TRUE(sent_message_id().empty());
802 mcs_client()->SendMessage(message
);
804 // No messages should be sent, but the callback should still be invoked.
805 EXPECT_EQ("X", sent_message_id());
806 EXPECT_EQ(MCSClient::TTL_EXCEEDED
, message_send_status());
807 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
810 TEST_F(MCSClientTest
, ExpiredTTLOnRestart
) {
813 LoginClient(std::vector
<std::string
>());
814 GetFakeHandler()->set_fail_send(true);
815 MCSMessage
message(BuildDataMessage(
816 "from", "category", "X", 1, "1", kTTLValue
, 1, 0, "", 0));
818 // The initial (failed) send.
819 GetFakeHandler()->ExpectOutgoingMessage(message
);
820 GetFakeHandler()->set_fail_send(false);
821 mcs_client()->SendMessage(message
);
823 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
825 // Move the clock forward and rebuild the client, which should fail the
826 // message send on restart.
827 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue
+ 2));
831 LoginClient(std::vector
<std::string
>());
833 EXPECT_EQ("X", sent_message_id());
834 EXPECT_EQ(MCSClient::TTL_EXCEEDED
, message_send_status());
835 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
838 // Sending two messages with the same collapse key and same app id while
839 // disconnected should only send the latter of the two on reconnection.
840 TEST_F(MCSClientTest
, CollapseKeysSameApp
) {
843 MCSMessage
message(BuildDataMessage(
844 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
845 mcs_client()->SendMessage(message
);
847 MCSMessage
message2(BuildDataMessage(
848 "from", "app", "message id 2", 1, "1", kTTLValue
, 1, 0, "token", 0));
849 mcs_client()->SendMessage(message2
);
851 LoginClient(std::vector
<std::string
>());
852 GetFakeHandler()->ExpectOutgoingMessage(message2
);
856 // Sending two messages with the same collapse key and different app id while
857 // disconnected should not perform any collapsing.
858 TEST_F(MCSClientTest
, CollapseKeysDifferentApp
) {
861 MCSMessage
message(BuildDataMessage(
862 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
863 mcs_client()->SendMessage(message
);
865 MCSMessage
message2(BuildDataMessage("from",
875 mcs_client()->SendMessage(message2
);
877 LoginClient(std::vector
<std::string
>());
878 GetFakeHandler()->ExpectOutgoingMessage(message
);
879 GetFakeHandler()->ExpectOutgoingMessage(message2
);
883 // Sending two messages with the same collapse key and app id, but different
884 // user, while disconnected, should not perform any collapsing.
885 TEST_F(MCSClientTest
, CollapseKeysDifferentUser
) {
888 MCSMessage
message(BuildDataMessage(
889 "from", "app", "message id 1", 1, "1", kTTLValue
, 1, 0, "token", 0));
890 mcs_client()->SendMessage(message
);
892 MCSMessage
message2(BuildDataMessage("from",
902 mcs_client()->SendMessage(message2
);
904 LoginClient(std::vector
<std::string
>());
905 GetFakeHandler()->ExpectOutgoingMessage(message
);
906 GetFakeHandler()->ExpectOutgoingMessage(message2
);
910 // Test case for setting a custom heartbeat interval, when it is too short.
911 // Covers both connection restart and storing of custom intervals.
912 TEST_F(MCSClientTest
, CustomHeartbeatIntervalTooShort
) {
915 LoginClient(std::vector
<std::string
>());
919 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
920 // By default custom client interval is not set.
921 EXPECT_FALSE(hb_manager
->HasClientHeartbeatInterval());
923 const std::string component_1
= "component1";
924 int interval_ms
= 30 * 1000; // 30 seconds, too low.
925 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
926 // Setting was too low so it was ignored.
927 EXPECT_FALSE(hb_manager
->HasClientHeartbeatInterval());
929 // Restore and check again to make sure that nothing was set in store.
932 LoginClientWithHeartbeat(std::vector
<std::string
>(), 0);
935 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
936 EXPECT_FALSE(hb_manager
->HasClientHeartbeatInterval());
939 // Test case for setting a custom heartbeat interval, when it is too long.
940 // Covers both connection restart and storing of custom intervals.
941 TEST_F(MCSClientTest
, CustomHeartbeatIntervalTooLong
) {
944 LoginClient(std::vector
<std::string
>());
948 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
950 const std::string component_1
= "component1";
951 int interval_ms
= 60 * 60 * 1000; // 1 hour, too high.
952 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
953 // Setting was too high, again it was ignored.
954 EXPECT_FALSE(hb_manager
->HasClientHeartbeatInterval());
956 // Restore and check again to make sure that nothing was set in store.
959 LoginClientWithHeartbeat(std::vector
<std::string
>(), 0);
962 // Setting was too high, again it was ignored.
963 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
964 EXPECT_FALSE(hb_manager
->HasClientHeartbeatInterval());
967 // Tests adding and removing custom heartbeat interval.
968 // Covers both connection restart and storing of custom intervals.
969 TEST_F(MCSClientTest
, CustomHeartbeatIntervalSingleInterval
) {
972 LoginClient(std::vector
<std::string
>());
976 TestConnectionListener test_connection_listener
;
977 connection_factory()->SetConnectionListener(&test_connection_listener
);
979 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
981 const std::string component_1
= "component1";
982 int interval_ms
= 5 * 60 * 1000; // 5 minutes. A valid setting.
984 AddExpectedLoginRequest(std::vector
<std::string
>(), interval_ms
);
985 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
988 // Interval was OK. HearbeatManager should get that setting now.
989 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
990 EXPECT_EQ(interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
991 EXPECT_EQ(1, test_connection_listener
.get_disconnect_counter());
993 // Check that setting was persisted and will take effect upon restart.
996 LoginClientWithHeartbeat(std::vector
<std::string
>(), interval_ms
);
999 // HB manger uses the shortest persisted interval after restart.
1000 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1001 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1002 EXPECT_EQ(interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
1004 mcs_client()->RemoveHeartbeatInterval(component_1
);
1007 // Check that setting was persisted and will take effect upon restart.
1010 LoginClientWithHeartbeat(std::vector
<std::string
>(), 0);
1013 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1014 EXPECT_FALSE(hb_manager
->HasClientHeartbeatInterval());
1017 // Tests adding custom heartbeat interval before connection is initialized.
1018 TEST_F(MCSClientTest
, CustomHeartbeatIntervalSetBeforeInitialize
) {
1021 const std::string component_1
= "component1";
1022 int interval_ms
= 5 * 60 * 1000; // 5 minutes. A valid setting.
1023 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
1025 LoginClientWithHeartbeat(std::vector
<std::string
>(), interval_ms
);
1026 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1027 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1030 // Tests adding custom heartbeat interval after connection is initialized, but
1031 // but before login is sent.
1032 TEST_F(MCSClientTest
, CustomHeartbeatIntervalSetBeforeLogin
) {
1035 const std::string component_1
= "component1";
1036 int interval_ms
= 5 * 60 * 1000; // 5 minutes. A valid setting.
1038 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
1039 LoginClientWithHeartbeat(std::vector
<std::string
>(), interval_ms
);
1040 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1041 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1044 // Tests situation when two heartbeat intervals are set and second is longer.
1045 // Covers both connection restart and storing of custom intervals.
1046 TEST_F(MCSClientTest
, CustomHeartbeatIntervalSecondIntervalLonger
) {
1049 LoginClient(std::vector
<std::string
>());
1053 TestConnectionListener test_connection_listener
;
1054 connection_factory()->SetConnectionListener(&test_connection_listener
);
1056 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1058 const std::string component_1
= "component1";
1059 int interval_ms
= 5 * 60 * 1000; // 5 minutes. A valid setting.
1061 AddExpectedLoginRequest(std::vector
<std::string
>(), interval_ms
);
1062 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
1065 const std::string component_2
= "component2";
1066 int other_interval_ms
= 10 * 60 * 1000; // 10 minutes. A valid setting.
1067 mcs_client()->AddHeartbeatInterval(component_2
, other_interval_ms
);
1070 // Interval was OK, but longer. HearbeatManager will use the first one.
1071 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1072 EXPECT_EQ(interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
1073 EXPECT_EQ(1, test_connection_listener
.get_disconnect_counter());
1075 // Check that setting was persisted and will take effect upon restart.
1078 LoginClientWithHeartbeat(std::vector
<std::string
>(), interval_ms
);
1081 // HB manger uses the shortest persisted interval after restart.
1082 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1083 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1084 EXPECT_EQ(interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
1087 // Tests situation when two heartbeat intervals are set and second is shorter.
1088 // Covers both connection restart and storing of custom intervals.
1089 TEST_F(MCSClientTest
, CustomHeartbeatIntervalSecondIntervalShorter
) {
1092 LoginClient(std::vector
<std::string
>());
1096 TestConnectionListener test_connection_listener
;
1097 connection_factory()->SetConnectionListener(&test_connection_listener
);
1099 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1101 const std::string component_1
= "component1";
1102 int interval_ms
= 5 * 60 * 1000; // 5 minutes. A valid setting.
1104 AddExpectedLoginRequest(std::vector
<std::string
>(), interval_ms
);
1105 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
1108 const std::string component_2
= "component2";
1109 int other_interval_ms
= 3 * 60 * 1000; // 3 minutes. A valid setting.
1110 AddExpectedLoginRequest(std::vector
<std::string
>(), other_interval_ms
);
1111 mcs_client()->AddHeartbeatInterval(component_2
, other_interval_ms
);
1113 // Interval was OK. HearbeatManager should get that setting now.
1114 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1115 EXPECT_EQ(other_interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
1116 EXPECT_EQ(2, test_connection_listener
.get_disconnect_counter());
1118 // Check that setting was persisted and will take effect upon restart.
1121 LoginClientWithHeartbeat(std::vector
<std::string
>(), other_interval_ms
);
1124 // HB manger uses the shortest persisted interval after restart.
1125 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1126 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1127 EXPECT_EQ(other_interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
1130 // Tests situation shorter of two intervals is removed.
1131 // Covers both connection restart and storing of custom intervals.
1132 TEST_F(MCSClientTest
, CustomHeartbeatIntervalRemoveShorterInterval
) {
1135 LoginClient(std::vector
<std::string
>());
1139 TestConnectionListener test_connection_listener
;
1140 connection_factory()->SetConnectionListener(&test_connection_listener
);
1142 HeartbeatManager
* hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1144 const std::string component_1
= "component1";
1145 int interval_ms
= 5 * 60 * 1000; // 5 minutes. A valid setting.
1147 AddExpectedLoginRequest(std::vector
<std::string
>(), interval_ms
);
1148 mcs_client()->AddHeartbeatInterval(component_1
, interval_ms
);
1151 const std::string component_2
= "component2";
1152 int other_interval_ms
= 3 * 60 * 1000; // 3 minutes. A valid setting.
1153 AddExpectedLoginRequest(std::vector
<std::string
>(), other_interval_ms
);
1154 mcs_client()->AddHeartbeatInterval(component_2
, other_interval_ms
);
1157 mcs_client()->RemoveHeartbeatInterval(component_2
);
1160 // Removing the lowest setting reverts to second lowest.
1161 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1162 EXPECT_EQ(interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());
1163 // No connection reset expected.
1164 EXPECT_EQ(2, test_connection_listener
.get_disconnect_counter());
1166 // Check that setting was persisted and will take effect upon restart.
1169 LoginClientWithHeartbeat(std::vector
<std::string
>(), interval_ms
);
1172 // HB manger uses the shortest persisted interval after restart.
1173 hb_manager
= mcs_client()->GetHeartbeatManagerForTesting();
1174 EXPECT_TRUE(hb_manager
->HasClientHeartbeatInterval());
1175 EXPECT_EQ(interval_ms
, hb_manager
->GetClientHeartbeatIntervalMs());