| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/offline_pages/core/model/startup_maintenance_task.h" |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/files/file_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "build/build_config.h" |
| #include "components/offline_pages/core/client_namespace_constants.h" |
| #include "components/offline_pages/core/model/model_task_test_base.h" |
| #include "components/offline_pages/core/model/offline_page_test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace offline_pages { |
| |
| namespace { |
| |
| const int64_t kTestFileSize = 512 * (1 << 10); // Default file size is 512KB. |
| |
| // Used for checking if the page is still present in database and/or filesystem. |
| enum class PagePresence { |
| BOTH_DB_AND_FILESYSTEM, |
| DB_ONLY, |
| FILESYSTEM_ONLY, |
| NONE, |
| }; |
| |
| } // namespace |
| |
| class StartupMaintenanceTaskTest : public ModelTaskTestBase { |
| public: |
| StartupMaintenanceTaskTest(); |
| ~StartupMaintenanceTaskTest() override; |
| |
| void SetUp() override; |
| PagePresence CheckPagePresence(const OfflinePageItem& page); |
| |
| base::HistogramTester* histogram_tester() { return histogram_tester_.get(); } |
| |
| private: |
| std::unique_ptr<base::HistogramTester> histogram_tester_; |
| }; |
| |
| StartupMaintenanceTaskTest::StartupMaintenanceTaskTest() {} |
| |
| StartupMaintenanceTaskTest::~StartupMaintenanceTaskTest() {} |
| |
| void StartupMaintenanceTaskTest::SetUp() { |
| ModelTaskTestBase::SetUp(); |
| histogram_tester_ = std::make_unique<base::HistogramTester>(); |
| } |
| |
| PagePresence StartupMaintenanceTaskTest::CheckPagePresence( |
| const OfflinePageItem& page) { |
| if (base::PathExists(page.file_path)) { |
| if (store_test_util()->GetPageByOfflineId(page.offline_id)) |
| return PagePresence::BOTH_DB_AND_FILESYSTEM; |
| else |
| return PagePresence::FILESYSTEM_ONLY; |
| } else { |
| if (store_test_util()->GetPageByOfflineId(page.offline_id)) |
| return PagePresence::DB_ONLY; |
| else |
| return PagePresence::NONE; |
| } |
| } |
| |
| // This test is affected by https://crbug.com/725685, which only affects windows |
| // platform. |
| #if defined(OS_WIN) |
| #define MAYBE_TestDeletePageInLegacyArchivesDir \ |
| DISABLED_TestDeletePageInLegacyArchivesDir |
| #else |
| #define MAYBE_TestDeletePageInLegacyArchivesDir \ |
| TestDeletePageInLegacyArchivesDir |
| #endif |
| TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeletePageInLegacyArchivesDir) { |
| // |temporary_page| will be removed since it's temporary and its archive file |
| // is in private directory. |
| // |persistent_page| will not be affected by the maintenance task. |
| generator()->SetArchiveDirectory(PrivateDir()); |
| generator()->SetNamespace(kLastNNamespace); |
| OfflinePageItem temporary_page1 = AddPage(); |
| OfflinePageItem temporary_page2 = AddPageWithoutDBEntry(); |
| generator()->SetNamespace(kDownloadNamespace); |
| OfflinePageItem persistent_page1 = AddPage(); |
| OfflinePageItem persistent_page2 = AddPageWithoutDBEntry(); |
| |
| EXPECT_EQ(2LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(4UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| |
| auto task = std::make_unique<StartupMaintenanceTask>( |
| store(), archive_manager(), policy_controller()); |
| RunTask(std::move(task)); |
| |
| EXPECT_EQ(1LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2)); |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(persistent_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2)); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount", 2, 1); |
| } |
| |
| // This test is affected by https://crbug.com/725685, which only affects windows |
| // platform. |
| #if defined(OS_WIN) |
| #define MAYBE_TestDeleteFileWithoutDbEntry DISABLED_TestDeleteFileWithoutDbEntry |
| #else |
| #define MAYBE_TestDeleteFileWithoutDbEntry TestDeleteFileWithoutDbEntry |
| #endif |
| TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeleteFileWithoutDbEntry) { |
| // |temporary_page1| will not be affected. |
| // |temporary_page2| will have the file deleted since the file doesn't have a |
| // DB entry. |
| // |persistent_page1| will not be affected. |
| // |persistent_page2| will have its file deleted, since the file is in private |
| // directory and has no associated DB entry. |
| generator()->SetNamespace(kLastNNamespace); |
| generator()->SetArchiveDirectory(TemporaryDir()); |
| OfflinePageItem temporary_page1 = AddPage(); |
| OfflinePageItem temporary_page2 = AddPageWithoutDBEntry(); |
| |
| generator()->SetNamespace(kDownloadNamespace); |
| generator()->SetArchiveDirectory(PrivateDir()); |
| OfflinePageItem persistent_page1 = AddPage(); |
| OfflinePageItem persistent_page2 = AddPageWithoutDBEntry(); |
| |
| EXPECT_EQ(2LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(TemporaryDir())); |
| EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| EXPECT_EQ(PagePresence::FILESYSTEM_ONLY, CheckPagePresence(temporary_page2)); |
| EXPECT_EQ(PagePresence::FILESYSTEM_ONLY, CheckPagePresence(persistent_page2)); |
| |
| auto task = std::make_unique<StartupMaintenanceTask>( |
| store(), archive_manager(), policy_controller()); |
| RunTask(std::move(task)); |
| |
| EXPECT_EQ(2LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(TemporaryDir())); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(temporary_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2)); |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(persistent_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2)); |
| |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount", 1, 1); |
| histogram_tester()->ExpectTotalCount( |
| "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount", |
| 0); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount", 1, 1); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.Result", |
| static_cast<int>(SyncOperationResult::SUCCESS), 1); |
| } |
| |
| // This test is affected by https://crbug.com/725685, which only affects windows |
| // platform. |
| #if defined(OS_WIN) |
| #define MAYBE_TestDeleteDbEntryWithoutFile DISABLED_TestDeleteDbEntryWithoutFile |
| #else |
| #define MAYBE_TestDeleteDbEntryWithoutFile TestDeleteDbEntryWithoutFile |
| #endif |
| TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeleteDbEntryWithoutFile) { |
| // |temporary_page1| will not be affected. |
| // |temporary_page2| will be deleted from DB since it has no file associated. |
| // |persistent_page1| will not be affected. |
| // |persistent_page2| will be marked as file_missing. |
| generator()->SetNamespace(kLastNNamespace); |
| generator()->SetArchiveDirectory(TemporaryDir()); |
| OfflinePageItem temporary_page1 = AddPage(); |
| OfflinePageItem temporary_page2 = AddPageWithoutFile(); |
| |
| generator()->SetNamespace(kDownloadNamespace); |
| generator()->SetArchiveDirectory(PrivateDir()); |
| OfflinePageItem persistent_page1 = AddPage(); |
| OfflinePageItem persistent_page2 = AddPageWithoutFile(); |
| |
| EXPECT_EQ(4LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(TemporaryDir())); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| EXPECT_EQ(PagePresence::DB_ONLY, CheckPagePresence(temporary_page2)); |
| EXPECT_EQ(PagePresence::DB_ONLY, CheckPagePresence(persistent_page2)); |
| |
| auto task = std::make_unique<StartupMaintenanceTask>( |
| store(), archive_manager(), policy_controller()); |
| RunTask(std::move(task)); |
| |
| EXPECT_EQ(3LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(TemporaryDir())); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(temporary_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2)); |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(persistent_page1)); |
| EXPECT_EQ(PagePresence::DB_ONLY, CheckPagePresence(persistent_page2)); |
| |
| histogram_tester()->ExpectTotalCount( |
| "OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount", 0); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount", 1, |
| 1); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.Result", |
| static_cast<int>(SyncOperationResult::SUCCESS), 1); |
| } |
| |
| // This test is affected by https://crbug.com/725685, which only affects windows |
| // platform. |
| #if defined(OS_WIN) |
| #define MAYBE_CombinedTest DISABLED_CombinedTest |
| #else |
| #define MAYBE_CombinedTest CombinedTest |
| #endif |
| TEST_F(StartupMaintenanceTaskTest, MAYBE_CombinedTest) { |
| // Adding a bunch of pages with different setups for temporary pages. |
| // |temporary_page1| will not be affected. |
| // |temporary_page{2,3,4,5,6}| will be deleted. |
| generator()->SetNamespace(kLastNNamespace); |
| generator()->SetArchiveDirectory(TemporaryDir()); |
| OfflinePageItem temporary_page1 = AddPage(); |
| OfflinePageItem temporary_page2 = AddPageWithoutDBEntry(); |
| OfflinePageItem temporary_page3 = AddPageWithoutFile(); |
| generator()->SetArchiveDirectory(PrivateDir()); |
| OfflinePageItem temporary_page4 = AddPage(); |
| OfflinePageItem temporary_page5 = AddPageWithoutDBEntry(); |
| OfflinePageItem temporary_page6 = AddPageWithoutFile(); |
| // Adding a bunch of pages with different setups for persistent pages. |
| // |persistent_page1| will not be affected. |
| // |persistent_page2| will be deleted from Filesystem, since it's in private |
| // directory. |
| generator()->SetNamespace(kDownloadNamespace); |
| OfflinePageItem persistent_page1 = AddPage(); |
| OfflinePageItem persistent_page2 = AddPageWithoutDBEntry(); |
| |
| EXPECT_EQ(5LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(TemporaryDir())); |
| EXPECT_EQ(4UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| |
| auto task = std::make_unique<StartupMaintenanceTask>( |
| store(), archive_manager(), policy_controller()); |
| RunTask(std::move(task)); |
| |
| EXPECT_EQ(2LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(TemporaryDir())); |
| EXPECT_EQ(1UL, test_utils::GetFileCountInDirectory(PrivateDir())); |
| |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(temporary_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page2)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page3)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page4)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page5)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(temporary_page6)); |
| |
| EXPECT_EQ(PagePresence::BOTH_DB_AND_FILESYSTEM, |
| CheckPagePresence(persistent_page1)); |
| EXPECT_EQ(PagePresence::NONE, CheckPagePresence(persistent_page2)); |
| |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Legacy.DeletedHeadlessFileCount", 2, 1); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.PagesMissingArchiveFileCount", 2, |
| 1); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.PagesMissingDbEntryCount", 1, 1); |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ConsistencyCheck.Temporary.Result", |
| static_cast<int>(SyncOperationResult::SUCCESS), 1); |
| } |
| |
| TEST_F(StartupMaintenanceTaskTest, TestKeepingNonMhtmlFile) { |
| // Create a persistent offline page with mhtml extension but has no DB entry. |
| // It will not be deleted since it's in public directory. |
| generator()->SetNamespace(kDownloadNamespace); |
| generator()->SetArchiveDirectory(PublicDir()); |
| OfflinePageItem page1 = AddPageWithoutDBEntry(); |
| // Create a file with non-mhtml extension. It should not be affected. |
| base::FilePath path; |
| base::CreateTemporaryFileInDir(PublicDir(), &path); |
| base::FilePath mp3_path = path.AddExtension(FILE_PATH_LITERAL("mp3")); |
| EXPECT_TRUE(base::Move(path, mp3_path)); |
| |
| EXPECT_EQ(0LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PublicDir())); |
| |
| auto task = std::make_unique<StartupMaintenanceTask>( |
| store(), archive_manager(), policy_controller()); |
| RunTask(std::move(task)); |
| |
| EXPECT_EQ(0LL, store_test_util()->GetPageCount()); |
| EXPECT_EQ(2UL, test_utils::GetFileCountInDirectory(PublicDir())); |
| EXPECT_EQ(PagePresence::FILESYSTEM_ONLY, CheckPagePresence(page1)); |
| } |
| |
| TEST_F(StartupMaintenanceTaskTest, TestReportStorageUsage) { |
| generator()->SetFileSize(kTestFileSize); |
| std::vector<std::string> namespaces = policy_controller()->GetAllNamespaces(); |
| |
| // Adding pages into each namespace. |
| for (const auto& name_space : namespaces) { |
| // Set the correct namespace for generated pages, also put them into the |
| // correct directories, otherwise they might be cleaned based on consistency |
| // check. |
| generator()->SetNamespace(name_space); |
| if (policy_controller()->IsRemovedOnCacheReset(name_space)) |
| generator()->SetArchiveDirectory(TemporaryDir()); |
| else |
| generator()->SetArchiveDirectory(PrivateDir()); |
| |
| // For each namespace, insert pages based on the length of the namespace, so |
| // that we don't need to have const values here. |
| for (size_t count = 0; count < name_space.length(); ++count) |
| AddPage(); |
| } |
| |
| auto task = std::make_unique<StartupMaintenanceTask>( |
| store(), archive_manager(), policy_controller()); |
| RunTask(std::move(task)); |
| |
| // For each namespace, check if the storage usage was correctly reported, |
| // since the value is reported with KiB as unit, divide it by 1024 here. |
| for (const auto& name_space : namespaces) { |
| histogram_tester()->ExpectUniqueSample( |
| "OfflinePages.ClearStoragePreRunUsage2." + name_space, |
| name_space.length() * kTestFileSize / 1024, 1); |
| } |
| } |
| |
| } // namespace offline_pages |