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 "chrome/browser/chromeos/drive/sync_client.h" 6 7 #include "base/files/file_path.h" 8 #include "base/files/file_util.h" 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/prefs/testing_pref_service.h" 12 #include "base/run_loop.h" 13 #include "base/test/test_timeouts.h" 14 #include "chrome/browser/chromeos/drive/change_list_loader.h" 15 #include "chrome/browser/chromeos/drive/drive.pb.h" 16 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h" 17 #include "chrome/browser/chromeos/drive/file_cache.h" 18 #include "chrome/browser/chromeos/drive/file_change.h" 19 #include "chrome/browser/chromeos/drive/file_system/move_operation.h" 20 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h" 21 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h" 22 #include "chrome/browser/chromeos/drive/file_system_util.h" 23 #include "chrome/browser/chromeos/drive/job_scheduler.h" 24 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h" 25 #include "chrome/browser/chromeos/drive/resource_metadata.h" 26 #include "chrome/browser/chromeos/drive/test_util.h" 27 #include "chrome/browser/drive/event_logger.h" 28 #include "chrome/browser/drive/fake_drive_service.h" 29 #include "content/public/test/test_browser_thread_bundle.h" 30 #include "google_apis/drive/drive_api_parser.h" 31 #include "google_apis/drive/test_util.h" 32 #include "testing/gtest/include/gtest/gtest.h" 33 34 namespace drive { 35 namespace internal { 36 37 namespace { 38 39 // The content of files initially stored in the cache. 40 const char kLocalContent[] = "Hello!"; 41 42 // The content of files stored in the service. 43 const char kRemoteContent[] = "World!"; 44 45 // SyncClientTestDriveService will return GDATA_CANCELLED when a request is 46 // made with the specified resource ID. 47 class SyncClientTestDriveService : public ::drive::FakeDriveService { 48 public: 49 SyncClientTestDriveService() : download_file_count_(0) {} 50 51 // FakeDriveService override: 52 virtual google_apis::CancelCallback DownloadFile( 53 const base::FilePath& local_cache_path, 54 const std::string& resource_id, 55 const google_apis::DownloadActionCallback& download_action_callback, 56 const google_apis::GetContentCallback& get_content_callback, 57 const google_apis::ProgressCallback& progress_callback) OVERRIDE { 58 ++download_file_count_; 59 if (resource_id == resource_id_to_be_cancelled_) { 60 base::MessageLoopProxy::current()->PostTask( 61 FROM_HERE, 62 base::Bind(download_action_callback, 63 google_apis::GDATA_CANCELLED, 64 base::FilePath())); 65 return google_apis::CancelCallback(); 66 } 67 if (resource_id == resource_id_to_be_paused_) { 68 paused_action_ = base::Bind(download_action_callback, 69 google_apis::GDATA_OTHER_ERROR, 70 base::FilePath()); 71 return google_apis::CancelCallback(); 72 } 73 return FakeDriveService::DownloadFile(local_cache_path, 74 resource_id, 75 download_action_callback, 76 get_content_callback, 77 progress_callback); 78 } 79 80 int download_file_count() const { return download_file_count_; } 81 82 void set_resource_id_to_be_cancelled(const std::string& resource_id) { 83 resource_id_to_be_cancelled_ = resource_id; 84 } 85 86 void set_resource_id_to_be_paused(const std::string& resource_id) { 87 resource_id_to_be_paused_ = resource_id; 88 } 89 90 const base::Closure& paused_action() const { return paused_action_; } 91 92 private: 93 int download_file_count_; 94 std::string resource_id_to_be_cancelled_; 95 std::string resource_id_to_be_paused_; 96 base::Closure paused_action_; 97 }; 98 99 } // namespace 100 101 class SyncClientTest : public testing::Test { 102 public: 103 virtual void SetUp() OVERRIDE { 104 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 105 106 pref_service_.reset(new TestingPrefServiceSimple); 107 test_util::RegisterDrivePrefs(pref_service_->registry()); 108 109 fake_network_change_notifier_.reset( 110 new test_util::FakeNetworkChangeNotifier); 111 112 logger_.reset(new EventLogger); 113 114 drive_service_.reset(new SyncClientTestDriveService); 115 116 scheduler_.reset(new JobScheduler(pref_service_.get(), 117 logger_.get(), 118 drive_service_.get(), 119 base::MessageLoopProxy::current().get())); 120 121 metadata_storage_.reset(new ResourceMetadataStorage( 122 temp_dir_.path(), base::MessageLoopProxy::current().get())); 123 ASSERT_TRUE(metadata_storage_->Initialize()); 124 125 cache_.reset(new FileCache(metadata_storage_.get(), 126 temp_dir_.path(), 127 base::MessageLoopProxy::current().get(), 128 NULL /* free_disk_space_getter */)); 129 ASSERT_TRUE(cache_->Initialize()); 130 131 metadata_.reset(new internal::ResourceMetadata( 132 metadata_storage_.get(), cache_.get(), 133 base::MessageLoopProxy::current())); 134 ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize()); 135 136 about_resource_loader_.reset(new AboutResourceLoader(scheduler_.get())); 137 loader_controller_.reset(new LoaderController); 138 change_list_loader_.reset(new ChangeListLoader( 139 logger_.get(), 140 base::MessageLoopProxy::current().get(), 141 metadata_.get(), 142 scheduler_.get(), 143 about_resource_loader_.get(), 144 loader_controller_.get())); 145 ASSERT_NO_FATAL_FAILURE(SetUpTestData()); 146 147 sync_client_.reset(new SyncClient(base::MessageLoopProxy::current().get(), 148 &delegate_, 149 scheduler_.get(), 150 metadata_.get(), 151 cache_.get(), 152 loader_controller_.get(), 153 temp_dir_.path())); 154 155 // Disable delaying so that DoSyncLoop() starts immediately. 156 sync_client_->set_delay_for_testing(base::TimeDelta::FromSeconds(0)); 157 } 158 159 // Adds a file to the service root and |resource_ids_|. 160 void AddFileEntry(const std::string& title) { 161 google_apis::GDataErrorCode error = google_apis::GDATA_FILE_ERROR; 162 scoped_ptr<google_apis::FileResource> entry; 163 drive_service_->AddNewFile( 164 "text/plain", 165 kRemoteContent, 166 drive_service_->GetRootResourceId(), 167 title, 168 false, // shared_with_me 169 google_apis::test_util::CreateCopyResultCallback(&error, &entry)); 170 base::RunLoop().RunUntilIdle(); 171 ASSERT_EQ(google_apis::HTTP_CREATED, error); 172 ASSERT_TRUE(entry); 173 resource_ids_[title] = entry->file_id(); 174 } 175 176 // Sets up data for tests. 177 void SetUpTestData() { 178 // Prepare a temp file. 179 base::FilePath temp_file; 180 EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file)); 181 ASSERT_TRUE(google_apis::test_util::WriteStringToFile(temp_file, 182 kLocalContent)); 183 184 // Add file entries to the service. 185 ASSERT_NO_FATAL_FAILURE(AddFileEntry("foo")); 186 ASSERT_NO_FATAL_FAILURE(AddFileEntry("bar")); 187 ASSERT_NO_FATAL_FAILURE(AddFileEntry("baz")); 188 ASSERT_NO_FATAL_FAILURE(AddFileEntry("fetched")); 189 ASSERT_NO_FATAL_FAILURE(AddFileEntry("dirty")); 190 ASSERT_NO_FATAL_FAILURE(AddFileEntry("removed")); 191 ASSERT_NO_FATAL_FAILURE(AddFileEntry("moved")); 192 193 // Load data from the service to the metadata. 194 FileError error = FILE_ERROR_FAILED; 195 change_list_loader_->LoadIfNeeded( 196 google_apis::test_util::CreateCopyResultCallback(&error)); 197 base::RunLoop().RunUntilIdle(); 198 EXPECT_EQ(FILE_ERROR_OK, error); 199 200 // Prepare 3 pinned-but-not-present files. 201 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("foo"))); 202 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("bar"))); 203 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("baz"))); 204 205 // Prepare a pinned-and-fetched file. 206 const std::string md5_fetched = "md5"; 207 EXPECT_EQ(FILE_ERROR_OK, 208 cache_->Store(GetLocalId("fetched"), md5_fetched, 209 temp_file, FileCache::FILE_OPERATION_COPY)); 210 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("fetched"))); 211 212 // Prepare a pinned-and-fetched-and-dirty file. 213 EXPECT_EQ(FILE_ERROR_OK, 214 cache_->Store(GetLocalId("dirty"), std::string(), 215 temp_file, FileCache::FILE_OPERATION_COPY)); 216 EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("dirty"))); 217 218 // Prepare a removed file. 219 file_system::RemoveOperation remove_operation( 220 base::MessageLoopProxy::current().get(), &delegate_, metadata_.get(), 221 cache_.get()); 222 remove_operation.Remove( 223 util::GetDriveMyDriveRootPath().AppendASCII("removed"), 224 false, // is_recursive 225 google_apis::test_util::CreateCopyResultCallback(&error)); 226 base::RunLoop().RunUntilIdle(); 227 EXPECT_EQ(FILE_ERROR_OK, error); 228 229 // Prepare a moved file. 230 file_system::MoveOperation move_operation( 231 base::MessageLoopProxy::current().get(), &delegate_, metadata_.get()); 232 move_operation.Move( 233 util::GetDriveMyDriveRootPath().AppendASCII("moved"), 234 util::GetDriveMyDriveRootPath().AppendASCII("moved_new_title"), 235 google_apis::test_util::CreateCopyResultCallback(&error)); 236 base::RunLoop().RunUntilIdle(); 237 EXPECT_EQ(FILE_ERROR_OK, error); 238 } 239 240 protected: 241 std::string GetLocalId(const std::string& title) { 242 EXPECT_EQ(1U, resource_ids_.count(title)); 243 std::string local_id; 244 EXPECT_EQ(FILE_ERROR_OK, 245 metadata_->GetIdByResourceId(resource_ids_[title], &local_id)); 246 return local_id; 247 } 248 249 content::TestBrowserThreadBundle thread_bundle_; 250 base::ScopedTempDir temp_dir_; 251 scoped_ptr<TestingPrefServiceSimple> pref_service_; 252 scoped_ptr<test_util::FakeNetworkChangeNotifier> 253 fake_network_change_notifier_; 254 scoped_ptr<EventLogger> logger_; 255 scoped_ptr<SyncClientTestDriveService> drive_service_; 256 file_system::OperationDelegate delegate_; 257 scoped_ptr<JobScheduler> scheduler_; 258 scoped_ptr<ResourceMetadataStorage, 259 test_util::DestroyHelperForTests> metadata_storage_; 260 scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_; 261 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_; 262 scoped_ptr<AboutResourceLoader> about_resource_loader_; 263 scoped_ptr<LoaderController> loader_controller_; 264 scoped_ptr<ChangeListLoader> change_list_loader_; 265 scoped_ptr<SyncClient> sync_client_; 266 267 std::map<std::string, std::string> resource_ids_; // Name-to-id map. 268 }; 269 270 TEST_F(SyncClientTest, StartProcessingBacklog) { 271 sync_client_->StartProcessingBacklog(); 272 base::RunLoop().RunUntilIdle(); 273 274 ResourceEntry entry; 275 // Pinned files get downloaded. 276 EXPECT_EQ(FILE_ERROR_OK, 277 metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); 278 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); 279 280 EXPECT_EQ(FILE_ERROR_OK, 281 metadata_->GetResourceEntryById(GetLocalId("bar"), &entry)); 282 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); 283 284 EXPECT_EQ(FILE_ERROR_OK, 285 metadata_->GetResourceEntryById(GetLocalId("baz"), &entry)); 286 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); 287 288 // Dirty file gets uploaded. 289 EXPECT_EQ(FILE_ERROR_OK, 290 metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry)); 291 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); 292 293 // Removed entry is not found. 294 google_apis::GDataErrorCode status = google_apis::GDATA_OTHER_ERROR; 295 scoped_ptr<google_apis::FileResource> server_entry; 296 drive_service_->GetFileResource( 297 resource_ids_["removed"], 298 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 299 base::RunLoop().RunUntilIdle(); 300 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 301 ASSERT_TRUE(server_entry); 302 EXPECT_TRUE(server_entry->labels().is_trashed()); 303 304 // Moved entry was moved. 305 status = google_apis::GDATA_OTHER_ERROR; 306 drive_service_->GetFileResource( 307 resource_ids_["moved"], 308 google_apis::test_util::CreateCopyResultCallback(&status, &server_entry)); 309 base::RunLoop().RunUntilIdle(); 310 EXPECT_EQ(google_apis::HTTP_SUCCESS, status); 311 ASSERT_TRUE(server_entry); 312 EXPECT_EQ("moved_new_title", server_entry->title()); 313 } 314 315 TEST_F(SyncClientTest, AddFetchTask) { 316 sync_client_->AddFetchTask(GetLocalId("foo")); 317 base::RunLoop().RunUntilIdle(); 318 319 ResourceEntry entry; 320 EXPECT_EQ(FILE_ERROR_OK, 321 metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); 322 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); 323 } 324 325 TEST_F(SyncClientTest, AddFetchTaskAndCancelled) { 326 // Trigger fetching of a file which results in cancellation. 327 drive_service_->set_resource_id_to_be_cancelled(resource_ids_["foo"]); 328 sync_client_->AddFetchTask(GetLocalId("foo")); 329 base::RunLoop().RunUntilIdle(); 330 331 // The file should be unpinned if the user wants the download to be cancelled. 332 ResourceEntry entry; 333 EXPECT_EQ(FILE_ERROR_OK, 334 metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); 335 EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned()); 336 } 337 338 TEST_F(SyncClientTest, RemoveFetchTask) { 339 sync_client_->AddFetchTask(GetLocalId("foo")); 340 sync_client_->AddFetchTask(GetLocalId("bar")); 341 sync_client_->AddFetchTask(GetLocalId("baz")); 342 343 sync_client_->RemoveFetchTask(GetLocalId("foo")); 344 sync_client_->RemoveFetchTask(GetLocalId("baz")); 345 base::RunLoop().RunUntilIdle(); 346 347 // Only "bar" should be fetched. 348 ResourceEntry entry; 349 EXPECT_EQ(FILE_ERROR_OK, 350 metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); 351 EXPECT_FALSE(entry.file_specific_info().cache_state().is_present()); 352 353 EXPECT_EQ(FILE_ERROR_OK, 354 metadata_->GetResourceEntryById(GetLocalId("bar"), &entry)); 355 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); 356 357 EXPECT_EQ(FILE_ERROR_OK, 358 metadata_->GetResourceEntryById(GetLocalId("baz"), &entry)); 359 EXPECT_FALSE(entry.file_specific_info().cache_state().is_present()); 360 361 } 362 363 TEST_F(SyncClientTest, ExistingPinnedFiles) { 364 // Start checking the existing pinned files. This will collect the resource 365 // IDs of pinned files, with stale local cache files. 366 sync_client_->StartCheckingExistingPinnedFiles(); 367 base::RunLoop().RunUntilIdle(); 368 369 // "fetched" and "dirty" are the existing pinned files. 370 // The non-dirty one should be synced, but the dirty one should not. 371 base::FilePath cache_file; 372 std::string content; 373 EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(GetLocalId("fetched"), &cache_file)); 374 EXPECT_TRUE(base::ReadFileToString(cache_file, &content)); 375 EXPECT_EQ(kRemoteContent, content); 376 content.clear(); 377 378 EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(GetLocalId("dirty"), &cache_file)); 379 EXPECT_TRUE(base::ReadFileToString(cache_file, &content)); 380 EXPECT_EQ(kLocalContent, content); 381 } 382 383 TEST_F(SyncClientTest, RetryOnDisconnection) { 384 // Let the service go down. 385 drive_service_->set_offline(true); 386 // Change the network connection state after some delay, to test that 387 // FILE_ERROR_NO_CONNECTION is handled by SyncClient correctly. 388 // Without this delay, JobScheduler will keep the jobs unrun and SyncClient 389 // will receive no error. 390 base::MessageLoopProxy::current()->PostDelayedTask( 391 FROM_HERE, 392 base::Bind(&test_util::FakeNetworkChangeNotifier::SetConnectionType, 393 base::Unretained(fake_network_change_notifier_.get()), 394 net::NetworkChangeNotifier::CONNECTION_NONE), 395 TestTimeouts::tiny_timeout()); 396 397 // Try fetch and upload. 398 sync_client_->AddFetchTask(GetLocalId("foo")); 399 sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), 400 GetLocalId("dirty")); 401 base::RunLoop().RunUntilIdle(); 402 403 // Not yet fetched nor uploaded. 404 ResourceEntry entry; 405 EXPECT_EQ(FILE_ERROR_OK, 406 metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); 407 EXPECT_FALSE(entry.file_specific_info().cache_state().is_present()); 408 EXPECT_EQ(FILE_ERROR_OK, 409 metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry)); 410 EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty()); 411 412 // Switch to online. 413 fake_network_change_notifier_->SetConnectionType( 414 net::NetworkChangeNotifier::CONNECTION_WIFI); 415 drive_service_->set_offline(false); 416 base::RunLoop().RunUntilIdle(); 417 418 // Fetched and uploaded. 419 EXPECT_EQ(FILE_ERROR_OK, 420 metadata_->GetResourceEntryById(GetLocalId("foo"), &entry)); 421 EXPECT_TRUE(entry.file_specific_info().cache_state().is_present()); 422 EXPECT_EQ(FILE_ERROR_OK, 423 metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry)); 424 EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty()); 425 } 426 427 TEST_F(SyncClientTest, ScheduleRerun) { 428 // Add a fetch task for "foo", this should result in being paused. 429 drive_service_->set_resource_id_to_be_paused(resource_ids_["foo"]); 430 sync_client_->AddFetchTask(GetLocalId("foo")); 431 base::RunLoop().RunUntilIdle(); 432 433 // While the first task is paused, add a task again. 434 // This results in scheduling rerun of the task. 435 sync_client_->AddFetchTask(GetLocalId("foo")); 436 base::RunLoop().RunUntilIdle(); 437 438 // Resume the paused task. 439 drive_service_->set_resource_id_to_be_paused(std::string()); 440 ASSERT_FALSE(drive_service_->paused_action().is_null()); 441 drive_service_->paused_action().Run(); 442 base::RunLoop().RunUntilIdle(); 443 444 // Task should be run twice. 445 EXPECT_EQ(2, drive_service_->download_file_count()); 446 } 447 448 TEST_F(SyncClientTest, Dependencies) { 449 // Create directories locally. 450 const base::FilePath kPath1(FILE_PATH_LITERAL("drive/root/dir1")); 451 const base::FilePath kPath2 = kPath1.AppendASCII("dir2"); 452 453 ResourceEntry parent; 454 EXPECT_EQ(FILE_ERROR_OK, 455 metadata_->GetResourceEntryByPath(kPath1.DirName(), &parent)); 456 457 ResourceEntry entry1; 458 entry1.set_parent_local_id(parent.local_id()); 459 entry1.set_title(kPath1.BaseName().AsUTF8Unsafe()); 460 entry1.mutable_file_info()->set_is_directory(true); 461 entry1.set_metadata_edit_state(ResourceEntry::DIRTY); 462 std::string local_id1; 463 EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry1, &local_id1)); 464 465 ResourceEntry entry2; 466 entry2.set_parent_local_id(local_id1); 467 entry2.set_title(kPath2.BaseName().AsUTF8Unsafe()); 468 entry2.mutable_file_info()->set_is_directory(true); 469 entry2.set_metadata_edit_state(ResourceEntry::DIRTY); 470 std::string local_id2; 471 EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry2, &local_id2)); 472 473 // Start syncing the child first. 474 sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id2); 475 // Start syncing the parent later. 476 sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id1); 477 base::RunLoop().RunUntilIdle(); 478 479 // Both entries are synced. 480 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id1, &entry1)); 481 EXPECT_EQ(ResourceEntry::CLEAN, entry1.metadata_edit_state()); 482 EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id2, &entry2)); 483 EXPECT_EQ(ResourceEntry::CLEAN, entry2.metadata_edit_state()); 484 } 485 486 TEST_F(SyncClientTest, WaitForUpdateTaskToComplete) { 487 // Create a directory locally. 488 const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/dir1")); 489 490 ResourceEntry parent; 491 EXPECT_EQ(FILE_ERROR_OK, 492 metadata_->GetResourceEntryByPath(kPath.DirName(), &parent)); 493 494 ResourceEntry entry; 495 entry.set_parent_local_id(parent.local_id()); 496 entry.set_title(kPath.BaseName().AsUTF8Unsafe()); 497 entry.mutable_file_info()->set_is_directory(true); 498 entry.set_metadata_edit_state(ResourceEntry::DIRTY); 499 std::string local_id; 500 EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry, &local_id)); 501 502 // Sync task is not yet avialable. 503 FileError error = FILE_ERROR_FAILED; 504 EXPECT_FALSE(sync_client_->WaitForUpdateTaskToComplete( 505 local_id, google_apis::test_util::CreateCopyResultCallback(&error))); 506 507 // Start syncing the directory and wait for it to complete. 508 sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id); 509 510 EXPECT_TRUE(sync_client_->WaitForUpdateTaskToComplete( 511 local_id, google_apis::test_util::CreateCopyResultCallback(&error))); 512 513 base::RunLoop().RunUntilIdle(); 514 515 // The callback is called. 516 EXPECT_EQ(FILE_ERROR_OK, error); 517 } 518 519 } // namespace internal 520 } // namespace drive 521