| Index: content/browser/download/base_file_unittest.cc
|
| diff --git a/content/browser/download/base_file_unittest.cc b/content/browser/download/base_file_unittest.cc
|
| index 030a635324abb210e79020ea36b249d36a2f04f6..911af194bba2a253d23d35d11eb9205c96eaf95a 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();
|
|
|