Home | History | Annotate | Download | only in drive_backend_v1
      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.
      4 
      5 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/message_loop/message_loop_proxy.h"
      9 #include "base/run_loop.h"
     10 #include "chrome/browser/sync_file_system/drive_backend_v1/drive_metadata_store.h"
     11 #include "chrome/browser/sync_file_system/drive_backend_v1/fake_api_util.h"
     12 #include "chrome/browser/sync_file_system/sync_file_system.pb.h"
     13 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
     14 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     15 #include "chrome/test/base/testing_browser_process.h"
     16 #include "chrome/test/base/testing_profile.h"
     17 #include "chrome/test/base/testing_profile_manager.h"
     18 #include "content/public/test/test_browser_thread_bundle.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 namespace sync_file_system {
     22 
     23 using drive_backend::APIUtilInterface;
     24 using drive_backend::FakeAPIUtil;
     25 
     26 namespace {
     27 
     28 const char kTestProfileName[] = "test-profile";
     29 
     30 const char kSyncRootResourceId[] = "folder:sync_root_resource_id";
     31 
     32 void DidInitialize(bool* done, SyncStatusCode status, bool created) {
     33   EXPECT_EQ(SYNC_STATUS_OK, status);
     34   *done = true;
     35 }
     36 
     37 void ExpectEqStatus(bool* done,
     38                     SyncStatusCode expected,
     39                     SyncStatusCode actual) {
     40   EXPECT_FALSE(*done);
     41   *done = true;
     42   EXPECT_EQ(expected, actual);
     43 }
     44 
     45 void ExpectOkStatus(SyncStatusCode status) {
     46   EXPECT_EQ(SYNC_STATUS_OK, status);
     47 }
     48 
     49 }  // namespace
     50 
     51 class DriveFileSyncServiceTest : public testing::Test {
     52  public:
     53   DriveFileSyncServiceTest()
     54       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
     55         profile_manager_(TestingBrowserProcess::GetGlobal()),
     56         fake_api_util_(NULL),
     57         metadata_store_(NULL) {}
     58 
     59   virtual void SetUp() OVERRIDE {
     60     ASSERT_TRUE(profile_manager_.SetUp());
     61 
     62     RegisterSyncableFileSystem();
     63     fake_api_util_ = new FakeAPIUtil;
     64 
     65     ASSERT_TRUE(scoped_base_dir_.CreateUniqueTempDir());
     66     base_dir_ = scoped_base_dir_.path();
     67     metadata_store_ = new DriveMetadataStore(
     68         base_dir_, base::MessageLoopProxy::current().get());
     69     bool done = false;
     70     metadata_store_->Initialize(base::Bind(&DidInitialize, &done));
     71     base::RunLoop().RunUntilIdle();
     72     metadata_store_->SetSyncRootDirectory(kSyncRootResourceId);
     73     EXPECT_TRUE(done);
     74 
     75     sync_service_ = DriveFileSyncService::CreateForTesting(
     76         profile_manager_.CreateTestingProfile(kTestProfileName),
     77         base_dir_,
     78         scoped_ptr<APIUtilInterface>(fake_api_util_),
     79         scoped_ptr<DriveMetadataStore>(metadata_store_)).Pass();
     80     base::RunLoop().RunUntilIdle();
     81   }
     82 
     83   virtual void TearDown() OVERRIDE {
     84     metadata_store_ = NULL;
     85     fake_api_util_ = NULL;
     86     sync_service_.reset();
     87     base::RunLoop().RunUntilIdle();
     88 
     89     base_dir_ = base::FilePath();
     90     RevokeSyncableFileSystem();
     91   }
     92 
     93   virtual ~DriveFileSyncServiceTest() {
     94   }
     95 
     96  protected:
     97   FakeAPIUtil* fake_api_util() { return fake_api_util_; }
     98   DriveMetadataStore* metadata_store() { return metadata_store_; }
     99   DriveFileSyncService* sync_service() { return sync_service_.get(); }
    100   std::map<GURL, std::string>* pending_batch_sync_origins() {
    101     return &(sync_service()->pending_batch_sync_origins_);
    102   }
    103 
    104   // Helper function to add an origin to the given origin sync status. To make
    105   // naming easier, each origin, resourceID, etc. will all share the same
    106   // prefixes and only be distinguished by the given suffix ID which could be a
    107   // number (1, 2, 3, etc.) or a letter (A, B, C, etc.).
    108   // e.g. originA, originB, folder:resource_idA, folder:resource_idB, etc.
    109   void AddOrigin(std::string status, const char* suffix) {
    110     const GURL origin(std::string("chrome-extension://app_") + suffix);
    111     const std::string resource_id(std::string("folder:resource_id") + suffix);
    112 
    113     if (status == "Pending") {
    114       pending_batch_sync_origins()->insert(std::make_pair(origin, resource_id));
    115     } else if (status == "Enabled") {
    116       metadata_store()->AddIncrementalSyncOrigin(origin, resource_id);
    117     } else if (status == "Disabled") {
    118       metadata_store()->AddIncrementalSyncOrigin(origin, resource_id);
    119       metadata_store()->DisableOrigin(origin, base::Bind(&ExpectOkStatus));
    120     } else {
    121       NOTREACHED();
    122     }
    123   }
    124 
    125   bool VerifyOriginStatusCount(size_t expected_pending,
    126                                size_t expected_enabled,
    127                                size_t expected_disabled) {
    128     size_t actual_pending = pending_batch_sync_origins()->size();
    129     size_t actual_enabled = metadata_store()->incremental_sync_origins().size();
    130     size_t actual_disabled = metadata_store()->disabled_origins().size();
    131 
    132     // Prints which counts don't match up if any.
    133     EXPECT_EQ(expected_pending, actual_pending);
    134     EXPECT_EQ(expected_enabled, actual_enabled);
    135     EXPECT_EQ(expected_disabled, actual_disabled);
    136 
    137     // If any count doesn't match, the original line number can be printed by
    138     // simply adding ASSERT_TRUE on the call to this function.
    139     if (expected_pending == actual_pending &&
    140         expected_enabled == actual_enabled &&
    141         expected_disabled == actual_disabled)
    142       return true;
    143 
    144     return false;
    145   }
    146 
    147  private:
    148   base::ScopedTempDir scoped_base_dir_;
    149   content::TestBrowserThreadBundle thread_bundle_;
    150 
    151   TestingProfileManager profile_manager_;
    152   base::FilePath base_dir_;
    153 
    154   FakeAPIUtil* fake_api_util_;          // Owned by |sync_service_|.
    155   DriveMetadataStore* metadata_store_;  // Owned by |sync_service_|.
    156 
    157   scoped_ptr<DriveFileSyncService> sync_service_;
    158 
    159   DISALLOW_COPY_AND_ASSIGN(DriveFileSyncServiceTest);
    160 };
    161 
    162 TEST_F(DriveFileSyncServiceTest, UninstallOrigin) {
    163   // Add fake app origin directory using fake drive_sync_client.
    164   std::string origin_dir_resource_id = "uninstalledappresourceid";
    165   fake_api_util()->PushRemoteChange("parent_id",
    166                                     "parent_title",
    167                                     "uninstall_me_folder",
    168                                     origin_dir_resource_id,
    169                                     "resource_md5",
    170                                     SYNC_FILE_TYPE_FILE,
    171                                     false);
    172 
    173   // Add meta_data entry so GURL->resourse_id mapping is there.
    174   const GURL origin_gurl("chrome-extension://uninstallme");
    175   metadata_store()->AddIncrementalSyncOrigin(origin_gurl,
    176                                              origin_dir_resource_id);
    177 
    178   // Delete the origin directory.
    179   bool done = false;
    180   sync_service()->UninstallOrigin(
    181       origin_gurl,
    182       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
    183       base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
    184   base::RunLoop().RunUntilIdle();
    185   EXPECT_TRUE(done);
    186 
    187   // Assert the App's origin folder was marked as deleted.
    188   EXPECT_TRUE(fake_api_util()->remote_resources().find(
    189       origin_dir_resource_id)->second.deleted);
    190 }
    191 
    192 TEST_F(DriveFileSyncServiceTest, UninstallUnpackedOrigin) {
    193   // Add fake app origin directory using fake drive_sync_client.
    194   std::string origin_dir_resource_id = "uninstalledappresourceid";
    195   fake_api_util()->PushRemoteChange("parent_id",
    196                                     "parent_title",
    197                                     "uninstall_me_folder",
    198                                     origin_dir_resource_id,
    199                                     "resource_md5",
    200                                     SYNC_FILE_TYPE_FILE,
    201                                     false);
    202 
    203   // Add meta_data entry so GURL->resourse_id mapping is there.
    204   const GURL origin_gurl("chrome-extension://uninstallme");
    205   metadata_store()->AddIncrementalSyncOrigin(origin_gurl,
    206                                              origin_dir_resource_id);
    207 
    208   // Uninstall the origin.
    209   bool done = false;
    210   sync_service()->UninstallOrigin(
    211       origin_gurl,
    212       RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE,
    213       base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
    214   base::RunLoop().RunUntilIdle();
    215   EXPECT_TRUE(done);
    216 
    217   // Assert the App's origin folder has not been deleted.
    218   EXPECT_FALSE(fake_api_util()->remote_resources().find(
    219       origin_dir_resource_id)->second.deleted);
    220 }
    221 
    222 TEST_F(DriveFileSyncServiceTest, UninstallOriginWithoutOriginDirectory) {
    223   // Not add fake app origin directory.
    224   std::string origin_dir_resource_id = "uninstalledappresourceid";
    225 
    226   // Add meta_data entry so GURL->resourse_id mapping is there.
    227   const GURL origin_gurl("chrome-extension://uninstallme");
    228   metadata_store()->AddIncrementalSyncOrigin(origin_gurl,
    229                                              origin_dir_resource_id);
    230 
    231   // Delete the origin directory (but not found).
    232   bool done = false;
    233   sync_service()->UninstallOrigin(
    234       origin_gurl,
    235       RemoteFileSyncService::UNINSTALL_AND_PURGE_REMOTE,
    236       base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
    237   base::RunLoop().RunUntilIdle();
    238   EXPECT_TRUE(done);
    239 
    240   // Assert the App's origin folder does not exist.
    241   const FakeAPIUtil::RemoteResourceByResourceId& remote_resources =
    242       fake_api_util()->remote_resources();
    243   EXPECT_TRUE(remote_resources.find(origin_dir_resource_id) ==
    244               remote_resources.end());
    245 }
    246 
    247 TEST_F(DriveFileSyncServiceTest, DisableOriginPendingOrigin) {
    248   // Disable a pending origin after DriveFileSystemService has already started.
    249   const GURL origin("chrome-extension://app");
    250   std::string origin_resource_id = "app_resource_id";
    251   pending_batch_sync_origins()->insert(std::make_pair(origin,
    252                                                       origin_resource_id));
    253   ASSERT_TRUE(VerifyOriginStatusCount(1u, 0u, 0u));
    254 
    255   // Pending origins that are disabled are dropped and do not go to disabled.
    256   sync_service()->DisableOrigin(origin, base::Bind(&ExpectOkStatus));
    257   base::RunLoop().RunUntilIdle();
    258   ASSERT_TRUE(VerifyOriginStatusCount(0u, 0u, 0u));
    259 }
    260 
    261 TEST_F(DriveFileSyncServiceTest,
    262        DisableOriginIncrementalOrigin) {
    263   // Disable a pending origin after DriveFileSystemService has already started.
    264   const GURL origin("chrome-extension://app");
    265   std::string origin_resource_id = "app_resource_id";
    266   metadata_store()->AddIncrementalSyncOrigin(origin, origin_resource_id);
    267   ASSERT_TRUE(VerifyOriginStatusCount(0u, 1u, 0u));
    268 
    269   sync_service()->DisableOrigin(origin, base::Bind(&ExpectOkStatus));
    270   base::RunLoop().RunUntilIdle();
    271   ASSERT_TRUE(VerifyOriginStatusCount(0u, 0u, 1u));
    272 }
    273 
    274 TEST_F(DriveFileSyncServiceTest, EnableOrigin) {
    275   const GURL origin("chrome-extension://app");
    276   std::string origin_resource_id = "app_resource_id";
    277   metadata_store()->AddIncrementalSyncOrigin(origin, origin_resource_id);
    278   metadata_store()->DisableOrigin(origin, base::Bind(&ExpectOkStatus));
    279   ASSERT_TRUE(VerifyOriginStatusCount(0u, 0u, 1u));
    280 
    281   // Re-enable the previously disabled origin. It initially goes to pending
    282   // status and then to enabled (incremental) again when NotifyTasksDone() in
    283   // SyncTaskManager invokes MaybeStartFetchChanges() and pending
    284   // origins > 0.
    285   sync_service()->EnableOrigin(origin, base::Bind(&ExpectOkStatus));
    286   base::RunLoop().RunUntilIdle();
    287   ASSERT_TRUE(VerifyOriginStatusCount(0u, 1u, 0u));
    288 }
    289 
    290 TEST_F(DriveFileSyncServiceTest, GetOriginStatusMap) {
    291   scoped_ptr<RemoteFileSyncService::OriginStatusMap> origin_status_map;
    292   sync_service()->GetOriginStatusMap(
    293       CreateResultReceiver(&origin_status_map));
    294   ASSERT_EQ(0u, origin_status_map->size());
    295 
    296   // Add 3 pending, 2 enabled and 1 disabled sync origin.
    297   AddOrigin("Pending", "p0");
    298   AddOrigin("Pending", "p1");
    299   AddOrigin("Pending", "p2");
    300   AddOrigin("Enabled", "e0");
    301   AddOrigin("Enabled", "e1");
    302   AddOrigin("Disabled", "d0");
    303 
    304   sync_service()->GetOriginStatusMap(
    305       CreateResultReceiver(&origin_status_map));
    306   ASSERT_EQ(6u, origin_status_map->size());
    307   EXPECT_EQ("Pending", (*origin_status_map)[GURL("chrome-extension://app_p0")]);
    308   EXPECT_EQ("Pending", (*origin_status_map)[GURL("chrome-extension://app_p1")]);
    309   EXPECT_EQ("Pending", (*origin_status_map)[GURL("chrome-extension://app_p2")]);
    310   EXPECT_EQ("Enabled", (*origin_status_map)[GURL("chrome-extension://app_e0")]);
    311   EXPECT_EQ("Enabled", (*origin_status_map)[GURL("chrome-extension://app_e1")]);
    312   EXPECT_EQ("Disabled",
    313             (*origin_status_map)[GURL("chrome-extension://app_d0")]);
    314 }
    315 
    316 }  // namespace sync_file_system
    317