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,
78 make_scoped_ptr(new base::Timer(true, false))),
82 std::string GetNextPersistentId() override {
83 return base::UintToString(++next_id_);
90 class MCSClientTest : public testing::Test {
93 virtual ~MCSClientTest();
95 virtual void SetUp() override;
97 void BuildMCSClient();
98 void InitializeClient();
99 void StoreCredentials();
100 void LoginClient(const std::vector<std::string>& acknowledged_ids);
102 base::SimpleTestClock* clock() { return &clock_; }
103 TestMCSClient* mcs_client() const { return mcs_client_.get(); }
104 FakeConnectionFactory* connection_factory() {
105 return &connection_factory_;
107 bool init_success() const { return init_success_; }
108 uint64 restored_android_id() const { return restored_android_id_; }
109 uint64 restored_security_token() const { return restored_security_token_; }
110 MCSMessage* received_message() const { return received_message_.get(); }
111 std::string sent_message_id() const { return sent_message_id_;}
112 MCSClient::MessageSendStatus message_send_status() const {
113 return message_send_status_;
116 void SetDeviceCredentialsCallback(bool success);
118 FakeConnectionHandler* GetFakeHandler() const;
120 void WaitForMCSEvent();
124 void ErrorCallback();
125 void MessageReceivedCallback(const MCSMessage& message);
126 void MessageSentCallback(int64 user_serial_number,
127 const std::string& app_id,
128 const std::string& message_id,
129 MCSClient::MessageSendStatus status);
131 base::SimpleTestClock clock_;
133 base::ScopedTempDir temp_directory_;
134 base::MessageLoop message_loop_;
135 scoped_ptr<base::RunLoop> run_loop_;
136 scoped_ptr<GCMStore> gcm_store_;
138 FakeConnectionFactory connection_factory_;
139 scoped_ptr<TestMCSClient> mcs_client_;
141 uint64 restored_android_id_;
142 uint64 restored_security_token_;
143 scoped_ptr<MCSMessage> received_message_;
144 std::string sent_message_id_;
145 MCSClient::MessageSendStatus message_send_status_;
147 gcm::FakeGCMStatsRecorder recorder_;
150 MCSClientTest::MCSClientTest()
151 : run_loop_(new base::RunLoop()),
153 restored_android_id_(0),
154 restored_security_token_(0),
155 message_send_status_(MCSClient::SENT) {
156 EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
157 run_loop_.reset(new base::RunLoop());
159 // Advance the clock to a non-zero time.
160 clock_.Advance(base::TimeDelta::FromSeconds(1));
163 MCSClientTest::~MCSClientTest() {}
165 void MCSClientTest::SetUp() {
166 testing::Test::SetUp();
169 void MCSClientTest::BuildMCSClient() {
170 gcm_store_.reset(new GCMStoreImpl(
171 temp_directory_.path(),
172 message_loop_.message_loop_proxy(),
173 make_scoped_ptr<Encryptor>(new FakeEncryptor)));
174 mcs_client_.reset(new TestMCSClient(&clock_,
175 &connection_factory_,
180 void MCSClientTest::InitializeClient() {
181 gcm_store_->Load(base::Bind(
182 &MCSClient::Initialize,
183 base::Unretained(mcs_client_.get()),
184 base::Bind(&MCSClientTest::ErrorCallback,
185 base::Unretained(this)),
186 base::Bind(&MCSClientTest::MessageReceivedCallback,
187 base::Unretained(this)),
188 base::Bind(&MCSClientTest::MessageSentCallback, base::Unretained(this))));
189 run_loop_->RunUntilIdle();
190 run_loop_.reset(new base::RunLoop());
193 void MCSClientTest::LoginClient(
194 const std::vector<std::string>& acknowledged_ids) {
195 scoped_ptr<mcs_proto::LoginRequest> login_request =
196 BuildLoginRequest(kAndroidId, kSecurityToken, "");
197 for (size_t i = 0; i < acknowledged_ids.size(); ++i)
198 login_request->add_received_persistent_id(acknowledged_ids[i]);
199 GetFakeHandler()->ExpectOutgoingMessage(
200 MCSMessage(kLoginRequestTag, login_request.Pass()));
201 mcs_client_->Login(kAndroidId, kSecurityToken);
203 run_loop_.reset(new base::RunLoop());
206 void MCSClientTest::StoreCredentials() {
207 gcm_store_->SetDeviceCredentials(
208 kAndroidId, kSecurityToken,
209 base::Bind(&MCSClientTest::SetDeviceCredentialsCallback,
210 base::Unretained(this)));
212 run_loop_.reset(new base::RunLoop());
215 FakeConnectionHandler* MCSClientTest::GetFakeHandler() const {
216 return reinterpret_cast<FakeConnectionHandler*>(
217 connection_factory_.GetConnectionHandler());
220 void MCSClientTest::WaitForMCSEvent() {
222 run_loop_.reset(new base::RunLoop());
225 void MCSClientTest::PumpLoop() {
226 run_loop_->RunUntilIdle();
227 run_loop_.reset(new base::RunLoop());
230 void MCSClientTest::ErrorCallback() {
231 init_success_ = false;
232 DVLOG(1) << "Error callback invoked, killing loop.";
236 void MCSClientTest::MessageReceivedCallback(const MCSMessage& message) {
237 received_message_.reset(new MCSMessage(message));
238 DVLOG(1) << "Message received callback invoked, killing loop.";
242 void MCSClientTest::MessageSentCallback(int64 user_serial_number,
243 const std::string& app_id,
244 const std::string& message_id,
245 MCSClient::MessageSendStatus status) {
246 DVLOG(1) << "Message sent callback invoked, killing loop.";
247 sent_message_id_ = message_id;
248 message_send_status_ = status;
252 void MCSClientTest::SetDeviceCredentialsCallback(bool success) {
253 ASSERT_TRUE(success);
257 // Initialize a new client.
258 TEST_F(MCSClientTest, InitializeNew) {
261 EXPECT_TRUE(init_success());
264 // Initialize a new client, shut it down, then restart the client. Should
265 // reload the existing device credentials.
266 TEST_F(MCSClientTest, InitializeExisting) {
269 LoginClient(std::vector<std::string>());
271 // Rebuild the client, to reload from the GCM store.
275 EXPECT_TRUE(init_success());
278 // Log in successfully to the MCS endpoint.
279 TEST_F(MCSClientTest, LoginSuccess) {
282 LoginClient(std::vector<std::string>());
283 EXPECT_TRUE(connection_factory()->IsEndpointReachable());
284 EXPECT_TRUE(init_success());
285 ASSERT_TRUE(received_message());
286 EXPECT_EQ(kLoginResponseTag, received_message()->tag());
289 // Encounter a server error during the login attempt. Should trigger a
291 TEST_F(MCSClientTest, FailLogin) {
294 GetFakeHandler()->set_fail_login(true);
295 connection_factory()->set_delay_reconnect(true);
296 LoginClient(std::vector<std::string>());
297 EXPECT_FALSE(connection_factory()->IsEndpointReachable());
298 EXPECT_FALSE(init_success());
299 EXPECT_FALSE(received_message());
300 EXPECT_TRUE(connection_factory()->reconnect_pending());
303 // Send a message without RMQ support.
304 TEST_F(MCSClientTest, SendMessageNoRMQ) {
307 LoginClient(std::vector<std::string>());
309 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
310 GetFakeHandler()->ExpectOutgoingMessage(message);
311 mcs_client()->SendMessage(message);
312 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
315 // Send a message without RMQ support while disconnected. Message send should
316 // fail immediately, invoking callback.
317 TEST_F(MCSClientTest, SendMessageNoRMQWhileDisconnected) {
321 EXPECT_TRUE(sent_message_id().empty());
323 BuildDataMessage("from", "category", "X", 1, "", 0, 1, 0, "", 0));
324 mcs_client()->SendMessage(message);
326 // Message sent callback should be invoked, but no message should actually
328 EXPECT_EQ("X", sent_message_id());
329 EXPECT_EQ(MCSClient::NO_CONNECTION_ON_ZERO_TTL, message_send_status());
330 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
333 // Send a message with RMQ support.
334 TEST_F(MCSClientTest, SendMessageRMQ) {
337 LoginClient(std::vector<std::string>());
338 MCSMessage message(BuildDataMessage(
339 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
340 GetFakeHandler()->ExpectOutgoingMessage(message);
341 mcs_client()->SendMessage(message);
342 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
345 // Send a message with RMQ support while disconnected. On reconnect, the message
347 TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
350 LoginClient(std::vector<std::string>());
351 GetFakeHandler()->set_fail_send(true);
352 MCSMessage message(BuildDataMessage(
353 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
355 // The initial (failed) send.
356 GetFakeHandler()->ExpectOutgoingMessage(message);
357 // The login request.
358 GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(
359 kLoginRequestTag, BuildLoginRequest(kAndroidId, kSecurityToken, "")));
360 // The second (re)send.
361 MCSMessage message2(BuildDataMessage(
362 "from", "category", "X", 1, "1", kTTLValue, 1, kTTLValue - 1, "", 0));
363 GetFakeHandler()->ExpectOutgoingMessage(message2);
364 mcs_client()->SendMessage(message);
365 PumpLoop(); // Wait for the queuing to happen.
366 EXPECT_EQ(MCSClient::QUEUED, message_send_status());
367 EXPECT_EQ("X", sent_message_id());
368 EXPECT_FALSE(GetFakeHandler()->AllOutgoingMessagesReceived());
369 GetFakeHandler()->set_fail_send(false);
370 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
371 connection_factory()->Connect();
372 WaitForMCSEvent(); // Wait for the login to finish.
373 PumpLoop(); // Wait for the send to happen.
376 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
377 ack->set_last_stream_id_received(2);
378 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
381 EXPECT_EQ(MCSClient::SENT, message_send_status());
382 EXPECT_EQ("X", sent_message_id());
383 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
386 // Send a message with RMQ support without receiving an acknowledgement. On
387 // restart the message should be resent.
388 TEST_F(MCSClientTest, SendMessageRMQOnRestart) {
391 LoginClient(std::vector<std::string>());
392 GetFakeHandler()->set_fail_send(true);
393 MCSMessage message(BuildDataMessage(
394 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
396 // The initial (failed) send.
397 GetFakeHandler()->ExpectOutgoingMessage(message);
398 GetFakeHandler()->set_fail_send(false);
399 mcs_client()->SendMessage(message);
401 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
403 // Rebuild the client, which should resend the old message.
408 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
409 MCSMessage message2(BuildDataMessage(
410 "from", "category", "X", 1, "1", kTTLValue, 1, kTTLValue - 1, "", 0));
411 LoginClient(std::vector<std::string>());
412 GetFakeHandler()->ExpectOutgoingMessage(message2);
414 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
417 // Send messages with RMQ support, followed by receiving a stream ack. On
418 // restart nothing should be recent.
419 TEST_F(MCSClientTest, SendMessageRMQWithStreamAck) {
422 LoginClient(std::vector<std::string>());
424 // Send some messages.
425 for (int i = 1; i <= kMessageBatchSize; ++i) {
426 MCSMessage message(BuildDataMessage("from",
430 base::IntToString(i),
436 GetFakeHandler()->ExpectOutgoingMessage(message);
437 mcs_client()->SendMessage(message);
440 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
443 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
444 ack->set_last_stream_id_received(kMessageBatchSize + 1);
445 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
448 // Reconnect and ensure no messages are resent.
452 LoginClient(std::vector<std::string>());
456 // Send messages with RMQ support. On restart, receive a SelectiveAck with
457 // the login response. No messages should be resent.
458 TEST_F(MCSClientTest, SendMessageRMQAckOnReconnect) {
461 LoginClient(std::vector<std::string>());
463 // Send some messages.
464 std::vector<std::string> id_list;
465 for (int i = 1; i <= kMessageBatchSize; ++i) {
466 id_list.push_back(base::IntToString(i));
467 MCSMessage message(BuildDataMessage("from",
477 GetFakeHandler()->ExpectOutgoingMessage(message);
478 mcs_client()->SendMessage(message);
481 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
483 // Rebuild the client, and receive an acknowledgment for the messages as
484 // part of the login response.
488 LoginClient(std::vector<std::string>());
489 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(id_list));
490 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
491 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
494 // Send messages with RMQ support. On restart, receive a SelectiveAck with
495 // the login response that only acks some messages. The unacked messages should
497 TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) {
500 LoginClient(std::vector<std::string>());
502 // Send some messages.
503 std::vector<std::string> id_list;
504 for (int i = 1; i <= kMessageBatchSize; ++i) {
505 id_list.push_back(base::IntToString(i));
506 MCSMessage message(BuildDataMessage("from",
516 GetFakeHandler()->ExpectOutgoingMessage(message);
517 mcs_client()->SendMessage(message);
520 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
522 // Rebuild the client, and receive an acknowledgment for the messages as
523 // part of the login response.
527 LoginClient(std::vector<std::string>());
529 std::vector<std::string> acked_ids, remaining_ids;
530 acked_ids.insert(acked_ids.end(),
532 id_list.begin() + kMessageBatchSize / 2);
533 remaining_ids.insert(remaining_ids.end(),
534 id_list.begin() + kMessageBatchSize / 2,
536 for (int i = 1; i <= kMessageBatchSize / 2; ++i) {
537 MCSMessage message(BuildDataMessage("from",
539 remaining_ids[i - 1],
541 remaining_ids[i - 1],
547 GetFakeHandler()->ExpectOutgoingMessage(message);
549 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
550 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
553 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
556 // Handle a selective ack that only acks some messages. The remaining unacked
557 // messages should be resent. On restart, those same unacked messages should be
558 // resent, and any pending acks for incoming messages should also be resent.
559 TEST_F(MCSClientTest, SelectiveAckMidStream) {
562 LoginClient(std::vector<std::string>());
564 // Server stream id 2 ("s1").
565 // Acks client stream id 0 (login).
566 MCSMessage sMessage1(BuildDataMessage(
567 "from", "category", "X", 0, "s1", kTTLValue, 1, 0, "", 0));
568 GetFakeHandler()->ReceiveMessage(sMessage1);
572 // Client stream id 1 ("1").
573 // Acks server stream id 2 ("s1").
574 MCSMessage cMessage1(BuildDataMessage(
575 "from", "category", "Y", 2, "1", kTTLValue, 1, 0, "", 0));
576 GetFakeHandler()->ExpectOutgoingMessage(cMessage1);
577 mcs_client()->SendMessage(cMessage1);
579 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
581 // Server stream id 3 ("s2").
582 // Acks client stream id 1 ("1").
583 // Confirms ack of server stream id 2 ("s1").
584 MCSMessage sMessage2(BuildDataMessage(
585 "from", "category", "X", 1, "s2", kTTLValue, 1, 0, "", 0));
586 GetFakeHandler()->ReceiveMessage(sMessage2);
590 // Client Stream id 2 ("2").
591 // Acks server stream id 3 ("s2").
592 MCSMessage cMessage2(BuildDataMessage(
593 "from", "category", "Y", 3, "2", kTTLValue, 1, 0, "", 0));
594 GetFakeHandler()->ExpectOutgoingMessage(cMessage2);
595 mcs_client()->SendMessage(cMessage2);
597 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
599 // Simulate the last message being dropped by having the server selectively
600 // ack client message "1".
601 // Client message "2" should be resent, acking server stream id 4 (selective
603 MCSMessage cMessage3(BuildDataMessage(
604 "from", "category", "Y", 4, "2", kTTLValue, 1, 0, "", 0));
605 GetFakeHandler()->ExpectOutgoingMessage(cMessage3);
606 std::vector<std::string> acked_ids(1, "1");
607 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
608 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
611 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
613 // Rebuild the client without any further acks from server. Note that this
614 // resets the stream ids.
615 // Sever message "s2" should be acked as part of login.
616 // Client message "2" should be resent.
622 LoginClient(acked_ids);
624 MCSMessage cMessage4(BuildDataMessage(
625 "from", "category", "Y", 1, "2", kTTLValue, 1, 0, "", 0));
626 GetFakeHandler()->ExpectOutgoingMessage(cMessage4);
628 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
631 // Receive some messages. On restart, the login request should contain the
632 // appropriate acknowledged ids.
633 TEST_F(MCSClientTest, AckOnLogin) {
636 LoginClient(std::vector<std::string>());
638 // Receive some messages.
639 std::vector<std::string> id_list;
640 for (int i = 1; i <= kMessageBatchSize; ++i) {
641 id_list.push_back(base::IntToString(i));
642 MCSMessage message(BuildDataMessage(
643 "from", "category", "X", 1, id_list.back(), kTTLValue, 1, 0, "", 0));
644 GetFakeHandler()->ReceiveMessage(message);
649 // Restart the client.
653 LoginClient(id_list);
656 // Receive some messages. On the next send, the outgoing message should contain
657 // the appropriate last stream id received field to ack the received messages.
658 TEST_F(MCSClientTest, AckOnSend) {
661 LoginClient(std::vector<std::string>());
663 // Receive some messages.
664 std::vector<std::string> id_list;
665 for (int i = 1; i <= kMessageBatchSize; ++i) {
666 id_list.push_back(base::IntToString(i));
667 MCSMessage message(BuildDataMessage("from",
677 GetFakeHandler()->ReceiveMessage(message);
681 // Trigger a message send, which should acknowledge via stream ack.
682 MCSMessage message(BuildDataMessage("from",
685 kMessageBatchSize + 1,
692 GetFakeHandler()->ExpectOutgoingMessage(message);
693 mcs_client()->SendMessage(message);
694 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
697 // Receive the ack limit in messages, which should trigger an automatic
698 // stream ack. Receive a heartbeat to confirm the ack.
699 TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) {
702 LoginClient(std::vector<std::string>());
705 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
706 ack->set_last_stream_id_received(kAckLimitSize + 1);
707 GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
709 // Receive some messages.
710 std::vector<std::string> id_list;
711 for (int i = 1; i <= kAckLimitSize; ++i) {
712 id_list.push_back(base::IntToString(i));
713 MCSMessage message(BuildDataMessage("from",
723 GetFakeHandler()->ReceiveMessage(message);
727 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
729 // Receive a heartbeat confirming the ack (and receive the heartbeat ack).
730 scoped_ptr<mcs_proto::HeartbeatPing> heartbeat(
731 new mcs_proto::HeartbeatPing());
732 heartbeat->set_last_stream_id_received(2);
734 scoped_ptr<mcs_proto::HeartbeatAck> heartbeat_ack(
735 new mcs_proto::HeartbeatAck());
736 heartbeat_ack->set_last_stream_id_received(kAckLimitSize + 2);
737 GetFakeHandler()->ExpectOutgoingMessage(
738 MCSMessage(kHeartbeatAckTag, heartbeat_ack.Pass()));
740 GetFakeHandler()->ReceiveMessage(
741 MCSMessage(kHeartbeatPingTag, heartbeat.Pass()));
743 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
745 // Rebuild the client. Nothing should be sent on login.
749 LoginClient(std::vector<std::string>());
750 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
753 // If a message's TTL has expired by the time it reaches the front of the send
754 // queue, it should be dropped.
755 TEST_F(MCSClientTest, ExpiredTTLOnSend) {
758 LoginClient(std::vector<std::string>());
759 MCSMessage message(BuildDataMessage(
760 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
762 // Advance time to after the TTL.
763 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 2));
764 EXPECT_TRUE(sent_message_id().empty());
765 mcs_client()->SendMessage(message);
767 // No messages should be sent, but the callback should still be invoked.
768 EXPECT_EQ("X", sent_message_id());
769 EXPECT_EQ(MCSClient::TTL_EXCEEDED, message_send_status());
770 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
773 TEST_F(MCSClientTest, ExpiredTTLOnRestart) {
776 LoginClient(std::vector<std::string>());
777 GetFakeHandler()->set_fail_send(true);
778 MCSMessage message(BuildDataMessage(
779 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
781 // The initial (failed) send.
782 GetFakeHandler()->ExpectOutgoingMessage(message);
783 GetFakeHandler()->set_fail_send(false);
784 mcs_client()->SendMessage(message);
786 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
788 // Move the clock forward and rebuild the client, which should fail the
789 // message send on restart.
790 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 2));
794 LoginClient(std::vector<std::string>());
796 EXPECT_EQ("X", sent_message_id());
797 EXPECT_EQ(MCSClient::TTL_EXCEEDED, message_send_status());
798 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
801 // Sending two messages with the same collapse key and same app id while
802 // disconnected should only send the latter of the two on reconnection.
803 TEST_F(MCSClientTest, CollapseKeysSameApp) {
806 MCSMessage message(BuildDataMessage(
807 "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
808 mcs_client()->SendMessage(message);
810 MCSMessage message2(BuildDataMessage(
811 "from", "app", "message id 2", 1, "1", kTTLValue, 1, 0, "token", 0));
812 mcs_client()->SendMessage(message2);
814 LoginClient(std::vector<std::string>());
815 GetFakeHandler()->ExpectOutgoingMessage(message2);
819 // Sending two messages with the same collapse key and different app id while
820 // disconnected should not perform any collapsing.
821 TEST_F(MCSClientTest, CollapseKeysDifferentApp) {
824 MCSMessage message(BuildDataMessage(
825 "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
826 mcs_client()->SendMessage(message);
828 MCSMessage message2(BuildDataMessage("from",
838 mcs_client()->SendMessage(message2);
840 LoginClient(std::vector<std::string>());
841 GetFakeHandler()->ExpectOutgoingMessage(message);
842 GetFakeHandler()->ExpectOutgoingMessage(message2);
846 // Sending two messages with the same collapse key and app id, but different
847 // user, while disconnected, should not perform any collapsing.
848 TEST_F(MCSClientTest, CollapseKeysDifferentUser) {
851 MCSMessage message(BuildDataMessage(
852 "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
853 mcs_client()->SendMessage(message);
855 MCSMessage message2(BuildDataMessage("from",
865 mcs_client()->SendMessage(message2);
867 LoginClient(std::vector<std::string>());
868 GetFakeHandler()->ExpectOutgoingMessage(message);
869 GetFakeHandler()->ExpectOutgoingMessage(message2);