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