Re-land: C++ readability review
[chromium-blink-merge.git] / google_apis / gcm / engine / mcs_client_unittest.cc
blobf0952c1747e0a029f0e3d9ad60356ef2231c86ac
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/bind.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"
25 namespace gcm {
27 namespace {
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
37 // stream ack.
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,
50 int ttl,
51 uint64 sent,
52 int queued,
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 {
72 public:
73 TestMCSClient(base::Clock* clock,
74 ConnectionFactory* connection_factory,
75 GCMStore* gcm_store,
76 gcm::GCMStatsRecorder* recorder)
77 : MCSClient("", clock, connection_factory, gcm_store, recorder),
78 next_id_(0) {
81 std::string GetNextPersistentId() override {
82 return base::UintToString(++next_id_);
85 private:
86 uint32 next_id_;
89 class MCSClientTest : public testing::Test {
90 public:
91 MCSClientTest();
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();
120 void PumpLoop();
122 private:
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_;
139 bool init_success_;
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()),
151 init_success_(true),
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_,
175 gcm_store_.get(),
176 &recorder_));
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);
201 run_loop_->Run();
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)));
210 run_loop_->Run();
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() {
220 run_loop_->Run();
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.";
232 run_loop_->Quit();
235 void MCSClientTest::MessageReceivedCallback(const MCSMessage& message) {
236 received_message_.reset(new MCSMessage(message));
237 DVLOG(1) << "Message received callback invoked, killing loop.";
238 run_loop_->Quit();
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;
248 run_loop_->Quit();
251 void MCSClientTest::SetDeviceCredentialsCallback(bool success) {
252 ASSERT_TRUE(success);
253 run_loop_->Quit();
256 // Initialize a new client.
257 TEST_F(MCSClientTest, InitializeNew) {
258 BuildMCSClient();
259 InitializeClient();
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) {
266 BuildMCSClient();
267 InitializeClient();
268 LoginClient(std::vector<std::string>());
270 // Rebuild the client, to reload from the GCM store.
271 StoreCredentials();
272 BuildMCSClient();
273 InitializeClient();
274 EXPECT_TRUE(init_success());
277 // Log in successfully to the MCS endpoint.
278 TEST_F(MCSClientTest, LoginSuccess) {
279 BuildMCSClient();
280 InitializeClient();
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
289 // reconnect.
290 TEST_F(MCSClientTest, FailLogin) {
291 BuildMCSClient();
292 InitializeClient();
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) {
304 BuildMCSClient();
305 InitializeClient();
306 LoginClient(std::vector<std::string>());
307 MCSMessage message(
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) {
317 BuildMCSClient();
318 InitializeClient();
320 EXPECT_TRUE(sent_message_id().empty());
321 MCSMessage message(
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
326 // be sent.
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) {
334 BuildMCSClient();
335 InitializeClient();
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
345 // should be resent.
346 TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
347 BuildMCSClient();
348 InitializeClient();
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.
374 // Receive the ack.
375 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
376 ack->set_last_stream_id_received(2);
377 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
378 WaitForMCSEvent();
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) {
388 BuildMCSClient();
389 InitializeClient();
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);
399 PumpLoop();
400 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
402 // Rebuild the client, which should resend the old message.
403 StoreCredentials();
404 BuildMCSClient();
405 InitializeClient();
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);
412 PumpLoop();
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) {
419 BuildMCSClient();
420 InitializeClient();
421 LoginClient(std::vector<std::string>());
423 // Send some messages.
424 for (int i = 1; i <= kMessageBatchSize; ++i) {
425 MCSMessage message(BuildDataMessage("from",
426 "category",
427 "X",
429 base::IntToString(i),
430 kTTLValue,
434 0));
435 GetFakeHandler()->ExpectOutgoingMessage(message);
436 mcs_client()->SendMessage(message);
437 PumpLoop();
439 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
441 // Receive the ack.
442 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
443 ack->set_last_stream_id_received(kMessageBatchSize + 1);
444 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
445 WaitForMCSEvent();
447 // Reconnect and ensure no messages are resent.
448 StoreCredentials();
449 BuildMCSClient();
450 InitializeClient();
451 LoginClient(std::vector<std::string>());
452 PumpLoop();
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) {
458 BuildMCSClient();
459 InitializeClient();
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",
467 "category",
468 id_list.back(),
470 id_list.back(),
471 kTTLValue,
475 0));
476 GetFakeHandler()->ExpectOutgoingMessage(message);
477 mcs_client()->SendMessage(message);
478 PumpLoop();
480 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
482 // Rebuild the client, and receive an acknowledgment for the messages as
483 // part of the login response.
484 StoreCredentials();
485 BuildMCSClient();
486 InitializeClient();
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
495 // be resent.
496 TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) {
497 BuildMCSClient();
498 InitializeClient();
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",
506 "category",
507 id_list.back(),
509 id_list.back(),
510 kTTLValue,
514 0));
515 GetFakeHandler()->ExpectOutgoingMessage(message);
516 mcs_client()->SendMessage(message);
517 PumpLoop();
519 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
521 // Rebuild the client, and receive an acknowledgment for the messages as
522 // part of the login response.
523 StoreCredentials();
524 BuildMCSClient();
525 InitializeClient();
526 LoginClient(std::vector<std::string>());
528 std::vector<std::string> acked_ids, remaining_ids;
529 acked_ids.insert(acked_ids.end(),
530 id_list.begin(),
531 id_list.begin() + kMessageBatchSize / 2);
532 remaining_ids.insert(remaining_ids.end(),
533 id_list.begin() + kMessageBatchSize / 2,
534 id_list.end());
535 for (int i = 1; i <= kMessageBatchSize / 2; ++i) {
536 MCSMessage message(BuildDataMessage("from",
537 "category",
538 remaining_ids[i - 1],
540 remaining_ids[i - 1],
541 kTTLValue,
545 0));
546 GetFakeHandler()->ExpectOutgoingMessage(message);
548 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
549 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
550 WaitForMCSEvent();
551 PumpLoop();
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) {
559 BuildMCSClient();
560 InitializeClient();
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);
568 WaitForMCSEvent();
569 PumpLoop();
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);
577 PumpLoop();
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);
586 WaitForMCSEvent();
587 PumpLoop();
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);
595 PumpLoop();
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
601 // ack).
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()));
608 WaitForMCSEvent();
609 PumpLoop();
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.
616 StoreCredentials();
617 BuildMCSClient();
618 InitializeClient();
620 acked_ids[0] = "s2";
621 LoginClient(acked_ids);
623 MCSMessage cMessage4(BuildDataMessage(
624 "from", "category", "Y", 1, "2", kTTLValue, 1, 0, "", 0));
625 GetFakeHandler()->ExpectOutgoingMessage(cMessage4);
626 PumpLoop();
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) {
633 BuildMCSClient();
634 InitializeClient();
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);
644 WaitForMCSEvent();
645 PumpLoop();
648 // Restart the client.
649 StoreCredentials();
650 BuildMCSClient();
651 InitializeClient();
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) {
658 BuildMCSClient();
659 InitializeClient();
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",
667 "category",
668 id_list.back(),
670 id_list.back(),
671 kTTLValue,
675 0));
676 GetFakeHandler()->ReceiveMessage(message);
677 PumpLoop();
680 // Trigger a message send, which should acknowledge via stream ack.
681 MCSMessage message(BuildDataMessage("from",
682 "category",
683 "X",
684 kMessageBatchSize + 1,
685 "1",
686 kTTLValue,
690 0));
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) {
699 BuildMCSClient();
700 InitializeClient();
701 LoginClient(std::vector<std::string>());
703 // The stream ack.
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",
713 "category",
714 id_list.back(),
716 id_list.back(),
717 kTTLValue,
721 0));
722 GetFakeHandler()->ReceiveMessage(message);
723 WaitForMCSEvent();
724 PumpLoop();
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()));
741 PumpLoop();
742 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
744 // Rebuild the client. Nothing should be sent on login.
745 StoreCredentials();
746 BuildMCSClient();
747 InitializeClient();
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) {
755 BuildMCSClient();
756 InitializeClient();
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) {
773 BuildMCSClient();
774 InitializeClient();
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);
784 PumpLoop();
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));
790 StoreCredentials();
791 BuildMCSClient();
792 InitializeClient();
793 LoginClient(std::vector<std::string>());
794 PumpLoop();
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) {
803 BuildMCSClient();
804 InitializeClient();
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);
815 PumpLoop();
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) {
821 BuildMCSClient();
822 InitializeClient();
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",
828 "app 2",
829 "message id 2",
831 "2",
832 kTTLValue,
835 "token",
836 0));
837 mcs_client()->SendMessage(message2);
839 LoginClient(std::vector<std::string>());
840 GetFakeHandler()->ExpectOutgoingMessage(message);
841 GetFakeHandler()->ExpectOutgoingMessage(message2);
842 PumpLoop();
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) {
848 BuildMCSClient();
849 InitializeClient();
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",
855 "app",
856 "message id 2",
858 "2",
859 kTTLValue,
862 "token",
863 1));
864 mcs_client()->SendMessage(message2);
866 LoginClient(std::vector<std::string>());
867 GetFakeHandler()->ExpectOutgoingMessage(message);
868 GetFakeHandler()->ExpectOutgoingMessage(message2);
869 PumpLoop();
872 } // namespace
874 } // namespace gcm