Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / google_apis / gcm / engine / mcs_client_unittest.cc
index da88f26..522ce45 100644 (file)
@@ -4,16 +4,22 @@
 
 #include "google_apis/gcm/engine/mcs_client.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/simple_test_clock.h"
-#include "components/webdata/encryptor/encryptor.h"
+#include "base/timer/timer.h"
+#include "google_apis/gcm/base/fake_encryptor.h"
 #include "google_apis/gcm/base/mcs_util.h"
 #include "google_apis/gcm/engine/fake_connection_factory.h"
 #include "google_apis/gcm/engine/fake_connection_handler.h"
 #include "google_apis/gcm/engine/gcm_store_impl.h"
+#include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gcm {
@@ -66,12 +72,14 @@ class TestMCSClient : public MCSClient {
  public:
   TestMCSClient(base::Clock* clock,
                 ConnectionFactory* connection_factory,
-                GCMStore* gcm_store)
-    : MCSClient("", clock, connection_factory, gcm_store),
+                GCMStore* gcm_store,
+                gcm::GCMStatsRecorder* recorder)
+    : MCSClient("", clock, connection_factory, gcm_store, recorder,
+                make_scoped_ptr(new base::Timer(true, false))),
       next_id_(0) {
   }
 
-  virtual std::string GetNextPersistentId() OVERRIDE {
+  std::string GetNextPersistentId() override {
     return base::UintToString(++next_id_);
   }
 
@@ -84,6 +92,8 @@ class MCSClientTest : public testing::Test {
   MCSClientTest();
   virtual ~MCSClientTest();
 
+  virtual void SetUp() override;
+
   void BuildMCSClient();
   void InitializeClient();
   void StoreCredentials();
@@ -133,6 +143,8 @@ class MCSClientTest : public testing::Test {
   scoped_ptr<MCSMessage> received_message_;
   std::string sent_message_id_;
   MCSClient::MessageSendStatus message_send_status_;
+
+  gcm::FakeGCMStatsRecorder recorder_;
 };
 
 MCSClientTest::MCSClientTest()
@@ -144,24 +156,25 @@ MCSClientTest::MCSClientTest()
   EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
   run_loop_.reset(new base::RunLoop());
 
-  // On OSX, prevent the Keychain permissions popup during unit tests.
-#if defined(OS_MACOSX)
-  Encryptor::UseMockKeychain(true);
-#endif
-
   // Advance the clock to a non-zero time.
   clock_.Advance(base::TimeDelta::FromSeconds(1));
 }
 
 MCSClientTest::~MCSClientTest() {}
 
+void MCSClientTest::SetUp() {
+  testing::Test::SetUp();
+}
+
 void MCSClientTest::BuildMCSClient() {
-  gcm_store_.reset(new GCMStoreImpl(true,
-                                    temp_directory_.path(),
-                                    message_loop_.message_loop_proxy()));
+  gcm_store_.reset(new GCMStoreImpl(
+      temp_directory_.path(),
+      message_loop_.message_loop_proxy(),
+      make_scoped_ptr<Encryptor>(new FakeEncryptor)));
   mcs_client_.reset(new TestMCSClient(&clock_,
                                       &connection_factory_,
-                                      gcm_store_.get()));
+                                      gcm_store_.get(),
+                                      &recorder_));
 }
 
 void MCSClientTest::InitializeClient() {
@@ -184,8 +197,7 @@ void MCSClientTest::LoginClient(
   for (size_t i = 0; i < acknowledged_ids.size(); ++i)
     login_request->add_received_persistent_id(acknowledged_ids[i]);
   GetFakeHandler()->ExpectOutgoingMessage(
-      MCSMessage(kLoginRequestTag,
-                 login_request.PassAs<const google::protobuf::MessageLite>()));
+      MCSMessage(kLoginRequestTag, login_request.Pass()));
   mcs_client_->Login(kAndroidId, kSecurityToken);
   run_loop_->Run();
   run_loop_.reset(new base::RunLoop());
@@ -343,11 +355,8 @@ TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
   // The initial (failed) send.
   GetFakeHandler()->ExpectOutgoingMessage(message);
   // The login request.
-  GetFakeHandler()->ExpectOutgoingMessage(
-      MCSMessage(
-          kLoginRequestTag,
-          BuildLoginRequest(kAndroidId, kSecurityToken, "").
-              PassAs<const google::protobuf::MessageLite>()));
+  GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(
+      kLoginRequestTag, BuildLoginRequest(kAndroidId, kSecurityToken, "")));
   // The second (re)send.
   MCSMessage message2(BuildDataMessage(
       "from", "category", "X", 1, "1", kTTLValue, 1, kTTLValue - 1, "", 0));
@@ -355,12 +364,22 @@ TEST_F(MCSClientTest, SendMessageRMQWhileDisconnected) {
   mcs_client()->SendMessage(message);
   PumpLoop();         // Wait for the queuing to happen.
   EXPECT_EQ(MCSClient::QUEUED, message_send_status());
+  EXPECT_EQ("X", sent_message_id());
   EXPECT_FALSE(GetFakeHandler()->AllOutgoingMessagesReceived());
   GetFakeHandler()->set_fail_send(false);
   clock()->Advance(base::TimeDelta::FromSeconds(kTTLValue - 1));
   connection_factory()->Connect();
   WaitForMCSEvent();  // Wait for the login to finish.
   PumpLoop();         // Wait for the send to happen.
+
+  // Receive the ack.
+  scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
+  ack->set_last_stream_id_received(2);
+  GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
+  WaitForMCSEvent();
+
+  EXPECT_EQ(MCSClient::SENT, message_send_status());
+  EXPECT_EQ("X", sent_message_id());
   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
 }
 
@@ -423,9 +442,7 @@ TEST_F(MCSClientTest, SendMessageRMQWithStreamAck) {
   // Receive the ack.
   scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
   ack->set_last_stream_id_received(kMessageBatchSize + 1);
-  GetFakeHandler()->ReceiveMessage(
-      MCSMessage(kIqStanzaTag,
-                 ack.PassAs<const google::protobuf::MessageLite>()));
+  GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
   WaitForMCSEvent();
 
   // Reconnect and ensure no messages are resent.
@@ -470,9 +487,7 @@ TEST_F(MCSClientTest, SendMessageRMQAckOnReconnect) {
   InitializeClient();
   LoginClient(std::vector<std::string>());
   scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(id_list));
-  GetFakeHandler()->ReceiveMessage(
-      MCSMessage(kIqStanzaTag,
-                 ack.PassAs<const google::protobuf::MessageLite>()));
+  GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
 }
 
@@ -532,14 +547,87 @@ TEST_F(MCSClientTest, SendMessageRMQPartialAckOnReconnect) {
     GetFakeHandler()->ExpectOutgoingMessage(message);
   }
   scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
-  GetFakeHandler()->ReceiveMessage(
-      MCSMessage(kIqStanzaTag,
-                 ack.PassAs<const google::protobuf::MessageLite>()));
+  GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
   WaitForMCSEvent();
   PumpLoop();
   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
 }
 
+// Handle a selective ack that only acks some messages. The remaining unacked
+// messages should be resent. On restart, those same unacked messages should be
+// resent, and any pending acks for incoming messages should also be resent.
+TEST_F(MCSClientTest, SelectiveAckMidStream) {
+  BuildMCSClient();
+  InitializeClient();
+  LoginClient(std::vector<std::string>());
+
+  // Server stream id 2 ("s1").
+  // Acks client stream id 0 (login).
+  MCSMessage sMessage1(BuildDataMessage(
+      "from", "category", "X", 0, "s1", kTTLValue, 1, 0, "", 0));
+  GetFakeHandler()->ReceiveMessage(sMessage1);
+  WaitForMCSEvent();
+  PumpLoop();
+
+  // Client stream id 1 ("1").
+  // Acks server stream id 2 ("s1").
+  MCSMessage cMessage1(BuildDataMessage(
+      "from", "category", "Y", 2, "1", kTTLValue, 1, 0, "", 0));
+  GetFakeHandler()->ExpectOutgoingMessage(cMessage1);
+  mcs_client()->SendMessage(cMessage1);
+  PumpLoop();
+  EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
+
+  // Server stream id 3 ("s2").
+  // Acks client stream id 1 ("1").
+  // Confirms ack of server stream id 2 ("s1").
+  MCSMessage sMessage2(BuildDataMessage(
+      "from", "category", "X", 1, "s2", kTTLValue, 1, 0, "", 0));
+  GetFakeHandler()->ReceiveMessage(sMessage2);
+  WaitForMCSEvent();
+  PumpLoop();
+
+  // Client Stream id 2 ("2").
+  // Acks server stream id 3 ("s2").
+  MCSMessage cMessage2(BuildDataMessage(
+      "from", "category", "Y", 3, "2", kTTLValue, 1, 0, "", 0));
+  GetFakeHandler()->ExpectOutgoingMessage(cMessage2);
+  mcs_client()->SendMessage(cMessage2);
+  PumpLoop();
+  EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
+
+  // Simulate the last message being dropped by having the server selectively
+  // ack client message "1".
+  // Client message "2" should be resent, acking server stream id 4 (selective
+  // ack).
+  MCSMessage cMessage3(BuildDataMessage(
+      "from", "category", "Y", 4, "2", kTTLValue, 1, 0, "", 0));
+  GetFakeHandler()->ExpectOutgoingMessage(cMessage3);
+  std::vector<std::string> acked_ids(1, "1");
+  scoped_ptr<mcs_proto::IqStanza> ack(BuildSelectiveAck(acked_ids));
+  GetFakeHandler()->ReceiveMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
+  WaitForMCSEvent();
+  PumpLoop();
+  EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
+
+  // Rebuild the client without any further acks from server. Note that this
+  // resets the stream ids.
+  // Sever message "s2" should be acked as part of login.
+  // Client message "2" should be resent.
+  StoreCredentials();
+  BuildMCSClient();
+  InitializeClient();
+
+  acked_ids[0] = "s2";
+  LoginClient(acked_ids);
+
+  MCSMessage cMessage4(BuildDataMessage(
+      "from", "category", "Y", 1, "2", kTTLValue, 1, 0, "", 0));
+  GetFakeHandler()->ExpectOutgoingMessage(cMessage4);
+  PumpLoop();
+  EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());
+}
+
 // Receive some messages. On restart, the login request should contain the
 // appropriate acknowledged ids.
 TEST_F(MCSClientTest, AckOnLogin) {
@@ -616,9 +704,7 @@ TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) {
   // The stream ack.
   scoped_ptr<mcs_proto::IqStanza> ack = BuildStreamAck();
   ack->set_last_stream_id_received(kAckLimitSize + 1);
-  GetFakeHandler()->ExpectOutgoingMessage(
-      MCSMessage(kIqStanzaTag,
-                 ack.PassAs<const google::protobuf::MessageLite>()));
+  GetFakeHandler()->ExpectOutgoingMessage(MCSMessage(kIqStanzaTag, ack.Pass()));
 
   // Receive some messages.
   std::vector<std::string> id_list;
@@ -649,12 +735,10 @@ TEST_F(MCSClientTest, AckWhenLimitReachedWithHeartbeat) {
       new mcs_proto::HeartbeatAck());
   heartbeat_ack->set_last_stream_id_received(kAckLimitSize + 2);
   GetFakeHandler()->ExpectOutgoingMessage(
-      MCSMessage(kHeartbeatAckTag,
-                 heartbeat_ack.PassAs<const google::protobuf::MessageLite>()));
+      MCSMessage(kHeartbeatAckTag, heartbeat_ack.Pass()));
 
   GetFakeHandler()->ReceiveMessage(
-      MCSMessage(kHeartbeatPingTag,
-                 heartbeat.PassAs<const google::protobuf::MessageLite>()));
+      MCSMessage(kHeartbeatPingTag, heartbeat.Pass()));
   PumpLoop();
   EXPECT_TRUE(GetFakeHandler()->AllOutgoingMessagesReceived());