| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/sync/entry_update_performer.h" | 5 #include "chrome/browser/chromeos/drive/sync/entry_update_performer.h" |
| 6 | 6 |
| 7 #include "base/callback_helpers.h" |
| 8 #include "base/file_util.h" |
| 9 #include "base/md5.h" |
| 7 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
| 11 #include "chrome/browser/chromeos/drive/file_cache.h" |
| 8 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h" | 12 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h" |
| 9 #include "chrome/browser/chromeos/drive/file_system_interface.h" | 13 #include "chrome/browser/chromeos/drive/file_system_interface.h" |
| 10 #include "chrome/browser/chromeos/drive/resource_metadata.h" | 14 #include "chrome/browser/chromeos/drive/resource_metadata.h" |
| 11 #include "chrome/browser/drive/drive_api_util.h" | 15 #include "chrome/browser/drive/drive_api_util.h" |
| 12 #include "chrome/browser/drive/fake_drive_service.h" | 16 #include "chrome/browser/drive/fake_drive_service.h" |
| 17 #include "google_apis/drive/drive_api_parser.h" |
| 13 #include "google_apis/drive/gdata_wapi_parser.h" | 18 #include "google_apis/drive/gdata_wapi_parser.h" |
| 14 #include "google_apis/drive/test_util.h" | 19 #include "google_apis/drive/test_util.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 21 |
| 17 namespace drive { | 22 namespace drive { |
| 18 namespace internal { | 23 namespace internal { |
| 19 | 24 |
| 20 class EntryUpdatePerformerTest : public file_system::OperationTestBase { | 25 class EntryUpdatePerformerTest : public file_system::OperationTestBase { |
| 21 protected: | 26 protected: |
| 22 virtual void SetUp() OVERRIDE { | 27 virtual void SetUp() OVERRIDE { |
| 23 OperationTestBase::SetUp(); | 28 OperationTestBase::SetUp(); |
| 24 performer_.reset(new EntryUpdatePerformer(blocking_task_runner(), | 29 performer_.reset(new EntryUpdatePerformer(blocking_task_runner(), |
| 25 observer(), | 30 observer(), |
| 26 scheduler(), | 31 scheduler(), |
| 27 metadata())); | 32 metadata(), |
| 33 cache())); |
| 34 } |
| 35 |
| 36 // Stores |content| to the cache and mark it as dirty. |
| 37 FileError StoreAndMarkDirty(const std::string& local_id, |
| 38 const std::string& content) { |
| 39 base::FilePath path; |
| 40 if (!base::CreateTemporaryFileInDir(temp_dir(), &path) || |
| 41 !google_apis::test_util::WriteStringToFile(path, content)) |
| 42 return FILE_ERROR_FAILED; |
| 43 |
| 44 // Store the file to cache. |
| 45 FileError error = FILE_ERROR_FAILED; |
| 46 base::PostTaskAndReplyWithResult( |
| 47 blocking_task_runner(), |
| 48 FROM_HERE, |
| 49 base::Bind(&FileCache::Store, |
| 50 base::Unretained(cache()), |
| 51 local_id, base::MD5String(content), path, |
| 52 FileCache::FILE_OPERATION_COPY), |
| 53 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 54 test_util::RunBlockingPoolTask(); |
| 55 if (error != FILE_ERROR_OK) |
| 56 return error; |
| 57 |
| 58 // Add the dirty bit. |
| 59 error = FILE_ERROR_FAILED; |
| 60 scoped_ptr<base::ScopedClosureRunner> file_closer; |
| 61 base::PostTaskAndReplyWithResult( |
| 62 blocking_task_runner(), |
| 63 FROM_HERE, |
| 64 base::Bind(&FileCache::OpenForWrite, |
| 65 base::Unretained(cache()), |
| 66 local_id, |
| 67 &file_closer), |
| 68 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 69 test_util::RunBlockingPoolTask(); |
| 70 return error; |
| 28 } | 71 } |
| 29 | 72 |
| 30 scoped_ptr<EntryUpdatePerformer> performer_; | 73 scoped_ptr<EntryUpdatePerformer> performer_; |
| 31 }; | 74 }; |
| 32 | 75 |
| 33 TEST_F(EntryUpdatePerformerTest, UpdateEntry) { | 76 TEST_F(EntryUpdatePerformerTest, UpdateEntry) { |
| 34 base::FilePath src_path( | 77 base::FilePath src_path( |
| 35 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); | 78 FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt")); |
| 36 base::FilePath dest_path( | 79 base::FilePath dest_path( |
| 37 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder")); | 80 FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder")); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) { | 142 TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) { |
| 100 const std::string id = "this ID should result in NOT_FOUND"; | 143 const std::string id = "this ID should result in NOT_FOUND"; |
| 101 FileError error = FILE_ERROR_FAILED; | 144 FileError error = FILE_ERROR_FAILED; |
| 102 performer_->UpdateEntry( | 145 performer_->UpdateEntry( |
| 103 id, ClientContext(USER_INITIATED), | 146 id, ClientContext(USER_INITIATED), |
| 104 google_apis::test_util::CreateCopyResultCallback(&error)); | 147 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 105 test_util::RunBlockingPoolTask(); | 148 test_util::RunBlockingPoolTask(); |
| 106 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); | 149 EXPECT_EQ(FILE_ERROR_NOT_FOUND, error); |
| 107 } | 150 } |
| 108 | 151 |
| 152 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdate) { |
| 153 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); |
| 154 const std::string kResourceId("file:2_file_resource_id"); |
| 155 |
| 156 const std::string local_id = GetLocalId(kFilePath); |
| 157 EXPECT_FALSE(local_id.empty()); |
| 158 |
| 159 const std::string kTestFileContent = "I'm being uploaded! Yay!"; |
| 160 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); |
| 161 |
| 162 int64 original_changestamp = |
| 163 fake_service()->about_resource().largest_change_id(); |
| 164 |
| 165 // The callback will be called upon completion of UpdateEntry(). |
| 166 FileError error = FILE_ERROR_FAILED; |
| 167 performer_->UpdateEntry( |
| 168 local_id, |
| 169 ClientContext(USER_INITIATED), |
| 170 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 171 test_util::RunBlockingPoolTask(); |
| 172 EXPECT_EQ(FILE_ERROR_OK, error); |
| 173 |
| 174 // Check that the server has received an update. |
| 175 EXPECT_LT(original_changestamp, |
| 176 fake_service()->about_resource().largest_change_id()); |
| 177 |
| 178 // Check that the file size is updated to that of the updated content. |
| 179 google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR; |
| 180 scoped_ptr<google_apis::ResourceEntry> server_entry; |
| 181 fake_service()->GetResourceEntry( |
| 182 kResourceId, |
| 183 google_apis::test_util::CreateCopyResultCallback(&gdata_error, |
| 184 &server_entry)); |
| 185 test_util::RunBlockingPoolTask(); |
| 186 EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); |
| 187 EXPECT_EQ(static_cast<int64>(kTestFileContent.size()), |
| 188 server_entry->file_size()); |
| 189 |
| 190 // Make sure that the cache is no longer dirty. |
| 191 bool success = false; |
| 192 FileCacheEntry cache_entry; |
| 193 base::PostTaskAndReplyWithResult( |
| 194 blocking_task_runner(), |
| 195 FROM_HERE, |
| 196 base::Bind(&FileCache::GetCacheEntry, |
| 197 base::Unretained(cache()), |
| 198 local_id, |
| 199 &cache_entry), |
| 200 google_apis::test_util::CreateCopyResultCallback(&success)); |
| 201 test_util::RunBlockingPoolTask(); |
| 202 ASSERT_TRUE(success); |
| 203 EXPECT_FALSE(cache_entry.is_dirty()); |
| 204 } |
| 205 |
| 206 TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdateMd5Check) { |
| 207 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); |
| 208 const std::string kResourceId("file:2_file_resource_id"); |
| 209 |
| 210 const std::string local_id = GetLocalId(kFilePath); |
| 211 EXPECT_FALSE(local_id.empty()); |
| 212 |
| 213 const std::string kTestFileContent = "I'm being uploaded! Yay!"; |
| 214 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); |
| 215 |
| 216 int64 original_changestamp = |
| 217 fake_service()->about_resource().largest_change_id(); |
| 218 |
| 219 // The callback will be called upon completion of UpdateEntry(). |
| 220 FileError error = FILE_ERROR_FAILED; |
| 221 performer_->UpdateEntry( |
| 222 local_id, |
| 223 ClientContext(USER_INITIATED), |
| 224 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 225 test_util::RunBlockingPoolTask(); |
| 226 EXPECT_EQ(FILE_ERROR_OK, error); |
| 227 |
| 228 // Check that the server has received an update. |
| 229 EXPECT_LT(original_changestamp, |
| 230 fake_service()->about_resource().largest_change_id()); |
| 231 |
| 232 // Check that the file size is updated to that of the updated content. |
| 233 google_apis::GDataErrorCode gdata_error = google_apis::GDATA_OTHER_ERROR; |
| 234 scoped_ptr<google_apis::ResourceEntry> server_entry; |
| 235 fake_service()->GetResourceEntry( |
| 236 kResourceId, |
| 237 google_apis::test_util::CreateCopyResultCallback(&gdata_error, |
| 238 &server_entry)); |
| 239 test_util::RunBlockingPoolTask(); |
| 240 EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error); |
| 241 EXPECT_EQ(static_cast<int64>(kTestFileContent.size()), |
| 242 server_entry->file_size()); |
| 243 |
| 244 // Make sure that the cache is no longer dirty. |
| 245 bool success = false; |
| 246 FileCacheEntry cache_entry; |
| 247 base::PostTaskAndReplyWithResult( |
| 248 blocking_task_runner(), |
| 249 FROM_HERE, |
| 250 base::Bind(&FileCache::GetCacheEntry, |
| 251 base::Unretained(cache()), |
| 252 local_id, |
| 253 &cache_entry), |
| 254 google_apis::test_util::CreateCopyResultCallback(&success)); |
| 255 test_util::RunBlockingPoolTask(); |
| 256 ASSERT_TRUE(success); |
| 257 EXPECT_FALSE(cache_entry.is_dirty()); |
| 258 |
| 259 // Again mark the cache file dirty. |
| 260 scoped_ptr<base::ScopedClosureRunner> file_closer; |
| 261 error = FILE_ERROR_FAILED; |
| 262 base::PostTaskAndReplyWithResult( |
| 263 blocking_task_runner(), |
| 264 FROM_HERE, |
| 265 base::Bind(&FileCache::OpenForWrite, |
| 266 base::Unretained(cache()), |
| 267 local_id, |
| 268 &file_closer), |
| 269 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 270 test_util::RunBlockingPoolTask(); |
| 271 EXPECT_EQ(FILE_ERROR_OK, error); |
| 272 file_closer.reset(); |
| 273 |
| 274 // And call UpdateEntry again. |
| 275 // In this case, although the file is marked as dirty, but the content |
| 276 // hasn't been changed. Thus, the actual uploading should be skipped. |
| 277 original_changestamp = fake_service()->about_resource().largest_change_id(); |
| 278 error = FILE_ERROR_FAILED; |
| 279 performer_->UpdateEntry( |
| 280 local_id, |
| 281 ClientContext(USER_INITIATED), |
| 282 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 283 test_util::RunBlockingPoolTask(); |
| 284 EXPECT_EQ(FILE_ERROR_OK, error); |
| 285 |
| 286 EXPECT_EQ(original_changestamp, |
| 287 fake_service()->about_resource().largest_change_id()); |
| 288 |
| 289 // Make sure that the cache is no longer dirty. |
| 290 success = false; |
| 291 base::PostTaskAndReplyWithResult( |
| 292 blocking_task_runner(), |
| 293 FROM_HERE, |
| 294 base::Bind(&FileCache::GetCacheEntry, |
| 295 base::Unretained(cache()), |
| 296 local_id, |
| 297 &cache_entry), |
| 298 google_apis::test_util::CreateCopyResultCallback(&success)); |
| 299 test_util::RunBlockingPoolTask(); |
| 300 ASSERT_TRUE(success); |
| 301 EXPECT_FALSE(cache_entry.is_dirty()); |
| 302 } |
| 303 |
| 304 TEST_F(EntryUpdatePerformerTest, UpdateEntry_OpenedForWrite) { |
| 305 const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt")); |
| 306 const std::string kResourceId("file:2_file_resource_id"); |
| 307 |
| 308 const std::string local_id = GetLocalId(kFilePath); |
| 309 EXPECT_FALSE(local_id.empty()); |
| 310 |
| 311 const std::string kTestFileContent = "I'm being uploaded! Yay!"; |
| 312 EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent)); |
| 313 |
| 314 // Emulate a situation where someone is writing to the file. |
| 315 scoped_ptr<base::ScopedClosureRunner> file_closer; |
| 316 FileError error = FILE_ERROR_FAILED; |
| 317 base::PostTaskAndReplyWithResult( |
| 318 blocking_task_runner(), |
| 319 FROM_HERE, |
| 320 base::Bind(&FileCache::OpenForWrite, |
| 321 base::Unretained(cache()), |
| 322 local_id, |
| 323 &file_closer), |
| 324 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 325 test_util::RunBlockingPoolTask(); |
| 326 EXPECT_EQ(FILE_ERROR_OK, error); |
| 327 |
| 328 // Update. This should not clear the dirty bit. |
| 329 error = FILE_ERROR_FAILED; |
| 330 performer_->UpdateEntry( |
| 331 local_id, |
| 332 ClientContext(USER_INITIATED), |
| 333 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 334 test_util::RunBlockingPoolTask(); |
| 335 EXPECT_EQ(FILE_ERROR_OK, error); |
| 336 |
| 337 // Make sure that the cache is still dirty. |
| 338 bool success = false; |
| 339 FileCacheEntry cache_entry; |
| 340 base::PostTaskAndReplyWithResult( |
| 341 blocking_task_runner(), |
| 342 FROM_HERE, |
| 343 base::Bind(&FileCache::GetCacheEntry, |
| 344 base::Unretained(cache()), |
| 345 local_id, |
| 346 &cache_entry), |
| 347 google_apis::test_util::CreateCopyResultCallback(&success)); |
| 348 test_util::RunBlockingPoolTask(); |
| 349 EXPECT_TRUE(success); |
| 350 EXPECT_TRUE(cache_entry.is_dirty()); |
| 351 |
| 352 // Close the file. |
| 353 file_closer.reset(); |
| 354 |
| 355 // Update. This should clear the dirty bit. |
| 356 error = FILE_ERROR_FAILED; |
| 357 performer_->UpdateEntry( |
| 358 local_id, |
| 359 ClientContext(USER_INITIATED), |
| 360 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 361 test_util::RunBlockingPoolTask(); |
| 362 EXPECT_EQ(FILE_ERROR_OK, error); |
| 363 |
| 364 // Make sure that the cache is no longer dirty. |
| 365 base::PostTaskAndReplyWithResult( |
| 366 blocking_task_runner(), |
| 367 FROM_HERE, |
| 368 base::Bind(&FileCache::GetCacheEntry, |
| 369 base::Unretained(cache()), |
| 370 local_id, |
| 371 &cache_entry), |
| 372 google_apis::test_util::CreateCopyResultCallback(&success)); |
| 373 test_util::RunBlockingPoolTask(); |
| 374 EXPECT_TRUE(success); |
| 375 EXPECT_FALSE(cache_entry.is_dirty()); |
| 376 } |
| 377 |
| 109 } // namespace internal | 378 } // namespace internal |
| 110 } // namespace drive | 379 } // namespace drive |
| OLD | NEW |