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