1// Copyright (c) 2011 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/memory/scoped_temp_dir.h" 7#include "base/message_loop.h" 8#include "base/string_number_conversions.h" 9#include "chrome/browser/download/download_file.h" 10#include "chrome/browser/download/download_manager.h" 11#include "chrome/browser/download/download_status_updater.h" 12#include "chrome/browser/download/download_util.h" 13#include "chrome/browser/download/mock_download_manager.h" 14#include "chrome/browser/history/download_create_info.h" 15#include "content/browser/browser_thread.h" 16#include "net/base/file_stream.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19class DownloadFileTest : public testing::Test { 20 public: 21 22 static const char* kTestData1; 23 static const char* kTestData2; 24 static const char* kTestData3; 25 static const char* kDataHash; 26 static const int32 kDummyDownloadId; 27 static const int kDummyChildId; 28 static const int kDummyRequestId; 29 30 // We need a UI |BrowserThread| in order to destruct |download_manager_|, 31 // which has trait |BrowserThread::DeleteOnUIThread|. Without this, 32 // calling Release() on |download_manager_| won't ever result in its 33 // destructor being called and we get a leak. 34 DownloadFileTest() : 35 ui_thread_(BrowserThread::UI, &loop_), 36 file_thread_(BrowserThread::FILE, &loop_) { 37 } 38 39 ~DownloadFileTest() { 40 } 41 42 virtual void SetUp() { 43 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 44 download_manager_ = new MockDownloadManager(&download_status_updater_); 45 } 46 47 virtual void TearDown() { 48 // When a DownloadManager's reference count drops to 0, it is not 49 // deleted immediately. Instead, a task is posted to the UI thread's 50 // message loop to delete it. 51 // So, drop the reference count to 0 and run the message loop once 52 // to ensure that all resources are cleaned up before the test exits. 53 download_manager_ = NULL; 54 ui_thread_.message_loop()->RunAllPending(); 55 } 56 57 virtual void CreateDownloadFile(scoped_ptr<DownloadFile>* file, int offset) { 58 DownloadCreateInfo info; 59 info.download_id = kDummyDownloadId + offset; 60 info.child_id = kDummyChildId; 61 info.request_id = kDummyRequestId - offset; 62 info.save_info.file_stream = file_stream_; 63 file->reset(new DownloadFile(&info, download_manager_)); 64 } 65 66 virtual void DestroyDownloadFile(scoped_ptr<DownloadFile>* file, int offset) { 67 EXPECT_EQ(kDummyDownloadId + offset, (*file)->id()); 68 EXPECT_EQ(download_manager_, (*file)->GetDownloadManager()); 69 EXPECT_FALSE((*file)->in_progress()); 70 EXPECT_EQ(static_cast<int64>(expected_data_.size()), 71 (*file)->bytes_so_far()); 72 73 // Make sure the data has been properly written to disk. 74 std::string disk_data; 75 EXPECT_TRUE(file_util::ReadFileToString((*file)->full_path(), 76 &disk_data)); 77 EXPECT_EQ(expected_data_, disk_data); 78 79 // Make sure the mock BrowserThread outlives the DownloadFile to satisfy 80 // thread checks inside it. 81 file->reset(); 82 } 83 84 void AppendDataToFile(scoped_ptr<DownloadFile>* file, 85 const std::string& data) { 86 EXPECT_TRUE((*file)->in_progress()); 87 (*file)->AppendDataToFile(data.data(), data.size()); 88 expected_data_ += data; 89 EXPECT_EQ(static_cast<int64>(expected_data_.size()), 90 (*file)->bytes_so_far()); 91 } 92 93 protected: 94 // Temporary directory for renamed downloads. 95 ScopedTempDir temp_dir_; 96 97 DownloadStatusUpdater download_status_updater_; 98 scoped_refptr<DownloadManager> download_manager_; 99 100 linked_ptr<net::FileStream> file_stream_; 101 102 // DownloadFile instance we are testing. 103 scoped_ptr<DownloadFile> download_file_; 104 105 private: 106 MessageLoop loop_; 107 // UI thread. 108 BrowserThread ui_thread_; 109 // File thread to satisfy debug checks in DownloadFile. 110 BrowserThread file_thread_; 111 112 // Keep track of what data should be saved to the disk file. 113 std::string expected_data_; 114}; 115 116const char* DownloadFileTest::kTestData1 = 117 "Let's write some data to the file!\n"; 118const char* DownloadFileTest::kTestData2 = "Writing more data.\n"; 119const char* DownloadFileTest::kTestData3 = "Final line."; 120const char* DownloadFileTest::kDataHash = 121 "CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8"; 122 123const int32 DownloadFileTest::kDummyDownloadId = 23; 124const int DownloadFileTest::kDummyChildId = 3; 125const int DownloadFileTest::kDummyRequestId = 67; 126 127// Rename the file before any data is downloaded, after some has, after it all 128// has, and after it's closed. 129TEST_F(DownloadFileTest, RenameFileFinal) { 130 CreateDownloadFile(&download_file_, 0); 131 ASSERT_TRUE(download_file_->Initialize(true)); 132 FilePath initial_path(download_file_->full_path()); 133 EXPECT_TRUE(file_util::PathExists(initial_path)); 134 FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1")); 135 FilePath path_2(initial_path.InsertBeforeExtensionASCII("_2")); 136 FilePath path_3(initial_path.InsertBeforeExtensionASCII("_3")); 137 FilePath path_4(initial_path.InsertBeforeExtensionASCII("_4")); 138 139 // Rename the file before downloading any data. 140 EXPECT_TRUE(download_file_->Rename(path_1)); 141 FilePath renamed_path = download_file_->full_path(); 142 EXPECT_EQ(path_1, renamed_path); 143 144 // Check the files. 145 EXPECT_FALSE(file_util::PathExists(initial_path)); 146 EXPECT_TRUE(file_util::PathExists(path_1)); 147 148 // Download the data. 149 AppendDataToFile(&download_file_, kTestData1); 150 AppendDataToFile(&download_file_, kTestData2); 151 152 // Rename the file after downloading some data. 153 EXPECT_TRUE(download_file_->Rename(path_2)); 154 renamed_path = download_file_->full_path(); 155 EXPECT_EQ(path_2, renamed_path); 156 157 // Check the files. 158 EXPECT_FALSE(file_util::PathExists(path_1)); 159 EXPECT_TRUE(file_util::PathExists(path_2)); 160 161 AppendDataToFile(&download_file_, kTestData3); 162 163 // Rename the file after downloading all the data. 164 EXPECT_TRUE(download_file_->Rename(path_3)); 165 renamed_path = download_file_->full_path(); 166 EXPECT_EQ(path_3, renamed_path); 167 168 // Check the files. 169 EXPECT_FALSE(file_util::PathExists(path_2)); 170 EXPECT_TRUE(file_util::PathExists(path_3)); 171 172 // Should not be able to get the hash until the file is closed. 173 std::string hash; 174 EXPECT_FALSE(download_file_->GetSha256Hash(&hash)); 175 176 download_file_->Finish(); 177 178 // Rename the file after downloading all the data and closing the file. 179 EXPECT_TRUE(download_file_->Rename(path_4)); 180 renamed_path = download_file_->full_path(); 181 EXPECT_EQ(path_4, renamed_path); 182 183 // Check the files. 184 EXPECT_FALSE(file_util::PathExists(path_3)); 185 EXPECT_TRUE(file_util::PathExists(path_4)); 186 187 // Check the hash. 188 EXPECT_TRUE(download_file_->GetSha256Hash(&hash)); 189 EXPECT_EQ(kDataHash, base::HexEncode(hash.data(), hash.size())); 190 191 DestroyDownloadFile(&download_file_, 0); 192} 193