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/chromeos/drive/change_list_loader.h" 6 7#include "base/files/scoped_temp_dir.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/prefs/testing_pref_service.h" 10#include "base/run_loop.h" 11#include "chrome/browser/chromeos/drive/change_list_loader_observer.h" 12#include "chrome/browser/chromeos/drive/change_list_processor.h" 13#include "chrome/browser/chromeos/drive/file_cache.h" 14#include "chrome/browser/chromeos/drive/file_system_util.h" 15#include "chrome/browser/chromeos/drive/job_scheduler.h" 16#include "chrome/browser/chromeos/drive/resource_metadata.h" 17#include "chrome/browser/chromeos/drive/test_util.h" 18#include "chrome/browser/drive/fake_drive_service.h" 19#include "content/public/test/test_browser_thread_bundle.h" 20#include "google_apis/drive/test_util.h" 21#include "testing/gtest/include/gtest/gtest.h" 22 23namespace drive { 24namespace internal { 25 26class TestChangeListLoaderObserver : public ChangeListLoaderObserver { 27 public: 28 explicit TestChangeListLoaderObserver(ChangeListLoader* loader) 29 : loader_(loader), 30 load_from_server_complete_count_(0), 31 initial_load_complete_count_(0) { 32 loader_->AddObserver(this); 33 } 34 35 virtual ~TestChangeListLoaderObserver() { 36 loader_->RemoveObserver(this); 37 } 38 39 const std::set<base::FilePath>& changed_directories() const { 40 return changed_directories_; 41 } 42 void clear_changed_directories() { changed_directories_.clear(); } 43 44 int load_from_server_complete_count() const { 45 return load_from_server_complete_count_; 46 } 47 int initial_load_complete_count() const { 48 return initial_load_complete_count_; 49 } 50 51 // ChageListObserver overrides: 52 virtual void OnDirectoryChanged( 53 const base::FilePath& directory_path) OVERRIDE { 54 changed_directories_.insert(directory_path); 55 } 56 virtual void OnLoadFromServerComplete() OVERRIDE { 57 ++load_from_server_complete_count_; 58 } 59 virtual void OnInitialLoadComplete() OVERRIDE { 60 ++initial_load_complete_count_; 61 } 62 63 private: 64 ChangeListLoader* loader_; 65 std::set<base::FilePath> changed_directories_; 66 int load_from_server_complete_count_; 67 int initial_load_complete_count_; 68 69 DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver); 70}; 71 72class ChangeListLoaderTest : public testing::Test { 73 protected: 74 virtual void SetUp() OVERRIDE { 75 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 76 pref_service_.reset(new TestingPrefServiceSimple); 77 test_util::RegisterDrivePrefs(pref_service_->registry()); 78 79 drive_service_.reset(new FakeDriveService); 80 ASSERT_TRUE(drive_service_->LoadResourceListForWapi( 81 "gdata/root_feed.json")); 82 ASSERT_TRUE(drive_service_->LoadAccountMetadataForWapi( 83 "gdata/account_metadata.json")); 84 85 scheduler_.reset(new JobScheduler(pref_service_.get(), 86 drive_service_.get(), 87 base::MessageLoopProxy::current().get())); 88 metadata_storage_.reset(new ResourceMetadataStorage( 89 temp_dir_.path(), base::MessageLoopProxy::current().get())); 90 ASSERT_TRUE(metadata_storage_->Initialize()); 91 92 metadata_.reset(new ResourceMetadata( 93 metadata_storage_.get(), base::MessageLoopProxy::current().get())); 94 ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); 95 96 cache_.reset(new FileCache(metadata_storage_.get(), 97 temp_dir_.path(), 98 base::MessageLoopProxy::current().get(), 99 NULL /* free_disk_space_getter */)); 100 ASSERT_TRUE(cache_->Initialize()); 101 102 change_list_loader_.reset( 103 new ChangeListLoader(base::MessageLoopProxy::current().get(), 104 metadata_.get(), 105 scheduler_.get(), 106 drive_service_.get())); 107 } 108 109 // Adds a new file to the root directory of the service. 110 scoped_ptr<google_apis::ResourceEntry> AddNewFile(const std::string& title) { 111 google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR; 112 scoped_ptr<google_apis::ResourceEntry> entry; 113 drive_service_->AddNewFile( 114 "text/plain", 115 "content text", 116 drive_service_->GetRootResourceId(), 117 title, 118 false, // shared_with_me 119 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 120 base::RunLoop().RunUntilIdle(); 121 EXPECT_EQ(google_apis::HTTP_CREATED, error); 122 return entry.Pass(); 123 } 124 125 content::TestBrowserThreadBundle thread_bundle_; 126 base::ScopedTempDir temp_dir_; 127 scoped_ptr<TestingPrefServiceSimple> pref_service_; 128 scoped_ptr<FakeDriveService> drive_service_; 129 scoped_ptr<JobScheduler> scheduler_; 130 scoped_ptr<ResourceMetadataStorage, 131 test_util::DestroyHelperForTests> metadata_storage_; 132 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; 133 scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_; 134 scoped_ptr<ChangeListLoader> change_list_loader_; 135}; 136 137TEST_F(ChangeListLoaderTest, LoadIfNeeded) { 138 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 139 140 // Start initial load. 141 TestChangeListLoaderObserver observer(change_list_loader_.get()); 142 143 EXPECT_EQ(0, drive_service_->about_resource_load_count()); 144 145 FileError error = FILE_ERROR_FAILED; 146 change_list_loader_->LoadIfNeeded( 147 DirectoryFetchInfo(), 148 google_apis::test_util::CreateCopyResultCallback(&error)); 149 EXPECT_TRUE(change_list_loader_->IsRefreshing()); 150 base::RunLoop().RunUntilIdle(); 151 EXPECT_EQ(FILE_ERROR_OK, error); 152 153 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 154 EXPECT_LT(0, metadata_->GetLargestChangestamp()); 155 EXPECT_EQ(1, drive_service_->resource_list_load_count()); 156 EXPECT_EQ(1, drive_service_->about_resource_load_count()); 157 EXPECT_EQ(1, observer.initial_load_complete_count()); 158 EXPECT_EQ(1, observer.load_from_server_complete_count()); 159 EXPECT_TRUE(observer.changed_directories().empty()); 160 161 base::FilePath file_path = 162 util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); 163 ResourceEntry entry; 164 EXPECT_EQ(FILE_ERROR_OK, 165 metadata_->GetResourceEntryByPath(file_path, &entry)); 166 167 // Reload. This should result in no-op. 168 int64 previous_changestamp = metadata_->GetLargestChangestamp(); 169 int previous_resource_list_load_count = 170 drive_service_->resource_list_load_count(); 171 change_list_loader_->LoadIfNeeded( 172 DirectoryFetchInfo(), 173 google_apis::test_util::CreateCopyResultCallback(&error)); 174 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 175 base::RunLoop().RunUntilIdle(); 176 EXPECT_EQ(FILE_ERROR_OK, error); 177 178 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 179 // Cached value is used. 180 EXPECT_EQ(1, drive_service_->about_resource_load_count()); 181 EXPECT_EQ(previous_changestamp, metadata_->GetLargestChangestamp()); 182 EXPECT_EQ(previous_resource_list_load_count, 183 drive_service_->resource_list_load_count()); 184} 185 186TEST_F(ChangeListLoaderTest, LoadIfNeeded_LocalMetadataAvailable) { 187 // Prepare metadata. 188 FileError error = FILE_ERROR_FAILED; 189 change_list_loader_->LoadIfNeeded( 190 DirectoryFetchInfo(), 191 google_apis::test_util::CreateCopyResultCallback(&error)); 192 base::RunLoop().RunUntilIdle(); 193 EXPECT_EQ(FILE_ERROR_OK, error); 194 195 // Reset loader. 196 change_list_loader_.reset( 197 new ChangeListLoader(base::MessageLoopProxy::current().get(), 198 metadata_.get(), 199 scheduler_.get(), 200 drive_service_.get())); 201 202 // Add a file to the service. 203 scoped_ptr<google_apis::ResourceEntry> gdata_entry = AddNewFile("New File"); 204 ASSERT_TRUE(gdata_entry); 205 206 // Start loading. Because local metadata is available, the load results in 207 // returning FILE_ERROR_OK without fetching full list of resources. 208 const int previous_resource_list_load_count = 209 drive_service_->resource_list_load_count(); 210 TestChangeListLoaderObserver observer(change_list_loader_.get()); 211 212 change_list_loader_->LoadIfNeeded( 213 DirectoryFetchInfo(), 214 google_apis::test_util::CreateCopyResultCallback(&error)); 215 EXPECT_TRUE(change_list_loader_->IsRefreshing()); 216 base::RunLoop().RunUntilIdle(); 217 EXPECT_EQ(FILE_ERROR_OK, error); 218 EXPECT_EQ(previous_resource_list_load_count, 219 drive_service_->resource_list_load_count()); 220 EXPECT_EQ(1, observer.initial_load_complete_count()); 221 222 // Update should be checked by LoadIfNeeded(). 223 EXPECT_EQ(drive_service_->largest_changestamp(), 224 metadata_->GetLargestChangestamp()); 225 EXPECT_EQ(1, drive_service_->change_list_load_count()); 226 EXPECT_EQ(1, observer.load_from_server_complete_count()); 227 EXPECT_EQ(1U, observer.changed_directories().count( 228 util::GetDriveMyDriveRootPath())); 229 230 base::FilePath file_path = 231 util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title()); 232 ResourceEntry entry; 233 EXPECT_EQ(FILE_ERROR_OK, 234 metadata_->GetResourceEntryByPath(file_path, &entry)); 235} 236 237TEST_F(ChangeListLoaderTest, LoadIfNeeded_MyDrive) { 238 TestChangeListLoaderObserver observer(change_list_loader_.get()); 239 240 // Emulate the slowness of GetAllResourceList(). 241 drive_service_->set_never_return_all_resource_list(true); 242 243 // Load grand root. 244 FileError error = FILE_ERROR_FAILED; 245 change_list_loader_->LoadIfNeeded( 246 DirectoryFetchInfo(util::kDriveGrandRootLocalId, 0), 247 google_apis::test_util::CreateCopyResultCallback(&error)); 248 base::RunLoop().RunUntilIdle(); 249 EXPECT_EQ(FILE_ERROR_OK, error); 250 EXPECT_EQ(1U, observer.changed_directories().count( 251 util::GetDriveGrandRootPath())); 252 observer.clear_changed_directories(); 253 254 // GetAllResourceList() was called. 255 EXPECT_EQ(1, drive_service_->blocked_resource_list_load_count()); 256 257 // My Drive is present in the local metadata, but its child is not. 258 ResourceEntry entry; 259 EXPECT_EQ(FILE_ERROR_OK, 260 metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(), 261 &entry)); 262 const int64 mydrive_changestamp = 263 entry.directory_specific_info().changestamp(); 264 265 base::FilePath file_path = 266 util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt"); 267 EXPECT_EQ(FILE_ERROR_NOT_FOUND, 268 metadata_->GetResourceEntryByPath(file_path, &entry)); 269 270 // Load My Drive. 271 change_list_loader_->LoadIfNeeded( 272 DirectoryFetchInfo(drive_service_->GetRootResourceId(), 273 mydrive_changestamp), 274 google_apis::test_util::CreateCopyResultCallback(&error)); 275 base::RunLoop().RunUntilIdle(); 276 EXPECT_EQ(FILE_ERROR_OK, error); 277 EXPECT_EQ(1U, observer.changed_directories().count( 278 util::GetDriveMyDriveRootPath())); 279 280 // Now the file is present. 281 EXPECT_EQ(FILE_ERROR_OK, 282 metadata_->GetResourceEntryByPath(file_path, &entry)); 283} 284 285TEST_F(ChangeListLoaderTest, LoadIfNeeded_NewDirectories) { 286 // Make local metadata up to date. 287 FileError error = FILE_ERROR_FAILED; 288 change_list_loader_->LoadIfNeeded( 289 DirectoryFetchInfo(), 290 google_apis::test_util::CreateCopyResultCallback(&error)); 291 base::RunLoop().RunUntilIdle(); 292 EXPECT_EQ(FILE_ERROR_OK, error); 293 294 // Add a new file. 295 scoped_ptr<google_apis::ResourceEntry> file = AddNewFile("New File"); 296 ASSERT_TRUE(file); 297 298 // Emulate the slowness of GetAllResourceList(). 299 drive_service_->set_never_return_all_resource_list(true); 300 301 // Enter refreshing state. 302 FileError check_for_updates_error = FILE_ERROR_FAILED; 303 change_list_loader_->CheckForUpdates( 304 google_apis::test_util::CreateCopyResultCallback( 305 &check_for_updates_error)); 306 EXPECT_TRUE(change_list_loader_->IsRefreshing()); 307 308 // Load My Drive. 309 TestChangeListLoaderObserver observer(change_list_loader_.get()); 310 change_list_loader_->LoadIfNeeded( 311 DirectoryFetchInfo(drive_service_->GetRootResourceId(), 312 metadata_->GetLargestChangestamp()), 313 google_apis::test_util::CreateCopyResultCallback(&error)); 314 base::RunLoop().RunUntilIdle(); 315 EXPECT_EQ(FILE_ERROR_OK, error); 316 EXPECT_EQ(1U, observer.changed_directories().count( 317 util::GetDriveMyDriveRootPath())); 318 319 // The new file is present in the local metadata. 320 base::FilePath file_path = 321 util::GetDriveMyDriveRootPath().AppendASCII(file->title()); 322 ResourceEntry entry; 323 EXPECT_EQ(FILE_ERROR_OK, 324 metadata_->GetResourceEntryByPath(file_path, &entry)); 325} 326 327TEST_F(ChangeListLoaderTest, LoadIfNeeded_MultipleCalls) { 328 TestChangeListLoaderObserver observer(change_list_loader_.get()); 329 330 // Load grand root. 331 FileError error = FILE_ERROR_FAILED; 332 change_list_loader_->LoadIfNeeded( 333 DirectoryFetchInfo(util::kDriveGrandRootLocalId, 0), 334 google_apis::test_util::CreateCopyResultCallback(&error)); 335 336 // Load grand root again without waiting for the result. 337 FileError error2 = FILE_ERROR_FAILED; 338 change_list_loader_->LoadIfNeeded( 339 DirectoryFetchInfo(util::kDriveGrandRootLocalId, 0), 340 google_apis::test_util::CreateCopyResultCallback(&error2)); 341 base::RunLoop().RunUntilIdle(); 342 343 // Callback is called for each method call. 344 EXPECT_EQ(FILE_ERROR_OK, error); 345 EXPECT_EQ(FILE_ERROR_OK, error2); 346 347 // No duplicated resource list load and observer events. 348 EXPECT_EQ(1, drive_service_->resource_list_load_count()); 349 EXPECT_EQ(1, observer.initial_load_complete_count()); 350 EXPECT_EQ(1, observer.load_from_server_complete_count()); 351} 352 353TEST_F(ChangeListLoaderTest, CheckForUpdates) { 354 // CheckForUpdates() results in no-op before load. 355 FileError check_for_updates_error = FILE_ERROR_FAILED; 356 change_list_loader_->CheckForUpdates( 357 google_apis::test_util::CreateCopyResultCallback( 358 &check_for_updates_error)); 359 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 360 base::RunLoop().RunUntilIdle(); 361 EXPECT_EQ(FILE_ERROR_FAILED, 362 check_for_updates_error); // Callback was not run. 363 EXPECT_EQ(0, metadata_->GetLargestChangestamp()); 364 EXPECT_EQ(0, drive_service_->resource_list_load_count()); 365 EXPECT_EQ(0, drive_service_->about_resource_load_count()); 366 367 // Start initial load. 368 FileError load_error = FILE_ERROR_FAILED; 369 change_list_loader_->LoadIfNeeded( 370 DirectoryFetchInfo(), 371 google_apis::test_util::CreateCopyResultCallback(&load_error)); 372 EXPECT_TRUE(change_list_loader_->IsRefreshing()); 373 374 // CheckForUpdates() while loading. 375 change_list_loader_->CheckForUpdates( 376 google_apis::test_util::CreateCopyResultCallback( 377 &check_for_updates_error)); 378 379 base::RunLoop().RunUntilIdle(); 380 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 381 EXPECT_EQ(FILE_ERROR_OK, load_error); 382 EXPECT_EQ(FILE_ERROR_OK, check_for_updates_error); 383 EXPECT_LT(0, metadata_->GetLargestChangestamp()); 384 EXPECT_EQ(1, drive_service_->resource_list_load_count()); 385 386 int64 previous_changestamp = metadata_->GetLargestChangestamp(); 387 // CheckForUpdates() results in no update. 388 change_list_loader_->CheckForUpdates( 389 google_apis::test_util::CreateCopyResultCallback( 390 &check_for_updates_error)); 391 EXPECT_TRUE(change_list_loader_->IsRefreshing()); 392 base::RunLoop().RunUntilIdle(); 393 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 394 EXPECT_EQ(previous_changestamp, metadata_->GetLargestChangestamp()); 395 396 // Add a file to the service. 397 scoped_ptr<google_apis::ResourceEntry> gdata_entry = AddNewFile("New File"); 398 ASSERT_TRUE(gdata_entry); 399 400 // CheckForUpdates() results in update. 401 TestChangeListLoaderObserver observer(change_list_loader_.get()); 402 change_list_loader_->CheckForUpdates( 403 google_apis::test_util::CreateCopyResultCallback( 404 &check_for_updates_error)); 405 EXPECT_TRUE(change_list_loader_->IsRefreshing()); 406 base::RunLoop().RunUntilIdle(); 407 EXPECT_FALSE(change_list_loader_->IsRefreshing()); 408 EXPECT_LT(previous_changestamp, metadata_->GetLargestChangestamp()); 409 EXPECT_EQ(1, observer.load_from_server_complete_count()); 410 EXPECT_EQ(1U, observer.changed_directories().count( 411 util::GetDriveMyDriveRootPath())); 412 413 // The new file is found in the local metadata. 414 base::FilePath new_file_path = 415 util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title()); 416 ResourceEntry entry; 417 EXPECT_EQ(FILE_ERROR_OK, 418 metadata_->GetResourceEntryByPath(new_file_path, &entry)); 419} 420 421} // namespace internal 422} // namespace drive 423