[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / google_apis / gcm / engine / mcs_client_unittest.cc
blob3e94532b742ae444234ec5e188882b40d0680f97
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/gcm_stats_recorder.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 namespace gcm {
23 namespace {
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
33 // stream ack.
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,
46 int ttl,
47 uint64 sent,
48 int queued,
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 {
68 public:
69 TestMCSClient(base::Clock* clock,
70 ConnectionFactory* connection_factory,
71 GCMStore* gcm_store,
72 gcm::GCMStatsRecorder* recorder)
73 : MCSClient("", clock, connection_factory, gcm_store, recorder),
74 next_id_(0) {
77 virtual std::string GetNextPersistentId() OVERRIDE {
78 return base::UintToString(++next_id_);
81 private:
82 uint32 next_id_;
85 class MCSClientTest : public testing::Test {
86 public:
87 MCSClientTest();
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();
116 void PumpLoop();
118 private:
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_;
135 bool init_success_;
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::GCMStatsRecorder recorder_;
145 MCSClientTest::MCSClientTest()
146 : run_loop_(new base::RunLoop()),
147 init_success_(true),
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_,
171 gcm_store_.get(),
172 &recorder_));
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);
198 run_loop_->Run();
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)));
207 run_loop_->Run();
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() {
217 run_loop_->Run();
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.";
229 run_loop_->Quit();
232 void MCSClientTest::MessageReceivedCallback(const MCSMessage& message) {
233 received_message_.reset(new MCSMessage(message));
234 DVLOG(1) << "Message received callback invoked, killing loop.";
235 run_loop_->Quit();
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;
245 run_loop_->Quit();
248 void MCSClientTest::SetDeviceCredentialsCallback(bool success) {
249 ASSERT_TRUE(success);
250 run_loop_->Quit();
253 // Initialize a new client.
254 TEST_F(MCSClientTest, InitializeNew) {
255 BuildMCSClient();
256 InitializeClient();
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) {
263 BuildMCSClient();
264 InitializeClient();
265 LoginClient(std::vector<std::string>());
267 // Rebuild the client, to reload from the GCM store.
268 StoreCredentials();
269 BuildMCSClient();
270 InitializeClient();
271 EXPECT_TRUE(init_success());
274 // Log in successfully to the MCS endpoint.
275 TEST_F(MCSClientTest, LoginSuccess) {
276 BuildMCSClient();
277 InitializeClient();
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
286 // reconnect.
287 TEST_F(MCSClientTest, FailLogin) {
288 BuildMCSClient();
289 InitializeClient();
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) {
301 BuildMCSClient();
302 InitializeClient();
303 LoginClient(std::vector<std::string>());
304 MCSMessage message(
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) {
314 BuildMCSClient();
315 InitializeClient();
317 EXPECT_TRUE(sent_message_id().empty());
318 MCSMessage message(
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
323 // be sent.
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) {
331 BuildMCSClient();
332 InitializeClient();
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
342 // should be resent.
343 TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
344 BuildMCSClient();
345 InitializeClient();
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(
355 MCSMessage(
356 kLoginRequestTag,
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_FALSE(GetFakeHandler()->AllOutgoingMessagesReceived());
367 GetFakeHandler()->set_fail_send(false);
368 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
369 connection_factory()->Connect();
370 WaitForMCSEvent(); // Wait for the login to finish.
371 PumpLoop(); // Wait for the send to happen.
372 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
375 // Send a message with RMQ support without receiving an acknowledgement. On
376 // restart the message should be resent.
377 TEST_F(MCSClientTest, SendMessageRMQOnRestart) {
378 BuildMCSClient();
379 InitializeClient();
380 LoginClient(std::vector<std::string>());
381 GetFakeHandler()->set_fail_send(true);
382 MCSMessage message(BuildDataMessage(
383 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
385 // The initial (failed) send.
386 GetFakeHandler()->ExpectOutgoingMessage(message);
387 GetFakeHandler()->set_fail_send(false);
388 mcs_client()->SendMessage(message);
389 PumpLoop();
390 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
392 // Rebuild the client, which should resend the old message.
393 StoreCredentials();
394 BuildMCSClient();
395 InitializeClient();
397 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
398 MCSMessage message2(BuildDataMessage(
399 "from", "category", "X", 1, "1", kTTLValue, 1, kTTLValue - 1, "", 0));
400 LoginClient(std::vector<std::string>());
401 GetFakeHandler()->ExpectOutgoingMessage(message2);
402 PumpLoop();
403 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
406 // Send messages with RMQ support, followed by receiving a stream ack. On
407 // restart nothing should be recent.
408 TEST_F(MCSClientTest, SendMessageRMQWithStreamAck) {
409 BuildMCSClient();
410 InitializeClient();
411 LoginClient(std::vector<std::string>());
413 // Send some messages.
414 for (int i = 1; i <= kMessageBatchSize; ++i) {
415 MCSMessage message(BuildDataMessage("from",
416 "category",
417 "X",
419 base::IntToString(i),
420 kTTLValue,
424 0));
425 GetFakeHandler()->ExpectOutgoingMessage(message);
426 mcs_client()->SendMessage(message);
427 PumpLoop();
429 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
431 // Receive the ack.
432 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
433 ack->set_last_stream_id_received(kMessageBatchSize + 1);
434 GetFakeHandler()->ReceiveMessage(
435 MCSMessage(kIqStanzaTag,
436 ack.PassAs<const google::protobuf::MessageLite>()));
437 WaitForMCSEvent();
439 // Reconnect and ensure no messages are resent.
440 StoreCredentials();
441 BuildMCSClient();
442 InitializeClient();
443 LoginClient(std::vector<std::string>());
444 PumpLoop();
447 // Send messages with RMQ support. On restart, receive a SelectiveAck with
448 // the login response. No messages should be resent.
449 TEST_F(MCSClientTest, SendMessageRMQAckOnReconnect) {
450 BuildMCSClient();
451 InitializeClient();
452 LoginClient(std::vector<std::string>());
454 // Send some messages.
455 std::vector<std::string> id_list;
456 for (int i = 1; i <= kMessageBatchSize; ++i) {
457 id_list.push_back(base::IntToString(i));
458 MCSMessage message(BuildDataMessage("from",
459 "category",
460 id_list.back(),
462 id_list.back(),
463 kTTLValue,
467 0));
468 GetFakeHandler()->ExpectOutgoingMessage(message);
469 mcs_client()->SendMessage(message);
470 PumpLoop();
472 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
474 // Rebuild the client, and receive an acknowledgment for the messages as
475 // part of the login response.
476 StoreCredentials();
477 BuildMCSClient();
478 InitializeClient();
479 LoginClient(std::vector<std::string>());
480 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(id_list));
481 GetFakeHandler()->ReceiveMessage(
482 MCSMessage(kIqStanzaTag,
483 ack.PassAs<const google::protobuf::MessageLite>()));
484 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
487 // Send messages with RMQ support. On restart, receive a SelectiveAck with
488 // the login response that only acks some messages. The unacked messages should
489 // be resent.
490 TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) {
491 BuildMCSClient();
492 InitializeClient();
493 LoginClient(std::vector<std::string>());
495 // Send some messages.
496 std::vector<std::string> id_list;
497 for (int i = 1; i <= kMessageBatchSize; ++i) {
498 id_list.push_back(base::IntToString(i));
499 MCSMessage message(BuildDataMessage("from",
500 "category",
501 id_list.back(),
503 id_list.back(),
504 kTTLValue,
508 0));
509 GetFakeHandler()->ExpectOutgoingMessage(message);
510 mcs_client()->SendMessage(message);
511 PumpLoop();
513 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
515 // Rebuild the client, and receive an acknowledgment for the messages as
516 // part of the login response.
517 StoreCredentials();
518 BuildMCSClient();
519 InitializeClient();
520 LoginClient(std::vector<std::string>());
522 std::vector<std::string> acked_ids, remaining_ids;
523 acked_ids.insert(acked_ids.end(),
524 id_list.begin(),
525 id_list.begin() + kMessageBatchSize / 2);
526 remaining_ids.insert(remaining_ids.end(),
527 id_list.begin() + kMessageBatchSize / 2,
528 id_list.end());
529 for (int i = 1; i <= kMessageBatchSize / 2; ++i) {
530 MCSMessage message(BuildDataMessage("from",
531 "category",
532 remaining_ids[i - 1],
534 remaining_ids[i - 1],
535 kTTLValue,
539 0));
540 GetFakeHandler()->ExpectOutgoingMessage(message);
542 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
543 GetFakeHandler()->ReceiveMessage(
544 MCSMessage(kIqStanzaTag,
545 ack.PassAs<const google::protobuf::MessageLite>()));
546 WaitForMCSEvent();
547 PumpLoop();
548 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
551 // Receive some messages. On restart, the login request should contain the
552 // appropriate acknowledged ids.
553 TEST_F(MCSClientTest, AckOnLogin) {
554 BuildMCSClient();
555 InitializeClient();
556 LoginClient(std::vector<std::string>());
558 // Receive some messages.
559 std::vector<std::string> id_list;
560 for (int i = 1; i <= kMessageBatchSize; ++i) {
561 id_list.push_back(base::IntToString(i));
562 MCSMessage message(BuildDataMessage(
563 "from", "category", "X", 1, id_list.back(), kTTLValue, 1, 0, "", 0));
564 GetFakeHandler()->ReceiveMessage(message);
565 WaitForMCSEvent();
566 PumpLoop();
569 // Restart the client.
570 StoreCredentials();
571 BuildMCSClient();
572 InitializeClient();
573 LoginClient(id_list);
576 // Receive some messages. On the next send, the outgoing message should contain
577 // the appropriate last stream id received field to ack the received messages.
578 TEST_F(MCSClientTest, AckOnSend) {
579 BuildMCSClient();
580 InitializeClient();
581 LoginClient(std::vector<std::string>());
583 // Receive some messages.
584 std::vector<std::string> id_list;
585 for (int i = 1; i <= kMessageBatchSize; ++i) {
586 id_list.push_back(base::IntToString(i));
587 MCSMessage message(BuildDataMessage("from",
588 "category",
589 id_list.back(),
591 id_list.back(),
592 kTTLValue,
596 0));
597 GetFakeHandler()->ReceiveMessage(message);
598 PumpLoop();
601 // Trigger a message send, which should acknowledge via stream ack.
602 MCSMessage message(BuildDataMessage("from",
603 "category",
604 "X",
605 kMessageBatchSize + 1,
606 "1",
607 kTTLValue,
611 0));
612 GetFakeHandler()->ExpectOutgoingMessage(message);
613 mcs_client()->SendMessage(message);
614 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
617 // Receive the ack limit in messages, which should trigger an automatic
618 // stream ack. Receive a heartbeat to confirm the ack.
619 TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) {
620 BuildMCSClient();
621 InitializeClient();
622 LoginClient(std::vector<std::string>());
624 // The stream ack.
625 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
626 ack->set_last_stream_id_received(kAckLimitSize + 1);
627 GetFakeHandler()->ExpectOutgoingMessage(
628 MCSMessage(kIqStanzaTag,
629 ack.PassAs<const google::protobuf::MessageLite>()));
631 // Receive some messages.
632 std::vector<std::string> id_list;
633 for (int i = 1; i <= kAckLimitSize; ++i) {
634 id_list.push_back(base::IntToString(i));
635 MCSMessage message(BuildDataMessage("from",
636 "category",
637 id_list.back(),
639 id_list.back(),
640 kTTLValue,
644 0));
645 GetFakeHandler()->ReceiveMessage(message);
646 WaitForMCSEvent();
647 PumpLoop();
649 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
651 // Receive a heartbeat confirming the ack (and receive the heartbeat ack).
652 scoped_ptr<mcs_proto::HeartbeatPing> heartbeat(
653 new mcs_proto::HeartbeatPing());
654 heartbeat->set_last_stream_id_received(2);
656 scoped_ptr<mcs_proto::HeartbeatAck> heartbeat_ack(
657 new mcs_proto::HeartbeatAck());
658 heartbeat_ack->set_last_stream_id_received(kAckLimitSize + 2);
659 GetFakeHandler()->ExpectOutgoingMessage(
660 MCSMessage(kHeartbeatAckTag,
661 heartbeat_ack.PassAs<const google::protobuf::MessageLite>()));
663 GetFakeHandler()->ReceiveMessage(
664 MCSMessage(kHeartbeatPingTag,
665 heartbeat.PassAs<const google::protobuf::MessageLite>()));
666 PumpLoop();
667 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
669 // Rebuild the client. Nothing should be sent on login.
670 StoreCredentials();
671 BuildMCSClient();
672 InitializeClient();
673 LoginClient(std::vector<std::string>());
674 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
677 // If a message's TTL has expired by the time it reaches the front of the send
678 // queue, it should be dropped.
679 TEST_F(MCSClientTest, ExpiredTTLOnSend) {
680 BuildMCSClient();
681 InitializeClient();
682 LoginClient(std::vector<std::string>());
683 MCSMessage message(BuildDataMessage(
684 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
686 // Advance time to after the TTL.
687 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 2));
688 EXPECT_TRUE(sent_message_id().empty());
689 mcs_client()->SendMessage(message);
691 // No messages should be sent, but the callback should still be invoked.
692 EXPECT_EQ("X", sent_message_id());
693 EXPECT_EQ(MCSClient::TTL_EXCEEDED, message_send_status());
694 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
697 TEST_F(MCSClientTest, ExpiredTTLOnRestart) {
698 BuildMCSClient();
699 InitializeClient();
700 LoginClient(std::vector<std::string>());
701 GetFakeHandler()->set_fail_send(true);
702 MCSMessage message(BuildDataMessage(
703 "from", "category", "X", 1, "1", kTTLValue, 1, 0, "", 0));
705 // The initial (failed) send.
706 GetFakeHandler()->ExpectOutgoingMessage(message);
707 GetFakeHandler()->set_fail_send(false);
708 mcs_client()->SendMessage(message);
709 PumpLoop();
710 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
712 // Move the clock forward and rebuild the client, which should fail the
713 // message send on restart.
714 clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue + 2));
715 StoreCredentials();
716 BuildMCSClient();
717 InitializeClient();
718 LoginClient(std::vector<std::string>());
719 PumpLoop();
720 EXPECT_EQ("X", sent_message_id());
721 EXPECT_EQ(MCSClient::TTL_EXCEEDED, message_send_status());
722 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
725 // Sending two messages with the same collapse key and same app id while
726 // disconnected should only send the latter of the two on reconnection.
727 TEST_F(MCSClientTest, CollapseKeysSameApp) {
728 BuildMCSClient();
729 InitializeClient();
730 MCSMessage message(BuildDataMessage(
731 "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
732 mcs_client()->SendMessage(message);
734 MCSMessage message2(BuildDataMessage(
735 "from", "app", "message id 2", 1, "1", kTTLValue, 1, 0, "token", 0));
736 mcs_client()->SendMessage(message2);
738 LoginClient(std::vector<std::string>());
739 GetFakeHandler()->ExpectOutgoingMessage(message2);
740 PumpLoop();
743 // Sending two messages with the same collapse key and different app id while
744 // disconnected should not perform any collapsing.
745 TEST_F(MCSClientTest, CollapseKeysDifferentApp) {
746 BuildMCSClient();
747 InitializeClient();
748 MCSMessage message(BuildDataMessage(
749 "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
750 mcs_client()->SendMessage(message);
752 MCSMessage message2(BuildDataMessage("from",
753 "app 2",
754 "message id 2",
756 "2",
757 kTTLValue,
760 "token",
761 0));
762 mcs_client()->SendMessage(message2);
764 LoginClient(std::vector<std::string>());
765 GetFakeHandler()->ExpectOutgoingMessage(message);
766 GetFakeHandler()->ExpectOutgoingMessage(message2);
767 PumpLoop();
770 // Sending two messages with the same collapse key and app id, but different
771 // user, while disconnected, should not perform any collapsing.
772 TEST_F(MCSClientTest, CollapseKeysDifferentUser) {
773 BuildMCSClient();
774 InitializeClient();
775 MCSMessage message(BuildDataMessage(
776 "from", "app", "message id 1", 1, "1", kTTLValue, 1, 0, "token", 0));
777 mcs_client()->SendMessage(message);
779 MCSMessage message2(BuildDataMessage("from",
780 "app",
781 "message id 2",
783 "2",
784 kTTLValue,
787 "token",
788 1));
789 mcs_client()->SendMessage(message2);
791 LoginClient(std::vector<std::string>());
792 GetFakeHandler()->ExpectOutgoingMessage(message);
793 GetFakeHandler()->ExpectOutgoingMessage(message2);
794 PumpLoop();
797 } // namespace
799 } // namespace gcm