Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2011 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 "chrome/browser/sync/js_sync_manager_observer.h"
      6 
      7 #include <cstddef>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/sync/engine/syncapi.h"
     12 #include "chrome/browser/sync/js_arg_list.h"
     13 #include "chrome/browser/sync/js_test_util.h"
     14 #include "chrome/browser/sync/sessions/session_state.h"
     15 #include "chrome/browser/sync/syncable/model_type.h"
     16 #include "chrome/test/sync/engine/test_user_share.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 namespace browser_sync {
     20 namespace {
     21 
     22 using ::testing::InSequence;
     23 using ::testing::StrictMock;
     24 
     25 class JsSyncManagerObserverTest : public testing::Test {
     26  protected:
     27   JsSyncManagerObserverTest() : sync_manager_observer_(&mock_router_) {}
     28 
     29   StrictMock<MockJsEventRouter> mock_router_;
     30   JsSyncManagerObserver sync_manager_observer_;
     31 };
     32 
     33 TEST_F(JsSyncManagerObserverTest, NoArgNotifiations) {
     34   InSequence dummy;
     35 
     36   EXPECT_CALL(mock_router_,
     37               RouteJsEvent("onInitializationComplete",
     38                            HasArgs(JsArgList()), NULL));
     39   EXPECT_CALL(mock_router_,
     40               RouteJsEvent("onPassphraseFailed",
     41                            HasArgs(JsArgList()), NULL));
     42 
     43   EXPECT_CALL(mock_router_,
     44               RouteJsEvent("onStopSyncingPermanently",
     45                            HasArgs(JsArgList()), NULL));
     46   EXPECT_CALL(mock_router_,
     47               RouteJsEvent("onClearServerDataSucceeded",
     48                            HasArgs(JsArgList()), NULL));
     49   EXPECT_CALL(mock_router_,
     50               RouteJsEvent("onClearServerDataFailed",
     51                            HasArgs(JsArgList()), NULL));
     52 
     53   sync_manager_observer_.OnInitializationComplete();
     54   sync_manager_observer_.OnPassphraseFailed();
     55   sync_manager_observer_.OnStopSyncingPermanently();
     56   sync_manager_observer_.OnClearServerDataSucceeded();
     57   sync_manager_observer_.OnClearServerDataFailed();
     58 }
     59 
     60 TEST_F(JsSyncManagerObserverTest, OnChangesComplete) {
     61   InSequence dummy;
     62 
     63   for (int i = syncable::FIRST_REAL_MODEL_TYPE;
     64        i < syncable::MODEL_TYPE_COUNT; ++i) {
     65     const std::string& model_type_str =
     66         syncable::ModelTypeToString(syncable::ModelTypeFromInt(i));
     67     ListValue expected_args;
     68     expected_args.Append(Value::CreateStringValue(model_type_str));
     69     EXPECT_CALL(mock_router_,
     70                 RouteJsEvent("onChangesComplete",
     71                              HasArgsAsList(expected_args), NULL));
     72   }
     73 
     74   for (int i = syncable::FIRST_REAL_MODEL_TYPE;
     75        i < syncable::MODEL_TYPE_COUNT; ++i) {
     76     sync_manager_observer_.OnChangesComplete(syncable::ModelTypeFromInt(i));
     77   }
     78 }
     79 
     80 TEST_F(JsSyncManagerObserverTest, OnSyncCycleCompleted) {
     81   std::string download_progress_markers[syncable::MODEL_TYPE_COUNT];
     82   sessions::SyncSessionSnapshot snapshot(sessions::SyncerStatus(),
     83                                          sessions::ErrorCounters(),
     84                                          100,
     85                                          false,
     86                                          syncable::ModelTypeBitSet(),
     87                                          download_progress_markers,
     88                                          false,
     89                                          true,
     90                                          100,
     91                                          5,
     92                                          false,
     93                                          sessions::SyncSourceInfo());
     94   ListValue expected_args;
     95   expected_args.Append(snapshot.ToValue());
     96 
     97   EXPECT_CALL(mock_router_,
     98               RouteJsEvent("onSyncCycleCompleted",
     99                            HasArgsAsList(expected_args), NULL));
    100 
    101   sync_manager_observer_.OnSyncCycleCompleted(&snapshot);
    102 }
    103 
    104 TEST_F(JsSyncManagerObserverTest, OnAuthError) {
    105   GoogleServiceAuthError error(GoogleServiceAuthError::TWO_FACTOR);
    106   ListValue expected_args;
    107   expected_args.Append(error.ToValue());
    108 
    109   EXPECT_CALL(mock_router_,
    110               RouteJsEvent("onAuthError",
    111                            HasArgsAsList(expected_args), NULL));
    112 
    113   sync_manager_observer_.OnAuthError(error);
    114 }
    115 
    116 TEST_F(JsSyncManagerObserverTest, OnPassphraseRequired) {
    117   InSequence dummy;
    118 
    119   ListValue true_args, false_args;
    120   true_args.Append(Value::CreateBooleanValue(true));
    121   false_args.Append(Value::CreateBooleanValue(false));
    122 
    123   EXPECT_CALL(mock_router_,
    124               RouteJsEvent("onPassphraseRequired",
    125                            HasArgsAsList(false_args), NULL));
    126   EXPECT_CALL(mock_router_,
    127               RouteJsEvent("onPassphraseRequired",
    128                            HasArgsAsList(true_args), NULL));
    129 
    130   sync_manager_observer_.OnPassphraseRequired(false);
    131   sync_manager_observer_.OnPassphraseRequired(true);
    132 }
    133 
    134 TEST_F(JsSyncManagerObserverTest, SensitiveNotifiations) {
    135   ListValue redacted_args;
    136   redacted_args.Append(Value::CreateStringValue("<redacted>"));
    137 
    138   EXPECT_CALL(mock_router_,
    139               RouteJsEvent("onUpdatedToken",
    140                            HasArgsAsList(redacted_args), NULL));
    141   EXPECT_CALL(mock_router_,
    142               RouteJsEvent("onPassphraseAccepted",
    143                            HasArgsAsList(redacted_args), NULL));
    144 
    145   sync_manager_observer_.OnUpdatedToken("sensitive_token");
    146   sync_manager_observer_.OnPassphraseAccepted("sensitive_token");
    147 }
    148 
    149 TEST_F(JsSyncManagerObserverTest, OnEncryptionComplete) {
    150   ListValue expected_args;
    151   ListValue* encrypted_type_values = new ListValue();
    152   syncable::ModelTypeSet encrypted_types;
    153 
    154   expected_args.Append(encrypted_type_values);
    155   for (int i = syncable::FIRST_REAL_MODEL_TYPE;
    156        i < syncable::MODEL_TYPE_COUNT; ++i) {
    157     syncable::ModelType type = syncable::ModelTypeFromInt(i);
    158     encrypted_types.insert(type);
    159     encrypted_type_values->Append(Value::CreateStringValue(
    160         syncable::ModelTypeToString(type)));
    161   }
    162 
    163   EXPECT_CALL(mock_router_,
    164               RouteJsEvent("onEncryptionComplete",
    165                            HasArgsAsList(expected_args), NULL));
    166 
    167   sync_manager_observer_.OnEncryptionComplete(encrypted_types);
    168 }
    169 
    170 TEST_F(JsSyncManagerObserverTest, OnMigrationNeededForTypes) {
    171   ListValue expected_args;
    172   ListValue* type_values = new ListValue();
    173   syncable::ModelTypeSet types;
    174 
    175   expected_args.Append(type_values);
    176   for (int i = syncable::FIRST_REAL_MODEL_TYPE;
    177        i < syncable::MODEL_TYPE_COUNT; ++i) {
    178     syncable::ModelType type = syncable::ModelTypeFromInt(i);
    179     types.insert(type);
    180     type_values->Append(Value::CreateStringValue(
    181         syncable::ModelTypeToString(type)));
    182   }
    183 
    184   EXPECT_CALL(mock_router_,
    185               RouteJsEvent("onMigrationNeededForTypes",
    186                            HasArgsAsList(expected_args), NULL));
    187 
    188   sync_manager_observer_.OnMigrationNeededForTypes(types);
    189 }
    190 
    191 namespace {
    192 
    193 // Makes a node of the given model type.  Returns the id of the
    194 // newly-created node.
    195 int64 MakeNode(sync_api::UserShare* share, syncable::ModelType model_type) {
    196   sync_api::WriteTransaction trans(share);
    197   sync_api::ReadNode root_node(&trans);
    198   root_node.InitByRootLookup();
    199   sync_api::WriteNode node(&trans);
    200   EXPECT_TRUE(node.InitUniqueByCreation(
    201       model_type, root_node,
    202       syncable::ModelTypeToString(model_type)));
    203   node.SetIsFolder(false);
    204   return node.GetId();
    205 }
    206 
    207 }  // namespace
    208 
    209 TEST_F(JsSyncManagerObserverTest, OnChangesApplied) {
    210   InSequence dummy;
    211 
    212   TestUserShare test_user_share;
    213   test_user_share.SetUp();
    214 
    215   // We don't test with passwords as that requires additional setup.
    216 
    217   // Build a list of example ChangeRecords.
    218   sync_api::SyncManager::ChangeRecord changes[syncable::MODEL_TYPE_COUNT];
    219   for (int i = syncable::AUTOFILL_PROFILE;
    220        i < syncable::MODEL_TYPE_COUNT; ++i) {
    221     changes[i].id =
    222         MakeNode(test_user_share.user_share(), syncable::ModelTypeFromInt(i));
    223     switch (i % 3) {
    224       case 0:
    225         changes[i].action =
    226             sync_api::SyncManager::ChangeRecord::ACTION_ADD;
    227         break;
    228       case 1:
    229         changes[i].action =
    230             sync_api::SyncManager::ChangeRecord::ACTION_UPDATE;
    231         break;
    232       default:
    233         changes[i].action =
    234             sync_api::SyncManager::ChangeRecord::ACTION_DELETE;
    235         break;
    236     }
    237     {
    238       sync_api::ReadTransaction trans(test_user_share.user_share());
    239       sync_api::ReadNode node(&trans);
    240       EXPECT_TRUE(node.InitByIdLookup(changes[i].id));
    241       changes[i].specifics = node.GetEntry()->Get(syncable::SPECIFICS);
    242     }
    243   }
    244 
    245   // For each i, we call OnChangesApplied() with the first arg equal
    246   // to i cast to ModelType and the second argument with the changes
    247   // starting from changes[i].
    248 
    249   // Set expectations for each data type.
    250   for (int i = syncable::AUTOFILL_PROFILE;
    251        i < syncable::MODEL_TYPE_COUNT; ++i) {
    252     const std::string& model_type_str =
    253         syncable::ModelTypeToString(syncable::ModelTypeFromInt(i));
    254     ListValue expected_args;
    255     expected_args.Append(Value::CreateStringValue(model_type_str));
    256     ListValue* expected_changes = new ListValue();
    257     expected_args.Append(expected_changes);
    258     for (int j = i; j < syncable::MODEL_TYPE_COUNT; ++j) {
    259       sync_api::ReadTransaction trans(test_user_share.user_share());
    260       expected_changes->Append(changes[j].ToValue(&trans));
    261     }
    262     EXPECT_CALL(mock_router_,
    263                 RouteJsEvent("onChangesApplied",
    264                              HasArgsAsList(expected_args), NULL));
    265   }
    266 
    267   // Fire OnChangesApplied() for each data type.
    268   for (int i = syncable::AUTOFILL_PROFILE;
    269        i < syncable::MODEL_TYPE_COUNT; ++i) {
    270     sync_api::ReadTransaction trans(test_user_share.user_share());
    271     sync_manager_observer_.OnChangesApplied(syncable::ModelTypeFromInt(i),
    272                                             &trans, &changes[i],
    273                                             syncable::MODEL_TYPE_COUNT - i);
    274   }
    275 
    276   test_user_share.TearDown();
    277 }
    278 
    279 }  // namespace
    280 }  // namespace browser_sync
    281