diff options
author | ahendrickson@chromium.org <ahendrickson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 19:22:41 +0000 |
---|---|---|
committer | ahendrickson@chromium.org <ahendrickson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 19:22:41 +0000 |
commit | 443853c674eeabd922bfcda2caf0411f47c9a93c (patch) | |
tree | 425513cd9998b67aa183aa6f7c9a700761de533f /content/browser/download/base_file_unittest.cc | |
parent | b6dbdce9b4c536b4d0208ab2a0bf39bd219824bf (diff) | |
download | chromium_src-443853c674eeabd922bfcda2caf0411f47c9a93c.zip chromium_src-443853c674eeabd922bfcda2caf0411f47c9a93c.tar.gz chromium_src-443853c674eeabd922bfcda2caf0411f47c9a93c.tar.bz2 |
In order to resume a download some more information needs to be gathered.
This CL adds member data to classes to support this. It is the first of several CLs to implement download resumption.
In addition hash information is propagated from DownloadFile to DownloadItem, because a new DownloadFile will be created when the download is resumed. It will also need to be persisted in order to resume across chrome runs.
The plan is that data will be collected in DownloadResourceHandler::OnResponseStarted() and passed down to DownloadItem.
On resume, it will pass the information from the resuming DownloadItem to ResourceDispatcherHost::BeginDownload(), which will set any required headers.
BUG= 7648
TEST=None
Review URL: http://codereview.chromium.org/8404049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115573 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/download/base_file_unittest.cc')
-rw-r--r-- | content/browser/download/base_file_unittest.cc | 213 |
1 files changed, 168 insertions, 45 deletions
diff --git a/content/browser/download/base_file_unittest.cc b/content/browser/download/base_file_unittest.cc index 030a635..911af194 100644 --- a/content/browser/download/base_file_unittest.cc +++ b/content/browser/download/base_file_unittest.cc @@ -11,6 +11,7 @@ #include "base/string_number_conversions.h" #include "base/test/test_file_util.h" #include "content/browser/browser_thread_impl.h" +#include "crypto/secure_hash.h" #include "net/base/file_stream.h" #include "net/base/mock_file_stream.h" #include "net/base/net_errors.h" @@ -37,6 +38,9 @@ const base::TimeDelta kElapsedTimeDelta = base::TimeDelta::FromSeconds( class BaseFileTest : public testing::Test { public: + static const size_t kSha256HashLen = 32; + static const unsigned char kEmptySha256Hash[kSha256HashLen]; + BaseFileTest() : expect_file_survives_(false), expect_in_progress_(true), @@ -45,9 +49,10 @@ class BaseFileTest : public testing::Test { } virtual void SetUp() { + ResetHash(); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); base_file_.reset( - new BaseFile(FilePath(), GURL(), GURL(), 0, file_stream_)); + new BaseFile(FilePath(), GURL(), GURL(), 0, false, "", file_stream_)); } virtual void TearDown() { @@ -73,6 +78,28 @@ class BaseFileTest : public testing::Test { EXPECT_EQ(expect_file_survives_, file_util::PathExists(full_path)); } + void ResetHash() { + secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + memcpy(sha256_hash_, kEmptySha256Hash, kSha256HashLen); + } + + void UpdateHash(const char* data, size_t length) { + secure_hash_->Update(data, length); + } + + std::string GetFinalHash() { + std::string hash; + secure_hash_->Finish(sha256_hash_, kSha256HashLen); + hash.assign(reinterpret_cast<const char*>(sha256_hash_), + sizeof(sha256_hash_)); + return hash; + } + + void MakeFileWithHash() { + base_file_.reset( + new BaseFile(FilePath(), GURL(), GURL(), 0, true, "", file_stream_)); + } + bool OpenMockFileStream() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); @@ -121,9 +148,9 @@ class BaseFileTest : public testing::Test { static FilePath CreateTestFile() { FilePath file_name; linked_ptr<net::FileStream> dummy_file_stream; - BaseFile file(FilePath(), GURL(), GURL(), 0, dummy_file_stream); + BaseFile file(FilePath(), GURL(), GURL(), 0, false, "", dummy_file_stream); - EXPECT_EQ(net::OK, file.Initialize(false)); + EXPECT_EQ(net::OK, file.Initialize()); file_name = file.full_path(); EXPECT_NE(FilePath::StringType(), file_name.value()); @@ -139,8 +166,9 @@ class BaseFileTest : public testing::Test { static void CreateFileWithName(const FilePath& file_name) { EXPECT_NE(FilePath::StringType(), file_name.value()); linked_ptr<net::FileStream> dummy_file_stream; - BaseFile duplicate_file(file_name, GURL(), GURL(), 0, dummy_file_stream); - EXPECT_EQ(net::OK, duplicate_file.Initialize(false)); + BaseFile duplicate_file( + file_name, GURL(), GURL(), 0, false, "", dummy_file_stream); + EXPECT_EQ(net::OK, duplicate_file.Initialize()); // Write something into it. duplicate_file.AppendDataToFile(kTestData4, kTestDataLength4); // Detach the file so it isn't deleted on destruction of |duplicate_file|. @@ -173,6 +201,11 @@ class BaseFileTest : public testing::Test { // Expect the file to be in progress. bool expect_in_progress_; + // Hash calculator. + scoped_ptr<crypto::SecureHash> secure_hash_; + + unsigned char sha256_hash_[kSha256HashLen]; + private: // Keep track of what data should be saved to the disk file. std::string expected_data_; @@ -183,6 +216,9 @@ class BaseFileTest : public testing::Test { BrowserThreadImpl file_thread_; }; +// This will initialize the entire array to zero. +const unsigned char BaseFileTest::kEmptySha256Hash[] = { 0 }; + // Test the most basic scenario: just create the object and do a sanity check // on all its accessors. This is actually a case that rarely happens // in production, where we would at least Initialize it. @@ -192,7 +228,7 @@ TEST_F(BaseFileTest, CreateDestroy) { // Cancel the download explicitly. TEST_F(BaseFileTest, Cancel) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); EXPECT_TRUE(file_util::PathExists(base_file_->full_path())); base_file_->Cancel(); EXPECT_FALSE(file_util::PathExists(base_file_->full_path())); @@ -202,7 +238,7 @@ TEST_F(BaseFileTest, Cancel) { // Write data to the file and detach it, so it doesn't get deleted // automatically when base_file_ is destructed. TEST_F(BaseFileTest, WriteAndDetach) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); base_file_->Finish(); base_file_->Detach(); @@ -211,14 +247,23 @@ TEST_F(BaseFileTest, WriteAndDetach) { // Write data to the file and detach it, and calculate its sha256 hash. TEST_F(BaseFileTest, WriteWithHashAndDetach) { - ASSERT_EQ(net::OK, base_file_->Initialize(true)); + // Calculate the final hash. + ResetHash(); + UpdateHash(kTestData1, kTestDataLength1); + std::string expected_hash = GetFinalHash(); + std::string expected_hash_hex = + base::HexEncode(expected_hash.data(), expected_hash.size()); + + MakeFileWithHash(); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); base_file_->Finish(); std::string hash; - base_file_->GetSha256Hash(&hash); + base_file_->GetHash(&hash); EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", - base::HexEncode(hash.data(), hash.size())); + expected_hash_hex); + EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size())); base_file_->Detach(); expect_file_survives_ = true; @@ -226,7 +271,7 @@ TEST_F(BaseFileTest, WriteWithHashAndDetach) { // Rename the file after writing to it, then detach. TEST_F(BaseFileTest, WriteThenRenameAndDetach) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); FilePath initial_path(base_file_->full_path()); EXPECT_TRUE(file_util::PathExists(initial_path)); @@ -246,54 +291,118 @@ TEST_F(BaseFileTest, WriteThenRenameAndDetach) { // Write data to the file once. TEST_F(BaseFileTest, SingleWrite) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); base_file_->Finish(); } // Write data to the file multiple times. TEST_F(BaseFileTest, MultipleWrites) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData2)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData3)); std::string hash; - EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); + EXPECT_FALSE(base_file_->GetHash(&hash)); base_file_->Finish(); } // Write data to the file once and calculate its sha256 hash. TEST_F(BaseFileTest, SingleWriteWithHash) { - ASSERT_EQ(net::OK, base_file_->Initialize(true)); + // Calculate the final hash. + ResetHash(); + UpdateHash(kTestData1, kTestDataLength1); + std::string expected_hash = GetFinalHash(); + std::string expected_hash_hex = + base::HexEncode(expected_hash.data(), expected_hash.size()); + + MakeFileWithHash(); + ASSERT_EQ(net::OK, base_file_->Initialize()); + // Can get partial hash states before Finish() is called. + EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); + EXPECT_STRNE(std::string().c_str(), base_file_->GetHashState().c_str()); base_file_->Finish(); std::string hash; - base_file_->GetSha256Hash(&hash); - EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE", - base::HexEncode(hash.data(), hash.size())); + base_file_->GetHash(&hash); + EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size())); } // Write data to the file multiple times and calculate its sha256 hash. TEST_F(BaseFileTest, MultipleWritesWithHash) { - std::string hash; + // Calculate the final hash. + ResetHash(); + UpdateHash(kTestData1, kTestDataLength1); + UpdateHash(kTestData2, kTestDataLength2); + UpdateHash(kTestData3, kTestDataLength3); + std::string expected_hash = GetFinalHash(); + std::string expected_hash_hex = + base::HexEncode(expected_hash.data(), expected_hash.size()); - ASSERT_EQ(net::OK, base_file_->Initialize(true)); + std::string hash; + MakeFileWithHash(); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData2)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData3)); - // no hash before Finish() is called either. - EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); + // No hash before Finish() is called. + EXPECT_FALSE(base_file_->GetHash(&hash)); base_file_->Finish(); - EXPECT_TRUE(base_file_->GetSha256Hash(&hash)); + EXPECT_TRUE(base_file_->GetHash(&hash)); EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8", - base::HexEncode(hash.data(), hash.size())); + expected_hash_hex); + EXPECT_EQ(expected_hash_hex, base::HexEncode(hash.data(), hash.size())); +} + +// Write data to the file multiple times, interrupt it, and continue using +// another file. Calculate the resulting combined sha256 hash. +TEST_F(BaseFileTest, MultipleWritesInterruptedWithHash) { + // Calculate the final hash. + ResetHash(); + UpdateHash(kTestData1, kTestDataLength1); + UpdateHash(kTestData2, kTestDataLength2); + UpdateHash(kTestData3, kTestDataLength3); + std::string expected_hash = GetFinalHash(); + std::string expected_hash_hex = + base::HexEncode(expected_hash.data(), expected_hash.size()); + + MakeFileWithHash(); + ASSERT_EQ(net::OK, base_file_->Initialize()); + // Write some data + ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); + ASSERT_EQ(net::OK, AppendDataToFile(kTestData2)); + // Get the hash state and file name. + std::string hash_state; + hash_state = base_file_->GetHashState(); + // Finish the file. + base_file_->Finish(); + + // Create another file + linked_ptr<net::FileStream> second_stream; + BaseFile second_file(FilePath(), + GURL(), + GURL(), + base_file_->bytes_so_far(), + true, + hash_state, + second_stream); + ASSERT_EQ(net::OK, second_file.Initialize()); + std::string data(kTestData3); + EXPECT_EQ(net::OK, second_file.AppendDataToFile(data.data(), data.size())); + second_file.Finish(); + + std::string hash; + EXPECT_TRUE(second_file.GetHash(&hash)); + // This will fail until getting the hash state is supported in SecureHash. + EXPECT_STREQ(expected_hash_hex.c_str(), + base::HexEncode(hash.data(), hash.size()).c_str()); } // Rename the file after all writes to it. TEST_F(BaseFileTest, WriteThenRename) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); FilePath initial_path(base_file_->full_path()); EXPECT_TRUE(file_util::PathExists(initial_path)); @@ -311,7 +420,7 @@ TEST_F(BaseFileTest, WriteThenRename) { // Rename the file while the download is still in progress. TEST_F(BaseFileTest, RenameWhileInProgress) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); FilePath initial_path(base_file_->full_path()); EXPECT_TRUE(file_util::PathExists(initial_path)); @@ -334,14 +443,19 @@ TEST_F(BaseFileTest, RenameWhileInProgress) { TEST_F(BaseFileTest, MultipleWritesWithError) { ASSERT_TRUE(OpenMockFileStream()); base_file_.reset(new BaseFile(mock_file_stream_->get_path(), - GURL(), GURL(), 0, mock_file_stream_)); - EXPECT_EQ(net::OK, base_file_->Initialize(false)); + GURL(), + GURL(), + 0, + false, + "", + mock_file_stream_)); + EXPECT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData2)); ForceError(net::ERR_ACCESS_DENIED); ASSERT_NE(net::OK, AppendDataToFile(kTestData3)); std::string hash; - EXPECT_FALSE(base_file_->GetSha256Hash(&hash)); + EXPECT_FALSE(base_file_->GetHash(&hash)); base_file_->Finish(); } @@ -355,7 +469,7 @@ TEST_F(BaseFileTest, UninitializedFile) { // Overwrite base_file_ with another file with the same name and // non-zero contents, and make sure the last file to close 'wins'. TEST_F(BaseFileTest, DuplicateBaseFile) { - EXPECT_EQ(net::OK, base_file_->Initialize(false)); + EXPECT_EQ(net::OK, base_file_->Initialize()); // Create another |BaseFile| referring to the file that |base_file_| owns. CreateFileWithName(base_file_->full_path()); @@ -372,11 +486,15 @@ TEST_F(BaseFileTest, AppendToBaseFile) { set_expected_data(kTestData4); // Use the file we've just created. - base_file_.reset( - new BaseFile(existing_file_name, GURL(), GURL(), kTestDataLength4, - file_stream_)); + base_file_.reset(new BaseFile(existing_file_name, + GURL(), + GURL(), + kTestDataLength4, + false, + "", + file_stream_)); - EXPECT_EQ(net::OK, base_file_->Initialize(false)); + EXPECT_EQ(net::OK, base_file_->Initialize()); const FilePath file_name = base_file_->full_path(); EXPECT_NE(FilePath::StringType(), file_name.value()); @@ -398,12 +516,17 @@ TEST_F(BaseFileTest, ReadonlyBaseFile) { EXPECT_TRUE(file_util::MakeFileUnwritable(readonly_file_name)); // Try to overwrite it. - base_file_.reset( - new BaseFile(readonly_file_name, GURL(), GURL(), 0, file_stream_)); + base_file_.reset(new BaseFile(readonly_file_name, + GURL(), + GURL(), + 0, + false, + "", + file_stream_)); expect_in_progress_ = false; - int init_error = base_file_->Initialize(false); + int init_error = base_file_->Initialize(); DVLOG(1) << " init_error = " << init_error; EXPECT_NE(net::OK, init_error); @@ -418,17 +541,17 @@ TEST_F(BaseFileTest, ReadonlyBaseFile) { expect_file_survives_ = true; } -TEST_F(BaseFileTest, IsEmptySha256Hash) { +TEST_F(BaseFileTest, IsEmptyHash) { std::string empty(BaseFile::kSha256HashLen, '\x00'); - EXPECT_TRUE(BaseFile::IsEmptySha256Hash(empty)); + EXPECT_TRUE(BaseFile::IsEmptyHash(empty)); std::string not_empty(BaseFile::kSha256HashLen, '\x01'); - EXPECT_FALSE(BaseFile::IsEmptySha256Hash(not_empty)); - EXPECT_FALSE(BaseFile::IsEmptySha256Hash("")); + EXPECT_FALSE(BaseFile::IsEmptyHash(not_empty)); + EXPECT_FALSE(BaseFile::IsEmptyHash("")); } // Test that calculating speed after no writes. TEST_F(BaseFileTest, SpeedWithoutWrite) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); base::TimeTicks current = StartTick() + kElapsedTimeDelta; ASSERT_EQ(0, CurrentSpeedAtTime(current)); base_file_->Finish(); @@ -436,7 +559,7 @@ TEST_F(BaseFileTest, SpeedWithoutWrite) { // Test that calculating speed after a single write. TEST_F(BaseFileTest, SpeedAfterSingleWrite) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); base::TimeTicks current = StartTick() + kElapsedTimeDelta; int64 expected_speed = kTestDataLength1 / kElapsedTimeSeconds; @@ -446,7 +569,7 @@ TEST_F(BaseFileTest, SpeedAfterSingleWrite) { // Test that calculating speed after a multiple writes. TEST_F(BaseFileTest, SpeedAfterMultipleWrite) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData2)); ASSERT_EQ(net::OK, AppendDataToFile(kTestData3)); @@ -460,7 +583,7 @@ TEST_F(BaseFileTest, SpeedAfterMultipleWrite) { // Test that calculating speed after no delay - should not divide by 0. TEST_F(BaseFileTest, SpeedAfterNoElapsedTime) { - ASSERT_EQ(net::OK, base_file_->Initialize(false)); + ASSERT_EQ(net::OK, base_file_->Initialize()); ASSERT_EQ(net::OK, AppendDataToFile(kTestData1)); ASSERT_EQ(0, CurrentSpeedAtTime(StartTick())); base_file_->Finish(); |