Add ICU message format support
[chromium-blink-merge.git] / google_apis / gcm / engine / mcs_client_unittest.cc
blob6c7ea721de66d15edf94c9973b03b0f6df695314
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 TestConnectionListener : public ConnectionFactory::ConnectionListener {
90 public:
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_; }
101 private:
102 int disconnect_counter_;
105 class MCSClientTest : public testing::Test {
106 public:
107 MCSClientTest();
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();
141 void PumpLoop();
143 private:
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_;
160 bool init_success_;
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()),
172 init_success_(true),
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_,
196 gcm_store_.get(),
197 &recorder_));
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);
223 run_loop_->Run();
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)));
248 run_loop_->Run();
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() {
258 run_loop_->Run();
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.";
270 run_loop_->Quit();
273 void MCSClientTest::MessageReceivedCallback(const MCSMessage& message) {
274 received_message_.reset(new MCSMessage(message));
275 DVLOG(1) << "Message received callback invoked, killing loop.";
276 run_loop_->Quit();
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;
286 run_loop_->Quit();
289 void MCSClientTest::SetDeviceCredentialsCallback(bool success) {
290 ASSERT_TRUE(success);
291 run_loop_->Quit();
294 // Initialize a new client.
295 TEST_F(MCSClientTest, InitializeNew) {
296 BuildMCSClient();
297 InitializeClient();
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) {
304 BuildMCSClient();
305 InitializeClient();
306 LoginClient(std::vector<std::string>());
308 // Rebuild the client, to reload from the GCM store.
309 StoreCredentials();
310 BuildMCSClient();
311 InitializeClient();
312 EXPECT_TRUE(init_success());
315 // Log in successfully to the MCS endpoint.
316 TEST_F(MCSClientTest, LoginSuccess) {
317 BuildMCSClient();
318 InitializeClient();
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
327 // reconnect.
328 TEST_F(MCSClientTest, FailLogin) {
329 BuildMCSClient();
330 InitializeClient();
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) {
342 BuildMCSClient();
343 InitializeClient();
344 LoginClient(std::vector<std::string>());
345 MCSMessage message(
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) {
355 BuildMCSClient();
356 InitializeClient();
358 EXPECT_TRUE(sent_message_id().empty());
359 MCSMessage message(
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
364 // be sent.
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) {
372 BuildMCSClient();
373 InitializeClient();
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
383 // should be resent.
384 TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
385 BuildMCSClient();
386 InitializeClient();
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.
412 // Receive the ack.
413 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
414 ack->set_last_stream_id_received(2);
415 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
416 WaitForMCSEvent();
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) {
426 BuildMCSClient();
427 InitializeClient();
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);
437 PumpLoop();
438 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
440 // Rebuild the client, which should resend the old message.
441 StoreCredentials();
442 BuildMCSClient();
443 InitializeClient();
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);
450 PumpLoop();
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) {
457 BuildMCSClient();
458 InitializeClient();
459 LoginClient(std::vector<std::string>());
461 // Send some messages.
462 for (int i = 1; i <= kMessageBatchSize; ++i) {
463 MCSMessage message(BuildDataMessage("from",
464 "category",
465 "X",
467 base::IntToString(i),
468 kTTLValue,
472 0));
473 GetFakeHandler()->ExpectOutgoingMessage(message);
474 mcs_client()->SendMessage(message);
475 PumpLoop();
477 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
479 // Receive the ack.
480 scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
481 ack->set_last_stream_id_received(kMessageBatchSize + 1);
482 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
483 WaitForMCSEvent();
485 // Reconnect and ensure no messages are resent.
486 StoreCredentials();
487 BuildMCSClient();
488 InitializeClient();
489 LoginClient(std::vector<std::string>());
490 PumpLoop();
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) {
496 BuildMCSClient();
497 InitializeClient();
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",
505 "category",
506 id_list.back(),
508 id_list.back(),
509 kTTLValue,
513 0));
514 GetFakeHandler()->ExpectOutgoingMessage(message);
515 mcs_client()->SendMessage(message);
516 PumpLoop();
518 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
520 // Rebuild the client, and receive an acknowledgment for the messages as
521 // part of the login response.
522 StoreCredentials();
523 BuildMCSClient();
524 InitializeClient();
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
533 // be resent.
534 TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) {
535 BuildMCSClient();
536 InitializeClient();
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",
544 "category",
545 id_list.back(),
547 id_list.back(),
548 kTTLValue,
552 0));
553 GetFakeHandler()->ExpectOutgoingMessage(message);
554 mcs_client()->SendMessage(message);
555 PumpLoop();
557 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
559 // Rebuild the client, and receive an acknowledgment for the messages as
560 // part of the login response.
561 StoreCredentials();
562 BuildMCSClient();
563 InitializeClient();
564 LoginClient(std::vector<std::string>());
566 std::vector<std::string> acked_ids, remaining_ids;
567 acked_ids.insert(acked_ids.end(),
568 id_list.begin(),
569 id_list.begin() + kMessageBatchSize / 2);
570 remaining_ids.insert(remaining_ids.end(),
571 id_list.begin() + kMessageBatchSize / 2,
572 id_list.end());
573 for (int i = 1; i <= kMessageBatchSize / 2; ++i) {
574 MCSMessage message(BuildDataMessage("from",
575 "category",
576 remaining_ids[i - 1],
578 remaining_ids[i - 1],
579 kTTLValue,
583 0));
584 GetFakeHandler()->ExpectOutgoingMessage(message);
586 scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
587 GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
588 WaitForMCSEvent();
589 PumpLoop();
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) {
597 BuildMCSClient();
598 InitializeClient();
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);
606 WaitForMCSEvent();
607 PumpLoop();
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);
615 PumpLoop();
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);
624 WaitForMCSEvent();
625 PumpLoop();
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);
633 PumpLoop();
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
639 // ack).
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()));
646 WaitForMCSEvent();
647 PumpLoop();
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.
654 StoreCredentials();
655 BuildMCSClient();
656 InitializeClient();
658 acked_ids[0] = "s2";
659 LoginClient(acked_ids);
661 MCSMessage cMessage4(BuildDataMessage(
662 "from", "category", "Y", 1, "2", kTTLValue, 1, 0, "", 0));
663 GetFakeHandler()->ExpectOutgoingMessage(cMessage4);
664 PumpLoop();
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) {
671 BuildMCSClient();
672 InitializeClient();
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);
682 WaitForMCSEvent();
683 PumpLoop();
686 // Restart the client.
687 StoreCredentials();
688 BuildMCSClient();
689 InitializeClient();
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) {
696 BuildMCSClient();
697 InitializeClient();
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",
705 "category",
706 id_list.back(),
708 id_list.back(),
709 kTTLValue,
713 0));
714 GetFakeHandler()->ReceiveMessage(message);
715 PumpLoop();
718 // Trigger a message send, which should acknowledge via stream ack.
719 MCSMessage message(BuildDataMessage("from",
720 "category",
721 "X",
722 kMessageBatchSize + 1,
723 "1",
724 kTTLValue,
728 0));
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) {
737 BuildMCSClient();
738 InitializeClient();
739 LoginClient(std::vector<std::string>());
741 // The stream ack.
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",
751 "category",
752 id_list.back(),
754 id_list.back(),
755 kTTLValue,
759 0));
760 GetFakeHandler()->ReceiveMessage(message);
761 WaitForMCSEvent();
762 PumpLoop();
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()));
779 PumpLoop();
780 EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
782 // Rebuild the client. Nothing should be sent on login.
783 StoreCredentials();
784 BuildMCSClient();
785 InitializeClient();
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) {
793 BuildMCSClient();
794 InitializeClient();
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) {
811 BuildMCSClient();
812 InitializeClient();
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);
822 PumpLoop();
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));
828 StoreCredentials();
829 BuildMCSClient();
830 InitializeClient();
831 LoginClient(std::vector<std::string>());
832 PumpLoop();
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) {
841 BuildMCSClient();
842 InitializeClient();
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);
853 PumpLoop();
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) {
859 BuildMCSClient();
860 InitializeClient();
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",
866 "app 2",
867 "message id 2",
869 "2",
870 kTTLValue,
873 "token",
874 0));
875 mcs_client()->SendMessage(message2);
877 LoginClient(std::vector<std::string>());
878 GetFakeHandler()->ExpectOutgoingMessage(message);
879 GetFakeHandler()->ExpectOutgoingMessage(message2);
880 PumpLoop();
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) {
886 BuildMCSClient();
887 InitializeClient();
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",
893 "app",
894 "message id 2",
896 "2",
897 kTTLValue,
900 "token",
901 1));
902 mcs_client()->SendMessage(message2);
904 LoginClient(std::vector<std::string>());
905 GetFakeHandler()->ExpectOutgoingMessage(message);
906 GetFakeHandler()->ExpectOutgoingMessage(message2);
907 PumpLoop();
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) {
913 BuildMCSClient();
914 InitializeClient();
915 LoginClient(std::vector<std::string>());
916 PumpLoop();
917 StoreCredentials();
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.
930 BuildMCSClient();
931 InitializeClient();
932 LoginClientWithHeartbeat(std::vector<std::string>(), 0);
933 PumpLoop();
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) {
942 BuildMCSClient();
943 InitializeClient();
944 LoginClient(std::vector<std::string>());
945 PumpLoop();
946 StoreCredentials();
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.
957 BuildMCSClient();
958 InitializeClient();
959 LoginClientWithHeartbeat(std::vector<std::string>(), 0);
960 PumpLoop();
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) {
970 BuildMCSClient();
971 InitializeClient();
972 LoginClient(std::vector<std::string>());
973 PumpLoop();
974 StoreCredentials();
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);
986 PumpLoop();
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.
994 BuildMCSClient();
995 InitializeClient();
996 LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms);
997 PumpLoop();
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);
1005 PumpLoop();
1007 // Check that setting was persisted and will take effect upon restart.
1008 BuildMCSClient();
1009 InitializeClient();
1010 LoginClientWithHeartbeat(std::vector<std::string>(), 0);
1011 PumpLoop();
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) {
1019 BuildMCSClient();
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);
1024 InitializeClient();
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) {
1033 BuildMCSClient();
1035 const std::string component_1 = "component1";
1036 int interval_ms = 5 * 60 * 1000; // 5 minutes. A valid setting.
1037 InitializeClient();
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) {
1047 BuildMCSClient();
1048 InitializeClient();
1049 LoginClient(std::vector<std::string>());
1050 PumpLoop();
1051 StoreCredentials();
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);
1063 PumpLoop();
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);
1068 PumpLoop();
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.
1076 BuildMCSClient();
1077 InitializeClient();
1078 LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms);
1079 PumpLoop();
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) {
1090 BuildMCSClient();
1091 InitializeClient();
1092 LoginClient(std::vector<std::string>());
1093 PumpLoop();
1094 StoreCredentials();
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);
1106 PumpLoop();
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);
1112 PumpLoop();
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.
1119 BuildMCSClient();
1120 InitializeClient();
1121 LoginClientWithHeartbeat(std::vector<std::string>(), other_interval_ms);
1122 PumpLoop();
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) {
1133 BuildMCSClient();
1134 InitializeClient();
1135 LoginClient(std::vector<std::string>());
1136 PumpLoop();
1137 StoreCredentials();
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);
1149 PumpLoop();
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);
1155 PumpLoop();
1157 mcs_client()->RemoveHeartbeatInterval(component_2);
1158 PumpLoop();
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.
1167 BuildMCSClient();
1168 InitializeClient();
1169 LoginClientWithHeartbeat(std::vector<std::string>(), interval_ms);
1170 PumpLoop();
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());
1178 } // namespace
1180 } // namespace gcm