| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/disk_cache/simple/simple_version_upgrade.h" |
| |
| #include <stdint.h> |
| #include <string> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/format_macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "net/base/net_errors.h" |
| #include "net/disk_cache/disk_cache.h" |
| #include "net/disk_cache/simple/simple_backend_version.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| // Same as |disk_cache::kSimpleInitialMagicNumber|. |
| const uint64_t kSimpleInitialMagicNumber = UINT64_C(0xfcfb6d1ba7725c30); |
| |
| // The "fake index" file that cache backends use to distinguish whether the |
| // cache belongs to one backend or another. |
| const char kFakeIndexFileName[] = "index"; |
| |
| // Same as |SimpleIndexFile::kIndexDirectory|. |
| const char kIndexDirName[] = "index-dir"; |
| |
| // Same as |SimpleIndexFile::kIndexFileName|. |
| const char kIndexFileName[] = "the-real-index"; |
| |
| bool WriteFakeIndexFileV8(const base::FilePath& cache_path) { |
| disk_cache::FakeIndexData data; |
| data.version = 8; |
| data.initial_magic_number = kSimpleInitialMagicNumber; |
| data.zero = 0; |
| data.zero2 = 0; |
| const base::FilePath file_name = cache_path.AppendASCII("index"); |
| return base::WriteFile(file_name, base::byte_span_from_ref(data)); |
| } |
| |
| TEST(SimpleVersionUpgradeTest, FailsToMigrateBackwards) { |
| base::ScopedTempDir cache_dir; |
| ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); |
| const base::FilePath cache_path = cache_dir.GetPath(); |
| |
| disk_cache::FakeIndexData data; |
| data.version = 100500; |
| data.initial_magic_number = kSimpleInitialMagicNumber; |
| data.zero = 0; |
| data.zero2 = 0; |
| const base::FilePath file_name = cache_path.AppendASCII(kFakeIndexFileName); |
| ASSERT_TRUE(base::WriteFile(file_name, base::byte_span_from_ref(data))); |
| disk_cache::TrivialFileOperations file_operations; |
| EXPECT_EQ(disk_cache::SimpleCacheConsistencyResult::kVersionFromTheFuture, |
| disk_cache::UpgradeSimpleCacheOnDisk(&file_operations, |
| cache_dir.GetPath())); |
| } |
| |
| TEST(SimpleVersionUpgradeTest, ExperimentBacktoDefault) { |
| base::ScopedTempDir cache_dir; |
| ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); |
| const base::FilePath cache_path = cache_dir.GetPath(); |
| |
| disk_cache::FakeIndexData data; |
| data.version = disk_cache::kSimpleVersion; |
| data.initial_magic_number = kSimpleInitialMagicNumber; |
| data.zero = 2; |
| data.zero2 = 4; |
| const base::FilePath file_name = cache_path.AppendASCII(kFakeIndexFileName); |
| ASSERT_TRUE(base::WriteFile(file_name, base::byte_span_from_ref(data))); |
| |
| disk_cache::TrivialFileOperations file_operations; |
| // The cache needs to transition from a deprecated experiment back to not |
| // having one. |
| EXPECT_EQ(disk_cache::SimpleCacheConsistencyResult::kBadZeroCheck, |
| disk_cache::UpgradeSimpleCacheOnDisk(&file_operations, |
| cache_dir.GetPath())); |
| } |
| |
| TEST(SimpleVersionUpgradeTest, FakeIndexVersionGetsUpdated) { |
| base::ScopedTempDir cache_dir; |
| ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); |
| const base::FilePath cache_path = cache_dir.GetPath(); |
| |
| ASSERT_TRUE(WriteFakeIndexFileV8(cache_path)); |
| |
| const std::string file_contents("incorrectly serialized data"); |
| const base::FilePath index_file = cache_path.AppendASCII(kIndexFileName); |
| ASSERT_TRUE(base::WriteFile(index_file, file_contents)); |
| |
| disk_cache::TrivialFileOperations file_operations; |
| // Upgrade. |
| ASSERT_EQ(disk_cache::SimpleCacheConsistencyResult::kOK, |
| disk_cache::UpgradeSimpleCacheOnDisk(&file_operations, cache_path)); |
| |
| // Check that the version in the fake index file is updated. |
| std::string new_fake_index_contents; |
| ASSERT_TRUE(base::ReadFileToString(cache_path.AppendASCII(kFakeIndexFileName), |
| &new_fake_index_contents)); |
| const disk_cache::FakeIndexData* fake_index_header; |
| EXPECT_EQ(sizeof(*fake_index_header), new_fake_index_contents.size()); |
| // TODO(crbug.com/428945428): Fix unsafe uses of std::string::data(). |
| fake_index_header = |
| UNSAFE_TODO(reinterpret_cast<const disk_cache::FakeIndexData*>( |
| new_fake_index_contents.data())); |
| EXPECT_EQ(disk_cache::kSimpleVersion, fake_index_header->version); |
| EXPECT_EQ(kSimpleInitialMagicNumber, fake_index_header->initial_magic_number); |
| } |
| |
| TEST(SimpleVersionUpgradeTest, DeleteAllIndexFilesWhenCacheIsEmpty) { |
| const std::string kCorruptData("corrupt"); |
| |
| base::ScopedTempDir cache_dir; |
| ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); |
| const base::FilePath cache_path = cache_dir.GetPath(); |
| |
| const base::FilePath fake_index = cache_path.AppendASCII(kFakeIndexFileName); |
| ASSERT_TRUE(base::WriteFile(fake_index, kCorruptData)); |
| |
| const base::FilePath index_path = cache_path.AppendASCII(kIndexDirName); |
| ASSERT_TRUE(base::CreateDirectory(index_path)); |
| |
| const base::FilePath index = index_path.AppendASCII(kIndexFileName); |
| ASSERT_TRUE(base::WriteFile(index, kCorruptData)); |
| |
| EXPECT_TRUE(disk_cache::DeleteIndexFilesIfCacheIsEmpty(cache_path)); |
| EXPECT_TRUE(base::PathExists(cache_path)); |
| EXPECT_TRUE(base::IsDirectoryEmpty(cache_path)); |
| } |
| |
| TEST(SimpleVersionUpgradeTest, DoesNotDeleteIndexFilesWhenCacheIsNotEmpty) { |
| const std::string kCorruptData("corrupt"); |
| |
| base::ScopedTempDir cache_dir; |
| ASSERT_TRUE(cache_dir.CreateUniqueTempDir()); |
| const base::FilePath cache_path = cache_dir.GetPath(); |
| |
| const base::FilePath fake_index = cache_path.AppendASCII(kFakeIndexFileName); |
| ASSERT_TRUE(base::WriteFile(fake_index, kCorruptData)); |
| |
| const base::FilePath index_path = cache_path.AppendASCII(kIndexDirName); |
| ASSERT_TRUE(base::CreateDirectory(index_path)); |
| |
| const base::FilePath index = index_path.AppendASCII(kIndexFileName); |
| ASSERT_TRUE(base::WriteFile(index, kCorruptData)); |
| |
| const base::FilePath entry_file = cache_path.AppendASCII("01234567_0"); |
| ASSERT_TRUE(base::WriteFile(entry_file, kCorruptData)); |
| |
| EXPECT_FALSE(disk_cache::DeleteIndexFilesIfCacheIsEmpty(cache_path)); |
| EXPECT_TRUE(base::PathExists(cache_path)); |
| EXPECT_FALSE(base::IsDirectoryEmpty(cache_path)); |
| EXPECT_TRUE(base::PathExists(fake_index)); |
| EXPECT_TRUE(base::PathExists(index_path)); |
| EXPECT_TRUE(base::PathExists(index)); |
| EXPECT_TRUE(base::PathExists(entry_file)); |
| } |
| |
| } // namespace |