Home | History | Annotate | Download | only in drive_backend
      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/register_app_task.h"
      6 
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/format_macros.h"
      9 #include "base/run_loop.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "chrome/browser/drive/drive_uploader.h"
     13 #include "chrome/browser/drive/fake_drive_service.h"
     14 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
     15 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_util.h"
     16 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h"
     17 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
     18 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h"
     19 #include "chrome/browser/sync_file_system/drive_backend_v1/fake_drive_service_helper.h"
     20 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
     21 #include "content/public/test/test_browser_thread_bundle.h"
     22 #include "google_apis/drive/gdata_wapi_parser.h"
     23 #include "testing/gtest/include/gtest/gtest.h"
     24 #include "third_party/leveldatabase/src/include/leveldb/db.h"
     25 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
     26 
     27 namespace sync_file_system {
     28 namespace drive_backend {
     29 
     30 namespace {
     31 const int64 kSyncRootTrackerID = 100;
     32 }  // namespace
     33 
     34 class RegisterAppTaskTest : public testing::Test,
     35                             public SyncEngineContext {
     36  public:
     37   RegisterAppTaskTest()
     38       : next_file_id_(1000),
     39         next_tracker_id_(10000) {}
     40   virtual ~RegisterAppTaskTest() {}
     41 
     42   virtual void SetUp() OVERRIDE {
     43     ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
     44 
     45     fake_drive_service_.reset(new drive::FakeDriveService);
     46     ASSERT_TRUE(fake_drive_service_->LoadAccountMetadataForWapi(
     47         "sync_file_system/account_metadata.json"));
     48     ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
     49         "gdata/empty_feed.json"));
     50 
     51     drive_uploader_.reset(new drive::DriveUploader(
     52         fake_drive_service_.get(), base::MessageLoopProxy::current()));
     53 
     54     fake_drive_service_helper_.reset(new FakeDriveServiceHelper(
     55         fake_drive_service_.get(), drive_uploader_.get()));
     56 
     57     ASSERT_EQ(google_apis::HTTP_CREATED,
     58               fake_drive_service_helper_->AddOrphanedFolder(
     59                   kSyncRootFolderTitle, &sync_root_folder_id_));
     60   }
     61 
     62   virtual void TearDown() OVERRIDE {
     63     metadata_database_.reset();
     64     base::RunLoop().RunUntilIdle();
     65   }
     66 
     67   virtual drive::DriveServiceInterface* GetDriveService() OVERRIDE {
     68     return fake_drive_service_.get();
     69   }
     70 
     71   virtual drive::DriveUploaderInterface* GetDriveUploader() OVERRIDE {
     72     return NULL;
     73   }
     74 
     75   virtual MetadataDatabase* GetMetadataDatabase() OVERRIDE {
     76     return metadata_database_.get();
     77   }
     78 
     79   virtual RemoteChangeProcessor* GetRemoteChangeProcessor() OVERRIDE {
     80     return NULL;
     81   }
     82 
     83   virtual base::SequencedTaskRunner* GetBlockingTaskRunner() OVERRIDE {
     84     return base::MessageLoopProxy::current();
     85   }
     86 
     87  protected:
     88   scoped_ptr<leveldb::DB> OpenLevelDB() {
     89     leveldb::DB* db = NULL;
     90     leveldb::Options options;
     91     options.create_if_missing = true;
     92     leveldb::Status status =
     93         leveldb::DB::Open(options, database_dir_.path().AsUTF8Unsafe(), &db);
     94     EXPECT_TRUE(status.ok());
     95     return make_scoped_ptr<leveldb::DB>(db);
     96   }
     97 
     98   void SetUpInitialData(leveldb::DB* db) {
     99     ServiceMetadata service_metadata;
    100     service_metadata.set_largest_change_id(100);
    101     service_metadata.set_sync_root_tracker_id(kSyncRootTrackerID);
    102     service_metadata.set_next_tracker_id(next_tracker_id_);
    103 
    104     FileDetails sync_root_details;
    105     sync_root_details.set_title(kSyncRootFolderTitle);
    106     sync_root_details.set_file_kind(FILE_KIND_FOLDER);
    107     sync_root_details.set_change_id(1);
    108 
    109     FileMetadata sync_root_metadata;
    110     sync_root_metadata.set_file_id(sync_root_folder_id_);
    111     *sync_root_metadata.mutable_details() = sync_root_details;
    112 
    113     FileTracker sync_root_tracker;
    114     sync_root_tracker.set_tracker_id(service_metadata.sync_root_tracker_id());
    115     sync_root_tracker.set_parent_tracker_id(0);
    116     sync_root_tracker.set_file_id(sync_root_metadata.file_id());
    117     sync_root_tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
    118     *sync_root_tracker.mutable_synced_details() = sync_root_details;
    119     sync_root_tracker.set_active(true);
    120 
    121     leveldb::WriteBatch batch;
    122     batch.Put(kDatabaseVersionKey,
    123               base::Int64ToString(kCurrentDatabaseVersion));
    124     PutServiceMetadataToBatch(service_metadata, &batch);
    125     PutFileToBatch(sync_root_metadata, &batch);
    126     PutTrackerToBatch(sync_root_tracker, &batch);
    127     EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
    128   }
    129 
    130   void CreateMetadataDatabase(scoped_ptr<leveldb::DB> db) {
    131     ASSERT_TRUE(db);
    132     ASSERT_FALSE(metadata_database_);
    133     ASSERT_EQ(SYNC_STATUS_OK,
    134               MetadataDatabase::CreateForTesting(
    135                   db.Pass(), &metadata_database_));
    136   }
    137 
    138   SyncStatusCode RunRegisterAppTask(const std::string& app_id) {
    139     RegisterAppTask task(this, app_id);
    140     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
    141     task.Run(CreateResultReceiver(&status));
    142     base::RunLoop().RunUntilIdle();
    143     return status;
    144   }
    145 
    146   void SetUpRegisteredAppRoot(
    147       const std::string& app_id,
    148       leveldb::DB* db) {
    149     FileDetails details;
    150     details.set_title(app_id);
    151     details.set_file_kind(FILE_KIND_FOLDER);
    152     details.add_parent_folder_ids(sync_root_folder_id_);
    153 
    154     FileMetadata metadata;
    155     metadata.set_file_id(GenerateFileID());
    156     *metadata.mutable_details() = details;
    157 
    158     FileTracker tracker;
    159     tracker.set_parent_tracker_id(kSyncRootTrackerID);
    160     tracker.set_tracker_id(next_tracker_id_++);
    161     tracker.set_file_id(metadata.file_id());
    162     tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
    163     tracker.set_app_id(app_id);
    164     *tracker.mutable_synced_details() = details;
    165     tracker.set_active(true);
    166 
    167     leveldb::WriteBatch batch;
    168     PutFileToBatch(metadata, &batch);
    169     PutTrackerToBatch(tracker, &batch);
    170     EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
    171   }
    172 
    173   void SetUpUnregisteredAppRoot(const std::string& app_id,
    174                                 leveldb::DB* db) {
    175     FileDetails details;
    176     details.set_title(app_id);
    177     details.set_file_kind(FILE_KIND_FOLDER);
    178     details.add_parent_folder_ids(sync_root_folder_id_);
    179 
    180     FileMetadata metadata;
    181     metadata.set_file_id(GenerateFileID());
    182     *metadata.mutable_details() = details;
    183 
    184     FileTracker tracker;
    185     tracker.set_parent_tracker_id(kSyncRootTrackerID);
    186     tracker.set_tracker_id(next_tracker_id_++);
    187     tracker.set_file_id(metadata.file_id());
    188     tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
    189     *tracker.mutable_synced_details() = details;
    190     tracker.set_active(false);
    191 
    192     leveldb::WriteBatch batch;
    193     PutFileToBatch(metadata, &batch);
    194     PutTrackerToBatch(tracker, &batch);
    195     EXPECT_TRUE(db->Write(leveldb::WriteOptions(), &batch).ok());
    196   }
    197 
    198   size_t CountRegisteredAppRoot() {
    199     // TODO(tzik): Add function to MetadataDatabase to list trackers by parent.
    200     typedef MetadataDatabase::TrackersByTitle TrackersByTitle;
    201     const TrackersByTitle& trackers_by_title =
    202         metadata_database_->trackers_by_parent_and_title_[kSyncRootTrackerID];
    203 
    204     size_t count = 0;
    205     for (TrackersByTitle::const_iterator itr = trackers_by_title.begin();
    206          itr != trackers_by_title.end(); ++itr) {
    207       if (itr->second.has_active())
    208         ++count;
    209     }
    210 
    211     return count;
    212   }
    213 
    214   bool IsAppRegistered(const std::string& app_id) {
    215     TrackerSet trackers;
    216     if (!metadata_database_->FindTrackersByParentAndTitle(
    217             kSyncRootTrackerID, app_id, &trackers))
    218       return false;
    219     return trackers.has_active();
    220   }
    221 
    222   size_t CountRemoteFileInSyncRoot() {
    223     ScopedVector<google_apis::ResourceEntry> files;
    224     EXPECT_EQ(google_apis::HTTP_SUCCESS,
    225               fake_drive_service_helper_->ListFilesInFolder(
    226                   sync_root_folder_id_, &files));
    227     return files.size();
    228   }
    229 
    230   bool HasRemoteAppRoot(const std::string& app_id) {
    231     TrackerSet files;
    232     if (!metadata_database_->FindTrackersByParentAndTitle(
    233             kSyncRootTrackerID, app_id, &files) ||
    234         !files.has_active())
    235       return false;
    236 
    237     std::string app_root_folder_id = files.active_tracker()->file_id();
    238     scoped_ptr<google_apis::ResourceEntry> entry;
    239     if (google_apis::HTTP_SUCCESS !=
    240         fake_drive_service_helper_->GetResourceEntry(
    241             app_root_folder_id, &entry))
    242       return false;
    243 
    244     return !entry->deleted();
    245   }
    246 
    247  private:
    248   std::string GenerateFileID() {
    249     return base::StringPrintf("file_id_%" PRId64, next_file_id_++);
    250   }
    251 
    252   std::string sync_root_folder_id_;
    253 
    254   int64 next_file_id_;
    255   int64 next_tracker_id_;
    256 
    257   content::TestBrowserThreadBundle browser_threads_;
    258   base::ScopedTempDir database_dir_;
    259 
    260   scoped_ptr<drive::FakeDriveService> fake_drive_service_;
    261   scoped_ptr<drive::DriveUploader> drive_uploader_;
    262   scoped_ptr<FakeDriveServiceHelper> fake_drive_service_helper_;
    263 
    264   scoped_ptr<MetadataDatabase> metadata_database_;
    265 
    266   DISALLOW_COPY_AND_ASSIGN(RegisterAppTaskTest);
    267 };
    268 
    269 TEST_F(RegisterAppTaskTest, AlreadyRegistered) {
    270   scoped_ptr<leveldb::DB> db(OpenLevelDB());
    271   ASSERT_TRUE(db);
    272   SetUpInitialData(db.get());
    273 
    274   const std::string kAppID = "app_id";
    275   SetUpRegisteredAppRoot(kAppID, db.get());
    276 
    277   CreateMetadataDatabase(db.Pass());
    278   EXPECT_EQ(SYNC_STATUS_OK, RunRegisterAppTask(kAppID));
    279 
    280   EXPECT_EQ(1u, CountRegisteredAppRoot());
    281   EXPECT_TRUE(IsAppRegistered(kAppID));
    282 }
    283 
    284 TEST_F(RegisterAppTaskTest, CreateAppFolder) {
    285   scoped_ptr<leveldb::DB> db(OpenLevelDB());
    286   ASSERT_TRUE(db);
    287   SetUpInitialData(db.get());
    288 
    289   const std::string kAppID = "app_id";
    290   CreateMetadataDatabase(db.Pass());
    291   RunRegisterAppTask(kAppID);
    292 
    293   EXPECT_EQ(1u, CountRegisteredAppRoot());
    294   EXPECT_TRUE(IsAppRegistered(kAppID));
    295 
    296   EXPECT_EQ(1u, CountRemoteFileInSyncRoot());
    297   EXPECT_TRUE(HasRemoteAppRoot(kAppID));
    298 }
    299 
    300 TEST_F(RegisterAppTaskTest, RegisterExistingFolder) {
    301   scoped_ptr<leveldb::DB> db(OpenLevelDB());
    302   ASSERT_TRUE(db);
    303   SetUpInitialData(db.get());
    304 
    305   const std::string kAppID = "app_id";
    306   SetUpUnregisteredAppRoot(kAppID, db.get());
    307 
    308   CreateMetadataDatabase(db.Pass());
    309   RunRegisterAppTask(kAppID);
    310 
    311   EXPECT_EQ(1u, CountRegisteredAppRoot());
    312   EXPECT_TRUE(IsAppRegistered(kAppID));
    313 }
    314 
    315 TEST_F(RegisterAppTaskTest, RegisterExistingFolder_MultipleCandidate) {
    316   scoped_ptr<leveldb::DB> db(OpenLevelDB());
    317   ASSERT_TRUE(db);
    318   SetUpInitialData(db.get());
    319 
    320   const std::string kAppID = "app_id";
    321   SetUpUnregisteredAppRoot(kAppID, db.get());
    322   SetUpUnregisteredAppRoot(kAppID, db.get());
    323 
    324   CreateMetadataDatabase(db.Pass());
    325   RunRegisterAppTask(kAppID);
    326 
    327   EXPECT_EQ(1u, CountRegisteredAppRoot());
    328   EXPECT_TRUE(IsAppRegistered(kAppID));
    329 }
    330 
    331 }  // namespace drive_backend
    332 }  // namespace sync_file_system
    333