| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 <string> | |
| 6 #include <vector> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/file_path.h" | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/json/json_file_value_serializer.h" | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/path_service.h" | |
| 15 #include "base/scoped_temp_dir.h" | |
| 16 #include "base/stringprintf.h" | |
| 17 #include "base/threading/sequenced_worker_pool.h" | |
| 18 #include "base/values.h" | |
| 19 #include "chrome/browser/chromeos/cros/cros_library.h" | |
| 20 #include "chrome/browser/chromeos/gdata/drive.pb.h" | |
| 21 #include "chrome/browser/chromeos/gdata/drive_api_parser.h" | |
| 22 #include "chrome/browser/chromeos/gdata/drive_webapps_registry.h" | |
| 23 #include "chrome/browser/chromeos/gdata/gdata_file_system.h" | |
| 24 #include "chrome/browser/chromeos/gdata/gdata_test_util.h" | |
| 25 #include "chrome/browser/chromeos/gdata/gdata_uploader.h" | |
| 26 #include "chrome/browser/chromeos/gdata/gdata_util.h" | |
| 27 #include "chrome/browser/chromeos/gdata/mock_directory_change_observer.h" | |
| 28 #include "chrome/browser/chromeos/gdata/mock_drive_cache_observer.h" | |
| 29 #include "chrome/browser/chromeos/gdata/mock_drive_service.h" | |
| 30 #include "chrome/common/chrome_paths.h" | |
| 31 #include "chrome/test/base/testing_profile.h" | |
| 32 #include "content/public/browser/browser_thread.h" | |
| 33 #include "content/public/test/test_browser_thread.h" | |
| 34 #include "testing/gmock/include/gmock/gmock.h" | |
| 35 #include "testing/gtest/include/gtest/gtest.h" | |
| 36 | |
| 37 using ::testing::AtLeast; | |
| 38 using ::testing::Eq; | |
| 39 using ::testing::NotNull; | |
| 40 using ::testing::Return; | |
| 41 using ::testing::StrictMock; | |
| 42 using ::testing::_; | |
| 43 | |
| 44 namespace gdata { | |
| 45 namespace { | |
| 46 | |
| 47 const char kSymLinkToDevNull[] = "/dev/null"; | |
| 48 | |
| 49 const int64 kLotsOfSpace = kMinFreeSpace * 10; | |
| 50 | |
| 51 struct SearchResultPair { | |
| 52 const char* path; | |
| 53 const bool is_directory; | |
| 54 }; | |
| 55 | |
| 56 // Callback to GDataFileSystem::Search used in ContentSearch tests. | |
| 57 // Verifies returned vector of results. | |
| 58 void DriveSearchCallback( | |
| 59 MessageLoop* message_loop, | |
| 60 const SearchResultPair* expected_results, | |
| 61 size_t expected_results_size, | |
| 62 DriveFileError error, | |
| 63 const GURL& next_feed, | |
| 64 scoped_ptr<std::vector<SearchResultInfo> > results) { | |
| 65 ASSERT_TRUE(results.get()); | |
| 66 ASSERT_EQ(expected_results_size, results->size()); | |
| 67 | |
| 68 for (size_t i = 0; i < results->size(); i++) { | |
| 69 EXPECT_EQ(FilePath(expected_results[i].path), | |
| 70 results->at(i).path); | |
| 71 EXPECT_EQ(expected_results[i].is_directory, | |
| 72 results->at(i).is_directory); | |
| 73 } | |
| 74 | |
| 75 message_loop->Quit(); | |
| 76 } | |
| 77 | |
| 78 // Action used to set mock expectations for | |
| 79 // DriveServiceInterface::GetDocumentEntry(). | |
| 80 ACTION_P2(MockGetDocumentEntry, status, value) { | |
| 81 base::MessageLoopProxy::current()->PostTask(FROM_HERE, | |
| 82 base::Bind(arg1, status, base::Passed(value))); | |
| 83 } | |
| 84 | |
| 85 // Action used to set mock expectations for | |
| 86 // GDataUploaderInterface::UploadExistingFile(). | |
| 87 ACTION_P4(MockUploadExistingFile, | |
| 88 error, gdata_path, local_file_path, document_entry) { | |
| 89 scoped_ptr<UploadFileInfo> upload_file_info(new UploadFileInfo); | |
| 90 upload_file_info->gdata_path = gdata_path; | |
| 91 upload_file_info->file_path = local_file_path; | |
| 92 upload_file_info->entry.reset(document_entry); | |
| 93 base::MessageLoopProxy::current()->PostTask(FROM_HERE, | |
| 94 base::Bind(arg5, error, base::Passed(&upload_file_info))); | |
| 95 | |
| 96 const int kUploadId = 123; | |
| 97 return kUploadId; | |
| 98 } | |
| 99 | |
| 100 // Action used to set mock expectations for | |
| 101 // GDataFileSystem::CopyDocument(). | |
| 102 ACTION_P2(MockCopyDocument, status, value) { | |
| 103 base::MessageLoopProxy::current()->PostTask( | |
| 104 FROM_HERE, | |
| 105 base::Bind(arg2, status, base::Passed(value))); | |
| 106 } | |
| 107 | |
| 108 // Returns the absolute path for a test file stored under | |
| 109 // chrome/test/data/chromeos/gdata. | |
| 110 FilePath GetTestFilePath(const FilePath::StringType& base_name) { | |
| 111 FilePath path; | |
| 112 std::string error; | |
| 113 PathService::Get(chrome::DIR_TEST_DATA, &path); | |
| 114 path = path.AppendASCII("chromeos") | |
| 115 .AppendASCII("gdata") | |
| 116 .AppendASCII(base_name.c_str()); | |
| 117 EXPECT_TRUE(file_util::PathExists(path)) << | |
| 118 "Couldn't find " << path.value(); | |
| 119 return path; | |
| 120 } | |
| 121 | |
| 122 // Loads a test JSON file as a base::Value. | |
| 123 base::Value* LoadJSONFile(const std::string& base_name) { | |
| 124 FilePath path = GetTestFilePath(base_name); | |
| 125 | |
| 126 std::string error; | |
| 127 JSONFileValueSerializer serializer(path); | |
| 128 base::Value* value = serializer.Deserialize(NULL, &error); | |
| 129 EXPECT_TRUE(value) << | |
| 130 "Parse error " << path.value() << ": " << error; | |
| 131 return value; | |
| 132 } | |
| 133 | |
| 134 // Counts the number of files (not directories) in |entries|. | |
| 135 int CountFiles(const DriveEntryProtoVector& entries) { | |
| 136 int num_files = 0; | |
| 137 for (size_t i = 0; i < entries.size(); ++i) { | |
| 138 if (!entries[i].file_info().is_directory()) | |
| 139 ++num_files; | |
| 140 } | |
| 141 return num_files; | |
| 142 } | |
| 143 | |
| 144 } // namespace | |
| 145 | |
| 146 class MockFreeDiskSpaceGetter : public FreeDiskSpaceGetterInterface { | |
| 147 public: | |
| 148 virtual ~MockFreeDiskSpaceGetter() {} | |
| 149 MOCK_CONST_METHOD0(AmountOfFreeDiskSpace, int64()); | |
| 150 }; | |
| 151 | |
| 152 class MockGDataUploader : public GDataUploaderInterface { | |
| 153 public: | |
| 154 virtual ~MockGDataUploader() {} | |
| 155 // This function is not mockable by gmock. | |
| 156 virtual int UploadNewFile( | |
| 157 scoped_ptr<UploadFileInfo> upload_file_info) OVERRIDE { | |
| 158 // Set a document entry for an uploaded file. | |
| 159 // Used for TransferFileFromLocalToRemote_RegularFile test. | |
| 160 scoped_ptr<base::Value> value(LoadJSONFile("uploaded_file.json")); | |
| 161 scoped_ptr<DocumentEntry> document_entry( | |
| 162 DocumentEntry::ExtractAndParse(*value)); | |
| 163 upload_file_info->entry = document_entry.Pass(); | |
| 164 | |
| 165 // Run the completion callback. | |
| 166 const UploadFileInfo::UploadCompletionCallback callback = | |
| 167 upload_file_info->completion_callback; | |
| 168 if (!callback.is_null()) | |
| 169 callback.Run(DRIVE_FILE_OK, upload_file_info.Pass()); | |
| 170 | |
| 171 const int kUploadId = 123; | |
| 172 return kUploadId; | |
| 173 } | |
| 174 | |
| 175 // This function is not mockable by gmock. | |
| 176 virtual int StreamExistingFile( | |
| 177 scoped_ptr<UploadFileInfo> upload_file_info) OVERRIDE { return 0; } | |
| 178 | |
| 179 MOCK_METHOD6(UploadExistingFile, | |
| 180 int(const GURL& upload_location, | |
| 181 const FilePath& gdata_file_path, | |
| 182 const FilePath& local_file_path, | |
| 183 int64 file_size, | |
| 184 const std::string& content_type, | |
| 185 const UploadFileInfo::UploadCompletionCallback& callback)); | |
| 186 | |
| 187 MOCK_METHOD2(UpdateUpload, void(int upload_id, | |
| 188 content::DownloadItem* download)); | |
| 189 MOCK_CONST_METHOD1(GetUploadedBytes, int64(int upload_id)); | |
| 190 }; | |
| 191 | |
| 192 class MockDriveWebAppsRegistry : public DriveWebAppsRegistryInterface { | |
| 193 public: | |
| 194 virtual ~MockDriveWebAppsRegistry() {} | |
| 195 | |
| 196 MOCK_METHOD3(GetWebAppsForFile, void(const FilePath& file, | |
| 197 const std::string& mime_type, | |
| 198 ScopedVector<DriveWebAppInfo>* apps)); | |
| 199 MOCK_METHOD1(GetExtensionsForWebStoreApp, | |
| 200 std::set<std::string>(const std::string& web_store_id)); | |
| 201 MOCK_METHOD1(UpdateFromFeed, void(const AccountMetadataFeed& metadata)); | |
| 202 MOCK_METHOD1(UpdateFromApplicationList, void(const AppList& applist)); | |
| 203 }; | |
| 204 | |
| 205 class GDataFileSystemTest : public testing::Test { | |
| 206 protected: | |
| 207 GDataFileSystemTest() | |
| 208 : ui_thread_(content::BrowserThread::UI, &message_loop_), | |
| 209 io_thread_(content::BrowserThread::IO), | |
| 210 cache_(NULL), | |
| 211 file_system_(NULL), | |
| 212 mock_drive_service_(NULL), | |
| 213 mock_webapps_registry_(NULL), | |
| 214 num_callback_invocations_(0), | |
| 215 expected_error_(DRIVE_FILE_OK), | |
| 216 expected_cache_state_(0), | |
| 217 expected_sub_dir_type_(DriveCache::CACHE_TYPE_META), | |
| 218 expected_success_(true), | |
| 219 expect_outgoing_symlink_(false), | |
| 220 root_feed_changestamp_(0) { | |
| 221 } | |
| 222 | |
| 223 virtual void SetUp() OVERRIDE { | |
| 224 chromeos::CrosLibrary::Initialize(true /* use_stub */); | |
| 225 io_thread_.StartIOThread(); | |
| 226 | |
| 227 profile_.reset(new TestingProfile); | |
| 228 | |
| 229 callback_helper_ = new CallbackHelper; | |
| 230 | |
| 231 // Allocate and keep a pointer to the mock, and inject it into the | |
| 232 // GDataFileSystem object, which will own the mock object. | |
| 233 mock_drive_service_ = new StrictMock<MockDriveService>; | |
| 234 | |
| 235 EXPECT_CALL(*mock_drive_service_, Initialize(profile_.get())).Times(1); | |
| 236 | |
| 237 // Likewise, this will be owned by GDataFileSystem. | |
| 238 mock_free_disk_space_checker_ = new StrictMock<MockFreeDiskSpaceGetter>; | |
| 239 SetFreeDiskSpaceGetterForTesting(mock_free_disk_space_checker_); | |
| 240 | |
| 241 scoped_refptr<base::SequencedWorkerPool> pool = | |
| 242 content::BrowserThread::GetBlockingPool(); | |
| 243 blocking_task_runner_ = | |
| 244 pool->GetSequencedTaskRunner(pool->GetSequenceToken()); | |
| 245 | |
| 246 cache_ = DriveCache::CreateDriveCacheOnUIThread( | |
| 247 DriveCache::GetCacheRootPath(profile_.get()), blocking_task_runner_); | |
| 248 | |
| 249 mock_uploader_.reset(new StrictMock<MockGDataUploader>); | |
| 250 mock_webapps_registry_.reset(new StrictMock<MockDriveWebAppsRegistry>); | |
| 251 | |
| 252 ASSERT_FALSE(file_system_); | |
| 253 file_system_ = new GDataFileSystem(profile_.get(), | |
| 254 cache_, | |
| 255 mock_drive_service_, | |
| 256 mock_uploader_.get(), | |
| 257 mock_webapps_registry_.get(), | |
| 258 blocking_task_runner_); | |
| 259 | |
| 260 mock_cache_observer_.reset(new StrictMock<MockDriveCacheObserver>); | |
| 261 cache_->AddObserver(mock_cache_observer_.get()); | |
| 262 | |
| 263 mock_directory_observer_.reset(new StrictMock<MockDirectoryChangeObserver>); | |
| 264 file_system_->AddObserver(mock_directory_observer_.get()); | |
| 265 | |
| 266 file_system_->Initialize(); | |
| 267 cache_->RequestInitializeOnUIThreadForTesting(); | |
| 268 test_util::RunBlockingPoolTask(); | |
| 269 } | |
| 270 | |
| 271 virtual void TearDown() OVERRIDE { | |
| 272 ASSERT_TRUE(file_system_); | |
| 273 EXPECT_CALL(*mock_drive_service_, CancelAll()).Times(1); | |
| 274 delete file_system_; | |
| 275 file_system_ = NULL; | |
| 276 delete mock_drive_service_; | |
| 277 mock_drive_service_ = NULL; | |
| 278 SetFreeDiskSpaceGetterForTesting(NULL); | |
| 279 cache_->DestroyOnUIThread(); | |
| 280 // The cache destruction requires to post a task to the blocking pool. | |
| 281 test_util::RunBlockingPoolTask(); | |
| 282 | |
| 283 profile_.reset(NULL); | |
| 284 chromeos::CrosLibrary::Shutdown(); | |
| 285 } | |
| 286 | |
| 287 // Loads test json file as root ("/drive") element. | |
| 288 void LoadRootFeedDocument(const std::string& filename) { | |
| 289 LoadChangeFeed(filename, 0); | |
| 290 } | |
| 291 | |
| 292 void LoadChangeFeed(const std::string& filename, | |
| 293 int largest_changestamp) { | |
| 294 std::string error; | |
| 295 scoped_ptr<Value> document(LoadJSONFile(filename)); | |
| 296 ASSERT_TRUE(document.get()); | |
| 297 ASSERT_TRUE(document->GetType() == Value::TYPE_DICTIONARY); | |
| 298 scoped_ptr<DocumentFeed> document_feed( | |
| 299 DocumentFeed::ExtractAndParse(*document)); | |
| 300 ASSERT_TRUE(document_feed.get()); | |
| 301 std::vector<DocumentFeed*> feed_list; | |
| 302 feed_list.push_back(document_feed.get()); | |
| 303 ASSERT_TRUE(UpdateContent(feed_list, largest_changestamp)); | |
| 304 } | |
| 305 | |
| 306 void AddDirectoryFromFile(const FilePath& directory_path, | |
| 307 const std::string& filename) { | |
| 308 std::string error; | |
| 309 scoped_ptr<Value> atom(LoadJSONFile(filename)); | |
| 310 ASSERT_TRUE(atom.get()); | |
| 311 ASSERT_TRUE(atom->GetType() == Value::TYPE_DICTIONARY); | |
| 312 | |
| 313 DictionaryValue* dict_value = NULL; | |
| 314 Value* entry_value = NULL; | |
| 315 ASSERT_TRUE(atom->GetAsDictionary(&dict_value)); | |
| 316 ASSERT_TRUE(dict_value->Get("entry", &entry_value)); | |
| 317 | |
| 318 DictionaryValue* entry_dict = NULL; | |
| 319 ASSERT_TRUE(entry_value->GetAsDictionary(&entry_dict)); | |
| 320 | |
| 321 // Tweak entry title to match the last segment of the directory path | |
| 322 // (new directory name). | |
| 323 std::vector<FilePath::StringType> dir_parts; | |
| 324 directory_path.GetComponents(&dir_parts); | |
| 325 entry_dict->SetString("title.$t", dir_parts[dir_parts.size() - 1]); | |
| 326 | |
| 327 ASSERT_EQ(file_system_->AddNewDirectory(directory_path.DirName(), | |
| 328 entry_value), | |
| 329 DRIVE_FILE_OK) | |
| 330 << "Failed adding " | |
| 331 << directory_path.DirName().value(); | |
| 332 } | |
| 333 | |
| 334 // Updates the content of directory under |directory_path| with parsed feed | |
| 335 // |value|. | |
| 336 bool UpdateContent(const std::vector<DocumentFeed*>& list, | |
| 337 int largest_changestamp) { | |
| 338 GURL unused; | |
| 339 return file_system_->UpdateFromFeedForTesting( | |
| 340 list, | |
| 341 largest_changestamp, | |
| 342 root_feed_changestamp_++) == DRIVE_FILE_OK; | |
| 343 } | |
| 344 | |
| 345 bool RemoveEntry(const FilePath& file_path) { | |
| 346 return file_system_->RemoveEntryAndCacheLocally(file_path) == | |
| 347 DRIVE_FILE_OK; | |
| 348 } | |
| 349 | |
| 350 FilePath GetCachePathForFile(const std::string& resource_id, | |
| 351 const std::string& md5) { | |
| 352 return cache_->GetCacheFilePath(resource_id, | |
| 353 md5, | |
| 354 DriveCache::CACHE_TYPE_TMP, | |
| 355 DriveCache::CACHED_FILE_FROM_SERVER); | |
| 356 } | |
| 357 | |
| 358 // Gets entry info by path synchronously. | |
| 359 scoped_ptr<DriveEntryProto> GetEntryInfoByPathSync( | |
| 360 const FilePath& file_path) { | |
| 361 file_system_->GetEntryInfoByPath( | |
| 362 file_path, | |
| 363 base::Bind(&CallbackHelper::GetEntryInfoCallback, | |
| 364 callback_helper_.get())); | |
| 365 test_util::RunBlockingPoolTask(); | |
| 366 | |
| 367 return callback_helper_->entry_proto_.Pass(); | |
| 368 } | |
| 369 | |
| 370 // Gets directory info by path synchronously. | |
| 371 scoped_ptr<DriveEntryProtoVector> ReadDirectoryByPathSync( | |
| 372 const FilePath& file_path) { | |
| 373 file_system_->ReadDirectoryByPath( | |
| 374 file_path, | |
| 375 base::Bind(&CallbackHelper::ReadDirectoryCallback, | |
| 376 callback_helper_.get())); | |
| 377 test_util::RunBlockingPoolTask(); | |
| 378 | |
| 379 return callback_helper_->directory_entries_.Pass(); | |
| 380 } | |
| 381 | |
| 382 // Returns true if an entry exists at |file_path|. | |
| 383 bool EntryExists(const FilePath& file_path) { | |
| 384 return GetEntryInfoByPathSync(file_path).get(); | |
| 385 } | |
| 386 | |
| 387 | |
| 388 // Gets the resource ID of |file_path|. Returns an empty string if not found. | |
| 389 std::string GetResourceIdByPath(const FilePath& file_path) { | |
| 390 scoped_ptr<DriveEntryProto> entry_proto = | |
| 391 GetEntryInfoByPathSync(file_path); | |
| 392 if (entry_proto.get()) | |
| 393 return entry_proto->resource_id(); | |
| 394 else | |
| 395 return ""; | |
| 396 } | |
| 397 | |
| 398 // Helper function to call GetCacheEntry from origin thread. | |
| 399 bool GetCacheEntryFromOriginThread(const std::string& resource_id, | |
| 400 const std::string& md5, | |
| 401 DriveCacheEntry* cache_entry) { | |
| 402 bool result = false; | |
| 403 blocking_task_runner_->PostTask( | |
| 404 FROM_HERE, | |
| 405 base::Bind(&GDataFileSystemTest::GetCacheEntryFromOriginThreadInternal, | |
| 406 base::Unretained(this), | |
| 407 resource_id, | |
| 408 md5, | |
| 409 cache_entry, | |
| 410 &result)); | |
| 411 test_util::RunBlockingPoolTask(); | |
| 412 return result; | |
| 413 } | |
| 414 | |
| 415 // Used to implement GetCacheEntry. | |
| 416 void GetCacheEntryFromOriginThreadInternal( | |
| 417 const std::string& resource_id, | |
| 418 const std::string& md5, | |
| 419 DriveCacheEntry* cache_entry, | |
| 420 bool* result) { | |
| 421 *result = cache_->GetCacheEntry(resource_id, md5, cache_entry); | |
| 422 } | |
| 423 | |
| 424 // Returns true if the cache entry exists for the given resource ID and MD5. | |
| 425 bool CacheEntryExists(const std::string& resource_id, | |
| 426 const std::string& md5) { | |
| 427 DriveCacheEntry cache_entry; | |
| 428 return GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry); | |
| 429 } | |
| 430 | |
| 431 // Returns true if the cache file exists for the given resource ID and MD5. | |
| 432 bool CacheFileExists(const std::string& resource_id, | |
| 433 const std::string& md5) { | |
| 434 const FilePath file_path = cache_->GetCacheFilePath( | |
| 435 resource_id, | |
| 436 md5, | |
| 437 DriveCache::CACHE_TYPE_TMP, | |
| 438 DriveCache::CACHED_FILE_FROM_SERVER); | |
| 439 return file_util::PathExists(file_path); | |
| 440 } | |
| 441 | |
| 442 void TestStoreToCache( | |
| 443 const std::string& resource_id, | |
| 444 const std::string& md5, | |
| 445 const FilePath& source_path, | |
| 446 DriveFileError expected_error, | |
| 447 int expected_cache_state, | |
| 448 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
| 449 expected_error_ = expected_error; | |
| 450 expected_cache_state_ = expected_cache_state; | |
| 451 expected_sub_dir_type_ = expected_sub_dir_type; | |
| 452 | |
| 453 cache_->StoreOnUIThread( | |
| 454 resource_id, md5, source_path, | |
| 455 DriveCache::FILE_OPERATION_COPY, | |
| 456 base::Bind(&GDataFileSystemTest::VerifyCacheFileState, | |
| 457 base::Unretained(this))); | |
| 458 | |
| 459 test_util::RunBlockingPoolTask(); | |
| 460 } | |
| 461 | |
| 462 void TestPin( | |
| 463 const std::string& resource_id, | |
| 464 const std::string& md5, | |
| 465 DriveFileError expected_error, | |
| 466 int expected_cache_state, | |
| 467 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
| 468 expected_error_ = expected_error; | |
| 469 expected_cache_state_ = expected_cache_state; | |
| 470 expected_sub_dir_type_ = expected_sub_dir_type; | |
| 471 | |
| 472 cache_->PinOnUIThread( | |
| 473 resource_id, md5, | |
| 474 base::Bind(&GDataFileSystemTest::VerifyCacheFileState, | |
| 475 base::Unretained(this))); | |
| 476 | |
| 477 test_util::RunBlockingPoolTask(); | |
| 478 } | |
| 479 | |
| 480 void TestMarkDirty( | |
| 481 const std::string& resource_id, | |
| 482 const std::string& md5, | |
| 483 DriveFileError expected_error, | |
| 484 int expected_cache_state, | |
| 485 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
| 486 expected_error_ = expected_error; | |
| 487 expected_cache_state_ = expected_cache_state; | |
| 488 expected_sub_dir_type_ = expected_sub_dir_type; | |
| 489 expect_outgoing_symlink_ = false; | |
| 490 | |
| 491 cache_->MarkDirtyOnUIThread( | |
| 492 resource_id, md5, | |
| 493 base::Bind(&GDataFileSystemTest::VerifyMarkDirty, | |
| 494 base::Unretained(this))); | |
| 495 | |
| 496 test_util::RunBlockingPoolTask(); | |
| 497 } | |
| 498 | |
| 499 void VerifyMarkDirty(DriveFileError error, | |
| 500 const std::string& resource_id, | |
| 501 const std::string& md5, | |
| 502 const FilePath& cache_file_path) { | |
| 503 VerifyCacheFileState(error, resource_id, md5); | |
| 504 | |
| 505 // Verify filename of |cache_file_path|. | |
| 506 if (error == DRIVE_FILE_OK) { | |
| 507 FilePath base_name = cache_file_path.BaseName(); | |
| 508 EXPECT_EQ(util::EscapeCacheFileName(resource_id) + | |
| 509 FilePath::kExtensionSeparator + | |
| 510 "local", | |
| 511 base_name.value()); | |
| 512 } else { | |
| 513 EXPECT_TRUE(cache_file_path.empty()); | |
| 514 } | |
| 515 } | |
| 516 | |
| 517 void TestCommitDirty( | |
| 518 const std::string& resource_id, | |
| 519 const std::string& md5, | |
| 520 DriveFileError expected_error, | |
| 521 int expected_cache_state, | |
| 522 DriveCache::CacheSubDirectoryType expected_sub_dir_type) { | |
| 523 expected_error_ = expected_error; | |
| 524 expected_cache_state_ = expected_cache_state; | |
| 525 expected_sub_dir_type_ = expected_sub_dir_type; | |
| 526 expect_outgoing_symlink_ = true; | |
| 527 | |
| 528 cache_->CommitDirtyOnUIThread( | |
| 529 resource_id, md5, | |
| 530 base::Bind(&GDataFileSystemTest::VerifyCacheFileState, | |
| 531 base::Unretained(this))); | |
| 532 | |
| 533 test_util::RunBlockingPoolTask(); | |
| 534 } | |
| 535 | |
| 536 // Verify the file identified by |resource_id| and |md5| is in the expected | |
| 537 // cache state after |OpenFile|, that is, marked dirty and has no outgoing | |
| 538 // symlink, etc. | |
| 539 void VerifyCacheStateAfterOpenFile(DriveFileError error, | |
| 540 const std::string& resource_id, | |
| 541 const std::string& md5, | |
| 542 const FilePath& cache_file_path) { | |
| 543 expected_error_ = DRIVE_FILE_OK; | |
| 544 expected_cache_state_ = (test_util::TEST_CACHE_STATE_PRESENT | | |
| 545 test_util::TEST_CACHE_STATE_DIRTY | | |
| 546 test_util::TEST_CACHE_STATE_PERSISTENT); | |
| 547 expected_sub_dir_type_ = DriveCache::CACHE_TYPE_PERSISTENT; | |
| 548 expect_outgoing_symlink_ = false; | |
| 549 VerifyMarkDirty(error, resource_id, md5, cache_file_path); | |
| 550 } | |
| 551 | |
| 552 // Verify the file identified by |resource_id| and |md5| is in the expected | |
| 553 // cache state after |CloseFile|, that is, marked dirty and has an outgoing | |
| 554 // symlink, etc. | |
| 555 void VerifyCacheStateAfterCloseFile(DriveFileError error, | |
| 556 const std::string& resource_id, | |
| 557 const std::string& md5) { | |
| 558 expected_error_ = DRIVE_FILE_OK; | |
| 559 expected_cache_state_ = (test_util::TEST_CACHE_STATE_PRESENT | | |
| 560 test_util::TEST_CACHE_STATE_DIRTY | | |
| 561 test_util::TEST_CACHE_STATE_PERSISTENT); | |
| 562 expected_sub_dir_type_ = DriveCache::CACHE_TYPE_PERSISTENT; | |
| 563 expect_outgoing_symlink_ = true; | |
| 564 VerifyCacheFileState(error, resource_id, md5); | |
| 565 } | |
| 566 | |
| 567 void VerifyCacheFileState(DriveFileError error, | |
| 568 const std::string& resource_id, | |
| 569 const std::string& md5) { | |
| 570 ++num_callback_invocations_; | |
| 571 | |
| 572 EXPECT_EQ(expected_error_, error); | |
| 573 | |
| 574 // Verify cache map. | |
| 575 DriveCacheEntry cache_entry; | |
| 576 const bool cache_entry_found = | |
| 577 GetCacheEntryFromOriginThread(resource_id, md5, &cache_entry); | |
| 578 if (test_util::ToCacheEntry(expected_cache_state_).is_present() || | |
| 579 test_util::ToCacheEntry(expected_cache_state_).is_pinned()) { | |
| 580 ASSERT_TRUE(cache_entry_found); | |
| 581 EXPECT_TRUE(test_util::CacheStatesEqual( | |
| 582 test_util::ToCacheEntry(expected_cache_state_), | |
| 583 cache_entry)); | |
| 584 EXPECT_EQ(expected_sub_dir_type_, | |
| 585 DriveCache::GetSubDirectoryType(cache_entry)); | |
| 586 } else { | |
| 587 EXPECT_FALSE(cache_entry_found); | |
| 588 } | |
| 589 | |
| 590 // Verify actual cache file. | |
| 591 FilePath dest_path = cache_->GetCacheFilePath( | |
| 592 resource_id, | |
| 593 md5, | |
| 594 test_util::ToCacheEntry(expected_cache_state_).is_pinned() || | |
| 595 test_util::ToCacheEntry(expected_cache_state_).is_dirty() ? | |
| 596 DriveCache::CACHE_TYPE_PERSISTENT : | |
| 597 DriveCache::CACHE_TYPE_TMP, | |
| 598 test_util::ToCacheEntry(expected_cache_state_).is_dirty() ? | |
| 599 DriveCache::CACHED_FILE_LOCALLY_MODIFIED : | |
| 600 DriveCache::CACHED_FILE_FROM_SERVER); | |
| 601 bool exists = file_util::PathExists(dest_path); | |
| 602 if (test_util::ToCacheEntry(expected_cache_state_).is_present()) | |
| 603 EXPECT_TRUE(exists); | |
| 604 else | |
| 605 EXPECT_FALSE(exists); | |
| 606 | |
| 607 // Verify symlink in pinned dir. | |
| 608 FilePath symlink_path = cache_->GetCacheFilePath( | |
| 609 resource_id, | |
| 610 std::string(), | |
| 611 DriveCache::CACHE_TYPE_PINNED, | |
| 612 DriveCache::CACHED_FILE_FROM_SERVER); | |
| 613 // Check that pin symlink exists, without dereferencing to target path. | |
| 614 exists = file_util::IsLink(symlink_path); | |
| 615 if (test_util::ToCacheEntry(expected_cache_state_).is_pinned()) { | |
| 616 EXPECT_TRUE(exists); | |
| 617 FilePath target_path; | |
| 618 EXPECT_TRUE(file_util::ReadSymbolicLink(symlink_path, &target_path)); | |
| 619 if (test_util::ToCacheEntry(expected_cache_state_).is_present()) | |
| 620 EXPECT_EQ(dest_path, target_path); | |
| 621 else | |
| 622 EXPECT_EQ(kSymLinkToDevNull, target_path.value()); | |
| 623 } else { | |
| 624 EXPECT_FALSE(exists); | |
| 625 } | |
| 626 | |
| 627 // Verify symlink in outgoing dir. | |
| 628 symlink_path = cache_->GetCacheFilePath( | |
| 629 resource_id, | |
| 630 std::string(), | |
| 631 DriveCache::CACHE_TYPE_OUTGOING, | |
| 632 DriveCache::CACHED_FILE_FROM_SERVER); | |
| 633 // Check that outgoing symlink exists, without dereferencing to target path. | |
| 634 exists = file_util::IsLink(symlink_path); | |
| 635 if (expect_outgoing_symlink_ && | |
| 636 test_util::ToCacheEntry(expected_cache_state_).is_dirty()) { | |
| 637 EXPECT_TRUE(exists); | |
| 638 FilePath target_path; | |
| 639 EXPECT_TRUE(file_util::ReadSymbolicLink(symlink_path, &target_path)); | |
| 640 EXPECT_TRUE(target_path.value() != kSymLinkToDevNull); | |
| 641 if (test_util::ToCacheEntry(expected_cache_state_).is_present()) | |
| 642 EXPECT_EQ(dest_path, target_path); | |
| 643 } else { | |
| 644 EXPECT_FALSE(exists); | |
| 645 } | |
| 646 } | |
| 647 | |
| 648 void SetExpectationsForGetDocumentEntry(scoped_ptr<base::Value>* document, | |
| 649 const std::string& resource_id) { | |
| 650 EXPECT_CALL(*mock_drive_service_, GetDocumentEntry(resource_id, _)) | |
| 651 .WillOnce(MockGetDocumentEntry(gdata::HTTP_SUCCESS, document)); | |
| 652 } | |
| 653 | |
| 654 // Loads serialized proto file from GCache, and makes sure the root | |
| 655 // filesystem has a root at 'drive' | |
| 656 void TestLoadMetadataFromCache() { | |
| 657 file_system_->LoadRootFeedFromCacheForTesting(); | |
| 658 test_util::RunBlockingPoolTask(); | |
| 659 } | |
| 660 | |
| 661 // Creates a proto file representing a filesystem with directories: | |
| 662 // drive, drive/Dir1, drive/Dir1/SubDir2 | |
| 663 // and files | |
| 664 // drive/File1, drive/Dir1/File2, drive/Dir1/SubDir2/File3. | |
| 665 // Sets the changestamp to 654321, equal to that of "account_metadata.json" | |
| 666 // test data, indicating the cache is holding the latest file system info. | |
| 667 void SaveTestFileSystem() { | |
| 668 DriveRootDirectoryProto root; | |
| 669 root.set_version(kProtoVersion); | |
| 670 root.set_largest_changestamp(654321); | |
| 671 DriveDirectoryProto* root_dir = root.mutable_gdata_directory(); | |
| 672 DriveEntryProto* dir_base = root_dir->mutable_gdata_entry(); | |
| 673 PlatformFileInfoProto* platform_info = dir_base->mutable_file_info(); | |
| 674 dir_base->set_title("drive"); | |
| 675 dir_base->set_resource_id(kDriveRootDirectoryResourceId); | |
| 676 dir_base->set_upload_url("http://resumable-create-media/1"); | |
| 677 platform_info->set_is_directory(true); | |
| 678 | |
| 679 // drive/File1 | |
| 680 DriveEntryProto* file = root_dir->add_child_files(); | |
| 681 file->set_title("File1"); | |
| 682 file->set_resource_id("resource_id:File1"); | |
| 683 file->set_upload_url("http://resumable-edit-media/1"); | |
| 684 file->mutable_file_specific_info()->set_file_md5("md5"); | |
| 685 platform_info = file->mutable_file_info(); | |
| 686 platform_info->set_is_directory(false); | |
| 687 platform_info->set_size(1048576); | |
| 688 | |
| 689 // drive/Dir1 | |
| 690 DriveDirectoryProto* dir1 = root_dir->add_child_directories(); | |
| 691 dir_base = dir1->mutable_gdata_entry(); | |
| 692 dir_base->set_title("Dir1"); | |
| 693 dir_base->set_resource_id("resource_id:Dir1"); | |
| 694 dir_base->set_upload_url("http://resumable-create-media/2"); | |
| 695 platform_info = dir_base->mutable_file_info(); | |
| 696 platform_info->set_is_directory(true); | |
| 697 | |
| 698 // drive/Dir1/File2 | |
| 699 file = dir1->add_child_files(); | |
| 700 file->set_title("File2"); | |
| 701 file->set_resource_id("resource_id:File2"); | |
| 702 file->set_upload_url("http://resumable-edit-media/2"); | |
| 703 file->mutable_file_specific_info()->set_file_md5("md5"); | |
| 704 platform_info = file->mutable_file_info(); | |
| 705 platform_info->set_is_directory(false); | |
| 706 platform_info->set_size(555); | |
| 707 | |
| 708 // drive/Dir1/SubDir2 | |
| 709 DriveDirectoryProto* dir2 = dir1->add_child_directories(); | |
| 710 dir_base = dir2->mutable_gdata_entry(); | |
| 711 dir_base->set_title("SubDir2"); | |
| 712 dir_base->set_resource_id("resource_id:SubDir2"); | |
| 713 dir_base->set_upload_url("http://resumable-create-media/3"); | |
| 714 platform_info = dir_base->mutable_file_info(); | |
| 715 platform_info->set_is_directory(true); | |
| 716 | |
| 717 // drive/Dir1/SubDir2/File3 | |
| 718 file = dir2->add_child_files(); | |
| 719 file->set_title("File3"); | |
| 720 file->set_resource_id("resource_id:File3"); | |
| 721 file->set_upload_url("http://resumable-edit-media/3"); | |
| 722 file->mutable_file_specific_info()->set_file_md5("md5"); | |
| 723 platform_info = file->mutable_file_info(); | |
| 724 platform_info->set_is_directory(false); | |
| 725 platform_info->set_size(12345); | |
| 726 | |
| 727 // Write this proto out to GCache/vi/meta/file_system.pb | |
| 728 std::string serialized_proto; | |
| 729 ASSERT_TRUE(root.SerializeToString(&serialized_proto)); | |
| 730 ASSERT_TRUE(!serialized_proto.empty()); | |
| 731 | |
| 732 FilePath cache_dir_path = profile_->GetPath().Append( | |
| 733 FILE_PATH_LITERAL("GCache/v1/meta/")); | |
| 734 ASSERT_TRUE(file_util::CreateDirectory(cache_dir_path)); | |
| 735 const int file_size = static_cast<int>(serialized_proto.length()); | |
| 736 ASSERT_EQ(file_util::WriteFile(cache_dir_path.Append("file_system.pb"), | |
| 737 serialized_proto.data(), file_size), file_size); | |
| 738 } | |
| 739 | |
| 740 // Verifies that |file_path| is a valid JSON file for the hosted document | |
| 741 // associated with |entry| (i.e. |url| and |resource_id| match). | |
| 742 void VerifyHostedDocumentJSONFile(const DriveEntryProto& entry_proto, | |
| 743 const FilePath& file_path) { | |
| 744 std::string error; | |
| 745 JSONFileValueSerializer serializer(file_path); | |
| 746 scoped_ptr<Value> value(serializer.Deserialize(NULL, &error)); | |
| 747 ASSERT_TRUE(value.get()) << "Parse error " << file_path.value() | |
| 748 << ": " << error; | |
| 749 DictionaryValue* dict_value = NULL; | |
| 750 ASSERT_TRUE(value->GetAsDictionary(&dict_value)); | |
| 751 | |
| 752 std::string edit_url, resource_id; | |
| 753 EXPECT_TRUE(dict_value->GetString("url", &edit_url)); | |
| 754 EXPECT_TRUE(dict_value->GetString("resource_id", &resource_id)); | |
| 755 | |
| 756 EXPECT_EQ(entry_proto.file_specific_info().alternate_url(), | |
| 757 edit_url); | |
| 758 EXPECT_EQ(entry_proto.resource_id(), resource_id); | |
| 759 } | |
| 760 | |
| 761 // This is used as a helper for registering callbacks that need to be | |
| 762 // RefCountedThreadSafe, and a place where we can fetch results from various | |
| 763 // operations. | |
| 764 class CallbackHelper | |
| 765 : public base::RefCountedThreadSafe<CallbackHelper> { | |
| 766 public: | |
| 767 CallbackHelper() | |
| 768 : last_error_(DRIVE_FILE_OK), | |
| 769 quota_bytes_total_(0), | |
| 770 quota_bytes_used_(0), | |
| 771 entry_proto_(NULL) {} | |
| 772 | |
| 773 virtual void GetFileCallback(DriveFileError error, | |
| 774 const FilePath& file_path, | |
| 775 const std::string& mime_type, | |
| 776 DriveFileType file_type) { | |
| 777 last_error_ = error; | |
| 778 download_path_ = file_path; | |
| 779 mime_type_ = mime_type; | |
| 780 file_type_ = file_type; | |
| 781 } | |
| 782 | |
| 783 virtual void FileOperationCallback(DriveFileError error) { | |
| 784 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 785 | |
| 786 last_error_ = error; | |
| 787 } | |
| 788 | |
| 789 virtual void GetAvailableSpaceCallback(DriveFileError error, | |
| 790 int64 bytes_total, | |
| 791 int64 bytes_used) { | |
| 792 last_error_ = error; | |
| 793 quota_bytes_total_ = bytes_total; | |
| 794 quota_bytes_used_ = bytes_used; | |
| 795 } | |
| 796 | |
| 797 virtual void OpenFileCallback(DriveFileError error, | |
| 798 const FilePath& file_path) { | |
| 799 last_error_ = error; | |
| 800 opened_file_path_ = file_path; | |
| 801 MessageLoop::current()->Quit(); | |
| 802 } | |
| 803 | |
| 804 virtual void CloseFileCallback(DriveFileError error) { | |
| 805 last_error_ = error; | |
| 806 MessageLoop::current()->Quit(); | |
| 807 } | |
| 808 | |
| 809 virtual void GetEntryInfoCallback( | |
| 810 DriveFileError error, | |
| 811 scoped_ptr<DriveEntryProto> entry_proto) { | |
| 812 last_error_ = error; | |
| 813 entry_proto_ = entry_proto.Pass(); | |
| 814 } | |
| 815 | |
| 816 virtual void ReadDirectoryCallback( | |
| 817 DriveFileError error, | |
| 818 bool /* hide_hosted_documents */, | |
| 819 scoped_ptr<DriveEntryProtoVector> entries) { | |
| 820 last_error_ = error; | |
| 821 directory_entries_ = entries.Pass(); | |
| 822 } | |
| 823 | |
| 824 DriveFileError last_error_; | |
| 825 FilePath download_path_; | |
| 826 FilePath opened_file_path_; | |
| 827 std::string mime_type_; | |
| 828 DriveFileType file_type_; | |
| 829 int64 quota_bytes_total_; | |
| 830 int64 quota_bytes_used_; | |
| 831 scoped_ptr<DriveEntryProto> entry_proto_; | |
| 832 scoped_ptr<DriveEntryProtoVector> directory_entries_; | |
| 833 | |
| 834 protected: | |
| 835 virtual ~CallbackHelper() {} | |
| 836 | |
| 837 private: | |
| 838 friend class base::RefCountedThreadSafe<CallbackHelper>; | |
| 839 }; | |
| 840 | |
| 841 MessageLoopForUI message_loop_; | |
| 842 // The order of the test threads is important, do not change the order. | |
| 843 // See also content/browser/browser_thread_impl.cc. | |
| 844 content::TestBrowserThread ui_thread_; | |
| 845 content::TestBrowserThread io_thread_; | |
| 846 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; | |
| 847 scoped_ptr<TestingProfile> profile_; | |
| 848 scoped_refptr<CallbackHelper> callback_helper_; | |
| 849 DriveCache* cache_; | |
| 850 scoped_ptr<StrictMock<MockGDataUploader> > mock_uploader_; | |
| 851 GDataFileSystem* file_system_; | |
| 852 StrictMock<MockDriveService>* mock_drive_service_; | |
| 853 scoped_ptr<StrictMock<MockDriveWebAppsRegistry> > mock_webapps_registry_; | |
| 854 StrictMock<MockFreeDiskSpaceGetter>* mock_free_disk_space_checker_; | |
| 855 scoped_ptr<StrictMock<MockDriveCacheObserver> > mock_cache_observer_; | |
| 856 scoped_ptr<StrictMock<MockDirectoryChangeObserver> > mock_directory_observer_; | |
| 857 | |
| 858 int num_callback_invocations_; | |
| 859 DriveFileError expected_error_; | |
| 860 int expected_cache_state_; | |
| 861 DriveCache::CacheSubDirectoryType expected_sub_dir_type_; | |
| 862 bool expected_success_; | |
| 863 bool expect_outgoing_symlink_; | |
| 864 std::string expected_file_extension_; | |
| 865 int root_feed_changestamp_; | |
| 866 static bool cros_initialized_; | |
| 867 }; | |
| 868 | |
| 869 bool GDataFileSystemTest::cros_initialized_ = false; | |
| 870 | |
| 871 void AsyncInitializationCallback( | |
| 872 int* counter, | |
| 873 int expected_counter, | |
| 874 const FilePath& expected_file_path, | |
| 875 MessageLoop* message_loop, | |
| 876 DriveFileError error, | |
| 877 scoped_ptr<DriveEntryProto> entry_proto) { | |
| 878 ASSERT_EQ(DRIVE_FILE_OK, error); | |
| 879 ASSERT_TRUE(entry_proto.get()); | |
| 880 ASSERT_TRUE(entry_proto->file_info().is_directory()); | |
| 881 EXPECT_EQ(expected_file_path.value(), entry_proto->base_name()); | |
| 882 | |
| 883 (*counter)++; | |
| 884 if (*counter >= expected_counter) | |
| 885 message_loop->Quit(); | |
| 886 } | |
| 887 | |
| 888 TEST_F(GDataFileSystemTest, DuplicatedAsyncInitialization) { | |
| 889 int counter = 0; | |
| 890 GetEntryInfoCallback callback = base::Bind( | |
| 891 &AsyncInitializationCallback, | |
| 892 &counter, | |
| 893 2, | |
| 894 FilePath(FILE_PATH_LITERAL("drive")), | |
| 895 &message_loop_); | |
| 896 | |
| 897 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
| 898 EXPECT_CALL(*mock_drive_service_, | |
| 899 GetDocuments(Eq(GURL()), _, _, _, _)).Times(1); | |
| 900 | |
| 901 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
| 902 | |
| 903 file_system_->GetEntryInfoByPath( | |
| 904 FilePath(FILE_PATH_LITERAL("drive")), callback); | |
| 905 file_system_->GetEntryInfoByPath( | |
| 906 FilePath(FILE_PATH_LITERAL("drive")), callback); | |
| 907 message_loop_.Run(); // Wait to get our result | |
| 908 EXPECT_EQ(2, counter); | |
| 909 } | |
| 910 | |
| 911 TEST_F(GDataFileSystemTest, SearchRootDirectory) { | |
| 912 LoadRootFeedDocument("root_feed.json"); | |
| 913 | |
| 914 const FilePath kFilePath = FilePath(FILE_PATH_LITERAL("drive")); | |
| 915 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync( | |
| 916 FilePath(FILE_PATH_LITERAL(kFilePath))); | |
| 917 ASSERT_TRUE(entry.get()); | |
| 918 EXPECT_EQ(kDriveRootDirectoryResourceId, entry->resource_id()); | |
| 919 } | |
| 920 | |
| 921 TEST_F(GDataFileSystemTest, SearchExistingFile) { | |
| 922 LoadRootFeedDocument("root_feed.json"); | |
| 923 | |
| 924 const FilePath kFilePath = FilePath( | |
| 925 FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 926 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
| 927 ASSERT_TRUE(entry.get()); | |
| 928 EXPECT_EQ("file:2_file_resource_id", entry->resource_id()); | |
| 929 } | |
| 930 | |
| 931 TEST_F(GDataFileSystemTest, SearchExistingDocument) { | |
| 932 LoadRootFeedDocument("root_feed.json"); | |
| 933 | |
| 934 const FilePath kFilePath = FilePath( | |
| 935 FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
| 936 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
| 937 ASSERT_TRUE(entry.get()); | |
| 938 EXPECT_EQ("document:5_document_resource_id", entry->resource_id()); | |
| 939 } | |
| 940 | |
| 941 TEST_F(GDataFileSystemTest, SearchNonExistingFile) { | |
| 942 LoadRootFeedDocument("root_feed.json"); | |
| 943 | |
| 944 const FilePath kFilePath = FilePath( | |
| 945 FILE_PATH_LITERAL("drive/nonexisting.file")); | |
| 946 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
| 947 ASSERT_FALSE(entry.get()); | |
| 948 } | |
| 949 | |
| 950 TEST_F(GDataFileSystemTest, SearchEncodedFileNames) { | |
| 951 LoadRootFeedDocument("root_feed.json"); | |
| 952 | |
| 953 const FilePath kFilePath1 = FilePath( | |
| 954 FILE_PATH_LITERAL("drive/Slash / in file 1.txt")); | |
| 955 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath1); | |
| 956 ASSERT_FALSE(entry.get()); | |
| 957 | |
| 958 const FilePath kFilePath2 = FilePath::FromUTF8Unsafe( | |
| 959 "drive/Slash \xE2\x88\x95 in file 1.txt"); | |
| 960 entry = GetEntryInfoByPathSync(kFilePath2); | |
| 961 ASSERT_TRUE(entry.get()); | |
| 962 EXPECT_EQ("file:slash_file_resource_id", entry->resource_id()); | |
| 963 | |
| 964 const FilePath kFilePath3 = FilePath::FromUTF8Unsafe( | |
| 965 "drive/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt"); | |
| 966 entry = GetEntryInfoByPathSync(kFilePath3); | |
| 967 ASSERT_TRUE(entry.get()); | |
| 968 EXPECT_EQ("file:slash_subdir_file", entry->resource_id()); | |
| 969 } | |
| 970 | |
| 971 TEST_F(GDataFileSystemTest, SearchEncodedFileNamesLoadingRoot) { | |
| 972 LoadRootFeedDocument("root_feed.json"); | |
| 973 | |
| 974 const FilePath kFilePath1 = FilePath( | |
| 975 FILE_PATH_LITERAL("drive/Slash / in file 1.txt")); | |
| 976 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath1); | |
| 977 ASSERT_FALSE(entry.get()); | |
| 978 | |
| 979 const FilePath kFilePath2 = FilePath::FromUTF8Unsafe( | |
| 980 "drive/Slash \xE2\x88\x95 in file 1.txt"); | |
| 981 entry = GetEntryInfoByPathSync(kFilePath2); | |
| 982 ASSERT_TRUE(entry.get()); | |
| 983 EXPECT_EQ("file:slash_file_resource_id", entry->resource_id()); | |
| 984 | |
| 985 const FilePath kFilePath3 = FilePath::FromUTF8Unsafe( | |
| 986 "drive/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt"); | |
| 987 entry = GetEntryInfoByPathSync(kFilePath3); | |
| 988 ASSERT_TRUE(entry.get()); | |
| 989 EXPECT_EQ("file:slash_subdir_file", entry->resource_id()); | |
| 990 } | |
| 991 | |
| 992 TEST_F(GDataFileSystemTest, SearchDuplicateNames) { | |
| 993 LoadRootFeedDocument("root_feed.json"); | |
| 994 | |
| 995 const FilePath kFilePath1 = FilePath( | |
| 996 FILE_PATH_LITERAL("drive/Duplicate Name.txt")); | |
| 997 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath1); | |
| 998 ASSERT_TRUE(entry.get()); | |
| 999 EXPECT_EQ("file:3_file_resource_id", entry->resource_id()); | |
| 1000 | |
| 1001 const FilePath kFilePath2 = FilePath( | |
| 1002 FILE_PATH_LITERAL("drive/Duplicate Name (2).txt")); | |
| 1003 entry = GetEntryInfoByPathSync(kFilePath2); | |
| 1004 ASSERT_TRUE(entry.get()); | |
| 1005 EXPECT_EQ("file:4_file_resource_id", entry->resource_id()); | |
| 1006 } | |
| 1007 | |
| 1008 TEST_F(GDataFileSystemTest, SearchExistingDirectory) { | |
| 1009 LoadRootFeedDocument("root_feed.json"); | |
| 1010 | |
| 1011 const FilePath kFilePath = FilePath( | |
| 1012 FILE_PATH_LITERAL("drive/Directory 1")); | |
| 1013 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
| 1014 ASSERT_TRUE(entry.get()); | |
| 1015 ASSERT_EQ("folder:1_folder_resource_id", entry->resource_id()); | |
| 1016 } | |
| 1017 | |
| 1018 TEST_F(GDataFileSystemTest, SearchInSubdir) { | |
| 1019 LoadRootFeedDocument("root_feed.json"); | |
| 1020 | |
| 1021 const FilePath kFilePath = FilePath( | |
| 1022 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
| 1023 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
| 1024 ASSERT_TRUE(entry.get()); | |
| 1025 ASSERT_EQ("file:subdirectory_file_1_id", entry->resource_id()); | |
| 1026 } | |
| 1027 | |
| 1028 // Check the reconstruction of the directory structure from only the root feed. | |
| 1029 TEST_F(GDataFileSystemTest, SearchInSubSubdir) { | |
| 1030 LoadRootFeedDocument("root_feed.json"); | |
| 1031 | |
| 1032 const FilePath kFilePath = FilePath( | |
| 1033 FILE_PATH_LITERAL("drive/Directory 1/Sub Directory Folder/" | |
| 1034 "Sub Sub Directory Folder")); | |
| 1035 scoped_ptr<DriveEntryProto> entry = GetEntryInfoByPathSync(kFilePath); | |
| 1036 ASSERT_TRUE(entry.get()); | |
| 1037 ASSERT_EQ("folder:sub_sub_directory_folder_id", entry->resource_id()); | |
| 1038 } | |
| 1039 | |
| 1040 TEST_F(GDataFileSystemTest, FilePathTests) { | |
| 1041 LoadRootFeedDocument("root_feed.json"); | |
| 1042 | |
| 1043 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/File 1.txt")))); | |
| 1044 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Directory 1")))); | |
| 1045 EXPECT_TRUE(EntryExists( | |
| 1046 FilePath( | |
| 1047 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")))); | |
| 1048 } | |
| 1049 | |
| 1050 TEST_F(GDataFileSystemTest, ChangeFeed_AddAndDeleteFileInRoot) { | |
| 1051 int latest_changelog = 0; | |
| 1052 LoadRootFeedDocument("root_feed.json"); | |
| 1053 | |
| 1054 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1055 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(2); | |
| 1056 | |
| 1057 LoadChangeFeed("delta_file_added_in_root.json", ++latest_changelog); | |
| 1058 EXPECT_TRUE( | |
| 1059 EntryExists(FilePath(FILE_PATH_LITERAL("drive/Added file.gdoc")))); | |
| 1060 | |
| 1061 LoadChangeFeed("delta_file_deleted_in_root.json", ++latest_changelog); | |
| 1062 EXPECT_FALSE( | |
| 1063 EntryExists(FilePath(FILE_PATH_LITERAL("drive/Added file.gdoc")))); | |
| 1064 } | |
| 1065 | |
| 1066 | |
| 1067 TEST_F(GDataFileSystemTest, ChangeFeed_AddAndDeleteFileFromExistingDirectory) { | |
| 1068 int latest_changelog = 0; | |
| 1069 LoadRootFeedDocument("root_feed.json"); | |
| 1070 | |
| 1071 EXPECT_TRUE(EntryExists(FilePath( | |
| 1072 FILE_PATH_LITERAL("drive/Directory 1")))); | |
| 1073 | |
| 1074 // Add file to an existing directory. | |
| 1075 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1076 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1077 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1078 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1079 LoadChangeFeed("delta_file_added_in_directory.json", ++latest_changelog); | |
| 1080 EXPECT_TRUE(EntryExists(FilePath( | |
| 1081 FILE_PATH_LITERAL("drive/Directory 1/Added file.gdoc")))); | |
| 1082 | |
| 1083 // Remove that file from the directory. | |
| 1084 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1085 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1086 LoadChangeFeed("delta_file_deleted_in_directory.json", ++latest_changelog); | |
| 1087 EXPECT_TRUE(EntryExists(FilePath( | |
| 1088 FILE_PATH_LITERAL("drive/Directory 1")))); | |
| 1089 EXPECT_FALSE(EntryExists(FilePath( | |
| 1090 FILE_PATH_LITERAL("drive/Directory 1/Added file.gdoc")))); | |
| 1091 } | |
| 1092 | |
| 1093 TEST_F(GDataFileSystemTest, ChangeFeed_AddFileToNewDirectory) { | |
| 1094 int latest_changelog = 0; | |
| 1095 LoadRootFeedDocument("root_feed.json"); | |
| 1096 // Add file to a new directory. | |
| 1097 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1098 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1099 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1100 Eq(FilePath(FILE_PATH_LITERAL("drive/New Directory"))))).Times(1); | |
| 1101 | |
| 1102 LoadChangeFeed("delta_file_added_in_new_directory.json", ++latest_changelog); | |
| 1103 | |
| 1104 EXPECT_TRUE(EntryExists(FilePath( | |
| 1105 FILE_PATH_LITERAL("drive/New Directory")))); | |
| 1106 EXPECT_TRUE(EntryExists(FilePath( | |
| 1107 FILE_PATH_LITERAL("drive/New Directory/File in new dir.gdoc")))); | |
| 1108 } | |
| 1109 | |
| 1110 TEST_F(GDataFileSystemTest, ChangeFeed_AddFileToNewButDeletedDirectory) { | |
| 1111 int latest_changelog = 0; | |
| 1112 LoadRootFeedDocument("root_feed.json"); | |
| 1113 | |
| 1114 // This feed contains thw following updates: | |
| 1115 // 1) A new PDF file is added to a new directory | |
| 1116 // 2) but the new directory is marked "deleted" (i.e. moved to Trash) | |
| 1117 // Hence, the PDF file should be just ignored. | |
| 1118 LoadChangeFeed("delta_file_added_in_new_but_deleted_directory.json", | |
| 1119 ++latest_changelog); | |
| 1120 } | |
| 1121 | |
| 1122 TEST_F(GDataFileSystemTest, ChangeFeed_DirectoryMovedFromRootToDirectory) { | |
| 1123 int latest_changelog = 0; | |
| 1124 LoadRootFeedDocument("root_feed.json"); | |
| 1125 | |
| 1126 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1127 "drive/Directory 2")))); | |
| 1128 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1129 "drive/Directory 1")))); | |
| 1130 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1131 "drive/Directory 1/SubDirectory File 1.txt")))); | |
| 1132 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1133 "drive/Directory 1/Sub Directory Folder")))); | |
| 1134 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1135 "drive/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")))); | |
| 1136 | |
| 1137 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1138 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1139 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1140 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 2"))))).Times(1); | |
| 1141 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1142 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 2/Directory 1"))))) | |
| 1143 .Times(1); | |
| 1144 LoadChangeFeed("delta_dir_moved_from_root_to_directory.json", | |
| 1145 ++latest_changelog); | |
| 1146 | |
| 1147 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1148 "drive/Directory 2")))); | |
| 1149 EXPECT_FALSE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1150 "drive/Directory 1")))); | |
| 1151 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1152 "drive/Directory 2/Directory 1")))); | |
| 1153 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1154 "drive/Directory 2/Directory 1/SubDirectory File 1.txt")))); | |
| 1155 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1156 "drive/Directory 2/Directory 1/Sub Directory Folder")))); | |
| 1157 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1158 "drive/Directory 2/Directory 1/Sub Directory Folder/" | |
| 1159 "Sub Sub Directory Folder")))); | |
| 1160 } | |
| 1161 | |
| 1162 TEST_F(GDataFileSystemTest, ChangeFeed_FileMovedFromDirectoryToRoot) { | |
| 1163 int latest_changelog = 0; | |
| 1164 LoadRootFeedDocument("root_feed.json"); | |
| 1165 | |
| 1166 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1167 "drive/Directory 1")))); | |
| 1168 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1169 "drive/Directory 1/Sub Directory Folder")))); | |
| 1170 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1171 "drive/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")))); | |
| 1172 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1173 "drive/Directory 1/SubDirectory File 1.txt")))); | |
| 1174 | |
| 1175 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1176 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1177 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1178 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1179 LoadChangeFeed("delta_file_moved_from_directory_to_root.json", | |
| 1180 ++latest_changelog); | |
| 1181 | |
| 1182 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1183 "drive/Directory 1")))); | |
| 1184 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1185 "drive/Directory 1/Sub Directory Folder")))); | |
| 1186 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1187 "drive/Directory 1/Sub Directory Folder/Sub Sub Directory Folder")))); | |
| 1188 EXPECT_FALSE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1189 "drive/Directory 1/SubDirectory File 1.txt")))); | |
| 1190 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1191 "drive/SubDirectory File 1.txt")))); | |
| 1192 } | |
| 1193 | |
| 1194 TEST_F(GDataFileSystemTest, ChangeFeed_FileRenamedInDirectory) { | |
| 1195 int latest_changelog = 0; | |
| 1196 LoadRootFeedDocument("root_feed.json"); | |
| 1197 | |
| 1198 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1199 "drive/Directory 1")))); | |
| 1200 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1201 "drive/Directory 1/SubDirectory File 1.txt")))); | |
| 1202 | |
| 1203 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1204 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1205 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1206 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1207 LoadChangeFeed("delta_file_renamed_in_directory.json", | |
| 1208 ++latest_changelog); | |
| 1209 | |
| 1210 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1211 "drive/Directory 1")))); | |
| 1212 EXPECT_FALSE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1213 "drive/Directory 1/SubDirectory File 1.txt")))); | |
| 1214 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL( | |
| 1215 "drive/Directory 1/New SubDirectory File 1.txt")))); | |
| 1216 } | |
| 1217 | |
| 1218 TEST_F(GDataFileSystemTest, CachedFeedLoading) { | |
| 1219 SaveTestFileSystem(); | |
| 1220 TestLoadMetadataFromCache(); | |
| 1221 | |
| 1222 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/File1")))); | |
| 1223 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Dir1")))); | |
| 1224 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Dir1/File2")))); | |
| 1225 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/Dir1/SubDir2")))); | |
| 1226 EXPECT_TRUE(EntryExists( | |
| 1227 FilePath(FILE_PATH_LITERAL("drive/Dir1/SubDir2/File3")))); | |
| 1228 } | |
| 1229 | |
| 1230 TEST_F(GDataFileSystemTest, CachedFeadLoadingThenServerFeedLoading) { | |
| 1231 SaveTestFileSystem(); | |
| 1232 | |
| 1233 // SaveTestFileSystem and "account_metadata.json" have the same changestamp, | |
| 1234 // so no request for new feeds (i.e., call to GetDocuments) should happen. | |
| 1235 mock_drive_service_->set_account_metadata( | |
| 1236 LoadJSONFile("account_metadata.json")); | |
| 1237 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
| 1238 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
| 1239 EXPECT_CALL(*mock_drive_service_, GetDocuments(_, _, _, _, _)).Times(0); | |
| 1240 | |
| 1241 // Kicks loading of cached file system and query for server update. | |
| 1242 EXPECT_TRUE(EntryExists(FilePath(FILE_PATH_LITERAL("drive/File1")))); | |
| 1243 | |
| 1244 // Since the file system has verified that it holds the latest snapshot, | |
| 1245 // it should change its state to FROM_SERVER, which admits periodic refresh. | |
| 1246 // To test it, call CheckForUpdates and verify it does try to check updates. | |
| 1247 mock_drive_service_->set_account_metadata( | |
| 1248 LoadJSONFile("account_metadata.json")); | |
| 1249 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
| 1250 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
| 1251 | |
| 1252 file_system_->CheckForUpdates(); | |
| 1253 test_util::RunBlockingPoolTask(); | |
| 1254 } | |
| 1255 | |
| 1256 TEST_F(GDataFileSystemTest, TransferFileFromLocalToRemote_RegularFile) { | |
| 1257 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 1258 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
| 1259 | |
| 1260 LoadRootFeedDocument("root_feed.json"); | |
| 1261 | |
| 1262 // We'll add a file to the Drive root directory. | |
| 1263 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1264 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1265 | |
| 1266 FileOperationCallback callback = | |
| 1267 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1268 callback_helper_.get()); | |
| 1269 | |
| 1270 // Prepare a local file. | |
| 1271 ScopedTempDir temp_dir; | |
| 1272 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 1273 const FilePath local_src_file_path = temp_dir.path().Append("local.txt"); | |
| 1274 const std::string kContent = "hello"; | |
| 1275 file_util::WriteFile(local_src_file_path, kContent.data(), kContent.size()); | |
| 1276 | |
| 1277 // Confirm that the remote file does not exist. | |
| 1278 const FilePath remote_dest_file_path(FILE_PATH_LITERAL("drive/remote.txt")); | |
| 1279 EXPECT_FALSE(EntryExists(remote_dest_file_path)); | |
| 1280 | |
| 1281 // Transfer the local file to Drive. | |
| 1282 file_system_->TransferFileFromLocalToRemote( | |
| 1283 local_src_file_path, remote_dest_file_path, callback); | |
| 1284 test_util::RunBlockingPoolTask(); | |
| 1285 | |
| 1286 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1287 | |
| 1288 // Now the remote file should exist. | |
| 1289 EXPECT_TRUE(EntryExists(remote_dest_file_path)); | |
| 1290 } | |
| 1291 | |
| 1292 TEST_F(GDataFileSystemTest, TransferFileFromLocalToRemote_HostedDocument) { | |
| 1293 LoadRootFeedDocument("root_feed.json"); | |
| 1294 | |
| 1295 // Prepare a local file, which is a json file of a hosted document, which | |
| 1296 // matches "Document 1" in root_feed.json. | |
| 1297 ScopedTempDir temp_dir; | |
| 1298 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 1299 const FilePath local_src_file_path = temp_dir.path().Append("local.gdoc"); | |
| 1300 const std::string kEditUrl = | |
| 1301 "https://3_document_self_link/document:5_document_resource_id"; | |
| 1302 const std::string kResourceId = "document:5_document_resource_id"; | |
| 1303 const std::string kContent = | |
| 1304 base::StringPrintf("{\"url\": \"%s\", \"resource_id\": \"%s\"}", | |
| 1305 kEditUrl.c_str(), kResourceId.c_str()); | |
| 1306 file_util::WriteFile(local_src_file_path, kContent.data(), kContent.size()); | |
| 1307 | |
| 1308 // Confirm that the remote file does not exist. | |
| 1309 const FilePath remote_dest_file_path( | |
| 1310 FILE_PATH_LITERAL("drive/Directory 1/Document 1.gdoc")); | |
| 1311 EXPECT_FALSE(EntryExists(remote_dest_file_path)); | |
| 1312 | |
| 1313 // We'll add a file to "Directory 1" directory on Drive. | |
| 1314 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1315 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1316 | |
| 1317 // We'll copy a hosted document using CopyDocument. | |
| 1318 // ".gdoc" suffix should be stripped when copying. | |
| 1319 scoped_ptr<base::Value> document(LoadJSONFile("uploaded_document.json")); | |
| 1320 EXPECT_CALL(*mock_drive_service_, | |
| 1321 CopyDocument(kResourceId, | |
| 1322 FILE_PATH_LITERAL("Document 1"), | |
| 1323 _)) | |
| 1324 .WillOnce(MockCopyDocument(gdata::HTTP_SUCCESS, &document)); | |
| 1325 // We'll then add the hosted document to the destination directory. | |
| 1326 EXPECT_CALL(*mock_drive_service_, | |
| 1327 AddResourceToDirectory(_, _, _)).Times(1); | |
| 1328 | |
| 1329 FileOperationCallback callback = | |
| 1330 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1331 callback_helper_.get()); | |
| 1332 | |
| 1333 // Transfer the local file to Drive. | |
| 1334 file_system_->TransferFileFromLocalToRemote( | |
| 1335 local_src_file_path, remote_dest_file_path, callback); | |
| 1336 test_util::RunBlockingPoolTask(); | |
| 1337 | |
| 1338 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1339 | |
| 1340 // Now the remote file should exist. | |
| 1341 EXPECT_TRUE(EntryExists(remote_dest_file_path)); | |
| 1342 } | |
| 1343 | |
| 1344 TEST_F(GDataFileSystemTest, TransferFileFromRemoteToLocal_RegularFile) { | |
| 1345 LoadRootFeedDocument("root_feed.json"); | |
| 1346 | |
| 1347 FileOperationCallback callback = | |
| 1348 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1349 callback_helper_.get()); | |
| 1350 | |
| 1351 ScopedTempDir temp_dir; | |
| 1352 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 1353 FilePath local_dest_file_path = temp_dir.path().Append("local_copy.txt"); | |
| 1354 | |
| 1355 FilePath remote_src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1356 scoped_ptr<DriveEntryProto> file = GetEntryInfoByPathSync( | |
| 1357 remote_src_file_path); | |
| 1358 FilePath cache_file = GetCachePathForFile( | |
| 1359 file->resource_id(), | |
| 1360 file->file_specific_info().file_md5()); | |
| 1361 const int64 file_size = file->file_info().size(); | |
| 1362 | |
| 1363 // Pretend we have enough space. | |
| 1364 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 1365 .Times(2).WillRepeatedly(Return(file_size + kMinFreeSpace)); | |
| 1366 | |
| 1367 const std::string remote_src_file_data = "Test file data"; | |
| 1368 mock_drive_service_->set_file_data(new std::string(remote_src_file_data)); | |
| 1369 | |
| 1370 // Before Download starts metadata from server will be fetched. | |
| 1371 // We will read content url from the result. | |
| 1372 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 1373 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 1374 | |
| 1375 // The file is obtained with the mock DriveService. | |
| 1376 EXPECT_CALL(*mock_drive_service_, | |
| 1377 DownloadFile(remote_src_file_path, | |
| 1378 cache_file, | |
| 1379 GURL("https://file_content_url_changed/"), | |
| 1380 _, _)) | |
| 1381 .Times(1); | |
| 1382 | |
| 1383 file_system_->TransferFileFromRemoteToLocal( | |
| 1384 remote_src_file_path, local_dest_file_path, callback); | |
| 1385 test_util::RunBlockingPoolTask(); | |
| 1386 | |
| 1387 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1388 | |
| 1389 std::string cache_file_data; | |
| 1390 EXPECT_TRUE(file_util::ReadFileToString(cache_file, &cache_file_data)); | |
| 1391 EXPECT_EQ(remote_src_file_data, cache_file_data); | |
| 1392 | |
| 1393 std::string local_dest_file_data; | |
| 1394 EXPECT_TRUE(file_util::ReadFileToString(local_dest_file_path, | |
| 1395 &local_dest_file_data)); | |
| 1396 EXPECT_EQ(remote_src_file_data, local_dest_file_data); | |
| 1397 } | |
| 1398 | |
| 1399 TEST_F(GDataFileSystemTest, TransferFileFromRemoteToLocal_HostedDocument) { | |
| 1400 LoadRootFeedDocument("root_feed.json"); | |
| 1401 | |
| 1402 FileOperationCallback callback = | |
| 1403 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1404 callback_helper_.get()); | |
| 1405 | |
| 1406 ScopedTempDir temp_dir; | |
| 1407 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
| 1408 FilePath local_dest_file_path = temp_dir.path().Append("local_copy.txt"); | |
| 1409 FilePath remote_src_file_path(FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
| 1410 file_system_->TransferFileFromRemoteToLocal( | |
| 1411 remote_src_file_path, local_dest_file_path, callback); | |
| 1412 test_util::RunBlockingPoolTask(); | |
| 1413 | |
| 1414 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1415 | |
| 1416 scoped_ptr<DriveEntryProto> entry_proto = GetEntryInfoByPathSync( | |
| 1417 remote_src_file_path); | |
| 1418 ASSERT_TRUE(entry_proto.get()); | |
| 1419 VerifyHostedDocumentJSONFile(*entry_proto, local_dest_file_path); | |
| 1420 } | |
| 1421 | |
| 1422 TEST_F(GDataFileSystemTest, CopyNotExistingFile) { | |
| 1423 FilePath src_file_path(FILE_PATH_LITERAL("drive/Dummy file.txt")); | |
| 1424 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
| 1425 | |
| 1426 LoadRootFeedDocument("root_feed.json"); | |
| 1427 | |
| 1428 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1429 | |
| 1430 FileOperationCallback callback = | |
| 1431 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1432 callback_helper_.get()); | |
| 1433 | |
| 1434 file_system_->Copy(src_file_path, dest_file_path, callback); | |
| 1435 test_util::RunBlockingPoolTask(); | |
| 1436 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
| 1437 | |
| 1438 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1439 EXPECT_FALSE(EntryExists(dest_file_path)); | |
| 1440 } | |
| 1441 | |
| 1442 TEST_F(GDataFileSystemTest, CopyFileToNonExistingDirectory) { | |
| 1443 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1444 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Dummy")); | |
| 1445 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Dummy/Test.log")); | |
| 1446 | |
| 1447 LoadRootFeedDocument("root_feed.json"); | |
| 1448 | |
| 1449 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1450 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1451 src_file_path); | |
| 1452 ASSERT_TRUE(src_entry_proto.get()); | |
| 1453 std::string src_file_path_resource_id = | |
| 1454 src_entry_proto->resource_id(); | |
| 1455 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1456 | |
| 1457 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
| 1458 | |
| 1459 FileOperationCallback callback = | |
| 1460 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1461 callback_helper_.get()); | |
| 1462 | |
| 1463 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1464 test_util::RunBlockingPoolTask(); | |
| 1465 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
| 1466 | |
| 1467 EXPECT_TRUE(EntryExists(src_file_path)); | |
| 1468 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
| 1469 EXPECT_FALSE(EntryExists(dest_file_path)); | |
| 1470 } | |
| 1471 | |
| 1472 // Test the case where the parent of |dest_file_path| is an existing file, | |
| 1473 // not a directory. | |
| 1474 TEST_F(GDataFileSystemTest, CopyFileToInvalidPath) { | |
| 1475 FilePath src_file_path(FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
| 1476 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Duplicate Name.txt")); | |
| 1477 FilePath dest_file_path(FILE_PATH_LITERAL( | |
| 1478 "drive/Duplicate Name.txt/Document 1.gdoc")); | |
| 1479 | |
| 1480 LoadRootFeedDocument("root_feed.json"); | |
| 1481 | |
| 1482 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1483 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1484 src_file_path); | |
| 1485 ASSERT_TRUE(src_entry_proto.get()); | |
| 1486 std::string src_file_resource_id = | |
| 1487 src_entry_proto->resource_id(); | |
| 1488 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1489 | |
| 1490 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
| 1491 scoped_ptr<DriveEntryProto> dest_entry_proto = GetEntryInfoByPathSync( | |
| 1492 dest_parent_path); | |
| 1493 ASSERT_TRUE(dest_entry_proto.get()); | |
| 1494 | |
| 1495 FileOperationCallback callback = | |
| 1496 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1497 callback_helper_.get()); | |
| 1498 | |
| 1499 file_system_->Copy(src_file_path, dest_file_path, callback); | |
| 1500 test_util::RunBlockingPoolTask(); | |
| 1501 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_A_DIRECTORY, | |
| 1502 callback_helper_->last_error_); | |
| 1503 | |
| 1504 EXPECT_TRUE(EntryExists(src_file_path)); | |
| 1505 EXPECT_TRUE(EntryExists(src_file_path)); | |
| 1506 EXPECT_TRUE(EntryExists(dest_parent_path)); | |
| 1507 | |
| 1508 EXPECT_FALSE(EntryExists(dest_file_path)); | |
| 1509 } | |
| 1510 | |
| 1511 TEST_F(GDataFileSystemTest, RenameFile) { | |
| 1512 const FilePath src_file_path( | |
| 1513 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
| 1514 const FilePath src_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
| 1515 const FilePath dest_file_path( | |
| 1516 FILE_PATH_LITERAL("drive/Directory 1/Test.log")); | |
| 1517 | |
| 1518 LoadRootFeedDocument("root_feed.json"); | |
| 1519 | |
| 1520 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1521 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1522 src_file_path); | |
| 1523 ASSERT_TRUE(src_entry_proto.get()); | |
| 1524 std::string src_file_resource_id = | |
| 1525 src_entry_proto->resource_id(); | |
| 1526 | |
| 1527 EXPECT_CALL(*mock_drive_service_, | |
| 1528 RenameResource(GURL(src_entry_proto->edit_url()), | |
| 1529 FILE_PATH_LITERAL("Test.log"), _)); | |
| 1530 | |
| 1531 FileOperationCallback callback = | |
| 1532 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1533 callback_helper_.get()); | |
| 1534 | |
| 1535 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1536 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1537 | |
| 1538 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1539 test_util::RunBlockingPoolTask(); | |
| 1540 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1541 | |
| 1542 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1543 EXPECT_TRUE(EntryExists(dest_file_path)); | |
| 1544 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
| 1545 } | |
| 1546 | |
| 1547 TEST_F(GDataFileSystemTest, MoveFileFromRootToSubDirectory) { | |
| 1548 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1549 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
| 1550 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Directory 1/Test.log")); | |
| 1551 | |
| 1552 LoadRootFeedDocument("root_feed.json"); | |
| 1553 | |
| 1554 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1555 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1556 src_file_path); | |
| 1557 ASSERT_TRUE(src_entry_proto.get()); | |
| 1558 std::string src_file_resource_id = | |
| 1559 src_entry_proto->resource_id(); | |
| 1560 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1561 | |
| 1562 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
| 1563 scoped_ptr<DriveEntryProto> dest_parent_proto = GetEntryInfoByPathSync( | |
| 1564 dest_parent_path); | |
| 1565 ASSERT_TRUE(dest_parent_proto.get()); | |
| 1566 ASSERT_TRUE(dest_parent_proto->file_info().is_directory()); | |
| 1567 EXPECT_FALSE(dest_parent_proto->content_url().empty()); | |
| 1568 | |
| 1569 EXPECT_CALL(*mock_drive_service_, | |
| 1570 RenameResource(GURL(src_entry_proto->edit_url()), | |
| 1571 FILE_PATH_LITERAL("Test.log"), _)); | |
| 1572 EXPECT_CALL(*mock_drive_service_, | |
| 1573 AddResourceToDirectory( | |
| 1574 GURL(dest_parent_proto->content_url()), | |
| 1575 GURL(src_entry_proto->edit_url()), _)); | |
| 1576 | |
| 1577 FileOperationCallback callback = | |
| 1578 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1579 callback_helper_.get()); | |
| 1580 | |
| 1581 // Expect notification for both source and destination directories. | |
| 1582 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1583 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1584 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1585 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1586 | |
| 1587 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1588 test_util::RunBlockingPoolTask(); | |
| 1589 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1590 | |
| 1591 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1592 EXPECT_TRUE(EntryExists(dest_file_path)); | |
| 1593 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
| 1594 } | |
| 1595 | |
| 1596 TEST_F(GDataFileSystemTest, MoveFileFromSubDirectoryToRoot) { | |
| 1597 FilePath src_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
| 1598 FilePath src_file_path( | |
| 1599 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
| 1600 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
| 1601 | |
| 1602 LoadRootFeedDocument("root_feed.json"); | |
| 1603 | |
| 1604 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1605 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1606 src_file_path); | |
| 1607 ASSERT_TRUE(src_entry_proto.get()); | |
| 1608 std::string src_file_resource_id = | |
| 1609 src_entry_proto->resource_id(); | |
| 1610 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1611 | |
| 1612 ASSERT_TRUE(EntryExists(src_parent_path)); | |
| 1613 scoped_ptr<DriveEntryProto> src_parent_proto = GetEntryInfoByPathSync( | |
| 1614 src_parent_path); | |
| 1615 ASSERT_TRUE(src_parent_proto.get()); | |
| 1616 ASSERT_TRUE(src_parent_proto->file_info().is_directory()); | |
| 1617 EXPECT_FALSE(src_parent_proto->content_url().empty()); | |
| 1618 | |
| 1619 EXPECT_CALL(*mock_drive_service_, | |
| 1620 RenameResource(GURL(src_entry_proto->edit_url()), | |
| 1621 FILE_PATH_LITERAL("Test.log"), _)); | |
| 1622 EXPECT_CALL(*mock_drive_service_, | |
| 1623 RemoveResourceFromDirectory( | |
| 1624 GURL(src_parent_proto->content_url()), | |
| 1625 GURL(src_entry_proto->edit_url()), | |
| 1626 src_file_resource_id, _)); | |
| 1627 | |
| 1628 FileOperationCallback callback = | |
| 1629 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1630 callback_helper_.get()); | |
| 1631 | |
| 1632 // Expect notification for both source and destination directories. | |
| 1633 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1634 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1635 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1636 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1637 | |
| 1638 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1639 test_util::RunBlockingPoolTask(); | |
| 1640 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1641 | |
| 1642 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1643 ASSERT_TRUE(EntryExists(dest_file_path)); | |
| 1644 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
| 1645 } | |
| 1646 | |
| 1647 TEST_F(GDataFileSystemTest, MoveFileBetweenSubDirectories) { | |
| 1648 FilePath src_parent_path(FILE_PATH_LITERAL("drive/Directory 1")); | |
| 1649 FilePath src_file_path( | |
| 1650 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
| 1651 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/New Folder 1")); | |
| 1652 FilePath dest_file_path(FILE_PATH_LITERAL("drive/New Folder 1/Test.log")); | |
| 1653 FilePath interim_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
| 1654 | |
| 1655 LoadRootFeedDocument("root_feed.json"); | |
| 1656 | |
| 1657 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1658 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1659 | |
| 1660 AddDirectoryFromFile(dest_parent_path, "directory_entry_atom.json"); | |
| 1661 | |
| 1662 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1663 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1664 src_file_path); | |
| 1665 ASSERT_TRUE(src_entry_proto.get()); | |
| 1666 std::string src_file_resource_id = | |
| 1667 src_entry_proto->resource_id(); | |
| 1668 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1669 | |
| 1670 ASSERT_TRUE(EntryExists(src_parent_path)); | |
| 1671 scoped_ptr<DriveEntryProto> src_parent_proto = GetEntryInfoByPathSync( | |
| 1672 src_parent_path); | |
| 1673 ASSERT_TRUE(src_parent_proto.get()); | |
| 1674 ASSERT_TRUE(src_parent_proto->file_info().is_directory()); | |
| 1675 EXPECT_FALSE(src_parent_proto->content_url().empty()); | |
| 1676 | |
| 1677 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
| 1678 scoped_ptr<DriveEntryProto> dest_parent_proto = GetEntryInfoByPathSync( | |
| 1679 dest_parent_path); | |
| 1680 ASSERT_TRUE(dest_parent_proto.get()); | |
| 1681 ASSERT_TRUE(dest_parent_proto->file_info().is_directory()); | |
| 1682 EXPECT_FALSE(dest_parent_proto->content_url().empty()); | |
| 1683 | |
| 1684 EXPECT_FALSE(EntryExists(interim_file_path)); | |
| 1685 | |
| 1686 EXPECT_CALL(*mock_drive_service_, | |
| 1687 RenameResource(GURL(src_entry_proto->edit_url()), | |
| 1688 FILE_PATH_LITERAL("Test.log"), _)); | |
| 1689 EXPECT_CALL(*mock_drive_service_, | |
| 1690 RemoveResourceFromDirectory( | |
| 1691 GURL(src_parent_proto->content_url()), | |
| 1692 GURL(src_entry_proto->edit_url()), | |
| 1693 src_file_resource_id, _)); | |
| 1694 EXPECT_CALL(*mock_drive_service_, | |
| 1695 AddResourceToDirectory( | |
| 1696 GURL(dest_parent_proto->content_url()), | |
| 1697 GURL(src_entry_proto->edit_url()), | |
| 1698 _)); | |
| 1699 | |
| 1700 FileOperationCallback callback = | |
| 1701 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1702 callback_helper_.get()); | |
| 1703 | |
| 1704 // Expect notification for both source and destination directories plus | |
| 1705 // interim file path. | |
| 1706 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1707 Eq(FilePath(FILE_PATH_LITERAL("drive/Directory 1"))))).Times(1); | |
| 1708 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1709 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1710 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1711 Eq(FilePath(FILE_PATH_LITERAL("drive/New Folder 1"))))).Times(1); | |
| 1712 | |
| 1713 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1714 test_util::RunBlockingPoolTask(); | |
| 1715 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1716 | |
| 1717 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1718 EXPECT_FALSE(EntryExists(interim_file_path)); | |
| 1719 | |
| 1720 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1721 EXPECT_TRUE(EntryExists(dest_file_path)); | |
| 1722 EXPECT_EQ(src_file_resource_id, GetResourceIdByPath(dest_file_path)); | |
| 1723 } | |
| 1724 | |
| 1725 TEST_F(GDataFileSystemTest, MoveNotExistingFile) { | |
| 1726 FilePath src_file_path(FILE_PATH_LITERAL("drive/Dummy file.txt")); | |
| 1727 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Test.log")); | |
| 1728 | |
| 1729 LoadRootFeedDocument("root_feed.json"); | |
| 1730 | |
| 1731 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1732 | |
| 1733 FileOperationCallback callback = | |
| 1734 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1735 callback_helper_.get()); | |
| 1736 | |
| 1737 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1738 test_util::RunBlockingPoolTask(); | |
| 1739 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
| 1740 | |
| 1741 EXPECT_FALSE(EntryExists(src_file_path)); | |
| 1742 EXPECT_FALSE(EntryExists(dest_file_path)); | |
| 1743 } | |
| 1744 | |
| 1745 TEST_F(GDataFileSystemTest, MoveFileToNonExistingDirectory) { | |
| 1746 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1747 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Dummy")); | |
| 1748 FilePath dest_file_path(FILE_PATH_LITERAL("drive/Dummy/Test.log")); | |
| 1749 | |
| 1750 LoadRootFeedDocument("root_feed.json"); | |
| 1751 | |
| 1752 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1753 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1754 src_file_path); | |
| 1755 ASSERT_TRUE(src_entry_proto.get()); | |
| 1756 std::string src_file_resource_id = | |
| 1757 src_entry_proto->resource_id(); | |
| 1758 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1759 | |
| 1760 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
| 1761 | |
| 1762 FileOperationCallback callback = | |
| 1763 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1764 callback_helper_.get()); | |
| 1765 | |
| 1766 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1767 test_util::RunBlockingPoolTask(); | |
| 1768 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
| 1769 | |
| 1770 | |
| 1771 EXPECT_FALSE(EntryExists(dest_parent_path)); | |
| 1772 EXPECT_FALSE(EntryExists(dest_file_path)); | |
| 1773 } | |
| 1774 | |
| 1775 // Test the case where the parent of |dest_file_path| is a existing file, | |
| 1776 // not a directory. | |
| 1777 TEST_F(GDataFileSystemTest, MoveFileToInvalidPath) { | |
| 1778 FilePath src_file_path(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1779 FilePath dest_parent_path(FILE_PATH_LITERAL("drive/Duplicate Name.txt")); | |
| 1780 FilePath dest_file_path(FILE_PATH_LITERAL( | |
| 1781 "drive/Duplicate Name.txt/Test.log")); | |
| 1782 | |
| 1783 LoadRootFeedDocument("root_feed.json"); | |
| 1784 | |
| 1785 ASSERT_TRUE(EntryExists(src_file_path)); | |
| 1786 scoped_ptr<DriveEntryProto> src_entry_proto = GetEntryInfoByPathSync( | |
| 1787 src_file_path); | |
| 1788 ASSERT_TRUE(src_entry_proto.get()); | |
| 1789 std::string src_file_resource_id = | |
| 1790 src_entry_proto->resource_id(); | |
| 1791 EXPECT_FALSE(src_entry_proto->edit_url().empty()); | |
| 1792 | |
| 1793 ASSERT_TRUE(EntryExists(dest_parent_path)); | |
| 1794 scoped_ptr<DriveEntryProto> dest_parent_proto = GetEntryInfoByPathSync( | |
| 1795 dest_parent_path); | |
| 1796 ASSERT_TRUE(dest_parent_proto.get()); | |
| 1797 | |
| 1798 FileOperationCallback callback = | |
| 1799 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1800 callback_helper_.get()); | |
| 1801 | |
| 1802 file_system_->Move(src_file_path, dest_file_path, callback); | |
| 1803 test_util::RunBlockingPoolTask(); | |
| 1804 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_A_DIRECTORY, | |
| 1805 callback_helper_->last_error_); | |
| 1806 | |
| 1807 EXPECT_TRUE(EntryExists(src_file_path)); | |
| 1808 EXPECT_TRUE(EntryExists(dest_parent_path)); | |
| 1809 EXPECT_FALSE(EntryExists(dest_file_path)); | |
| 1810 } | |
| 1811 | |
| 1812 TEST_F(GDataFileSystemTest, RemoveEntries) { | |
| 1813 LoadRootFeedDocument("root_feed.json"); | |
| 1814 | |
| 1815 FilePath nonexisting_file(FILE_PATH_LITERAL("drive/Dummy file.txt")); | |
| 1816 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1817 FilePath dir_in_root(FILE_PATH_LITERAL("drive/Directory 1")); | |
| 1818 FilePath file_in_subdir( | |
| 1819 FILE_PATH_LITERAL("drive/Directory 1/SubDirectory File 1.txt")); | |
| 1820 | |
| 1821 ASSERT_TRUE(EntryExists(file_in_root)); | |
| 1822 scoped_ptr<DriveEntryProto> file_in_root_proto = GetEntryInfoByPathSync( | |
| 1823 file_in_root); | |
| 1824 ASSERT_TRUE(file_in_root_proto.get()); | |
| 1825 | |
| 1826 ASSERT_TRUE(EntryExists(dir_in_root)); | |
| 1827 scoped_ptr<DriveEntryProto> dir_in_root_proto = GetEntryInfoByPathSync( | |
| 1828 dir_in_root); | |
| 1829 ASSERT_TRUE(dir_in_root_proto.get()); | |
| 1830 ASSERT_TRUE(dir_in_root_proto->file_info().is_directory()); | |
| 1831 | |
| 1832 ASSERT_TRUE(EntryExists(file_in_subdir)); | |
| 1833 scoped_ptr<DriveEntryProto> file_in_subdir_proto = GetEntryInfoByPathSync( | |
| 1834 file_in_subdir); | |
| 1835 ASSERT_TRUE(file_in_subdir_proto.get()); | |
| 1836 | |
| 1837 // Once for file in root and once for file... | |
| 1838 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1839 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(2); | |
| 1840 | |
| 1841 // Remove first file in root. | |
| 1842 EXPECT_TRUE(RemoveEntry(file_in_root)); | |
| 1843 EXPECT_FALSE(EntryExists(file_in_root)); | |
| 1844 EXPECT_TRUE(EntryExists(dir_in_root)); | |
| 1845 EXPECT_TRUE(EntryExists(file_in_subdir)); | |
| 1846 | |
| 1847 // Remove directory. | |
| 1848 EXPECT_TRUE(RemoveEntry(dir_in_root)); | |
| 1849 EXPECT_FALSE(EntryExists(file_in_root)); | |
| 1850 EXPECT_FALSE(EntryExists(dir_in_root)); | |
| 1851 EXPECT_FALSE(EntryExists(file_in_subdir)); | |
| 1852 | |
| 1853 // Try removing file in already removed subdirectory. | |
| 1854 EXPECT_FALSE(RemoveEntry(file_in_subdir)); | |
| 1855 | |
| 1856 // Try removing non-existing file. | |
| 1857 EXPECT_FALSE(RemoveEntry(nonexisting_file)); | |
| 1858 | |
| 1859 // Try removing root file element. | |
| 1860 EXPECT_FALSE(RemoveEntry(FilePath(FILE_PATH_LITERAL("drive")))); | |
| 1861 | |
| 1862 // Need this to ensure OnDirectoryChanged() is run. | |
| 1863 test_util::RunBlockingPoolTask(); | |
| 1864 } | |
| 1865 | |
| 1866 TEST_F(GDataFileSystemTest, CreateDirectory) { | |
| 1867 LoadRootFeedDocument("root_feed.json"); | |
| 1868 | |
| 1869 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1870 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1871 | |
| 1872 // Create directory in root. | |
| 1873 FilePath dir_path(FILE_PATH_LITERAL("drive/New Folder 1")); | |
| 1874 EXPECT_FALSE(EntryExists(dir_path)); | |
| 1875 AddDirectoryFromFile(dir_path, "directory_entry_atom.json"); | |
| 1876 EXPECT_TRUE(EntryExists(dir_path)); | |
| 1877 | |
| 1878 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1879 Eq(FilePath(FILE_PATH_LITERAL("drive/New Folder 1"))))).Times(1); | |
| 1880 | |
| 1881 // Create directory in a sub directory. | |
| 1882 FilePath subdir_path(FILE_PATH_LITERAL("drive/New Folder 1/New Folder 2")); | |
| 1883 EXPECT_FALSE(EntryExists(subdir_path)); | |
| 1884 AddDirectoryFromFile(subdir_path, "directory_entry_atom2.json"); | |
| 1885 EXPECT_TRUE(EntryExists(subdir_path)); | |
| 1886 } | |
| 1887 | |
| 1888 TEST_F(GDataFileSystemTest, FindFirstMissingParentDirectory) { | |
| 1889 LoadRootFeedDocument("root_feed.json"); | |
| 1890 | |
| 1891 GURL last_dir_content_url; | |
| 1892 FilePath first_missing_parent_path; | |
| 1893 | |
| 1894 // Create directory in root. | |
| 1895 FilePath dir_path(FILE_PATH_LITERAL("drive/New Folder 1")); | |
| 1896 EXPECT_EQ( | |
| 1897 GDataFileSystem::FOUND_MISSING, | |
| 1898 file_system_->FindFirstMissingParentDirectory(dir_path, | |
| 1899 &last_dir_content_url, | |
| 1900 &first_missing_parent_path)); | |
| 1901 EXPECT_EQ(FilePath(FILE_PATH_LITERAL("drive/New Folder 1")), | |
| 1902 first_missing_parent_path); | |
| 1903 EXPECT_TRUE(last_dir_content_url.is_empty()); // root directory. | |
| 1904 | |
| 1905 // Missing folders in subdir of an existing folder. | |
| 1906 FilePath dir_path2(FILE_PATH_LITERAL("drive/Directory 1/New Folder 2")); | |
| 1907 EXPECT_EQ( | |
| 1908 GDataFileSystem::FOUND_MISSING, | |
| 1909 file_system_->FindFirstMissingParentDirectory(dir_path2, | |
| 1910 &last_dir_content_url, | |
| 1911 &first_missing_parent_path)); | |
| 1912 EXPECT_EQ(FilePath(FILE_PATH_LITERAL("drive/Directory 1/New Folder 2")), | |
| 1913 first_missing_parent_path); | |
| 1914 EXPECT_FALSE(last_dir_content_url.is_empty()); // non-root directory. | |
| 1915 | |
| 1916 // Missing two folders on the path. | |
| 1917 FilePath dir_path3 = dir_path2.Append(FILE_PATH_LITERAL("Another Folder")); | |
| 1918 EXPECT_EQ( | |
| 1919 GDataFileSystem::FOUND_MISSING, | |
| 1920 file_system_->FindFirstMissingParentDirectory(dir_path3, | |
| 1921 &last_dir_content_url, | |
| 1922 &first_missing_parent_path)); | |
| 1923 EXPECT_EQ(FilePath(FILE_PATH_LITERAL("drive/Directory 1/New Folder 2")), | |
| 1924 first_missing_parent_path); | |
| 1925 EXPECT_FALSE(last_dir_content_url.is_empty()); // non-root directory. | |
| 1926 | |
| 1927 // Folders on top of an existing file. | |
| 1928 EXPECT_EQ( | |
| 1929 GDataFileSystem::FOUND_INVALID, | |
| 1930 file_system_->FindFirstMissingParentDirectory( | |
| 1931 FilePath(FILE_PATH_LITERAL("drive/File 1.txt/BadDir")), | |
| 1932 &last_dir_content_url, | |
| 1933 &first_missing_parent_path)); | |
| 1934 | |
| 1935 // Existing folder. | |
| 1936 EXPECT_EQ( | |
| 1937 GDataFileSystem::DIRECTORY_ALREADY_PRESENT, | |
| 1938 file_system_->FindFirstMissingParentDirectory( | |
| 1939 FilePath(FILE_PATH_LITERAL("drive/Directory 1")), | |
| 1940 &last_dir_content_url, | |
| 1941 &first_missing_parent_path)); | |
| 1942 } | |
| 1943 | |
| 1944 // Create a directory through the document service | |
| 1945 TEST_F(GDataFileSystemTest, CreateDirectoryWithService) { | |
| 1946 LoadRootFeedDocument("root_feed.json"); | |
| 1947 EXPECT_CALL(*mock_drive_service_, | |
| 1948 CreateDirectory(_, "Sample Directory Title", _)).Times(1); | |
| 1949 EXPECT_CALL(*mock_directory_observer_, OnDirectoryChanged( | |
| 1950 Eq(FilePath(FILE_PATH_LITERAL("drive"))))).Times(1); | |
| 1951 | |
| 1952 // Set last error so it's not a valid error code. | |
| 1953 callback_helper_->last_error_ = static_cast<DriveFileError>(1); | |
| 1954 file_system_->CreateDirectory( | |
| 1955 FilePath(FILE_PATH_LITERAL("drive/Sample Directory Title")), | |
| 1956 false, // is_exclusive | |
| 1957 true, // is_recursive | |
| 1958 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 1959 callback_helper_.get())); | |
| 1960 test_util::RunBlockingPoolTask(); | |
| 1961 // TODO(gspencer): Uncomment this when we get a blob that | |
| 1962 // works that can be returned from the mock. | |
| 1963 // EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 1964 } | |
| 1965 | |
| 1966 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_EnoughSpace) { | |
| 1967 LoadRootFeedDocument("root_feed.json"); | |
| 1968 | |
| 1969 GetFileCallback callback = | |
| 1970 base::Bind(&CallbackHelper::GetFileCallback, | |
| 1971 callback_helper_.get()); | |
| 1972 | |
| 1973 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 1974 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 1975 FilePath downloaded_file = GetCachePathForFile( | |
| 1976 entry_proto->resource_id(), | |
| 1977 entry_proto->file_specific_info().file_md5()); | |
| 1978 const int64 file_size = entry_proto->file_info().size(); | |
| 1979 | |
| 1980 // Pretend we have enough space. | |
| 1981 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 1982 .Times(2).WillRepeatedly(Return(file_size + kMinFreeSpace)); | |
| 1983 | |
| 1984 // Before Download starts metadata from server will be fetched. | |
| 1985 // We will read content url from the result. | |
| 1986 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 1987 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 1988 | |
| 1989 // The file is obtained with the mock DriveService. | |
| 1990 EXPECT_CALL(*mock_drive_service_, | |
| 1991 DownloadFile(file_in_root, | |
| 1992 downloaded_file, | |
| 1993 GURL("https://file_content_url_changed/"), | |
| 1994 _, _)) | |
| 1995 .Times(1); | |
| 1996 | |
| 1997 file_system_->GetFileByPath(file_in_root, callback, | |
| 1998 GetContentCallback()); | |
| 1999 test_util::RunBlockingPoolTask(); | |
| 2000 | |
| 2001 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 2002 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
| 2003 EXPECT_EQ(downloaded_file.value(), | |
| 2004 callback_helper_->download_path_.value()); | |
| 2005 } | |
| 2006 | |
| 2007 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_NoSpaceAtAll) { | |
| 2008 LoadRootFeedDocument("root_feed.json"); | |
| 2009 | |
| 2010 GetFileCallback callback = | |
| 2011 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2012 callback_helper_.get()); | |
| 2013 | |
| 2014 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2015 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 2016 FilePath downloaded_file = GetCachePathForFile( | |
| 2017 entry_proto->resource_id(), | |
| 2018 entry_proto->file_specific_info().file_md5()); | |
| 2019 | |
| 2020 // Pretend we have no space at all. | |
| 2021 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2022 .Times(2).WillRepeatedly(Return(0)); | |
| 2023 | |
| 2024 // Before Download starts metadata from server will be fetched. | |
| 2025 // We will read content url from the result. | |
| 2026 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 2027 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 2028 | |
| 2029 // The file is not obtained with the mock DriveService, because of no space. | |
| 2030 EXPECT_CALL(*mock_drive_service_, | |
| 2031 DownloadFile(file_in_root, | |
| 2032 downloaded_file, | |
| 2033 GURL("https://file_content_url_changed/"), | |
| 2034 _, _)) | |
| 2035 .Times(0); | |
| 2036 | |
| 2037 file_system_->GetFileByPath(file_in_root, callback, | |
| 2038 GetContentCallback()); | |
| 2039 test_util::RunBlockingPoolTask(); | |
| 2040 | |
| 2041 EXPECT_EQ(DRIVE_FILE_ERROR_NO_SPACE, | |
| 2042 callback_helper_->last_error_); | |
| 2043 } | |
| 2044 | |
| 2045 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_NoEnoughSpaceButCanFreeUp) { | |
| 2046 LoadRootFeedDocument("root_feed.json"); | |
| 2047 | |
| 2048 GetFileCallback callback = | |
| 2049 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2050 callback_helper_.get()); | |
| 2051 | |
| 2052 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2053 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 2054 FilePath downloaded_file = GetCachePathForFile( | |
| 2055 entry_proto->resource_id(), | |
| 2056 entry_proto->file_specific_info().file_md5()); | |
| 2057 const int64 file_size = entry_proto->file_info().size(); | |
| 2058 | |
| 2059 // Pretend we have no space first (checked before downloading a file), | |
| 2060 // but then start reporting we have space. This is to emulate that | |
| 2061 // the disk space was freed up by removing temporary files. | |
| 2062 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2063 .WillOnce(Return(file_size + kMinFreeSpace)) | |
| 2064 .WillOnce(Return(0)) | |
| 2065 .WillOnce(Return(file_size + kMinFreeSpace)) | |
| 2066 .WillOnce(Return(file_size + kMinFreeSpace)); | |
| 2067 | |
| 2068 // Store something in the temporary cache directory. | |
| 2069 TestStoreToCache("<resource_id>", | |
| 2070 "<md5>", | |
| 2071 GetTestFilePath("root_feed.json"), | |
| 2072 DRIVE_FILE_OK, | |
| 2073 test_util::TEST_CACHE_STATE_PRESENT, | |
| 2074 DriveCache::CACHE_TYPE_TMP); | |
| 2075 ASSERT_TRUE(CacheEntryExists("<resource_id>", "<md5>")); | |
| 2076 ASSERT_TRUE(CacheFileExists("<resource_id>", "<md5>")); | |
| 2077 | |
| 2078 // Before Download starts metadata from server will be fetched. | |
| 2079 // We will read content url from the result. | |
| 2080 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 2081 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 2082 | |
| 2083 // The file is obtained with the mock DriveService, because of we freed up the | |
| 2084 // space. | |
| 2085 EXPECT_CALL(*mock_drive_service_, | |
| 2086 DownloadFile(file_in_root, | |
| 2087 downloaded_file, | |
| 2088 GURL("https://file_content_url_changed/"), | |
| 2089 _, _)) | |
| 2090 .Times(1); | |
| 2091 | |
| 2092 file_system_->GetFileByPath(file_in_root, callback, | |
| 2093 GetContentCallback()); | |
| 2094 test_util::RunBlockingPoolTask(); | |
| 2095 | |
| 2096 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 2097 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
| 2098 EXPECT_EQ(downloaded_file.value(), | |
| 2099 callback_helper_->download_path_.value()); | |
| 2100 | |
| 2101 // The file should be removed in order to free up space, and the cache | |
| 2102 // entry should also be removed. | |
| 2103 ASSERT_FALSE(CacheEntryExists("<resource_id>", "<md5>")); | |
| 2104 ASSERT_FALSE(CacheFileExists("<resource_id>", "<md5>")); | |
| 2105 } | |
| 2106 | |
| 2107 TEST_F(GDataFileSystemTest, GetFileByPath_FromGData_EnoughSpaceButBecomeFull) { | |
| 2108 LoadRootFeedDocument("root_feed.json"); | |
| 2109 | |
| 2110 GetFileCallback callback = | |
| 2111 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2112 callback_helper_.get()); | |
| 2113 | |
| 2114 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2115 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 2116 FilePath downloaded_file = GetCachePathForFile( | |
| 2117 entry_proto->resource_id(), | |
| 2118 entry_proto->file_specific_info().file_md5()); | |
| 2119 const int64 file_size = entry_proto->file_info().size(); | |
| 2120 | |
| 2121 // Pretend we have enough space first (checked before downloading a file), | |
| 2122 // but then start reporting we have not enough space. This is to emulate that | |
| 2123 // the disk space becomes full after the file is downloaded for some reason | |
| 2124 // (ex. the actual file was larger than the expected size). | |
| 2125 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2126 .WillOnce(Return(file_size + kMinFreeSpace)) | |
| 2127 .WillOnce(Return(kMinFreeSpace - 1)) | |
| 2128 .WillOnce(Return(kMinFreeSpace - 1)); | |
| 2129 | |
| 2130 // Before Download starts metadata from server will be fetched. | |
| 2131 // We will read content url from the result. | |
| 2132 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 2133 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 2134 | |
| 2135 // The file is obtained with the mock DriveService. | |
| 2136 EXPECT_CALL(*mock_drive_service_, | |
| 2137 DownloadFile(file_in_root, | |
| 2138 downloaded_file, | |
| 2139 GURL("https://file_content_url_changed/"), | |
| 2140 _, _)) | |
| 2141 .Times(1); | |
| 2142 | |
| 2143 file_system_->GetFileByPath(file_in_root, callback, | |
| 2144 GetContentCallback()); | |
| 2145 test_util::RunBlockingPoolTask(); | |
| 2146 | |
| 2147 EXPECT_EQ(DRIVE_FILE_ERROR_NO_SPACE, | |
| 2148 callback_helper_->last_error_); | |
| 2149 } | |
| 2150 | |
| 2151 TEST_F(GDataFileSystemTest, GetFileByPath_FromCache) { | |
| 2152 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2153 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
| 2154 | |
| 2155 LoadRootFeedDocument("root_feed.json"); | |
| 2156 | |
| 2157 GetFileCallback callback = | |
| 2158 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2159 callback_helper_.get()); | |
| 2160 | |
| 2161 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2162 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 2163 FilePath downloaded_file = GetCachePathForFile( | |
| 2164 entry_proto->resource_id(), | |
| 2165 entry_proto->file_specific_info().file_md5()); | |
| 2166 | |
| 2167 // Store something as cached version of this file. | |
| 2168 TestStoreToCache(entry_proto->resource_id(), | |
| 2169 entry_proto->file_specific_info().file_md5(), | |
| 2170 GetTestFilePath("root_feed.json"), | |
| 2171 DRIVE_FILE_OK, | |
| 2172 test_util::TEST_CACHE_STATE_PRESENT, | |
| 2173 DriveCache::CACHE_TYPE_TMP); | |
| 2174 | |
| 2175 // Make sure we don't fetch metadata for downloading file. | |
| 2176 EXPECT_CALL(*mock_drive_service_, GetDocumentEntry(_, _)).Times(0); | |
| 2177 | |
| 2178 // Make sure we don't call downloads at all. | |
| 2179 EXPECT_CALL(*mock_drive_service_, | |
| 2180 DownloadFile(file_in_root, | |
| 2181 downloaded_file, | |
| 2182 GURL("https://file_content_url_changed/"), | |
| 2183 _, _)) | |
| 2184 .Times(0); | |
| 2185 | |
| 2186 file_system_->GetFileByPath(file_in_root, callback, | |
| 2187 GetContentCallback()); | |
| 2188 test_util::RunBlockingPoolTask(); | |
| 2189 | |
| 2190 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
| 2191 EXPECT_EQ(downloaded_file.value(), | |
| 2192 callback_helper_->download_path_.value()); | |
| 2193 } | |
| 2194 | |
| 2195 TEST_F(GDataFileSystemTest, GetFileByPath_HostedDocument) { | |
| 2196 LoadRootFeedDocument("root_feed.json"); | |
| 2197 | |
| 2198 GetFileCallback callback = | |
| 2199 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2200 callback_helper_.get()); | |
| 2201 | |
| 2202 FilePath file_in_root(FILE_PATH_LITERAL("drive/Document 1.gdoc")); | |
| 2203 scoped_ptr<DriveEntryProto> src_entry_proto = | |
| 2204 GetEntryInfoByPathSync(file_in_root); | |
| 2205 ASSERT_TRUE(src_entry_proto.get()); | |
| 2206 | |
| 2207 file_system_->GetFileByPath(file_in_root, callback, | |
| 2208 GetContentCallback()); | |
| 2209 test_util::RunBlockingPoolTask(); | |
| 2210 | |
| 2211 EXPECT_EQ(HOSTED_DOCUMENT, callback_helper_->file_type_); | |
| 2212 EXPECT_FALSE(callback_helper_->download_path_.empty()); | |
| 2213 | |
| 2214 ASSERT_TRUE(src_entry_proto.get()); | |
| 2215 VerifyHostedDocumentJSONFile(*src_entry_proto, | |
| 2216 callback_helper_->download_path_); | |
| 2217 } | |
| 2218 | |
| 2219 TEST_F(GDataFileSystemTest, GetFileByResourceId) { | |
| 2220 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2221 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
| 2222 | |
| 2223 LoadRootFeedDocument("root_feed.json"); | |
| 2224 | |
| 2225 GetFileCallback callback = | |
| 2226 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2227 callback_helper_.get()); | |
| 2228 | |
| 2229 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2230 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 2231 FilePath downloaded_file = GetCachePathForFile( | |
| 2232 entry_proto->resource_id(), | |
| 2233 entry_proto->file_specific_info().file_md5()); | |
| 2234 | |
| 2235 // Before Download starts metadata from server will be fetched. | |
| 2236 // We will read content url from the result. | |
| 2237 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 2238 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 2239 | |
| 2240 // The file is obtained with the mock DriveService, because it's not stored in | |
| 2241 // the cache. | |
| 2242 EXPECT_CALL(*mock_drive_service_, | |
| 2243 DownloadFile(file_in_root, | |
| 2244 downloaded_file, | |
| 2245 GURL("https://file_content_url_changed/"), | |
| 2246 _, _)) | |
| 2247 .Times(1); | |
| 2248 | |
| 2249 file_system_->GetFileByResourceId(entry_proto->resource_id(), | |
| 2250 callback, | |
| 2251 GetContentCallback()); | |
| 2252 test_util::RunBlockingPoolTask(); | |
| 2253 | |
| 2254 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
| 2255 EXPECT_EQ(downloaded_file.value(), | |
| 2256 callback_helper_->download_path_.value()); | |
| 2257 } | |
| 2258 | |
| 2259 TEST_F(GDataFileSystemTest, GetFileByResourceId_FromCache) { | |
| 2260 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2261 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
| 2262 | |
| 2263 LoadRootFeedDocument("root_feed.json"); | |
| 2264 | |
| 2265 GetFileCallback callback = | |
| 2266 base::Bind(&CallbackHelper::GetFileCallback, | |
| 2267 callback_helper_.get()); | |
| 2268 | |
| 2269 FilePath file_in_root(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2270 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(file_in_root)); | |
| 2271 FilePath downloaded_file = GetCachePathForFile( | |
| 2272 entry_proto->resource_id(), | |
| 2273 entry_proto->file_specific_info().file_md5()); | |
| 2274 | |
| 2275 // Store something as cached version of this file. | |
| 2276 TestStoreToCache(entry_proto->resource_id(), | |
| 2277 entry_proto->file_specific_info().file_md5(), | |
| 2278 GetTestFilePath("root_feed.json"), | |
| 2279 DRIVE_FILE_OK, | |
| 2280 test_util::TEST_CACHE_STATE_PRESENT, | |
| 2281 DriveCache::CACHE_TYPE_TMP); | |
| 2282 | |
| 2283 // The file is obtained from the cache. | |
| 2284 // Make sure we don't call downloads at all. | |
| 2285 EXPECT_CALL(*mock_drive_service_, DownloadFile(_, _, _, _, _)) | |
| 2286 .Times(0); | |
| 2287 | |
| 2288 file_system_->GetFileByResourceId(entry_proto->resource_id(), | |
| 2289 callback, | |
| 2290 GetContentCallback()); | |
| 2291 test_util::RunBlockingPoolTask(); | |
| 2292 | |
| 2293 EXPECT_EQ(REGULAR_FILE, callback_helper_->file_type_); | |
| 2294 EXPECT_EQ(downloaded_file.value(), | |
| 2295 callback_helper_->download_path_.value()); | |
| 2296 } | |
| 2297 | |
| 2298 TEST_F(GDataFileSystemTest, UpdateFileByResourceId_PersistentFile) { | |
| 2299 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2300 .Times(AtLeast(1)).WillRepeatedly(Return(kLotsOfSpace)); | |
| 2301 | |
| 2302 LoadRootFeedDocument("root_feed.json"); | |
| 2303 | |
| 2304 // This is a file defined in root_feed.json. | |
| 2305 const FilePath kFilePath(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2306 const std::string kResourceId("file:2_file_resource_id"); | |
| 2307 const std::string kMd5("3b4382ebefec6e743578c76bbd0575ce"); | |
| 2308 | |
| 2309 // Pin the file so it'll be store in "persistent" directory. | |
| 2310 EXPECT_CALL(*mock_cache_observer_, OnCachePinned(kResourceId, kMd5)).Times(1); | |
| 2311 TestPin(kResourceId, | |
| 2312 kMd5, | |
| 2313 DRIVE_FILE_OK, | |
| 2314 test_util::TEST_CACHE_STATE_PINNED, | |
| 2315 DriveCache::CACHE_TYPE_TMP); | |
| 2316 | |
| 2317 // First store a file to cache. A cache file will be created at: | |
| 2318 // GCache/v1/persistent/<kResourceId>.<kMd5> | |
| 2319 const FilePath original_cache_file_path = | |
| 2320 DriveCache::GetCacheRootPath(profile_.get()) | |
| 2321 .AppendASCII("persistent") | |
| 2322 .AppendASCII(kResourceId + "." + kMd5); | |
| 2323 TestStoreToCache(kResourceId, | |
| 2324 kMd5, | |
| 2325 GetTestFilePath("root_feed.json"), // Anything works. | |
| 2326 DRIVE_FILE_OK, | |
| 2327 test_util::TEST_CACHE_STATE_PRESENT | | |
| 2328 test_util::TEST_CACHE_STATE_PINNED | | |
| 2329 test_util::TEST_CACHE_STATE_PERSISTENT, | |
| 2330 DriveCache::CACHE_TYPE_PERSISTENT); | |
| 2331 ASSERT_TRUE(file_util::PathExists(original_cache_file_path)); | |
| 2332 | |
| 2333 // Add the dirty bit. The cache file will be renamed to | |
| 2334 // GCache/v1/persistent/<kResourceId>.local | |
| 2335 TestMarkDirty(kResourceId, | |
| 2336 kMd5, | |
| 2337 DRIVE_FILE_OK, | |
| 2338 test_util::TEST_CACHE_STATE_PRESENT | | |
| 2339 test_util::TEST_CACHE_STATE_PINNED | | |
| 2340 test_util::TEST_CACHE_STATE_DIRTY | | |
| 2341 test_util::TEST_CACHE_STATE_PERSISTENT, | |
| 2342 DriveCache::CACHE_TYPE_PERSISTENT); | |
| 2343 const FilePath dirty_cache_file_path = | |
| 2344 DriveCache::GetCacheRootPath(profile_.get()) | |
| 2345 .AppendASCII("persistent") | |
| 2346 .AppendASCII(kResourceId + ".local"); | |
| 2347 ASSERT_FALSE(file_util::PathExists(original_cache_file_path)); | |
| 2348 ASSERT_TRUE(file_util::PathExists(dirty_cache_file_path)); | |
| 2349 | |
| 2350 // Modify the cached file. | |
| 2351 const std::string kDummyCacheContent("modification to the cache"); | |
| 2352 ASSERT_TRUE(file_util::WriteFile(dirty_cache_file_path, | |
| 2353 kDummyCacheContent.c_str(), | |
| 2354 kDummyCacheContent.size())); | |
| 2355 | |
| 2356 // Commit the dirty bit. The cache file name remains the same | |
| 2357 // but a symlink will be created at: | |
| 2358 // GCache/v1/outgoing/<kResourceId> | |
| 2359 EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(kResourceId)).Times(1); | |
| 2360 TestCommitDirty(kResourceId, | |
| 2361 kMd5, | |
| 2362 DRIVE_FILE_OK, | |
| 2363 test_util::TEST_CACHE_STATE_PRESENT | | |
| 2364 test_util::TEST_CACHE_STATE_PINNED | | |
| 2365 test_util::TEST_CACHE_STATE_DIRTY | | |
| 2366 test_util::TEST_CACHE_STATE_PERSISTENT, | |
| 2367 DriveCache::CACHE_TYPE_PERSISTENT); | |
| 2368 const FilePath outgoing_symlink_path = | |
| 2369 DriveCache::GetCacheRootPath(profile_.get()) | |
| 2370 .AppendASCII("outgoing") | |
| 2371 .AppendASCII(kResourceId); | |
| 2372 ASSERT_TRUE(file_util::PathExists(dirty_cache_file_path)); | |
| 2373 ASSERT_TRUE(file_util::PathExists(outgoing_symlink_path)); | |
| 2374 | |
| 2375 // Create a DocumentEntry, which is needed to mock | |
| 2376 // GDataUploaderInterface::UploadExistingFile(). | |
| 2377 // TODO(satorux): This should be cleaned up. crbug.com/134240. | |
| 2378 DocumentEntry* document_entry = NULL; | |
| 2379 scoped_ptr<base::Value> value(LoadJSONFile("root_feed.json")); | |
| 2380 ASSERT_TRUE(value.get()); | |
| 2381 base::DictionaryValue* as_dict = NULL; | |
| 2382 base::ListValue* entry_list = NULL; | |
| 2383 if (value->GetAsDictionary(&as_dict) && | |
| 2384 as_dict->GetList("feed.entry", &entry_list)) { | |
| 2385 for (size_t i = 0; i < entry_list->GetSize(); ++i) { | |
| 2386 base::DictionaryValue* entry = NULL; | |
| 2387 std::string resource_id; | |
| 2388 if (entry_list->GetDictionary(i, &entry) && | |
| 2389 entry->GetString("gd$resourceId.$t", &resource_id) && | |
| 2390 resource_id == kResourceId) { | |
| 2391 // This will be deleted by UploadExistingFile(). | |
| 2392 document_entry = DocumentEntry::CreateFrom(*entry); | |
| 2393 } | |
| 2394 } | |
| 2395 } | |
| 2396 ASSERT_TRUE(document_entry); | |
| 2397 | |
| 2398 // The mock uploader will be used to simulate a file upload. | |
| 2399 EXPECT_CALL(*mock_uploader_, UploadExistingFile( | |
| 2400 GURL("https://file_link_resumable_edit_media/"), | |
| 2401 kFilePath, | |
| 2402 dirty_cache_file_path, | |
| 2403 kDummyCacheContent.size(), // The size after modification must be used. | |
| 2404 "audio/mpeg", | |
| 2405 _)) // callback | |
| 2406 .WillOnce(MockUploadExistingFile( | |
| 2407 DRIVE_FILE_OK, | |
| 2408 FilePath::FromUTF8Unsafe("drive/File1"), | |
| 2409 dirty_cache_file_path, | |
| 2410 document_entry)); | |
| 2411 | |
| 2412 // We'll notify the directory change to the observer upon completion. | |
| 2413 EXPECT_CALL(*mock_directory_observer_, | |
| 2414 OnDirectoryChanged(Eq(FilePath(kDriveRootDirectory)))).Times(1); | |
| 2415 | |
| 2416 // The callback will be called upon completion of | |
| 2417 // UpdateFileByResourceId(). | |
| 2418 FileOperationCallback callback = | |
| 2419 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 2420 callback_helper_.get()); | |
| 2421 | |
| 2422 // Check the number of files in the root directory. We'll compare the | |
| 2423 // number after updating a file. | |
| 2424 scoped_ptr<DriveEntryProtoVector> root_directory_entries( | |
| 2425 ReadDirectoryByPathSync(FilePath::FromUTF8Unsafe("drive"))); | |
| 2426 ASSERT_TRUE(root_directory_entries.get()); | |
| 2427 const int num_files_in_root = CountFiles(*root_directory_entries); | |
| 2428 | |
| 2429 file_system_->UpdateFileByResourceId(kResourceId, callback); | |
| 2430 test_util::RunBlockingPoolTask(); | |
| 2431 | |
| 2432 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 2433 // Make sure that the number of files did not change (i.e. we updated an | |
| 2434 // existing file, rather than adding a new file. The number of files | |
| 2435 // increases if we don't handle the file update right). | |
| 2436 EXPECT_EQ(num_files_in_root, CountFiles(*root_directory_entries)); | |
| 2437 // After the file is updated, the dirty bit is cleared, hence the symlink | |
| 2438 // should be gone. | |
| 2439 ASSERT_FALSE(file_util::PathExists(outgoing_symlink_path)); | |
| 2440 } | |
| 2441 | |
| 2442 TEST_F(GDataFileSystemTest, UpdateFileByResourceId_NonexistentFile) { | |
| 2443 LoadRootFeedDocument("root_feed.json"); | |
| 2444 | |
| 2445 // This is nonexistent in root_feed.json. | |
| 2446 const FilePath kFilePath(FILE_PATH_LITERAL("drive/Nonexistent.txt")); | |
| 2447 const std::string kResourceId("file:nonexistent_resource_id"); | |
| 2448 const std::string kMd5("nonexistent_md5"); | |
| 2449 | |
| 2450 // The callback will be called upon completion of | |
| 2451 // UpdateFileByResourceId(). | |
| 2452 FileOperationCallback callback = | |
| 2453 base::Bind(&CallbackHelper::FileOperationCallback, | |
| 2454 callback_helper_.get()); | |
| 2455 | |
| 2456 file_system_->UpdateFileByResourceId(kResourceId, callback); | |
| 2457 test_util::RunBlockingPoolTask(); | |
| 2458 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
| 2459 } | |
| 2460 | |
| 2461 TEST_F(GDataFileSystemTest, ContentSearch) { | |
| 2462 LoadRootFeedDocument("root_feed.json"); | |
| 2463 | |
| 2464 mock_drive_service_->set_search_result("search_result_feed.json"); | |
| 2465 | |
| 2466 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "foo", _, _)) | |
| 2467 .Times(1); | |
| 2468 | |
| 2469 const SearchResultPair kExpectedResults[] = { | |
| 2470 { "drive/Directory 1/SubDirectory File 1.txt", false }, | |
| 2471 { "drive/Directory 1", true } | |
| 2472 }; | |
| 2473 | |
| 2474 SearchCallback callback = base::Bind(&DriveSearchCallback, | |
| 2475 &message_loop_, kExpectedResults, ARRAYSIZE_UNSAFE(kExpectedResults)); | |
| 2476 | |
| 2477 file_system_->Search("foo", GURL(), callback); | |
| 2478 message_loop_.Run(); // Wait to get our result. | |
| 2479 } | |
| 2480 | |
| 2481 TEST_F(GDataFileSystemTest, ContentSearchWithNewEntry) { | |
| 2482 LoadRootFeedDocument("root_feed.json"); | |
| 2483 | |
| 2484 // Search result returning two entries "Directory 1/" and | |
| 2485 // "Directory 1/SubDirectory Newly Added File.txt". The latter is not | |
| 2486 // contained in the root feed. | |
| 2487 mock_drive_service_->set_search_result( | |
| 2488 "search_result_with_new_entry_feed.json"); | |
| 2489 | |
| 2490 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "foo", _, _)) | |
| 2491 .Times(1); | |
| 2492 | |
| 2493 // As the result of the first Search(), only entries in the current file | |
| 2494 // system snapshot are expected to be returned. | |
| 2495 const SearchResultPair kExpectedResults[] = { | |
| 2496 { "drive/Directory 1", true } | |
| 2497 }; | |
| 2498 | |
| 2499 // At the same time, unknown entry should trigger delta feed request. | |
| 2500 // This will cause notification to observers (e.g., File Browser) so that | |
| 2501 // they can request search again. | |
| 2502 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)).Times(1); | |
| 2503 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "", _, _)) | |
| 2504 .Times(1); | |
| 2505 EXPECT_CALL(*mock_webapps_registry_, UpdateFromFeed(_)).Times(1); | |
| 2506 | |
| 2507 SearchCallback callback = base::Bind(&DriveSearchCallback, | |
| 2508 &message_loop_, kExpectedResults, ARRAYSIZE_UNSAFE(kExpectedResults)); | |
| 2509 | |
| 2510 file_system_->Search("foo", GURL(), callback); | |
| 2511 message_loop_.Run(); // Wait to get our result. | |
| 2512 } | |
| 2513 | |
| 2514 TEST_F(GDataFileSystemTest, ContentSearchEmptyResult) { | |
| 2515 LoadRootFeedDocument("root_feed.json"); | |
| 2516 | |
| 2517 mock_drive_service_->set_search_result("empty_feed.json"); | |
| 2518 | |
| 2519 EXPECT_CALL(*mock_drive_service_, GetDocuments(Eq(GURL()), _, "foo", _, _)) | |
| 2520 .Times(1); | |
| 2521 | |
| 2522 const SearchResultPair* expected_results = NULL; | |
| 2523 | |
| 2524 SearchCallback callback = base::Bind(&DriveSearchCallback, | |
| 2525 &message_loop_, expected_results, 0u); | |
| 2526 | |
| 2527 file_system_->Search("foo", GURL(), callback); | |
| 2528 message_loop_.Run(); // Wait to get our result. | |
| 2529 } | |
| 2530 | |
| 2531 TEST_F(GDataFileSystemTest, GetAvailableSpace) { | |
| 2532 GetAvailableSpaceCallback callback = | |
| 2533 base::Bind(&CallbackHelper::GetAvailableSpaceCallback, | |
| 2534 callback_helper_.get()); | |
| 2535 | |
| 2536 EXPECT_CALL(*mock_drive_service_, GetAccountMetadata(_)); | |
| 2537 | |
| 2538 file_system_->GetAvailableSpace(callback); | |
| 2539 test_util::RunBlockingPoolTask(); | |
| 2540 EXPECT_EQ(GG_LONGLONG(6789012345), callback_helper_->quota_bytes_used_); | |
| 2541 EXPECT_EQ(GG_LONGLONG(9876543210), callback_helper_->quota_bytes_total_); | |
| 2542 } | |
| 2543 | |
| 2544 TEST_F(GDataFileSystemTest, RequestDirectoryRefresh) { | |
| 2545 LoadRootFeedDocument("root_feed.json"); | |
| 2546 | |
| 2547 // We'll fetch documents in the root directory with its resource ID. | |
| 2548 EXPECT_CALL(*mock_drive_service_, | |
| 2549 GetDocuments(Eq(GURL()), _, _, kDriveRootDirectoryResourceId, _)) | |
| 2550 .Times(1); | |
| 2551 // We'll notify the directory change to the observer. | |
| 2552 EXPECT_CALL(*mock_directory_observer_, | |
| 2553 OnDirectoryChanged(Eq(FilePath(kDriveRootDirectory)))).Times(1); | |
| 2554 | |
| 2555 file_system_->RequestDirectoryRefresh(FilePath(kDriveRootDirectory)); | |
| 2556 test_util::RunBlockingPoolTask(); | |
| 2557 } | |
| 2558 | |
| 2559 TEST_F(GDataFileSystemTest, OpenAndCloseFile) { | |
| 2560 LoadRootFeedDocument("root_feed.json"); | |
| 2561 | |
| 2562 OpenFileCallback callback = | |
| 2563 base::Bind(&CallbackHelper::OpenFileCallback, | |
| 2564 callback_helper_.get()); | |
| 2565 FileOperationCallback close_file_callback = | |
| 2566 base::Bind(&CallbackHelper::CloseFileCallback, | |
| 2567 callback_helper_.get()); | |
| 2568 | |
| 2569 const FilePath kFileInRoot(FILE_PATH_LITERAL("drive/File 1.txt")); | |
| 2570 scoped_ptr<DriveEntryProto> entry_proto(GetEntryInfoByPathSync(kFileInRoot)); | |
| 2571 FilePath downloaded_file = GetCachePathForFile( | |
| 2572 entry_proto->resource_id(), | |
| 2573 entry_proto->file_specific_info().file_md5()); | |
| 2574 const int64 file_size = entry_proto->file_info().size(); | |
| 2575 const std::string& file_resource_id = | |
| 2576 entry_proto->resource_id(); | |
| 2577 const std::string& file_md5 = entry_proto->file_specific_info().file_md5(); | |
| 2578 | |
| 2579 // A dirty file is created on close. | |
| 2580 EXPECT_CALL(*mock_cache_observer_, OnCacheCommitted(file_resource_id)) | |
| 2581 .Times(1); | |
| 2582 | |
| 2583 // Pretend we have enough space. | |
| 2584 EXPECT_CALL(*mock_free_disk_space_checker_, AmountOfFreeDiskSpace()) | |
| 2585 .Times(2).WillRepeatedly(Return(file_size + kMinFreeSpace)); | |
| 2586 | |
| 2587 const std::string kExpectedFileData = "test file data"; | |
| 2588 mock_drive_service_->set_file_data(new std::string(kExpectedFileData)); | |
| 2589 | |
| 2590 // Before Download starts metadata from server will be fetched. | |
| 2591 // We will read content url from the result. | |
| 2592 scoped_ptr<base::Value> document(LoadJSONFile("document_to_download.json")); | |
| 2593 SetExpectationsForGetDocumentEntry(&document, "file:2_file_resource_id"); | |
| 2594 | |
| 2595 // The file is obtained with the mock DriveService. | |
| 2596 EXPECT_CALL(*mock_drive_service_, | |
| 2597 DownloadFile(kFileInRoot, | |
| 2598 downloaded_file, | |
| 2599 GURL("https://file_content_url_changed/"), | |
| 2600 _, _)) | |
| 2601 .Times(1); | |
| 2602 | |
| 2603 // Open kFileInRoot ("drive/File 1.txt"). | |
| 2604 file_system_->OpenFile(kFileInRoot, callback); | |
| 2605 message_loop_.Run(); | |
| 2606 const FilePath opened_file_path = callback_helper_->opened_file_path_; | |
| 2607 | |
| 2608 // Verify that the file was properly opened. | |
| 2609 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 2610 | |
| 2611 // Try to open the already opened file. | |
| 2612 file_system_->OpenFile(kFileInRoot, callback); | |
| 2613 message_loop_.Run(); | |
| 2614 | |
| 2615 // It must fail. | |
| 2616 EXPECT_EQ(DRIVE_FILE_ERROR_IN_USE, callback_helper_->last_error_); | |
| 2617 | |
| 2618 // Verify that the file contents match the expected contents. | |
| 2619 std::string cache_file_data; | |
| 2620 EXPECT_TRUE(file_util::ReadFileToString(opened_file_path, &cache_file_data)); | |
| 2621 EXPECT_EQ(kExpectedFileData, cache_file_data); | |
| 2622 | |
| 2623 // Verify that the cache state was changed as expected. | |
| 2624 VerifyCacheStateAfterOpenFile(DRIVE_FILE_OK, | |
| 2625 file_resource_id, | |
| 2626 file_md5, | |
| 2627 opened_file_path); | |
| 2628 | |
| 2629 // Close kFileInRoot ("drive/File 1.txt"). | |
| 2630 file_system_->CloseFile(kFileInRoot, close_file_callback); | |
| 2631 message_loop_.Run(); | |
| 2632 | |
| 2633 // Verify that the file was properly closed. | |
| 2634 EXPECT_EQ(DRIVE_FILE_OK, callback_helper_->last_error_); | |
| 2635 | |
| 2636 // Verify that the cache state was changed as expected. | |
| 2637 VerifyCacheStateAfterCloseFile(DRIVE_FILE_OK, | |
| 2638 file_resource_id, | |
| 2639 file_md5); | |
| 2640 | |
| 2641 // Try to close the same file twice. | |
| 2642 file_system_->CloseFile(kFileInRoot, close_file_callback); | |
| 2643 message_loop_.Run(); | |
| 2644 | |
| 2645 // It must fail. | |
| 2646 EXPECT_EQ(DRIVE_FILE_ERROR_NOT_FOUND, callback_helper_->last_error_); | |
| 2647 } | |
| 2648 | |
| 2649 } // namespace gdata | |
| OLD | NEW |