Home | History | Annotate | Download | only in notifier
      1 // Copyright (c) 2012 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.
      4 
      5 #include "sync/notifier/sync_system_resources.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/callback.h"
     12 #include "base/message_loop/message_loop.h"
     13 
     14 #include "google/cacheinvalidation/include/types.h"
     15 #include "jingle/notifier/listener/fake_push_client.h"
     16 #include "sync/notifier/push_client_channel.h"
     17 #include "sync/notifier/state_writer.h"
     18 #include "testing/gmock/include/gmock/gmock.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace syncer {
     22 namespace {
     23 
     24 using ::testing::_;
     25 using ::testing::SaveArg;
     26 
     27 class MockStateWriter : public StateWriter {
     28  public:
     29   MOCK_METHOD1(WriteState, void(const std::string&));
     30 };
     31 
     32 class MockClosure {
     33  public:
     34   MOCK_CONST_METHOD0(Run, void(void));
     35   base::Closure* CreateClosure() {
     36     return new base::Closure(
     37         base::Bind(&MockClosure::Run, base::Unretained(this)));
     38   }
     39 };
     40 
     41 class MockStorageCallback {
     42  public:
     43   MOCK_CONST_METHOD1(Run, void(invalidation::Status));
     44   base::Callback<void(invalidation::Status)>* CreateCallback() {
     45     return new base::Callback<void(invalidation::Status)>(
     46         base::Bind(&MockStorageCallback::Run, base::Unretained(this)));
     47   }
     48 };
     49 
     50 class SyncSystemResourcesTest : public testing::Test {
     51  protected:
     52   SyncSystemResourcesTest()
     53       : push_client_channel_(
     54             scoped_ptr<notifier::PushClient>(new notifier::FakePushClient())),
     55         sync_system_resources_(&push_client_channel_, &mock_state_writer_) {}
     56 
     57   virtual ~SyncSystemResourcesTest() {}
     58 
     59   void ScheduleShouldNotRun() {
     60     {
     61       // Owned by ScheduleImmediately.
     62       MockClosure mock_closure;
     63       base::Closure* should_not_run = mock_closure.CreateClosure();
     64       EXPECT_CALL(mock_closure, Run()).Times(0);
     65       sync_system_resources_.internal_scheduler()->Schedule(
     66           invalidation::Scheduler::NoDelay(), should_not_run);
     67     }
     68     {
     69       // Owned by ScheduleOnListenerThread.
     70       MockClosure mock_closure;
     71       base::Closure* should_not_run = mock_closure.CreateClosure();
     72       EXPECT_CALL(mock_closure, Run()).Times(0);
     73       sync_system_resources_.listener_scheduler()->Schedule(
     74           invalidation::Scheduler::NoDelay(), should_not_run);
     75     }
     76     {
     77       // Owned by ScheduleWithDelay.
     78       MockClosure mock_closure;
     79       base::Closure* should_not_run = mock_closure.CreateClosure();
     80       EXPECT_CALL(mock_closure, Run()).Times(0);
     81       sync_system_resources_.internal_scheduler()->Schedule(
     82           invalidation::TimeDelta::FromSeconds(0), should_not_run);
     83     }
     84   }
     85 
     86   // Needed by |sync_system_resources_|.
     87   base::MessageLoop message_loop_;
     88   MockStateWriter mock_state_writer_;
     89   PushClientChannel push_client_channel_;
     90   SyncSystemResources sync_system_resources_;
     91 
     92  private:
     93   DISALLOW_COPY_AND_ASSIGN(SyncSystemResourcesTest);
     94 };
     95 
     96 // Make sure current_time() doesn't crash or leak.
     97 TEST_F(SyncSystemResourcesTest, CurrentTime) {
     98   invalidation::Time current_time =
     99       sync_system_resources_.internal_scheduler()->GetCurrentTime();
    100   DVLOG(1) << "current_time returned: " << current_time.ToInternalValue();
    101 }
    102 
    103 // Make sure Log() doesn't crash or leak.
    104 TEST_F(SyncSystemResourcesTest, Log) {
    105   sync_system_resources_.logger()->Log(SyncLogger::INFO_LEVEL,
    106                                          __FILE__, __LINE__, "%s %d",
    107                                          "test string", 5);
    108 }
    109 
    110 TEST_F(SyncSystemResourcesTest, ScheduleBeforeStart) {
    111   ScheduleShouldNotRun();
    112   sync_system_resources_.Start();
    113 }
    114 
    115 TEST_F(SyncSystemResourcesTest, ScheduleAfterStop) {
    116   sync_system_resources_.Start();
    117   sync_system_resources_.Stop();
    118   ScheduleShouldNotRun();
    119 }
    120 
    121 TEST_F(SyncSystemResourcesTest, ScheduleAndStop) {
    122   sync_system_resources_.Start();
    123   ScheduleShouldNotRun();
    124   sync_system_resources_.Stop();
    125 }
    126 
    127 TEST_F(SyncSystemResourcesTest, ScheduleAndDestroy) {
    128   sync_system_resources_.Start();
    129   ScheduleShouldNotRun();
    130 }
    131 
    132 TEST_F(SyncSystemResourcesTest, ScheduleImmediately) {
    133   sync_system_resources_.Start();
    134   MockClosure mock_closure;
    135   EXPECT_CALL(mock_closure, Run());
    136   sync_system_resources_.internal_scheduler()->Schedule(
    137       invalidation::Scheduler::NoDelay(), mock_closure.CreateClosure());
    138   message_loop_.RunUntilIdle();
    139 }
    140 
    141 TEST_F(SyncSystemResourcesTest, ScheduleOnListenerThread) {
    142   sync_system_resources_.Start();
    143   MockClosure mock_closure;
    144   EXPECT_CALL(mock_closure, Run());
    145   sync_system_resources_.listener_scheduler()->Schedule(
    146       invalidation::Scheduler::NoDelay(), mock_closure.CreateClosure());
    147   EXPECT_TRUE(
    148       sync_system_resources_.internal_scheduler()->IsRunningOnThread());
    149   message_loop_.RunUntilIdle();
    150 }
    151 
    152 TEST_F(SyncSystemResourcesTest, ScheduleWithZeroDelay) {
    153   sync_system_resources_.Start();
    154   MockClosure mock_closure;
    155   EXPECT_CALL(mock_closure, Run());
    156   sync_system_resources_.internal_scheduler()->Schedule(
    157       invalidation::TimeDelta::FromSeconds(0), mock_closure.CreateClosure());
    158   message_loop_.RunUntilIdle();
    159 }
    160 
    161 // TODO(akalin): Figure out how to test with a non-zero delay.
    162 
    163 TEST_F(SyncSystemResourcesTest, WriteState) {
    164   sync_system_resources_.Start();
    165   EXPECT_CALL(mock_state_writer_, WriteState(_));
    166   // Owned by WriteState.
    167   MockStorageCallback mock_storage_callback;
    168   invalidation::Status results(invalidation::Status::PERMANENT_FAILURE,
    169                                "fake-failure");
    170   EXPECT_CALL(mock_storage_callback, Run(_))
    171       .WillOnce(SaveArg<0>(&results));
    172   sync_system_resources_.storage()->WriteKey(
    173       std::string(), "state", mock_storage_callback.CreateCallback());
    174   message_loop_.RunUntilIdle();
    175   EXPECT_EQ(invalidation::Status(invalidation::Status::SUCCESS, std::string()),
    176             results);
    177 }
    178 
    179 class TestSyncNetworkChannel : public SyncNetworkChannel {
    180  public:
    181   TestSyncNetworkChannel() {}
    182   virtual ~TestSyncNetworkChannel() {}
    183 
    184   using SyncNetworkChannel::NotifyStateChange;
    185   using SyncNetworkChannel::DeliverIncomingMessage;
    186 
    187   virtual void SendEncodedMessage(const std::string& encoded_message) OVERRIDE {
    188     last_encoded_message_ = encoded_message;
    189   }
    190 
    191   std::string last_encoded_message_;
    192 };
    193 
    194 class SyncNetworkChannelTest
    195     : public testing::Test,
    196       public SyncNetworkChannel::Observer {
    197  protected:
    198   SyncNetworkChannelTest()
    199       : last_invalidator_state_(DEFAULT_INVALIDATION_ERROR),
    200         connected_(false) {
    201     network_channel_.AddObserver(this);
    202     network_channel_.SetMessageReceiver(
    203         invalidation::NewPermanentCallback(
    204             this, &SyncNetworkChannelTest::OnIncomingMessage));
    205     network_channel_.AddNetworkStatusReceiver(
    206         invalidation::NewPermanentCallback(
    207             this, &SyncNetworkChannelTest::OnNetworkStatusChange));
    208   }
    209 
    210   virtual ~SyncNetworkChannelTest() {
    211     network_channel_.RemoveObserver(this);
    212   }
    213 
    214   virtual void OnNetworkChannelStateChanged(
    215       InvalidatorState invalidator_state) OVERRIDE {
    216     last_invalidator_state_ = invalidator_state;
    217   }
    218 
    219   void OnIncomingMessage(std::string incoming_message) {
    220     last_message_ = incoming_message;
    221   }
    222 
    223   void OnNetworkStatusChange(bool connected) {
    224     connected_ = connected;
    225   }
    226 
    227   TestSyncNetworkChannel network_channel_;
    228   InvalidatorState last_invalidator_state_;
    229   std::string last_message_;
    230   bool connected_;
    231 };
    232 
    233 const char kMessage[] = "message";
    234 const char kServiceContext[] = "service context";
    235 const int64 kSchedulingHash = 100;
    236 
    237 // Encode a message with some context and then decode it.  The decoded info
    238 // should match the original info.
    239 TEST_F(SyncNetworkChannelTest, EncodeDecode) {
    240   const std::string& data =
    241       SyncNetworkChannel::EncodeMessageForTest(
    242           kMessage, kServiceContext, kSchedulingHash);
    243   std::string message;
    244   std::string service_context;
    245   int64 scheduling_hash = 0LL;
    246   EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest(
    247       data, &message, &service_context, &scheduling_hash));
    248   EXPECT_EQ(kMessage, message);
    249   EXPECT_EQ(kServiceContext, service_context);
    250   EXPECT_EQ(kSchedulingHash, scheduling_hash);
    251 }
    252 
    253 // Encode a message with no context and then decode it.  The decoded message
    254 // should match the original message, but the context and hash should be
    255 // untouched.
    256 TEST_F(SyncNetworkChannelTest, EncodeDecodeNoContext) {
    257   const std::string& data =
    258       SyncNetworkChannel::EncodeMessageForTest(
    259           kMessage, std::string(), kSchedulingHash);
    260   std::string message;
    261   std::string service_context = kServiceContext;
    262   int64 scheduling_hash = kSchedulingHash + 1;
    263   EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest(
    264       data, &message, &service_context, &scheduling_hash));
    265   EXPECT_EQ(kMessage, message);
    266   EXPECT_EQ(kServiceContext, service_context);
    267   EXPECT_EQ(kSchedulingHash + 1, scheduling_hash);
    268 }
    269 
    270 // Decode an empty notification. It should result in an empty message
    271 // but should leave the context and hash untouched.
    272 TEST_F(SyncNetworkChannelTest, DecodeEmpty) {
    273   std::string message = kMessage;
    274   std::string service_context = kServiceContext;
    275   int64 scheduling_hash = kSchedulingHash;
    276   EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest(
    277       std::string(), &message, &service_context, &scheduling_hash));
    278   EXPECT_TRUE(message.empty());
    279   EXPECT_EQ(kServiceContext, service_context);
    280   EXPECT_EQ(kSchedulingHash, scheduling_hash);
    281 }
    282 
    283 // Try to decode a garbage notification.  It should leave all its
    284 // arguments untouched and return false.
    285 TEST_F(SyncNetworkChannelTest, DecodeGarbage) {
    286   std::string data = "garbage";
    287   std::string message = kMessage;
    288   std::string service_context = kServiceContext;
    289   int64 scheduling_hash = kSchedulingHash;
    290   EXPECT_FALSE(SyncNetworkChannel::DecodeMessageForTest(
    291       data, &message, &service_context, &scheduling_hash));
    292   EXPECT_EQ(kMessage, message);
    293   EXPECT_EQ(kServiceContext, service_context);
    294   EXPECT_EQ(kSchedulingHash, scheduling_hash);
    295 }
    296 
    297 // Simulate network channel state change. It should propagate to observer.
    298 TEST_F(SyncNetworkChannelTest, OnNetworkChannelStateChanged) {
    299   EXPECT_EQ(DEFAULT_INVALIDATION_ERROR, last_invalidator_state_);
    300   EXPECT_FALSE(connected_);
    301   network_channel_.NotifyStateChange(INVALIDATIONS_ENABLED);
    302   EXPECT_EQ(INVALIDATIONS_ENABLED, last_invalidator_state_);
    303   EXPECT_TRUE(connected_);
    304   network_channel_.NotifyStateChange(INVALIDATION_CREDENTIALS_REJECTED);
    305   EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, last_invalidator_state_);
    306   EXPECT_FALSE(connected_);
    307 }
    308 
    309 // Call SendMessage on the channel.  SendEncodedMessage should be called for it.
    310 TEST_F(SyncNetworkChannelTest, SendMessage) {
    311   network_channel_.SendMessage(kMessage);
    312   std::string expected_encoded_message =
    313       SyncNetworkChannel::EncodeMessageForTest(
    314           kMessage,
    315           network_channel_.GetServiceContextForTest(),
    316           network_channel_.GetSchedulingHashForTest());
    317   ASSERT_EQ(expected_encoded_message, network_channel_.last_encoded_message_);
    318 }
    319 
    320 // Simulate an incoming notification. It should be decoded properly
    321 // by the channel.
    322 TEST_F(SyncNetworkChannelTest, OnIncomingMessage) {
    323   const std::string message =
    324       SyncNetworkChannel::EncodeMessageForTest(
    325           kMessage, kServiceContext, kSchedulingHash);
    326 
    327   network_channel_.DeliverIncomingMessage(message);
    328   EXPECT_EQ(kServiceContext,
    329             network_channel_.GetServiceContextForTest());
    330   EXPECT_EQ(kSchedulingHash,
    331             network_channel_.GetSchedulingHashForTest());
    332   EXPECT_EQ(kMessage, last_message_);
    333 }
    334 
    335 // Simulate an incoming notification with no receiver. It should be dropped by
    336 // the channel.
    337 TEST_F(SyncNetworkChannelTest, OnIncomingMessageNoReceiver) {
    338   const std::string message =
    339       SyncNetworkChannel::EncodeMessageForTest(
    340           kMessage, kServiceContext, kSchedulingHash);
    341 
    342   network_channel_.SetMessageReceiver(NULL);
    343   network_channel_.DeliverIncomingMessage(message);
    344   EXPECT_TRUE(network_channel_.GetServiceContextForTest().empty());
    345   EXPECT_EQ(static_cast<int64>(0),
    346             network_channel_.GetSchedulingHashForTest());
    347   EXPECT_TRUE(last_message_.empty());
    348 }
    349 
    350 // Simulate an incoming garbage notification. It should be dropped by
    351 // the channel.
    352 TEST_F(SyncNetworkChannelTest, OnIncomingMessageGarbage) {
    353   std::string message = "garbage";
    354 
    355   network_channel_.DeliverIncomingMessage(message);
    356   EXPECT_TRUE(network_channel_.GetServiceContextForTest().empty());
    357   EXPECT_EQ(static_cast<int64>(0),
    358             network_channel_.GetSchedulingHashForTest());
    359   EXPECT_TRUE(last_message_.empty());
    360 }
    361 
    362 // Send a message, simulate an incoming message with context, and then
    363 // send the same message again.  The first sent message should not
    364 // have any context, but the second sent message should have the
    365 // context from the incoming emssage.
    366 TEST_F(SyncNetworkChannelTest, PersistedMessageState) {
    367   network_channel_.SendMessage(kMessage);
    368   ASSERT_FALSE(network_channel_.last_encoded_message_.empty());
    369   {
    370     std::string message;
    371     std::string service_context;
    372     int64 scheduling_hash = 0LL;
    373     EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest(
    374         network_channel_.last_encoded_message_,
    375         &message, &service_context, &scheduling_hash));
    376     EXPECT_EQ(kMessage, message);
    377     EXPECT_TRUE(service_context.empty());
    378     EXPECT_EQ(0LL, scheduling_hash);
    379   }
    380 
    381   const std::string& encoded_message =
    382       SyncNetworkChannel::EncodeMessageForTest(
    383           kMessage, kServiceContext, kSchedulingHash);
    384   network_channel_.DeliverIncomingMessage(encoded_message);
    385 
    386   network_channel_.last_encoded_message_.clear();
    387   network_channel_.SendMessage(kMessage);
    388   ASSERT_FALSE(network_channel_.last_encoded_message_.empty());
    389   {
    390     std::string message;
    391     std::string service_context;
    392     int64 scheduling_hash = 0LL;
    393     EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest(
    394         network_channel_.last_encoded_message_,
    395         &message, &service_context, &scheduling_hash));
    396     EXPECT_EQ(kMessage, message);
    397     EXPECT_EQ(kServiceContext, service_context);
    398     EXPECT_EQ(kSchedulingHash, scheduling_hash);
    399   }
    400 }
    401 
    402 }  // namespace
    403 }  // namespace syncer
    404