Home | History | Annotate | Download | only in download
      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 "base/file_util.h"
      6 #include "base/files/file_path.h"
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/memory/weak_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/observer_list.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/test/test_file_util.h"
     13 #include "chrome/browser/download/download_path_reservation_tracker.h"
     14 #include "chrome/browser/download/download_target_determiner.h"
     15 #include "content/public/test/mock_download_item.h"
     16 #include "content/public/test/test_browser_thread.h"
     17 #include "testing/gmock/include/gmock/gmock.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 using content::BrowserThread;
     21 using content::DownloadItem;
     22 using content::MockDownloadItem;
     23 using testing::AnyNumber;
     24 using testing::Return;
     25 using testing::ReturnRef;
     26 using testing::ReturnRefOfCopy;
     27 
     28 namespace {
     29 
     30 // MockDownloadItem with real observers and state.
     31 class FakeDownloadItem : public MockDownloadItem {
     32  public:
     33   explicit FakeDownloadItem()
     34       : state_(IN_PROGRESS) {
     35   }
     36   virtual ~FakeDownloadItem() {
     37     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadDestroyed(this));
     38     EXPECT_FALSE(observers_.might_have_observers());
     39   }
     40   virtual void AddObserver(Observer* observer) OVERRIDE {
     41     observers_.AddObserver(observer);
     42   }
     43   virtual void RemoveObserver(Observer* observer) OVERRIDE {
     44     observers_.RemoveObserver(observer);
     45   }
     46   virtual void UpdateObservers() OVERRIDE {
     47     FOR_EACH_OBSERVER(Observer, observers_, OnDownloadUpdated(this));
     48   }
     49 
     50   virtual DownloadState GetState() const OVERRIDE {
     51     return state_;
     52   }
     53 
     54   void SetState(DownloadState state) {
     55     state_ = state;
     56     UpdateObservers();
     57   }
     58 
     59  private:
     60   DownloadState state_;
     61   ObserverList<Observer> observers_;
     62 };
     63 
     64 class DownloadPathReservationTrackerTest : public testing::Test {
     65  public:
     66   DownloadPathReservationTrackerTest();
     67 
     68   // testing::Test
     69   virtual void SetUp() OVERRIDE;
     70   virtual void TearDown() OVERRIDE;
     71 
     72   FakeDownloadItem* CreateDownloadItem(int32 id);
     73   base::FilePath GetPathInDownloadsDirectory(
     74       const base::FilePath::CharType* suffix);
     75   bool IsPathInUse(const base::FilePath& path);
     76   void CallGetReservedPath(
     77       DownloadItem* download_item,
     78       const base::FilePath& target_path,
     79       bool create_directory,
     80       DownloadPathReservationTracker::FilenameConflictAction conflict_action,
     81       base::FilePath* return_path,
     82       bool* return_verified);
     83 
     84   const base::FilePath& default_download_path() const {
     85     return default_download_path_;
     86   }
     87   void set_default_download_path(const base::FilePath& path) {
     88     default_download_path_ = path;
     89   }
     90   // Creates a name of form 'a'*repeat + suffix
     91   base::FilePath GetLongNamePathInDownloadsDirectory(
     92       size_t repeat, const base::FilePath::CharType* suffix);
     93 
     94  protected:
     95   base::ScopedTempDir test_download_dir_;
     96   base::FilePath default_download_path_;
     97   base::MessageLoopForUI message_loop_;
     98   content::TestBrowserThread ui_thread_;
     99   content::TestBrowserThread file_thread_;
    100 
    101  private:
    102   void TestReservedPathCallback(base::FilePath* return_path,
    103                                 bool* return_verified, bool* did_run_callback,
    104                                 const base::FilePath& path, bool verified);
    105 };
    106 
    107 DownloadPathReservationTrackerTest::DownloadPathReservationTrackerTest()
    108     : ui_thread_(BrowserThread::UI, &message_loop_),
    109       file_thread_(BrowserThread::FILE, &message_loop_) {
    110 }
    111 
    112 void DownloadPathReservationTrackerTest::SetUp() {
    113   ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
    114   set_default_download_path(test_download_dir_.path());
    115 }
    116 
    117 void DownloadPathReservationTrackerTest::TearDown() {
    118   message_loop_.RunUntilIdle();
    119 }
    120 
    121 FakeDownloadItem* DownloadPathReservationTrackerTest::CreateDownloadItem(
    122     int32 id) {
    123   FakeDownloadItem* item = new ::testing::StrictMock<FakeDownloadItem>;
    124   EXPECT_CALL(*item, GetId())
    125       .WillRepeatedly(Return(id));
    126   EXPECT_CALL(*item, GetTargetFilePath())
    127       .WillRepeatedly(ReturnRefOfCopy(base::FilePath()));
    128   return item;
    129 }
    130 
    131 base::FilePath DownloadPathReservationTrackerTest::GetPathInDownloadsDirectory(
    132     const base::FilePath::CharType* suffix) {
    133   return default_download_path().Append(suffix).NormalizePathSeparators();
    134 }
    135 
    136 bool DownloadPathReservationTrackerTest::IsPathInUse(
    137     const base::FilePath& path) {
    138   return DownloadPathReservationTracker::IsPathInUseForTesting(path);
    139 }
    140 
    141 void DownloadPathReservationTrackerTest::CallGetReservedPath(
    142     DownloadItem* download_item,
    143     const base::FilePath& target_path,
    144     bool create_directory,
    145     DownloadPathReservationTracker::FilenameConflictAction conflict_action,
    146     base::FilePath* return_path,
    147     bool* return_verified) {
    148   // Weak pointer factory to prevent the callback from running after this
    149   // function has returned.
    150   base::WeakPtrFactory<DownloadPathReservationTrackerTest> weak_ptr_factory(
    151       this);
    152   bool did_run_callback = false;
    153   DownloadPathReservationTracker::GetReservedPath(
    154       download_item,
    155       target_path,
    156       default_download_path(),
    157       create_directory,
    158       conflict_action,
    159       base::Bind(&DownloadPathReservationTrackerTest::TestReservedPathCallback,
    160                  weak_ptr_factory.GetWeakPtr(), return_path, return_verified,
    161                  &did_run_callback));
    162   message_loop_.RunUntilIdle();
    163   EXPECT_TRUE(did_run_callback);
    164 }
    165 
    166 void DownloadPathReservationTrackerTest::TestReservedPathCallback(
    167     base::FilePath* return_path, bool* return_verified, bool* did_run_callback,
    168     const base::FilePath& path, bool verified) {
    169   *did_run_callback = true;
    170   *return_path = path;
    171   *return_verified = verified;
    172 }
    173 
    174 base::FilePath
    175 DownloadPathReservationTrackerTest::GetLongNamePathInDownloadsDirectory(
    176     size_t repeat, const base::FilePath::CharType* suffix) {
    177   return GetPathInDownloadsDirectory(
    178       (base::FilePath::StringType(repeat, FILE_PATH_LITERAL('a'))
    179           + suffix).c_str());
    180 }
    181 
    182 }  // namespace
    183 
    184 // A basic reservation is acquired and committed.
    185 TEST_F(DownloadPathReservationTrackerTest, BasicReservation) {
    186   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    187   base::FilePath path(
    188       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    189   ASSERT_FALSE(IsPathInUse(path));
    190 
    191   base::FilePath reserved_path;
    192   bool verified = false;
    193   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    194     DownloadPathReservationTracker::OVERWRITE;
    195   bool create_directory = false;
    196   CallGetReservedPath(
    197       item.get(),
    198       path,
    199       create_directory,
    200       conflict_action,
    201       &reserved_path,
    202       &verified);
    203   EXPECT_TRUE(IsPathInUse(path));
    204   EXPECT_TRUE(verified);
    205   EXPECT_EQ(path.value(), reserved_path.value());
    206 
    207   // Destroying the item should release the reservation.
    208   item->SetState(DownloadItem::COMPLETE);
    209   item.reset();
    210   message_loop_.RunUntilIdle();
    211   EXPECT_FALSE(IsPathInUse(path));
    212 }
    213 
    214 // A download that is interrupted should lose its reservation.
    215 TEST_F(DownloadPathReservationTrackerTest, InterruptedDownload) {
    216   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    217   base::FilePath path(
    218       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    219   ASSERT_FALSE(IsPathInUse(path));
    220 
    221   base::FilePath reserved_path;
    222   bool verified = false;
    223   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    224     DownloadPathReservationTracker::OVERWRITE;
    225   bool create_directory = false;
    226   CallGetReservedPath(
    227       item.get(),
    228       path,
    229       create_directory,
    230       conflict_action,
    231       &reserved_path,
    232       &verified);
    233   EXPECT_TRUE(IsPathInUse(path));
    234   EXPECT_TRUE(verified);
    235   EXPECT_EQ(path.value(), reserved_path.value());
    236 
    237   // Once the download is interrupted, the path should become available again.
    238   item->SetState(DownloadItem::INTERRUPTED);
    239   message_loop_.RunUntilIdle();
    240   EXPECT_FALSE(IsPathInUse(path));
    241 }
    242 
    243 // A completed download should also lose its reservation.
    244 TEST_F(DownloadPathReservationTrackerTest, CompleteDownload) {
    245   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    246   base::FilePath path(
    247       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    248   ASSERT_FALSE(IsPathInUse(path));
    249 
    250   base::FilePath reserved_path;
    251   bool verified = false;
    252   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    253     DownloadPathReservationTracker::OVERWRITE;
    254   bool create_directory = false;
    255   CallGetReservedPath(
    256       item.get(),
    257       path,
    258       create_directory,
    259       conflict_action,
    260       &reserved_path,
    261       &verified);
    262   EXPECT_TRUE(IsPathInUse(path));
    263   EXPECT_TRUE(verified);
    264   EXPECT_EQ(path.value(), reserved_path.value());
    265 
    266   // Once the download completes, the path should become available again. For a
    267   // real download, at this point only the path reservation will be released.
    268   // The path wouldn't be available since it is occupied on disk by the
    269   // completed download.
    270   item->SetState(DownloadItem::COMPLETE);
    271   message_loop_.RunUntilIdle();
    272   EXPECT_FALSE(IsPathInUse(path));
    273 }
    274 
    275 // If there are files on the file system, a unique reservation should uniquify
    276 // around it.
    277 TEST_F(DownloadPathReservationTrackerTest, ConflictingFiles) {
    278   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    279   base::FilePath path(
    280       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    281   base::FilePath path1(
    282       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
    283   // Create a file at |path|, and a .crdownload file at |path1|.
    284   ASSERT_EQ(0, file_util::WriteFile(path, "", 0));
    285   ASSERT_EQ(0,
    286             file_util::WriteFile(
    287                 DownloadTargetDeterminer::GetCrDownloadPath(path1), "", 0));
    288   ASSERT_TRUE(IsPathInUse(path));
    289 
    290   base::FilePath reserved_path;
    291   bool verified = false;
    292   bool create_directory = false;
    293   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    294     DownloadPathReservationTracker::UNIQUIFY;
    295   CallGetReservedPath(
    296       item.get(),
    297       path,
    298       create_directory,
    299       conflict_action,
    300       &reserved_path,
    301       &verified);
    302   EXPECT_TRUE(IsPathInUse(path));
    303   EXPECT_TRUE(IsPathInUse(reserved_path));
    304   EXPECT_TRUE(verified);
    305   // The path should be uniquified, skipping over foo.txt but not over
    306   // "foo (1).txt.crdownload"
    307   EXPECT_EQ(
    308       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")).value(),
    309       reserved_path.value());
    310 
    311   item->SetState(DownloadItem::COMPLETE);
    312   item.reset();
    313   message_loop_.RunUntilIdle();
    314   EXPECT_TRUE(IsPathInUse(path));
    315   EXPECT_FALSE(IsPathInUse(reserved_path));
    316 }
    317 
    318 // Multiple reservations for the same path should uniquify around each other.
    319 TEST_F(DownloadPathReservationTrackerTest, ConflictingReservations) {
    320   scoped_ptr<FakeDownloadItem> item1(CreateDownloadItem(1));
    321   base::FilePath path(
    322       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    323   base::FilePath uniquified_path(
    324       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
    325   ASSERT_FALSE(IsPathInUse(path));
    326   ASSERT_FALSE(IsPathInUse(uniquified_path));
    327 
    328   base::FilePath reserved_path1;
    329   bool verified = false;
    330   bool create_directory = false;
    331 
    332   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    333     DownloadPathReservationTracker::UNIQUIFY;
    334   CallGetReservedPath(
    335       item1.get(),
    336       path,
    337       create_directory,
    338       conflict_action,
    339       &reserved_path1,
    340       &verified);
    341   EXPECT_TRUE(IsPathInUse(path));
    342   EXPECT_TRUE(verified);
    343 
    344 
    345   {
    346     // Requesting a reservation for the same path with uniquification results in
    347     // a uniquified path.
    348     scoped_ptr<FakeDownloadItem> item2(CreateDownloadItem(2));
    349     base::FilePath reserved_path2;
    350     CallGetReservedPath(
    351         item2.get(),
    352         path,
    353         create_directory,
    354         conflict_action,
    355         &reserved_path2,
    356         &verified);
    357     EXPECT_TRUE(IsPathInUse(path));
    358     EXPECT_TRUE(IsPathInUse(uniquified_path));
    359     EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
    360     item2->SetState(DownloadItem::COMPLETE);
    361   }
    362   message_loop_.RunUntilIdle();
    363   EXPECT_TRUE(IsPathInUse(path));
    364   EXPECT_FALSE(IsPathInUse(uniquified_path));
    365 
    366   {
    367     // Since the previous download item was removed, requesting a reservation
    368     // for the same path should result in the same uniquified path.
    369     scoped_ptr<FakeDownloadItem> item2(CreateDownloadItem(2));
    370     base::FilePath reserved_path2;
    371     CallGetReservedPath(
    372         item2.get(),
    373         path,
    374         create_directory,
    375         conflict_action,
    376         &reserved_path2,
    377         &verified);
    378     EXPECT_TRUE(IsPathInUse(path));
    379     EXPECT_TRUE(IsPathInUse(uniquified_path));
    380     EXPECT_EQ(uniquified_path.value(), reserved_path2.value());
    381     item2->SetState(DownloadItem::COMPLETE);
    382   }
    383   message_loop_.RunUntilIdle();
    384 
    385   // Now acquire an overwriting reservation. We should end up with the same
    386   // non-uniquified path for both reservations.
    387   scoped_ptr<FakeDownloadItem> item3(CreateDownloadItem(2));
    388   base::FilePath reserved_path3;
    389   conflict_action = DownloadPathReservationTracker::OVERWRITE;
    390   CallGetReservedPath(
    391       item3.get(),
    392       path,
    393       create_directory,
    394       conflict_action,
    395       &reserved_path3,
    396       &verified);
    397   EXPECT_TRUE(IsPathInUse(path));
    398   EXPECT_FALSE(IsPathInUse(uniquified_path));
    399 
    400   EXPECT_EQ(path.value(), reserved_path1.value());
    401   EXPECT_EQ(path.value(), reserved_path3.value());
    402 
    403   item1->SetState(DownloadItem::COMPLETE);
    404   item3->SetState(DownloadItem::COMPLETE);
    405 }
    406 
    407 // If a unique path cannot be determined after trying kMaxUniqueFiles
    408 // uniquifiers, then the callback should notified that verification failed, and
    409 // the returned path should be set to the original requested path.
    410 TEST_F(DownloadPathReservationTrackerTest, UnresolvedConflicts) {
    411   base::FilePath path(
    412       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    413   scoped_ptr<FakeDownloadItem> items[
    414       DownloadPathReservationTracker::kMaxUniqueFiles + 1];
    415   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    416     DownloadPathReservationTracker::UNIQUIFY;
    417   bool create_directory = false;
    418 
    419   // Create |kMaxUniqueFiles + 1| reservations for |path|. The first reservation
    420   // will have no uniquifier. The |kMaxUniqueFiles| remaining reservations do.
    421   for (int i = 0; i <= DownloadPathReservationTracker::kMaxUniqueFiles; i++) {
    422     base::FilePath reserved_path;
    423     base::FilePath expected_path;
    424     bool verified = false;
    425     if (i > 0) {
    426       expected_path =
    427           path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", i));
    428     } else {
    429       expected_path = path;
    430     }
    431     items[i].reset(CreateDownloadItem(i));
    432     EXPECT_FALSE(IsPathInUse(expected_path));
    433     CallGetReservedPath(
    434         items[i].get(),
    435         path,
    436         create_directory,
    437         conflict_action,
    438         &reserved_path,
    439         &verified);
    440     EXPECT_TRUE(IsPathInUse(expected_path));
    441     EXPECT_EQ(expected_path.value(), reserved_path.value());
    442     EXPECT_TRUE(verified);
    443   }
    444   // The next reservation for |path| will fail to be unique.
    445   scoped_ptr<FakeDownloadItem> item(
    446       CreateDownloadItem(DownloadPathReservationTracker::kMaxUniqueFiles + 1));
    447   base::FilePath reserved_path;
    448   bool verified = true;
    449   CallGetReservedPath(
    450       item.get(),
    451       path,
    452       create_directory,
    453       conflict_action,
    454       &reserved_path,
    455       &verified);
    456   EXPECT_FALSE(verified);
    457   EXPECT_EQ(path.value(), reserved_path.value());
    458 
    459   item->SetState(DownloadItem::COMPLETE);
    460   for (int i = 0; i <= DownloadPathReservationTracker::kMaxUniqueFiles; i++) {
    461     items[i]->SetState(DownloadItem::COMPLETE);
    462   }
    463 }
    464 
    465 // If the target directory is unwriteable, then callback should be notified that
    466 // verification failed.
    467 TEST_F(DownloadPathReservationTrackerTest, UnwriteableDirectory) {
    468   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    469   base::FilePath path(
    470       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    471   base::FilePath dir(path.DirName());
    472   ASSERT_FALSE(IsPathInUse(path));
    473 
    474   {
    475     // Scope for PermissionRestorer
    476     file_util::PermissionRestorer restorer(dir);
    477     EXPECT_TRUE(file_util::MakeFileUnwritable(dir));
    478     base::FilePath reserved_path;
    479     bool verified = true;
    480     DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    481       DownloadPathReservationTracker::OVERWRITE;
    482     bool create_directory = false;
    483     CallGetReservedPath(
    484         item.get(),
    485         path,
    486         create_directory,
    487         conflict_action,
    488         &reserved_path,
    489         &verified);
    490     // Verification fails.
    491     EXPECT_FALSE(verified);
    492     EXPECT_EQ(path.BaseName().value(), reserved_path.BaseName().value());
    493   }
    494   item->SetState(DownloadItem::COMPLETE);
    495 }
    496 
    497 // If the default download directory doesn't exist, then it should be
    498 // created. But only if we are actually going to create the download path there.
    499 TEST_F(DownloadPathReservationTrackerTest, CreateDefaultDownloadPath) {
    500   base::FilePath path(
    501       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo/foo.txt")));
    502   base::FilePath dir(path.DirName());
    503   ASSERT_FALSE(base::DirectoryExists(dir));
    504   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    505     DownloadPathReservationTracker::OVERWRITE;
    506   bool create_directory = false;
    507 
    508   {
    509     scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    510     base::FilePath reserved_path;
    511     bool verified = true;
    512     CallGetReservedPath(
    513         item.get(),
    514         path,
    515         create_directory,
    516         conflict_action,
    517         &reserved_path,
    518         &verified);
    519     // Verification fails because the directory doesn't exist.
    520     EXPECT_FALSE(verified);
    521     item->SetState(DownloadItem::COMPLETE);
    522   }
    523   ASSERT_FALSE(IsPathInUse(path));
    524   {
    525     scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    526     base::FilePath reserved_path;
    527     bool verified = true;
    528     set_default_download_path(dir);
    529     CallGetReservedPath(
    530         item.get(),
    531         path,
    532         create_directory,
    533         conflict_action,
    534         &reserved_path,
    535         &verified);
    536     // Verification succeeds because the directory is created.
    537     EXPECT_TRUE(verified);
    538     EXPECT_TRUE(base::DirectoryExists(dir));
    539     item->SetState(DownloadItem::COMPLETE);
    540   }
    541 }
    542 
    543 // If the target path of the download item changes, the reservation should be
    544 // updated to match.
    545 TEST_F(DownloadPathReservationTrackerTest, UpdatesToTargetPath) {
    546   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    547   base::FilePath path(
    548       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
    549   ASSERT_FALSE(IsPathInUse(path));
    550 
    551   base::FilePath reserved_path;
    552   bool verified = false;
    553   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    554     DownloadPathReservationTracker::OVERWRITE;
    555   bool create_directory = false;
    556   CallGetReservedPath(
    557       item.get(),
    558       path,
    559       create_directory,
    560       conflict_action,
    561       &reserved_path,
    562       &verified);
    563   EXPECT_TRUE(IsPathInUse(path));
    564   EXPECT_TRUE(verified);
    565   EXPECT_EQ(path.value(), reserved_path.value());
    566 
    567   // The target path is initially empty. If an OnDownloadUpdated() is issued in
    568   // this state, we shouldn't lose the reservation.
    569   ASSERT_EQ(base::FilePath::StringType(), item->GetTargetFilePath().value());
    570   item->UpdateObservers();
    571   message_loop_.RunUntilIdle();
    572   EXPECT_TRUE(IsPathInUse(path));
    573 
    574   // If the target path changes, we should update the reservation to match.
    575   base::FilePath new_target_path(
    576       GetPathInDownloadsDirectory(FILE_PATH_LITERAL("bar.txt")));
    577   ASSERT_FALSE(IsPathInUse(new_target_path));
    578   EXPECT_CALL(*item, GetTargetFilePath())
    579       .WillRepeatedly(ReturnRef(new_target_path));
    580   item->UpdateObservers();
    581   message_loop_.RunUntilIdle();
    582   EXPECT_FALSE(IsPathInUse(path));
    583   EXPECT_TRUE(IsPathInUse(new_target_path));
    584 
    585   // Destroying the item should release the reservation.
    586   item->SetState(DownloadItem::COMPLETE);
    587   item.reset();
    588   message_loop_.RunUntilIdle();
    589   EXPECT_FALSE(IsPathInUse(new_target_path));
    590 }
    591 
    592 // Tests for long name truncation. On other platforms automatic truncation
    593 // is not performed (yet).
    594 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
    595 
    596 TEST_F(DownloadPathReservationTrackerTest, BasicTruncation) {
    597   int real_max_length =
    598       file_util::GetMaximumPathComponentLength(default_download_path());
    599   ASSERT_NE(-1, real_max_length);
    600 
    601   // TODO(kinaba): the current implementation leaves spaces for appending
    602   // ".crdownload". So take it into account. Should be removed in the future.
    603   const size_t max_length = real_max_length - 11;
    604 
    605   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    606   base::FilePath path(GetLongNamePathInDownloadsDirectory(
    607       max_length, FILE_PATH_LITERAL(".txt")));
    608   ASSERT_FALSE(IsPathInUse(path));
    609 
    610   base::FilePath reserved_path;
    611   bool verified = false;
    612   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    613     DownloadPathReservationTracker::OVERWRITE;
    614   bool create_directory = false;
    615   CallGetReservedPath(
    616       item.get(),
    617       path,
    618       create_directory,
    619       conflict_action,
    620       &reserved_path,
    621       &verified);
    622   EXPECT_TRUE(IsPathInUse(reserved_path));
    623   EXPECT_TRUE(verified);
    624   // The file name length is truncated to max_length.
    625   EXPECT_EQ(max_length, reserved_path.BaseName().value().size());
    626   // But the extension is kept unchanged.
    627   EXPECT_EQ(path.Extension(), reserved_path.Extension());
    628   item->SetState(DownloadItem::COMPLETE);
    629 }
    630 
    631 TEST_F(DownloadPathReservationTrackerTest, TruncationConflict) {
    632   int real_max_length =
    633       file_util::GetMaximumPathComponentLength(default_download_path());
    634   ASSERT_NE(-1, real_max_length);
    635   const size_t max_length = real_max_length - 11;
    636 
    637   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    638   base::FilePath path(GetLongNamePathInDownloadsDirectory(
    639       max_length, FILE_PATH_LITERAL(".txt")));
    640   base::FilePath path0(GetLongNamePathInDownloadsDirectory(
    641       max_length - 4, FILE_PATH_LITERAL(".txt")));
    642   base::FilePath path1(GetLongNamePathInDownloadsDirectory(
    643       max_length - 8, FILE_PATH_LITERAL(" (1).txt")));
    644   base::FilePath path2(GetLongNamePathInDownloadsDirectory(
    645       max_length - 8, FILE_PATH_LITERAL(" (2).txt")));
    646   ASSERT_FALSE(IsPathInUse(path));
    647   // "aaa...aaaaaaa.txt" (truncated path) and
    648   // "aaa...aaa (1).txt" (truncated and first uniquification try) exists.
    649   // "aaa...aaa (2).txt" should be used.
    650   ASSERT_EQ(0, file_util::WriteFile(path0, "", 0));
    651   ASSERT_EQ(0, file_util::WriteFile(path1, "", 0));
    652 
    653   base::FilePath reserved_path;
    654   bool verified = false;
    655   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    656     DownloadPathReservationTracker::UNIQUIFY;
    657   bool create_directory = false;
    658   CallGetReservedPath(
    659       item.get(),
    660       path,
    661       create_directory,
    662       conflict_action,
    663       &reserved_path,
    664       &verified);
    665   EXPECT_TRUE(IsPathInUse(reserved_path));
    666   EXPECT_TRUE(verified);
    667   EXPECT_EQ(path2, reserved_path);
    668   item->SetState(DownloadItem::COMPLETE);
    669 }
    670 
    671 TEST_F(DownloadPathReservationTrackerTest, TruncationFail) {
    672   int real_max_length =
    673       file_util::GetMaximumPathComponentLength(default_download_path());
    674   ASSERT_NE(-1, real_max_length);
    675   const size_t max_length = real_max_length - 11;
    676 
    677   scoped_ptr<FakeDownloadItem> item(CreateDownloadItem(1));
    678   base::FilePath path(GetPathInDownloadsDirectory(
    679       (FILE_PATH_LITERAL("a.") +
    680           base::FilePath::StringType(max_length, 'b')).c_str()));
    681   ASSERT_FALSE(IsPathInUse(path));
    682 
    683   base::FilePath reserved_path;
    684   bool verified = false;
    685   DownloadPathReservationTracker::FilenameConflictAction conflict_action =
    686     DownloadPathReservationTracker::OVERWRITE;
    687   bool create_directory = false;
    688   CallGetReservedPath(
    689       item.get(),
    690       path,
    691       create_directory,
    692       conflict_action,
    693       &reserved_path,
    694       &verified);
    695   // We cannot truncate a path with very long extension.
    696   EXPECT_FALSE(verified);
    697   item->SetState(DownloadItem::COMPLETE);
    698 }
    699 
    700 #endif
    701